rev 47452 : imported patch jdk-new-asmv6.patch

   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(&quot;Hello world!&quot;);
  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, &quot;Example&quot;, null, &quot;java/lang/Object&quot;, null);
  89  *
  90  * Method m = Method.getMethod(&quot;void &lt;init&gt; ()&quot;);
  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(&quot;void main (String[])&quot;);
  98  * mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);
  99  * mg.getStatic(Type.getType(System.class), &quot;out&quot;, Type.getType(PrintStream.class));
 100  * mg.push(&quot;Hello world!&quot;);
 101  * mg.invokeVirtual(Type.getType(PrintStream.class),
 102  *         Method.getMethod(&quot;void println (String)&quot;));
 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.ASM6, 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}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
 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(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(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(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(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         Label doCatch = new Label();
1651         if (exception == null) {
1652             mv.visitTryCatchBlock(start, end, doCatch, null);
1653         } else {
1654             mv.visitTryCatchBlock(start, end, doCatch,
1655                     exception.getInternalName());
1656         }
1657         mark(doCatch);
1658     }
1659 }
--- EOF ---