1 /*** 2 * ASM: a very small and fast Java bytecode manipulation framework 3 * Copyright (c) 2000-2005 INRIA, France Telecom 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 package org.objectweb.asm.commons; 31 32 import java.util.ArrayList; 33 import java.util.Arrays; 34 import java.util.List; 35 36 import org.objectweb.asm.ClassVisitor; 37 import org.objectweb.asm.Label; 38 import org.objectweb.asm.MethodVisitor; 39 import org.objectweb.asm.Opcodes; 40 import org.objectweb.asm.Type; 41 42 /** 43 * A {@link org.objectweb.asm.MethodAdapter} with convenient methods to generate 44 * code. For example, using this adapter, the class below 45 * 46 * <pre> 47 * public class Example { 48 * public static void main(String[] args) { 49 * System.out.println("Hello world!"); 50 * } 51 * } 52 * </pre> 53 * 54 * can be generated as follows: 55 * 56 * <pre> 57 * ClassWriter cw = new ClassWriter(true); 58 * cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null); 59 * 60 * Method m = Method.getMethod("void <init> ()"); 61 * GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw); 62 * mg.loadThis(); 63 * mg.invokeConstructor(Type.getType(Object.class), m); 64 * mg.returnValue(); 65 * mg.endMethod(); 66 * 67 * m = Method.getMethod("void main (String[])"); 68 * mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw); 69 * mg.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class)); 70 * mg.push("Hello world!"); 71 * mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println (String)")); 72 * mg.returnValue(); 73 * mg.endMethod(); 74 * 75 * cw.visitEnd(); 76 * </pre> 77 * 78 * @author Juozas Baliuka 79 * @author Chris Nokleberg 80 * @author Eric Bruneton 81 */ 82 public class GeneratorAdapter extends LocalVariablesSorter { 83 84 private final static Type BYTE_TYPE = Type.getType("Ljava/lang/Byte;"); 85 86 private final static Type BOOLEAN_TYPE = Type.getType("Ljava/lang/Boolean;"); 87 88 private final static Type SHORT_TYPE = Type.getType("Ljava/lang/Short;"); 89 90 private final static Type CHARACTER_TYPE = Type.getType("Ljava/lang/Character;"); 91 92 private final static Type INTEGER_TYPE = Type.getType("Ljava/lang/Integer;"); 93 94 private final static Type FLOAT_TYPE = Type.getType("Ljava/lang/Float;"); 95 96 private final static Type LONG_TYPE = Type.getType("Ljava/lang/Long;"); 97 98 private final static Type DOUBLE_TYPE = Type.getType("Ljava/lang/Double;"); 99 100 private final static Type NUMBER_TYPE = Type.getType("Ljava/lang/Number;"); 101 102 private final static Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); 103 104 private final static Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()"); 105 106 private final static Method CHAR_VALUE = Method.getMethod("char charValue()"); 107 108 private final static Method INT_VALUE = Method.getMethod("int intValue()"); 109 110 private final static Method FLOAT_VALUE = Method.getMethod("float floatValue()"); 111 112 private final static Method LONG_VALUE = Method.getMethod("long longValue()"); 113 114 private final static Method DOUBLE_VALUE = Method.getMethod("double doubleValue()"); 115 116 /** 117 * Constant for the {@link #math math} method. 118 */ 119 public final static int ADD = Opcodes.IADD; 120 121 /** 122 * Constant for the {@link #math math} method. 123 */ 124 public final static int SUB = Opcodes.ISUB; 125 126 /** 127 * Constant for the {@link #math math} method. 128 */ 129 public final static int MUL = Opcodes.IMUL; 130 131 /** 132 * Constant for the {@link #math math} method. 133 */ 134 public final static int DIV = Opcodes.IDIV; 135 136 /** 137 * Constant for the {@link #math math} method. 138 */ 139 public final static int REM = Opcodes.IREM; 140 141 /** 142 * Constant for the {@link #math math} method. 143 */ 144 public final static int NEG = Opcodes.INEG; 145 146 /** 147 * Constant for the {@link #math math} method. 148 */ 149 public final static int SHL = Opcodes.ISHL; 150 151 /** 152 * Constant for the {@link #math math} method. 153 */ 154 public final static int SHR = Opcodes.ISHR; 155 156 /** 157 * Constant for the {@link #math math} method. 158 */ 159 public final static int USHR = Opcodes.IUSHR; 160 161 /** 162 * Constant for the {@link #math math} method. 163 */ 164 public final static int AND = Opcodes.IAND; 165 166 /** 167 * Constant for the {@link #math math} method. 168 */ 169 public final static int OR = Opcodes.IOR; 170 171 /** 172 * Constant for the {@link #math math} method. 173 */ 174 public final static int XOR = Opcodes.IXOR; 175 176 /** 177 * Constant for the {@link #ifCmp ifCmp} method. 178 */ 179 public final static int EQ = Opcodes.IFEQ; 180 181 /** 182 * Constant for the {@link #ifCmp ifCmp} method. 183 */ 184 public final static int NE = Opcodes.IFNE; 185 186 /** 187 * Constant for the {@link #ifCmp ifCmp} method. 188 */ 189 public final static int LT = Opcodes.IFLT; 190 191 /** 192 * Constant for the {@link #ifCmp ifCmp} method. 193 */ 194 public final static int GE = Opcodes.IFGE; 195 196 /** 197 * Constant for the {@link #ifCmp ifCmp} method. 198 */ 199 public final static int GT = Opcodes.IFGT; 200 201 /** 202 * Constant for the {@link #ifCmp ifCmp} method. 203 */ 204 public final static int LE = Opcodes.IFLE; 205 206 /** 207 * Access flags of the method visited by this adapter. 208 */ 209 private final int access; 210 211 /** 212 * Return type of the method visited by this adapter. 213 */ 214 private final Type returnType; 215 216 /** 217 * Argument types of the method visited by this adapter. 218 */ 219 private final Type[] argumentTypes; 220 221 /** 222 * Types of the local variables of the method visited by this adapter. 223 */ 224 private final List localTypes; 225 226 /** 227 * Creates a new {@link GeneratorAdapter}. 228 * 229 * @param mv the method visitor to which this adapter delegates calls. 230 * @param access the method's access flags (see {@link Opcodes}). 231 * @param name the method's name. 232 * @param desc the method's descriptor (see {@link Type Type}). 233 */ 234 public GeneratorAdapter( 235 MethodVisitor mv, 236 int access, 237 String name, 238 String desc) 239 { 240 super(access, desc, mv); 241 this.access = access; 242 this.returnType = Type.getReturnType(desc); 243 this.argumentTypes = Type.getArgumentTypes(desc); 244 this.localTypes = new ArrayList(); 245 } 246 247 /** 248 * Creates a new {@link GeneratorAdapter}. 249 * 250 * @param access access flags of the adapted method. 251 * @param method the adapted method. 252 * @param mv the method visitor to which this adapter delegates calls. 253 */ 254 public GeneratorAdapter( 255 final int access, 256 final Method method, 257 final MethodVisitor mv) 258 { 259 super(access, method.getDescriptor(), mv); 260 this.access = access; 261 this.returnType = method.getReturnType(); 262 this.argumentTypes = method.getArgumentTypes(); 263 this.localTypes = new ArrayList(); 264 } 265 266 /** 267 * Creates a new {@link GeneratorAdapter}. 268 * 269 * @param access access flags of the adapted method. 270 * @param method the adapted method. 271 * @param signature the signature of the adapted method (may be 272 * <tt>null</tt>). 273 * @param exceptions the exceptions thrown by the adapted method (may be 274 * <tt>null</tt>). 275 * @param cv the class visitor to which this adapter delegates calls. 276 */ 277 public GeneratorAdapter( 278 final int access, 279 final Method method, 280 final String signature, 281 final Type[] exceptions, 282 final ClassVisitor cv) 283 { 284 this(access, method, cv.visitMethod(access, 285 method.getName(), 286 method.getDescriptor(), 287 signature, 288 getInternalNames(exceptions))); 289 } 290 291 /** 292 * Returns the internal names of the given types. 293 * 294 * @param types a set of types. 295 * @return the internal names of the given types. 296 */ 297 private static String[] getInternalNames(final Type[] types) { 298 if (types == null) { 299 return null; 300 } 301 String[] names = new String[types.length]; 302 for (int i = 0; i < names.length; ++i) { 303 names[i] = types[i].getInternalName(); 304 } 305 return names; 306 } 307 308 // ------------------------------------------------------------------------ 309 // Instructions to push constants on the stack 310 // ------------------------------------------------------------------------ 311 312 /** 313 * Generates the instruction to push the given value on the stack. 314 * 315 * @param value the value to be pushed on the stack. 316 */ 317 public void push(final boolean value) { 318 push(value ? 1 : 0); 319 } 320 321 /** 322 * Generates the instruction to push the given value on the stack. 323 * 324 * @param value the value to be pushed on the stack. 325 */ 326 public void push(final int value) { 327 if (value >= -1 && value <= 5) { 328 mv.visitInsn(Opcodes.ICONST_0 + value); 329 } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { 330 mv.visitIntInsn(Opcodes.BIPUSH, value); 331 } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { 332 mv.visitIntInsn(Opcodes.SIPUSH, value); 333 } else { 334 mv.visitLdcInsn(new Integer(value)); 335 } 336 } 337 338 /** 339 * Generates the instruction to push the given value on the stack. 340 * 341 * @param value the value to be pushed on the stack. 342 */ 343 public void push(final long value) { 344 if (value == 0L || value == 1L) { 345 mv.visitInsn(Opcodes.LCONST_0 + (int) value); 346 } else { 347 mv.visitLdcInsn(new Long(value)); 348 } 349 } 350 351 /** 352 * Generates the instruction to push the given value on the stack. 353 * 354 * @param value the value to be pushed on the stack. 355 */ 356 public void push(final float value) { 357 int bits = Float.floatToIntBits(value); 358 if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2 359 mv.visitInsn(Opcodes.FCONST_0 + (int) value); 360 } else { 361 mv.visitLdcInsn(new Float(value)); 362 } 363 } 364 365 /** 366 * Generates the instruction to push the given value on the stack. 367 * 368 * @param value the value to be pushed on the stack. 369 */ 370 public void push(final double value) { 371 long bits = Double.doubleToLongBits(value); 372 if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d 373 mv.visitInsn(Opcodes.DCONST_0 + (int) value); 374 } else { 375 mv.visitLdcInsn(new Double(value)); 376 } 377 } 378 379 /** 380 * Generates the instruction to push the given value on the stack. 381 * 382 * @param value the value to be pushed on the stack. May be <tt>null</tt>. 383 */ 384 public void push(final String value) { 385 if (value == null) { 386 mv.visitInsn(Opcodes.ACONST_NULL); 387 } else { 388 mv.visitLdcInsn(value); 389 } 390 } 391 392 /** 393 * Generates the instruction to push the given value on the stack. 394 * 395 * @param value the value to be pushed on the stack. 396 */ 397 public void push(final Type value) { 398 if (value == null) { 399 mv.visitInsn(Opcodes.ACONST_NULL); 400 } else { 401 mv.visitLdcInsn(value); 402 } 403 } 404 405 // ------------------------------------------------------------------------ 406 // Instructions to load and store method arguments 407 // ------------------------------------------------------------------------ 408 409 /** 410 * Returns the index of the given method argument in the frame's local 411 * variables array. 412 * 413 * @param arg the index of a method argument. 414 * @return the index of the given method argument in the frame's local 415 * variables array. 416 */ 417 private int getArgIndex(final int arg) { 418 int index = ((access & Opcodes.ACC_STATIC) == 0 ? 1 : 0); 419 for (int i = 0; i < arg; i++) { 420 index += argumentTypes[i].getSize(); 421 } 422 return index; 423 } 424 425 /** 426 * Generates the instruction to push a local variable on the stack. 427 * 428 * @param type the type of the local variable to be loaded. 429 * @param index an index in the frame's local variables array. 430 */ 431 private void loadInsn(final Type type, final int index) { 432 mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index); 433 } 434 435 /** 436 * Generates the instruction to store the top stack value in a local 437 * variable. 438 * 439 * @param type the type of the local variable to be stored. 440 * @param index an index in the frame's local variables array. 441 */ 442 private void storeInsn(final Type type, final int index) { 443 mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index); 444 } 445 446 /** 447 * Generates the instruction to load 'this' on the stack. 448 */ 449 public void loadThis() { 450 if ((access & Opcodes.ACC_STATIC) != 0) { 451 throw new IllegalStateException("no 'this' pointer within static method"); 452 } 453 mv.visitVarInsn(Opcodes.ALOAD, 0); 454 } 455 456 /** 457 * Generates the instruction to load the given method argument on the stack. 458 * 459 * @param arg the index of a method argument. 460 */ 461 public void loadArg(final int arg) { 462 loadInsn(argumentTypes[arg], getArgIndex(arg)); 463 } 464 465 /** 466 * Generates the instructions to load the given method arguments on the 467 * stack. 468 * 469 * @param arg the index of the first method argument to be loaded. 470 * @param count the number of method arguments to be loaded. 471 */ 472 public void loadArgs(final int arg, final int count) { 473 int index = getArgIndex(arg); 474 for (int i = 0; i < count; ++i) { 475 Type t = argumentTypes[arg + i]; 476 loadInsn(t, index); 477 index += t.getSize(); 478 } 479 } 480 481 /** 482 * Generates the instructions to load all the method arguments on the stack. 483 */ 484 public void loadArgs() { 485 loadArgs(0, argumentTypes.length); 486 } 487 488 /** 489 * Generates the instructions to load all the method arguments on the stack, 490 * as a single object array. 491 */ 492 public void loadArgArray() { 493 push(argumentTypes.length); 494 newArray(OBJECT_TYPE); 495 for (int i = 0; i < argumentTypes.length; i++) { 496 dup(); 497 push(i); 498 loadArg(i); 499 box(argumentTypes[i]); 500 arrayStore(OBJECT_TYPE); 501 } 502 } 503 504 /** 505 * Generates the instruction to store the top stack value in the given 506 * method argument. 507 * 508 * @param arg the index of a method argument. 509 */ 510 public void storeArg(final int arg) { 511 storeInsn(argumentTypes[arg], getArgIndex(arg)); 512 } 513 514 // ------------------------------------------------------------------------ 515 // Instructions to load and store local variables 516 // ------------------------------------------------------------------------ 517 518 /** 519 * Creates a new local variable of the given type. 520 * 521 * @param type the type of the local variable to be created. 522 * @return the identifier of the newly created local variable. 523 */ 524 public int newLocal(final Type type) { 525 int local = super.newLocal(type.getSize()); 526 setLocalType(local, type); 527 return local; 528 } 529 530 /** 531 * Returns the type of the given local variable. 532 * 533 * @param local a local variable identifier, as returned by {@link #newLocal 534 * newLocal}. 535 * @return the type of the given local variable. 536 */ 537 public Type getLocalType(final int local) { 538 return (Type) localTypes.get(local - firstLocal); 539 } 540 541 /** 542 * Sets the current type of the given local variable. 543 * 544 * @param local a local variable identifier, as returned by {@link #newLocal 545 * newLocal}. 546 * @param type the type of the value being stored in the local variable 547 */ 548 private void setLocalType(final int local, final Type type) { 549 int index = local - firstLocal; 550 while (localTypes.size() < index + 1) 551 localTypes.add(null); 552 localTypes.set(index, type); 553 } 554 555 /** 556 * Generates the instruction to load the given local variable on the stack. 557 * 558 * @param local a local variable identifier, as returned by {@link #newLocal 559 * newLocal}. 560 */ 561 public void loadLocal(final int local) { 562 loadInsn(getLocalType(local), local); 563 } 564 565 /** 566 * Generates the instruction to load the given local variable on the stack. 567 * 568 * @param local a local variable identifier, as returned by {@link #newLocal 569 * newLocal}. 570 * @param type the type of this local variable. 571 */ 572 public void loadLocal(final int local, final Type type) { 573 setLocalType(local, type); 574 loadInsn(type, local); 575 } 576 577 /** 578 * Generates the instruction to store the top stack value in the given local 579 * variable. 580 * 581 * @param local a local variable identifier, as returned by {@link #newLocal 582 * newLocal}. 583 */ 584 public void storeLocal(final int local) { 585 storeInsn(getLocalType(local), local); 586 } 587 588 /** 589 * Generates the instruction to store the top stack value in the given local 590 * variable. 591 * 592 * @param local a local variable identifier, as returned by {@link #newLocal 593 * newLocal}. 594 * @param type the type of this local variable. 595 */ 596 public void storeLocal(final int local, final Type type) { 597 setLocalType(local, type); 598 storeInsn(type, local); 599 } 600 601 /** 602 * Generates the instruction to load an element from an array. 603 * 604 * @param type the type of the array element to be loaded. 605 */ 606 public void arrayLoad(final Type type) { 607 mv.visitInsn(type.getOpcode(Opcodes.IALOAD)); 608 } 609 610 /** 611 * Generates the instruction to store an element in an array. 612 * 613 * @param type the type of the array element to be stored. 614 */ 615 public void arrayStore(final Type type) { 616 mv.visitInsn(type.getOpcode(Opcodes.IASTORE)); 617 } 618 619 // ------------------------------------------------------------------------ 620 // Instructions to manage the stack 621 // ------------------------------------------------------------------------ 622 623 /** 624 * Generates a POP instruction. 625 */ 626 public void pop() { 627 mv.visitInsn(Opcodes.POP); 628 } 629 630 /** 631 * Generates a POP2 instruction. 632 */ 633 public void pop2() { 634 mv.visitInsn(Opcodes.POP2); 635 } 636 637 /** 638 * Generates a DUP instruction. 639 */ 640 public void dup() { 641 mv.visitInsn(Opcodes.DUP); 642 } 643 644 /** 645 * Generates a DUP2 instruction. 646 */ 647 public void dup2() { 648 mv.visitInsn(Opcodes.DUP2); 649 } 650 651 /** 652 * Generates a DUP_X1 instruction. 653 */ 654 public void dupX1() { 655 mv.visitInsn(Opcodes.DUP_X1); 656 } 657 658 /** 659 * Generates a DUP_X2 instruction. 660 */ 661 public void dupX2() { 662 mv.visitInsn(Opcodes.DUP_X2); 663 } 664 665 /** 666 * Generates a DUP2_X1 instruction. 667 */ 668 public void dup2X1() { 669 mv.visitInsn(Opcodes.DUP2_X1); 670 } 671 672 /** 673 * Generates a DUP2_X2 instruction. 674 */ 675 public void dup2X2() { 676 mv.visitInsn(Opcodes.DUP2_X2); 677 } 678 679 /** 680 * Generates a SWAP instruction. 681 */ 682 public void swap() { 683 mv.visitInsn(Opcodes.SWAP); 684 } 685 686 /** 687 * Generates the instructions to swap the top two stack values. 688 * 689 * @param prev type of the top - 1 stack value. 690 * @param type type of the top stack value. 691 */ 692 public void swap(final Type prev, final Type type) { 693 if (type.getSize() == 1) { 694 if (prev.getSize() == 1) { 695 swap(); // same as dupX1(), pop(); 696 } else { 697 dupX2(); 698 pop(); 699 } 700 } else { 701 if (prev.getSize() == 1) { 702 dup2X1(); 703 pop2(); 704 } else { 705 dup2X2(); 706 pop2(); 707 } 708 } 709 } 710 711 // ------------------------------------------------------------------------ 712 // Instructions to do mathematical and logical operations 713 // ------------------------------------------------------------------------ 714 715 /** 716 * Generates the instruction to do the specified mathematical or logical 717 * operation. 718 * 719 * @param op a mathematical or logical operation. Must be one of ADD, SUB, 720 * MUL, DIV, REM, NEG, SHL, SHR, USHR, AND, OR, XOR. 721 * @param type the type of the operand(s) for this operation. 722 */ 723 public void math(final int op, final Type type) { 724 mv.visitInsn(type.getOpcode(op)); 725 } 726 727 /** 728 * Generates the instructions to compute the bitwise negation of the top 729 * stack value. 730 */ 731 public void not() { 732 mv.visitInsn(Opcodes.ICONST_1); 733 mv.visitInsn(Opcodes.IXOR); 734 } 735 736 /** 737 * Generates the instruction to increment the given local variable. 738 * 739 * @param local the local variable to be incremented. 740 * @param amount the amount by which the local variable must be incremented. 741 */ 742 public void iinc(final int local, final int amount) { 743 mv.visitIincInsn(local, amount); 744 } 745 746 /** 747 * Generates the instructions to cast a numerical value from one type to 748 * another. 749 * 750 * @param from the type of the top stack value 751 * @param to the type into which this value must be cast. 752 */ 753 public void cast(final Type from, final Type to) { 754 if (from != to) { 755 if (from == Type.DOUBLE_TYPE) { 756 if (to == Type.FLOAT_TYPE) { 757 mv.visitInsn(Opcodes.D2F); 758 } else if (to == Type.LONG_TYPE) { 759 mv.visitInsn(Opcodes.D2L); 760 } else { 761 mv.visitInsn(Opcodes.D2I); 762 cast(Type.INT_TYPE, to); 763 } 764 } else if (from == Type.FLOAT_TYPE) { 765 if (to == Type.DOUBLE_TYPE) { 766 mv.visitInsn(Opcodes.F2D); 767 } else if (to == Type.LONG_TYPE) { 768 mv.visitInsn(Opcodes.F2L); 769 } else { 770 mv.visitInsn(Opcodes.F2I); 771 cast(Type.INT_TYPE, to); 772 } 773 } else if (from == Type.LONG_TYPE) { 774 if (to == Type.DOUBLE_TYPE) { 775 mv.visitInsn(Opcodes.L2D); 776 } else if (to == Type.FLOAT_TYPE) { 777 mv.visitInsn(Opcodes.L2F); 778 } else { 779 mv.visitInsn(Opcodes.L2I); 780 cast(Type.INT_TYPE, to); 781 } 782 } else { 783 if (to == Type.BYTE_TYPE) { 784 mv.visitInsn(Opcodes.I2B); 785 } else if (to == Type.CHAR_TYPE) { 786 mv.visitInsn(Opcodes.I2C); 787 } else if (to == Type.DOUBLE_TYPE) { 788 mv.visitInsn(Opcodes.I2D); 789 } else if (to == Type.FLOAT_TYPE) { 790 mv.visitInsn(Opcodes.I2F); 791 } else if (to == Type.LONG_TYPE) { 792 mv.visitInsn(Opcodes.I2L); 793 } else if (to == Type.SHORT_TYPE) { 794 mv.visitInsn(Opcodes.I2S); 795 } 796 } 797 } 798 } 799 800 // ------------------------------------------------------------------------ 801 // Instructions to do boxing and unboxing operations 802 // ------------------------------------------------------------------------ 803 804 /** 805 * Generates the instructions to box the top stack value. This value is 806 * replaced by its boxed equivalent on top of the stack. 807 * 808 * @param type the type of the top stack value. 809 */ 810 public void box(final Type type) { 811 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { 812 return; 813 } 814 if (type == Type.VOID_TYPE) { 815 push((String) null); 816 } else { 817 Type boxed = type; 818 switch (type.getSort()) { 819 case Type.BYTE: 820 boxed = BYTE_TYPE; 821 break; 822 case Type.BOOLEAN: 823 boxed = BOOLEAN_TYPE; 824 break; 825 case Type.SHORT: 826 boxed = SHORT_TYPE; 827 break; 828 case Type.CHAR: 829 boxed = CHARACTER_TYPE; 830 break; 831 case Type.INT: 832 boxed = INTEGER_TYPE; 833 break; 834 case Type.FLOAT: 835 boxed = FLOAT_TYPE; 836 break; 837 case Type.LONG: 838 boxed = LONG_TYPE; 839 break; 840 case Type.DOUBLE: 841 boxed = DOUBLE_TYPE; 842 break; 843 } 844 newInstance(boxed); 845 if (type.getSize() == 2) { 846 // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o 847 dupX2(); 848 dupX2(); 849 pop(); 850 } else { 851 // p -> po -> opo -> oop -> o 852 dupX1(); 853 swap(); 854 } 855 invokeConstructor(boxed, new Method("<init>", 856 Type.VOID_TYPE, 857 new Type[] { type })); 858 } 859 } 860 861 /** 862 * Generates the instructions to unbox the top stack value. This value is 863 * replaced by its unboxed equivalent on top of the stack. 864 * 865 * @param type the type of the top stack value. 866 */ 867 public void unbox(final Type type) { 868 Type t = NUMBER_TYPE; 869 Method sig = null; 870 switch (type.getSort()) { 871 case Type.VOID: 872 return; 873 case Type.CHAR: 874 t = CHARACTER_TYPE; 875 sig = CHAR_VALUE; 876 break; 877 case Type.BOOLEAN: 878 t = BOOLEAN_TYPE; 879 sig = BOOLEAN_VALUE; 880 break; 881 case Type.DOUBLE: 882 sig = DOUBLE_VALUE; 883 break; 884 case Type.FLOAT: 885 sig = FLOAT_VALUE; 886 break; 887 case Type.LONG: 888 sig = LONG_VALUE; 889 break; 890 case Type.INT: 891 case Type.SHORT: 892 case Type.BYTE: 893 sig = INT_VALUE; 894 } 895 if (sig == null) { 896 checkCast(type); 897 } else { 898 checkCast(t); 899 invokeVirtual(t, sig); 900 } 901 } 902 903 // ------------------------------------------------------------------------ 904 // Instructions to jump to other instructions 905 // ------------------------------------------------------------------------ 906 907 /** 908 * Creates a new {@link Label}. 909 * 910 * @return a new {@link Label}. 911 */ 912 public Label newLabel() { 913 return new Label(); 914 } 915 916 /** 917 * Marks the current code position with the given label. 918 * 919 * @param label a label. 920 */ 921 public void mark(final Label label) { 922 mv.visitLabel(label); 923 } 924 925 /** 926 * Marks the current code position with a new label. 927 * 928 * @return the label that was created to mark the current code position. 929 */ 930 public Label mark() { 931 Label label = new Label(); 932 mv.visitLabel(label); 933 return label; 934 } 935 936 /** 937 * Generates the instructions to jump to a label based on the comparison of 938 * the top two stack values. 939 * 940 * @param type the type of the top two stack values. 941 * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, 942 * LE. 943 * @param label where to jump if the comparison result is <tt>true</tt>. 944 */ 945 public void ifCmp(final Type type, final int mode, final Label label) { 946 int intOp = -1; 947 int jumpMode = mode; 948 switch (mode) { 949 case GE: 950 jumpMode = LT; 951 break; 952 case LE: 953 jumpMode = GT; 954 break; 955 } 956 switch (type.getSort()) { 957 case Type.LONG: 958 mv.visitInsn(Opcodes.LCMP); 959 break; 960 case Type.DOUBLE: 961 mv.visitInsn(Opcodes.DCMPG); 962 break; 963 case Type.FLOAT: 964 mv.visitInsn(Opcodes.FCMPG); 965 break; 966 case Type.ARRAY: 967 case Type.OBJECT: 968 switch (mode) { 969 case EQ: 970 mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label); 971 return; 972 case NE: 973 mv.visitJumpInsn(Opcodes.IF_ACMPNE, label); 974 return; 975 } 976 throw new IllegalArgumentException("Bad comparison for type " 977 + type); 978 default: 979 switch (mode) { 980 case EQ: 981 intOp = Opcodes.IF_ICMPEQ; 982 break; 983 case NE: 984 intOp = Opcodes.IF_ICMPNE; 985 break; 986 case GE: 987 intOp = Opcodes.IF_ICMPGE; 988 break; 989 case LT: 990 intOp = Opcodes.IF_ICMPLT; 991 break; 992 case LE: 993 intOp = Opcodes.IF_ICMPLE; 994 break; 995 case GT: 996 intOp = Opcodes.IF_ICMPGT; 997 break; 998 } 999 mv.visitJumpInsn(intOp, label); 1000 return; 1001 } 1002 mv.visitJumpInsn(jumpMode, label); 1003 } 1004 1005 /** 1006 * Generates the instructions to jump to a label based on the comparison of 1007 * the top two integer stack values. 1008 * 1009 * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, 1010 * LE. 1011 * @param label where to jump if the comparison result is <tt>true</tt>. 1012 */ 1013 public void ifICmp(final int mode, final Label label) { 1014 ifCmp(Type.INT_TYPE, mode, label); 1015 } 1016 1017 /** 1018 * Generates the instructions to jump to a label based on the comparison of 1019 * the top integer stack value with zero. 1020 * 1021 * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, 1022 * LE. 1023 * @param label where to jump if the comparison result is <tt>true</tt>. 1024 */ 1025 public void ifZCmp(final int mode, final Label label) { 1026 mv.visitJumpInsn(mode, label); 1027 } 1028 1029 /** 1030 * Generates the instruction to jump to the given label if the top stack 1031 * value is null. 1032 * 1033 * @param label where to jump if the condition is <tt>true</tt>. 1034 */ 1035 public void ifNull(final Label label) { 1036 mv.visitJumpInsn(Opcodes.IFNULL, label); 1037 } 1038 1039 /** 1040 * Generates the instruction to jump to the given label if the top stack 1041 * value is not null. 1042 * 1043 * @param label where to jump if the condition is <tt>true</tt>. 1044 */ 1045 public void ifNonNull(final Label label) { 1046 mv.visitJumpInsn(Opcodes.IFNONNULL, label); 1047 } 1048 1049 /** 1050 * Generates the instruction to jump to the given label. 1051 * 1052 * @param label where to jump if the condition is <tt>true</tt>. 1053 */ 1054 public void goTo(final Label label) { 1055 mv.visitJumpInsn(Opcodes.GOTO, label); 1056 } 1057 1058 /** 1059 * Generates a RET instruction. 1060 * 1061 * @param local a local variable identifier, as returned by {@link #newLocal 1062 * newLocal}. 1063 */ 1064 public void ret(final int local) { 1065 mv.visitVarInsn(Opcodes.RET, local); 1066 } 1067 1068 /** 1069 * Generates the instructions for a switch statement. 1070 * 1071 * @param keys the switch case keys. 1072 * @param generator a generator to generate the code for the switch cases. 1073 */ 1074 public void tableSwitch( 1075 final int[] keys, 1076 final TableSwitchGenerator generator) 1077 { 1078 float density; 1079 if (keys.length == 0) { 1080 density = 0; 1081 } else { 1082 density = (float) keys.length 1083 / (keys[keys.length - 1] - keys[0] + 1); 1084 } 1085 tableSwitch(keys, generator, density >= 0.5f); 1086 } 1087 1088 /** 1089 * Generates the instructions for a switch statement. 1090 * 1091 * @param keys the switch case keys. 1092 * @param generator a generator to generate the code for the switch cases. 1093 * @param useTable <tt>true</tt> to use a TABLESWITCH instruction, or 1094 * <tt>false</tt> to use a LOOKUPSWITCH instruction. 1095 */ 1096 public void tableSwitch( 1097 final int[] keys, 1098 final TableSwitchGenerator generator, 1099 final boolean useTable) 1100 { 1101 for (int i = 1; i < keys.length; ++i) { 1102 if (keys[i] < keys[i - 1]) { 1103 throw new IllegalArgumentException("keys must be sorted ascending"); 1104 } 1105 } 1106 Label def = newLabel(); 1107 Label end = newLabel(); 1108 if (keys.length > 0) { 1109 int len = keys.length; 1110 int min = keys[0]; 1111 int max = keys[len - 1]; 1112 int range = max - min + 1; 1113 if (useTable) { 1114 Label[] labels = new Label[range]; 1115 Arrays.fill(labels, def); 1116 for (int i = 0; i < len; ++i) { 1117 labels[keys[i] - min] = newLabel(); 1118 } 1119 mv.visitTableSwitchInsn(min, max, def, labels); 1120 for (int i = 0; i < range; ++i) { 1121 Label label = labels[i]; 1122 if (label != def) { 1123 mark(label); 1124 generator.generateCase(i + min, end); 1125 } 1126 } 1127 } else { 1128 Label[] labels = new Label[len]; 1129 for (int i = 0; i < len; ++i) { 1130 labels[i] = newLabel(); 1131 } 1132 mv.visitLookupSwitchInsn(def, keys, labels); 1133 for (int i = 0; i < len; ++i) { 1134 mark(labels[i]); 1135 generator.generateCase(keys[i], end); 1136 } 1137 } 1138 } 1139 mark(def); 1140 generator.generateDefault(); 1141 mark(end); 1142 } 1143 1144 /** 1145 * Generates the instruction to return the top stack value to the caller. 1146 */ 1147 public void returnValue() { 1148 mv.visitInsn(returnType.getOpcode(Opcodes.IRETURN)); 1149 } 1150 1151 // ------------------------------------------------------------------------ 1152 // Instructions to load and store fields 1153 // ------------------------------------------------------------------------ 1154 1155 /** 1156 * Generates a get field or set field instruction. 1157 * 1158 * @param opcode the instruction's opcode. 1159 * @param ownerType the class in which the field is defined. 1160 * @param name the name of the field. 1161 * @param fieldType the type of the field. 1162 */ 1163 private void fieldInsn( 1164 final int opcode, 1165 final Type ownerType, 1166 final String name, 1167 final Type fieldType) 1168 { 1169 mv.visitFieldInsn(opcode, 1170 ownerType.getInternalName(), 1171 name, 1172 fieldType.getDescriptor()); 1173 } 1174 1175 /** 1176 * Generates the instruction to push the value of a static field on the 1177 * stack. 1178 * 1179 * @param owner the class in which the field is defined. 1180 * @param name the name of the field. 1181 * @param type the type of the field. 1182 */ 1183 public void getStatic(final Type owner, final String name, final Type type) 1184 { 1185 fieldInsn(Opcodes.GETSTATIC, owner, name, type); 1186 } 1187 1188 /** 1189 * Generates the instruction to store the top stack value in a static field. 1190 * 1191 * @param owner the class in which the field is defined. 1192 * @param name the name of the field. 1193 * @param type the type of the field. 1194 */ 1195 public void putStatic(final Type owner, final String name, final Type type) 1196 { 1197 fieldInsn(Opcodes.PUTSTATIC, owner, name, type); 1198 } 1199 1200 /** 1201 * Generates the instruction to push the value of a non static field on the 1202 * stack. 1203 * 1204 * @param owner the class in which the field is defined. 1205 * @param name the name of the field. 1206 * @param type the type of the field. 1207 */ 1208 public void getField(final Type owner, final String name, final Type type) { 1209 fieldInsn(Opcodes.GETFIELD, owner, name, type); 1210 } 1211 1212 /** 1213 * Generates the instruction to store the top stack value in a non static 1214 * field. 1215 * 1216 * @param owner the class in which the field is defined. 1217 * @param name the name of the field. 1218 * @param type the type of the field. 1219 */ 1220 public void putField(final Type owner, final String name, final Type type) { 1221 fieldInsn(Opcodes.PUTFIELD, owner, name, type); 1222 } 1223 1224 // ------------------------------------------------------------------------ 1225 // Instructions to invoke methods 1226 // ------------------------------------------------------------------------ 1227 1228 /** 1229 * Generates an invoke method instruction. 1230 * 1231 * @param opcode the instruction's opcode. 1232 * @param type the class in which the method is defined. 1233 * @param method the method to be invoked. 1234 */ 1235 private void invokeInsn( 1236 final int opcode, 1237 final Type type, 1238 final Method method) 1239 { 1240 String owner = type.getSort() == Type.ARRAY 1241 ? type.getDescriptor() 1242 : type.getInternalName(); 1243 mv.visitMethodInsn(opcode, 1244 owner, 1245 method.getName(), 1246 method.getDescriptor()); 1247 } 1248 1249 /** 1250 * Generates the instruction to invoke a normal method. 1251 * 1252 * @param owner the class in which the method is defined. 1253 * @param method the method to be invoked. 1254 */ 1255 public void invokeVirtual(final Type owner, final Method method) { 1256 invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method); 1257 } 1258 1259 /** 1260 * Generates the instruction to invoke a constructor. 1261 * 1262 * @param type the class in which the constructor is defined. 1263 * @param method the constructor to be invoked. 1264 */ 1265 public void invokeConstructor(final Type type, final Method method) { 1266 invokeInsn(Opcodes.INVOKESPECIAL, type, method); 1267 } 1268 1269 /** 1270 * Generates the instruction to invoke a static method. 1271 * 1272 * @param owner the class in which the method is defined. 1273 * @param method the method to be invoked. 1274 */ 1275 public void invokeStatic(final Type owner, final Method method) { 1276 invokeInsn(Opcodes.INVOKESTATIC, owner, method); 1277 } 1278 1279 /** 1280 * Generates the instruction to invoke an interface method. 1281 * 1282 * @param owner the class in which the method is defined. 1283 * @param method the method to be invoked. 1284 */ 1285 public void invokeInterface(final Type owner, final Method method) { 1286 invokeInsn(Opcodes.INVOKEINTERFACE, owner, method); 1287 } 1288 1289 // ------------------------------------------------------------------------ 1290 // Instructions to create objects and arrays 1291 // ------------------------------------------------------------------------ 1292 1293 /** 1294 * Generates a type dependent instruction. 1295 * 1296 * @param opcode the instruction's opcode. 1297 * @param type the instruction's operand. 1298 */ 1299 private void typeInsn(final int opcode, final Type type) { 1300 String desc; 1301 if (type.getSort() == Type.ARRAY) { 1302 desc = type.getDescriptor(); 1303 } else { 1304 desc = type.getInternalName(); 1305 } 1306 mv.visitTypeInsn(opcode, desc); 1307 } 1308 1309 /** 1310 * Generates the instruction to create a new object. 1311 * 1312 * @param type the class of the object to be created. 1313 */ 1314 public void newInstance(final Type type) { 1315 typeInsn(Opcodes.NEW, type); 1316 } 1317 1318 /** 1319 * Generates the instruction to create a new array. 1320 * 1321 * @param type the type of the array elements. 1322 */ 1323 public void newArray(final Type type) { 1324 int typ; 1325 switch (type.getSort()) { 1326 case Type.BOOLEAN: 1327 typ = Opcodes.T_BOOLEAN; 1328 break; 1329 case Type.CHAR: 1330 typ = Opcodes.T_CHAR; 1331 break; 1332 case Type.BYTE: 1333 typ = Opcodes.T_BYTE; 1334 break; 1335 case Type.SHORT: 1336 typ = Opcodes.T_SHORT; 1337 break; 1338 case Type.INT: 1339 typ = Opcodes.T_INT; 1340 break; 1341 case Type.FLOAT: 1342 typ = Opcodes.T_FLOAT; 1343 break; 1344 case Type.LONG: 1345 typ = Opcodes.T_LONG; 1346 break; 1347 case Type.DOUBLE: 1348 typ = Opcodes.T_DOUBLE; 1349 break; 1350 default: 1351 typeInsn(Opcodes.ANEWARRAY, type); 1352 return; 1353 } 1354 mv.visitIntInsn(Opcodes.NEWARRAY, typ); 1355 } 1356 1357 // ------------------------------------------------------------------------ 1358 // Miscelaneous instructions 1359 // ------------------------------------------------------------------------ 1360 1361 /** 1362 * Generates the instruction to compute the length of an array. 1363 */ 1364 public void arrayLength() { 1365 mv.visitInsn(Opcodes.ARRAYLENGTH); 1366 } 1367 1368 /** 1369 * Generates the instruction to throw an exception. 1370 */ 1371 public void throwException() { 1372 mv.visitInsn(Opcodes.ATHROW); 1373 } 1374 1375 /** 1376 * Generates the instructions to create and throw an exception. The 1377 * exception class must have a constructor with a single String argument. 1378 * 1379 * @param type the class of the exception to be thrown. 1380 * @param msg the detailed message of the exception. 1381 */ 1382 public void throwException(final Type type, final String msg) { 1383 newInstance(type); 1384 dup(); 1385 push(msg); 1386 invokeConstructor(type, Method.getMethod("void <init> (String)")); 1387 throwException(); 1388 } 1389 1390 /** 1391 * Generates the instruction to check that the top stack value is of the 1392 * given type. 1393 * 1394 * @param type a class or interface type. 1395 */ 1396 public void checkCast(final Type type) { 1397 if (!type.equals(OBJECT_TYPE)) { 1398 typeInsn(Opcodes.CHECKCAST, type); 1399 } 1400 } 1401 1402 /** 1403 * Generates the instruction to test if the top stack value is of the given 1404 * type. 1405 * 1406 * @param type a class or interface type. 1407 */ 1408 public void instanceOf(final Type type) { 1409 typeInsn(Opcodes.INSTANCEOF, type); 1410 } 1411 1412 /** 1413 * Generates the instruction to get the monitor of the top stack value. 1414 */ 1415 public void monitorEnter() { 1416 mv.visitInsn(Opcodes.MONITORENTER); 1417 } 1418 1419 /** 1420 * Generates the instruction to release the monitor of the top stack value. 1421 */ 1422 public void monitorExit() { 1423 mv.visitInsn(Opcodes.MONITOREXIT); 1424 } 1425 1426 // ------------------------------------------------------------------------ 1427 // Non instructions 1428 // ------------------------------------------------------------------------ 1429 1430 /** 1431 * Marks the end of the visited method. 1432 */ 1433 public void endMethod() { 1434 if ((access & Opcodes.ACC_ABSTRACT) == 0) { 1435 mv.visitMaxs(0, 0); 1436 } 1437 } 1438 1439 /** 1440 * Marks the start of an exception handler. 1441 * 1442 * @param start beginning of the exception handler's scope (inclusive). 1443 * @param end end of the exception handler's scope (exclusive). 1444 * @param exception internal name of the type of exceptions handled by the 1445 * handler. 1446 */ 1447 public void catchException( 1448 final Label start, 1449 final Label end, 1450 final Type exception) 1451 { 1452 mv.visitTryCatchBlock(start, end, mark(), exception.getInternalName()); 1453 } 1454 } 1455