| // ASM: a very small and fast Java bytecode manipulation framework |
| // Copyright (c) 2000-2011 INRIA, France Telecom |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions |
| // are met: |
| // 1. Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // 2. Redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in the |
| // documentation and/or other materials provided with the distribution. |
| // 3. Neither the name of the copyright holders nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| // THE POSSIBILITY OF SUCH DAMAGE. |
| |
| package org.apache.tapestry5.internal.plastic.asm.commons; |
| |
| import org.apache.tapestry5.internal.plastic.asm.ConstantDynamic; |
| import org.apache.tapestry5.internal.plastic.asm.Handle; |
| import org.apache.tapestry5.internal.plastic.asm.Label; |
| import org.apache.tapestry5.internal.plastic.asm.MethodVisitor; |
| import org.apache.tapestry5.internal.plastic.asm.Opcodes; |
| import org.apache.tapestry5.internal.plastic.asm.Type; |
| |
| /** |
| * A {@link MethodVisitor} providing a more detailed API to generate and transform instructions. |
| * |
| * @author Eric Bruneton |
| */ |
| public class InstructionAdapter extends MethodVisitor { |
| |
| /** The type of the java.lang.Object class. */ |
| public static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); |
| |
| /** |
| * Constructs a new {@link InstructionAdapter}. <i>Subclasses must not use this constructor</i>. |
| * Instead, they must use the {@link #InstructionAdapter(int, MethodVisitor)} version. |
| * |
| * @param methodVisitor the method visitor to which this adapter delegates calls. |
| * @throws IllegalStateException If a subclass calls this constructor. |
| */ |
| public InstructionAdapter(final MethodVisitor methodVisitor) { |
| this(Opcodes.ASM7, methodVisitor); |
| if (getClass() != InstructionAdapter.class) { |
| throw new IllegalStateException(); |
| } |
| } |
| |
| /** |
| * Constructs a new {@link InstructionAdapter}. |
| * |
| * @param api the ASM API version implemented by this visitor. Must be one of {@link |
| * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}. |
| * @param methodVisitor the method visitor to which this adapter delegates calls. |
| */ |
| protected InstructionAdapter(final int api, final MethodVisitor methodVisitor) { |
| super(api, methodVisitor); |
| } |
| |
| @Override |
| public void visitInsn(final int opcode) { |
| switch (opcode) { |
| case Opcodes.NOP: |
| nop(); |
| break; |
| case Opcodes.ACONST_NULL: |
| aconst(null); |
| break; |
| case Opcodes.ICONST_M1: |
| case Opcodes.ICONST_0: |
| case Opcodes.ICONST_1: |
| case Opcodes.ICONST_2: |
| case Opcodes.ICONST_3: |
| case Opcodes.ICONST_4: |
| case Opcodes.ICONST_5: |
| iconst(opcode - Opcodes.ICONST_0); |
| break; |
| case Opcodes.LCONST_0: |
| case Opcodes.LCONST_1: |
| lconst((long) (opcode - Opcodes.LCONST_0)); |
| break; |
| case Opcodes.FCONST_0: |
| case Opcodes.FCONST_1: |
| case Opcodes.FCONST_2: |
| fconst((float) (opcode - Opcodes.FCONST_0)); |
| break; |
| case Opcodes.DCONST_0: |
| case Opcodes.DCONST_1: |
| dconst((double) (opcode - Opcodes.DCONST_0)); |
| break; |
| case Opcodes.IALOAD: |
| aload(Type.INT_TYPE); |
| break; |
| case Opcodes.LALOAD: |
| aload(Type.LONG_TYPE); |
| break; |
| case Opcodes.FALOAD: |
| aload(Type.FLOAT_TYPE); |
| break; |
| case Opcodes.DALOAD: |
| aload(Type.DOUBLE_TYPE); |
| break; |
| case Opcodes.AALOAD: |
| aload(OBJECT_TYPE); |
| break; |
| case Opcodes.BALOAD: |
| aload(Type.BYTE_TYPE); |
| break; |
| case Opcodes.CALOAD: |
| aload(Type.CHAR_TYPE); |
| break; |
| case Opcodes.SALOAD: |
| aload(Type.SHORT_TYPE); |
| break; |
| case Opcodes.IASTORE: |
| astore(Type.INT_TYPE); |
| break; |
| case Opcodes.LASTORE: |
| astore(Type.LONG_TYPE); |
| break; |
| case Opcodes.FASTORE: |
| astore(Type.FLOAT_TYPE); |
| break; |
| case Opcodes.DASTORE: |
| astore(Type.DOUBLE_TYPE); |
| break; |
| case Opcodes.AASTORE: |
| astore(OBJECT_TYPE); |
| break; |
| case Opcodes.BASTORE: |
| astore(Type.BYTE_TYPE); |
| break; |
| case Opcodes.CASTORE: |
| astore(Type.CHAR_TYPE); |
| break; |
| case Opcodes.SASTORE: |
| astore(Type.SHORT_TYPE); |
| break; |
| case Opcodes.POP: |
| pop(); |
| break; |
| case Opcodes.POP2: |
| pop2(); |
| break; |
| case Opcodes.DUP: |
| dup(); |
| break; |
| case Opcodes.DUP_X1: |
| dupX1(); |
| break; |
| case Opcodes.DUP_X2: |
| dupX2(); |
| break; |
| case Opcodes.DUP2: |
| dup2(); |
| break; |
| case Opcodes.DUP2_X1: |
| dup2X1(); |
| break; |
| case Opcodes.DUP2_X2: |
| dup2X2(); |
| break; |
| case Opcodes.SWAP: |
| swap(); |
| break; |
| case Opcodes.IADD: |
| add(Type.INT_TYPE); |
| break; |
| case Opcodes.LADD: |
| add(Type.LONG_TYPE); |
| break; |
| case Opcodes.FADD: |
| add(Type.FLOAT_TYPE); |
| break; |
| case Opcodes.DADD: |
| add(Type.DOUBLE_TYPE); |
| break; |
| case Opcodes.ISUB: |
| sub(Type.INT_TYPE); |
| break; |
| case Opcodes.LSUB: |
| sub(Type.LONG_TYPE); |
| break; |
| case Opcodes.FSUB: |
| sub(Type.FLOAT_TYPE); |
| break; |
| case Opcodes.DSUB: |
| sub(Type.DOUBLE_TYPE); |
| break; |
| case Opcodes.IMUL: |
| mul(Type.INT_TYPE); |
| break; |
| case Opcodes.LMUL: |
| mul(Type.LONG_TYPE); |
| break; |
| case Opcodes.FMUL: |
| mul(Type.FLOAT_TYPE); |
| break; |
| case Opcodes.DMUL: |
| mul(Type.DOUBLE_TYPE); |
| break; |
| case Opcodes.IDIV: |
| div(Type.INT_TYPE); |
| break; |
| case Opcodes.LDIV: |
| div(Type.LONG_TYPE); |
| break; |
| case Opcodes.FDIV: |
| div(Type.FLOAT_TYPE); |
| break; |
| case Opcodes.DDIV: |
| div(Type.DOUBLE_TYPE); |
| break; |
| case Opcodes.IREM: |
| rem(Type.INT_TYPE); |
| break; |
| case Opcodes.LREM: |
| rem(Type.LONG_TYPE); |
| break; |
| case Opcodes.FREM: |
| rem(Type.FLOAT_TYPE); |
| break; |
| case Opcodes.DREM: |
| rem(Type.DOUBLE_TYPE); |
| break; |
| case Opcodes.INEG: |
| neg(Type.INT_TYPE); |
| break; |
| case Opcodes.LNEG: |
| neg(Type.LONG_TYPE); |
| break; |
| case Opcodes.FNEG: |
| neg(Type.FLOAT_TYPE); |
| break; |
| case Opcodes.DNEG: |
| neg(Type.DOUBLE_TYPE); |
| break; |
| case Opcodes.ISHL: |
| shl(Type.INT_TYPE); |
| break; |
| case Opcodes.LSHL: |
| shl(Type.LONG_TYPE); |
| break; |
| case Opcodes.ISHR: |
| shr(Type.INT_TYPE); |
| break; |
| case Opcodes.LSHR: |
| shr(Type.LONG_TYPE); |
| break; |
| case Opcodes.IUSHR: |
| ushr(Type.INT_TYPE); |
| break; |
| case Opcodes.LUSHR: |
| ushr(Type.LONG_TYPE); |
| break; |
| case Opcodes.IAND: |
| and(Type.INT_TYPE); |
| break; |
| case Opcodes.LAND: |
| and(Type.LONG_TYPE); |
| break; |
| case Opcodes.IOR: |
| or(Type.INT_TYPE); |
| break; |
| case Opcodes.LOR: |
| or(Type.LONG_TYPE); |
| break; |
| case Opcodes.IXOR: |
| xor(Type.INT_TYPE); |
| break; |
| case Opcodes.LXOR: |
| xor(Type.LONG_TYPE); |
| break; |
| case Opcodes.I2L: |
| cast(Type.INT_TYPE, Type.LONG_TYPE); |
| break; |
| case Opcodes.I2F: |
| cast(Type.INT_TYPE, Type.FLOAT_TYPE); |
| break; |
| case Opcodes.I2D: |
| cast(Type.INT_TYPE, Type.DOUBLE_TYPE); |
| break; |
| case Opcodes.L2I: |
| cast(Type.LONG_TYPE, Type.INT_TYPE); |
| break; |
| case Opcodes.L2F: |
| cast(Type.LONG_TYPE, Type.FLOAT_TYPE); |
| break; |
| case Opcodes.L2D: |
| cast(Type.LONG_TYPE, Type.DOUBLE_TYPE); |
| break; |
| case Opcodes.F2I: |
| cast(Type.FLOAT_TYPE, Type.INT_TYPE); |
| break; |
| case Opcodes.F2L: |
| cast(Type.FLOAT_TYPE, Type.LONG_TYPE); |
| break; |
| case Opcodes.F2D: |
| cast(Type.FLOAT_TYPE, Type.DOUBLE_TYPE); |
| break; |
| case Opcodes.D2I: |
| cast(Type.DOUBLE_TYPE, Type.INT_TYPE); |
| break; |
| case Opcodes.D2L: |
| cast(Type.DOUBLE_TYPE, Type.LONG_TYPE); |
| break; |
| case Opcodes.D2F: |
| cast(Type.DOUBLE_TYPE, Type.FLOAT_TYPE); |
| break; |
| case Opcodes.I2B: |
| cast(Type.INT_TYPE, Type.BYTE_TYPE); |
| break; |
| case Opcodes.I2C: |
| cast(Type.INT_TYPE, Type.CHAR_TYPE); |
| break; |
| case Opcodes.I2S: |
| cast(Type.INT_TYPE, Type.SHORT_TYPE); |
| break; |
| case Opcodes.LCMP: |
| lcmp(); |
| break; |
| case Opcodes.FCMPL: |
| cmpl(Type.FLOAT_TYPE); |
| break; |
| case Opcodes.FCMPG: |
| cmpg(Type.FLOAT_TYPE); |
| break; |
| case Opcodes.DCMPL: |
| cmpl(Type.DOUBLE_TYPE); |
| break; |
| case Opcodes.DCMPG: |
| cmpg(Type.DOUBLE_TYPE); |
| break; |
| case Opcodes.IRETURN: |
| areturn(Type.INT_TYPE); |
| break; |
| case Opcodes.LRETURN: |
| areturn(Type.LONG_TYPE); |
| break; |
| case Opcodes.FRETURN: |
| areturn(Type.FLOAT_TYPE); |
| break; |
| case Opcodes.DRETURN: |
| areturn(Type.DOUBLE_TYPE); |
| break; |
| case Opcodes.ARETURN: |
| areturn(OBJECT_TYPE); |
| break; |
| case Opcodes.RETURN: |
| areturn(Type.VOID_TYPE); |
| break; |
| case Opcodes.ARRAYLENGTH: |
| arraylength(); |
| break; |
| case Opcodes.ATHROW: |
| athrow(); |
| break; |
| case Opcodes.MONITORENTER: |
| monitorenter(); |
| break; |
| case Opcodes.MONITOREXIT: |
| monitorexit(); |
| break; |
| default: |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| @Override |
| public void visitIntInsn(final int opcode, final int operand) { |
| switch (opcode) { |
| case Opcodes.BIPUSH: |
| iconst(operand); |
| break; |
| case Opcodes.SIPUSH: |
| iconst(operand); |
| break; |
| case Opcodes.NEWARRAY: |
| switch (operand) { |
| case Opcodes.T_BOOLEAN: |
| newarray(Type.BOOLEAN_TYPE); |
| break; |
| case Opcodes.T_CHAR: |
| newarray(Type.CHAR_TYPE); |
| break; |
| case Opcodes.T_BYTE: |
| newarray(Type.BYTE_TYPE); |
| break; |
| case Opcodes.T_SHORT: |
| newarray(Type.SHORT_TYPE); |
| break; |
| case Opcodes.T_INT: |
| newarray(Type.INT_TYPE); |
| break; |
| case Opcodes.T_FLOAT: |
| newarray(Type.FLOAT_TYPE); |
| break; |
| case Opcodes.T_LONG: |
| newarray(Type.LONG_TYPE); |
| break; |
| case Opcodes.T_DOUBLE: |
| newarray(Type.DOUBLE_TYPE); |
| break; |
| default: |
| throw new IllegalArgumentException(); |
| } |
| break; |
| default: |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| @Override |
| public void visitVarInsn(final int opcode, final int var) { |
| switch (opcode) { |
| case Opcodes.ILOAD: |
| load(var, Type.INT_TYPE); |
| break; |
| case Opcodes.LLOAD: |
| load(var, Type.LONG_TYPE); |
| break; |
| case Opcodes.FLOAD: |
| load(var, Type.FLOAT_TYPE); |
| break; |
| case Opcodes.DLOAD: |
| load(var, Type.DOUBLE_TYPE); |
| break; |
| case Opcodes.ALOAD: |
| load(var, OBJECT_TYPE); |
| break; |
| case Opcodes.ISTORE: |
| store(var, Type.INT_TYPE); |
| break; |
| case Opcodes.LSTORE: |
| store(var, Type.LONG_TYPE); |
| break; |
| case Opcodes.FSTORE: |
| store(var, Type.FLOAT_TYPE); |
| break; |
| case Opcodes.DSTORE: |
| store(var, Type.DOUBLE_TYPE); |
| break; |
| case Opcodes.ASTORE: |
| store(var, OBJECT_TYPE); |
| break; |
| case Opcodes.RET: |
| ret(var); |
| break; |
| default: |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| @Override |
| public void visitTypeInsn(final int opcode, final String type) { |
| Type objectType = Type.getObjectType(type); |
| switch (opcode) { |
| case Opcodes.NEW: |
| anew(objectType); |
| break; |
| case Opcodes.ANEWARRAY: |
| newarray(objectType); |
| break; |
| case Opcodes.CHECKCAST: |
| checkcast(objectType); |
| break; |
| case Opcodes.INSTANCEOF: |
| instanceOf(objectType); |
| break; |
| default: |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| @Override |
| public void visitFieldInsn( |
| final int opcode, final String owner, final String name, final String descriptor) { |
| switch (opcode) { |
| case Opcodes.GETSTATIC: |
| getstatic(owner, name, descriptor); |
| break; |
| case Opcodes.PUTSTATIC: |
| putstatic(owner, name, descriptor); |
| break; |
| case Opcodes.GETFIELD: |
| getfield(owner, name, descriptor); |
| break; |
| case Opcodes.PUTFIELD: |
| putfield(owner, name, descriptor); |
| break; |
| default: |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| /** |
| * Deprecated. |
| * |
| * @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead. |
| */ |
| @Deprecated |
| @Override |
| public void visitMethodInsn( |
| final int opcode, final String owner, final String name, final String descriptor) { |
| if (api >= Opcodes.ASM5) { |
| super.visitMethodInsn(opcode, owner, name, descriptor); |
| return; |
| } |
| doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE); |
| } |
| |
| @Override |
| public void visitMethodInsn( |
| final int opcode, |
| final String owner, |
| final String name, |
| final String descriptor, |
| final boolean isInterface) { |
| if (api < Opcodes.ASM5) { |
| super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); |
| return; |
| } |
| doVisitMethodInsn(opcode, owner, name, descriptor, isInterface); |
| } |
| |
| private void doVisitMethodInsn( |
| final int opcode, |
| final String owner, |
| final String name, |
| final String descriptor, |
| final boolean isInterface) { |
| switch (opcode) { |
| case Opcodes.INVOKESPECIAL: |
| invokespecial(owner, name, descriptor, isInterface); |
| break; |
| case Opcodes.INVOKEVIRTUAL: |
| invokevirtual(owner, name, descriptor, isInterface); |
| break; |
| case Opcodes.INVOKESTATIC: |
| invokestatic(owner, name, descriptor, isInterface); |
| break; |
| case Opcodes.INVOKEINTERFACE: |
| invokeinterface(owner, name, descriptor); |
| break; |
| default: |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| @Override |
| public void visitInvokeDynamicInsn( |
| final String name, |
| final String descriptor, |
| final Handle bootstrapMethodHandle, |
| final Object... bootstrapMethodArguments) { |
| invokedynamic(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); |
| } |
| |
| @Override |
| public void visitJumpInsn(final int opcode, final Label label) { |
| switch (opcode) { |
| case Opcodes.IFEQ: |
| ifeq(label); |
| break; |
| case Opcodes.IFNE: |
| ifne(label); |
| break; |
| case Opcodes.IFLT: |
| iflt(label); |
| break; |
| case Opcodes.IFGE: |
| ifge(label); |
| break; |
| case Opcodes.IFGT: |
| ifgt(label); |
| break; |
| case Opcodes.IFLE: |
| ifle(label); |
| break; |
| case Opcodes.IF_ICMPEQ: |
| ificmpeq(label); |
| break; |
| case Opcodes.IF_ICMPNE: |
| ificmpne(label); |
| break; |
| case Opcodes.IF_ICMPLT: |
| ificmplt(label); |
| break; |
| case Opcodes.IF_ICMPGE: |
| ificmpge(label); |
| break; |
| case Opcodes.IF_ICMPGT: |
| ificmpgt(label); |
| break; |
| case Opcodes.IF_ICMPLE: |
| ificmple(label); |
| break; |
| case Opcodes.IF_ACMPEQ: |
| ifacmpeq(label); |
| break; |
| case Opcodes.IF_ACMPNE: |
| ifacmpne(label); |
| break; |
| case Opcodes.GOTO: |
| goTo(label); |
| break; |
| case Opcodes.JSR: |
| jsr(label); |
| break; |
| case Opcodes.IFNULL: |
| ifnull(label); |
| break; |
| case Opcodes.IFNONNULL: |
| ifnonnull(label); |
| break; |
| default: |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| @Override |
| public void visitLabel(final Label label) { |
| mark(label); |
| } |
| |
| @Override |
| public void visitLdcInsn(final Object value) { |
| if (api < Opcodes.ASM5 |
| && (value instanceof Handle |
| || (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) { |
| throw new UnsupportedOperationException("This feature requires ASM5"); |
| } |
| if (api != Opcodes.ASM7 && value instanceof ConstantDynamic) { |
| throw new UnsupportedOperationException("This feature requires ASM7"); |
| } |
| if (value instanceof Integer) { |
| iconst((Integer) value); |
| } else if (value instanceof Byte) { |
| iconst(((Byte) value).intValue()); |
| } else if (value instanceof Character) { |
| iconst(((Character) value).charValue()); |
| } else if (value instanceof Short) { |
| iconst(((Short) value).intValue()); |
| } else if (value instanceof Boolean) { |
| iconst(((Boolean) value).booleanValue() ? 1 : 0); |
| } else if (value instanceof Float) { |
| fconst((Float) value); |
| } else if (value instanceof Long) { |
| lconst((Long) value); |
| } else if (value instanceof Double) { |
| dconst((Double) value); |
| } else if (value instanceof String) { |
| aconst(value); |
| } else if (value instanceof Type) { |
| tconst((Type) value); |
| } else if (value instanceof Handle) { |
| hconst((Handle) value); |
| } else if (value instanceof ConstantDynamic) { |
| cconst((ConstantDynamic) value); |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| @Override |
| public void visitIincInsn(final int var, final int increment) { |
| iinc(var, increment); |
| } |
| |
| @Override |
| public void visitTableSwitchInsn( |
| final int min, final int max, final Label dflt, final Label... labels) { |
| tableswitch(min, max, dflt, labels); |
| } |
| |
| @Override |
| public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { |
| lookupswitch(dflt, keys, labels); |
| } |
| |
| @Override |
| public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { |
| multianewarray(descriptor, numDimensions); |
| } |
| |
| // ----------------------------------------------------------------------------------------------- |
| |
| /** Generates a nop instruction. */ |
| public void nop() { |
| mv.visitInsn(Opcodes.NOP); |
| } |
| |
| /** |
| * Generates the instruction to push the given value on the stack. |
| * |
| * @param value the constant to be pushed on the stack. This parameter must be an {@link Integer}, |
| * a {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link Type} of |
| * OBJECT or ARRAY sort for {@code .class} constants, for classes whose version is 49, a |
| * {@link Type} of METHOD sort for MethodType, a {@link Handle} for MethodHandle constants, |
| * for classes whose version is 51 or a {@link ConstantDynamic} for a constant dynamic for |
| * classes whose version is 55. |
| */ |
| public void aconst(final Object value) { |
| if (value == null) { |
| mv.visitInsn(Opcodes.ACONST_NULL); |
| } else { |
| mv.visitLdcInsn(value); |
| } |
| } |
| |
| /** |
| * Generates the instruction to push the given value on the stack. |
| * |
| * @param intValue the constant to be pushed on the stack. |
| */ |
| public void iconst(final int intValue) { |
| if (intValue >= -1 && intValue <= 5) { |
| mv.visitInsn(Opcodes.ICONST_0 + intValue); |
| } else if (intValue >= Byte.MIN_VALUE && intValue <= Byte.MAX_VALUE) { |
| mv.visitIntInsn(Opcodes.BIPUSH, intValue); |
| } else if (intValue >= Short.MIN_VALUE && intValue <= Short.MAX_VALUE) { |
| mv.visitIntInsn(Opcodes.SIPUSH, intValue); |
| } else { |
| mv.visitLdcInsn(intValue); |
| } |
| } |
| |
| /** |
| * Generates the instruction to push the given value on the stack. |
| * |
| * @param longValue the constant to be pushed on the stack. |
| */ |
| public void lconst(final long longValue) { |
| if (longValue == 0L || longValue == 1L) { |
| mv.visitInsn(Opcodes.LCONST_0 + (int) longValue); |
| } else { |
| mv.visitLdcInsn(longValue); |
| } |
| } |
| |
| /** |
| * Generates the instruction to push the given value on the stack. |
| * |
| * @param floatValue the constant to be pushed on the stack. |
| */ |
| public void fconst(final float floatValue) { |
| int bits = Float.floatToIntBits(floatValue); |
| if (bits == 0L || bits == 0x3F800000 || bits == 0x40000000) { // 0..2 |
| mv.visitInsn(Opcodes.FCONST_0 + (int) floatValue); |
| } else { |
| mv.visitLdcInsn(floatValue); |
| } |
| } |
| |
| /** |
| * Generates the instruction to push the given value on the stack. |
| * |
| * @param doubleValue the constant to be pushed on the stack. |
| */ |
| public void dconst(final double doubleValue) { |
| long bits = Double.doubleToLongBits(doubleValue); |
| if (bits == 0L || bits == 0x3FF0000000000000L) { // +0.0d and 1.0d |
| mv.visitInsn(Opcodes.DCONST_0 + (int) doubleValue); |
| } else { |
| mv.visitLdcInsn(doubleValue); |
| } |
| } |
| |
| /** |
| * Generates the instruction to push the given type on the stack. |
| * |
| * @param type the type to be pushed on the stack. |
| */ |
| public void tconst(final Type type) { |
| mv.visitLdcInsn(type); |
| } |
| |
| /** |
| * Generates the instruction to push the given handle on the stack. |
| * |
| * @param handle the handle to be pushed on the stack. |
| */ |
| public void hconst(final Handle handle) { |
| mv.visitLdcInsn(handle); |
| } |
| |
| /** |
| * Generates the instruction to push the given constant dynamic on the stack. |
| * |
| * @param constantDynamic the constant dynamic to be pushed on the stack. |
| */ |
| public void cconst(final ConstantDynamic constantDynamic) { |
| mv.visitLdcInsn(constantDynamic); |
| } |
| |
| public void load(final int var, final Type type) { |
| mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), var); |
| } |
| |
| public void aload(final Type type) { |
| mv.visitInsn(type.getOpcode(Opcodes.IALOAD)); |
| } |
| |
| public void store(final int var, final Type type) { |
| mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), var); |
| } |
| |
| public void astore(final Type type) { |
| mv.visitInsn(type.getOpcode(Opcodes.IASTORE)); |
| } |
| |
| public void pop() { |
| mv.visitInsn(Opcodes.POP); |
| } |
| |
| public void pop2() { |
| mv.visitInsn(Opcodes.POP2); |
| } |
| |
| public void dup() { |
| mv.visitInsn(Opcodes.DUP); |
| } |
| |
| public void dup2() { |
| mv.visitInsn(Opcodes.DUP2); |
| } |
| |
| public void dupX1() { |
| mv.visitInsn(Opcodes.DUP_X1); |
| } |
| |
| public void dupX2() { |
| mv.visitInsn(Opcodes.DUP_X2); |
| } |
| |
| public void dup2X1() { |
| mv.visitInsn(Opcodes.DUP2_X1); |
| } |
| |
| public void dup2X2() { |
| mv.visitInsn(Opcodes.DUP2_X2); |
| } |
| |
| public void swap() { |
| mv.visitInsn(Opcodes.SWAP); |
| } |
| |
| public void add(final Type type) { |
| mv.visitInsn(type.getOpcode(Opcodes.IADD)); |
| } |
| |
| public void sub(final Type type) { |
| mv.visitInsn(type.getOpcode(Opcodes.ISUB)); |
| } |
| |
| public void mul(final Type type) { |
| mv.visitInsn(type.getOpcode(Opcodes.IMUL)); |
| } |
| |
| public void div(final Type type) { |
| mv.visitInsn(type.getOpcode(Opcodes.IDIV)); |
| } |
| |
| public void rem(final Type type) { |
| mv.visitInsn(type.getOpcode(Opcodes.IREM)); |
| } |
| |
| public void neg(final Type type) { |
| mv.visitInsn(type.getOpcode(Opcodes.INEG)); |
| } |
| |
| public void shl(final Type type) { |
| mv.visitInsn(type.getOpcode(Opcodes.ISHL)); |
| } |
| |
| public void shr(final Type type) { |
| mv.visitInsn(type.getOpcode(Opcodes.ISHR)); |
| } |
| |
| public void ushr(final Type type) { |
| mv.visitInsn(type.getOpcode(Opcodes.IUSHR)); |
| } |
| |
| public void and(final Type type) { |
| mv.visitInsn(type.getOpcode(Opcodes.IAND)); |
| } |
| |
| public void or(final Type type) { |
| mv.visitInsn(type.getOpcode(Opcodes.IOR)); |
| } |
| |
| public void xor(final Type type) { |
| mv.visitInsn(type.getOpcode(Opcodes.IXOR)); |
| } |
| |
| public void iinc(final int var, final int increment) { |
| mv.visitIincInsn(var, increment); |
| } |
| |
| /** |
| * Generates the instruction to cast from the first given type to the other. |
| * |
| * @param from a Type. |
| * @param to a Type. |
| */ |
| public void cast(final Type from, final Type to) { |
| if (from != to) { |
| if (from == Type.DOUBLE_TYPE) { |
| if (to == Type.FLOAT_TYPE) { |
| mv.visitInsn(Opcodes.D2F); |
| } else if (to == Type.LONG_TYPE) { |
| mv.visitInsn(Opcodes.D2L); |
| } else { |
| mv.visitInsn(Opcodes.D2I); |
| cast(Type.INT_TYPE, to); |
| } |
| } else if (from == Type.FLOAT_TYPE) { |
| if (to == Type.DOUBLE_TYPE) { |
| mv.visitInsn(Opcodes.F2D); |
| } else if (to == Type.LONG_TYPE) { |
| mv.visitInsn(Opcodes.F2L); |
| } else { |
| mv.visitInsn(Opcodes.F2I); |
| cast(Type.INT_TYPE, to); |
| } |
| } else if (from == Type.LONG_TYPE) { |
| if (to == Type.DOUBLE_TYPE) { |
| mv.visitInsn(Opcodes.L2D); |
| } else if (to == Type.FLOAT_TYPE) { |
| mv.visitInsn(Opcodes.L2F); |
| } else { |
| mv.visitInsn(Opcodes.L2I); |
| cast(Type.INT_TYPE, to); |
| } |
| } else { |
| if (to == Type.BYTE_TYPE) { |
| mv.visitInsn(Opcodes.I2B); |
| } else if (to == Type.CHAR_TYPE) { |
| mv.visitInsn(Opcodes.I2C); |
| } else if (to == Type.DOUBLE_TYPE) { |
| mv.visitInsn(Opcodes.I2D); |
| } else if (to == Type.FLOAT_TYPE) { |
| mv.visitInsn(Opcodes.I2F); |
| } else if (to == Type.LONG_TYPE) { |
| mv.visitInsn(Opcodes.I2L); |
| } else if (to == Type.SHORT_TYPE) { |
| mv.visitInsn(Opcodes.I2S); |
| } |
| } |
| } |
| } |
| |
| public void lcmp() { |
| mv.visitInsn(Opcodes.LCMP); |
| } |
| |
| public void cmpl(final Type type) { |
| mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPL : Opcodes.DCMPL); |
| } |
| |
| public void cmpg(final Type type) { |
| mv.visitInsn(type == Type.FLOAT_TYPE ? Opcodes.FCMPG : Opcodes.DCMPG); |
| } |
| |
| public void ifeq(final Label label) { |
| mv.visitJumpInsn(Opcodes.IFEQ, label); |
| } |
| |
| public void ifne(final Label label) { |
| mv.visitJumpInsn(Opcodes.IFNE, label); |
| } |
| |
| public void iflt(final Label label) { |
| mv.visitJumpInsn(Opcodes.IFLT, label); |
| } |
| |
| public void ifge(final Label label) { |
| mv.visitJumpInsn(Opcodes.IFGE, label); |
| } |
| |
| public void ifgt(final Label label) { |
| mv.visitJumpInsn(Opcodes.IFGT, label); |
| } |
| |
| public void ifle(final Label label) { |
| mv.visitJumpInsn(Opcodes.IFLE, label); |
| } |
| |
| public void ificmpeq(final Label label) { |
| mv.visitJumpInsn(Opcodes.IF_ICMPEQ, label); |
| } |
| |
| public void ificmpne(final Label label) { |
| mv.visitJumpInsn(Opcodes.IF_ICMPNE, label); |
| } |
| |
| public void ificmplt(final Label label) { |
| mv.visitJumpInsn(Opcodes.IF_ICMPLT, label); |
| } |
| |
| public void ificmpge(final Label label) { |
| mv.visitJumpInsn(Opcodes.IF_ICMPGE, label); |
| } |
| |
| public void ificmpgt(final Label label) { |
| mv.visitJumpInsn(Opcodes.IF_ICMPGT, label); |
| } |
| |
| public void ificmple(final Label label) { |
| mv.visitJumpInsn(Opcodes.IF_ICMPLE, label); |
| } |
| |
| public void ifacmpeq(final Label label) { |
| mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label); |
| } |
| |
| public void ifacmpne(final Label label) { |
| mv.visitJumpInsn(Opcodes.IF_ACMPNE, label); |
| } |
| |
| public void goTo(final Label label) { |
| mv.visitJumpInsn(Opcodes.GOTO, label); |
| } |
| |
| public void jsr(final Label label) { |
| mv.visitJumpInsn(Opcodes.JSR, label); |
| } |
| |
| public void ret(final int var) { |
| mv.visitVarInsn(Opcodes.RET, var); |
| } |
| |
| public void tableswitch(final int min, final int max, final Label dflt, final Label... labels) { |
| mv.visitTableSwitchInsn(min, max, dflt, labels); |
| } |
| |
| public void lookupswitch(final Label dflt, final int[] keys, final Label[] labels) { |
| mv.visitLookupSwitchInsn(dflt, keys, labels); |
| } |
| |
| public void areturn(final Type type) { |
| mv.visitInsn(type.getOpcode(Opcodes.IRETURN)); |
| } |
| |
| public void getstatic(final String owner, final String name, final String descriptor) { |
| mv.visitFieldInsn(Opcodes.GETSTATIC, owner, name, descriptor); |
| } |
| |
| public void putstatic(final String owner, final String name, final String descriptor) { |
| mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, name, descriptor); |
| } |
| |
| public void getfield(final String owner, final String name, final String descriptor) { |
| mv.visitFieldInsn(Opcodes.GETFIELD, owner, name, descriptor); |
| } |
| |
| public void putfield(final String owner, final String name, final String descriptor) { |
| mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, descriptor); |
| } |
| |
| /** |
| * Deprecated. |
| * |
| * @param owner the internal name of the method's owner class. |
| * @param name the method's name. |
| * @param descriptor the method's descriptor (see {@link Type}). |
| * @deprecated use {@link #invokevirtual(String, String, String, boolean)} instead. |
| */ |
| @Deprecated |
| public void invokevirtual(final String owner, final String name, final String descriptor) { |
| if (api >= Opcodes.ASM5) { |
| invokevirtual(owner, name, descriptor, false); |
| return; |
| } |
| mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, descriptor); |
| } |
| |
| /** |
| * Generates the instruction to call the given virtual method. |
| * |
| * @param owner the internal name of the method's owner class (see {@link |
| * Type#getInternalName()}). |
| * @param name the method's name. |
| * @param descriptor the method's descriptor (see {@link Type}). |
| * @param isInterface if the method's owner class is an interface. |
| */ |
| public void invokevirtual( |
| final String owner, final String name, final String descriptor, final boolean isInterface) { |
| if (api < Opcodes.ASM5) { |
| if (isInterface) { |
| throw new IllegalArgumentException("INVOKEVIRTUAL on interfaces require ASM 5"); |
| } |
| invokevirtual(owner, name, descriptor); |
| return; |
| } |
| mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, descriptor, isInterface); |
| } |
| |
| /** |
| * Deprecated. |
| * |
| * @param owner the internal name of the method's owner class. |
| * @param name the method's name. |
| * @param descriptor the method's descriptor (see {@link Type}). |
| * @deprecated use {@link #invokespecial(String, String, String, boolean)} instead. |
| */ |
| @Deprecated |
| public void invokespecial(final String owner, final String name, final String descriptor) { |
| if (api >= Opcodes.ASM5) { |
| invokespecial(owner, name, descriptor, false); |
| return; |
| } |
| mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, descriptor, false); |
| } |
| |
| /** |
| * Generates the instruction to call the given special method. |
| * |
| * @param owner the internal name of the method's owner class (see {@link |
| * Type#getInternalName()}). |
| * @param name the method's name. |
| * @param descriptor the method's descriptor (see {@link Type}). |
| * @param isInterface if the method's owner class is an interface. |
| */ |
| public void invokespecial( |
| final String owner, final String name, final String descriptor, final boolean isInterface) { |
| if (api < Opcodes.ASM5) { |
| if (isInterface) { |
| throw new IllegalArgumentException("INVOKESPECIAL on interfaces require ASM 5"); |
| } |
| invokespecial(owner, name, descriptor); |
| return; |
| } |
| mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, descriptor, isInterface); |
| } |
| |
| /** |
| * Deprecated. |
| * |
| * @param owner the internal name of the method's owner class. |
| * @param name the method's name. |
| * @param descriptor the method's descriptor (see {@link Type}). |
| * @deprecated use {@link #invokestatic(String, String, String, boolean)} instead. |
| */ |
| @Deprecated |
| public void invokestatic(final String owner, final String name, final String descriptor) { |
| if (api >= Opcodes.ASM5) { |
| invokestatic(owner, name, descriptor, false); |
| return; |
| } |
| mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, false); |
| } |
| |
| /** |
| * Generates the instruction to call the given static method. |
| * |
| * @param owner the internal name of the method's owner class (see {@link |
| * Type#getInternalName()}). |
| * @param name the method's name. |
| * @param descriptor the method's descriptor (see {@link Type}). |
| * @param isInterface if the method's owner class is an interface. |
| */ |
| public void invokestatic( |
| final String owner, final String name, final String descriptor, final boolean isInterface) { |
| if (api < Opcodes.ASM5) { |
| if (isInterface) { |
| throw new IllegalArgumentException("INVOKESTATIC on interfaces require ASM 5"); |
| } |
| invokestatic(owner, name, descriptor); |
| return; |
| } |
| mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, isInterface); |
| } |
| |
| /** |
| * Generates the instruction to call the given interface method. |
| * |
| * @param owner the internal name of the method's owner class (see {@link |
| * Type#getInternalName()}). |
| * @param name the method's name. |
| * @param descriptor the method's descriptor (see {@link Type}). |
| */ |
| public void invokeinterface(final String owner, final String name, final String descriptor) { |
| mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, descriptor, true); |
| } |
| |
| /** |
| * Generates the instruction to call the given dynamic method. |
| * |
| * @param name the method's name. |
| * @param descriptor the method's descriptor (see {@link Type}). |
| * @param bootstrapMethodHandle the bootstrap method. |
| * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be |
| * an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link |
| * Type}, {@link Handle} or {@link ConstantDynamic} value. This method is allowed to modify |
| * the content of the array so a caller should expect that this array may change. |
| */ |
| public void invokedynamic( |
| final String name, |
| final String descriptor, |
| final Handle bootstrapMethodHandle, |
| final Object[] bootstrapMethodArguments) { |
| mv.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); |
| } |
| |
| public void anew(final Type type) { |
| mv.visitTypeInsn(Opcodes.NEW, type.getInternalName()); |
| } |
| |
| /** |
| * Generates the instruction to create and push on the stack an array of the given type. |
| * |
| * @param type an array Type. |
| */ |
| public void newarray(final Type type) { |
| int arrayType; |
| switch (type.getSort()) { |
| case Type.BOOLEAN: |
| arrayType = Opcodes.T_BOOLEAN; |
| break; |
| case Type.CHAR: |
| arrayType = Opcodes.T_CHAR; |
| break; |
| case Type.BYTE: |
| arrayType = Opcodes.T_BYTE; |
| break; |
| case Type.SHORT: |
| arrayType = Opcodes.T_SHORT; |
| break; |
| case Type.INT: |
| arrayType = Opcodes.T_INT; |
| break; |
| case Type.FLOAT: |
| arrayType = Opcodes.T_FLOAT; |
| break; |
| case Type.LONG: |
| arrayType = Opcodes.T_LONG; |
| break; |
| case Type.DOUBLE: |
| arrayType = Opcodes.T_DOUBLE; |
| break; |
| default: |
| mv.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName()); |
| return; |
| } |
| mv.visitIntInsn(Opcodes.NEWARRAY, arrayType); |
| } |
| |
| public void arraylength() { |
| mv.visitInsn(Opcodes.ARRAYLENGTH); |
| } |
| |
| public void athrow() { |
| mv.visitInsn(Opcodes.ATHROW); |
| } |
| |
| public void checkcast(final Type type) { |
| mv.visitTypeInsn(Opcodes.CHECKCAST, type.getInternalName()); |
| } |
| |
| public void instanceOf(final Type type) { |
| mv.visitTypeInsn(Opcodes.INSTANCEOF, type.getInternalName()); |
| } |
| |
| public void monitorenter() { |
| mv.visitInsn(Opcodes.MONITORENTER); |
| } |
| |
| public void monitorexit() { |
| mv.visitInsn(Opcodes.MONITOREXIT); |
| } |
| |
| public void multianewarray(final String descriptor, final int numDimensions) { |
| mv.visitMultiANewArrayInsn(descriptor, numDimensions); |
| } |
| |
| public void ifnull(final Label label) { |
| mv.visitJumpInsn(Opcodes.IFNULL, label); |
| } |
| |
| public void ifnonnull(final Label label) { |
| mv.visitJumpInsn(Opcodes.IFNONNULL, label); |
| } |
| |
| public void mark(final Label label) { |
| mv.visitLabel(label); |
| } |
| } |