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.Opcodes;
035import io.ebean.enhance.asm.MethodVisitor;
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 the {@code
066   *     ASM}<i>x</i> values in {@link Opcodes}.
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 varIndex) {
428    switch (opcode) {
429      case Opcodes.ILOAD:
430        load(varIndex, Type.INT_TYPE);
431        break;
432      case Opcodes.LLOAD:
433        load(varIndex, Type.LONG_TYPE);
434        break;
435      case Opcodes.FLOAD:
436        load(varIndex, Type.FLOAT_TYPE);
437        break;
438      case Opcodes.DLOAD:
439        load(varIndex, Type.DOUBLE_TYPE);
440        break;
441      case Opcodes.ALOAD:
442        load(varIndex, OBJECT_TYPE);
443        break;
444      case Opcodes.ISTORE:
445        store(varIndex, Type.INT_TYPE);
446        break;
447      case Opcodes.LSTORE:
448        store(varIndex, Type.LONG_TYPE);
449        break;
450      case Opcodes.FSTORE:
451        store(varIndex, Type.FLOAT_TYPE);
452        break;
453      case Opcodes.DSTORE:
454        store(varIndex, Type.DOUBLE_TYPE);
455        break;
456      case Opcodes.ASTORE:
457        store(varIndex, OBJECT_TYPE);
458        break;
459      case Opcodes.RET:
460        ret(varIndex);
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 varIndex, final int increment) {
658    iinc(varIndex, 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 varIndex, final Type type) {
788    mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), varIndex);
789  }
790
791  public void aload(final Type type) {
792    mv.visitInsn(type.getOpcode(Opcodes.IALOAD));
793  }
794
795  public void store(final int varIndex, final Type type) {
796    mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), varIndex);
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 varIndex, final int increment) {
888    mv.visitIincInsn(varIndex, 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    cast(mv, from, to);
899  }
900
901  /**
902   * Generates the instruction to cast from the first given type to the other.
903   *
904   * @param methodVisitor the method visitor to use to generate the instruction.
905   * @param from a Type.
906   * @param to a Type.
907   */
908  static void cast(final MethodVisitor methodVisitor, final Type from, final Type to) {
909    if (from != to) {
910      if (from == Type.DOUBLE_TYPE) {
911        if (to == Type.FLOAT_TYPE) {
912          methodVisitor.visitInsn(Opcodes.D2F);
913        } else if (to == Type.LONG_TYPE) {
914          methodVisitor.visitInsn(Opcodes.D2L);
915        } else {
916          methodVisitor.visitInsn(Opcodes.D2I);
917          cast(methodVisitor, Type.INT_TYPE, to);
918        }
919      } else if (from == Type.FLOAT_TYPE) {
920        if (to == Type.DOUBLE_TYPE) {
921          methodVisitor.visitInsn(Opcodes.F2D);
922        } else if (to == Type.LONG_TYPE) {
923          methodVisitor.visitInsn(Opcodes.F2L);
924        } else {
925          methodVisitor.visitInsn(Opcodes.F2I);
926          cast(methodVisitor, Type.INT_TYPE, to);
927        }
928      } else if (from == Type.LONG_TYPE) {
929        if (to == Type.DOUBLE_TYPE) {
930          methodVisitor.visitInsn(Opcodes.L2D);
931        } else if (to == Type.FLOAT_TYPE) {
932          methodVisitor.visitInsn(Opcodes.L2F);
933        } else {
934          methodVisitor.visitInsn(Opcodes.L2I);
935          cast(methodVisitor, Type.INT_TYPE, to);
936        }
937      } else {
938        if (to == Type.BYTE_TYPE) {
939          methodVisitor.visitInsn(Opcodes.I2B);
940        } else if (to == Type.CHAR_TYPE) {
941          methodVisitor.visitInsn(Opcodes.I2C);
942        } else if (to == Type.DOUBLE_TYPE) {
943          methodVisitor.visitInsn(Opcodes.I2D);
944        } else if (to == Type.FLOAT_TYPE) {
945          methodVisitor.visitInsn(Opcodes.I2F);
946        } else if (to == Type.LONG_TYPE) {
947          methodVisitor.visitInsn(Opcodes.I2L);
948        } else if (to == Type.SHORT_TYPE) {
949          methodVisitor.visitInsn(Opcodes.I2S);
950        }
951      }
952    }
953  }
954
955  public void lcmp() {
956    mv.visitInsn(Opcodes.LCMP);
957  }
958
959  public void cmpl(final Type type) {
960    mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPL : Opcodes.DCMPL);
961  }
962
963  public void cmpg(final Type type) {
964    mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPG : Opcodes.DCMPG);
965  }
966
967  public void ifeq(final Label label) {
968    mv.visitJumpInsn(Opcodes.IFEQ, label);
969  }
970
971  public void ifne(final Label label) {
972    mv.visitJumpInsn(Opcodes.IFNE, label);
973  }
974
975  public void iflt(final Label label) {
976    mv.visitJumpInsn(Opcodes.IFLT, label);
977  }
978
979  public void ifge(final Label label) {
980    mv.visitJumpInsn(Opcodes.IFGE, label);
981  }
982
983  public void ifgt(final Label label) {
984    mv.visitJumpInsn(Opcodes.IFGT, label);
985  }
986
987  public void ifle(final Label label) {
988    mv.visitJumpInsn(Opcodes.IFLE, label);
989  }
990
991  public void ificmpeq(final Label label) {
992    mv.visitJumpInsn(Opcodes.IF_ICMPEQ, label);
993  }
994
995  public void ificmpne(final Label label) {
996    mv.visitJumpInsn(Opcodes.IF_ICMPNE, label);
997  }
998
999  public void ificmplt(final Label label) {
1000    mv.visitJumpInsn(Opcodes.IF_ICMPLT, label);
1001  }
1002
1003  public void ificmpge(final Label label) {
1004    mv.visitJumpInsn(Opcodes.IF_ICMPGE, label);
1005  }
1006
1007  public void ificmpgt(final Label label) {
1008    mv.visitJumpInsn(Opcodes.IF_ICMPGT, label);
1009  }
1010
1011  public void ificmple(final Label label) {
1012    mv.visitJumpInsn(Opcodes.IF_ICMPLE, label);
1013  }
1014
1015  public void ifacmpeq(final Label label) {
1016    mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label);
1017  }
1018
1019  public void ifacmpne(final Label label) {
1020    mv.visitJumpInsn(Opcodes.IF_ACMPNE, label);
1021  }
1022
1023  public void goTo(final Label label) {
1024    mv.visitJumpInsn(Opcodes.GOTO, label);
1025  }
1026
1027  public void jsr(final Label label) {
1028    mv.visitJumpInsn(Opcodes.JSR, label);
1029  }
1030
1031  public void ret(final int varIndex) {
1032    mv.visitVarInsn(Opcodes.RET, varIndex);
1033  }
1034
1035  public void tableswitch(final int min, final int max, final Label dflt, final Label... labels) {
1036    mv.visitTableSwitchInsn(min, max, dflt, labels);
1037  }
1038
1039  public void lookupswitch(final Label dflt, final int[] keys, final Label[] labels) {
1040    mv.visitLookupSwitchInsn(dflt, keys, labels);
1041  }
1042
1043  public void areturn(final Type type) {
1044    mv.visitInsn(type.getOpcode(Opcodes.IRETURN));
1045  }
1046
1047  public void getstatic(final String owner, final String name, final String descriptor) {
1048    mv.visitFieldInsn(Opcodes.GETSTATIC, owner, name, descriptor);
1049  }
1050
1051  public void putstatic(final String owner, final String name, final String descriptor) {
1052    mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, name, descriptor);
1053  }
1054
1055  public void getfield(final String owner, final String name, final String descriptor) {
1056    mv.visitFieldInsn(Opcodes.GETFIELD, owner, name, descriptor);
1057  }
1058
1059  public void putfield(final String owner, final String name, final String descriptor) {
1060    mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, descriptor);
1061  }
1062
1063  /**
1064   * Deprecated.
1065   *
1066   * @param owner the internal name of the method's owner class.
1067   * @param name the method's name.
1068   * @param descriptor the method's descriptor (see {@link Type}).
1069   * @deprecated use {@link #invokevirtual(String, String, String, boolean)} instead.
1070   */
1071  @Deprecated
1072  public void invokevirtual(final String owner, final String name, final String descriptor) {
1073    if (api >= Opcodes.ASM5) {
1074      invokevirtual(owner, name, descriptor, false);
1075      return;
1076    }
1077    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, descriptor);
1078  }
1079
1080  /**
1081   * Generates the instruction to call the given virtual method.
1082   *
1083   * @param owner the internal name of the method's owner class (see {@link
1084   *     Type#getInternalName()}).
1085   * @param name the method's name.
1086   * @param descriptor the method's descriptor (see {@link Type}).
1087   * @param isInterface if the method's owner class is an interface.
1088   */
1089  public void invokevirtual(
1090      final String owner, final String name, final String descriptor, final boolean isInterface) {
1091    if (api < Opcodes.ASM5) {
1092      if (isInterface) {
1093        throw new UnsupportedOperationException("INVOKEVIRTUAL on interfaces require ASM 5");
1094      }
1095      invokevirtual(owner, name, descriptor);
1096      return;
1097    }
1098    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, descriptor, isInterface);
1099  }
1100
1101  /**
1102   * Deprecated.
1103   *
1104   * @param owner the internal name of the method's owner class.
1105   * @param name the method's name.
1106   * @param descriptor the method's descriptor (see {@link Type}).
1107   * @deprecated use {@link #invokespecial(String, String, String, boolean)} instead.
1108   */
1109  @Deprecated
1110  public void invokespecial(final String owner, final String name, final String descriptor) {
1111    if (api >= Opcodes.ASM5) {
1112      invokespecial(owner, name, descriptor, false);
1113      return;
1114    }
1115    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, descriptor, false);
1116  }
1117
1118  /**
1119   * Generates the instruction to call the given special method.
1120   *
1121   * @param owner the internal name of the method's owner class (see {@link
1122   *     Type#getInternalName()}).
1123   * @param name the method's name.
1124   * @param descriptor the method's descriptor (see {@link Type}).
1125   * @param isInterface if the method's owner class is an interface.
1126   */
1127  public void invokespecial(
1128      final String owner, final String name, final String descriptor, final boolean isInterface) {
1129    if (api < Opcodes.ASM5) {
1130      if (isInterface) {
1131        throw new UnsupportedOperationException("INVOKESPECIAL on interfaces require ASM 5");
1132      }
1133      invokespecial(owner, name, descriptor);
1134      return;
1135    }
1136    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, descriptor, isInterface);
1137  }
1138
1139  /**
1140   * Deprecated.
1141   *
1142   * @param owner the internal name of the method's owner class.
1143   * @param name the method's name.
1144   * @param descriptor the method's descriptor (see {@link Type}).
1145   * @deprecated use {@link #invokestatic(String, String, String, boolean)} instead.
1146   */
1147  @Deprecated
1148  public void invokestatic(final String owner, final String name, final String descriptor) {
1149    if (api >= Opcodes.ASM5) {
1150      invokestatic(owner, name, descriptor, false);
1151      return;
1152    }
1153    mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, false);
1154  }
1155
1156  /**
1157   * Generates the instruction to call the given static method.
1158   *
1159   * @param owner the internal name of the method's owner class (see {@link
1160   *     Type#getInternalName()}).
1161   * @param name the method's name.
1162   * @param descriptor the method's descriptor (see {@link Type}).
1163   * @param isInterface if the method's owner class is an interface.
1164   */
1165  public void invokestatic(
1166      final String owner, final String name, final String descriptor, final boolean isInterface) {
1167    if (api < Opcodes.ASM5) {
1168      if (isInterface) {
1169        throw new UnsupportedOperationException("INVOKESTATIC on interfaces require ASM 5");
1170      }
1171      invokestatic(owner, name, descriptor);
1172      return;
1173    }
1174    mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, isInterface);
1175  }
1176
1177  /**
1178   * Generates the instruction to call the given interface method.
1179   *
1180   * @param owner the internal name of the method's owner class (see {@link
1181   *     Type#getInternalName()}).
1182   * @param name the method's name.
1183   * @param descriptor the method's descriptor (see {@link Type}).
1184   */
1185  public void invokeinterface(final String owner, final String name, final String descriptor) {
1186    mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, descriptor, true);
1187  }
1188
1189  /**
1190   * Generates the instruction to call the given dynamic method.
1191   *
1192   * @param name the method's name.
1193   * @param descriptor the method's descriptor (see {@link Type}).
1194   * @param bootstrapMethodHandle the bootstrap method.
1195   * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
1196   *     an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
1197   *     Type}, {@link Handle} or {@link ConstantDynamic} value. This method is allowed to modify
1198   *     the content of the array so a caller should expect that this array may change.
1199   */
1200  public void invokedynamic(
1201      final String name,
1202      final String descriptor,
1203      final Handle bootstrapMethodHandle,
1204      final Object[] bootstrapMethodArguments) {
1205    mv.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
1206  }
1207
1208  public void anew(final Type type) {
1209    mv.visitTypeInsn(Opcodes.NEW, type.getInternalName());
1210  }
1211
1212  /**
1213   * Generates the instruction to create and push on the stack an array of the given type.
1214   *
1215   * @param type an array Type.
1216   */
1217  public void newarray(final Type type) {
1218    newarray(mv, type);
1219  }
1220
1221  /**
1222   * Generates the instruction to create and push on the stack an array of the given type.
1223   *
1224   * @param methodVisitor the method visitor to use to generate the instruction.
1225   * @param type an array Type.
1226   */
1227  static void newarray(final MethodVisitor methodVisitor, final Type type) {
1228    int arrayType;
1229    switch (type.getSort()) {
1230      case Type.BOOLEAN:
1231        arrayType = Opcodes.T_BOOLEAN;
1232        break;
1233      case Type.CHAR:
1234        arrayType = Opcodes.T_CHAR;
1235        break;
1236      case Type.BYTE:
1237        arrayType = Opcodes.T_BYTE;
1238        break;
1239      case Type.SHORT:
1240        arrayType = Opcodes.T_SHORT;
1241        break;
1242      case Type.INT:
1243        arrayType = Opcodes.T_INT;
1244        break;
1245      case Type.FLOAT:
1246        arrayType = Opcodes.T_FLOAT;
1247        break;
1248      case Type.LONG:
1249        arrayType = Opcodes.T_LONG;
1250        break;
1251      case Type.DOUBLE:
1252        arrayType = Opcodes.T_DOUBLE;
1253        break;
1254      default:
1255        methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName());
1256        return;
1257    }
1258    methodVisitor.visitIntInsn(Opcodes.NEWARRAY, arrayType);
1259  }
1260
1261  public void arraylength() {
1262    mv.visitInsn(Opcodes.ARRAYLENGTH);
1263  }
1264
1265  public void athrow() {
1266    mv.visitInsn(Opcodes.ATHROW);
1267  }
1268
1269  public void checkcast(final Type type) {
1270    mv.visitTypeInsn(Opcodes.CHECKCAST, type.getInternalName());
1271  }
1272
1273  public void instanceOf(final Type type) {
1274    mv.visitTypeInsn(Opcodes.INSTANCEOF, type.getInternalName());
1275  }
1276
1277  public void monitorenter() {
1278    mv.visitInsn(Opcodes.MONITORENTER);
1279  }
1280
1281  public void monitorexit() {
1282    mv.visitInsn(Opcodes.MONITOREXIT);
1283  }
1284
1285  public void multianewarray(final String descriptor, final int numDimensions) {
1286    mv.visitMultiANewArrayInsn(descriptor, numDimensions);
1287  }
1288
1289  public void ifnull(final Label label) {
1290    mv.visitJumpInsn(Opcodes.IFNULL, label);
1291  }
1292
1293  public void ifnonnull(final Label label) {
1294    mv.visitJumpInsn(Opcodes.IFNONNULL, label);
1295  }
1296
1297  public void mark(final Label label) {
1298    mv.visitLabel(label);
1299  }
1300}