001// ASM: a very small and fast Java bytecode manipulation framework 002// Copyright (c) 2000-2011 INRIA, France Telecom 003// All rights reserved. 004// 005// Redistribution and use in source and binary forms, with or without 006// modification, are permitted provided that the following conditions 007// are met: 008// 1. Redistributions of source code must retain the above copyright 009// notice, this list of conditions and the following disclaimer. 010// 2. Redistributions in binary form must reproduce the above copyright 011// notice, this list of conditions and the following disclaimer in the 012// documentation and/or other materials provided with the distribution. 013// 3. Neither the name of the copyright holders nor the names of its 014// contributors may be used to endorse or promote products derived from 015// this software without specific prior written permission. 016// 017// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 018// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 019// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 020// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 021// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 022// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 023// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 024// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 025// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 026// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 027// THE POSSIBILITY OF SUCH DAMAGE. 028 029package io.ebean.enhance.asm.commons; 030 031import io.ebean.enhance.asm.*; 032 033/** 034 * A {@link MethodVisitor} providing a more detailed API to generate and transform instructions. 035 * 036 * @author Eric Bruneton 037 */ 038public class InstructionAdapter extends MethodVisitor { 039 040 /** The type of the java.lang.Object class. */ 041 public static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); 042 043 /** 044 * Constructs a new {@link InstructionAdapter}. <i>Subclasses must not use this constructor</i>. 045 * Instead, they must use the {@link #InstructionAdapter(int, MethodVisitor)} version. 046 * 047 * @param methodVisitor the method visitor to which this adapter delegates calls. 048 * @throws IllegalStateException If a subclass calls this constructor. 049 */ 050 public InstructionAdapter(final MethodVisitor methodVisitor) { 051 this(/* latest api = */ Opcodes.ASM9, methodVisitor); 052 if (getClass() != InstructionAdapter.class) { 053 throw new IllegalStateException(); 054 } 055 } 056 057 /** 058 * Constructs a new {@link InstructionAdapter}. 059 * 060 * @param api the ASM API version implemented by this visitor. Must be one of the {@code 061 * ASM}<i>x</i> values in {@link Opcodes}. 062 * @param methodVisitor the method visitor to which this adapter delegates calls. 063 */ 064 protected InstructionAdapter(final int api, final MethodVisitor methodVisitor) { 065 super(api, methodVisitor); 066 } 067 068 @Override 069 public void visitInsn(final int opcode) { 070 switch (opcode) { 071 case Opcodes.NOP: 072 nop(); 073 break; 074 case Opcodes.ACONST_NULL: 075 aconst(null); 076 break; 077 case Opcodes.ICONST_M1: 078 case Opcodes.ICONST_0: 079 case Opcodes.ICONST_1: 080 case Opcodes.ICONST_2: 081 case Opcodes.ICONST_3: 082 case Opcodes.ICONST_4: 083 case Opcodes.ICONST_5: 084 iconst(opcode - Opcodes.ICONST_0); 085 break; 086 case Opcodes.LCONST_0: 087 case Opcodes.LCONST_1: 088 lconst((long) (opcode - Opcodes.LCONST_0)); 089 break; 090 case Opcodes.FCONST_0: 091 case Opcodes.FCONST_1: 092 case Opcodes.FCONST_2: 093 fconst((float) (opcode - Opcodes.FCONST_0)); 094 break; 095 case Opcodes.DCONST_0: 096 case Opcodes.DCONST_1: 097 dconst((double) (opcode - Opcodes.DCONST_0)); 098 break; 099 case Opcodes.IALOAD: 100 aload(Type.INT_TYPE); 101 break; 102 case Opcodes.LALOAD: 103 aload(Type.LONG_TYPE); 104 break; 105 case Opcodes.FALOAD: 106 aload(Type.FLOAT_TYPE); 107 break; 108 case Opcodes.DALOAD: 109 aload(Type.DOUBLE_TYPE); 110 break; 111 case Opcodes.AALOAD: 112 aload(OBJECT_TYPE); 113 break; 114 case Opcodes.BALOAD: 115 aload(Type.BYTE_TYPE); 116 break; 117 case Opcodes.CALOAD: 118 aload(Type.CHAR_TYPE); 119 break; 120 case Opcodes.SALOAD: 121 aload(Type.SHORT_TYPE); 122 break; 123 case Opcodes.IASTORE: 124 astore(Type.INT_TYPE); 125 break; 126 case Opcodes.LASTORE: 127 astore(Type.LONG_TYPE); 128 break; 129 case Opcodes.FASTORE: 130 astore(Type.FLOAT_TYPE); 131 break; 132 case Opcodes.DASTORE: 133 astore(Type.DOUBLE_TYPE); 134 break; 135 case Opcodes.AASTORE: 136 astore(OBJECT_TYPE); 137 break; 138 case Opcodes.BASTORE: 139 astore(Type.BYTE_TYPE); 140 break; 141 case Opcodes.CASTORE: 142 astore(Type.CHAR_TYPE); 143 break; 144 case Opcodes.SASTORE: 145 astore(Type.SHORT_TYPE); 146 break; 147 case Opcodes.POP: 148 pop(); 149 break; 150 case Opcodes.POP2: 151 pop2(); 152 break; 153 case Opcodes.DUP: 154 dup(); 155 break; 156 case Opcodes.DUP_X1: 157 dupX1(); 158 break; 159 case Opcodes.DUP_X2: 160 dupX2(); 161 break; 162 case Opcodes.DUP2: 163 dup2(); 164 break; 165 case Opcodes.DUP2_X1: 166 dup2X1(); 167 break; 168 case Opcodes.DUP2_X2: 169 dup2X2(); 170 break; 171 case Opcodes.SWAP: 172 swap(); 173 break; 174 case Opcodes.IADD: 175 add(Type.INT_TYPE); 176 break; 177 case Opcodes.LADD: 178 add(Type.LONG_TYPE); 179 break; 180 case Opcodes.FADD: 181 add(Type.FLOAT_TYPE); 182 break; 183 case Opcodes.DADD: 184 add(Type.DOUBLE_TYPE); 185 break; 186 case Opcodes.ISUB: 187 sub(Type.INT_TYPE); 188 break; 189 case Opcodes.LSUB: 190 sub(Type.LONG_TYPE); 191 break; 192 case Opcodes.FSUB: 193 sub(Type.FLOAT_TYPE); 194 break; 195 case Opcodes.DSUB: 196 sub(Type.DOUBLE_TYPE); 197 break; 198 case Opcodes.IMUL: 199 mul(Type.INT_TYPE); 200 break; 201 case Opcodes.LMUL: 202 mul(Type.LONG_TYPE); 203 break; 204 case Opcodes.FMUL: 205 mul(Type.FLOAT_TYPE); 206 break; 207 case Opcodes.DMUL: 208 mul(Type.DOUBLE_TYPE); 209 break; 210 case Opcodes.IDIV: 211 div(Type.INT_TYPE); 212 break; 213 case Opcodes.LDIV: 214 div(Type.LONG_TYPE); 215 break; 216 case Opcodes.FDIV: 217 div(Type.FLOAT_TYPE); 218 break; 219 case Opcodes.DDIV: 220 div(Type.DOUBLE_TYPE); 221 break; 222 case Opcodes.IREM: 223 rem(Type.INT_TYPE); 224 break; 225 case Opcodes.LREM: 226 rem(Type.LONG_TYPE); 227 break; 228 case Opcodes.FREM: 229 rem(Type.FLOAT_TYPE); 230 break; 231 case Opcodes.DREM: 232 rem(Type.DOUBLE_TYPE); 233 break; 234 case Opcodes.INEG: 235 neg(Type.INT_TYPE); 236 break; 237 case Opcodes.LNEG: 238 neg(Type.LONG_TYPE); 239 break; 240 case Opcodes.FNEG: 241 neg(Type.FLOAT_TYPE); 242 break; 243 case Opcodes.DNEG: 244 neg(Type.DOUBLE_TYPE); 245 break; 246 case Opcodes.ISHL: 247 shl(Type.INT_TYPE); 248 break; 249 case Opcodes.LSHL: 250 shl(Type.LONG_TYPE); 251 break; 252 case Opcodes.ISHR: 253 shr(Type.INT_TYPE); 254 break; 255 case Opcodes.LSHR: 256 shr(Type.LONG_TYPE); 257 break; 258 case Opcodes.IUSHR: 259 ushr(Type.INT_TYPE); 260 break; 261 case Opcodes.LUSHR: 262 ushr(Type.LONG_TYPE); 263 break; 264 case Opcodes.IAND: 265 and(Type.INT_TYPE); 266 break; 267 case Opcodes.LAND: 268 and(Type.LONG_TYPE); 269 break; 270 case Opcodes.IOR: 271 or(Type.INT_TYPE); 272 break; 273 case Opcodes.LOR: 274 or(Type.LONG_TYPE); 275 break; 276 case Opcodes.IXOR: 277 xor(Type.INT_TYPE); 278 break; 279 case Opcodes.LXOR: 280 xor(Type.LONG_TYPE); 281 break; 282 case Opcodes.I2L: 283 cast(Type.INT_TYPE, Type.LONG_TYPE); 284 break; 285 case Opcodes.I2F: 286 cast(Type.INT_TYPE, Type.FLOAT_TYPE); 287 break; 288 case Opcodes.I2D: 289 cast(Type.INT_TYPE, Type.DOUBLE_TYPE); 290 break; 291 case Opcodes.L2I: 292 cast(Type.LONG_TYPE, Type.INT_TYPE); 293 break; 294 case Opcodes.L2F: 295 cast(Type.LONG_TYPE, Type.FLOAT_TYPE); 296 break; 297 case Opcodes.L2D: 298 cast(Type.LONG_TYPE, Type.DOUBLE_TYPE); 299 break; 300 case Opcodes.F2I: 301 cast(Type.FLOAT_TYPE, Type.INT_TYPE); 302 break; 303 case Opcodes.F2L: 304 cast(Type.FLOAT_TYPE, Type.LONG_TYPE); 305 break; 306 case Opcodes.F2D: 307 cast(Type.FLOAT_TYPE, Type.DOUBLE_TYPE); 308 break; 309 case Opcodes.D2I: 310 cast(Type.DOUBLE_TYPE, Type.INT_TYPE); 311 break; 312 case Opcodes.D2L: 313 cast(Type.DOUBLE_TYPE, Type.LONG_TYPE); 314 break; 315 case Opcodes.D2F: 316 cast(Type.DOUBLE_TYPE, Type.FLOAT_TYPE); 317 break; 318 case Opcodes.I2B: 319 cast(Type.INT_TYPE, Type.BYTE_TYPE); 320 break; 321 case Opcodes.I2C: 322 cast(Type.INT_TYPE, Type.CHAR_TYPE); 323 break; 324 case Opcodes.I2S: 325 cast(Type.INT_TYPE, Type.SHORT_TYPE); 326 break; 327 case Opcodes.LCMP: 328 lcmp(); 329 break; 330 case Opcodes.FCMPL: 331 cmpl(Type.FLOAT_TYPE); 332 break; 333 case Opcodes.FCMPG: 334 cmpg(Type.FLOAT_TYPE); 335 break; 336 case Opcodes.DCMPL: 337 cmpl(Type.DOUBLE_TYPE); 338 break; 339 case Opcodes.DCMPG: 340 cmpg(Type.DOUBLE_TYPE); 341 break; 342 case Opcodes.IRETURN: 343 areturn(Type.INT_TYPE); 344 break; 345 case Opcodes.LRETURN: 346 areturn(Type.LONG_TYPE); 347 break; 348 case Opcodes.FRETURN: 349 areturn(Type.FLOAT_TYPE); 350 break; 351 case Opcodes.DRETURN: 352 areturn(Type.DOUBLE_TYPE); 353 break; 354 case Opcodes.ARETURN: 355 areturn(OBJECT_TYPE); 356 break; 357 case Opcodes.RETURN: 358 areturn(Type.VOID_TYPE); 359 break; 360 case Opcodes.ARRAYLENGTH: 361 arraylength(); 362 break; 363 case Opcodes.ATHROW: 364 athrow(); 365 break; 366 case Opcodes.MONITORENTER: 367 monitorenter(); 368 break; 369 case Opcodes.MONITOREXIT: 370 monitorexit(); 371 break; 372 default: 373 throw new IllegalArgumentException(); 374 } 375 } 376 377 @Override 378 public void visitIntInsn(final int opcode, final int operand) { 379 switch (opcode) { 380 case Opcodes.BIPUSH: 381 iconst(operand); 382 break; 383 case Opcodes.SIPUSH: 384 iconst(operand); 385 break; 386 case Opcodes.NEWARRAY: 387 switch (operand) { 388 case Opcodes.T_BOOLEAN: 389 newarray(Type.BOOLEAN_TYPE); 390 break; 391 case Opcodes.T_CHAR: 392 newarray(Type.CHAR_TYPE); 393 break; 394 case Opcodes.T_BYTE: 395 newarray(Type.BYTE_TYPE); 396 break; 397 case Opcodes.T_SHORT: 398 newarray(Type.SHORT_TYPE); 399 break; 400 case Opcodes.T_INT: 401 newarray(Type.INT_TYPE); 402 break; 403 case Opcodes.T_FLOAT: 404 newarray(Type.FLOAT_TYPE); 405 break; 406 case Opcodes.T_LONG: 407 newarray(Type.LONG_TYPE); 408 break; 409 case Opcodes.T_DOUBLE: 410 newarray(Type.DOUBLE_TYPE); 411 break; 412 default: 413 throw new IllegalArgumentException(); 414 } 415 break; 416 default: 417 throw new IllegalArgumentException(); 418 } 419 } 420 421 @Override 422 public void visitVarInsn(final int opcode, final int varIndex) { 423 switch (opcode) { 424 case Opcodes.ILOAD: 425 load(varIndex, Type.INT_TYPE); 426 break; 427 case Opcodes.LLOAD: 428 load(varIndex, Type.LONG_TYPE); 429 break; 430 case Opcodes.FLOAD: 431 load(varIndex, Type.FLOAT_TYPE); 432 break; 433 case Opcodes.DLOAD: 434 load(varIndex, Type.DOUBLE_TYPE); 435 break; 436 case Opcodes.ALOAD: 437 load(varIndex, OBJECT_TYPE); 438 break; 439 case Opcodes.ISTORE: 440 store(varIndex, Type.INT_TYPE); 441 break; 442 case Opcodes.LSTORE: 443 store(varIndex, Type.LONG_TYPE); 444 break; 445 case Opcodes.FSTORE: 446 store(varIndex, Type.FLOAT_TYPE); 447 break; 448 case Opcodes.DSTORE: 449 store(varIndex, Type.DOUBLE_TYPE); 450 break; 451 case Opcodes.ASTORE: 452 store(varIndex, OBJECT_TYPE); 453 break; 454 case Opcodes.RET: 455 ret(varIndex); 456 break; 457 default: 458 throw new IllegalArgumentException(); 459 } 460 } 461 462 @Override 463 public void visitTypeInsn(final int opcode, final String type) { 464 Type objectType = Type.getObjectType(type); 465 switch (opcode) { 466 case Opcodes.NEW: 467 anew(objectType); 468 break; 469 case Opcodes.ANEWARRAY: 470 newarray(objectType); 471 break; 472 case Opcodes.CHECKCAST: 473 checkcast(objectType); 474 break; 475 case Opcodes.INSTANCEOF: 476 instanceOf(objectType); 477 break; 478 default: 479 throw new IllegalArgumentException(); 480 } 481 } 482 483 @Override 484 public void visitFieldInsn( 485 final int opcode, final String owner, final String name, final String descriptor) { 486 switch (opcode) { 487 case Opcodes.GETSTATIC: 488 getstatic(owner, name, descriptor); 489 break; 490 case Opcodes.PUTSTATIC: 491 putstatic(owner, name, descriptor); 492 break; 493 case Opcodes.GETFIELD: 494 getfield(owner, name, descriptor); 495 break; 496 case Opcodes.PUTFIELD: 497 putfield(owner, name, descriptor); 498 break; 499 default: 500 throw new IllegalArgumentException(); 501 } 502 } 503 504 @Override 505 public void visitMethodInsn( 506 final int opcodeAndSource, 507 final String owner, 508 final String name, 509 final String descriptor, 510 final boolean isInterface) { 511 if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) { 512 // Redirect the call to the deprecated version of this method. 513 super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface); 514 return; 515 } 516 int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK; 517 518 switch (opcode) { 519 case Opcodes.INVOKESPECIAL: 520 invokespecial(owner, name, descriptor, isInterface); 521 break; 522 case Opcodes.INVOKEVIRTUAL: 523 invokevirtual(owner, name, descriptor, isInterface); 524 break; 525 case Opcodes.INVOKESTATIC: 526 invokestatic(owner, name, descriptor, isInterface); 527 break; 528 case Opcodes.INVOKEINTERFACE: 529 invokeinterface(owner, name, descriptor); 530 break; 531 default: 532 throw new IllegalArgumentException(); 533 } 534 } 535 536 @Override 537 public void visitInvokeDynamicInsn( 538 final String name, 539 final String descriptor, 540 final Handle bootstrapMethodHandle, 541 final Object... bootstrapMethodArguments) { 542 invokedynamic(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); 543 } 544 545 @Override 546 public void visitJumpInsn(final int opcode, final Label label) { 547 switch (opcode) { 548 case Opcodes.IFEQ: 549 ifeq(label); 550 break; 551 case Opcodes.IFNE: 552 ifne(label); 553 break; 554 case Opcodes.IFLT: 555 iflt(label); 556 break; 557 case Opcodes.IFGE: 558 ifge(label); 559 break; 560 case Opcodes.IFGT: 561 ifgt(label); 562 break; 563 case Opcodes.IFLE: 564 ifle(label); 565 break; 566 case Opcodes.IF_ICMPEQ: 567 ificmpeq(label); 568 break; 569 case Opcodes.IF_ICMPNE: 570 ificmpne(label); 571 break; 572 case Opcodes.IF_ICMPLT: 573 ificmplt(label); 574 break; 575 case Opcodes.IF_ICMPGE: 576 ificmpge(label); 577 break; 578 case Opcodes.IF_ICMPGT: 579 ificmpgt(label); 580 break; 581 case Opcodes.IF_ICMPLE: 582 ificmple(label); 583 break; 584 case Opcodes.IF_ACMPEQ: 585 ifacmpeq(label); 586 break; 587 case Opcodes.IF_ACMPNE: 588 ifacmpne(label); 589 break; 590 case Opcodes.GOTO: 591 goTo(label); 592 break; 593 case Opcodes.JSR: 594 jsr(label); 595 break; 596 case Opcodes.IFNULL: 597 ifnull(label); 598 break; 599 case Opcodes.IFNONNULL: 600 ifnonnull(label); 601 break; 602 default: 603 throw new IllegalArgumentException(); 604 } 605 } 606 607 @Override 608 public void visitLabel(final Label label) { 609 mark(label); 610 } 611 612 @Override 613 public void visitLdcInsn(final Object value) { 614 if (api < Opcodes.ASM5 615 && (value instanceof Handle 616 || (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) { 617 throw new UnsupportedOperationException("This feature requires ASM5"); 618 } 619 if (api < Opcodes.ASM7 && value instanceof ConstantDynamic) { 620 throw new UnsupportedOperationException("This feature requires ASM7"); 621 } 622 if (value instanceof Integer) { 623 iconst((Integer) value); 624 } else if (value instanceof Byte) { 625 iconst(((Byte) value).intValue()); 626 } else if (value instanceof Character) { 627 iconst(((Character) value).charValue()); 628 } else if (value instanceof Short) { 629 iconst(((Short) value).intValue()); 630 } else if (value instanceof Boolean) { 631 iconst(((Boolean) value).booleanValue() ? 1 : 0); 632 } else if (value instanceof Float) { 633 fconst((Float) value); 634 } else if (value instanceof Long) { 635 lconst((Long) value); 636 } else if (value instanceof Double) { 637 dconst((Double) value); 638 } else if (value instanceof String) { 639 aconst(value); 640 } else if (value instanceof Type) { 641 tconst((Type) value); 642 } else if (value instanceof Handle) { 643 hconst((Handle) value); 644 } else if (value instanceof ConstantDynamic) { 645 cconst((ConstantDynamic) value); 646 } else { 647 throw new IllegalArgumentException(); 648 } 649 } 650 651 @Override 652 public void visitIincInsn(final int varIndex, final int increment) { 653 iinc(varIndex, increment); 654 } 655 656 @Override 657 public void visitTableSwitchInsn( 658 final int min, final int max, final Label dflt, final Label... labels) { 659 tableswitch(min, max, dflt, labels); 660 } 661 662 @Override 663 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { 664 lookupswitch(dflt, keys, labels); 665 } 666 667 @Override 668 public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { 669 multianewarray(descriptor, numDimensions); 670 } 671 672 // ----------------------------------------------------------------------------------------------- 673 674 /** Generates a nop instruction. */ 675 public void nop() { 676 mv.visitInsn(Opcodes.NOP); 677 } 678 679 /** 680 * Generates the instruction to push the given value on the stack. 681 * 682 * @param value the constant to be pushed on the stack. This parameter must be an {@link Integer}, 683 * a {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link Type} of 684 * OBJECT or ARRAY sort for {@code .class} constants, for classes whose version is 49, a 685 * {@link Type} of METHOD sort for MethodType, a {@link Handle} for MethodHandle constants, 686 * for classes whose version is 51 or a {@link ConstantDynamic} for a constant dynamic for 687 * classes whose version is 55. 688 */ 689 public void aconst(final Object value) { 690 if (value == null) { 691 mv.visitInsn(Opcodes.ACONST_NULL); 692 } else { 693 mv.visitLdcInsn(value); 694 } 695 } 696 697 /** 698 * Generates the instruction to push the given value on the stack. 699 * 700 * @param intValue the constant to be pushed on the stack. 701 */ 702 public void iconst(final int intValue) { 703 if (intValue >= -1 && intValue <= 5) { 704 mv.visitInsn(Opcodes.ICONST_0 + intValue); 705 } else if (intValue >= Byte.MIN_VALUE && intValue <= Byte.MAX_VALUE) { 706 mv.visitIntInsn(Opcodes.BIPUSH, intValue); 707 } else if (intValue >= Short.MIN_VALUE && intValue <= Short.MAX_VALUE) { 708 mv.visitIntInsn(Opcodes.SIPUSH, intValue); 709 } else { 710 mv.visitLdcInsn(intValue); 711 } 712 } 713 714 /** 715 * Generates the instruction to push the given value on the stack. 716 * 717 * @param longValue the constant to be pushed on the stack. 718 */ 719 public void lconst(final long longValue) { 720 if (longValue == 0L || longValue == 1L) { 721 mv.visitInsn(Opcodes.LCONST_0 + (int) longValue); 722 } else { 723 mv.visitLdcInsn(longValue); 724 } 725 } 726 727 /** 728 * Generates the instruction to push the given value on the stack. 729 * 730 * @param floatValue the constant to be pushed on the stack. 731 */ 732 public void fconst(final float floatValue) { 733 int bits = Float.floatToIntBits(floatValue); 734 if (bits == 0L || bits == 0x3F800000 || bits == 0x40000000) { // 0..2 735 mv.visitInsn(Opcodes.FCONST_0 + (int) floatValue); 736 } else { 737 mv.visitLdcInsn(floatValue); 738 } 739 } 740 741 /** 742 * Generates the instruction to push the given value on the stack. 743 * 744 * @param doubleValue the constant to be pushed on the stack. 745 */ 746 public void dconst(final double doubleValue) { 747 long bits = Double.doubleToLongBits(doubleValue); 748 if (bits == 0L || bits == 0x3FF0000000000000L) { // +0.0d and 1.0d 749 mv.visitInsn(Opcodes.DCONST_0 + (int) doubleValue); 750 } else { 751 mv.visitLdcInsn(doubleValue); 752 } 753 } 754 755 /** 756 * Generates the instruction to push the given type on the stack. 757 * 758 * @param type the type to be pushed on the stack. 759 */ 760 public void tconst(final Type type) { 761 mv.visitLdcInsn(type); 762 } 763 764 /** 765 * Generates the instruction to push the given handle on the stack. 766 * 767 * @param handle the handle to be pushed on the stack. 768 */ 769 public void hconst(final Handle handle) { 770 mv.visitLdcInsn(handle); 771 } 772 773 /** 774 * Generates the instruction to push the given constant dynamic on the stack. 775 * 776 * @param constantDynamic the constant dynamic to be pushed on the stack. 777 */ 778 public void cconst(final ConstantDynamic constantDynamic) { 779 mv.visitLdcInsn(constantDynamic); 780 } 781 782 public void load(final int varIndex, final Type type) { 783 mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), varIndex); 784 } 785 786 public void aload(final Type type) { 787 mv.visitInsn(type.getOpcode(Opcodes.IALOAD)); 788 } 789 790 public void store(final int varIndex, final Type type) { 791 mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), varIndex); 792 } 793 794 public void astore(final Type type) { 795 mv.visitInsn(type.getOpcode(Opcodes.IASTORE)); 796 } 797 798 public void pop() { 799 mv.visitInsn(Opcodes.POP); 800 } 801 802 public void pop2() { 803 mv.visitInsn(Opcodes.POP2); 804 } 805 806 public void dup() { 807 mv.visitInsn(Opcodes.DUP); 808 } 809 810 public void dup2() { 811 mv.visitInsn(Opcodes.DUP2); 812 } 813 814 public void dupX1() { 815 mv.visitInsn(Opcodes.DUP_X1); 816 } 817 818 public void dupX2() { 819 mv.visitInsn(Opcodes.DUP_X2); 820 } 821 822 public void dup2X1() { 823 mv.visitInsn(Opcodes.DUP2_X1); 824 } 825 826 public void dup2X2() { 827 mv.visitInsn(Opcodes.DUP2_X2); 828 } 829 830 public void swap() { 831 mv.visitInsn(Opcodes.SWAP); 832 } 833 834 public void add(final Type type) { 835 mv.visitInsn(type.getOpcode(Opcodes.IADD)); 836 } 837 838 public void sub(final Type type) { 839 mv.visitInsn(type.getOpcode(Opcodes.ISUB)); 840 } 841 842 public void mul(final Type type) { 843 mv.visitInsn(type.getOpcode(Opcodes.IMUL)); 844 } 845 846 public void div(final Type type) { 847 mv.visitInsn(type.getOpcode(Opcodes.IDIV)); 848 } 849 850 public void rem(final Type type) { 851 mv.visitInsn(type.getOpcode(Opcodes.IREM)); 852 } 853 854 public void neg(final Type type) { 855 mv.visitInsn(type.getOpcode(Opcodes.INEG)); 856 } 857 858 public void shl(final Type type) { 859 mv.visitInsn(type.getOpcode(Opcodes.ISHL)); 860 } 861 862 public void shr(final Type type) { 863 mv.visitInsn(type.getOpcode(Opcodes.ISHR)); 864 } 865 866 public void ushr(final Type type) { 867 mv.visitInsn(type.getOpcode(Opcodes.IUSHR)); 868 } 869 870 public void and(final Type type) { 871 mv.visitInsn(type.getOpcode(Opcodes.IAND)); 872 } 873 874 public void or(final Type type) { 875 mv.visitInsn(type.getOpcode(Opcodes.IOR)); 876 } 877 878 public void xor(final Type type) { 879 mv.visitInsn(type.getOpcode(Opcodes.IXOR)); 880 } 881 882 public void iinc(final int varIndex, final int increment) { 883 mv.visitIincInsn(varIndex, increment); 884 } 885 886 /** 887 * Generates the instruction to cast from the first given type to the other. 888 * 889 * @param from a Type. 890 * @param to a Type. 891 */ 892 public void cast(final Type from, final Type to) { 893 cast(mv, from, to); 894 } 895 896 /** 897 * Generates the instruction to cast from the first given type to the other. 898 * 899 * @param methodVisitor the method visitor to use to generate the instruction. 900 * @param from a Type. 901 * @param to a Type. 902 */ 903 static void cast(final MethodVisitor methodVisitor, final Type from, final Type to) { 904 if (from != to) { 905 if (from == Type.DOUBLE_TYPE) { 906 if (to == Type.FLOAT_TYPE) { 907 methodVisitor.visitInsn(Opcodes.D2F); 908 } else if (to == Type.LONG_TYPE) { 909 methodVisitor.visitInsn(Opcodes.D2L); 910 } else { 911 methodVisitor.visitInsn(Opcodes.D2I); 912 cast(methodVisitor, Type.INT_TYPE, to); 913 } 914 } else if (from == Type.FLOAT_TYPE) { 915 if (to == Type.DOUBLE_TYPE) { 916 methodVisitor.visitInsn(Opcodes.F2D); 917 } else if (to == Type.LONG_TYPE) { 918 methodVisitor.visitInsn(Opcodes.F2L); 919 } else { 920 methodVisitor.visitInsn(Opcodes.F2I); 921 cast(methodVisitor, Type.INT_TYPE, to); 922 } 923 } else if (from == Type.LONG_TYPE) { 924 if (to == Type.DOUBLE_TYPE) { 925 methodVisitor.visitInsn(Opcodes.L2D); 926 } else if (to == Type.FLOAT_TYPE) { 927 methodVisitor.visitInsn(Opcodes.L2F); 928 } else { 929 methodVisitor.visitInsn(Opcodes.L2I); 930 cast(methodVisitor, Type.INT_TYPE, to); 931 } 932 } else { 933 if (to == Type.BYTE_TYPE) { 934 methodVisitor.visitInsn(Opcodes.I2B); 935 } else if (to == Type.CHAR_TYPE) { 936 methodVisitor.visitInsn(Opcodes.I2C); 937 } else if (to == Type.DOUBLE_TYPE) { 938 methodVisitor.visitInsn(Opcodes.I2D); 939 } else if (to == Type.FLOAT_TYPE) { 940 methodVisitor.visitInsn(Opcodes.I2F); 941 } else if (to == Type.LONG_TYPE) { 942 methodVisitor.visitInsn(Opcodes.I2L); 943 } else if (to == Type.SHORT_TYPE) { 944 methodVisitor.visitInsn(Opcodes.I2S); 945 } 946 } 947 } 948 } 949 950 public void lcmp() { 951 mv.visitInsn(Opcodes.LCMP); 952 } 953 954 public void cmpl(final Type type) { 955 mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPL : Opcodes.DCMPL); 956 } 957 958 public void cmpg(final Type type) { 959 mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPG : Opcodes.DCMPG); 960 } 961 962 public void ifeq(final Label label) { 963 mv.visitJumpInsn(Opcodes.IFEQ, label); 964 } 965 966 public void ifne(final Label label) { 967 mv.visitJumpInsn(Opcodes.IFNE, label); 968 } 969 970 public void iflt(final Label label) { 971 mv.visitJumpInsn(Opcodes.IFLT, label); 972 } 973 974 public void ifge(final Label label) { 975 mv.visitJumpInsn(Opcodes.IFGE, label); 976 } 977 978 public void ifgt(final Label label) { 979 mv.visitJumpInsn(Opcodes.IFGT, label); 980 } 981 982 public void ifle(final Label label) { 983 mv.visitJumpInsn(Opcodes.IFLE, label); 984 } 985 986 public void ificmpeq(final Label label) { 987 mv.visitJumpInsn(Opcodes.IF_ICMPEQ, label); 988 } 989 990 public void ificmpne(final Label label) { 991 mv.visitJumpInsn(Opcodes.IF_ICMPNE, label); 992 } 993 994 public void ificmplt(final Label label) { 995 mv.visitJumpInsn(Opcodes.IF_ICMPLT, label); 996 } 997 998 public void ificmpge(final Label label) { 999 mv.visitJumpInsn(Opcodes.IF_ICMPGE, label); 1000 } 1001 1002 public void ificmpgt(final Label label) { 1003 mv.visitJumpInsn(Opcodes.IF_ICMPGT, label); 1004 } 1005 1006 public void ificmple(final Label label) { 1007 mv.visitJumpInsn(Opcodes.IF_ICMPLE, label); 1008 } 1009 1010 public void ifacmpeq(final Label label) { 1011 mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label); 1012 } 1013 1014 public void ifacmpne(final Label label) { 1015 mv.visitJumpInsn(Opcodes.IF_ACMPNE, label); 1016 } 1017 1018 public void goTo(final Label label) { 1019 mv.visitJumpInsn(Opcodes.GOTO, label); 1020 } 1021 1022 public void jsr(final Label label) { 1023 mv.visitJumpInsn(Opcodes.JSR, label); 1024 } 1025 1026 public void ret(final int varIndex) { 1027 mv.visitVarInsn(Opcodes.RET, varIndex); 1028 } 1029 1030 public void tableswitch(final int min, final int max, final Label dflt, final Label... labels) { 1031 mv.visitTableSwitchInsn(min, max, dflt, labels); 1032 } 1033 1034 public void lookupswitch(final Label dflt, final int[] keys, final Label[] labels) { 1035 mv.visitLookupSwitchInsn(dflt, keys, labels); 1036 } 1037 1038 public void areturn(final Type type) { 1039 mv.visitInsn(type.getOpcode(Opcodes.IRETURN)); 1040 } 1041 1042 public void getstatic(final String owner, final String name, final String descriptor) { 1043 mv.visitFieldInsn(Opcodes.GETSTATIC, owner, name, descriptor); 1044 } 1045 1046 public void putstatic(final String owner, final String name, final String descriptor) { 1047 mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, name, descriptor); 1048 } 1049 1050 public void getfield(final String owner, final String name, final String descriptor) { 1051 mv.visitFieldInsn(Opcodes.GETFIELD, owner, name, descriptor); 1052 } 1053 1054 public void putfield(final String owner, final String name, final String descriptor) { 1055 mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, descriptor); 1056 } 1057 1058 /** 1059 * Deprecated. 1060 * 1061 * @param owner the internal name of the method's owner class (see {@link 1062 * Type#getInternalName()}). 1063 * @param name the method's name. 1064 * @param descriptor the method's descriptor (see {@link Type}). 1065 * @deprecated use {@link #invokevirtual(String, String, String, boolean)} instead. 1066 */ 1067 @Deprecated 1068 public void invokevirtual(final String owner, final String name, final String descriptor) { 1069 if (api >= Opcodes.ASM5) { 1070 invokevirtual(owner, name, descriptor, false); 1071 return; 1072 } 1073 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, descriptor); 1074 } 1075 1076 /** 1077 * Generates the instruction to call the given virtual method. 1078 * 1079 * @param owner the internal name of the method's owner class (see {@link 1080 * Type#getInternalName()}). 1081 * @param name the method's name. 1082 * @param descriptor the method's descriptor (see {@link Type}). 1083 * @param isInterface if the method's owner class is an interface. 1084 */ 1085 public void invokevirtual( 1086 final String owner, final String name, final String descriptor, final boolean isInterface) { 1087 if (api < Opcodes.ASM5) { 1088 if (isInterface) { 1089 throw new UnsupportedOperationException("INVOKEVIRTUAL on interfaces require ASM 5"); 1090 } 1091 invokevirtual(owner, name, descriptor); 1092 return; 1093 } 1094 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, descriptor, isInterface); 1095 } 1096 1097 /** 1098 * Deprecated. 1099 * 1100 * @param owner the internal name of the method's owner class (see {@link 1101 * Type#getInternalName()}). 1102 * @param name the method's name. 1103 * @param descriptor the method's descriptor (see {@link Type}). 1104 * @deprecated use {@link #invokespecial(String, String, String, boolean)} instead. 1105 */ 1106 @Deprecated 1107 public void invokespecial(final String owner, final String name, final String descriptor) { 1108 if (api >= Opcodes.ASM5) { 1109 invokespecial(owner, name, descriptor, false); 1110 return; 1111 } 1112 mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, descriptor, false); 1113 } 1114 1115 /** 1116 * Generates the instruction to call the given special method. 1117 * 1118 * @param owner the internal name of the method's owner class (see {@link 1119 * Type#getInternalName()}). 1120 * @param name the method's name. 1121 * @param descriptor the method's descriptor (see {@link Type}). 1122 * @param isInterface if the method's owner class is an interface. 1123 */ 1124 public void invokespecial( 1125 final String owner, final String name, final String descriptor, final boolean isInterface) { 1126 if (api < Opcodes.ASM5) { 1127 if (isInterface) { 1128 throw new UnsupportedOperationException("INVOKESPECIAL on interfaces require ASM 5"); 1129 } 1130 invokespecial(owner, name, descriptor); 1131 return; 1132 } 1133 mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, descriptor, isInterface); 1134 } 1135 1136 /** 1137 * Deprecated. 1138 * 1139 * @param owner the internal name of the method's owner class (see {@link 1140 * Type#getInternalName()}). 1141 * @param name the method's name. 1142 * @param descriptor the method's descriptor (see {@link Type}). 1143 * @deprecated use {@link #invokestatic(String, String, String, boolean)} instead. 1144 */ 1145 @Deprecated 1146 public void invokestatic(final String owner, final String name, final String descriptor) { 1147 if (api >= Opcodes.ASM5) { 1148 invokestatic(owner, name, descriptor, false); 1149 return; 1150 } 1151 mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, false); 1152 } 1153 1154 /** 1155 * Generates the instruction to call the given static method. 1156 * 1157 * @param owner the internal name of the method's owner class (see {@link 1158 * Type#getInternalName()}). 1159 * @param name the method's name. 1160 * @param descriptor the method's descriptor (see {@link Type}). 1161 * @param isInterface if the method's owner class is an interface. 1162 */ 1163 public void invokestatic( 1164 final String owner, final String name, final String descriptor, final boolean isInterface) { 1165 if (api < Opcodes.ASM5) { 1166 if (isInterface) { 1167 throw new UnsupportedOperationException("INVOKESTATIC on interfaces require ASM 5"); 1168 } 1169 invokestatic(owner, name, descriptor); 1170 return; 1171 } 1172 mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, isInterface); 1173 } 1174 1175 /** 1176 * Generates the instruction to call the given interface method. 1177 * 1178 * @param owner the internal name of the method's owner class (see {@link 1179 * Type#getInternalName()}). 1180 * @param name the method's name. 1181 * @param descriptor the method's descriptor (see {@link Type}). 1182 */ 1183 public void invokeinterface(final String owner, final String name, final String descriptor) { 1184 mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, descriptor, true); 1185 } 1186 1187 /** 1188 * Generates the instruction to call the given dynamic method. 1189 * 1190 * @param name the method's name. 1191 * @param descriptor the method's descriptor (see {@link Type}). 1192 * @param bootstrapMethodHandle the bootstrap method. 1193 * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be 1194 * an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link 1195 * Type}, {@link Handle} or {@link ConstantDynamic} value. This method is allowed to modify 1196 * the content of the array so a caller should expect that this array may change. 1197 */ 1198 public void invokedynamic( 1199 final String name, 1200 final String descriptor, 1201 final Handle bootstrapMethodHandle, 1202 final Object[] bootstrapMethodArguments) { 1203 mv.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); 1204 } 1205 1206 public void anew(final Type type) { 1207 mv.visitTypeInsn(Opcodes.NEW, type.getInternalName()); 1208 } 1209 1210 /** 1211 * Generates the instruction to create and push on the stack an array of the given type. 1212 * 1213 * @param type an array Type. 1214 */ 1215 public void newarray(final Type type) { 1216 newarray(mv, type); 1217 } 1218 1219 /** 1220 * Generates the instruction to create and push on the stack an array of the given type. 1221 * 1222 * @param methodVisitor the method visitor to use to generate the instruction. 1223 * @param type an array Type. 1224 */ 1225 static void newarray(final MethodVisitor methodVisitor, final Type type) { 1226 int arrayType; 1227 switch (type.getSort()) { 1228 case Type.BOOLEAN: 1229 arrayType = Opcodes.T_BOOLEAN; 1230 break; 1231 case Type.CHAR: 1232 arrayType = Opcodes.T_CHAR; 1233 break; 1234 case Type.BYTE: 1235 arrayType = Opcodes.T_BYTE; 1236 break; 1237 case Type.SHORT: 1238 arrayType = Opcodes.T_SHORT; 1239 break; 1240 case Type.INT: 1241 arrayType = Opcodes.T_INT; 1242 break; 1243 case Type.FLOAT: 1244 arrayType = Opcodes.T_FLOAT; 1245 break; 1246 case Type.LONG: 1247 arrayType = Opcodes.T_LONG; 1248 break; 1249 case Type.DOUBLE: 1250 arrayType = Opcodes.T_DOUBLE; 1251 break; 1252 default: 1253 methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName()); 1254 return; 1255 } 1256 methodVisitor.visitIntInsn(Opcodes.NEWARRAY, arrayType); 1257 } 1258 1259 public void arraylength() { 1260 mv.visitInsn(Opcodes.ARRAYLENGTH); 1261 } 1262 1263 public void athrow() { 1264 mv.visitInsn(Opcodes.ATHROW); 1265 } 1266 1267 public void checkcast(final Type type) { 1268 mv.visitTypeInsn(Opcodes.CHECKCAST, type.getInternalName()); 1269 } 1270 1271 public void instanceOf(final Type type) { 1272 mv.visitTypeInsn(Opcodes.INSTANCEOF, type.getInternalName()); 1273 } 1274 1275 public void monitorenter() { 1276 mv.visitInsn(Opcodes.MONITORENTER); 1277 } 1278 1279 public void monitorexit() { 1280 mv.visitInsn(Opcodes.MONITOREXIT); 1281 } 1282 1283 public void multianewarray(final String descriptor, final int numDimensions) { 1284 mv.visitMultiANewArrayInsn(descriptor, numDimensions); 1285 } 1286 1287 public void ifnull(final Label label) { 1288 mv.visitJumpInsn(Opcodes.IFNULL, label); 1289 } 1290 1291 public void ifnonnull(final Label label) { 1292 mv.visitJumpInsn(Opcodes.IFNONNULL, label); 1293 } 1294 1295 public void mark(final Label label) { 1296 mv.visitLabel(label); 1297 } 1298}