http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/GeneratorAdapter.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/GeneratorAdapter.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/GeneratorAdapter.java new file mode 100644 index 0000000..4d7a07f --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/GeneratorAdapter.java @@ -0,0 +1,1641 @@ +/*** + * 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.tajo.org.objectweb.asm.commons; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.tajo.org.objectweb.asm.ClassVisitor; +import org.apache.tajo.org.objectweb.asm.Handle; +import org.apache.tajo.org.objectweb.asm.Label; +import org.apache.tajo.org.objectweb.asm.MethodVisitor; +import org.apache.tajo.org.objectweb.asm.Opcodes; +import org.apache.tajo.org.objectweb.asm.Type; + +/** + * A {@link org.apache.tajo.org.objectweb.asm.MethodVisitor} with convenient methods to generate + * code. For example, using this adapter, the class below + * + * <pre> + * public class Example { + * public static void main(String[] args) { + * System.out.println("Hello world!"); + * } + * } + * </pre> + * + * can be generated as follows: + * + * <pre> + * ClassWriter cw = new ClassWriter(true); + * cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null); + * + * Method m = Method.getMethod("void <init> ()"); + * GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw); + * mg.loadThis(); + * mg.invokeConstructor(Type.getType(Object.class), m); + * mg.returnValue(); + * mg.endMethod(); + * + * m = Method.getMethod("void main (String[])"); + * mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw); + * mg.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class)); + * mg.push("Hello world!"); + * mg.invokeVirtual(Type.getType(PrintStream.class), + * Method.getMethod("void println (String)")); + * mg.returnValue(); + * mg.endMethod(); + * + * cw.visitEnd(); + * </pre> + * + * @author Juozas Baliuka + * @author Chris Nokleberg + * @author Eric Bruneton + * @author Prashant Deva + */ +public class GeneratorAdapter extends LocalVariablesSorter { + + private static final String CLDESC = "Ljava/lang/Class;"; + + private static final Type BYTE_TYPE = Type.getObjectType("java/lang/Byte"); + + private static final Type BOOLEAN_TYPE = Type + .getObjectType("java/lang/Boolean"); + + private static final Type SHORT_TYPE = Type + .getObjectType("java/lang/Short"); + + private static final Type CHARACTER_TYPE = Type + .getObjectType("java/lang/Character"); + + private static final Type INTEGER_TYPE = Type + .getObjectType("java/lang/Integer"); + + private static final Type FLOAT_TYPE = Type + .getObjectType("java/lang/Float"); + + private static final Type LONG_TYPE = Type.getObjectType("java/lang/Long"); + + private static final Type DOUBLE_TYPE = Type + .getObjectType("java/lang/Double"); + + private static final Type NUMBER_TYPE = Type + .getObjectType("java/lang/Number"); + + private static final Type OBJECT_TYPE = Type + .getObjectType("java/lang/Object"); + + private static final Method BOOLEAN_VALUE = Method + .getMethod("boolean booleanValue()"); + + private static final Method CHAR_VALUE = Method + .getMethod("char charValue()"); + + private static final Method INT_VALUE = Method.getMethod("int intValue()"); + + private static final Method FLOAT_VALUE = Method + .getMethod("float floatValue()"); + + private static final Method LONG_VALUE = Method + .getMethod("long longValue()"); + + private static final Method DOUBLE_VALUE = Method + .getMethod("double doubleValue()"); + + /** + * Constant for the {@link #math math} method. + */ + public static final int ADD = Opcodes.IADD; + + /** + * Constant for the {@link #math math} method. + */ + public static final int SUB = Opcodes.ISUB; + + /** + * Constant for the {@link #math math} method. + */ + public static final int MUL = Opcodes.IMUL; + + /** + * Constant for the {@link #math math} method. + */ + public static final int DIV = Opcodes.IDIV; + + /** + * Constant for the {@link #math math} method. + */ + public static final int REM = Opcodes.IREM; + + /** + * Constant for the {@link #math math} method. + */ + public static final int NEG = Opcodes.INEG; + + /** + * Constant for the {@link #math math} method. + */ + public static final int SHL = Opcodes.ISHL; + + /** + * Constant for the {@link #math math} method. + */ + public static final int SHR = Opcodes.ISHR; + + /** + * Constant for the {@link #math math} method. + */ + public static final int USHR = Opcodes.IUSHR; + + /** + * Constant for the {@link #math math} method. + */ + public static final int AND = Opcodes.IAND; + + /** + * Constant for the {@link #math math} method. + */ + public static final int OR = Opcodes.IOR; + + /** + * Constant for the {@link #math math} method. + */ + public static final int XOR = Opcodes.IXOR; + + /** + * Constant for the {@link #ifCmp ifCmp} method. + */ + public static final int EQ = Opcodes.IFEQ; + + /** + * Constant for the {@link #ifCmp ifCmp} method. + */ + public static final int NE = Opcodes.IFNE; + + /** + * Constant for the {@link #ifCmp ifCmp} method. + */ + public static final int LT = Opcodes.IFLT; + + /** + * Constant for the {@link #ifCmp ifCmp} method. + */ + public static final int GE = Opcodes.IFGE; + + /** + * Constant for the {@link #ifCmp ifCmp} method. + */ + public static final int GT = Opcodes.IFGT; + + /** + * Constant for the {@link #ifCmp ifCmp} method. + */ + public static final int LE = Opcodes.IFLE; + + /** + * Access flags of the method visited by this adapter. + */ + private final int access; + + /** + * Return type of the method visited by this adapter. + */ + private final Type returnType; + + /** + * Argument types of the method visited by this adapter. + */ + private final Type[] argumentTypes; + + /** + * Types of the local variables of the method visited by this adapter. + */ + private final List<Type> localTypes = new ArrayList<Type>(); + + /** + * Creates a new {@link GeneratorAdapter}. <i>Subclasses must not use this + * constructor</i>. Instead, they must use the + * {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)} + * version. + * + * @param mv + * the method visitor to which this adapter delegates calls. + * @param access + * the method's access flags (see {@link Opcodes}). + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link Type Type}). + */ + public GeneratorAdapter(final MethodVisitor mv, final int access, + final String name, final String desc) { + this(Opcodes.ASM4, mv, access, name, desc); + } + + /** + * Creates a new {@link GeneratorAdapter}. + * + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param mv + * the method visitor to which this adapter delegates calls. + * @param access + * the method's access flags (see {@link Opcodes}). + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link Type Type}). + */ + protected GeneratorAdapter(final int api, final MethodVisitor mv, + final int access, final String name, final String desc) { + super(api, access, desc, mv); + this.access = access; + this.returnType = Type.getReturnType(desc); + this.argumentTypes = Type.getArgumentTypes(desc); + } + + /** + * Creates a new {@link GeneratorAdapter}. <i>Subclasses must not use this + * constructor</i>. Instead, they must use the + * {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)} + * version. + * + * @param access + * access flags of the adapted method. + * @param method + * the adapted method. + * @param mv + * the method visitor to which this adapter delegates calls. + */ + public GeneratorAdapter(final int access, final Method method, + final MethodVisitor mv) { + this(mv, access, null, method.getDescriptor()); + } + + /** + * Creates a new {@link GeneratorAdapter}. <i>Subclasses must not use this + * constructor</i>. Instead, they must use the + * {@link #GeneratorAdapter(int, MethodVisitor, int, String, String)} + * version. + * + * @param access + * access flags of the adapted method. + * @param method + * the adapted method. + * @param signature + * the signature of the adapted method (may be <tt>null</tt>). + * @param exceptions + * the exceptions thrown by the adapted method (may be + * <tt>null</tt>). + * @param cv + * the class visitor to which this adapter delegates calls. + */ + public GeneratorAdapter(final int access, final Method method, + final String signature, final Type[] exceptions, + final ClassVisitor cv) { + this(access, method, cv + .visitMethod(access, method.getName(), method.getDescriptor(), + signature, getInternalNames(exceptions))); + } + + /** + * Returns the internal names of the given types. + * + * @param types + * a set of types. + * @return the internal names of the given types. + */ + private static String[] getInternalNames(final Type[] types) { + if (types == null) { + return null; + } + String[] names = new String[types.length]; + for (int i = 0; i < names.length; ++i) { + names[i] = types[i].getInternalName(); + } + return names; + } + + // ------------------------------------------------------------------------ + // Instructions to push constants on the stack + // ------------------------------------------------------------------------ + + /** + * Generates the instruction to push the given value on the stack. + * + * @param value + * the value to be pushed on the stack. + */ + public void push(final boolean value) { + push(value ? 1 : 0); + } + + /** + * Generates the instruction to push the given value on the stack. + * + * @param value + * the value to be pushed on the stack. + */ + public void push(final int value) { + if (value >= -1 && value <= 5) { + mv.visitInsn(Opcodes.ICONST_0 + value); + } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { + mv.visitIntInsn(Opcodes.BIPUSH, value); + } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { + mv.visitIntInsn(Opcodes.SIPUSH, value); + } else { + mv.visitLdcInsn(new Integer(value)); + } + } + + /** + * Generates the instruction to push the given value on the stack. + * + * @param value + * the value to be pushed on the stack. + */ + public void push(final long value) { + if (value == 0L || value == 1L) { + mv.visitInsn(Opcodes.LCONST_0 + (int) value); + } else { + mv.visitLdcInsn(new Long(value)); + } + } + + /** + * Generates the instruction to push the given value on the stack. + * + * @param value + * the value to be pushed on the stack. + */ + public void push(final float value) { + int bits = Float.floatToIntBits(value); + if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2 + mv.visitInsn(Opcodes.FCONST_0 + (int) value); + } else { + mv.visitLdcInsn(new Float(value)); + } + } + + /** + * Generates the instruction to push the given value on the stack. + * + * @param value + * the value to be pushed on the stack. + */ + public void push(final double value) { + long bits = Double.doubleToLongBits(value); + if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d + mv.visitInsn(Opcodes.DCONST_0 + (int) value); + } else { + mv.visitLdcInsn(new Double(value)); + } + } + + /** + * Generates the instruction to push the given value on the stack. + * + * @param value + * the value to be pushed on the stack. May be <tt>null</tt>. + */ + public void push(final String 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 value + * the value to be pushed on the stack. + */ + public void push(final Type value) { + if (value == null) { + mv.visitInsn(Opcodes.ACONST_NULL); + } else { + switch (value.getSort()) { + case Type.BOOLEAN: + mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", + "TYPE", CLDESC); + break; + case Type.CHAR: + mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Character", + "TYPE", CLDESC); + break; + case Type.BYTE: + mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Byte", "TYPE", + CLDESC); + break; + case Type.SHORT: + mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Short", "TYPE", + CLDESC); + break; + case Type.INT: + mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", + "TYPE", CLDESC); + break; + case Type.FLOAT: + mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Float", "TYPE", + CLDESC); + break; + case Type.LONG: + mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Long", "TYPE", + CLDESC); + break; + case Type.DOUBLE: + mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Double", + "TYPE", CLDESC); + break; + default: + mv.visitLdcInsn(value); + } + } + } + + /** + * Generates the instruction to push a handle on the stack. + * + * @param handle + * the handle to be pushed on the stack. + */ + public void push(final Handle handle) { + mv.visitLdcInsn(handle); + } + + // ------------------------------------------------------------------------ + // Instructions to load and store method arguments + // ------------------------------------------------------------------------ + + /** + * Returns the index of the given method argument in the frame's local + * variables array. + * + * @param arg + * the index of a method argument. + * @return the index of the given method argument in the frame's local + * variables array. + */ + private int getArgIndex(final int arg) { + int index = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0; + for (int i = 0; i < arg; i++) { + index += argumentTypes[i].getSize(); + } + return index; + } + + /** + * Generates the instruction to push a local variable on the stack. + * + * @param type + * the type of the local variable to be loaded. + * @param index + * an index in the frame's local variables array. + */ + private void loadInsn(final Type type, final int index) { + mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index); + } + + /** + * Generates the instruction to store the top stack value in a local + * variable. + * + * @param type + * the type of the local variable to be stored. + * @param index + * an index in the frame's local variables array. + */ + private void storeInsn(final Type type, final int index) { + mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index); + } + + /** + * Generates the instruction to load 'this' on the stack. + */ + public void loadThis() { + if ((access & Opcodes.ACC_STATIC) != 0) { + throw new IllegalStateException( + "no 'this' pointer within static method"); + } + mv.visitVarInsn(Opcodes.ALOAD, 0); + } + + /** + * Generates the instruction to load the given method argument on the stack. + * + * @param arg + * the index of a method argument. + */ + public void loadArg(final int arg) { + loadInsn(argumentTypes[arg], getArgIndex(arg)); + } + + /** + * Generates the instructions to load the given method arguments on the + * stack. + * + * @param arg + * the index of the first method argument to be loaded. + * @param count + * the number of method arguments to be loaded. + */ + public void loadArgs(final int arg, final int count) { + int index = getArgIndex(arg); + for (int i = 0; i < count; ++i) { + Type t = argumentTypes[arg + i]; + loadInsn(t, index); + index += t.getSize(); + } + } + + /** + * Generates the instructions to load all the method arguments on the stack. + */ + public void loadArgs() { + loadArgs(0, argumentTypes.length); + } + + /** + * Generates the instructions to load all the method arguments on the stack, + * as a single object array. + */ + public void loadArgArray() { + push(argumentTypes.length); + newArray(OBJECT_TYPE); + for (int i = 0; i < argumentTypes.length; i++) { + dup(); + push(i); + loadArg(i); + box(argumentTypes[i]); + arrayStore(OBJECT_TYPE); + } + } + + /** + * Generates the instruction to store the top stack value in the given + * method argument. + * + * @param arg + * the index of a method argument. + */ + public void storeArg(final int arg) { + storeInsn(argumentTypes[arg], getArgIndex(arg)); + } + + // ------------------------------------------------------------------------ + // Instructions to load and store local variables + // ------------------------------------------------------------------------ + + /** + * Returns the type of the given local variable. + * + * @param local + * a local variable identifier, as returned by + * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. + * @return the type of the given local variable. + */ + public Type getLocalType(final int local) { + return localTypes.get(local - firstLocal); + } + + @Override + protected void setLocalType(final int local, final Type type) { + int index = local - firstLocal; + while (localTypes.size() < index + 1) { + localTypes.add(null); + } + localTypes.set(index, type); + } + + /** + * Generates the instruction to load the given local variable on the stack. + * + * @param local + * a local variable identifier, as returned by + * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. + */ + public void loadLocal(final int local) { + loadInsn(getLocalType(local), local); + } + + /** + * Generates the instruction to load the given local variable on the stack. + * + * @param local + * a local variable identifier, as returned by + * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. + * @param type + * the type of this local variable. + */ + public void loadLocal(final int local, final Type type) { + setLocalType(local, type); + loadInsn(type, local); + } + + /** + * Generates the instruction to store the top stack value in the given local + * variable. + * + * @param local + * a local variable identifier, as returned by + * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. + */ + public void storeLocal(final int local) { + storeInsn(getLocalType(local), local); + } + + /** + * Generates the instruction to store the top stack value in the given local + * variable. + * + * @param local + * a local variable identifier, as returned by + * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. + * @param type + * the type of this local variable. + */ + public void storeLocal(final int local, final Type type) { + setLocalType(local, type); + storeInsn(type, local); + } + + /** + * Generates the instruction to load an element from an array. + * + * @param type + * the type of the array element to be loaded. + */ + public void arrayLoad(final Type type) { + mv.visitInsn(type.getOpcode(Opcodes.IALOAD)); + } + + /** + * Generates the instruction to store an element in an array. + * + * @param type + * the type of the array element to be stored. + */ + public void arrayStore(final Type type) { + mv.visitInsn(type.getOpcode(Opcodes.IASTORE)); + } + + // ------------------------------------------------------------------------ + // Instructions to manage the stack + // ------------------------------------------------------------------------ + + /** + * Generates a POP instruction. + */ + public void pop() { + mv.visitInsn(Opcodes.POP); + } + + /** + * Generates a POP2 instruction. + */ + public void pop2() { + mv.visitInsn(Opcodes.POP2); + } + + /** + * Generates a DUP instruction. + */ + public void dup() { + mv.visitInsn(Opcodes.DUP); + } + + /** + * Generates a DUP2 instruction. + */ + public void dup2() { + mv.visitInsn(Opcodes.DUP2); + } + + /** + * Generates a DUP_X1 instruction. + */ + public void dupX1() { + mv.visitInsn(Opcodes.DUP_X1); + } + + /** + * Generates a DUP_X2 instruction. + */ + public void dupX2() { + mv.visitInsn(Opcodes.DUP_X2); + } + + /** + * Generates a DUP2_X1 instruction. + */ + public void dup2X1() { + mv.visitInsn(Opcodes.DUP2_X1); + } + + /** + * Generates a DUP2_X2 instruction. + */ + public void dup2X2() { + mv.visitInsn(Opcodes.DUP2_X2); + } + + /** + * Generates a SWAP instruction. + */ + public void swap() { + mv.visitInsn(Opcodes.SWAP); + } + + /** + * Generates the instructions to swap the top two stack values. + * + * @param prev + * type of the top - 1 stack value. + * @param type + * type of the top stack value. + */ + public void swap(final Type prev, final Type type) { + if (type.getSize() == 1) { + if (prev.getSize() == 1) { + swap(); // same as dupX1(), pop(); + } else { + dupX2(); + pop(); + } + } else { + if (prev.getSize() == 1) { + dup2X1(); + pop2(); + } else { + dup2X2(); + pop2(); + } + } + } + + // ------------------------------------------------------------------------ + // Instructions to do mathematical and logical operations + // ------------------------------------------------------------------------ + + /** + * Generates the instruction to do the specified mathematical or logical + * operation. + * + * @param op + * a mathematical or logical operation. Must be one of ADD, SUB, + * MUL, DIV, REM, NEG, SHL, SHR, USHR, AND, OR, XOR. + * @param type + * the type of the operand(s) for this operation. + */ + public void math(final int op, final Type type) { + mv.visitInsn(type.getOpcode(op)); + } + + /** + * Generates the instructions to compute the bitwise negation of the top + * stack value. + */ + public void not() { + mv.visitInsn(Opcodes.ICONST_1); + mv.visitInsn(Opcodes.IXOR); + } + + /** + * Generates the instruction to increment the given local variable. + * + * @param local + * the local variable to be incremented. + * @param amount + * the amount by which the local variable must be incremented. + */ + public void iinc(final int local, final int amount) { + mv.visitIincInsn(local, amount); + } + + /** + * Generates the instructions to cast a numerical value from one type to + * another. + * + * @param from + * the type of the top stack value + * @param to + * the type into which this value must be cast. + */ + 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); + } + } + } + } + + // ------------------------------------------------------------------------ + // Instructions to do boxing and unboxing operations + // ------------------------------------------------------------------------ + + private static Type getBoxedType(final Type type) { + switch (type.getSort()) { + case Type.BYTE: + return BYTE_TYPE; + case Type.BOOLEAN: + return BOOLEAN_TYPE; + case Type.SHORT: + return SHORT_TYPE; + case Type.CHAR: + return CHARACTER_TYPE; + case Type.INT: + return INTEGER_TYPE; + case Type.FLOAT: + return FLOAT_TYPE; + case Type.LONG: + return LONG_TYPE; + case Type.DOUBLE: + return DOUBLE_TYPE; + } + return type; + } + + /** + * Generates the instructions to box the top stack value. This value is + * replaced by its boxed equivalent on top of the stack. + * + * @param type + * the type of the top stack value. + */ + public void box(final Type type) { + if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { + return; + } + if (type == Type.VOID_TYPE) { + push((String) null); + } else { + Type boxed = getBoxedType(type); + newInstance(boxed); + if (type.getSize() == 2) { + // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o + dupX2(); + dupX2(); + pop(); + } else { + // p -> po -> opo -> oop -> o + dupX1(); + swap(); + } + invokeConstructor(boxed, new Method("<init>", Type.VOID_TYPE, + new Type[] { type })); + } + } + + /** + * Generates the instructions to box the top stack value using Java 5's + * valueOf() method. This value is replaced by its boxed equivalent on top + * of the stack. + * + * @param type + * the type of the top stack value. + */ + public void valueOf(final Type type) { + if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { + return; + } + if (type == Type.VOID_TYPE) { + push((String) null); + } else { + Type boxed = getBoxedType(type); + invokeStatic(boxed, new Method("valueOf", boxed, + new Type[] { type })); + } + } + + /** + * Generates the instructions to unbox the top stack value. This value is + * replaced by its unboxed equivalent on top of the stack. + * + * @param type + * the type of the top stack value. + */ + public void unbox(final Type type) { + Type t = NUMBER_TYPE; + Method sig = null; + switch (type.getSort()) { + case Type.VOID: + return; + case Type.CHAR: + t = CHARACTER_TYPE; + sig = CHAR_VALUE; + break; + case Type.BOOLEAN: + t = BOOLEAN_TYPE; + sig = BOOLEAN_VALUE; + break; + case Type.DOUBLE: + sig = DOUBLE_VALUE; + break; + case Type.FLOAT: + sig = FLOAT_VALUE; + break; + case Type.LONG: + sig = LONG_VALUE; + break; + case Type.INT: + case Type.SHORT: + case Type.BYTE: + sig = INT_VALUE; + } + if (sig == null) { + checkCast(type); + } else { + checkCast(t); + invokeVirtual(t, sig); + } + } + + // ------------------------------------------------------------------------ + // Instructions to jump to other instructions + // ------------------------------------------------------------------------ + + /** + * Creates a new {@link Label}. + * + * @return a new {@link Label}. + */ + public Label newLabel() { + return new Label(); + } + + /** + * Marks the current code position with the given label. + * + * @param label + * a label. + */ + public void mark(final Label label) { + mv.visitLabel(label); + } + + /** + * Marks the current code position with a new label. + * + * @return the label that was created to mark the current code position. + */ + public Label mark() { + Label label = new Label(); + mv.visitLabel(label); + return label; + } + + /** + * Generates the instructions to jump to a label based on the comparison of + * the top two stack values. + * + * @param type + * the type of the top two stack values. + * @param mode + * how these values must be compared. One of EQ, NE, LT, GE, GT, + * LE. + * @param label + * where to jump if the comparison result is <tt>true</tt>. + */ + public void ifCmp(final Type type, final int mode, final Label label) { + switch (type.getSort()) { + case Type.LONG: + mv.visitInsn(Opcodes.LCMP); + break; + case Type.DOUBLE: + mv.visitInsn(mode == GE || mode == GT ? Opcodes.DCMPL + : Opcodes.DCMPG); + break; + case Type.FLOAT: + mv.visitInsn(mode == GE || mode == GT ? Opcodes.FCMPL + : Opcodes.FCMPG); + break; + case Type.ARRAY: + case Type.OBJECT: + switch (mode) { + case EQ: + mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label); + return; + case NE: + mv.visitJumpInsn(Opcodes.IF_ACMPNE, label); + return; + } + throw new IllegalArgumentException("Bad comparison for type " + + type); + default: + int intOp = -1; + switch (mode) { + case EQ: + intOp = Opcodes.IF_ICMPEQ; + break; + case NE: + intOp = Opcodes.IF_ICMPNE; + break; + case GE: + intOp = Opcodes.IF_ICMPGE; + break; + case LT: + intOp = Opcodes.IF_ICMPLT; + break; + case LE: + intOp = Opcodes.IF_ICMPLE; + break; + case GT: + intOp = Opcodes.IF_ICMPGT; + break; + } + mv.visitJumpInsn(intOp, label); + return; + } + mv.visitJumpInsn(mode, label); + } + + /** + * Generates the instructions to jump to a label based on the comparison of + * the top two integer stack values. + * + * @param mode + * how these values must be compared. One of EQ, NE, LT, GE, GT, + * LE. + * @param label + * where to jump if the comparison result is <tt>true</tt>. + */ + public void ifICmp(final int mode, final Label label) { + ifCmp(Type.INT_TYPE, mode, label); + } + + /** + * Generates the instructions to jump to a label based on the comparison of + * the top integer stack value with zero. + * + * @param mode + * how these values must be compared. One of EQ, NE, LT, GE, GT, + * LE. + * @param label + * where to jump if the comparison result is <tt>true</tt>. + */ + public void ifZCmp(final int mode, final Label label) { + mv.visitJumpInsn(mode, label); + } + + /** + * Generates the instruction to jump to the given label if the top stack + * value is null. + * + * @param label + * where to jump if the condition is <tt>true</tt>. + */ + public void ifNull(final Label label) { + mv.visitJumpInsn(Opcodes.IFNULL, label); + } + + /** + * Generates the instruction to jump to the given label if the top stack + * value is not null. + * + * @param label + * where to jump if the condition is <tt>true</tt>. + */ + public void ifNonNull(final Label label) { + mv.visitJumpInsn(Opcodes.IFNONNULL, label); + } + + /** + * Generates the instruction to jump to the given label. + * + * @param label + * where to jump if the condition is <tt>true</tt>. + */ + public void goTo(final Label label) { + mv.visitJumpInsn(Opcodes.GOTO, label); + } + + /** + * Generates a RET instruction. + * + * @param local + * a local variable identifier, as returned by + * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. + */ + public void ret(final int local) { + mv.visitVarInsn(Opcodes.RET, local); + } + + /** + * Generates the instructions for a switch statement. + * + * @param keys + * the switch case keys. + * @param generator + * a generator to generate the code for the switch cases. + */ + public void tableSwitch(final int[] keys, final TableSwitchGenerator generator) { + tableSwitch(keys, generator, new Label()); + } + + /** + * Generates the instructions for a switch statement. + * + * @param keys + * the switch case keys. + * @param generator + * a generator to generate the code for the switch cases. + */ + public void tableSwitch(final int[] keys, + final TableSwitchGenerator generator, Label defaultLabel) { + float density; + if (keys.length == 0) { + density = 0; + } else { + density = (float) keys.length + / (keys[keys.length - 1] - keys[0] + 1); + } + tableSwitch(keys, generator, density >= 0.5f, defaultLabel); + } + + @SuppressWarnings("unused") + public void tableSwitch(final int[] keys, + final TableSwitchGenerator generator, final boolean useTable) { + tableSwitch(keys, generator, useTable, new Label()); + } + + /** + * Generates the instructions for a switch statement. + * + * @param keys + * the switch case keys. + * @param generator + * a generator to generate the code for the switch cases. + * @param useTable + * <tt>true</tt> to use a TABLESWITCH instruction, or + * <tt>false</tt> to use a LOOKUPSWITCH instruction. + */ + public void tableSwitch(final int[] keys, + final TableSwitchGenerator generator, final boolean useTable, Label def) { + for (int i = 1; i < keys.length; ++i) { + if (keys[i] < keys[i - 1]) { + throw new IllegalArgumentException( + "keys must be sorted ascending"); + } + } + + Label end = newLabel(); + if (keys.length > 0) { + int len = keys.length; + int min = keys[0]; + int max = keys[len - 1]; + int range = max - min + 1; + if (useTable) { + Label[] labels = new Label[range]; + Arrays.fill(labels, def); + for (int i = 0; i < len; ++i) { + labels[keys[i] - min] = newLabel(); + } + mv.visitTableSwitchInsn(min, max, def, labels); + for (int i = 0; i < range; ++i) { + Label label = labels[i]; + if (label != def) { + mark(label); + generator.generateCase(i + min, end); + } + } + } else { + Label[] labels = new Label[len]; + for (int i = 0; i < len; ++i) { + labels[i] = newLabel(); + } + mv.visitLookupSwitchInsn(def, keys, labels); + for (int i = 0; i < len; ++i) { + mark(labels[i]); + generator.generateCase(keys[i], end); + } + } + } + mark(def); + generator.generateDefault(); + mark(end); + } + + /** + * Generates the instruction to return the top stack value to the caller. + */ + public void returnValue() { + mv.visitInsn(returnType.getOpcode(Opcodes.IRETURN)); + } + + // ------------------------------------------------------------------------ + // Instructions to load and store fields + // ------------------------------------------------------------------------ + + /** + * Generates a get field or set field instruction. + * + * @param opcode + * the instruction's opcode. + * @param ownerType + * the class in which the field is defined. + * @param name + * the name of the field. + * @param fieldType + * the type of the field. + */ + private void fieldInsn(final int opcode, final Type ownerType, + final String name, final Type fieldType) { + mv.visitFieldInsn(opcode, ownerType.getInternalName(), name, + fieldType.getDescriptor()); + } + + /** + * Generates the instruction to push the value of a static field on the + * stack. + * + * @param owner + * the class in which the field is defined. + * @param name + * the name of the field. + * @param type + * the type of the field. + */ + public void getStatic(final Type owner, final String name, final Type type) { + fieldInsn(Opcodes.GETSTATIC, owner, name, type); + } + + /** + * Generates the instruction to store the top stack value in a static field. + * + * @param owner + * the class in which the field is defined. + * @param name + * the name of the field. + * @param type + * the type of the field. + */ + public void putStatic(final Type owner, final String name, final Type type) { + fieldInsn(Opcodes.PUTSTATIC, owner, name, type); + } + + /** + * Generates the instruction to push the value of a non static field on the + * stack. + * + * @param owner + * the class in which the field is defined. + * @param name + * the name of the field. + * @param type + * the type of the field. + */ + public void getField(final Type owner, final String name, final Type type) { + fieldInsn(Opcodes.GETFIELD, owner, name, type); + } + + /** + * Generates the instruction to store the top stack value in a non static + * field. + * + * @param owner + * the class in which the field is defined. + * @param name + * the name of the field. + * @param type + * the type of the field. + */ + public void putField(final Type owner, final String name, final Type type) { + fieldInsn(Opcodes.PUTFIELD, owner, name, type); + } + + // ------------------------------------------------------------------------ + // Instructions to invoke methods + // ------------------------------------------------------------------------ + + /** + * Generates an invoke method instruction. + * + * @param opcode + * the instruction's opcode. + * @param type + * the class in which the method is defined. + * @param method + * the method to be invoked. + */ + private void invokeInsn(final int opcode, final Type type, + final Method method) { + String owner = type.getSort() == Type.ARRAY ? type.getDescriptor() + : type.getInternalName(); + mv.visitMethodInsn(opcode, owner, method.getName(), + method.getDescriptor()); + } + + /** + * Generates the instruction to invoke a normal method. + * + * @param owner + * the class in which the method is defined. + * @param method + * the method to be invoked. + */ + public void invokeVirtual(final Type owner, final Method method) { + invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method); + } + + /** + * Generates the instruction to invoke a constructor. + * + * @param type + * the class in which the constructor is defined. + * @param method + * the constructor to be invoked. + */ + public void invokeConstructor(final Type type, final Method method) { + invokeInsn(Opcodes.INVOKESPECIAL, type, method); + } + + /** + * Generates the instruction to invoke a static method. + * + * @param owner + * the class in which the method is defined. + * @param method + * the method to be invoked. + */ + public void invokeStatic(final Type owner, final Method method) { + invokeInsn(Opcodes.INVOKESTATIC, owner, method); + } + + /** + * Generates the instruction to invoke an interface method. + * + * @param owner + * the class in which the method is defined. + * @param method + * the method to be invoked. + */ + public void invokeInterface(final Type owner, final Method method) { + invokeInsn(Opcodes.INVOKEINTERFACE, owner, method); + } + + /** + * Generates an invokedynamic instruction. + * + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link Type Type}). + * @param bsm + * the bootstrap method. + * @param bsmArgs + * the bootstrap method constant arguments. Each argument must be + * an {@link Integer}, {@link Float}, {@link Long}, + * {@link Double}, {@link String}, {@link Type} or {@link Handle} + * 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(String name, String desc, Handle bsm, + Object... bsmArgs) { + mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); + } + + // ------------------------------------------------------------------------ + // Instructions to create objects and arrays + // ------------------------------------------------------------------------ + + /** + * Generates a type dependent instruction. + * + * @param opcode + * the instruction's opcode. + * @param type + * the instruction's operand. + */ + private void typeInsn(final int opcode, final Type type) { + mv.visitTypeInsn(opcode, type.getInternalName()); + } + + /** + * Generates the instruction to create a new object. + * + * @param type + * the class of the object to be created. + */ + public void newInstance(final Type type) { + typeInsn(Opcodes.NEW, type); + } + + /** + * Generates the instruction to create a new array. + * + * @param type + * the type of the array elements. + */ + public void newArray(final Type type) { + int typ; + switch (type.getSort()) { + case Type.BOOLEAN: + typ = Opcodes.T_BOOLEAN; + break; + case Type.CHAR: + typ = Opcodes.T_CHAR; + break; + case Type.BYTE: + typ = Opcodes.T_BYTE; + break; + case Type.SHORT: + typ = Opcodes.T_SHORT; + break; + case Type.INT: + typ = Opcodes.T_INT; + break; + case Type.FLOAT: + typ = Opcodes.T_FLOAT; + break; + case Type.LONG: + typ = Opcodes.T_LONG; + break; + case Type.DOUBLE: + typ = Opcodes.T_DOUBLE; + break; + default: + typeInsn(Opcodes.ANEWARRAY, type); + return; + } + mv.visitIntInsn(Opcodes.NEWARRAY, typ); + } + + // ------------------------------------------------------------------------ + // Miscelaneous instructions + // ------------------------------------------------------------------------ + + /** + * Generates the instruction to compute the length of an array. + */ + public void arrayLength() { + mv.visitInsn(Opcodes.ARRAYLENGTH); + } + + /** + * Generates the instruction to throw an exception. + */ + public void throwException() { + mv.visitInsn(Opcodes.ATHROW); + } + + /** + * Generates the instructions to create and throw an exception. The + * exception class must have a constructor with a single String argument. + * + * @param type + * the class of the exception to be thrown. + * @param msg + * the detailed message of the exception. + */ + public void throwException(final Type type, final String msg) { + newInstance(type); + dup(); + push(msg); + invokeConstructor(type, Method.getMethod("void <init> (String)")); + throwException(); + } + + /** + * Generates the instruction to check that the top stack value is of the + * given type. + * + * @param type + * a class or interface type. + */ + public void checkCast(final Type type) { + if (!type.equals(OBJECT_TYPE)) { + typeInsn(Opcodes.CHECKCAST, type); + } + } + + /** + * Generates the instruction to test if the top stack value is of the given + * type. + * + * @param type + * a class or interface type. + */ + public void instanceOf(final Type type) { + typeInsn(Opcodes.INSTANCEOF, type); + } + + /** + * Generates the instruction to get the monitor of the top stack value. + */ + public void monitorEnter() { + mv.visitInsn(Opcodes.MONITORENTER); + } + + /** + * Generates the instruction to release the monitor of the top stack value. + */ + public void monitorExit() { + mv.visitInsn(Opcodes.MONITOREXIT); + } + + // ------------------------------------------------------------------------ + // Non instructions + // ------------------------------------------------------------------------ + + /** + * Marks the end of the visited method. + */ + public void endMethod() { + if ((access & Opcodes.ACC_ABSTRACT) == 0) { + mv.visitMaxs(0, 0); + } + mv.visitEnd(); + } + + /** + * Marks the start of an exception handler. + * + * @param start + * beginning of the exception handler's scope (inclusive). + * @param end + * end of the exception handler's scope (exclusive). + * @param exception + * internal name of the type of exceptions handled by the + * handler. + */ + public void catchException(final Label start, final Label end, + final Type exception) { + if (exception == null) { + mv.visitTryCatchBlock(start, end, mark(), null); + } else { + mv.visitTryCatchBlock(start, end, mark(), + exception.getInternalName()); + } + } +}
http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/InstructionAdapter.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/InstructionAdapter.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/InstructionAdapter.java new file mode 100644 index 0000000..3ebfec4 --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/InstructionAdapter.java @@ -0,0 +1,1090 @@ +/*** + * 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.tajo.org.objectweb.asm.commons; + +import org.apache.tajo.org.objectweb.asm.Label; +import org.apache.tajo.org.objectweb.asm.Type; +import org.apache.tajo.org.objectweb.asm.Handle; +import org.apache.tajo.org.objectweb.asm.MethodVisitor; +import org.apache.tajo.org.objectweb.asm.Opcodes; + +/** + * A {@link MethodVisitor} providing a more detailed API to generate and + * transform instructions. + * + * @author Eric Bruneton + */ +public class InstructionAdapter extends MethodVisitor { + + public final static Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); + + /** + * Creates a new {@link InstructionAdapter}. <i>Subclasses must not use this + * constructor</i>. Instead, they must use the + * {@link #InstructionAdapter(int, MethodVisitor)} version. + * + * @param mv + * the method visitor to which this adapter delegates calls. + */ + public InstructionAdapter(final MethodVisitor mv) { + this(Opcodes.ASM4, mv); + } + + /** + * Creates a new {@link InstructionAdapter}. + * + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param mv + * the method visitor to which this adapter delegates calls. + */ + protected InstructionAdapter(final int api, final MethodVisitor mv) { + super(api, mv); + } + + @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(opcode - Opcodes.LCONST_0); + break; + case Opcodes.FCONST_0: + case Opcodes.FCONST_1: + case Opcodes.FCONST_2: + fconst(opcode - Opcodes.FCONST_0); + break; + case Opcodes.DCONST_0: + case Opcodes.DCONST_1: + dconst(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 t = Type.getObjectType(type); + switch (opcode) { + case Opcodes.NEW: + anew(t); + break; + case Opcodes.ANEWARRAY: + newarray(t); + break; + case Opcodes.CHECKCAST: + checkcast(t); + break; + case Opcodes.INSTANCEOF: + instanceOf(t); + break; + default: + throw new IllegalArgumentException(); + } + } + + @Override + public void visitFieldInsn(final int opcode, final String owner, + final String name, final String desc) { + switch (opcode) { + case Opcodes.GETSTATIC: + getstatic(owner, name, desc); + break; + case Opcodes.PUTSTATIC: + putstatic(owner, name, desc); + break; + case Opcodes.GETFIELD: + getfield(owner, name, desc); + break; + case Opcodes.PUTFIELD: + putfield(owner, name, desc); + break; + default: + throw new IllegalArgumentException(); + } + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { + switch (opcode) { + case Opcodes.INVOKESPECIAL: + invokespecial(owner, name, desc); + break; + case Opcodes.INVOKEVIRTUAL: + invokevirtual(owner, name, desc); + break; + case Opcodes.INVOKESTATIC: + invokestatic(owner, name, desc); + break; + case Opcodes.INVOKEINTERFACE: + invokeinterface(owner, name, desc); + break; + default: + throw new IllegalArgumentException(); + } + } + + @Override + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, + Object... bsmArgs) { + invokedynamic(name, desc, bsm, bsmArgs); + } + + @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 cst) { + if (cst instanceof Integer) { + int val = ((Integer) cst).intValue(); + iconst(val); + } else if (cst instanceof Byte) { + int val = ((Byte) cst).intValue(); + iconst(val); + } else if (cst instanceof Character) { + int val = ((Character) cst).charValue(); + iconst(val); + } else if (cst instanceof Short) { + int val = ((Short) cst).intValue(); + iconst(val); + } else if (cst instanceof Boolean) { + int val = ((Boolean) cst).booleanValue() ? 1 : 0; + iconst(val); + } else if (cst instanceof Float) { + float val = ((Float) cst).floatValue(); + fconst(val); + } else if (cst instanceof Long) { + long val = ((Long) cst).longValue(); + lconst(val); + } else if (cst instanceof Double) { + double val = ((Double) cst).doubleValue(); + dconst(val); + } else if (cst instanceof String) { + aconst(cst); + } else if (cst instanceof Type) { + tconst((Type) cst); + } else if (cst instanceof Handle) { + hconst((Handle) cst); + } 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 desc, final int dims) { + multianewarray(desc, dims); + } + + // ----------------------------------------------------------------------- + + public void nop() { + mv.visitInsn(Opcodes.NOP); + } + + public void aconst(final Object cst) { + if (cst == null) { + mv.visitInsn(Opcodes.ACONST_NULL); + } else { + mv.visitLdcInsn(cst); + } + } + + public void iconst(final int cst) { + if (cst >= -1 && cst <= 5) { + mv.visitInsn(Opcodes.ICONST_0 + cst); + } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) { + mv.visitIntInsn(Opcodes.BIPUSH, cst); + } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) { + mv.visitIntInsn(Opcodes.SIPUSH, cst); + } else { + mv.visitLdcInsn(new Integer(cst)); + } + } + + public void lconst(final long cst) { + if (cst == 0L || cst == 1L) { + mv.visitInsn(Opcodes.LCONST_0 + (int) cst); + } else { + mv.visitLdcInsn(new Long(cst)); + } + } + + public void fconst(final float cst) { + int bits = Float.floatToIntBits(cst); + if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2 + mv.visitInsn(Opcodes.FCONST_0 + (int) cst); + } else { + mv.visitLdcInsn(new Float(cst)); + } + } + + public void dconst(final double cst) { + long bits = Double.doubleToLongBits(cst); + if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d + mv.visitInsn(Opcodes.DCONST_0 + (int) cst); + } else { + mv.visitLdcInsn(new Double(cst)); + } + } + + public void tconst(final Type type) { + mv.visitLdcInsn(type); + } + + public void hconst(final Handle handle) { + mv.visitLdcInsn(handle); + } + + 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); + } + + 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 t) { + mv.visitInsn(t.getOpcode(Opcodes.IRETURN)); + } + + public void getstatic(final String owner, final String name, + final String desc) { + mv.visitFieldInsn(Opcodes.GETSTATIC, owner, name, desc); + } + + public void putstatic(final String owner, final String name, + final String desc) { + mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, name, desc); + } + + public void getfield(final String owner, final String name, + final String desc) { + mv.visitFieldInsn(Opcodes.GETFIELD, owner, name, desc); + } + + public void putfield(final String owner, final String name, + final String desc) { + mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, desc); + } + + public void invokevirtual(final String owner, final String name, + final String desc) { + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc); + } + + public void invokespecial(final String owner, final String name, + final String desc) { + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc); + } + + public void invokestatic(final String owner, final String name, + final String desc) { + mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc); + } + + public void invokeinterface(final String owner, final String name, + final String desc) { + mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc); + } + + public void invokedynamic(String name, String desc, Handle bsm, + Object[] bsmArgs) { + mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); + } + + public void anew(final Type type) { + mv.visitTypeInsn(Opcodes.NEW, type.getInternalName()); + } + + public void newarray(final Type type) { + int typ; + switch (type.getSort()) { + case Type.BOOLEAN: + typ = Opcodes.T_BOOLEAN; + break; + case Type.CHAR: + typ = Opcodes.T_CHAR; + break; + case Type.BYTE: + typ = Opcodes.T_BYTE; + break; + case Type.SHORT: + typ = Opcodes.T_SHORT; + break; + case Type.INT: + typ = Opcodes.T_INT; + break; + case Type.FLOAT: + typ = Opcodes.T_FLOAT; + break; + case Type.LONG: + typ = Opcodes.T_LONG; + break; + case Type.DOUBLE: + typ = Opcodes.T_DOUBLE; + break; + default: + mv.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName()); + return; + } + mv.visitIntInsn(Opcodes.NEWARRAY, typ); + } + + 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 desc, final int dims) { + mv.visitMultiANewArrayInsn(desc, dims); + } + + 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); + } +}
