You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by cc...@apache.org on 2017/12/14 21:56:48 UTC

[23/57] [abbrv] [partial] groovy git commit: Move Java source set into `src/main/java`

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionWriter.java
new file mode 100644
index 0000000..c03515a
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionWriter.java
@@ -0,0 +1,328 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+
+import static org.codehaus.groovy.syntax.Types.BITWISE_OR;
+import static org.codehaus.groovy.syntax.Types.COMPARE_NOT_EQUAL;
+import static org.codehaus.groovy.syntax.Types.COMPARE_TO;
+import static org.codehaus.groovy.syntax.Types.LEFT_SHIFT;
+import static org.codehaus.groovy.syntax.Types.LEFT_SQUARE_BRACKET;
+import static org.codehaus.groovy.syntax.Types.MINUS_MINUS;
+import static org.codehaus.groovy.syntax.Types.PLUS;
+import static org.codehaus.groovy.syntax.Types.PLUS_PLUS;
+import static org.objectweb.asm.Opcodes.GOTO;
+import static org.objectweb.asm.Opcodes.ICONST_0;
+import static org.objectweb.asm.Opcodes.ICONST_1;
+import static org.objectweb.asm.Opcodes.ICONST_M1;
+import static org.objectweb.asm.Opcodes.IFEQ;
+import static org.objectweb.asm.Opcodes.IFGE;
+import static org.objectweb.asm.Opcodes.IFGT;
+import static org.objectweb.asm.Opcodes.IFLE;
+import static org.objectweb.asm.Opcodes.IFLT;
+import static org.objectweb.asm.Opcodes.IFNE;
+
+/**
+ * Base class for writing primitive typed operations
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public abstract class BinaryExpressionWriter {
+    
+    private final WriterController controller;
+    private MethodCaller arraySet, arrayGet;
+
+    public BinaryExpressionWriter(WriterController controller, MethodCaller arraySet, MethodCaller arrayGet) {
+        this.controller = controller;
+        this.arraySet = arraySet;
+        this.arrayGet = arrayGet;
+    }
+
+    /**
+     * return writer controller
+     * @since 2.5.0
+     */
+    public WriterController getController() {
+        return controller;
+    }
+    
+    protected static final int[] stdCompareCodes = {
+        IFEQ,      // COMPARE_NOT_EQUAL            120
+        IFNE,      // COMPARE_IDENTICAL            121 
+        IFEQ,      // COMPARE_NOT_IDENTICAL        122
+        IFNE,      // COMPARE_EQUAL                123
+        IFGE,      // COMPARE_LESS_THAN            124
+        IFGT,      // COMPARE_LESS_THAN_EQUAL      125
+        IFLE,      // COMPARE_GREATER_THAN         126
+        IFLT,      // COMPARE_GREATER_THAN_EQUAL   127
+    };
+    
+    protected abstract int getCompareCode();
+
+    /**
+     * writes some int standard operations for compares
+     * @param type the token type
+     * @return true if a successful std operator write
+     */
+    protected boolean writeStdCompare(int type, boolean simulate) {
+        type = type-COMPARE_NOT_EQUAL;
+        // look if really compare
+        if (type<0||type>7) return false;
+
+        if (!simulate) {
+            MethodVisitor mv = controller.getMethodVisitor();
+            OperandStack operandStack = controller.getOperandStack();
+            // operands are on the stack already
+            int bytecode = stdCompareCodes[type];
+            mv.visitInsn(getCompareCode());
+            Label l1 = new Label();
+            mv.visitJumpInsn(bytecode,l1);
+            mv.visitInsn(ICONST_1);
+            Label l2 = new Label();
+            mv.visitJumpInsn(GOTO, l2);
+            mv.visitLabel(l1);
+            mv.visitInsn(ICONST_0);
+            mv.visitLabel(l2);
+            operandStack.replace(ClassHelper.boolean_TYPE, 2);
+        }
+        return true;
+    }
+    
+    protected abstract void doubleTwoOperands(MethodVisitor mv);
+    protected abstract void removeTwoOperands(MethodVisitor mv);
+    
+    protected boolean writeSpaceship(int type, boolean simulate) {
+        if (type != COMPARE_TO) return false;
+        /*  
+           we will actually do
+         
+          (x < y) ? -1 : ((x == y) ? 0 : 1)
+          which is the essence of what the call with Number would do
+          this compiles to something along
+          
+              <x>
+              <y>
+              LCMP
+              IFGE L1
+              ICONST_M1
+              GOTO L2
+          L1
+              <x>
+              <y>
+              LCMP
+              IFNE L3
+              ICONST_0
+              GOTO L2
+          L3
+              ICONST_1
+          L2
+          
+          since the operators are already on the stack and we don't want
+          to load them again, we will instead duplicate them. This will
+          require some pop actions in the branches!
+          
+              DUP4          (operands: L1L2L1L2)
+              LCMP          
+              IFGE L1       (operands: L1L2)
+              ICONST_M1     (operands: L1L2I)
+              GOTO L2
+          L1
+              -----         (operands: L1L2)
+              LCMP
+              IFNE L3       (operands: -)
+              ICONST_0      (operands: I)
+              GOTO L2
+          L3
+              - jump from L1 branch to here (operands: -)
+              ICONST_1      (operands: I)
+          L2  
+          - if jump from GOTO L2 we have LLI, but need only I
+          - if from L3 branch we get only I
+          
+          this means we have to pop of LL before loading -1
+          
+          since there is no DUP4 we have to do this:
+            DUP2_X1
+            POP2
+            DUP2_X1
+            DUP2_X1
+            POP2
+            DUP2_X1          
+        */
+        if (!simulate) {
+            MethodVisitor mv = controller.getMethodVisitor();
+            // duplicate arguments
+            doubleTwoOperands(mv);
+            
+            Label l1 = new Label();
+            mv.visitInsn(getCompareCode());
+            mv.visitJumpInsn(IFGE,l1);
+            // no jump, so -1, need to pop off surplus LL
+            removeTwoOperands(mv);
+            mv.visitInsn(ICONST_M1);
+            Label l2 = new Label();
+            mv.visitJumpInsn(GOTO, l2);
+            
+            mv.visitLabel(l1);
+            Label l3 = new Label();
+            mv.visitInsn(getCompareCode());
+            mv.visitJumpInsn(IFNE,l3);
+            mv.visitInsn(ICONST_0);
+            mv.visitJumpInsn(GOTO,l2);
+            
+            mv.visitLabel(l3);
+            mv.visitInsn(ICONST_1);
+            
+            controller.getOperandStack().replace(ClassHelper.int_TYPE, 2);
+        }
+        return true;
+    }
+
+    protected abstract ClassNode getNormalOpResultType();
+    protected abstract int getStandardOperationBytecode(int type);
+    
+    protected boolean writeStdOperators(int type, boolean simulate) {
+        type = type-PLUS;
+        if (type<0 || type>5 || type == 3 /*DIV*/) return false;
+        
+        if (!simulate) {
+            int bytecode = getStandardOperationBytecode(type);
+            controller.getMethodVisitor().visitInsn(bytecode);
+            controller.getOperandStack().replace(getNormalOpResultType(), 2);
+        }
+        return true;
+    }
+    
+    protected boolean writeDivision(boolean simulate) {
+        if (!supportsDivision()) return false;
+        if (!simulate) {
+            int bytecode = getStandardOperationBytecode(3 /*DIV*/);
+            controller.getMethodVisitor().visitInsn(bytecode);
+            controller.getOperandStack().replace(getDevisionOpResultType(), 2);
+        }
+        return true;
+    }
+    
+    protected boolean supportsDivision() {
+        return false;
+    }
+
+    protected abstract ClassNode getDevisionOpResultType();
+
+    protected abstract int getBitwiseOperationBytecode(int type);
+    
+    /**
+     * writes some the bitwise operations. type is one of BITWISE_OR, 
+     * BITWISE_AND, BITWISE_XOR
+     * @param type the token type
+     * @return true if a successful bitwise operation write
+     */
+    protected boolean writeBitwiseOp(int type, boolean simulate) {
+        type = type-BITWISE_OR;
+        if (type<0 || type>2) return false;
+
+        if (!simulate) {
+            int bytecode = getBitwiseOperationBytecode(type);
+            controller.getMethodVisitor().visitInsn(bytecode);
+            controller.getOperandStack().replace(getNormalOpResultType(), 2);
+        }
+        return true;
+    }
+    
+    protected abstract int getShiftOperationBytecode(int type);
+    
+    /**
+     * Write shifting operations.
+     * Type is one of LEFT_SHIFT, RIGHT_SHIFT, or RIGHT_SHIFT_UNSIGNED
+     *
+     * @param type the token type
+     * @return true on a successful shift operation write
+     */
+    protected boolean writeShiftOp(int type, boolean simulate) {
+        type = type - LEFT_SHIFT;
+        if (type < 0 || type > 2) return false;
+
+        if (!simulate) {
+            int bytecode = getShiftOperationBytecode(type);
+            controller.getMethodVisitor().visitInsn(bytecode);
+            controller.getOperandStack().replace(getNormalOpResultType(), 2);
+        }
+        return true;
+    }
+
+    public boolean write(int operation, boolean simulate) {
+        return  writeStdCompare(operation, simulate)         ||
+                writeSpaceship(operation, simulate)          ||
+                writeStdOperators(operation, simulate)       ||
+                writeBitwiseOp(operation, simulate)          ||
+                writeShiftOp(operation, simulate);
+    }
+    
+    protected MethodCaller getArrayGetCaller() {
+        return arrayGet;
+    }
+
+    protected ClassNode getArrayGetResultType(){
+        return getNormalOpResultType();
+    }
+    
+    protected MethodCaller getArraySetCaller() {
+        return arraySet;
+    }
+
+    public void setArraySetAndGet(MethodCaller arraySet, MethodCaller arrayGet) {
+        this.arraySet = arraySet;
+        this.arrayGet = arrayGet;
+    }
+    
+    public boolean arrayGet(int operation, boolean simulate) {
+        if (operation!=LEFT_SQUARE_BRACKET) return false;
+        
+        if (!simulate) {
+            getArrayGetCaller().call(controller.getMethodVisitor());
+        }
+        return true;
+    }
+
+    public boolean arraySet(boolean simulate) {        
+        if (!simulate) {
+            getArraySetCaller().call(controller.getMethodVisitor());
+        }
+        return true;
+    }
+
+    public boolean writePostOrPrefixMethod(int operation, boolean simulate) {
+        if (operation!=PLUS_PLUS && operation!=MINUS_MINUS) return false;
+        if (!simulate) {
+            MethodVisitor mv = controller.getMethodVisitor();
+            if (operation==PLUS_PLUS) {
+                writePlusPlus(mv);
+            } else {
+                writeMinusMinus(mv);
+            }
+        }
+        return true;
+    }
+
+    protected abstract void writePlusPlus(MethodVisitor mv);
+    protected abstract void writeMinusMinus(MethodVisitor mv);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/classgen/asm/BinaryFloatExpressionHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryFloatExpressionHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryFloatExpressionHelper.java
new file mode 100644
index 0000000..6a4552a
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryFloatExpressionHelper.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen.asm;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.runtime.BytecodeInterface8;
+import org.objectweb.asm.MethodVisitor;
+
+import static org.objectweb.asm.Opcodes.DUP2;
+import static org.objectweb.asm.Opcodes.FADD;
+import static org.objectweb.asm.Opcodes.FCMPG;
+import static org.objectweb.asm.Opcodes.FCONST_1;
+import static org.objectweb.asm.Opcodes.FDIV;
+import static org.objectweb.asm.Opcodes.FMUL;
+import static org.objectweb.asm.Opcodes.FREM;
+import static org.objectweb.asm.Opcodes.FSUB;
+import static org.objectweb.asm.Opcodes.POP2;
+
+/**
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class BinaryFloatExpressionHelper extends BinaryExpressionWriter {
+
+    public BinaryFloatExpressionHelper(WriterController controller) {
+        super(controller, floatArraySet, floatArrayGet);
+    }
+    
+    protected void doubleTwoOperands(MethodVisitor mv) {
+        mv.visitInsn(DUP2);
+    }
+
+    private static final MethodCaller 
+        floatArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "fArrayGet"),
+        floatArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "fArraySet");
+
+    protected boolean writeBitwiseOp(int type, boolean simulate) {
+        if (!simulate) throw new GroovyBugError("should not reach here");
+        return false;   
+    }    
+    
+    protected int getBitwiseOperationBytecode(int type) {
+        return -1;
+    }
+    
+    protected int getCompareCode() {
+        return FCMPG;
+    }
+    
+    protected ClassNode getNormalOpResultType() {
+        return ClassHelper.float_TYPE;
+    }
+    
+    protected boolean writeShiftOp(int type, boolean simulate) {
+        if (!simulate) throw new GroovyBugError("should not reach here");
+        return false;   
+    }    
+    
+    protected int getShiftOperationBytecode(int type) {
+        return -1;
+    }
+
+    private static final int[] stdOperations = {
+        FADD,           //  PLUS        200
+        FSUB,           //  MINUS       201
+        FMUL,           //  MULTIPLY    202
+        0,              //  DIV, (203) but we don't want that one
+        FDIV,           //  INTDIV      204
+        FREM,           //  MOD         203
+    };    
+    
+    protected int getStandardOperationBytecode(int type) {
+        return stdOperations[type];
+    }
+    
+    protected void removeTwoOperands(MethodVisitor mv) {
+        mv.visitInsn(POP2);
+    }
+    
+    protected void writeMinusMinus(MethodVisitor mv) {
+        mv.visitInsn(FCONST_1);
+        mv.visitInsn(FSUB);
+    }
+    
+    protected void writePlusPlus(MethodVisitor mv) {
+        mv.visitInsn(FCONST_1);
+        mv.visitInsn(FADD);
+    }
+
+    protected ClassNode getDevisionOpResultType() {
+        return ClassHelper.BigDecimal_TYPE;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/classgen/asm/BinaryIntExpressionHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryIntExpressionHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryIntExpressionHelper.java
new file mode 100644
index 0000000..dfa1245
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryIntExpressionHelper.java
@@ -0,0 +1,293 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.runtime.BytecodeInterface8;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+
+import static org.codehaus.groovy.syntax.Types.COMPARE_NOT_EQUAL;
+import static org.codehaus.groovy.syntax.Types.COMPARE_TO;
+import static org.objectweb.asm.Opcodes.DUP2;
+import static org.objectweb.asm.Opcodes.GOTO;
+import static org.objectweb.asm.Opcodes.IADD;
+import static org.objectweb.asm.Opcodes.IAND;
+import static org.objectweb.asm.Opcodes.ICONST_0;
+import static org.objectweb.asm.Opcodes.ICONST_1;
+import static org.objectweb.asm.Opcodes.ICONST_M1;
+import static org.objectweb.asm.Opcodes.IDIV;
+import static org.objectweb.asm.Opcodes.IF_ICMPEQ;
+import static org.objectweb.asm.Opcodes.IF_ICMPGE;
+import static org.objectweb.asm.Opcodes.IF_ICMPGT;
+import static org.objectweb.asm.Opcodes.IF_ICMPLE;
+import static org.objectweb.asm.Opcodes.IF_ICMPLT;
+import static org.objectweb.asm.Opcodes.IF_ICMPNE;
+import static org.objectweb.asm.Opcodes.IMUL;
+import static org.objectweb.asm.Opcodes.IOR;
+import static org.objectweb.asm.Opcodes.IREM;
+import static org.objectweb.asm.Opcodes.ISHL;
+import static org.objectweb.asm.Opcodes.ISHR;
+import static org.objectweb.asm.Opcodes.ISUB;
+import static org.objectweb.asm.Opcodes.IUSHR;
+import static org.objectweb.asm.Opcodes.IXOR;
+import static org.objectweb.asm.Opcodes.POP2;
+
+public class BinaryIntExpressionHelper extends BinaryExpressionWriter {
+    
+    private static final MethodCaller intArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "intArrayGet");
+    private static final MethodCaller intArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "intArraySet");
+
+    private static final int[] stdCompareCodes = {
+        IF_ICMPEQ,      // COMPARE_NOT_EQUAL            120
+        IF_ICMPNE,      // COMPARE_IDENTICAL            121 
+        IF_ICMPEQ,      // COMPARE_NOT_IDENTICAL        122
+        IF_ICMPNE,      // COMPARE_EQUAL                123
+        IF_ICMPGE,      // COMPARE_LESS_THAN            124
+        IF_ICMPGT,      // COMPARE_LESS_THAN_EQUAL      125
+        IF_ICMPLE,      // COMPARE_GREATER_THAN         126
+        IF_ICMPLT,      // COMPARE_GREATER_THAN_EQUAL   127
+    };
+    
+    private static final int[] stdOperations = {
+        IADD,           //  PLUS        200
+        ISUB,           //  MINUS       201
+        IMUL,           //  MULTIPLY    202
+        IDIV,           //  DIV         203
+        IDIV,           //  INTDIV      204
+        IREM,           //  MOD         203
+    };
+    
+    private static final int[] bitOp = {
+        IOR,            //  BITWISE_OR / PIPE   340
+        IAND,           //  BITWISE_AND         341
+        IXOR,           //  BIWISE_XOR          342
+    };    
+    
+    /* unhandled types from from org.codehaus.groovy.syntax.Types
+    public static final int LOGICAL_OR                  = 162;   // ||
+    public static final int LOGICAL_AND                 = 164;   // &&
+
+    public static final int DIVIDE                      = 203;   // /
+    public static final int STAR_STAR                   = 206;   // **
+    public static final int POWER                       = STAR_STAR;   //
+    
+    public static final int PLUS_EQUAL                  = 210;   // +=
+    public static final int MINUS_EQUAL                 = 211;   // -=
+    public static final int MULTIPLY_EQUAL              = 212;   // *=
+    public static final int DIVIDE_EQUAL                = 213;   // /=
+    public static final int INTDIV_EQUAL                = 214;   // \=
+    public static final int MOD_EQUAL                   = 215;   // %=
+    public static final int POWER_EQUAL                 = 216;   // **=
+
+    public static final int PLUS_PLUS                   = 250;   // ++
+    public static final int PREFIX_PLUS_PLUS            = 251;   // ++
+    public static final int POSTFIX_PLUS_PLUS           = 252;   // ++
+    public static final int PREFIX_PLUS                 = 253;   // +
+
+    public static final int MINUS_MINUS                 = 260;   // --
+    public static final int PREFIX_MINUS_MINUS          = 261;   // --
+    public static final int POSTFIX_MINUS_MINUS         = 262;   // --
+    public static final int PREFIX_MINUS                = 263;   // - (negation)
+*/
+    private static final int[] shiftOp = {
+        ISHL,           // LEFT_SHIFT               280
+        ISHR,           // RIGHT_SHIFT              281
+        IUSHR           // RIGHT_SHIFT_UNSIGNED     282
+    };
+
+/*
+    public static final int LEFT_SHIFT_EQUAL            = 285;   // <<=
+    public static final int RIGHT_SHIFT_EQUAL           = 286;   // >>=
+    public static final int RIGHT_SHIFT_UNSIGNED_EQUAL  = 287;   // >>>=
+
+    public static final int BITWISE_OR_EQUAL            = 350;   // |=
+    public static final int BITWISE_AND_EQUAL           = 351;   // &=
+    public static final int BITWISE_XOR_EQUAL           = 352;   // ^=
+    public static final int BITWISE_NEGATION            = REGEX_PATTERN;    // ~
+    */
+    
+    public BinaryIntExpressionHelper(WriterController wc) {
+        this(wc, intArraySet, intArrayGet);
+    }
+
+    /**
+     * @since 2.5.0
+     */
+    public BinaryIntExpressionHelper(WriterController wc, MethodCaller arraySet, MethodCaller arrayGet) {
+        super(wc, arraySet, arrayGet);
+    }
+
+    
+    /**
+     * writes a std compare. This involves the tokens IF_ICMPEQ, IF_ICMPNE, 
+     * IF_ICMPEQ, IF_ICMPNE, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE and IF_ICMPLT
+     * @param type the token type
+     * @return true if a successful std compare write
+     */
+    protected boolean writeStdCompare(int type, boolean simulate) {
+        type = type-COMPARE_NOT_EQUAL;
+        // look if really compare
+        if (type<0||type>7) return false;
+
+        if (!simulate) {
+            MethodVisitor mv = getController().getMethodVisitor();
+            OperandStack operandStack = getController().getOperandStack();
+            // operands are on the stack already
+            int bytecode = stdCompareCodes[type];
+            Label l1 = new Label();
+            mv.visitJumpInsn(bytecode,l1);
+            mv.visitInsn(ICONST_1);
+            Label l2 = new Label();
+            mv.visitJumpInsn(GOTO, l2);
+            mv.visitLabel(l1);
+            mv.visitInsn(ICONST_0);
+            mv.visitLabel(l2);
+            operandStack.replace(ClassHelper.boolean_TYPE, 2);
+        }
+        return true;
+    }
+    
+    /**
+     * writes the spaceship operator, type should be COMPARE_TO
+     * @param type the token type
+     * @return true if a successful spaceship operator write
+     */
+    protected boolean writeSpaceship(int type, boolean simulate) {
+        if (type != COMPARE_TO) return false;
+        /*  
+           we will actually do
+         
+          (x < y) ? -1 : ((x == y) ? 0 : 1)
+          which is the essence of what the call with Integers would do
+          this compiles to something along
+          
+              <x>
+              <y>
+              IF_ICMPGE L1
+              ICONST_M1
+              GOTO L2
+          L1
+              <x>
+              <y>
+              IF_ICMPNE L3
+              ICONST_0
+              GOTO L2
+          L3
+              ICONST_1
+          L2
+          
+          since the operators are already on the stack and we don't want
+          to load them again, we will instead duplicate them. This will
+          require some pop actions in the branches!
+          
+              DUP2          (operands: IIII) 
+              IF_ICMPGE L1  (operands: II)
+              ICONST_M1     (operands: III)
+              GOTO L2
+          L1
+              -----         (operands: II)
+              IF_ICMPNE L3  (operands: -)
+              ICONST_0      (operands: I)
+              GOTO L2
+          L3
+              - jump from L1 branch to here (operands: -)
+              ICONST_1      (operands: I)
+          L2  
+          - if jump from GOTO L2 we have III, but need only I
+          - if from L3 branch we get only I
+          
+          this means we have to pop of II before loading -1
+          
+        */
+        if (!simulate) {
+            MethodVisitor mv = getController().getMethodVisitor();
+            // duplicate int arguments
+            mv.visitInsn(DUP2);
+            
+            Label l1 = new Label();
+            mv.visitJumpInsn(IF_ICMPGE,l1);
+            // no jump, so -1, need to pop off surplus II
+            mv.visitInsn(POP2);
+            mv.visitInsn(ICONST_M1);
+            Label l2 = new Label();
+            mv.visitJumpInsn(GOTO, l2);
+            
+            mv.visitLabel(l1);
+            Label l3 = new Label();
+            mv.visitJumpInsn(IF_ICMPNE,l3);
+            mv.visitInsn(ICONST_0);
+            mv.visitJumpInsn(GOTO,l2);
+            
+            mv.visitLabel(l3);
+            mv.visitInsn(ICONST_1);
+
+            getController().getOperandStack().replace(ClassHelper.int_TYPE, 2);
+        }
+        return true;
+    }
+
+    protected void doubleTwoOperands(MethodVisitor mv) {
+        mv.visitInsn(DUP2);
+    }
+
+    protected int getBitwiseOperationBytecode(int type) {
+        return bitOp[type];
+    }
+
+    protected int getCompareCode() {
+        return -1;
+    }
+
+    protected ClassNode getNormalOpResultType() {
+        return ClassHelper.int_TYPE;
+    }
+
+    protected int getShiftOperationBytecode(int type) {
+        return shiftOp[type];
+    }
+
+    protected int getStandardOperationBytecode(int type) {
+        return stdOperations[type];
+    }
+
+    protected void removeTwoOperands(MethodVisitor mv) {
+        mv.visitInsn(POP2);
+    }
+
+    protected void writeMinusMinus(MethodVisitor mv) {
+        mv.visitInsn(ICONST_1);
+        mv.visitInsn(ISUB);
+    }
+
+    protected void writePlusPlus(MethodVisitor mv) {
+        mv.visitInsn(ICONST_1);
+        mv.visitInsn(IADD);
+    }
+
+    protected ClassNode getDevisionOpResultType() {
+        return ClassHelper.int_TYPE;
+    }
+
+    @Override
+    protected boolean supportsDivision() {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/classgen/asm/BinaryLongExpressionHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryLongExpressionHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryLongExpressionHelper.java
new file mode 100644
index 0000000..8bfaf98
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryLongExpressionHelper.java
@@ -0,0 +1,144 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.runtime.BytecodeInterface8;
+import org.objectweb.asm.MethodVisitor;
+
+import static org.objectweb.asm.Opcodes.DUP2_X1;
+import static org.objectweb.asm.Opcodes.LADD;
+import static org.objectweb.asm.Opcodes.LAND;
+import static org.objectweb.asm.Opcodes.LCMP;
+import static org.objectweb.asm.Opcodes.LCONST_1;
+import static org.objectweb.asm.Opcodes.LDIV;
+import static org.objectweb.asm.Opcodes.LMUL;
+import static org.objectweb.asm.Opcodes.LOR;
+import static org.objectweb.asm.Opcodes.LREM;
+import static org.objectweb.asm.Opcodes.LSHL;
+import static org.objectweb.asm.Opcodes.LSHR;
+import static org.objectweb.asm.Opcodes.LSUB;
+import static org.objectweb.asm.Opcodes.LUSHR;
+import static org.objectweb.asm.Opcodes.LXOR;
+import static org.objectweb.asm.Opcodes.POP2;
+
+/**
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class BinaryLongExpressionHelper extends BinaryExpressionWriter {
+
+    /**
+     * @since 2.5.0
+     */
+    public BinaryLongExpressionHelper(WriterController controller, MethodCaller arraySet, MethodCaller arrayGet) {
+        super(controller, arraySet, arrayGet);
+    }
+
+    public BinaryLongExpressionHelper(WriterController controller) {
+        this(controller, longArraySet, longArrayGet);
+    }
+
+    protected void doubleTwoOperands(MethodVisitor mv) {
+        /*
+            since there is no DUP4 we have to do this:
+            DUP2_X1
+            POP2
+            DUP2_X1
+            DUP2_X1
+            POP2
+            DUP2_X1          
+         */
+        mv.visitInsn(DUP2_X1);
+        mv.visitInsn(POP2);
+        mv.visitInsn(DUP2_X1);
+        mv.visitInsn(DUP2_X1);
+        mv.visitInsn(POP2);
+        mv.visitInsn(DUP2_X1);
+    }
+
+    protected void removeTwoOperands(MethodVisitor mv) {
+        mv.visitInsn(POP2);
+        mv.visitInsn(POP2);
+    }
+
+    private static final MethodCaller 
+        longArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "lArrayGet"),
+        longArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "lArraySet");
+
+    private static final int[] bitOp = {
+        LOR,            //  BITWISE_OR / PIPE   340
+        LAND,           //  BITWISE_AND         341
+        LXOR,           //  BIWISE_XOR          342
+    };
+
+    protected int getBitwiseOperationBytecode(int type) {
+        return bitOp[type];
+    }
+
+    protected int getCompareCode() {
+        return LCMP;
+    }
+
+    protected ClassNode getNormalOpResultType() {
+        return ClassHelper.long_TYPE;
+    }
+
+    private static final int[] shiftOp = {
+        LSHL,           // LEFT_SHIFT               280
+        LSHR,           // RIGHT_SHIFT              281
+        LUSHR           // RIGHT_SHIFT_UNSIGNED     282
+    };
+    
+    protected int getShiftOperationBytecode(int type) {
+        return shiftOp[type];
+    }
+
+    private static final int[] stdOperations = {
+        LADD,           //  PLUS        200
+        LSUB,           //  MINUS       201
+        LMUL,           //  MULTIPLY    202
+        LDIV,           //  DIV         203
+        LDIV,           //  INTDIV      204
+        LREM,           //  MOD         203
+    };
+    
+    protected int getStandardOperationBytecode(int type) {
+        return stdOperations[type];
+    }
+
+    protected void writeMinusMinus(MethodVisitor mv) {
+        mv.visitInsn(LCONST_1);
+        mv.visitInsn(LSUB);
+    }
+
+    protected void writePlusPlus(MethodVisitor mv) {
+        mv.visitInsn(LCONST_1);
+        mv.visitInsn(LADD);
+    }
+
+    protected ClassNode getDevisionOpResultType() {
+        return ClassHelper.long_TYPE;
+    }
+
+    @Override
+    protected boolean supportsDivision() {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/classgen/asm/BinaryObjectExpressionHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryObjectExpressionHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryObjectExpressionHelper.java
new file mode 100644
index 0000000..31350d5
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryObjectExpressionHelper.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen.asm;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.runtime.BytecodeInterface8;
+import org.objectweb.asm.MethodVisitor;
+
+/**
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class BinaryObjectExpressionHelper extends BinaryExpressionWriter {
+    private static final MethodCaller arrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "objectArrayGet");
+    private static final MethodCaller arraySet = MethodCaller.newStatic(BytecodeInterface8.class, "objectArraySet");
+
+    public BinaryObjectExpressionHelper(WriterController controller) {
+        super(controller, arraySet, arrayGet);
+    }
+    
+    // dummy methods
+    public boolean writePostOrPrefixMethod(int operation, boolean simulate) {
+        if (simulate) return false;
+        throw new GroovyBugError("should not reach here");
+    }
+    
+    public boolean write(int operation, boolean simulate) {
+        if (simulate) return false;
+        throw new GroovyBugError("should not reach here");
+    }
+    
+    protected boolean writeDivision(boolean simulate) {
+        if (simulate) return false;
+        throw new GroovyBugError("should not reach here");
+    }
+
+    protected int getBitwiseOperationBytecode(int type) {
+        return -1;
+    }
+    
+    protected int getCompareCode() {
+        return -1;
+    }
+    
+    protected ClassNode getNormalOpResultType() {
+        return null;
+    }
+    
+    protected ClassNode getDevisionOpResultType() {
+        return null;
+    }
+    
+    protected int getShiftOperationBytecode(int type) {
+        return -1;
+    }
+    
+    protected int getStandardOperationBytecode(int type) {
+        return -1;
+    }
+    
+    protected void removeTwoOperands(MethodVisitor mv) {}
+    protected void writePlusPlus(MethodVisitor mv) {}
+    protected void writeMinusMinus(MethodVisitor mv) {}
+    protected void doubleTwoOperands(MethodVisitor mv) {}
+    
+    @Override
+    protected ClassNode getArrayGetResultType() {
+    	return ClassHelper.OBJECT_TYPE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeDumper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeDumper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeDumper.java
new file mode 100644
index 0000000..935020f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeDumper.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen.asm;
+
+import org.codehaus.groovy.control.BytecodeProcessor;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.util.TraceClassVisitor;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ * An utility class which can be used in test cases to dump generated bytecode.
+ *
+ * @author Cédric Champeau
+ * @since 2.4.0
+ */
+public class BytecodeDumper implements BytecodeProcessor {
+    public static final BytecodeDumper STANDARD_ERR = new BytecodeDumper(new PrintWriter(System.err));
+
+    private final Writer out;
+
+    public BytecodeDumper(final Writer out) {
+        this.out = out;
+    }
+
+    @Override
+    public byte[] processBytecode(final String name, final byte[] original) {
+        PrintWriter pw = out instanceof PrintWriter ? (PrintWriter) out : new PrintWriter(out);
+        TraceClassVisitor visitor = new TraceClassVisitor(pw);
+        ClassReader reader = new ClassReader(original);
+        reader.accept(visitor, 0);
+        return original;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeHelper.java
new file mode 100644
index 0000000..d9eea08
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeHelper.java
@@ -0,0 +1,751 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.decompiled.DecompiledClassNode;
+import org.codehaus.groovy.reflection.ReflectionCache;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * A helper class for bytecode generation with AsmClassGenerator.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author <a href="mailto:b55r@sina.com">Bing Ran</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ */
+public class BytecodeHelper implements Opcodes {
+    
+    private static String DTT_CLASSNAME = BytecodeHelper.getClassInternalName(DefaultTypeTransformation.class.getName());
+
+    public static String getClassInternalName(ClassNode t) {
+        if (t.isPrimaryClassNode() || t instanceof DecompiledClassNode) {
+            if (t.isArray()) return "[L"+getClassInternalName(t.getComponentType())+";";
+            return getClassInternalName(t.getName());
+        }
+        return getClassInternalName(t.getTypeClass());
+    }
+
+    public static String getClassInternalName(Class t) {
+        return org.objectweb.asm.Type.getInternalName(t);
+    }
+
+    /**
+     * @return the ASM internal name of the type
+     */
+    public static String getClassInternalName(String name) {
+        return name.replace('.', '/');
+    }
+
+    public static String getMethodDescriptor(ClassNode returnType, Parameter[] parameters) {
+        StringBuilder buffer = new StringBuilder("(");
+        for (int i = 0; i < parameters.length; i++) {
+            buffer.append(getTypeDescription(parameters[i].getType()));
+        }
+        buffer.append(")");
+        buffer.append(getTypeDescription(returnType));
+        return buffer.toString();
+    }
+
+    /**
+     * Returns a method descriptor for the given {@link org.codehaus.groovy.ast.MethodNode}.
+     *
+     * @param methodNode the method node for which to create the descriptor
+     * @return a method descriptor as defined in section JVMS section 4.3.3
+     */
+    public static String getMethodDescriptor(MethodNode methodNode) {
+        return getMethodDescriptor(methodNode.getReturnType(), methodNode.getParameters());
+    }
+    
+    /**
+     * @return the ASM method type descriptor
+     */
+    public static String getMethodDescriptor(Class returnType, Class[] paramTypes) {
+        // lets avoid class loading
+        StringBuilder buffer = new StringBuilder("(");
+        for (int i = 0; i < paramTypes.length; i++) {
+            buffer.append(getTypeDescription(paramTypes[i]));
+        }
+        buffer.append(")");
+        buffer.append(getTypeDescription(returnType));
+        return buffer.toString();
+    }
+
+    public static String getTypeDescription(Class c) {
+        return org.objectweb.asm.Type.getDescriptor(c);
+    }
+
+    /**
+     * array types are special:
+     * eg.: String[]: classname: [Ljava.lang.String;
+     * Object:   classname: java.lang.Object
+     * int[] :   classname: [I
+     * unlike getTypeDescription '.' is not replaced by '/'.
+     * it seems that makes problems for
+     * the class loading if '.' is replaced by '/'
+     *
+     * @return the ASM type description for class loading
+     */
+    public static String getClassLoadingTypeDescription(ClassNode c) {
+        StringBuilder buf = new StringBuilder();
+        boolean array = false;
+        while (true) {
+            if (c.isArray()) {
+                buf.append('[');
+                c = c.getComponentType();
+                array = true;
+            } else {
+                if (ClassHelper.isPrimitiveType(c)) {
+                    buf.append(getTypeDescription(c));
+                } else {
+                    if (array) buf.append('L');
+                    buf.append(c.getName());
+                    if (array) buf.append(';');
+                }
+                return buf.toString();
+            }
+        }
+    }
+
+    /**
+     * array types are special:
+     * eg.: String[]: classname: [Ljava/lang/String;
+     * int[]: [I
+     *
+     * @return the ASM type description
+     */
+    public static String getTypeDescription(ClassNode c) {
+        return getTypeDescription(c, true);
+    }
+
+    /**
+     * array types are special:
+     * eg.: String[]: classname: [Ljava/lang/String;
+     * int[]: [I
+     *
+     * @return the ASM type description
+     */
+    private static String getTypeDescription(ClassNode c, boolean end) {
+        StringBuilder buf = new StringBuilder();
+        ClassNode d = c;
+        while (true) {
+            if (ClassHelper.isPrimitiveType(d.redirect())) {
+                d = d.redirect();
+                char car;
+                if (d == ClassHelper.int_TYPE) {
+                    car = 'I';
+                } else if (d == ClassHelper.VOID_TYPE) {
+                    car = 'V';
+                } else if (d == ClassHelper.boolean_TYPE) {
+                    car = 'Z';
+                } else if (d == ClassHelper.byte_TYPE) {
+                    car = 'B';
+                } else if (d == ClassHelper.char_TYPE) {
+                    car = 'C';
+                } else if (d == ClassHelper.short_TYPE) {
+                    car = 'S';
+                } else if (d == ClassHelper.double_TYPE) {
+                    car = 'D';
+                } else if (d == ClassHelper.float_TYPE) {
+                    car = 'F';
+                } else /* long */ {
+                    car = 'J';
+                }
+                buf.append(car);
+                return buf.toString();
+            } else if (d.isArray()) {
+                buf.append('[');
+                d = d.getComponentType();
+            } else {
+                buf.append('L');
+                String name = d.getName();
+                int len = name.length();
+                for (int i = 0; i < len; ++i) {
+                    char car = name.charAt(i);
+                    buf.append(car == '.' ? '/' : car);
+                }
+                if (end) buf.append(';');
+                return buf.toString();
+            }
+        }
+    }
+
+    /**
+     * @return an array of ASM internal names of the type
+     */
+    public static String[] getClassInternalNames(ClassNode[] names) {
+        int size = names.length;
+        String[] answer = new String[size];
+        for (int i = 0; i < size; i++) {
+            answer[i] = getClassInternalName(names[i]);
+        }
+        return answer;
+    }
+
+    public static void pushConstant(MethodVisitor mv, int value) {
+        switch (value) {
+            case 0:
+                mv.visitInsn(ICONST_0);
+                break;
+            case 1:
+                mv.visitInsn(ICONST_1);
+                break;
+            case 2:
+                mv.visitInsn(ICONST_2);
+                break;
+            case 3:
+                mv.visitInsn(ICONST_3);
+                break;
+            case 4:
+                mv.visitInsn(ICONST_4);
+                break;
+            case 5:
+                mv.visitInsn(ICONST_5);
+                break;
+            default:
+                if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
+                    mv.visitIntInsn(BIPUSH, value);
+                } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
+                    mv.visitIntInsn(SIPUSH, value);
+                } else {
+                    mv.visitLdcInsn(Integer.valueOf(value));
+                }
+        }
+    }
+    
+    /**
+     * negate a boolean on stack. true->false, false->true
+     */
+    public static void negateBoolean(MethodVisitor mv) {
+        // code to negate the primitive boolean
+        Label endLabel = new Label();
+        Label falseLabel = new Label();
+        mv.visitJumpInsn(IFNE, falseLabel);
+        mv.visitInsn(ICONST_1);
+        mv.visitJumpInsn(GOTO, endLabel);
+        mv.visitLabel(falseLabel);
+        mv.visitInsn(ICONST_0);
+        mv.visitLabel(endLabel);
+    }
+
+    /**
+     * load a message on the stack and remove it right away. Good for put a mark in the generated bytecode for debugging purpose.
+     *
+     * @param msg
+     */
+    /*public void mark(String msg) {
+        mv.visitLdcInsn(msg);
+        mv.visitInsn(POP);
+    }*/
+
+    /**
+     * returns a name that Class.forName() can take. Notably for arrays:
+     * [I, [Ljava.lang.String; etc
+     * Regular object type:  java.lang.String
+     *
+     * @param name
+     */
+    public static String formatNameForClassLoading(String name) {
+        if (name == null) {
+            return "java.lang.Object;";
+        }
+
+        if (name.equals("int")
+                || name.equals("long")
+                || name.equals("short")
+                || name.equals("float")
+                || name.equals("double")
+                || name.equals("byte")
+                || name.equals("char")
+                || name.equals("boolean")
+                || name.equals("void")
+                ) {
+            return name;
+        }
+
+        if (name.startsWith("[")) {
+            return name.replace('/', '.');
+        }
+
+        if (name.startsWith("L")) {
+            name = name.substring(1);
+            if (name.endsWith(";")) {
+                name = name.substring(0, name.length() - 1);
+            }
+            return name.replace('/', '.');
+        }
+
+        String prefix = "";
+        if (name.endsWith("[]")) { // todo need process multi
+            prefix = "[";
+            name = name.substring(0, name.length() - 2);
+            if (name.equals("int")) {
+                return prefix + "I";
+            } else if (name.equals("long")) {
+                return prefix + "J";
+            } else if (name.equals("short")) {
+                return prefix + "S";
+            } else if (name.equals("float")) {
+                return prefix + "F";
+            } else if (name.equals("double")) {
+                return prefix + "D";
+            } else if (name.equals("byte")) {
+                return prefix + "B";
+            } else if (name.equals("char")) {
+                return prefix + "C";
+            } else if (name.equals("boolean")) {
+                return prefix + "Z";
+            } else {
+                return prefix + "L" + name.replace('/', '.') + ";";
+            }
+        }
+        return name.replace('/', '.');
+
+    }
+
+    /*public void dup() {
+        mv.visitInsn(DUP);
+    }*/
+
+    public static void doReturn(MethodVisitor mv, ClassNode returnType) {
+        if (returnType == ClassHelper.double_TYPE) {
+            mv.visitInsn(DRETURN);
+        } else if (returnType == ClassHelper.float_TYPE) {
+            mv.visitInsn(FRETURN);
+        } else if (returnType == ClassHelper.long_TYPE) {
+            mv.visitInsn(LRETURN);
+        } else if (
+                returnType == ClassHelper.boolean_TYPE
+                        || returnType == ClassHelper.char_TYPE
+                        || returnType == ClassHelper.byte_TYPE
+                        || returnType == ClassHelper.int_TYPE
+                        || returnType == ClassHelper.short_TYPE) {
+            //byte,short,boolean,int are all IRETURN
+            mv.visitInsn(IRETURN);
+        } else if (returnType == ClassHelper.VOID_TYPE) {
+            mv.visitInsn(RETURN);
+        } else {
+            mv.visitInsn(ARETURN);
+        }
+
+    }
+
+    private static boolean hasGenerics(Parameter[] param) {
+        if (param.length == 0) return false;
+        for (int i = 0; i < param.length; i++) {
+            ClassNode type = param[i].getType();
+            if (hasGenerics(type)) return true;
+        }
+        return false;
+    }
+
+    private static boolean hasGenerics(ClassNode type) {
+        return type.isArray() ? hasGenerics(type.getComponentType()) : type.getGenericsTypes() != null;
+    }
+
+    public static String getGenericsMethodSignature(MethodNode node) {
+        GenericsType[] generics = node.getGenericsTypes();
+        Parameter[] param = node.getParameters();
+        ClassNode returnType = node.getReturnType();
+
+        if (generics == null && !hasGenerics(param) && !hasGenerics(returnType)) return null;
+
+        StringBuilder ret = new StringBuilder(100);
+        getGenericsTypeSpec(ret, generics);
+
+        GenericsType[] paramTypes = new GenericsType[param.length];
+        for (int i = 0; i < param.length; i++) {
+            ClassNode pType = param[i].getType();
+            if (pType.getGenericsTypes() == null || !pType.isGenericsPlaceHolder()) {
+                paramTypes[i] = new GenericsType(pType);
+            } else {
+                paramTypes[i] = pType.getGenericsTypes()[0];
+            }
+        }
+        addSubTypes(ret, paramTypes, "(", ")");
+        addSubTypes(ret, new GenericsType[]{new GenericsType(returnType)}, "", "");
+        return ret.toString();
+    }
+
+    private static boolean usesGenericsInClassSignature(ClassNode node) {
+        if (!node.isUsingGenerics()) return false;
+        if (hasGenerics(node)) return true;
+        ClassNode sclass = node.getUnresolvedSuperClass(false);
+        if (sclass.isUsingGenerics()) return true;
+        ClassNode[] interfaces = node.getInterfaces();
+        if (interfaces != null) {
+            for (int i = 0; i < interfaces.length; i++) {
+                if (interfaces[i].isUsingGenerics()) return true;
+            }
+        }
+
+        return false;
+    }
+
+    public static String getGenericsSignature(ClassNode node) {
+        if (!usesGenericsInClassSignature(node)) return null;
+        GenericsType[] genericsTypes = node.getGenericsTypes();
+        StringBuilder ret = new StringBuilder(100);
+        getGenericsTypeSpec(ret, genericsTypes);
+        GenericsType extendsPart = new GenericsType(node.getUnresolvedSuperClass(false));
+        writeGenericsBounds(ret, extendsPart, true);
+        ClassNode[] interfaces = node.getInterfaces();
+        for (int i = 0; i < interfaces.length; i++) {
+            GenericsType interfacePart = new GenericsType(interfaces[i]);
+            writeGenericsBounds(ret, interfacePart, false);
+        }
+        return ret.toString();
+    }
+
+    private static void getGenericsTypeSpec(StringBuilder ret, GenericsType[] genericsTypes) {
+        if (genericsTypes == null) return;
+        ret.append('<');
+        for (int i = 0; i < genericsTypes.length; i++) {
+            String name = genericsTypes[i].getName();
+            ret.append(name);
+            ret.append(':');
+            writeGenericsBounds(ret, genericsTypes[i], true);
+        }
+        ret.append('>');
+    }
+
+    public static String getGenericsBounds(ClassNode type) {
+        GenericsType[] genericsTypes = type.getGenericsTypes();
+        if (genericsTypes == null) return null;
+        StringBuilder ret = new StringBuilder(100);
+        if (type.isGenericsPlaceHolder()) {
+            addSubTypes(ret, type.getGenericsTypes(), "", "");
+        } else {
+            GenericsType gt = new GenericsType(type);
+            writeGenericsBounds(ret, gt, false);
+        }
+
+        return ret.toString();
+    }
+
+    private static void writeGenericsBoundType(StringBuilder ret, ClassNode printType, boolean writeInterfaceMarker) {
+        if (writeInterfaceMarker && printType.isInterface()) ret.append(":");
+        if (printType.isGenericsPlaceHolder() && printType.getGenericsTypes()!=null) {
+            ret.append("T");
+            ret.append(printType.getGenericsTypes()[0].getName());
+            ret.append(";");
+        }
+        else {
+            ret.append(getTypeDescription(printType, false));
+            addSubTypes(ret, printType.getGenericsTypes(), "<", ">");
+            if (!ClassHelper.isPrimitiveType(printType)) ret.append(";");
+        }
+    }
+
+    private static void writeGenericsBounds(StringBuilder ret, GenericsType type, boolean writeInterfaceMarker) {
+        if (type.getUpperBounds() != null) {
+            ClassNode[] bounds = type.getUpperBounds();
+            for (int i = 0; i < bounds.length; i++) {
+                writeGenericsBoundType(ret, bounds[i], writeInterfaceMarker);
+            }
+        } else if (type.getLowerBound() != null) {
+            writeGenericsBoundType(ret, type.getLowerBound(), writeInterfaceMarker);
+        } else {
+            writeGenericsBoundType(ret, type.getType(), writeInterfaceMarker);
+        }
+    }
+
+    private static void addSubTypes(StringBuilder ret, GenericsType[] types, String start, String end) {
+        if (types == null) return;
+        ret.append(start);
+        for (int i = 0; i < types.length; i++) {
+            if (types[i].getType().isArray()) {
+                ret.append("[");
+                addSubTypes(ret, new GenericsType[]{new GenericsType(types[i].getType().getComponentType())}, "", "");
+            }
+            else {
+                if (types[i].isPlaceholder()) {
+                    ret.append('T');
+                    String name = types[i].getName();
+                    ret.append(name);
+                    ret.append(';');
+                } else if (types[i].isWildcard()) {
+                    if (types[i].getUpperBounds() != null) {
+                        ret.append('+');
+                        writeGenericsBounds(ret, types[i], false);
+                    } else if (types[i].getLowerBound() != null) {
+                        ret.append('-');
+                        writeGenericsBounds(ret, types[i], false);
+                    } else {
+                        ret.append('*');
+                    }
+                } else {
+                    writeGenericsBounds(ret, types[i], false);
+                }
+            }
+        }
+        ret.append(end);
+    }
+
+    public static void load(MethodVisitor mv, ClassNode type, int idx) {
+        if (type == ClassHelper.double_TYPE) {
+            mv.visitVarInsn(DLOAD, idx);
+        } else if (type == ClassHelper.float_TYPE) {
+            mv.visitVarInsn(FLOAD, idx);
+        } else if (type == ClassHelper.long_TYPE) {
+            mv.visitVarInsn(LLOAD, idx);
+        } else if (
+                type == ClassHelper.boolean_TYPE
+                        || type == ClassHelper.char_TYPE
+                        || type == ClassHelper.byte_TYPE
+                        || type == ClassHelper.int_TYPE
+                        || type == ClassHelper.short_TYPE) {
+            mv.visitVarInsn(ILOAD, idx);
+        } else {
+            mv.visitVarInsn(ALOAD, idx);
+        }
+    }
+    
+
+    public static void doCast(MethodVisitor mv, ClassNode type) {
+        if (type == ClassHelper.OBJECT_TYPE) return;
+        if (ClassHelper.isPrimitiveType(type) && type != ClassHelper.VOID_TYPE) {
+            unbox(mv, type);
+        } else {
+            mv.visitTypeInsn(
+                    CHECKCAST,
+                    type.isArray() ? 
+                            BytecodeHelper.getTypeDescription(type) : 
+                            BytecodeHelper.getClassInternalName(type.getName()));
+        }
+    }
+
+    /**
+     * Given a wrapped number type (Byte, Integer, Short, ...), generates bytecode
+     * to convert it to a primitive number (int, long, double) using calls to
+     * wrapped.[targetType]Value()
+     * @param mv method visitor
+     * @param sourceType the wrapped number type
+     * @param targetType the primitive target type
+     */
+    public static void doCastToPrimitive(MethodVisitor mv, ClassNode sourceType, ClassNode targetType) {
+        mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(sourceType), targetType.getName() + "Value", "()" + BytecodeHelper.getTypeDescription(targetType), false);
+    }
+
+    /**
+     * Given a primitive number type (byte, integer, short, ...), generates bytecode
+     * to convert it to a wrapped number (Integer, Long, Double) using calls to
+     * [WrappedType].valueOf
+     * @param mv method visitor
+     * @param sourceType the primitive number type
+     * @param targetType the wrapped target type
+     */
+    public static void doCastToWrappedType(MethodVisitor mv, ClassNode sourceType, ClassNode targetType) {
+        mv.visitMethodInsn(INVOKESTATIC, getClassInternalName(targetType), "valueOf", "(" + getTypeDescription(sourceType) + ")" + getTypeDescription(targetType), false);
+    }
+
+    public static void doCast(MethodVisitor mv, Class type) {
+        if (type == Object.class) return;
+        if (type.isPrimitive() && type != Void.TYPE) {
+            unbox(mv, type);
+        } else {
+            mv.visitTypeInsn(
+                    CHECKCAST,
+                    type.isArray() ? 
+                            BytecodeHelper.getTypeDescription(type) : 
+                                BytecodeHelper.getClassInternalName(type.getName()));
+        }
+    }
+
+    /**
+     * Generates the bytecode to unbox the current value on the stack
+     */
+    public static void unbox(MethodVisitor mv, Class type) {
+        if (type.isPrimitive() && type != Void.TYPE) {
+            String returnString = "(Ljava/lang/Object;)" + BytecodeHelper.getTypeDescription(type);
+            mv.visitMethodInsn(INVOKESTATIC, DTT_CLASSNAME, type.getName() + "Unbox", returnString, false);
+        }
+    }
+
+    public static void unbox(MethodVisitor mv, ClassNode type) {
+        if (type.isPrimaryClassNode()) return;
+        unbox(mv, type.getTypeClass());
+    }
+
+    /**
+     * box top level operand
+     */
+    @Deprecated
+    public static boolean box(MethodVisitor mv, ClassNode type) {
+        if (type.isPrimaryClassNode()) return false;
+        return box(mv, type.getTypeClass());
+    }
+
+    
+    /**
+     * Generates the bytecode to autobox the current value on the stack
+     */
+    @Deprecated
+    public static boolean box(MethodVisitor mv, Class type) {
+        if (ReflectionCache.getCachedClass(type).isPrimitive && type != void.class) {
+            String returnString = "(" + BytecodeHelper.getTypeDescription(type) + ")Ljava/lang/Object;";
+            mv.visitMethodInsn(INVOKESTATIC, DTT_CLASSNAME, "box", returnString, false);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Visits a class literal. If the type of the classnode is a primitive type,
+     * the generated bytecode will be a GETSTATIC Integer.TYPE.
+     * If the classnode is not a primitive type, we will generate a LDC instruction.
+     */
+    public static void visitClassLiteral(MethodVisitor mv, ClassNode classNode) {
+        if (ClassHelper.isPrimitiveType(classNode)) {
+            mv.visitFieldInsn(
+                    GETSTATIC,
+                    getClassInternalName(ClassHelper.getWrapper(classNode)),
+                    "TYPE",
+                    "Ljava/lang/Class;");
+        } else {
+            mv.visitLdcInsn(org.objectweb.asm.Type.getType(getTypeDescription(classNode)));
+        }
+    }
+
+    /**
+     * Tells if a class node is candidate for class literal bytecode optimization. If so,
+     * bytecode may use LDC instructions instead of static constant Class fields to retrieve
+     * class literals.
+     * @param classNode the classnode for which we want to know if bytecode optimization is possible
+     * @return true if the bytecode can be optimized
+     */
+    public static boolean isClassLiteralPossible(ClassNode classNode) {
+        // the current implementation only checks for public modifier, because Groovy used to allow
+        // handles on classes even if they are package protected and not in the same package.
+        // There are situations where we could make more fine grained checks, but be careful of
+        // potential breakage of existing code.
+        return Modifier.isPublic(classNode.getModifiers());
+    }
+
+    /**
+     * Returns true if the two classes share the same compilation unit.
+     * @param a class a
+     * @param b class b
+     * @return true if both classes share the same compilation unit
+     */
+    public static boolean isSameCompilationUnit(ClassNode a, ClassNode b) {
+        CompileUnit cu1 = a.getCompileUnit();
+        CompileUnit cu2 = b.getCompileUnit();
+        return cu1 !=null && cu2 !=null && cu1==cu2;
+    }
+
+    /**
+     * Computes a hash code for a string. The purpose of this hashcode is to be constant independently of
+     * the JDK being used.
+     * @param str the string for which to compute the hashcode
+     * @return hashcode of the string
+     */
+    public static int hashCode(String str) {
+        final char[] chars = str.toCharArray();
+        int h = 0;
+        for (int i = 0; i < chars.length; i++) {
+            h = 31 * h + chars[i];
+        }
+        return h;
+    }
+
+    /**
+     * Converts a primitive type to boolean.
+     *
+     * @param mv method visitor
+     * @param type primitive type to convert
+     */
+    public static void convertPrimitiveToBoolean(MethodVisitor mv, ClassNode type) {
+        if (type == ClassHelper.boolean_TYPE) {
+            return;
+        }
+        // Special handling is done for floating point types in order to
+        // handle checking for 0 or NaN values.
+        if (type == ClassHelper.double_TYPE) {
+            convertDoubleToBoolean(mv, type);
+            return;
+        } else if (type == ClassHelper.float_TYPE) {
+            convertFloatToBoolean(mv, type);
+            return;
+        }
+        Label trueLabel = new Label();
+        Label falseLabel = new Label();
+        // Convert long to int for IFEQ comparison using LCMP
+        if (type==ClassHelper.long_TYPE) {
+            mv.visitInsn(LCONST_0);
+            mv.visitInsn(LCMP);
+        }
+        // This handles byte, short, char and int
+        mv.visitJumpInsn(IFEQ, falseLabel);
+        mv.visitInsn(ICONST_1);
+        mv.visitJumpInsn(GOTO, trueLabel);
+        mv.visitLabel(falseLabel);
+        mv.visitInsn(ICONST_0);
+        mv.visitLabel(trueLabel);
+    }
+
+    private static void convertDoubleToBoolean(MethodVisitor mv, ClassNode type) {
+        Label trueLabel = new Label();
+        Label falseLabel = new Label();
+        Label falseLabelWithPop = new Label();
+        mv.visitInsn(DUP2); // will need the extra for isNaN call if required
+        mv.visitInsn(DCONST_0);
+        mv.visitInsn(DCMPL);
+        mv.visitJumpInsn(IFEQ, falseLabelWithPop);
+        mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "isNaN", "(D)Z", false);
+        mv.visitJumpInsn(IFNE, falseLabel);
+        mv.visitInsn(ICONST_1);
+        mv.visitJumpInsn(GOTO, trueLabel);
+        mv.visitLabel(falseLabelWithPop);
+        mv.visitInsn(POP2);
+        mv.visitLabel(falseLabel);
+        mv.visitInsn(ICONST_0);
+        mv.visitLabel(trueLabel);
+    }
+
+    private static void convertFloatToBoolean(MethodVisitor mv, ClassNode type) {
+        Label trueLabel = new Label();
+        Label falseLabel = new Label();
+        Label falseLabelWithPop = new Label();
+        mv.visitInsn(DUP); // will need the extra for isNaN call if required
+        mv.visitInsn(FCONST_0);
+        mv.visitInsn(FCMPL);
+        mv.visitJumpInsn(IFEQ, falseLabelWithPop);
+        mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "isNaN", "(F)Z", false);
+        mv.visitJumpInsn(IFNE, falseLabel);
+        mv.visitInsn(ICONST_1);
+        mv.visitJumpInsn(GOTO, trueLabel);
+        mv.visitLabel(falseLabelWithPop);
+        mv.visitInsn(POP);
+        mv.visitLabel(falseLabel);
+        mv.visitInsn(ICONST_0);
+        mv.visitLabel(trueLabel);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeVariable.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeVariable.java b/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeVariable.java
new file mode 100644
index 0000000..1f34bc3
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeVariable.java
@@ -0,0 +1,124 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.objectweb.asm.Label;
+
+/**
+ * Represents compile time variable metadata while compiling a method.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ */
+public class BytecodeVariable {
+    
+    public static final BytecodeVariable THIS_VARIABLE = new BytecodeVariable();
+    public static final BytecodeVariable SUPER_VARIABLE = new BytecodeVariable();
+
+    private final int index;
+    private ClassNode type;
+    private String name;
+    private final int prevCurrent;
+    private boolean holder;
+
+    // br for setting on the LocalVariableTable in the class file
+    // these fields should probably go to jvm Operand class
+    private Label startLabel = null;
+    private Label endLabel = null;
+    private boolean dynamicTyped;
+
+    private BytecodeVariable(){
+        dynamicTyped = true;
+        index=0;
+        holder=false;
+        prevCurrent=0;
+    }
+    
+    public BytecodeVariable(int index, ClassNode type, String name, int prevCurrent) {
+        this.index = index;
+        this.type = type;
+        this.name = name;
+        this.prevCurrent = prevCurrent;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public ClassNode getType() {
+        return type;
+    }
+ 
+    /**
+     * @return the stack index for this variable
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * @return is this local variable shared in other scopes (and so must use a ValueHolder)
+     */
+    public boolean isHolder() {
+        return holder;
+    }
+
+    public void setHolder(boolean holder) {
+        this.holder = holder;
+    }
+    
+    public Label getStartLabel() {
+        return startLabel;
+    }
+
+    public void setStartLabel(Label startLabel) {
+        this.startLabel = startLabel;
+    }
+
+    public Label getEndLabel() {
+        return endLabel;
+    }
+
+    public void setEndLabel(Label endLabel) {
+        this.endLabel = endLabel;
+    }
+
+    public String toString() {
+        return name + "(index=" + index + ",type=" + type + ",holder="+holder+")";
+    }
+
+    public void setType(ClassNode type) {
+        this.type = type;
+        dynamicTyped |= type==ClassHelper.DYNAMIC_TYPE;
+    }
+
+    public void setDynamicTyped(boolean b) {
+        dynamicTyped = b;
+    }
+    
+    public boolean isDynamicTyped() {
+        return dynamicTyped;
+    }
+
+    public int getPrevIndex() {
+        return prevCurrent;
+    }
+}