package org.codehaus.groovy.gjit; import java.util.HashMap; import java.util.Map; import java.util.Stack; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.IincInsnNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.IntInsnNode; import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TypeInsnNode; import org.objectweb.asm.tree.VarInsnNode; import org.objectweb.asm.util.AbstractVisitor; public class SimpleInterpreter implements Opcodes { // ALOAD 1 // LDC 26 // AALOAD // ILOAD 8 // ALOAD 1 // LDC 27 // AALOAD // ALOAD 1 // LDC 28 // AALOAD // INVOKESTATIC MicroTreeNode2.$get$$class$TreeNode()Ljava/lang/Class; // ALOAD 13 // ILOAD 10 // INVOKESTATIC java/lang/Integer.valueOf(I)Ljava/lang/Integer; // INVOKEINTERFACE org/codehaus/groovy/runtime/callsite/CallSite.call(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; // INVOKEINTERFACE org/codehaus/groovy/runtime/callsite/CallSite.call(Ljava/lang/Object;)Ljava/lang/Object; // INVOKEINTERFACE org/codehaus/groovy/runtime/callsite/CallSite.call(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; private Stack<DefValue> stack = new Stack<DefValue>(); private Map<AbstractInsnNode, AbstractInsnNode[]> used = new HashMap<AbstractInsnNode, AbstractInsnNode[]>(); private AbstractInsnNode start; private AbstractInsnNode stop; private int maxStack; private InsnList units; // for debugging protected int currentIndex; public SimpleInterpreter(MethodNode methodNode, AbstractInsnNode s0, AbstractInsnNode s) { units = methodNode.instructions; maxStack = methodNode.maxStack; start = s0; stop = s; } private static final DefValue NULL_VALUE = new DefValue(null, Type.VOID_TYPE); private void prepareStack(AbstractInsnNode s0) { for(int i=0;i<maxStack;i++) { stack.push(NULL_VALUE); } } public Map<AbstractInsnNode, AbstractInsnNode[]> analyse() { AbstractInsnNode s0 = start; prepareStack(s0); // prepare fake stack entry for executing s0 // DebugUtils.print(" stop at::: "); // DebugUtils.dump(stop); while(s0 != stop) { // DebugUtils.print(" simple::: "); // DebugUtils.dump(s0); execute(s0); s0 = s0.getNext(); } execute(s0); return used; } private DefValue pop() { return stack.pop(); } private DefValue peek() { return stack.peek(); } private void push(DefValue defValue) { stack.push(defValue); } public void execute(AbstractInsnNode insn) { currentIndex = units.indexOf(insn); if(insn instanceof InsnNode) { execute0((InsnNode)insn); } else if(insn instanceof IntInsnNode) { execute0((IntInsnNode)insn); } else if(insn instanceof VarInsnNode) { execute0((VarInsnNode)insn); } else if(insn instanceof TypeInsnNode) { execute0((TypeInsnNode)insn); } else if(insn instanceof FieldInsnNode) { execute0((FieldInsnNode)insn); } else if(insn instanceof MethodInsnNode){ execute0((MethodInsnNode)insn); } else if(insn instanceof JumpInsnNode) { execute0((JumpInsnNode)insn); } else if(insn instanceof LdcInsnNode) { execute0((LdcInsnNode)insn); } else if(insn instanceof IincInsnNode) { execute0((IincInsnNode)insn); } } private void execute0(TypeInsnNode insn) { switch(insn.getOpcode()) { case NEW: push(new DefValue(insn, Type.getType(Object.class))); break; case ANEWARRAY: { DefValue size = pop(); used.put(insn, new AbstractInsnNode[]{size.source}); push(new DefValue(insn, Type.getType(Object.class))); } break; case CHECKCAST: { DefValue obj = pop(); used.put(insn, new AbstractInsnNode[]{obj.source}); push(new DefValue(insn, Type.getType(Object.class))); } break; case INSTANCEOF: { DefValue obj = pop(); used.put(insn, new AbstractInsnNode[]{obj.source}); push(new DefValue(insn, Type.INT_TYPE)); } break; default : throw new RuntimeException("not implemented yet: " + AbstractVisitor.OPCODES[insn.getOpcode()]); } } private void execute0(FieldInsnNode insn) { // GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. // DebugUtils.toggle(); // DebugUtils.dump(insn); // DebugUtils.toggle(); switch(insn.getOpcode()) { case GETFIELD: used.put(insn, new AbstractInsnNode[]{pop().source}); push(new DefValue(insn, Type.getType(insn.desc))); break; case PUTFIELD: used.put(insn, new AbstractInsnNode[]{pop().source, pop().source}); break; case GETSTATIC: push(new DefValue(insn, Type.getType(insn.desc))); break; case PUTSTATIC: used.put(insn, new AbstractInsnNode[]{pop().source}); break; } //DebugUtils.dump(insn); //throw new RuntimeException("not implemented yet: " + AbstractVisitor.OPCODES[insn.getOpcode()]); } private void execute0(MethodInsnNode insn) { Type[] argTypes = Type.getArgumentTypes(insn.desc); Type retType = Type.getReturnType(insn.desc); AbstractInsnNode[] paramSource; switch(insn.getOpcode()) { case INVOKESTATIC: paramSource = new AbstractInsnNode[argTypes.length]; for(int i=argTypes.length-1;i >= 0;i--) { DefValue v = pop(); paramSource[i] = v.source; } used.put(insn, paramSource); if(retType != Type.VOID_TYPE) push(new DefValue(insn, retType)); break; case INVOKEINTERFACE: case INVOKESPECIAL: case INVOKEVIRTUAL: paramSource = new AbstractInsnNode[argTypes.length + 1]; for(int i=argTypes.length-1;i >= 0;i--) { DefValue v = pop(); paramSource[i+1] = v.source; } paramSource[0] = pop().source; // ref object used.put(insn, paramSource); if(retType != Type.VOID_TYPE) push(new DefValue(insn, retType)); break; } } private void execute0(JumpInsnNode insn) { switch(insn.getOpcode()) { case IFEQ: case IFNE: case IFGE: case IFGT: case IFLE: case IFLT: used.put(insn, new AbstractInsnNode[]{pop().source}); break; default: throw new RuntimeException("not implemented yet: " + AbstractVisitor.OPCODES[insn.getOpcode()]); } // DebugUtils.dump(insn); // throw new RuntimeException("not implemented yet: " + AbstractVisitor.OPCODES[insn.getOpcode()]); } private void execute0(LdcInsnNode insn) { if(insn.cst instanceof Integer) push(new DefValue(insn, Type.INT_TYPE)); else if(insn.cst instanceof Long) push(new DefValue(insn, Type.LONG_TYPE)); else if(insn.cst instanceof Float) push(new DefValue(insn, Type.FLOAT_TYPE)); else if(insn.cst instanceof Double) push(new DefValue(insn, Type.DOUBLE_TYPE)); else push(new DefValue(insn, Type.getType(insn.cst.getClass()))); } private void execute0(IincInsnNode insn) { // TODO Auto-generated method stub } private void execute0(VarInsnNode insn) { // TODO Auto-generated method stub switch(insn.getOpcode()) { case ILOAD: push(new DefValue(insn, Type.INT_TYPE)); break; case LLOAD: push(new DefValue(insn, Type.LONG_TYPE)); break; case FLOAD: push(new DefValue(insn, Type.FLOAT_TYPE)); break; case DLOAD: push(new DefValue(insn, Type.DOUBLE_TYPE)); break; case ALOAD: push(new DefValue(insn, Type.getType(Object.class))); break; case ISTORE: case LSTORE: case FSTORE: case DSTORE: case ASTORE: DefValue v = pop(); used.put(insn, new AbstractInsnNode[]{v.source}); break; } } private void execute0(IntInsnNode insn) { switch(insn.getOpcode()){ case BIPUSH: push(new DefValue(insn, Type.INT_TYPE)); break; case SIPUSH: push(new DefValue(insn, Type.INT_TYPE)); break; case NEWARRAY: throw new RuntimeException("not implemented yet"); } } private void execute0(InsnNode insn) { /* NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, * ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, * FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD, * FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, * FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, * DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP, IADD, LADD, * FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, * LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, * ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, * LXOR, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, * I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, * FRETURN, DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, * MONITORENTER, or MONITOREXIT. */ switch(insn.getOpcode()) { case ICONST_M1: case ICONST_0: case ICONST_1: case ICONST_2: case ICONST_3: case ICONST_4: case ICONST_5: push(new DefValue(insn, Type.INT_TYPE)); break; case AASTORE: { DefValue val = pop(); DefValue index = pop(); DefValue aref = pop(); used.put(insn, new AbstractInsnNode[]{val.source, index.source, aref.source}); push(new DefValue(insn, Type.getType(Object.class))); } break; case AALOAD: { DefValue index = pop(); DefValue aref = pop(); used.put(insn, new AbstractInsnNode[]{index.source, aref.source}); push(new DefValue(insn, Type.getType(Object.class))); } break; case POP: { DefValue tos = pop(); used.put(insn, new AbstractInsnNode[]{tos.source}); } break; case DUP: case DUP2: { DefValue tos = peek(); used.put(insn, new AbstractInsnNode[]{tos.source}); push(tos); } break; case IADD: case ISUB: case IMUL: case IDIV: { DefValue arg1 = pop(); DefValue arg0 = pop(); used.put(insn, new AbstractInsnNode[]{arg0.source, arg1.source}); push(new DefValue(insn, Type.INT_TYPE)); } break; case LADD: case LSUB: case LMUL: case LDIV: { DefValue arg1 = pop(); DefValue arg0 = pop(); used.put(insn, new AbstractInsnNode[]{arg0.source, arg1.source}); push(new DefValue(insn, Type.LONG_TYPE)); } break; case DADD: case DSUB: case DMUL: case DDIV: { DefValue arg1 = pop(); DefValue arg0 = pop(); used.put(insn, new AbstractInsnNode[]{arg0.source, arg1.source}); push(new DefValue(insn, Type.DOUBLE_TYPE)); } break; case FADD: case FSUB: case FMUL: case FDIV: { DefValue arg1 = pop(); DefValue arg0 = pop(); used.put(insn, new AbstractInsnNode[]{arg0.source, arg1.source}); push(new DefValue(insn, Type.FLOAT_TYPE)); } break; case ACONST_NULL: push(new DefValue(insn, Type.VOID_TYPE)); break; case RETURN: break; case DCMPG: case DCMPL: { DefValue arg1 = pop(); DefValue arg0 = pop(); used.put(insn, new AbstractInsnNode[] { arg0.source, arg1.source }); push(new DefValue(insn, Type.INT_TYPE)); } case L2D: DefValue arg0 = pop(); used.put(insn, new AbstractInsnNode[] {arg0.source}); push(new DefValue(insn, Type.DOUBLE_TYPE)); break; default: throw new RuntimeException("not implemented yet: " + AbstractVisitor.OPCODES[insn.getOpcode()]); } } }