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