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