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