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