├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── api ├── build.gradle └── src │ └── main │ └── java │ └── dev │ └── xdark │ └── asminline │ ├── AsmBlock.java │ └── BiIntConsumer.java ├── build.gradle ├── common ├── build.gradle └── src │ └── main │ └── java │ └── dev │ └── xdark │ └── asminline │ ├── AsmInliner.java │ ├── AsmUtil.java │ ├── BlocksCollector.java │ ├── Constants.java │ ├── LoaderBoundClassWriter.java │ ├── LookupUtil.java │ ├── MethodInfo.java │ ├── PatchProcessor.java │ ├── VersionUtil.java │ └── VisitingAsmBlock.java ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── plugin ├── build.gradle └── src │ └── main │ └── java │ └── dev │ └── xdark │ └── asminline │ ├── AsmInlinePlugin.java │ └── BytecodeInlineExtension.java └── settings.gradle /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [ push ] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - name: Set up JDK 1.8 11 | uses: actions/setup-java@v1 12 | with: 13 | java-version: 1.8 14 | - name: Publish with Gradle 15 | run: ./gradlew --no-daemon publish 16 | env: 17 | IMPLARIO_REPO_USER: ${{ secrets.IMPLARIO_REPO_USER }} 18 | IMPLARIO_REPO_PASSWORD: ${{ secrets.IMPLARIO_REPO_PASSWORD }} 19 | continue-on-error: true 20 | - uses: actions/upload-artifact@v2 21 | with: 22 | name: Package 23 | path: build/libs/* 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IntelliJ 2 | out/ 3 | .idea/ 4 | .idea_modules/ 5 | *.iws 6 | *.iml 7 | 8 | # Eclipse 9 | .settings/ 10 | .classpath 11 | .checkstyle 12 | .project 13 | 14 | # Gradle 15 | target/ 16 | build/ 17 | gradle-app.setting 18 | .gradle 19 | .gradletasknamecache 20 | !gradle-wrapper.jar 21 | **/build/ 22 | 23 | # Misc 24 | hs_err_pid* 25 | *.log 26 | *.ctxt 27 | temp/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 xxDark 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # asm-inline 2 | 3 | At first I thought: *Oh, I can make an optimization transformer for Proguard* 4 | And then this happened. 5 | Example: 6 | 7 | ```Java 8 | public class Test { 9 | 10 | public static void main(String[] args) { 11 | AsmBlock.inline(b -> { 12 | b.getstatic(System.class, "out", PrintStream.class) 13 | .ldc("Hello, World!") 14 | .invokevirtual(PrintStream.class, "println", 15 | MethodType.methodType(Void.TYPE, String.class)); 16 | // Note that RETURN will be added by javac. 17 | }); 18 | } 19 | } 20 | ``` -------------------------------------------------------------------------------- /api/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compileOnly asm 3 | } 4 | -------------------------------------------------------------------------------- /api/src/main/java/dev/xdark/asminline/AsmBlock.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.asminline; 2 | 3 | import org.objectweb.asm.ConstantDynamic; 4 | import org.objectweb.asm.Handle; 5 | import org.objectweb.asm.Label; 6 | import org.objectweb.asm.Type; 7 | 8 | import java.lang.invoke.MethodType; 9 | import java.util.function.Consumer; 10 | 11 | public interface AsmBlock { 12 | 13 | static void inline(Consumer blocker) { 14 | throw new UnsupportedOperationException("Must be replaced with bytecode"); 15 | } 16 | 17 | static long inlineJ(Consumer blocker) { 18 | throw new UnsupportedOperationException("Must be replaced with bytecode"); 19 | } 20 | 21 | static double inlineD(Consumer blocker) { 22 | throw new UnsupportedOperationException("Must be replaced with bytecode"); 23 | } 24 | 25 | static int inlineI(Consumer blocker) { 26 | throw new UnsupportedOperationException("Must be replaced with bytecode"); 27 | } 28 | 29 | static float inlineF(Consumer blocker) { 30 | throw new UnsupportedOperationException("Must be replaced with bytecode"); 31 | } 32 | 33 | static char inlineC(Consumer blocker) { 34 | throw new UnsupportedOperationException("Must be replaced with bytecode"); 35 | } 36 | 37 | static short inlineS(Consumer blocker) { 38 | throw new UnsupportedOperationException("Must be replaced with bytecode"); 39 | } 40 | 41 | static byte inlineB(Consumer blocker) { 42 | throw new UnsupportedOperationException("Must be replaced with bytecode"); 43 | } 44 | 45 | static boolean inlineZ(Consumer blocker) { 46 | throw new UnsupportedOperationException("Must be replaced with bytecode"); 47 | } 48 | 49 | static V inlineA(Consumer blocker) { 50 | throw new UnsupportedOperationException("Must be replaced with bytecode"); 51 | } 52 | 53 | AsmBlock nop(); 54 | 55 | AsmBlock $null(); 56 | 57 | AsmBlock $int(int value); 58 | 59 | AsmBlock $long(long value); 60 | 61 | AsmBlock $float(float value); 62 | 63 | AsmBlock $double(double value); 64 | 65 | AsmBlock ldc(String value); 66 | 67 | AsmBlock ldc(Class type); 68 | 69 | AsmBlock ldc(Type type); 70 | 71 | AsmBlock ldc(MethodType type); 72 | 73 | AsmBlock ldc(Handle handle); 74 | 75 | AsmBlock ldc(ConstantDynamic constantDynamic); 76 | 77 | AsmBlock iload(int idx); 78 | 79 | AsmBlock lload(int idx); 80 | 81 | AsmBlock fload(int idx); 82 | 83 | AsmBlock dload(int idx); 84 | 85 | AsmBlock aload(int idx); 86 | 87 | AsmBlock iaload(); 88 | 89 | AsmBlock laload(); 90 | 91 | AsmBlock faload(); 92 | 93 | AsmBlock daload(); 94 | 95 | AsmBlock aaload(); 96 | 97 | AsmBlock baload(); 98 | 99 | AsmBlock caload(); 100 | 101 | AsmBlock saload(); 102 | 103 | AsmBlock istore(int idx); 104 | 105 | AsmBlock lstore(int idx); 106 | 107 | AsmBlock fstore(int idx); 108 | 109 | AsmBlock dstore(int idx); 110 | 111 | AsmBlock astore(int idx); 112 | 113 | AsmBlock iastore(); 114 | 115 | AsmBlock lastore(); 116 | 117 | AsmBlock fastore(); 118 | 119 | AsmBlock dastore(); 120 | 121 | AsmBlock aastore(); 122 | 123 | AsmBlock bastore(); 124 | 125 | AsmBlock castore(); 126 | 127 | AsmBlock sastore(); 128 | 129 | AsmBlock pop(); 130 | 131 | AsmBlock pop2(); 132 | 133 | AsmBlock dup(); 134 | 135 | AsmBlock dupx1(); 136 | 137 | AsmBlock dupx2(); 138 | 139 | AsmBlock dup2(); 140 | 141 | AsmBlock dup2x1(); 142 | 143 | AsmBlock dup2x2(); 144 | 145 | AsmBlock swap(); 146 | 147 | AsmBlock iadd(); 148 | 149 | AsmBlock ladd(); 150 | 151 | AsmBlock fadd(); 152 | 153 | AsmBlock dadd(); 154 | 155 | AsmBlock isub(); 156 | 157 | AsmBlock lsub(); 158 | 159 | AsmBlock fsub(); 160 | 161 | AsmBlock dsub(); 162 | 163 | AsmBlock imul(); 164 | 165 | AsmBlock lmul(); 166 | 167 | AsmBlock fmul(); 168 | 169 | AsmBlock dmul(); 170 | 171 | AsmBlock idiv(); 172 | 173 | AsmBlock ldiv(); 174 | 175 | AsmBlock fdiv(); 176 | 177 | AsmBlock ddiv(); 178 | 179 | AsmBlock irem(); 180 | 181 | AsmBlock lrem(); 182 | 183 | AsmBlock frem(); 184 | 185 | AsmBlock drem(); 186 | 187 | AsmBlock ineg(); 188 | 189 | AsmBlock lneg(); 190 | 191 | AsmBlock fneg(); 192 | 193 | AsmBlock dneg(); 194 | 195 | AsmBlock ishl(); 196 | 197 | AsmBlock lshl(); 198 | 199 | AsmBlock ishr(); 200 | 201 | AsmBlock lshr(); 202 | 203 | AsmBlock iushr(); 204 | 205 | AsmBlock lushr(); 206 | 207 | AsmBlock iand(); 208 | 209 | AsmBlock land(); 210 | 211 | AsmBlock ior(); 212 | 213 | AsmBlock lor(); 214 | 215 | AsmBlock ixor(); 216 | 217 | AsmBlock lxor(); 218 | 219 | AsmBlock iinc(int idx, int value); 220 | 221 | AsmBlock i2l(); 222 | 223 | AsmBlock i2f(); 224 | 225 | AsmBlock i2d(); 226 | 227 | AsmBlock l2i(); 228 | 229 | AsmBlock l2f(); 230 | 231 | AsmBlock l2d(); 232 | 233 | AsmBlock f2i(); 234 | 235 | AsmBlock f2l(); 236 | 237 | AsmBlock f2d(); 238 | 239 | AsmBlock d2i(); 240 | 241 | AsmBlock d2l(); 242 | 243 | AsmBlock d2f(); 244 | 245 | AsmBlock i2b(); 246 | 247 | AsmBlock i2c(); 248 | 249 | AsmBlock i2s(); 250 | 251 | AsmBlock lcmp(); 252 | 253 | AsmBlock fcmpl(); 254 | 255 | AsmBlock fcmpg(); 256 | 257 | AsmBlock dcmpl(); 258 | 259 | AsmBlock dcmpg(); 260 | 261 | // = 0 262 | AsmBlock ifeq(Label label); 263 | 264 | // != 0 265 | AsmBlock ifne(Label label); 266 | 267 | // < 0 268 | AsmBlock iflt(Label label); 269 | 270 | // >= 0 271 | AsmBlock ifge(Label label); 272 | 273 | // > 0 274 | AsmBlock ifgt(Label label); 275 | 276 | // < 0 277 | AsmBlock ifle(Label label); 278 | 279 | // [v2, v1]: v1 == v2 280 | AsmBlock icmpeq(Label label); 281 | 282 | // [v2, v1]: v1 != v2 283 | AsmBlock icmpne(Label label); 284 | 285 | // [v2, v1]: v1 < v2 286 | AsmBlock icmplt(Label label); 287 | 288 | // [v2, v1]: v1 >= v2 289 | AsmBlock icmpge(Label label); 290 | 291 | // [v2, v1]: v1 > v2 292 | AsmBlock icmpgt(Label label); 293 | 294 | // [v2, v1]: v1 <= v2 295 | AsmBlock icmple(Label label); 296 | 297 | // [v2, v1]: v1 == v2 298 | AsmBlock acmpeq(Label label); 299 | 300 | // [v2, v1]: v1 != v2 301 | AsmBlock acmpne(Label label); 302 | 303 | AsmBlock $goto(Label label); 304 | 305 | // TODO Maybe JSR/RET? 306 | 307 | AsmBlock tableswitch(int min, int max, Label dflt, Label... labels); 308 | 309 | AsmBlock lookupswitch(int[] keys, Label dflt, Label... labels); 310 | 311 | AsmBlock ireturn(); 312 | 313 | AsmBlock lreturn(); 314 | 315 | AsmBlock freturn(); 316 | 317 | AsmBlock dreturn(); 318 | 319 | AsmBlock areturn(); 320 | 321 | AsmBlock $return(); 322 | 323 | AsmBlock getstatic(String owner, String name, String desc); 324 | 325 | AsmBlock putstatic(String owner, String name, String desc); 326 | 327 | AsmBlock getfield(String owner, String name, String desc); 328 | 329 | AsmBlock putfield(String owner, String name, String desc); 330 | 331 | AsmBlock getstatic(Class owner, String name, String desc); 332 | 333 | AsmBlock putstatic(Class owner, String name, String desc); 334 | 335 | AsmBlock getfield(Class owner, String name, String desc); 336 | 337 | AsmBlock putfield(Class owner, String name, String desc); 338 | 339 | AsmBlock getstatic(String owner, String name, Class desc); 340 | 341 | AsmBlock putstatic(String owner, String name, Class desc); 342 | 343 | AsmBlock getfield(String owner, String name, Class desc); 344 | 345 | AsmBlock putfield(String owner, String name, Class desc); 346 | 347 | AsmBlock getstatic(Class owner, String name, Class desc); 348 | 349 | AsmBlock putstatic(Class owner, String name, Class desc); 350 | 351 | AsmBlock getfield(Class owner, String name, Class desc); 352 | 353 | AsmBlock putfield(Class owner, String name, Class desc); 354 | 355 | AsmBlock invokevirtual(String owner, String name, String desc); 356 | 357 | AsmBlock invokespecial(String owner, String name, String desc); 358 | 359 | AsmBlock invokestatic(String owner, String name, String desc); 360 | 361 | AsmBlock invokeinterface(String owner, String name, String desc); 362 | 363 | AsmBlock invokedynamic(String name, String desc, Handle bootstrap, Object... args); 364 | 365 | AsmBlock invokevirtual(String owner, String name, MethodType type); 366 | 367 | AsmBlock invokestatic(String owner, String name, MethodType type); 368 | 369 | AsmBlock invokeinterface(String owner, String name, MethodType type); 370 | 371 | AsmBlock invokevirtual(Class owner, String name, String desc); 372 | 373 | AsmBlock invokespecial(Class owner, String name, String desc); 374 | 375 | AsmBlock invokestatic(Class owner, String name, String desc); 376 | 377 | AsmBlock invokevirtual(Class owner, String name, MethodType type); 378 | 379 | AsmBlock invokespecial(Class owner, String name, MethodType type); 380 | 381 | AsmBlock invokestatic(Class owner, String name, MethodType type); 382 | 383 | AsmBlock invokeinterface(Class owner, String name, String desc); 384 | 385 | AsmBlock invokeinterface(Class owner, String name, MethodType type); 386 | 387 | AsmBlock $new(String type); 388 | 389 | AsmBlock $new(Class type); 390 | 391 | AsmBlock $new(Type type); 392 | 393 | AsmBlock newarray(int type); 394 | 395 | AsmBlock newarray(String type); 396 | 397 | AsmBlock arraylength(); 398 | 399 | AsmBlock athrow(); 400 | 401 | AsmBlock checkcast(String type); 402 | 403 | AsmBlock $instanceof(String type); 404 | 405 | AsmBlock monitorenter(); 406 | 407 | AsmBlock monitorexit(); 408 | 409 | AsmBlock multinewarray(String desc, int dimensions); 410 | 411 | // v == null 412 | AsmBlock ifnull(Label label); 413 | 414 | // v != null 415 | AsmBlock ifnonnull(Label label); 416 | 417 | AsmBlock label(Label label); 418 | 419 | AsmBlock $try(Label start, Label end, Label handler, String type); 420 | 421 | AsmBlock line(int line, Label start); 422 | 423 | AsmBlock parameter(String name, int access); 424 | 425 | AsmBlock array(long[] array, int off, int len); 426 | 427 | AsmBlock array(double[] array, int off, int len); 428 | 429 | AsmBlock array(int[] array, int off, int len); 430 | 431 | AsmBlock array(float[] array, int off, int len); 432 | 433 | AsmBlock array(char[] array, int off, int len); 434 | 435 | AsmBlock array(short[] array, int off, int len); 436 | 437 | AsmBlock array(byte[] array, int off, int len); 438 | 439 | AsmBlock array(boolean[] array, int off, int len); 440 | 441 | AsmBlock array(T[] array, int off, int len, BiIntConsumer producer); 442 | 443 | AsmBlock array(long[] array); 444 | 445 | AsmBlock array(double[] array); 446 | 447 | AsmBlock array(int[] array); 448 | 449 | AsmBlock array(float[] array); 450 | 451 | AsmBlock array(char[] array); 452 | 453 | AsmBlock array(short[] array); 454 | 455 | AsmBlock array(byte[] array); 456 | 457 | AsmBlock array(boolean[] array); 458 | 459 | AsmBlock array(T[] array, BiIntConsumer producer); 460 | } 461 | -------------------------------------------------------------------------------- /api/src/main/java/dev/xdark/asminline/BiIntConsumer.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.asminline; 2 | 3 | import java.util.function.BiConsumer; 4 | 5 | @FunctionalInterface 6 | public interface BiIntConsumer extends BiConsumer { 7 | 8 | default void accept(int i, U u) { 9 | this.accept(Integer.valueOf(i), u); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | group 'dev.xdark.asm-inline' 3 | version '1.1-SNAPSHOT' 4 | } 5 | 6 | subprojects { 7 | apply plugin: 'java' 8 | apply plugin: 'maven-publish' 9 | 10 | repositories { 11 | mavenCentral() 12 | } 13 | 14 | configurations { 15 | shade 16 | compileOnly.extendsFrom shade 17 | } 18 | 19 | java.toolchain { 20 | languageVersion.set(JavaLanguageVersion.of(17)) 21 | } 22 | tasks.withType(JavaCompile).configureEach { 23 | options.encoding = 'UTF-8' 24 | } 25 | 26 | project.ext { 27 | asm = 'org.ow2.asm:asm:9.6' 28 | } 29 | 30 | publishing { 31 | repositories { 32 | if (System.getenv('CI') == null) { 33 | mavenLocal() 34 | } else { 35 | maven { 36 | url = 'https://repo.implario.dev/public/' 37 | credentials { 38 | username System.getenv('IMPLARIO_REPO_USER') 39 | password System.getenv('IMPLARIO_REPO_PASSWORD') 40 | } 41 | } 42 | } 43 | } 44 | publications { 45 | maven(MavenPublication) { 46 | groupId project.group 47 | artifactId project.name 48 | version project.version 49 | from components.java 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /common/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compileOnly asm 3 | compileOnly project(':api') 4 | } 5 | -------------------------------------------------------------------------------- /common/src/main/java/dev/xdark/asminline/AsmInliner.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.asminline; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.ClassWriter; 5 | import org.objectweb.asm.Handle; 6 | import org.objectweb.asm.MethodVisitor; 7 | import org.objectweb.asm.Opcodes; 8 | import org.objectweb.asm.Type; 9 | 10 | import java.lang.invoke.MethodHandles; 11 | import java.util.Map; 12 | import java.util.function.Consumer; 13 | 14 | public final class AsmInliner extends ClassVisitor { 15 | 16 | private static final Type ASM_BLOCK = Type 17 | .getMethodType(Type.VOID_TYPE, Type.getType(AsmBlock.class)); 18 | private static final Handle LAMBDA_FACTORY_HANDLE = new Handle( 19 | Opcodes.H_INVOKESTATIC, 20 | "java/lang/invoke/LambdaMetafactory", 21 | "metafactory", 22 | "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", 23 | false 24 | ); 25 | private static final Type CONSUMER = Type.getType(Consumer.class); 26 | private final ClassLoader loader; 27 | private final Map methods; 28 | private String name; 29 | boolean rewrite; 30 | 31 | public AsmInliner(ClassVisitor classVisitor, ClassLoader loader, 32 | Map methods) { 33 | super(Opcodes.ASM9, classVisitor); 34 | this.loader = loader; 35 | this.methods = methods; 36 | } 37 | 38 | @Override 39 | public void visit(int version, int access, String name, String signature, String superName, 40 | String[] interfaces) { 41 | this.name = name; 42 | super.visit(version, access, name, signature, superName, interfaces); 43 | } 44 | 45 | @Override 46 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, 47 | String[] exceptions) { 48 | if (methods.containsKey(new MethodInfo(name, descriptor))) { 49 | return null; 50 | } 51 | 52 | return new MethodVisitor(Opcodes.ASM9, 53 | super.visitMethod(access, name, descriptor, signature, exceptions)) { 54 | @Override 55 | public void visitMethodInsn(int opcode, String owner, String name, String descriptor, 56 | boolean isInterface) { 57 | if (opcode == Opcodes.INVOKESTATIC && owner.equals("dev/xdark/asminline/AsmBlock") 58 | && isInlineName(name) 59 | && isInlineDescriptor(descriptor)) { 60 | return; 61 | } 62 | super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); 63 | } 64 | 65 | @Override 66 | public void visitInvokeDynamicInsn(String name, String descriptor, 67 | Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) { 68 | if (LAMBDA_FACTORY_HANDLE.equals(bootstrapMethodHandle)) { 69 | if (bootstrapMethodArguments.length > 2) { 70 | Object o = bootstrapMethodArguments[1]; 71 | if (o instanceof Handle) { 72 | Handle handle = (Handle) o; 73 | if (handle.getTag() == Opcodes.H_INVOKESTATIC) { 74 | Type type = Type.getMethodType(handle.getDesc()); 75 | if (ASM_BLOCK.equals(type)) { 76 | try { 77 | String methodName = handle.getName(); 78 | Class klass = generateInlineClass( 79 | new MethodInfo(methodName, Constants.BLOCK_TYPE_DESC)); 80 | AsmBlock block = new VisitingAsmBlock(this); 81 | LookupUtil.lookup().findStatic(klass, methodName, Constants.BLOCK_TYPE).invokeExact(block); 82 | AsmInliner.this.rewrite = true; 83 | } catch (Throwable e) { 84 | throw new RuntimeException(e); 85 | } 86 | return; 87 | } 88 | } 89 | } 90 | } 91 | } 92 | super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, 93 | bootstrapMethodArguments); 94 | } 95 | 96 | private boolean isInlineName(String name) { 97 | if (name.startsWith("inline")) { 98 | name = name.substring("inline".length()); 99 | if (name.isEmpty()) { 100 | return true; 101 | } 102 | if (name.length() != 1) { 103 | return false; 104 | } 105 | char c = name.charAt(0); 106 | return c == 'J' || c == 'D' || c == 'I' || c == 'F' || c == 'C' || c == 'S' || c == 'B' || c == 'Z' || c == 'A'; 107 | } 108 | return false; 109 | } 110 | 111 | private boolean isInlineDescriptor(String desc) { 112 | Type[] parameters = Type.getArgumentTypes(desc); 113 | return parameters.length == 1 && CONSUMER.equals(parameters[0]); 114 | } 115 | }; 116 | } 117 | 118 | private Class generateInlineClass(MethodInfo info) { 119 | ClassWriter writer = methods.get(info); 120 | if (writer == null) { 121 | throw new IllegalArgumentException("Unknown method: " + name + '.' + info.name + info.desc); 122 | } 123 | byte[] classBytes = writer.toByteArray(); 124 | try { 125 | return LookupUtil.lookup().in(Class.forName(name.replace('/', '.'), false, loader)) 126 | .defineHiddenClass(classBytes, true, MethodHandles.Lookup.ClassOption.NESTMATE) 127 | .lookupClass(); 128 | } catch (Exception ex) { 129 | throw new IllegalStateException(ex); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /common/src/main/java/dev/xdark/asminline/AsmUtil.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.asminline; 2 | 3 | import org.objectweb.asm.ClassWriter; 4 | import org.objectweb.asm.MethodVisitor; 5 | 6 | import java.lang.invoke.MethodHandle; 7 | import java.lang.invoke.MethodHandles.Lookup; 8 | 9 | final class AsmUtil { 10 | 11 | private static final MethodHandle MH_GET_SYMBOL_TABLE; 12 | private static final MethodHandle MH_SET_SYMBOL_TABLE; 13 | private static final MethodHandle MH_SET_FIRST_METHOD; 14 | 15 | private AsmUtil() { 16 | } 17 | 18 | static Object getSymbolTable(ClassWriter writer) { 19 | try { 20 | return MH_GET_SYMBOL_TABLE.invoke(writer); 21 | } catch (Throwable t) { 22 | throw new AssertionError(t); 23 | } 24 | } 25 | 26 | static void copySymbolTable(ClassWriter source, ClassWriter target) { 27 | try { 28 | MH_SET_SYMBOL_TABLE.invoke(target, MH_GET_SYMBOL_TABLE.invoke(source)); 29 | } catch (Throwable t) { 30 | throw new AssertionError(t); 31 | } 32 | } 33 | 34 | static void setSymbolTable(ClassWriter writer, Object symbolTable) { 35 | try { 36 | MH_SET_SYMBOL_TABLE.invoke(writer, symbolTable); 37 | } catch (Throwable t) { 38 | throw new AssertionError(t); 39 | } 40 | } 41 | 42 | static void setFirstMethod(ClassWriter writer, MethodVisitor method) { 43 | try { 44 | MH_SET_FIRST_METHOD.invoke(writer, method); 45 | } catch (Throwable t) { 46 | throw new AssertionError(t); 47 | } 48 | } 49 | 50 | static { 51 | try { 52 | Class symbolTable = Class.forName("org.objectweb.asm.SymbolTable"); 53 | Class methodWriter = Class.forName("org.objectweb.asm.MethodWriter"); 54 | Lookup lookup = LookupUtil.lookup(); 55 | MH_GET_SYMBOL_TABLE = lookup.findGetter(ClassWriter.class, "symbolTable", symbolTable); 56 | MH_SET_SYMBOL_TABLE = lookup.findSetter(ClassWriter.class, "symbolTable", symbolTable); 57 | MH_SET_FIRST_METHOD = lookup.findSetter(ClassWriter.class, "firstMethod", methodWriter); 58 | } catch (IllegalAccessException | ClassNotFoundException | NoSuchFieldException ex) { 59 | throw new ExceptionInInitializerError(ex); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /common/src/main/java/dev/xdark/asminline/BlocksCollector.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.asminline; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.ClassWriter; 5 | import org.objectweb.asm.MethodVisitor; 6 | import org.objectweb.asm.Opcodes; 7 | 8 | import java.lang.reflect.Modifier; 9 | import java.util.Map; 10 | 11 | final class BlocksCollector extends ClassVisitor { 12 | 13 | private final Map writers; 14 | private int version; 15 | private String name; 16 | 17 | public BlocksCollector( 18 | Map writers) { 19 | super(Opcodes.ASM9); 20 | this.writers = writers; 21 | } 22 | 23 | @Override 24 | public void visit(int version, int access, String name, String signature, String superName, 25 | String[] interfaces) { 26 | this.version = version; 27 | this.name = name; 28 | } 29 | 30 | @Override 31 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, 32 | String[] exceptions) { 33 | if (Modifier.isStatic(access) && Constants.BLOCK_TYPE_DESC.equals(descriptor)) { 34 | ClassWriter writer = new ClassWriter(0); 35 | writer.visit(version, Opcodes.ACC_PUBLIC, 36 | this.name + '$' + name + '$' + System.currentTimeMillis(), null, 37 | "java/lang/Object", null); 38 | MethodVisitor proxy = writer.visitMethod(access, name, descriptor, signature, exceptions); 39 | writers.put(new MethodInfo(name, descriptor), writer); 40 | return proxy; 41 | } 42 | return null; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /common/src/main/java/dev/xdark/asminline/Constants.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.asminline; 2 | 3 | import java.lang.invoke.MethodType; 4 | 5 | final class Constants { 6 | 7 | static final MethodType BLOCK_TYPE = MethodType.methodType(Void.TYPE, AsmBlock.class); 8 | static final String BLOCK_TYPE_DESC = BLOCK_TYPE.toMethodDescriptorString(); 9 | 10 | private Constants() { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /common/src/main/java/dev/xdark/asminline/LoaderBoundClassWriter.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.asminline; 2 | 3 | import org.objectweb.asm.ClassReader; 4 | import org.objectweb.asm.ClassWriter; 5 | 6 | final class LoaderBoundClassWriter extends ClassWriter { 7 | 8 | private final ClassLoader loader; 9 | 10 | public LoaderBoundClassWriter(int flags, ClassLoader loader) { 11 | super(flags); 12 | this.loader = loader; 13 | } 14 | 15 | public LoaderBoundClassWriter(ClassReader classReader, int flags, ClassLoader loader) { 16 | super(classReader, flags); 17 | this.loader = loader; 18 | } 19 | 20 | @Override 21 | protected ClassLoader getClassLoader() { 22 | return loader; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /common/src/main/java/dev/xdark/asminline/LookupUtil.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.asminline; 2 | 3 | import java.lang.invoke.MethodHandles.Lookup; 4 | import java.lang.reflect.Field; 5 | 6 | public final class LookupUtil { 7 | 8 | private static final Lookup LOOKUP; 9 | 10 | private LookupUtil() { 11 | } 12 | 13 | public static Lookup lookup() { 14 | return LOOKUP; 15 | } 16 | 17 | static { 18 | try { 19 | Field field = Lookup.class.getDeclaredField("IMPL_LOOKUP"); 20 | field.setAccessible(true); 21 | LOOKUP = (Lookup) field.get(null); 22 | } catch (IllegalAccessException | NoSuchFieldException ex) { 23 | throw new ExceptionInInitializerError(ex); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /common/src/main/java/dev/xdark/asminline/MethodInfo.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.asminline; 2 | 3 | import java.util.Objects; 4 | 5 | final class MethodInfo { 6 | 7 | final String name; 8 | final String desc; 9 | 10 | MethodInfo(String name, String desc) { 11 | this.name = name; 12 | this.desc = desc; 13 | } 14 | 15 | @Override 16 | public boolean equals(Object o) { 17 | if (this == o) { 18 | return true; 19 | } 20 | if (!(o instanceof MethodInfo)) { 21 | return false; 22 | } 23 | 24 | MethodInfo that = (MethodInfo) o; 25 | 26 | if (!Objects.equals(name, that.name)) { 27 | return false; 28 | } 29 | return Objects.equals(desc, that.desc); 30 | } 31 | 32 | @Override 33 | public int hashCode() { 34 | int result = name != null ? name.hashCode() : 0; 35 | result = 31 * result + (desc != null ? desc.hashCode() : 0); 36 | return result; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /common/src/main/java/dev/xdark/asminline/PatchProcessor.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.asminline; 2 | 3 | import org.objectweb.asm.ClassReader; 4 | import org.objectweb.asm.ClassWriter; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | import java.net.URI; 9 | import java.nio.file.FileSystem; 10 | import java.nio.file.FileSystems; 11 | import java.nio.file.FileVisitResult; 12 | import java.nio.file.Files; 13 | import java.nio.file.Path; 14 | import java.nio.file.SimpleFileVisitor; 15 | import java.nio.file.StandardOpenOption; 16 | import java.nio.file.attribute.BasicFileAttributes; 17 | import java.util.Collections; 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | 21 | public final class PatchProcessor { 22 | private final int writeFlags; 23 | 24 | public PatchProcessor(int writeFlags) { 25 | this.writeFlags = writeFlags; 26 | } 27 | 28 | public byte[] processBytes(ClassLoader loader, byte[] bytes) { 29 | ClassReader reader = new ClassReader(bytes); 30 | Map methods = new HashMap<>(); 31 | reader.accept(new BlocksCollector(methods), 0); 32 | if (methods.isEmpty()) { 33 | return bytes; 34 | } 35 | ClassWriter rewriter = new ClassWriter(reader, 0); 36 | AsmInliner inliner = new AsmInliner(rewriter, loader, methods); 37 | reader.accept(inliner, 0); 38 | if (inliner.rewrite) { 39 | ClassWriter writer = new LoaderBoundClassWriter(writeFlags, loader); 40 | AsmUtil.copySymbolTable(rewriter, writer); 41 | new ClassReader(rewriter.toByteArray()).accept(writer, 0); 42 | return writer.toByteArray(); 43 | } 44 | return bytes; 45 | } 46 | 47 | public void processDirectoryTree(ClassLoader loader, Path dir) throws IOException { 48 | Files.walkFileTree(dir, new SimpleFileVisitor() { 49 | @Override 50 | public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { 51 | FileVisitResult result = super.visitFile(file, attrs); 52 | if (file.getFileName().toString().endsWith(".class")) { 53 | byte[] bytes = Files.readAllBytes(file); 54 | byte[] rewrite = processBytes(loader, bytes); 55 | if (rewrite != bytes) { 56 | Files.write(file, rewrite, StandardOpenOption.TRUNCATE_EXISTING); 57 | } 58 | } 59 | return result; 60 | } 61 | }); 62 | } 63 | 64 | public void processFileSystem(ClassLoader loader, FileSystem fs) throws IOException { 65 | processDirectoryTree(loader, fs.getPath("/")); 66 | } 67 | 68 | public void processURI(ClassLoader loader, URI uri) throws IOException { 69 | try (FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap())) { 70 | processFileSystem(loader, fs); 71 | } 72 | } 73 | 74 | public void processArchive(ClassLoader loader, Path archive) throws IOException { 75 | processURI(loader, archive.toUri()); 76 | } 77 | 78 | public void processArchive(ClassLoader loader, File archive) throws IOException { 79 | processURI(loader, archive.toPath().toUri()); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /common/src/main/java/dev/xdark/asminline/VersionUtil.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.asminline; 2 | 3 | final class VersionUtil { 4 | 5 | static final boolean java9; 6 | 7 | private VersionUtil() { 8 | } 9 | 10 | static { 11 | boolean j9; 12 | try { 13 | Class.forName("jdk.internal.reflect.MagicAccessorImpl", true, null); 14 | Class.forName("jdk.internal.misc.Unsafe", true, null); 15 | j9 = true; 16 | } catch (ClassNotFoundException ignored) { 17 | j9 = false; 18 | } 19 | java9 = j9; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /common/src/main/java/dev/xdark/asminline/VisitingAsmBlock.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.asminline; 2 | 3 | import org.objectweb.asm.ConstantDynamic; 4 | import org.objectweb.asm.Handle; 5 | import org.objectweb.asm.Label; 6 | import org.objectweb.asm.MethodVisitor; 7 | import org.objectweb.asm.Type; 8 | 9 | import java.lang.invoke.MethodType; 10 | 11 | import static org.objectweb.asm.Opcodes.AALOAD; 12 | import static org.objectweb.asm.Opcodes.AASTORE; 13 | import static org.objectweb.asm.Opcodes.ACONST_NULL; 14 | import static org.objectweb.asm.Opcodes.ALOAD; 15 | import static org.objectweb.asm.Opcodes.ANEWARRAY; 16 | import static org.objectweb.asm.Opcodes.ARETURN; 17 | import static org.objectweb.asm.Opcodes.ARRAYLENGTH; 18 | import static org.objectweb.asm.Opcodes.ASTORE; 19 | import static org.objectweb.asm.Opcodes.ATHROW; 20 | import static org.objectweb.asm.Opcodes.BALOAD; 21 | import static org.objectweb.asm.Opcodes.BASTORE; 22 | import static org.objectweb.asm.Opcodes.BIPUSH; 23 | import static org.objectweb.asm.Opcodes.CALOAD; 24 | import static org.objectweb.asm.Opcodes.CASTORE; 25 | import static org.objectweb.asm.Opcodes.CHECKCAST; 26 | import static org.objectweb.asm.Opcodes.D2F; 27 | import static org.objectweb.asm.Opcodes.D2I; 28 | import static org.objectweb.asm.Opcodes.D2L; 29 | import static org.objectweb.asm.Opcodes.DADD; 30 | import static org.objectweb.asm.Opcodes.DALOAD; 31 | import static org.objectweb.asm.Opcodes.DASTORE; 32 | import static org.objectweb.asm.Opcodes.DCMPG; 33 | import static org.objectweb.asm.Opcodes.DCMPL; 34 | import static org.objectweb.asm.Opcodes.DDIV; 35 | import static org.objectweb.asm.Opcodes.DLOAD; 36 | import static org.objectweb.asm.Opcodes.DMUL; 37 | import static org.objectweb.asm.Opcodes.DNEG; 38 | import static org.objectweb.asm.Opcodes.DREM; 39 | import static org.objectweb.asm.Opcodes.DRETURN; 40 | import static org.objectweb.asm.Opcodes.DSTORE; 41 | import static org.objectweb.asm.Opcodes.DSUB; 42 | import static org.objectweb.asm.Opcodes.DUP; 43 | import static org.objectweb.asm.Opcodes.DUP2; 44 | import static org.objectweb.asm.Opcodes.DUP2_X1; 45 | import static org.objectweb.asm.Opcodes.DUP2_X2; 46 | import static org.objectweb.asm.Opcodes.DUP_X1; 47 | import static org.objectweb.asm.Opcodes.DUP_X2; 48 | import static org.objectweb.asm.Opcodes.F2D; 49 | import static org.objectweb.asm.Opcodes.F2I; 50 | import static org.objectweb.asm.Opcodes.F2L; 51 | import static org.objectweb.asm.Opcodes.FADD; 52 | import static org.objectweb.asm.Opcodes.FALOAD; 53 | import static org.objectweb.asm.Opcodes.FASTORE; 54 | import static org.objectweb.asm.Opcodes.FCMPG; 55 | import static org.objectweb.asm.Opcodes.FCMPL; 56 | import static org.objectweb.asm.Opcodes.FDIV; 57 | import static org.objectweb.asm.Opcodes.FLOAD; 58 | import static org.objectweb.asm.Opcodes.FMUL; 59 | import static org.objectweb.asm.Opcodes.FNEG; 60 | import static org.objectweb.asm.Opcodes.FREM; 61 | import static org.objectweb.asm.Opcodes.FRETURN; 62 | import static org.objectweb.asm.Opcodes.FSTORE; 63 | import static org.objectweb.asm.Opcodes.FSUB; 64 | import static org.objectweb.asm.Opcodes.GETFIELD; 65 | import static org.objectweb.asm.Opcodes.GETSTATIC; 66 | import static org.objectweb.asm.Opcodes.GOTO; 67 | import static org.objectweb.asm.Opcodes.I2B; 68 | import static org.objectweb.asm.Opcodes.I2C; 69 | import static org.objectweb.asm.Opcodes.I2D; 70 | import static org.objectweb.asm.Opcodes.I2F; 71 | import static org.objectweb.asm.Opcodes.I2L; 72 | import static org.objectweb.asm.Opcodes.I2S; 73 | import static org.objectweb.asm.Opcodes.IADD; 74 | import static org.objectweb.asm.Opcodes.IALOAD; 75 | import static org.objectweb.asm.Opcodes.IAND; 76 | import static org.objectweb.asm.Opcodes.IASTORE; 77 | import static org.objectweb.asm.Opcodes.IDIV; 78 | import static org.objectweb.asm.Opcodes.IFEQ; 79 | import static org.objectweb.asm.Opcodes.IFGE; 80 | import static org.objectweb.asm.Opcodes.IFGT; 81 | import static org.objectweb.asm.Opcodes.IFLE; 82 | import static org.objectweb.asm.Opcodes.IFLT; 83 | import static org.objectweb.asm.Opcodes.IFNE; 84 | import static org.objectweb.asm.Opcodes.IFNONNULL; 85 | import static org.objectweb.asm.Opcodes.IFNULL; 86 | import static org.objectweb.asm.Opcodes.IF_ACMPEQ; 87 | import static org.objectweb.asm.Opcodes.IF_ACMPNE; 88 | import static org.objectweb.asm.Opcodes.IF_ICMPEQ; 89 | import static org.objectweb.asm.Opcodes.IF_ICMPGE; 90 | import static org.objectweb.asm.Opcodes.IF_ICMPGT; 91 | import static org.objectweb.asm.Opcodes.IF_ICMPLE; 92 | import static org.objectweb.asm.Opcodes.IF_ICMPLT; 93 | import static org.objectweb.asm.Opcodes.IF_ICMPNE; 94 | import static org.objectweb.asm.Opcodes.ILOAD; 95 | import static org.objectweb.asm.Opcodes.IMUL; 96 | import static org.objectweb.asm.Opcodes.INEG; 97 | import static org.objectweb.asm.Opcodes.INSTANCEOF; 98 | import static org.objectweb.asm.Opcodes.INVOKEINTERFACE; 99 | import static org.objectweb.asm.Opcodes.INVOKESPECIAL; 100 | import static org.objectweb.asm.Opcodes.INVOKESTATIC; 101 | import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; 102 | import static org.objectweb.asm.Opcodes.IOR; 103 | import static org.objectweb.asm.Opcodes.IREM; 104 | import static org.objectweb.asm.Opcodes.IRETURN; 105 | import static org.objectweb.asm.Opcodes.ISHL; 106 | import static org.objectweb.asm.Opcodes.ISHR; 107 | import static org.objectweb.asm.Opcodes.ISTORE; 108 | import static org.objectweb.asm.Opcodes.ISUB; 109 | import static org.objectweb.asm.Opcodes.IUSHR; 110 | import static org.objectweb.asm.Opcodes.IXOR; 111 | import static org.objectweb.asm.Opcodes.L2D; 112 | import static org.objectweb.asm.Opcodes.L2F; 113 | import static org.objectweb.asm.Opcodes.L2I; 114 | import static org.objectweb.asm.Opcodes.LADD; 115 | import static org.objectweb.asm.Opcodes.LALOAD; 116 | import static org.objectweb.asm.Opcodes.LAND; 117 | import static org.objectweb.asm.Opcodes.LASTORE; 118 | import static org.objectweb.asm.Opcodes.LCMP; 119 | import static org.objectweb.asm.Opcodes.LDIV; 120 | import static org.objectweb.asm.Opcodes.LLOAD; 121 | import static org.objectweb.asm.Opcodes.LMUL; 122 | import static org.objectweb.asm.Opcodes.LNEG; 123 | import static org.objectweb.asm.Opcodes.LOR; 124 | import static org.objectweb.asm.Opcodes.LREM; 125 | import static org.objectweb.asm.Opcodes.LRETURN; 126 | import static org.objectweb.asm.Opcodes.LSHL; 127 | import static org.objectweb.asm.Opcodes.LSHR; 128 | import static org.objectweb.asm.Opcodes.LSTORE; 129 | import static org.objectweb.asm.Opcodes.LSUB; 130 | import static org.objectweb.asm.Opcodes.LUSHR; 131 | import static org.objectweb.asm.Opcodes.LXOR; 132 | import static org.objectweb.asm.Opcodes.MONITORENTER; 133 | import static org.objectweb.asm.Opcodes.MONITOREXIT; 134 | import static org.objectweb.asm.Opcodes.NEW; 135 | import static org.objectweb.asm.Opcodes.NEWARRAY; 136 | import static org.objectweb.asm.Opcodes.NOP; 137 | import static org.objectweb.asm.Opcodes.POP; 138 | import static org.objectweb.asm.Opcodes.POP2; 139 | import static org.objectweb.asm.Opcodes.PUTFIELD; 140 | import static org.objectweb.asm.Opcodes.PUTSTATIC; 141 | import static org.objectweb.asm.Opcodes.RETURN; 142 | import static org.objectweb.asm.Opcodes.SALOAD; 143 | import static org.objectweb.asm.Opcodes.SASTORE; 144 | import static org.objectweb.asm.Opcodes.SIPUSH; 145 | import static org.objectweb.asm.Opcodes.SWAP; 146 | import static org.objectweb.asm.Opcodes.T_BOOLEAN; 147 | import static org.objectweb.asm.Opcodes.T_BYTE; 148 | import static org.objectweb.asm.Opcodes.T_CHAR; 149 | import static org.objectweb.asm.Opcodes.T_DOUBLE; 150 | import static org.objectweb.asm.Opcodes.T_FLOAT; 151 | import static org.objectweb.asm.Opcodes.T_INT; 152 | import static org.objectweb.asm.Opcodes.T_LONG; 153 | import static org.objectweb.asm.Opcodes.T_SHORT; 154 | 155 | public final class VisitingAsmBlock implements AsmBlock { 156 | 157 | private final MethodVisitor visitor; 158 | 159 | public VisitingAsmBlock(MethodVisitor visitor) { 160 | this.visitor = visitor; 161 | } 162 | 163 | @Override 164 | public AsmBlock nop() { 165 | return visitInsn(NOP); 166 | } 167 | 168 | @Override 169 | public AsmBlock $null() { 170 | return visitInsn(ACONST_NULL); 171 | } 172 | 173 | @Override 174 | public AsmBlock $int(int value) { 175 | MethodVisitor visitor = this.visitor; 176 | if (value >= -1 && value <= 5) { 177 | visitor.visitInsn(value + 3); 178 | } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { 179 | visitor.visitIntInsn(BIPUSH, value); 180 | } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { 181 | visitor.visitIntInsn(SIPUSH, value); 182 | } else { 183 | visitor.visitLdcInsn(value); 184 | } 185 | return this; 186 | } 187 | 188 | @Override 189 | public AsmBlock $long(long value) { 190 | MethodVisitor visitor = this.visitor; 191 | if (value == 0L || value == 1L) { 192 | visitor.visitInsn((int) (value + 9)); 193 | } else { 194 | visitor.visitLdcInsn(value); 195 | } 196 | return this; 197 | } 198 | 199 | @Override 200 | public AsmBlock $float(float value) { 201 | MethodVisitor visitor = this.visitor; 202 | if (value == 0.0F || value == 1.0F || value == 2.0F) { 203 | visitor.visitInsn((int) value + 11); 204 | } else { 205 | visitor.visitLdcInsn(value); 206 | } 207 | return this; 208 | } 209 | 210 | @Override 211 | public AsmBlock $double(double value) { 212 | MethodVisitor visitor = this.visitor; 213 | if (value == 0.0 || value == 1.0) { 214 | visitor.visitInsn((int) value + 14); 215 | } else { 216 | visitor.visitLdcInsn(value); 217 | } 218 | return this; 219 | } 220 | 221 | @Override 222 | public AsmBlock ldc(String value) { 223 | return visitLdcInsn(value); 224 | } 225 | 226 | @Override 227 | public AsmBlock ldc(Class type) { 228 | return visitLdcInsn(Type.getType(type)); 229 | } 230 | 231 | @Override 232 | public AsmBlock ldc(Type type) { 233 | return visitLdcInsn(type); 234 | } 235 | 236 | @Override 237 | public AsmBlock ldc(MethodType type) { 238 | Class[] $parameters = type.parameterArray(); 239 | int j = $parameters.length; 240 | Type[] parameters = new Type[j]; 241 | while (j-- > 0) { 242 | parameters[j] = Type.getType($parameters[j]); 243 | } 244 | return visitLdcInsn(Type.getMethodType(Type.getType(type.returnType()), parameters)); 245 | } 246 | 247 | @Override 248 | public AsmBlock ldc(Handle handle) { 249 | return visitLdcInsn(handle); 250 | } 251 | 252 | @Override 253 | public AsmBlock ldc(ConstantDynamic constantDynamic) { 254 | return visitLdcInsn(constantDynamic); 255 | } 256 | 257 | @Override 258 | public AsmBlock iload(int idx) { 259 | return visitVarInsn(ILOAD, idx); 260 | } 261 | 262 | @Override 263 | public AsmBlock lload(int idx) { 264 | return visitVarInsn(LLOAD, idx); 265 | } 266 | 267 | @Override 268 | public AsmBlock fload(int idx) { 269 | return visitVarInsn(FLOAD, idx); 270 | } 271 | 272 | @Override 273 | public AsmBlock dload(int idx) { 274 | return visitVarInsn(DLOAD, idx); 275 | } 276 | 277 | @Override 278 | public AsmBlock aload(int idx) { 279 | return visitVarInsn(ALOAD, idx); 280 | } 281 | 282 | @Override 283 | public AsmBlock iaload() { 284 | return visitInsn(IALOAD); 285 | } 286 | 287 | @Override 288 | public AsmBlock laload() { 289 | return visitInsn(LALOAD); 290 | } 291 | 292 | @Override 293 | public AsmBlock faload() { 294 | return visitInsn(FALOAD); 295 | } 296 | 297 | @Override 298 | public AsmBlock daload() { 299 | return visitInsn(DALOAD); 300 | } 301 | 302 | @Override 303 | public AsmBlock aaload() { 304 | return visitInsn(AALOAD); 305 | } 306 | 307 | @Override 308 | public AsmBlock baload() { 309 | return visitInsn(BALOAD); 310 | } 311 | 312 | @Override 313 | public AsmBlock caload() { 314 | return visitInsn(CALOAD); 315 | } 316 | 317 | @Override 318 | public AsmBlock saload() { 319 | return visitInsn(SALOAD); 320 | } 321 | 322 | @Override 323 | public AsmBlock istore(int idx) { 324 | return visitVarInsn(ISTORE, idx); 325 | } 326 | 327 | @Override 328 | public AsmBlock lstore(int idx) { 329 | return visitVarInsn(LSTORE, idx); 330 | } 331 | 332 | @Override 333 | public AsmBlock fstore(int idx) { 334 | return visitVarInsn(FSTORE, idx); 335 | } 336 | 337 | @Override 338 | public AsmBlock dstore(int idx) { 339 | return visitVarInsn(DSTORE, idx); 340 | } 341 | 342 | @Override 343 | public AsmBlock astore(int idx) { 344 | return visitVarInsn(ASTORE, idx); 345 | } 346 | 347 | @Override 348 | public AsmBlock iastore() { 349 | return visitInsn(IASTORE); 350 | } 351 | 352 | @Override 353 | public AsmBlock lastore() { 354 | return visitInsn(LASTORE); 355 | } 356 | 357 | @Override 358 | public AsmBlock fastore() { 359 | return visitInsn(FASTORE); 360 | } 361 | 362 | @Override 363 | public AsmBlock dastore() { 364 | return visitInsn(DASTORE); 365 | } 366 | 367 | @Override 368 | public AsmBlock aastore() { 369 | return visitInsn(AASTORE); 370 | } 371 | 372 | @Override 373 | public AsmBlock bastore() { 374 | return visitInsn(BASTORE); 375 | } 376 | 377 | @Override 378 | public AsmBlock castore() { 379 | return visitInsn(CASTORE); 380 | } 381 | 382 | @Override 383 | public AsmBlock sastore() { 384 | return visitInsn(SASTORE); 385 | } 386 | 387 | @Override 388 | public AsmBlock pop() { 389 | return visitInsn(POP); 390 | } 391 | 392 | @Override 393 | public AsmBlock pop2() { 394 | return visitInsn(POP2); 395 | } 396 | 397 | @Override 398 | public AsmBlock dup() { 399 | return visitInsn(DUP); 400 | } 401 | 402 | @Override 403 | public AsmBlock dupx1() { 404 | return visitInsn(DUP_X1); 405 | } 406 | 407 | @Override 408 | public AsmBlock dupx2() { 409 | return visitInsn(DUP_X2); 410 | } 411 | 412 | @Override 413 | public AsmBlock dup2() { 414 | return visitInsn(DUP2); 415 | } 416 | 417 | @Override 418 | public AsmBlock dup2x1() { 419 | return visitInsn(DUP2_X1); 420 | } 421 | 422 | @Override 423 | public AsmBlock dup2x2() { 424 | return visitInsn(DUP2_X2); 425 | } 426 | 427 | @Override 428 | public AsmBlock swap() { 429 | return visitInsn(SWAP); 430 | } 431 | 432 | @Override 433 | public AsmBlock iadd() { 434 | return visitInsn(IADD); 435 | } 436 | 437 | @Override 438 | public AsmBlock ladd() { 439 | return visitInsn(LADD); 440 | } 441 | 442 | @Override 443 | public AsmBlock fadd() { 444 | return visitInsn(FADD); 445 | } 446 | 447 | @Override 448 | public AsmBlock dadd() { 449 | return visitInsn(DADD); 450 | } 451 | 452 | @Override 453 | public AsmBlock isub() { 454 | return visitInsn(ISUB); 455 | } 456 | 457 | @Override 458 | public AsmBlock lsub() { 459 | return visitInsn(LSUB); 460 | } 461 | 462 | @Override 463 | public AsmBlock fsub() { 464 | return visitInsn(FSUB); 465 | } 466 | 467 | @Override 468 | public AsmBlock dsub() { 469 | return visitInsn(DSUB); 470 | } 471 | 472 | @Override 473 | public AsmBlock imul() { 474 | return visitInsn(IMUL); 475 | } 476 | 477 | @Override 478 | public AsmBlock lmul() { 479 | return visitInsn(LMUL); 480 | } 481 | 482 | @Override 483 | public AsmBlock fmul() { 484 | return visitInsn(FMUL); 485 | } 486 | 487 | @Override 488 | public AsmBlock dmul() { 489 | return visitInsn(DMUL); 490 | } 491 | 492 | @Override 493 | public AsmBlock idiv() { 494 | return visitInsn(IDIV); 495 | } 496 | 497 | @Override 498 | public AsmBlock ldiv() { 499 | return visitInsn(LDIV); 500 | } 501 | 502 | @Override 503 | public AsmBlock fdiv() { 504 | return visitInsn(FDIV); 505 | } 506 | 507 | @Override 508 | public AsmBlock ddiv() { 509 | return visitInsn(DDIV); 510 | } 511 | 512 | @Override 513 | public AsmBlock irem() { 514 | return visitInsn(IREM); 515 | } 516 | 517 | @Override 518 | public AsmBlock lrem() { 519 | return visitInsn(LREM); 520 | } 521 | 522 | @Override 523 | public AsmBlock frem() { 524 | return visitInsn(FREM); 525 | } 526 | 527 | @Override 528 | public AsmBlock drem() { 529 | return visitInsn(DREM); 530 | } 531 | 532 | @Override 533 | public AsmBlock ineg() { 534 | return visitInsn(INEG); 535 | } 536 | 537 | @Override 538 | public AsmBlock lneg() { 539 | return visitInsn(LNEG); 540 | } 541 | 542 | @Override 543 | public AsmBlock fneg() { 544 | return visitInsn(FNEG); 545 | } 546 | 547 | @Override 548 | public AsmBlock dneg() { 549 | return visitInsn(DNEG); 550 | } 551 | 552 | @Override 553 | public AsmBlock ishl() { 554 | return visitInsn(ISHL); 555 | } 556 | 557 | @Override 558 | public AsmBlock lshl() { 559 | return visitInsn(LSHL); 560 | } 561 | 562 | @Override 563 | public AsmBlock ishr() { 564 | return visitInsn(ISHR); 565 | } 566 | 567 | @Override 568 | public AsmBlock lshr() { 569 | return visitInsn(LSHR); 570 | } 571 | 572 | @Override 573 | public AsmBlock iushr() { 574 | return visitInsn(IUSHR); 575 | } 576 | 577 | @Override 578 | public AsmBlock lushr() { 579 | return visitInsn(LUSHR); 580 | } 581 | 582 | @Override 583 | public AsmBlock iand() { 584 | return visitInsn(IAND); 585 | } 586 | 587 | @Override 588 | public AsmBlock land() { 589 | return visitInsn(LAND); 590 | } 591 | 592 | @Override 593 | public AsmBlock ior() { 594 | return visitInsn(IOR); 595 | } 596 | 597 | @Override 598 | public AsmBlock lor() { 599 | return visitInsn(LOR); 600 | } 601 | 602 | @Override 603 | public AsmBlock ixor() { 604 | return visitInsn(IXOR); 605 | } 606 | 607 | @Override 608 | public AsmBlock lxor() { 609 | return visitInsn(LXOR); 610 | } 611 | 612 | @Override 613 | public AsmBlock iinc(int idx, int value) { 614 | visitor.visitIincInsn(idx, value); 615 | return this; 616 | } 617 | 618 | @Override 619 | public AsmBlock i2l() { 620 | return visitInsn(I2L); 621 | } 622 | 623 | @Override 624 | public AsmBlock i2f() { 625 | return visitInsn(I2F); 626 | } 627 | 628 | @Override 629 | public AsmBlock i2d() { 630 | return visitInsn(I2D); 631 | } 632 | 633 | @Override 634 | public AsmBlock l2i() { 635 | return visitInsn(L2I); 636 | } 637 | 638 | @Override 639 | public AsmBlock l2f() { 640 | return visitInsn(L2F); 641 | } 642 | 643 | @Override 644 | public AsmBlock l2d() { 645 | return visitInsn(L2D); 646 | } 647 | 648 | @Override 649 | public AsmBlock f2i() { 650 | return visitInsn(F2I); 651 | } 652 | 653 | @Override 654 | public AsmBlock f2l() { 655 | return visitInsn(F2L); 656 | } 657 | 658 | @Override 659 | public AsmBlock f2d() { 660 | return visitInsn(F2D); 661 | } 662 | 663 | @Override 664 | public AsmBlock d2i() { 665 | return visitInsn(D2I); 666 | } 667 | 668 | @Override 669 | public AsmBlock d2l() { 670 | return visitInsn(D2L); 671 | } 672 | 673 | @Override 674 | public AsmBlock d2f() { 675 | return visitInsn(D2F); 676 | } 677 | 678 | @Override 679 | public AsmBlock i2b() { 680 | return visitInsn(I2B); 681 | } 682 | 683 | @Override 684 | public AsmBlock i2c() { 685 | return visitInsn(I2C); 686 | } 687 | 688 | @Override 689 | public AsmBlock i2s() { 690 | return visitInsn(I2S); 691 | } 692 | 693 | @Override 694 | public AsmBlock lcmp() { 695 | return visitInsn(LCMP); 696 | } 697 | 698 | @Override 699 | public AsmBlock fcmpl() { 700 | return visitInsn(FCMPL); 701 | } 702 | 703 | @Override 704 | public AsmBlock fcmpg() { 705 | return visitInsn(FCMPG); 706 | } 707 | 708 | @Override 709 | public AsmBlock dcmpl() { 710 | return visitInsn(DCMPL); 711 | } 712 | 713 | @Override 714 | public AsmBlock dcmpg() { 715 | return visitInsn(DCMPG); 716 | } 717 | 718 | @Override 719 | public AsmBlock ifeq(Label label) { 720 | return visitJumpInsn(IFEQ, label); 721 | } 722 | 723 | @Override 724 | public AsmBlock ifne(Label label) { 725 | return visitJumpInsn(IFNE, label); 726 | } 727 | 728 | @Override 729 | public AsmBlock iflt(Label label) { 730 | return visitJumpInsn(IFLT, label); 731 | } 732 | 733 | @Override 734 | public AsmBlock ifge(Label label) { 735 | return visitJumpInsn(IFGE, label); 736 | } 737 | 738 | @Override 739 | public AsmBlock ifgt(Label label) { 740 | return visitJumpInsn(IFGT, label); 741 | } 742 | 743 | @Override 744 | public AsmBlock ifle(Label label) { 745 | return visitJumpInsn(IFLE, label); 746 | } 747 | 748 | @Override 749 | public AsmBlock icmpeq(Label label) { 750 | return visitJumpInsn(IF_ICMPEQ, label); 751 | } 752 | 753 | @Override 754 | public AsmBlock icmpne(Label label) { 755 | return visitJumpInsn(IF_ICMPNE, label); 756 | } 757 | 758 | @Override 759 | public AsmBlock icmplt(Label label) { 760 | return visitJumpInsn(IF_ICMPLT, label); 761 | } 762 | 763 | @Override 764 | public AsmBlock icmpge(Label label) { 765 | return visitJumpInsn(IF_ICMPGE, label); 766 | } 767 | 768 | @Override 769 | public AsmBlock icmpgt(Label label) { 770 | return visitJumpInsn(IF_ICMPGT, label); 771 | } 772 | 773 | @Override 774 | public AsmBlock icmple(Label label) { 775 | return visitJumpInsn(IF_ICMPLE, label); 776 | } 777 | 778 | @Override 779 | public AsmBlock acmpeq(Label label) { 780 | return visitJumpInsn(IF_ACMPEQ, label); 781 | } 782 | 783 | @Override 784 | public AsmBlock acmpne(Label label) { 785 | return visitJumpInsn(IF_ACMPNE, label); 786 | } 787 | 788 | @Override 789 | public AsmBlock $goto(Label label) { 790 | return visitJumpInsn(GOTO, label); 791 | } 792 | 793 | @Override 794 | public AsmBlock tableswitch(int min, int max, Label dflt, Label... labels) { 795 | visitor.visitTableSwitchInsn(min, max, dflt, labels); 796 | return this; 797 | } 798 | 799 | @Override 800 | public AsmBlock lookupswitch(int[] keys, Label dflt, Label... labels) { 801 | visitor.visitLookupSwitchInsn(dflt, keys, labels); 802 | return this; 803 | } 804 | 805 | @Override 806 | public AsmBlock ireturn() { 807 | return visitInsn(IRETURN); 808 | } 809 | 810 | @Override 811 | public AsmBlock lreturn() { 812 | return visitInsn(LRETURN); 813 | } 814 | 815 | @Override 816 | public AsmBlock freturn() { 817 | return visitInsn(FRETURN); 818 | } 819 | 820 | @Override 821 | public AsmBlock dreturn() { 822 | return visitInsn(DRETURN); 823 | } 824 | 825 | @Override 826 | public AsmBlock areturn() { 827 | return visitInsn(ARETURN); 828 | } 829 | 830 | @Override 831 | public AsmBlock $return() { 832 | return visitInsn(RETURN); 833 | } 834 | 835 | @Override 836 | public AsmBlock getstatic(String owner, String name, String desc) { 837 | visitor.visitFieldInsn(GETSTATIC, owner, name, desc); 838 | return this; 839 | } 840 | 841 | @Override 842 | public AsmBlock putstatic(String owner, String name, String desc) { 843 | visitor.visitFieldInsn(PUTSTATIC, owner, name, desc); 844 | return this; 845 | } 846 | 847 | @Override 848 | public AsmBlock getfield(String owner, String name, String desc) { 849 | visitor.visitFieldInsn(GETFIELD, owner, name, desc); 850 | return this; 851 | } 852 | 853 | @Override 854 | public AsmBlock putfield(String owner, String name, String desc) { 855 | visitor.visitFieldInsn(PUTFIELD, owner, name, desc); 856 | return this; 857 | } 858 | 859 | @Override 860 | public AsmBlock getstatic(Class owner, String name, String desc) { 861 | return getstatic(internalName(owner), name, desc); 862 | } 863 | 864 | @Override 865 | public AsmBlock putstatic(Class owner, String name, String desc) { 866 | return putstatic(internalName(owner), name, desc); 867 | } 868 | 869 | @Override 870 | public AsmBlock getfield(Class owner, String name, String desc) { 871 | return getfield(internalName(owner), name, desc); 872 | } 873 | 874 | @Override 875 | public AsmBlock putfield(Class owner, String name, String desc) { 876 | return putfield(internalName(owner), name, desc); 877 | } 878 | 879 | @Override 880 | public AsmBlock getstatic(String owner, String name, Class desc) { 881 | return getstatic(owner, name, fieldDescriptor(desc)); 882 | } 883 | 884 | @Override 885 | public AsmBlock putstatic(String owner, String name, Class desc) { 886 | return putstatic(owner, name, fieldDescriptor(desc)); 887 | } 888 | 889 | @Override 890 | public AsmBlock getfield(String owner, String name, Class desc) { 891 | return getfield(owner, name, fieldDescriptor(desc)); 892 | } 893 | 894 | @Override 895 | public AsmBlock putfield(String owner, String name, Class desc) { 896 | return putfield(owner, name, fieldDescriptor(desc)); 897 | } 898 | 899 | @Override 900 | public AsmBlock getstatic(Class owner, String name, Class desc) { 901 | return getstatic(internalName(owner), name, fieldDescriptor(desc)); 902 | } 903 | 904 | @Override 905 | public AsmBlock putstatic(Class owner, String name, Class desc) { 906 | return putstatic(internalName(owner), name, fieldDescriptor(desc)); 907 | } 908 | 909 | @Override 910 | public AsmBlock getfield(Class owner, String name, Class desc) { 911 | return getfield(internalName(owner), name, fieldDescriptor(desc)); 912 | } 913 | 914 | @Override 915 | public AsmBlock putfield(Class owner, String name, Class desc) { 916 | return putfield(internalName(owner), name, fieldDescriptor(desc)); 917 | } 918 | 919 | @Override 920 | public AsmBlock invokevirtual(String owner, String name, String desc) { 921 | visitor.visitMethodInsn(INVOKEVIRTUAL, owner, name, desc, false); 922 | return this; 923 | } 924 | 925 | @Override 926 | public AsmBlock invokespecial(String owner, String name, String desc) { 927 | visitor.visitMethodInsn(INVOKESPECIAL, owner, name, desc, false); 928 | return this; 929 | } 930 | 931 | @Override 932 | public AsmBlock invokestatic(String owner, String name, String desc) { 933 | visitor.visitMethodInsn(INVOKESTATIC, owner, name, desc, false); 934 | return this; 935 | } 936 | 937 | @Override 938 | public AsmBlock invokeinterface(String owner, String name, String desc) { 939 | visitor.visitMethodInsn(INVOKEINTERFACE, owner, name, desc, true); 940 | return this; 941 | } 942 | 943 | @Override 944 | public AsmBlock invokevirtual(String owner, String name, MethodType type) { 945 | return invokevirtual(owner, name, type.toMethodDescriptorString()); 946 | } 947 | 948 | @Override 949 | public AsmBlock invokestatic(String owner, String name, MethodType type) { 950 | return invokestatic(owner, name, type.toMethodDescriptorString()); 951 | } 952 | 953 | @Override 954 | public AsmBlock invokeinterface(String owner, String name, MethodType type) { 955 | return invokeinterface(owner, name, type.toMethodDescriptorString()); 956 | } 957 | 958 | @Override 959 | public AsmBlock invokevirtual(Class owner, String name, String desc) { 960 | return invokevirtual(internalName(owner), name, desc); 961 | } 962 | 963 | @Override 964 | public AsmBlock invokespecial(Class owner, String name, String desc) { 965 | return invokespecial(internalName(owner), name, desc); 966 | } 967 | 968 | @Override 969 | public AsmBlock invokestatic(Class owner, String name, String desc) { 970 | return invokestatic(internalName(owner), name, desc); 971 | } 972 | 973 | @Override 974 | public AsmBlock invokevirtual(Class owner, String name, MethodType type) { 975 | return invokevirtual(internalName(owner), name, type.toMethodDescriptorString()); 976 | } 977 | 978 | @Override 979 | public AsmBlock invokespecial(Class owner, String name, MethodType type) { 980 | return invokespecial(internalName(owner), name, type.toMethodDescriptorString()); 981 | } 982 | 983 | @Override 984 | public AsmBlock invokestatic(Class owner, String name, MethodType type) { 985 | return invokestatic(internalName(owner), name, type.toMethodDescriptorString()); 986 | } 987 | 988 | @Override 989 | public AsmBlock invokeinterface(Class owner, String name, String desc) { 990 | return invokeinterface(internalName(owner), name, desc); 991 | } 992 | 993 | @Override 994 | public AsmBlock invokeinterface(Class owner, String name, MethodType type) { 995 | return invokeinterface(internalName(owner), name, type.toMethodDescriptorString()); 996 | } 997 | 998 | @Override 999 | public AsmBlock invokedynamic(String name, String desc, Handle bootstrap, Object... args) { 1000 | visitor.visitInvokeDynamicInsn(name, desc, bootstrap, args); 1001 | return this; 1002 | } 1003 | 1004 | @Override 1005 | public AsmBlock $new(String type) { 1006 | visitor.visitTypeInsn(NEW, type); 1007 | return this; 1008 | } 1009 | 1010 | @Override 1011 | public AsmBlock $new(Class type) { 1012 | visitor.visitTypeInsn(NEW, Type.getType(type).getInternalName()); 1013 | return this; 1014 | } 1015 | 1016 | @Override 1017 | public AsmBlock $new(Type type) { 1018 | visitor.visitTypeInsn(NEW, type.getInternalName()); 1019 | return this; 1020 | } 1021 | 1022 | @Override 1023 | public AsmBlock newarray(int type) { 1024 | visitor.visitIntInsn(NEWARRAY, type); 1025 | return this; 1026 | } 1027 | 1028 | @Override 1029 | public AsmBlock newarray(String type) { 1030 | visitor.visitTypeInsn(ANEWARRAY, type); 1031 | return this; 1032 | } 1033 | 1034 | @Override 1035 | public AsmBlock arraylength() { 1036 | return visitInsn(ARRAYLENGTH); 1037 | } 1038 | 1039 | @Override 1040 | public AsmBlock athrow() { 1041 | return visitInsn(ATHROW); 1042 | } 1043 | 1044 | @Override 1045 | public AsmBlock checkcast(String type) { 1046 | visitor.visitTypeInsn(CHECKCAST, type); 1047 | return this; 1048 | } 1049 | 1050 | @Override 1051 | public AsmBlock $instanceof(String type) { 1052 | visitor.visitTypeInsn(INSTANCEOF, type); 1053 | return this; 1054 | } 1055 | 1056 | @Override 1057 | public AsmBlock monitorenter() { 1058 | return visitInsn(MONITORENTER); 1059 | } 1060 | 1061 | @Override 1062 | public AsmBlock monitorexit() { 1063 | return visitInsn(MONITOREXIT); 1064 | } 1065 | 1066 | @Override 1067 | public AsmBlock multinewarray(String desc, int dimensions) { 1068 | visitor.visitMultiANewArrayInsn(desc, dimensions); 1069 | return this; 1070 | } 1071 | 1072 | @Override 1073 | public AsmBlock ifnull(Label label) { 1074 | return visitJumpInsn(IFNULL, label); 1075 | } 1076 | 1077 | @Override 1078 | public AsmBlock ifnonnull(Label label) { 1079 | return visitJumpInsn(IFNONNULL, label); 1080 | } 1081 | 1082 | @Override 1083 | public AsmBlock label(Label label) { 1084 | visitor.visitLabel(label); 1085 | return this; 1086 | } 1087 | 1088 | @Override 1089 | public AsmBlock $try(Label start, Label end, Label handler, String type) { 1090 | visitor.visitTryCatchBlock(start, end, handler, type); 1091 | return this; 1092 | } 1093 | 1094 | @Override 1095 | public AsmBlock line(int line, Label start) { 1096 | visitor.visitLineNumber(line, start); 1097 | return this; 1098 | } 1099 | 1100 | @Override 1101 | public AsmBlock parameter(String name, int access) { 1102 | visitor.visitParameter(name, access); 1103 | return this; 1104 | } 1105 | 1106 | @Override 1107 | public AsmBlock array(long[] array, int off, int len) { 1108 | newarray(T_LONG); 1109 | while (off < len) { 1110 | long v = array[off]; 1111 | dup().$int(off++).$long(v).lastore(); 1112 | } 1113 | return this; 1114 | } 1115 | 1116 | @Override 1117 | public AsmBlock array(double[] array, int off, int len) { 1118 | $int(len - off); 1119 | newarray(T_DOUBLE); 1120 | while (off < len) { 1121 | double v = array[off]; 1122 | dup().$int(off++).$double(v).dastore(); 1123 | } 1124 | return this; 1125 | } 1126 | 1127 | @Override 1128 | public AsmBlock array(int[] array, int off, int len) { 1129 | $int(len - off); 1130 | newarray(T_INT); 1131 | while (off < len) { 1132 | int v = array[off]; 1133 | dup().$int(off++).$int(v).iastore(); 1134 | } 1135 | return this; 1136 | } 1137 | 1138 | @Override 1139 | public AsmBlock array(float[] array, int off, int len) { 1140 | $int(len - off); 1141 | newarray(T_FLOAT); 1142 | while (off < len) { 1143 | float v = array[off]; 1144 | dup().$int(off++).$float(v).fastore(); 1145 | } 1146 | return this; 1147 | } 1148 | 1149 | @Override 1150 | public AsmBlock array(char[] array, int off, int len) { 1151 | $int(len - off); 1152 | newarray(T_CHAR); 1153 | while (off < len) { 1154 | char v = array[off]; 1155 | dup().$int(off++).$int(v).castore(); 1156 | } 1157 | return this; 1158 | } 1159 | 1160 | @Override 1161 | public AsmBlock array(short[] array, int off, int len) { 1162 | $int(len - off); 1163 | newarray(T_SHORT); 1164 | while (off < len) { 1165 | short v = array[off]; 1166 | dup().$int(off++).$int(v).sastore(); 1167 | } 1168 | return this; 1169 | } 1170 | 1171 | @Override 1172 | public AsmBlock array(byte[] array, int off, int len) { 1173 | $int(len - off); 1174 | newarray(T_BYTE); 1175 | while (off < len) { 1176 | byte v = array[off]; 1177 | dup().$int(off++).$int(v).bastore(); 1178 | } 1179 | return this; 1180 | } 1181 | 1182 | @Override 1183 | public AsmBlock array(boolean[] array, int off, int len) { 1184 | $int(len - off); 1185 | newarray(T_BOOLEAN); 1186 | while (off < len) { 1187 | boolean v = array[off]; 1188 | dup().$int(off++).$int(v ? 1 : 0).bastore(); 1189 | } 1190 | return this; 1191 | } 1192 | 1193 | @Override 1194 | public AsmBlock array(T[] array, int off, int len, BiIntConsumer producer) { 1195 | $int(len - off); 1196 | visitor.visitTypeInsn(ANEWARRAY, Type.getInternalName(array.getClass().getComponentType())); 1197 | while (off < len) { 1198 | T v = array[off]; 1199 | int idx = off++; 1200 | dup().$int(idx); 1201 | producer.accept(idx, v); 1202 | aastore(); 1203 | } 1204 | return this; 1205 | } 1206 | 1207 | @Override 1208 | public AsmBlock array(long[] array) { 1209 | $int(array.length); 1210 | newarray(T_LONG); 1211 | for (int i = 0, j = array.length; i < j; i++) { 1212 | long v = array[i]; 1213 | dup().$int(i).$long(v).lastore(); 1214 | } 1215 | return this; 1216 | } 1217 | 1218 | @Override 1219 | public AsmBlock array(double[] array) { 1220 | $int(array.length); 1221 | newarray(T_DOUBLE); 1222 | for (int i = 0, j = array.length; i < j; i++) { 1223 | double v = array[i]; 1224 | dup().$int(i).$double(v).dastore(); 1225 | } 1226 | return this; 1227 | } 1228 | 1229 | @Override 1230 | public AsmBlock array(int[] array) { 1231 | $int(array.length); 1232 | newarray(T_INT); 1233 | for (int i = 0, j = array.length; i < j; i++) { 1234 | int v = array[i]; 1235 | dup().$int(i).$int(v).iastore(); 1236 | } 1237 | return this; 1238 | } 1239 | 1240 | @Override 1241 | public AsmBlock array(float[] array) { 1242 | $int(array.length); 1243 | newarray(T_FLOAT); 1244 | for (int i = 0, j = array.length; i < j; i++) { 1245 | float v = array[i]; 1246 | dup().$int(i).$float(v).fastore(); 1247 | } 1248 | return this; 1249 | } 1250 | 1251 | @Override 1252 | public AsmBlock array(char[] array) { 1253 | $int(array.length); 1254 | newarray(T_CHAR); 1255 | for (int i = 0, j = array.length; i < j; i++) { 1256 | char v = array[i]; 1257 | dup().$int(i).$int(v).castore(); 1258 | } 1259 | return this; 1260 | } 1261 | 1262 | @Override 1263 | public AsmBlock array(short[] array) { 1264 | $int(array.length); 1265 | newarray(T_SHORT); 1266 | for (int i = 0, j = array.length; i < j; i++) { 1267 | short v = array[i]; 1268 | dup().$int(i).$int(v).sastore(); 1269 | } 1270 | return this; 1271 | } 1272 | 1273 | @Override 1274 | public AsmBlock array(byte[] array) { 1275 | $int(array.length); 1276 | newarray(T_BYTE); 1277 | for (int i = 0, j = array.length; i < j; i++) { 1278 | byte v = array[i]; 1279 | dup().$int(i).$int(v).bastore(); 1280 | } 1281 | return this; 1282 | } 1283 | 1284 | @Override 1285 | public AsmBlock array(boolean[] array) { 1286 | $int(array.length); 1287 | newarray(T_BOOLEAN); 1288 | for (int i = 0, j = array.length; i < j; i++) { 1289 | boolean v = array[i]; 1290 | dup().$int(i).$int(v ? 1 : 0).bastore(); 1291 | } 1292 | return this; 1293 | } 1294 | 1295 | @Override 1296 | public AsmBlock array(T[] array, BiIntConsumer producer) { 1297 | $int(array.length); 1298 | visitor.visitTypeInsn(ANEWARRAY, Type.getInternalName(array.getClass().getComponentType())); 1299 | for (int i = 0, j = array.length; i < j; i++) { 1300 | T v = array[i]; 1301 | dup().$int(i); 1302 | producer.accept(i, v); 1303 | aastore(); 1304 | } 1305 | return this; 1306 | } 1307 | 1308 | private AsmBlock visitInsn(int opcode) { 1309 | visitor.visitInsn(opcode); 1310 | return this; 1311 | } 1312 | 1313 | private AsmBlock visitJumpInsn(int opcode, Label label) { 1314 | visitor.visitJumpInsn(opcode, label); 1315 | return this; 1316 | } 1317 | 1318 | private AsmBlock visitVarInsn(int opcode, int var) { 1319 | visitor.visitVarInsn(opcode, var); 1320 | return this; 1321 | } 1322 | 1323 | private AsmBlock visitLdcInsn(Object value) { 1324 | visitor.visitLdcInsn(value); 1325 | return this; 1326 | } 1327 | 1328 | private static String internalName(Class c) { 1329 | return c.getName().replace('.', '/'); 1330 | } 1331 | 1332 | private static String fieldDescriptor(Class c) { 1333 | if (c.isPrimitive()) { 1334 | return getPrimitiveInternal(c); 1335 | } 1336 | String name = c.getName().replace('.', '/'); 1337 | if (c.isArray()) { 1338 | return name; 1339 | } 1340 | return 'L' + name + ';'; 1341 | } 1342 | 1343 | private static String getPrimitiveInternal(Class c) { 1344 | if (c == Long.TYPE) { 1345 | return "J"; 1346 | } else if (c == Double.TYPE) { 1347 | return "D"; 1348 | } else if (c == Integer.TYPE) { 1349 | return "I"; 1350 | } else if (c == Float.TYPE) { 1351 | return "F"; 1352 | } else if (c == Short.TYPE) { 1353 | return "S"; 1354 | } else if (c == Character.TYPE) { 1355 | return "C"; 1356 | } else if (c == Byte.TYPE) { 1357 | return "B"; 1358 | } else if (c == Boolean.TYPE) { 1359 | return "Z"; 1360 | } else { 1361 | throw new IllegalArgumentException("Unknown primitive: " + c); 1362 | } 1363 | } 1364 | } 1365 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xxDark/asm-inline/f36bfbf6b6ce4085374642ce87a2c567d94156c5/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /plugin/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-gradle-plugin' 2 | 3 | dependencies { 4 | shade asm 5 | compileOnly gradleApi() 6 | shade project(':api') 7 | shade project(':common') 8 | } 9 | 10 | gradlePlugin { 11 | plugins { 12 | asmInlinePlugin { 13 | id = 'dev.xdark.asminline' 14 | implementationClass = 'dev.xdark.asminline.AsmInlinePlugin' 15 | } 16 | } 17 | } 18 | 19 | jar { 20 | from { 21 | configurations.shade.collect { zipTree(it) } 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /plugin/src/main/java/dev/xdark/asminline/AsmInlinePlugin.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.asminline; 2 | 3 | import org.gradle.api.Plugin; 4 | import org.gradle.api.Project; 5 | import org.gradle.api.file.DirectoryProperty; 6 | import org.gradle.api.tasks.compile.JavaCompile; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | import java.io.UncheckedIOException; 11 | import java.net.MalformedURLException; 12 | import java.net.URL; 13 | import java.net.URLClassLoader; 14 | import java.nio.file.Files; 15 | import java.nio.file.Path; 16 | import java.util.stream.Stream; 17 | 18 | public final class AsmInlinePlugin implements Plugin { 19 | @Override 20 | public void apply(Project project) { 21 | BytecodeInlineExtension extension = project.getExtensions().create("bytecodeInlining", BytecodeInlineExtension.class); 22 | project.getTasks().withType(JavaCompile.class).configureEach(task -> { 23 | task.doLast(__ -> { 24 | PatchProcessor patchProcessor = new PatchProcessor(extension.getComputationFlags().get()); 25 | DirectoryProperty destinationDirectory = task.getDestinationDirectory(); 26 | URL[] urls = Stream.concat( 27 | task.getClasspath().getFiles().stream(), 28 | Stream.of(destinationDirectory.getAsFile().get()) 29 | ).map(file -> { 30 | try { 31 | return file.toURI().toURL(); 32 | } catch (MalformedURLException e) { 33 | throw new UncheckedIOException(e); 34 | } 35 | }).toArray(URL[]::new); 36 | try (URLClassLoader cl = URLClassLoader.newInstance(urls, getClass().getClassLoader())) { 37 | for (File file : destinationDirectory.getAsFileTree()) { 38 | Path path = file.toPath(); 39 | byte[] b = Files.readAllBytes(path); 40 | byte[] newBytes = patchProcessor.processBytes(cl, b); 41 | if (b != newBytes) { 42 | Files.write(path, newBytes); 43 | } 44 | } 45 | } catch (IOException ex) { 46 | throw new UncheckedIOException("Failed bytecode instrumentation", ex); 47 | } 48 | }); 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /plugin/src/main/java/dev/xdark/asminline/BytecodeInlineExtension.java: -------------------------------------------------------------------------------- 1 | package dev.xdark.asminline; 2 | 3 | import org.gradle.api.provider.Property; 4 | 5 | public interface BytecodeInlineExtension { 6 | 7 | Property getComputationFlags(); 8 | } 9 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'asm-inline' 2 | include 'api' 3 | include 'plugin' 4 | include 'common' 5 | --------------------------------------------------------------------------------