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