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