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.
028
029package io.ebean.enhance.asm.commons;
030
031import io.ebean.enhance.asm.ConstantDynamic;
032import io.ebean.enhance.asm.Handle;
033import io.ebean.enhance.asm.Label;
034import io.ebean.enhance.asm.MethodVisitor;
035import io.ebean.enhance.asm.Opcodes;
036import io.ebean.enhance.asm.Type;
037
038/**
039 * A {@link MethodVisitor} providing a more detailed API to generate and transform instructions.
040 *
041 * @author Eric Bruneton
042 */
043public class InstructionAdapter extends MethodVisitor {
044
045  /** The type of the java.lang.Object class. */
046  public static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;");
047
048  /**
049   * Constructs a new {@link InstructionAdapter}. <i>Subclasses must not use this constructor</i>.
050   * Instead, they must use the {@link #InstructionAdapter(int, MethodVisitor)} version.
051   *
052   * @param methodVisitor the method visitor to which this adapter delegates calls.
053   * @throws IllegalStateException If a subclass calls this constructor.
054   */
055  public InstructionAdapter(final MethodVisitor methodVisitor) {
056    this(/* latest api = */ Opcodes.ASM9, methodVisitor);
057    if (getClass() != InstructionAdapter.class) {
058      throw new IllegalStateException();
059    }
060  }
061
062  /**
063   * Constructs a new {@link InstructionAdapter}.
064   *
065   * @param api the ASM API version implemented by this visitor. Must be one of {@link
066   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7}, {@link
067   *     Opcodes#ASM8} or {@link Opcodes#ASM9}.
068   * @param methodVisitor the method visitor to which this adapter delegates calls.
069   */
070  protected InstructionAdapter(final int api, final MethodVisitor methodVisitor) {
071    super(api, methodVisitor);
072  }
073
074  @Override
075  public void visitInsn(final int opcode) {
076    switch (opcode) {
077      case Opcodes.NOP:
078        nop();
079        break;
080      case Opcodes.ACONST_NULL:
081        aconst(null);
082        break;
083      case Opcodes.ICONST_M1:
084      case Opcodes.ICONST_0:
085      case Opcodes.ICONST_1:
086      case Opcodes.ICONST_2:
087      case Opcodes.ICONST_3:
088      case Opcodes.ICONST_4:
089      case Opcodes.ICONST_5:
090        iconst(opcode - Opcodes.ICONST_0);
091        break;
092      case Opcodes.LCONST_0:
093      case Opcodes.LCONST_1:
094        lconst((long) (opcode - Opcodes.LCONST_0));
095        break;
096      case Opcodes.FCONST_0:
097      case Opcodes.FCONST_1:
098      case Opcodes.FCONST_2:
099        fconst((float) (opcode - Opcodes.FCONST_0));
100        break;
101      case Opcodes.DCONST_0:
102      case Opcodes.DCONST_1:
103        dconst((double) (opcode - Opcodes.DCONST_0));
104        break;
105      case Opcodes.IALOAD:
106        aload(Type.INT_TYPE);
107        break;
108      case Opcodes.LALOAD:
109        aload(Type.LONG_TYPE);
110        break;
111      case Opcodes.FALOAD:
112        aload(Type.FLOAT_TYPE);
113        break;
114      case Opcodes.DALOAD:
115        aload(Type.DOUBLE_TYPE);
116        break;
117      case Opcodes.AALOAD:
118        aload(OBJECT_TYPE);
119        break;
120      case Opcodes.BALOAD:
121        aload(Type.BYTE_TYPE);
122        break;
123      case Opcodes.CALOAD:
124        aload(Type.CHAR_TYPE);
125        break;
126      case Opcodes.SALOAD:
127        aload(Type.SHORT_TYPE);
128        break;
129      case Opcodes.IASTORE:
130        astore(Type.INT_TYPE);
131        break;
132      case Opcodes.LASTORE:
133        astore(Type.LONG_TYPE);
134        break;
135      case Opcodes.FASTORE:
136        astore(Type.FLOAT_TYPE);
137        break;
138      case Opcodes.DASTORE:
139        astore(Type.DOUBLE_TYPE);
140        break;
141      case Opcodes.AASTORE:
142        astore(OBJECT_TYPE);
143        break;
144      case Opcodes.BASTORE:
145        astore(Type.BYTE_TYPE);
146        break;
147      case Opcodes.CASTORE:
148        astore(Type.CHAR_TYPE);
149        break;
150      case Opcodes.SASTORE:
151        astore(Type.SHORT_TYPE);
152        break;
153      case Opcodes.POP:
154        pop();
155        break;
156      case Opcodes.POP2:
157        pop2();
158        break;
159      case Opcodes.DUP:
160        dup();
161        break;
162      case Opcodes.DUP_X1:
163        dupX1();
164        break;
165      case Opcodes.DUP_X2:
166        dupX2();
167        break;
168      case Opcodes.DUP2:
169        dup2();
170        break;
171      case Opcodes.DUP2_X1:
172        dup2X1();
173        break;
174      case Opcodes.DUP2_X2:
175        dup2X2();
176        break;
177      case Opcodes.SWAP:
178        swap();
179        break;
180      case Opcodes.IADD:
181        add(Type.INT_TYPE);
182        break;
183      case Opcodes.LADD:
184        add(Type.LONG_TYPE);
185        break;
186      case Opcodes.FADD:
187        add(Type.FLOAT_TYPE);
188        break;
189      case Opcodes.DADD:
190        add(Type.DOUBLE_TYPE);
191        break;
192      case Opcodes.ISUB:
193        sub(Type.INT_TYPE);
194        break;
195      case Opcodes.LSUB:
196        sub(Type.LONG_TYPE);
197        break;
198      case Opcodes.FSUB:
199        sub(Type.FLOAT_TYPE);
200        break;
201      case Opcodes.DSUB:
202        sub(Type.DOUBLE_TYPE);
203        break;
204      case Opcodes.IMUL:
205        mul(Type.INT_TYPE);
206        break;
207      case Opcodes.LMUL:
208        mul(Type.LONG_TYPE);
209        break;
210      case Opcodes.FMUL:
211        mul(Type.FLOAT_TYPE);
212        break;
213      case Opcodes.DMUL:
214        mul(Type.DOUBLE_TYPE);
215        break;
216      case Opcodes.IDIV:
217        div(Type.INT_TYPE);
218        break;
219      case Opcodes.LDIV:
220        div(Type.LONG_TYPE);
221        break;
222      case Opcodes.FDIV:
223        div(Type.FLOAT_TYPE);
224        break;
225      case Opcodes.DDIV:
226        div(Type.DOUBLE_TYPE);
227        break;
228      case Opcodes.IREM:
229        rem(Type.INT_TYPE);
230        break;
231      case Opcodes.LREM:
232        rem(Type.LONG_TYPE);
233        break;
234      case Opcodes.FREM:
235        rem(Type.FLOAT_TYPE);
236        break;
237      case Opcodes.DREM:
238        rem(Type.DOUBLE_TYPE);
239        break;
240      case Opcodes.INEG:
241        neg(Type.INT_TYPE);
242        break;
243      case Opcodes.LNEG:
244        neg(Type.LONG_TYPE);
245        break;
246      case Opcodes.FNEG:
247        neg(Type.FLOAT_TYPE);
248        break;
249      case Opcodes.DNEG:
250        neg(Type.DOUBLE_TYPE);
251        break;
252      case Opcodes.ISHL:
253        shl(Type.INT_TYPE);
254        break;
255      case Opcodes.LSHL:
256        shl(Type.LONG_TYPE);
257        break;
258      case Opcodes.ISHR:
259        shr(Type.INT_TYPE);
260        break;
261      case Opcodes.LSHR:
262        shr(Type.LONG_TYPE);
263        break;
264      case Opcodes.IUSHR:
265        ushr(Type.INT_TYPE);
266        break;
267      case Opcodes.LUSHR:
268        ushr(Type.LONG_TYPE);
269        break;
270      case Opcodes.IAND:
271        and(Type.INT_TYPE);
272        break;
273      case Opcodes.LAND:
274        and(Type.LONG_TYPE);
275        break;
276      case Opcodes.IOR:
277        or(Type.INT_TYPE);
278        break;
279      case Opcodes.LOR:
280        or(Type.LONG_TYPE);
281        break;
282      case Opcodes.IXOR:
283        xor(Type.INT_TYPE);
284        break;
285      case Opcodes.LXOR:
286        xor(Type.LONG_TYPE);
287        break;
288      case Opcodes.I2L:
289        cast(Type.INT_TYPE, Type.LONG_TYPE);
290        break;
291      case Opcodes.I2F:
292        cast(Type.INT_TYPE, Type.FLOAT_TYPE);
293        break;
294      case Opcodes.I2D:
295        cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
296        break;
297      case Opcodes.L2I:
298        cast(Type.LONG_TYPE, Type.INT_TYPE);
299        break;
300      case Opcodes.L2F:
301        cast(Type.LONG_TYPE, Type.FLOAT_TYPE);
302        break;
303      case Opcodes.L2D:
304        cast(Type.LONG_TYPE, Type.DOUBLE_TYPE);
305        break;
306      case Opcodes.F2I:
307        cast(Type.FLOAT_TYPE, Type.INT_TYPE);
308        break;
309      case Opcodes.F2L:
310        cast(Type.FLOAT_TYPE, Type.LONG_TYPE);
311        break;
312      case Opcodes.F2D:
313        cast(Type.FLOAT_TYPE, Type.DOUBLE_TYPE);
314        break;
315      case Opcodes.D2I:
316        cast(Type.DOUBLE_TYPE, Type.INT_TYPE);
317        break;
318      case Opcodes.D2L:
319        cast(Type.DOUBLE_TYPE, Type.LONG_TYPE);
320        break;
321      case Opcodes.D2F:
322        cast(Type.DOUBLE_TYPE, Type.FLOAT_TYPE);
323        break;
324      case Opcodes.I2B:
325        cast(Type.INT_TYPE, Type.BYTE_TYPE);
326        break;
327      case Opcodes.I2C:
328        cast(Type.INT_TYPE, Type.CHAR_TYPE);
329        break;
330      case Opcodes.I2S:
331        cast(Type.INT_TYPE, Type.SHORT_TYPE);
332        break;
333      case Opcodes.LCMP:
334        lcmp();
335        break;
336      case Opcodes.FCMPL:
337        cmpl(Type.FLOAT_TYPE);
338        break;
339      case Opcodes.FCMPG:
340        cmpg(Type.FLOAT_TYPE);
341        break;
342      case Opcodes.DCMPL:
343        cmpl(Type.DOUBLE_TYPE);
344        break;
345      case Opcodes.DCMPG:
346        cmpg(Type.DOUBLE_TYPE);
347        break;
348      case Opcodes.IRETURN:
349        areturn(Type.INT_TYPE);
350        break;
351      case Opcodes.LRETURN:
352        areturn(Type.LONG_TYPE);
353        break;
354      case Opcodes.FRETURN:
355        areturn(Type.FLOAT_TYPE);
356        break;
357      case Opcodes.DRETURN:
358        areturn(Type.DOUBLE_TYPE);
359        break;
360      case Opcodes.ARETURN:
361        areturn(OBJECT_TYPE);
362        break;
363      case Opcodes.RETURN:
364        areturn(Type.VOID_TYPE);
365        break;
366      case Opcodes.ARRAYLENGTH:
367        arraylength();
368        break;
369      case Opcodes.ATHROW:
370        athrow();
371        break;
372      case Opcodes.MONITORENTER:
373        monitorenter();
374        break;
375      case Opcodes.MONITOREXIT:
376        monitorexit();
377        break;
378      default:
379        throw new IllegalArgumentException();
380    }
381  }
382
383  @Override
384  public void visitIntInsn(final int opcode, final int operand) {
385    switch (opcode) {
386      case Opcodes.BIPUSH:
387        iconst(operand);
388        break;
389      case Opcodes.SIPUSH:
390        iconst(operand);
391        break;
392      case Opcodes.NEWARRAY:
393        switch (operand) {
394          case Opcodes.T_BOOLEAN:
395            newarray(Type.BOOLEAN_TYPE);
396            break;
397          case Opcodes.T_CHAR:
398            newarray(Type.CHAR_TYPE);
399            break;
400          case Opcodes.T_BYTE:
401            newarray(Type.BYTE_TYPE);
402            break;
403          case Opcodes.T_SHORT:
404            newarray(Type.SHORT_TYPE);
405            break;
406          case Opcodes.T_INT:
407            newarray(Type.INT_TYPE);
408            break;
409          case Opcodes.T_FLOAT:
410            newarray(Type.FLOAT_TYPE);
411            break;
412          case Opcodes.T_LONG:
413            newarray(Type.LONG_TYPE);
414            break;
415          case Opcodes.T_DOUBLE:
416            newarray(Type.DOUBLE_TYPE);
417            break;
418          default:
419            throw new IllegalArgumentException();
420        }
421        break;
422      default:
423        throw new IllegalArgumentException();
424    }
425  }
426
427  @Override
428  public void visitVarInsn(final int opcode, final int var) {
429    switch (opcode) {
430      case Opcodes.ILOAD:
431        load(var, Type.INT_TYPE);
432        break;
433      case Opcodes.LLOAD:
434        load(var, Type.LONG_TYPE);
435        break;
436      case Opcodes.FLOAD:
437        load(var, Type.FLOAT_TYPE);
438        break;
439      case Opcodes.DLOAD:
440        load(var, Type.DOUBLE_TYPE);
441        break;
442      case Opcodes.ALOAD:
443        load(var, OBJECT_TYPE);
444        break;
445      case Opcodes.ISTORE:
446        store(var, Type.INT_TYPE);
447        break;
448      case Opcodes.LSTORE:
449        store(var, Type.LONG_TYPE);
450        break;
451      case Opcodes.FSTORE:
452        store(var, Type.FLOAT_TYPE);
453        break;
454      case Opcodes.DSTORE:
455        store(var, Type.DOUBLE_TYPE);
456        break;
457      case Opcodes.ASTORE:
458        store(var, OBJECT_TYPE);
459        break;
460      case Opcodes.RET:
461        ret(var);
462        break;
463      default:
464        throw new IllegalArgumentException();
465    }
466  }
467
468  @Override
469  public void visitTypeInsn(final int opcode, final String type) {
470    Type objectType = Type.getObjectType(type);
471    switch (opcode) {
472      case Opcodes.NEW:
473        anew(objectType);
474        break;
475      case Opcodes.ANEWARRAY:
476        newarray(objectType);
477        break;
478      case Opcodes.CHECKCAST:
479        checkcast(objectType);
480        break;
481      case Opcodes.INSTANCEOF:
482        instanceOf(objectType);
483        break;
484      default:
485        throw new IllegalArgumentException();
486    }
487  }
488
489  @Override
490  public void visitFieldInsn(
491      final int opcode, final String owner, final String name, final String descriptor) {
492    switch (opcode) {
493      case Opcodes.GETSTATIC:
494        getstatic(owner, name, descriptor);
495        break;
496      case Opcodes.PUTSTATIC:
497        putstatic(owner, name, descriptor);
498        break;
499      case Opcodes.GETFIELD:
500        getfield(owner, name, descriptor);
501        break;
502      case Opcodes.PUTFIELD:
503        putfield(owner, name, descriptor);
504        break;
505      default:
506        throw new IllegalArgumentException();
507    }
508  }
509
510  @Override
511  public void visitMethodInsn(
512      final int opcodeAndSource,
513      final String owner,
514      final String name,
515      final String descriptor,
516      final boolean isInterface) {
517    if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
518      // Redirect the call to the deprecated version of this method.
519      super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
520      return;
521    }
522    int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK;
523
524    switch (opcode) {
525      case Opcodes.INVOKESPECIAL:
526        invokespecial(owner, name, descriptor, isInterface);
527        break;
528      case Opcodes.INVOKEVIRTUAL:
529        invokevirtual(owner, name, descriptor, isInterface);
530        break;
531      case Opcodes.INVOKESTATIC:
532        invokestatic(owner, name, descriptor, isInterface);
533        break;
534      case Opcodes.INVOKEINTERFACE:
535        invokeinterface(owner, name, descriptor);
536        break;
537      default:
538        throw new IllegalArgumentException();
539    }
540  }
541
542  @Override
543  public void visitInvokeDynamicInsn(
544      final String name,
545      final String descriptor,
546      final Handle bootstrapMethodHandle,
547      final Object... bootstrapMethodArguments) {
548    invokedynamic(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
549  }
550
551  @Override
552  public void visitJumpInsn(final int opcode, final Label label) {
553    switch (opcode) {
554      case Opcodes.IFEQ:
555        ifeq(label);
556        break;
557      case Opcodes.IFNE:
558        ifne(label);
559        break;
560      case Opcodes.IFLT:
561        iflt(label);
562        break;
563      case Opcodes.IFGE:
564        ifge(label);
565        break;
566      case Opcodes.IFGT:
567        ifgt(label);
568        break;
569      case Opcodes.IFLE:
570        ifle(label);
571        break;
572      case Opcodes.IF_ICMPEQ:
573        ificmpeq(label);
574        break;
575      case Opcodes.IF_ICMPNE:
576        ificmpne(label);
577        break;
578      case Opcodes.IF_ICMPLT:
579        ificmplt(label);
580        break;
581      case Opcodes.IF_ICMPGE:
582        ificmpge(label);
583        break;
584      case Opcodes.IF_ICMPGT:
585        ificmpgt(label);
586        break;
587      case Opcodes.IF_ICMPLE:
588        ificmple(label);
589        break;
590      case Opcodes.IF_ACMPEQ:
591        ifacmpeq(label);
592        break;
593      case Opcodes.IF_ACMPNE:
594        ifacmpne(label);
595        break;
596      case Opcodes.GOTO:
597        goTo(label);
598        break;
599      case Opcodes.JSR:
600        jsr(label);
601        break;
602      case Opcodes.IFNULL:
603        ifnull(label);
604        break;
605      case Opcodes.IFNONNULL:
606        ifnonnull(label);
607        break;
608      default:
609        throw new IllegalArgumentException();
610    }
611  }
612
613  @Override
614  public void visitLabel(final Label label) {
615    mark(label);
616  }
617
618  @Override
619  public void visitLdcInsn(final Object value) {
620    if (api < Opcodes.ASM5
621        && (value instanceof Handle
622            || (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) {
623      throw new UnsupportedOperationException("This feature requires ASM5");
624    }
625    if (api < Opcodes.ASM7 && value instanceof ConstantDynamic) {
626      throw new UnsupportedOperationException("This feature requires ASM7");
627    }
628    if (value instanceof Integer) {
629      iconst((Integer) value);
630    } else if (value instanceof Byte) {
631      iconst(((Byte) value).intValue());
632    } else if (value instanceof Character) {
633      iconst(((Character) value).charValue());
634    } else if (value instanceof Short) {
635      iconst(((Short) value).intValue());
636    } else if (value instanceof Boolean) {
637      iconst(((Boolean) value).booleanValue() ? 1 : 0);
638    } else if (value instanceof Float) {
639      fconst((Float) value);
640    } else if (value instanceof Long) {
641      lconst((Long) value);
642    } else if (value instanceof Double) {
643      dconst((Double) value);
644    } else if (value instanceof String) {
645      aconst(value);
646    } else if (value instanceof Type) {
647      tconst((Type) value);
648    } else if (value instanceof Handle) {
649      hconst((Handle) value);
650    } else if (value instanceof ConstantDynamic) {
651      cconst((ConstantDynamic) value);
652    } else {
653      throw new IllegalArgumentException();
654    }
655  }
656
657  @Override
658  public void visitIincInsn(final int var, final int increment) {
659    iinc(var, increment);
660  }
661
662  @Override
663  public void visitTableSwitchInsn(
664      final int min, final int max, final Label dflt, final Label... labels) {
665    tableswitch(min, max, dflt, labels);
666  }
667
668  @Override
669  public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
670    lookupswitch(dflt, keys, labels);
671  }
672
673  @Override
674  public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
675    multianewarray(descriptor, numDimensions);
676  }
677
678  // -----------------------------------------------------------------------------------------------
679
680  /** Generates a nop instruction. */
681  public void nop() {
682    mv.visitInsn(Opcodes.NOP);
683  }
684
685  /**
686   * Generates the instruction to push the given value on the stack.
687   *
688   * @param value the constant to be pushed on the stack. This parameter must be an {@link Integer},
689   *     a {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link Type} of
690   *     OBJECT or ARRAY sort for {@code .class} constants, for classes whose version is 49, a
691   *     {@link Type} of METHOD sort for MethodType, a {@link Handle} for MethodHandle constants,
692   *     for classes whose version is 51 or a {@link ConstantDynamic} for a constant dynamic for
693   *     classes whose version is 55.
694   */
695  public void aconst(final Object value) {
696    if (value == null) {
697      mv.visitInsn(Opcodes.ACONST_NULL);
698    } else {
699      mv.visitLdcInsn(value);
700    }
701  }
702
703  /**
704   * Generates the instruction to push the given value on the stack.
705   *
706   * @param intValue the constant to be pushed on the stack.
707   */
708  public void iconst(final int intValue) {
709    if (intValue >= -1 && intValue <= 5) {
710      mv.visitInsn(Opcodes.ICONST_0 + intValue);
711    } else if (intValue >= Byte.MIN_VALUE && intValue <= Byte.MAX_VALUE) {
712      mv.visitIntInsn(Opcodes.BIPUSH, intValue);
713    } else if (intValue >= Short.MIN_VALUE && intValue <= Short.MAX_VALUE) {
714      mv.visitIntInsn(Opcodes.SIPUSH, intValue);
715    } else {
716      mv.visitLdcInsn(intValue);
717    }
718  }
719
720  /**
721   * Generates the instruction to push the given value on the stack.
722   *
723   * @param longValue the constant to be pushed on the stack.
724   */
725  public void lconst(final long longValue) {
726    if (longValue == 0L || longValue == 1L) {
727      mv.visitInsn(Opcodes.LCONST_0 + (int) longValue);
728    } else {
729      mv.visitLdcInsn(longValue);
730    }
731  }
732
733  /**
734   * Generates the instruction to push the given value on the stack.
735   *
736   * @param floatValue the constant to be pushed on the stack.
737   */
738  public void fconst(final float floatValue) {
739    int bits = Float.floatToIntBits(floatValue);
740    if (bits == 0L || bits == 0x3F800000 || bits == 0x40000000) { // 0..2
741      mv.visitInsn(Opcodes.FCONST_0 + (int) floatValue);
742    } else {
743      mv.visitLdcInsn(floatValue);
744    }
745  }
746
747  /**
748   * Generates the instruction to push the given value on the stack.
749   *
750   * @param doubleValue the constant to be pushed on the stack.
751   */
752  public void dconst(final double doubleValue) {
753    long bits = Double.doubleToLongBits(doubleValue);
754    if (bits == 0L || bits == 0x3FF0000000000000L) { // +0.0d and 1.0d
755      mv.visitInsn(Opcodes.DCONST_0 + (int) doubleValue);
756    } else {
757      mv.visitLdcInsn(doubleValue);
758    }
759  }
760
761  /**
762   * Generates the instruction to push the given type on the stack.
763   *
764   * @param type the type to be pushed on the stack.
765   */
766  public void tconst(final Type type) {
767    mv.visitLdcInsn(type);
768  }
769
770  /**
771   * Generates the instruction to push the given handle on the stack.
772   *
773   * @param handle the handle to be pushed on the stack.
774   */
775  public void hconst(final Handle handle) {
776    mv.visitLdcInsn(handle);
777  }
778
779  /**
780   * Generates the instruction to push the given constant dynamic on the stack.
781   *
782   * @param constantDynamic the constant dynamic to be pushed on the stack.
783   */
784  public void cconst(final ConstantDynamic constantDynamic) {
785    mv.visitLdcInsn(constantDynamic);
786  }
787
788  public void load(final int var, final Type type) {
789    mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), var);
790  }
791
792  public void aload(final Type type) {
793    mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
794  }
795
796  public void store(final int var, final Type type) {
797    mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), var);
798  }
799
800  public void astore(final Type type) {
801    mv.visitInsn(type.getOpcode(Opcodes.IASTORE));
802  }
803
804  public void pop() {
805    mv.visitInsn(Opcodes.POP);
806  }
807
808  public void pop2() {
809    mv.visitInsn(Opcodes.POP2);
810  }
811
812  public void dup() {
813    mv.visitInsn(Opcodes.DUP);
814  }
815
816  public void dup2() {
817    mv.visitInsn(Opcodes.DUP2);
818  }
819
820  public void dupX1() {
821    mv.visitInsn(Opcodes.DUP_X1);
822  }
823
824  public void dupX2() {
825    mv.visitInsn(Opcodes.DUP_X2);
826  }
827
828  public void dup2X1() {
829    mv.visitInsn(Opcodes.DUP2_X1);
830  }
831
832  public void dup2X2() {
833    mv.visitInsn(Opcodes.DUP2_X2);
834  }
835
836  public void swap() {
837    mv.visitInsn(Opcodes.SWAP);
838  }
839
840  public void add(final Type type) {
841    mv.visitInsn(type.getOpcode(Opcodes.IADD));
842  }
843
844  public void sub(final Type type) {
845    mv.visitInsn(type.getOpcode(Opcodes.ISUB));
846  }
847
848  public void mul(final Type type) {
849    mv.visitInsn(type.getOpcode(Opcodes.IMUL));
850  }
851
852  public void div(final Type type) {
853    mv.visitInsn(type.getOpcode(Opcodes.IDIV));
854  }
855
856  public void rem(final Type type) {
857    mv.visitInsn(type.getOpcode(Opcodes.IREM));
858  }
859
860  public void neg(final Type type) {
861    mv.visitInsn(type.getOpcode(Opcodes.INEG));
862  }
863
864  public void shl(final Type type) {
865    mv.visitInsn(type.getOpcode(Opcodes.ISHL));
866  }
867
868  public void shr(final Type type) {
869    mv.visitInsn(type.getOpcode(Opcodes.ISHR));
870  }
871
872  public void ushr(final Type type) {
873    mv.visitInsn(type.getOpcode(Opcodes.IUSHR));
874  }
875
876  public void and(final Type type) {
877    mv.visitInsn(type.getOpcode(Opcodes.IAND));
878  }
879
880  public void or(final Type type) {
881    mv.visitInsn(type.getOpcode(Opcodes.IOR));
882  }
883
884  public void xor(final Type type) {
885    mv.visitInsn(type.getOpcode(Opcodes.IXOR));
886  }
887
888  public void iinc(final int var, final int increment) {
889    mv.visitIincInsn(var, increment);
890  }
891
892  /**
893   * Generates the instruction to cast from the first given type to the other.
894   *
895   * @param from a Type.
896   * @param to a Type.
897   */
898  public void cast(final Type from, final Type to) {
899    cast(mv, from, to);
900  }
901
902  /**
903   * Generates the instruction to cast from the first given type to the other.
904   *
905   * @param methodVisitor the method visitor to use to generate the instruction.
906   * @param from a Type.
907   * @param to a Type.
908   */
909  static void cast(final MethodVisitor methodVisitor, final Type from, final Type to) {
910    if (from != to) {
911      if (from == Type.DOUBLE_TYPE) {
912        if (to == Type.FLOAT_TYPE) {
913          methodVisitor.visitInsn(Opcodes.D2F);
914        } else if (to == Type.LONG_TYPE) {
915          methodVisitor.visitInsn(Opcodes.D2L);
916        } else {
917          methodVisitor.visitInsn(Opcodes.D2I);
918          cast(methodVisitor, Type.INT_TYPE, to);
919        }
920      } else if (from == Type.FLOAT_TYPE) {
921        if (to == Type.DOUBLE_TYPE) {
922          methodVisitor.visitInsn(Opcodes.F2D);
923        } else if (to == Type.LONG_TYPE) {
924          methodVisitor.visitInsn(Opcodes.F2L);
925        } else {
926          methodVisitor.visitInsn(Opcodes.F2I);
927          cast(methodVisitor, Type.INT_TYPE, to);
928        }
929      } else if (from == Type.LONG_TYPE) {
930        if (to == Type.DOUBLE_TYPE) {
931          methodVisitor.visitInsn(Opcodes.L2D);
932        } else if (to == Type.FLOAT_TYPE) {
933          methodVisitor.visitInsn(Opcodes.L2F);
934        } else {
935          methodVisitor.visitInsn(Opcodes.L2I);
936          cast(methodVisitor, Type.INT_TYPE, to);
937        }
938      } else {
939        if (to == Type.BYTE_TYPE) {
940          methodVisitor.visitInsn(Opcodes.I2B);
941        } else if (to == Type.CHAR_TYPE) {
942          methodVisitor.visitInsn(Opcodes.I2C);
943        } else if (to == Type.DOUBLE_TYPE) {
944          methodVisitor.visitInsn(Opcodes.I2D);
945        } else if (to == Type.FLOAT_TYPE) {
946          methodVisitor.visitInsn(Opcodes.I2F);
947        } else if (to == Type.LONG_TYPE) {
948          methodVisitor.visitInsn(Opcodes.I2L);
949        } else if (to == Type.SHORT_TYPE) {
950          methodVisitor.visitInsn(Opcodes.I2S);
951        }
952      }
953    }
954  }
955
956  public void lcmp() {
957    mv.visitInsn(Opcodes.LCMP);
958  }
959
960  public void cmpl(final Type type) {
961    mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPL : Opcodes.DCMPL);
962  }
963
964  public void cmpg(final Type type) {
965    mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPG : Opcodes.DCMPG);
966  }
967
968  public void ifeq(final Label label) {
969    mv.visitJumpInsn(Opcodes.IFEQ, label);
970  }
971
972  public void ifne(final Label label) {
973    mv.visitJumpInsn(Opcodes.IFNE, label);
974  }
975
976  public void iflt(final Label label) {
977    mv.visitJumpInsn(Opcodes.IFLT, label);
978  }
979
980  public void ifge(final Label label) {
981    mv.visitJumpInsn(Opcodes.IFGE, label);
982  }
983
984  public void ifgt(final Label label) {
985    mv.visitJumpInsn(Opcodes.IFGT, label);
986  }
987
988  public void ifle(final Label label) {
989    mv.visitJumpInsn(Opcodes.IFLE, label);
990  }
991
992  public void ificmpeq(final Label label) {
993    mv.visitJumpInsn(Opcodes.IF_ICMPEQ, label);
994  }
995
996  public void ificmpne(final Label label) {
997    mv.visitJumpInsn(Opcodes.IF_ICMPNE, label);
998  }
999
1000  public void ificmplt(final Label label) {
1001    mv.visitJumpInsn(Opcodes.IF_ICMPLT, label);
1002  }
1003
1004  public void ificmpge(final Label label) {
1005    mv.visitJumpInsn(Opcodes.IF_ICMPGE, label);
1006  }
1007
1008  public void ificmpgt(final Label label) {
1009    mv.visitJumpInsn(Opcodes.IF_ICMPGT, label);
1010  }
1011
1012  public void ificmple(final Label label) {
1013    mv.visitJumpInsn(Opcodes.IF_ICMPLE, label);
1014  }
1015
1016  public void ifacmpeq(final Label label) {
1017    mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);
1018  }
1019
1020  public void ifacmpne(final Label label) {
1021    mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);
1022  }
1023
1024  public void goTo(final Label label) {
1025    mv.visitJumpInsn(Opcodes.GOTO, label);
1026  }
1027
1028  public void jsr(final Label label) {
1029    mv.visitJumpInsn(Opcodes.JSR, label);
1030  }
1031
1032  public void ret(final int var) {
1033    mv.visitVarInsn(Opcodes.RET, var);
1034  }
1035
1036  public void tableswitch(final int min, final int max, final Label dflt, final Label... labels) {
1037    mv.visitTableSwitchInsn(min, max, dflt, labels);
1038  }
1039
1040  public void lookupswitch(final Label dflt, final int[] keys, final Label[] labels) {
1041    mv.visitLookupSwitchInsn(dflt, keys, labels);
1042  }
1043
1044  public void areturn(final Type type) {
1045    mv.visitInsn(type.getOpcode(Opcodes.IRETURN));
1046  }
1047
1048  public void getstatic(final String owner, final String name, final String descriptor) {
1049    mv.visitFieldInsn(Opcodes.GETSTATIC, owner, name, descriptor);
1050  }
1051
1052  public void putstatic(final String owner, final String name, final String descriptor) {
1053    mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, name, descriptor);
1054  }
1055
1056  public void getfield(final String owner, final String name, final String descriptor) {
1057    mv.visitFieldInsn(Opcodes.GETFIELD, owner, name, descriptor);
1058  }
1059
1060  public void putfield(final String owner, final String name, final String descriptor) {
1061    mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, descriptor);
1062  }
1063
1064  /**
1065   * Deprecated.
1066   *
1067   * @param owner the internal name of the method's owner class.
1068   * @param name the method's name.
1069   * @param descriptor the method's descriptor (see {@link Type}).
1070   * @deprecated use {@link #invokevirtual(String, String, String, boolean)} instead.
1071   */
1072  @Deprecated
1073  public void invokevirtual(final String owner, final String name, final String descriptor) {
1074    if (api >= Opcodes.ASM5) {
1075      invokevirtual(owner, name, descriptor, false);
1076      return;
1077    }
1078    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, descriptor);
1079  }
1080
1081  /**
1082   * Generates the instruction to call the given virtual method.
1083   *
1084   * @param owner the internal name of the method's owner class (see {@link
1085   *     Type#getInternalName()}).
1086   * @param name the method's name.
1087   * @param descriptor the method's descriptor (see {@link Type}).
1088   * @param isInterface if the method's owner class is an interface.
1089   */
1090  public void invokevirtual(
1091      final String owner, final String name, final String descriptor, final boolean isInterface) {
1092    if (api < Opcodes.ASM5) {
1093      if (isInterface) {
1094        throw new IllegalArgumentException("INVOKEVIRTUAL on interfaces require ASM 5");
1095      }
1096      invokevirtual(owner, name, descriptor);
1097      return;
1098    }
1099    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, descriptor, isInterface);
1100  }
1101
1102  /**
1103   * Deprecated.
1104   *
1105   * @param owner the internal name of the method's owner class.
1106   * @param name the method's name.
1107   * @param descriptor the method's descriptor (see {@link Type}).
1108   * @deprecated use {@link #invokespecial(String, String, String, boolean)} instead.
1109   */
1110  @Deprecated
1111  public void invokespecial(final String owner, final String name, final String descriptor) {
1112    if (api >= Opcodes.ASM5) {
1113      invokespecial(owner, name, descriptor, false);
1114      return;
1115    }
1116    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, descriptor, false);
1117  }
1118
1119  /**
1120   * Generates the instruction to call the given special method.
1121   *
1122   * @param owner the internal name of the method's owner class (see {@link
1123   *     Type#getInternalName()}).
1124   * @param name the method's name.
1125   * @param descriptor the method's descriptor (see {@link Type}).
1126   * @param isInterface if the method's owner class is an interface.
1127   */
1128  public void invokespecial(
1129      final String owner, final String name, final String descriptor, final boolean isInterface) {
1130    if (api < Opcodes.ASM5) {
1131      if (isInterface) {
1132        throw new IllegalArgumentException("INVOKESPECIAL on interfaces require ASM 5");
1133      }
1134      invokespecial(owner, name, descriptor);
1135      return;
1136    }
1137    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, descriptor, isInterface);
1138  }
1139
1140  /**
1141   * Deprecated.
1142   *
1143   * @param owner the internal name of the method's owner class.
1144   * @param name the method's name.
1145   * @param descriptor the method's descriptor (see {@link Type}).
1146   * @deprecated use {@link #invokestatic(String, String, String, boolean)} instead.
1147   */
1148  @Deprecated
1149  public void invokestatic(final String owner, final String name, final String descriptor) {
1150    if (api >= Opcodes.ASM5) {
1151      invokestatic(owner, name, descriptor, false);
1152      return;
1153    }
1154    mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, false);
1155  }
1156
1157  /**
1158   * Generates the instruction to call the given static method.
1159   *
1160   * @param owner the internal name of the method's owner class (see {@link
1161   *     Type#getInternalName()}).
1162   * @param name the method's name.
1163   * @param descriptor the method's descriptor (see {@link Type}).
1164   * @param isInterface if the method's owner class is an interface.
1165   */
1166  public void invokestatic(
1167      final String owner, final String name, final String descriptor, final boolean isInterface) {
1168    if (api < Opcodes.ASM5) {
1169      if (isInterface) {
1170        throw new IllegalArgumentException("INVOKESTATIC on interfaces require ASM 5");
1171      }
1172      invokestatic(owner, name, descriptor);
1173      return;
1174    }
1175    mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, isInterface);
1176  }
1177
1178  /**
1179   * Generates the instruction to call the given interface method.
1180   *
1181   * @param owner the internal name of the method's owner class (see {@link
1182   *     Type#getInternalName()}).
1183   * @param name the method's name.
1184   * @param descriptor the method's descriptor (see {@link Type}).
1185   */
1186  public void invokeinterface(final String owner, final String name, final String descriptor) {
1187    mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, descriptor, true);
1188  }
1189
1190  /**
1191   * Generates the instruction to call the given dynamic method.
1192   *
1193   * @param name the method's name.
1194   * @param descriptor the method's descriptor (see {@link Type}).
1195   * @param bootstrapMethodHandle the bootstrap method.
1196   * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
1197   *     an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
1198   *     Type}, {@link Handle} or {@link ConstantDynamic} value. This method is allowed to modify
1199   *     the content of the array so a caller should expect that this array may change.
1200   */
1201  public void invokedynamic(
1202      final String name,
1203      final String descriptor,
1204      final Handle bootstrapMethodHandle,
1205      final Object[] bootstrapMethodArguments) {
1206    mv.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
1207  }
1208
1209  public void anew(final Type type) {
1210    mv.visitTypeInsn(Opcodes.NEW, type.getInternalName());
1211  }
1212
1213  /**
1214   * Generates the instruction to create and push on the stack an array of the given type.
1215   *
1216   * @param type an array Type.
1217   */
1218  public void newarray(final Type type) {
1219    newarray(mv, type);
1220  }
1221
1222  /**
1223   * Generates the instruction to create and push on the stack an array of the given type.
1224   *
1225   * @param methodVisitor the method visitor to use to generate the instruction.
1226   * @param type an array Type.
1227   */
1228  static void newarray(final MethodVisitor methodVisitor, final Type type) {
1229    int arrayType;
1230    switch (type.getSort()) {
1231      case Type.BOOLEAN:
1232        arrayType = Opcodes.T_BOOLEAN;
1233        break;
1234      case Type.CHAR:
1235        arrayType = Opcodes.T_CHAR;
1236        break;
1237      case Type.BYTE:
1238        arrayType = Opcodes.T_BYTE;
1239        break;
1240      case Type.SHORT:
1241        arrayType = Opcodes.T_SHORT;
1242        break;
1243      case Type.INT:
1244        arrayType = Opcodes.T_INT;
1245        break;
1246      case Type.FLOAT:
1247        arrayType = Opcodes.T_FLOAT;
1248        break;
1249      case Type.LONG:
1250        arrayType = Opcodes.T_LONG;
1251        break;
1252      case Type.DOUBLE:
1253        arrayType = Opcodes.T_DOUBLE;
1254        break;
1255      default:
1256        methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName());
1257        return;
1258    }
1259    methodVisitor.visitIntInsn(Opcodes.NEWARRAY, arrayType);
1260  }
1261
1262  public void arraylength() {
1263    mv.visitInsn(Opcodes.ARRAYLENGTH);
1264  }
1265
1266  public void athrow() {
1267    mv.visitInsn(Opcodes.ATHROW);
1268  }
1269
1270  public void checkcast(final Type type) {
1271    mv.visitTypeInsn(Opcodes.CHECKCAST, type.getInternalName());
1272  }
1273
1274  public void instanceOf(final Type type) {
1275    mv.visitTypeInsn(Opcodes.INSTANCEOF, type.getInternalName());
1276  }
1277
1278  public void monitorenter() {
1279    mv.visitInsn(Opcodes.MONITORENTER);
1280  }
1281
1282  public void monitorexit() {
1283    mv.visitInsn(Opcodes.MONITOREXIT);
1284  }
1285
1286  public void multianewarray(final String descriptor, final int numDimensions) {
1287    mv.visitMultiANewArrayInsn(descriptor, numDimensions);
1288  }
1289
1290  public void ifnull(final Label label) {
1291    mv.visitJumpInsn(Opcodes.IFNULL, label);
1292  }
1293
1294  public void ifnonnull(final Label label) {
1295    mv.visitJumpInsn(Opcodes.IFNONNULL, label);
1296  }
1297
1298  public void mark(final Label label) {
1299    mv.visitLabel(label);
1300  }
1301}