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