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