[jboss-svn-commits] JBL Code SVN: r25763 - in labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule: binding and 4 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Fri Mar 20 06:16:54 EDT 2009


Author: adinn
Date: 2009-03-20 06:16:54 -0400 (Fri, 20 Mar 2009)
New Revision: 25763

Modified:
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Action.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Condition.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Event.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Rule.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/RuleElement.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/binding/Binding.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/compiler/Compiler.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/compiler/StackHeights.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ArithmeticExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ArrayExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/BitExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/BooleanLiteral.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ComparisonExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ConditionalEvalExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/DollarExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/Expression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ExpressionHelper.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/FieldExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/LogicalExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/MethodExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/MinusExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/NotExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/NumericLiteral.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/PlusExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ReturnExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/StaticExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/StringLiteral.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/StringPlusExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ThrowExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/TwiddleExpression.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/Variable.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/helper/InterpretedHelper.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/type/Type.java
Log:
included first cut of rule compilation -- enabled by setting property org.jboss.jbossts.orchestration.compileToBytecode

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Action.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Action.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Action.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -33,8 +33,12 @@
 import org.jboss.jbossts.orchestration.rule.exception.ParseException;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.helper.InterpretedHelper;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 import java.util.List;
 import java.util.ArrayList;
@@ -100,7 +104,36 @@
         return Type.VOID;
     }
 
-    public void interpret(HelperAdapter helper)
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException {
+        int currentStack = currentStackHeights.stackCount;
+        boolean hasActions = false;
+
+        for (Expression expr : action) {
+            hasActions = true;
+            expr.compile(mv, currentStackHeights, maxStackHeights);
+            Type resultType = expr.getType();
+            if (resultType != Type.VOID) {
+                int expected = (resultType.getNBytes() > 4 ? 2 : 1);
+                for (int i = 0; i < expected; i++) {
+                    mv.visitInsn(Opcodes.POP);
+                    currentStackHeights.addStackCount(-1);
+                }
+            }
+        }
+        if (!hasActions) {
+            // don't check or adjust stack heights as we did nothing
+            return;
+        }
+
+        // check original stack height has been restored
+        if (currentStackHeights.stackCount != currentStack) {
+            throw new CompileException("Action.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + currentStack);
+        }
+
+        // each action will have checked whether it needed to increase the maximum stack count so just return
+    }
+
+    public Object interpret(HelperAdapter helper)
             throws ExecuteException
     {
         if (action != null) {
@@ -108,6 +141,8 @@
                 expr.interpret(helper);
             }
         }
+        
+        return null;
     }
 
     public void writeTo(StringWriter stringWriter)

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Condition.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Condition.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Condition.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -32,8 +32,11 @@
 import org.jboss.jbossts.orchestration.rule.exception.ParseException;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.helper.InterpretedHelper;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
+import org.objectweb.asm.MethodVisitor;
 
 import java.io.StringWriter;
 import java.io.StringReader;
@@ -91,7 +94,30 @@
         return Type.Z;
     }
 
-    public boolean interpret(HelperAdapter helper)
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException {
+        int currentStack = currentStackHeights.stackCount;
+        // get the condition to compile itself -- it adds 1 to stack height
+        condition.compile(mv, currentStackHeights, maxStackHeights);
+        // unbox if necessary
+        if (condition.getType() == Type.BOOLEAN) {
+            compileUnbox(Type.BOOLEAN, Type.Z, mv, currentStackHeights, maxStackHeights);
+        }
+
+        // check stack heights
+        if (currentStackHeights.stackCount != currentStack + 1) {
+            throw new CompileException("Condition.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + currentStack);
+        }
+
+        // we needed room for 1 more values on the stack -- make sure we got it
+        int maxStack = maxStackHeights.stackCount;
+        int overflow = (currentStack + 1) - maxStack;
+
+        if (overflow > 0) {
+            maxStackHeights.addStackCount(overflow);
+        }
+    }
+
+    public Object interpret(HelperAdapter helper)
             throws ExecuteException
     {
         Boolean result = (Boolean)condition.interpret(helper);

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Event.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Event.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Event.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -35,8 +35,13 @@
 import org.jboss.jbossts.orchestration.rule.exception.ParseException;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.helper.InterpretedHelper;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
+import org.jboss.jbossts.orchestration.agent.adapter.RuleAdapter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 import java.util.List;
 import java.util.ArrayList;
@@ -90,11 +95,6 @@
         super(rule);
     }
 
-    public boolean compile()
-    {
-        return true;
-    }
-
     public Bindings getBindings()
     {
         return rule.getBindings();
@@ -249,7 +249,7 @@
         }
     }
 
-    public void interpret(HelperAdapter helper)
+    public Object interpret(HelperAdapter helper)
             throws ExecuteException
     {
         Iterator<Binding> iterator = getBindings().iterator();
@@ -257,12 +257,27 @@
         while (iterator.hasNext()) {
             Binding binding = iterator.next();
 
-            if (binding.isVar()) {
-                Object value = binding.getValue().interpret(helper);
-                helper.bindVariable(binding.getName(), value);
-            }
+            binding.interpret(helper);
         }
+        
+        return null;
+    }
 
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        int currentStack = currentStackHeights.stackCount;
+
+        Iterator<Binding> iterator = getBindings().iterator();
+        while (iterator.hasNext()) {
+            Binding binding = iterator.next();
+
+            binding.compile(mv, currentStackHeights, maxStackHeights);
+        }
+
+        // check stack heights
+        if (currentStackHeights.stackCount != currentStack) {
+            throw new CompileException("Event.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + currentStack);
+        }
     }
 
     public void writeTo(StringWriter stringWriter)

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Rule.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Rule.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Rule.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -216,6 +216,10 @@
         return action;
     }
 
+    public String getTriggerClass() {
+        return triggerClass;
+    }
+
     public static Rule create(String name, String targetClass, String targetMethod, Class<?> helperClass, Location targetLocation, String ruleSpec, ClassLoader loader)
             throws ParseException, TypeException, CompileException
     {
@@ -312,7 +316,7 @@
         } else {
             // we need to generate a helper adapter class which either interprets or compiles
 
-            helperImplementationClass = Compiler.getHelperAdapter(helperClass, compileToBytecode);
+            helperImplementationClass = Compiler.getHelperAdapter(this, helperClass, compileToBytecode);
         }
     }
 

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/RuleElement.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/RuleElement.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/RuleElement.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -27,6 +27,12 @@
 import org.jboss.jbossts.orchestration.rule.type.TypeGroup;
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
+import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
+import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 import java.io.StringWriter;
 
@@ -54,6 +60,399 @@
 
     public abstract Type typeCheck(Type expected) throws TypeException;
 
+    public abstract Object interpret(HelperAdapter helper) throws ExecuteException;
+
+    public abstract void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException;
+
+    protected void compileTypeConversion(Type fromType, Type toType, MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights)
+            throws CompileException
+    {
+        // make sure we have some real work to do
+
+        if (fromType.equals(toType)) {
+            return;
+        }
+
+        if (toType.isNumeric()) {
+            // do number conversion
+            compileNumericConversion(fromType, toType, mv, currentStackHeights, maxStackHeights);
+        } else if (toType.isString()) {
+            // do toString conversion
+            compileStringConversion(fromType, toType, mv, currentStackHeights, maxStackHeights);
+        } else if (toType.isBoolean()) {
+            // do toString conversion
+            compileBooleanConversion(fromType, toType, mv, currentStackHeights, maxStackHeights);
+        } else {
+            compileObjectConversion(fromType, toType, mv, currentStackHeights, maxStackHeights);
+        }
+    }
+
+    protected void compileNumericConversion(Type fromType, Type toType, MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights)
+            throws CompileException
+    {
+        // fromType != toType
+        boolean unbox = fromType.isObject();
+        boolean box = toType.isObject();
+
+        if (unbox) {
+            if (box) {
+                Type midType = Type.boxType(toType);
+                compileUnbox(fromType, midType, mv, currentStackHeights, maxStackHeights);
+                compileBox(midType, mv, currentStackHeights, maxStackHeights);
+            }
+            compileUnbox(fromType, toType, mv, currentStackHeights, maxStackHeights);
+        } else if (box) {
+            Type midType = Type.boxType(toType);
+            if (fromType != midType) {
+                compilePrimitiveConversion(fromType, midType, mv, currentStackHeights, maxStackHeights);
+            }
+            compileBox(toType, mv, currentStackHeights, maxStackHeights);
+        } else {
+            compilePrimitiveConversion(fromType, toType, mv, currentStackHeights, maxStackHeights);
+        }
+    }
+
+    /**
+     * compile code to convert a value of a boxed type to a primitive type, possibly not the immediately
+     * related primitive type
+     *
+     * @param fromType
+     * @param toType
+     * @param mv
+     * @param currentStackHeights
+     * @param maxStackHeights
+     * @throws CompileException
+     */
+   protected void compileUnbox(Type fromType, Type toType, MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights)
+            throws CompileException
+    {
+        // we either have a Boolean, a Character or a Number for fromType
+        if (fromType == Type.BOOLEAN) {
+            assert toType == Type.Z;
+            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
+        } else if (fromType == Type.CHARACTER) {
+            // obtain the underlying char then massage it to the correct bit format
+            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
+            compilePrimitiveConversion(Type.C, toType, mv, currentStackHeights, maxStackHeights);
+        } else {
+            // we have a numeric type so call the relevant conversion method
+            if (toType == Type.B) {
+                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Number", "byteValue", "()B");
+            } else if (toType == Type.S){
+                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Number", "shortValue", "()S");
+            } else if (toType == Type.C){
+                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I");
+                // now convert to char, dropping any sign extension
+                mv.visitIntInsn(Opcodes.ISHL, 16);
+                mv.visitIntInsn(Opcodes.LSHR, 16);
+            } else if (toType == Type.I){
+                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I");
+            } else if (toType == Type.J){
+                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Number", "longValue", "()L");
+                currentStackHeights.addStackCount(1);
+                if (currentStackHeights.stackCount > maxStackHeights.stackCount) {
+                    maxStackHeights.stackCount = currentStackHeights.stackCount;
+                }
+            } else if (toType == Type.F){
+                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Number", "floatValue", "()F");
+            } else {
+                assert toType == Type.D;
+                currentStackHeights.addStackCount(1);
+                if (currentStackHeights.stackCount > maxStackHeights.stackCount) {
+                    maxStackHeights.stackCount = currentStackHeights.stackCount;
+                }
+                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Number", "doubleValue", "()D");
+            }
+        }
+    }
+
+    /**
+     * box a value belonging to a primitive type
+     * @param toType
+     * @param mv
+     * @param currentStackHeights
+     * @param maxStackHeights
+     * @throws CompileException
+     */
+    protected void compileBox(Type toType, MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights)
+            throws CompileException
+    {
+        if (toType == Type.BOOLEAN) {
+            // this temporarily adds 2 to the stack height
+            if (currentStackHeights.stackCount + 2 > maxStackHeights.stackCount) {
+                maxStackHeights.stackCount = currentStackHeights.stackCount + 2;
+            }
+            mv.visitTypeInsn(Opcodes.NEW,  "java/lang/Boolean");
+            mv.visitInsn(Opcodes.DUP_X1);
+            mv.visitInsn(Opcodes.SWAP);
+            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Boolean", "<init>", "(Z)V");
+        } else if (toType == Type.BOOLEAN) {
+            // this temporarily adds 2 to the stack height
+            if (currentStackHeights.stackCount + 2 > maxStackHeights.stackCount) {
+                maxStackHeights.stackCount = currentStackHeights.stackCount + 2;
+            }
+            mv.visitTypeInsn(Opcodes.NEW,  "java/lang/Byte");
+            mv.visitInsn(Opcodes.DUP_X1);
+            mv.visitInsn(Opcodes.SWAP);
+            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Byte", "<init>", "(B)V");
+        } else if (toType == Type.SHORT){
+            // this temporarily adds 2 to the stack height
+            if (currentStackHeights.stackCount + 2 > maxStackHeights.stackCount) {
+                maxStackHeights.stackCount = currentStackHeights.stackCount + 2;
+            }
+            mv.visitTypeInsn(Opcodes.NEW,  "java/lang/Short");
+            mv.visitInsn(Opcodes.DUP_X1);
+            mv.visitInsn(Opcodes.SWAP);
+            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Short", "<init>", "(S)V");
+        } else if (toType == Type.CHARACTER){
+            // this temporarily adds 2 to the stack height
+            if (currentStackHeights.stackCount + 2 > maxStackHeights.stackCount) {
+                maxStackHeights.stackCount = currentStackHeights.stackCount + 2;
+            }
+            mv.visitTypeInsn(Opcodes.NEW,  "java/lang/Character");
+            mv.visitInsn(Opcodes.DUP_X1);
+            mv.visitInsn(Opcodes.SWAP);
+            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Character", "<init>", "(C)V");
+        } else if (toType == Type.INTEGER) {
+            // initial stack [i, ...]
+            // this temporarily adds 2 to the stack height
+            if (currentStackHeights.stackCount + 2 > maxStackHeights.stackCount) {
+                maxStackHeights.stackCount = currentStackHeights.stackCount + 2;
+            }
+            mv.visitTypeInsn(Opcodes.NEW,  "java/lang/Integer"); // => [Integer, i, ...]
+            mv.visitInsn(Opcodes.DUP_X1);                        // => [Integer, i, Integer, ...]
+            mv.visitInsn(Opcodes.SWAP);                          // => [i, Integer, Integer, ...]
+            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Integer", "<init>", "(I)V");
+        } else if (toType == Type.LONG) {
+            // initial stack [i, ...]
+            mv.visitInsn(Opcodes.I2L);  // => [l1, l0, ...]
+            // this temporarily adds 4 to the stack height
+            if (currentStackHeights.stackCount + 4 > maxStackHeights.stackCount) {
+                maxStackHeights.stackCount = currentStackHeights.stackCount + 4;
+            }
+            mv.visitTypeInsn(Opcodes.NEW,  "java/lang/Long");   // => [Long, l1, l0, ...]
+            mv.visitInsn(Opcodes.DUP_X2);                       // => [Long, l1, l0, Long, ...]
+            mv.visitInsn(Opcodes.DUP_X2);                       // => [Long, l1, l0, Long Long, ...]
+            mv.visitInsn(Opcodes.POP);                          // => [l1, l0, Long, Long ...]
+            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Long", "<init>", "(J)V"); // => [ Long, ...]
+        } else if (toType == Type.FLOAT) {
+            // initial stack [i, ...]
+            mv.visitInsn(Opcodes.I2F); // => [f, ...]
+            // this temporarily adds 2 to the stack height
+            if (currentStackHeights.stackCount + 2 > maxStackHeights.stackCount) {
+                maxStackHeights.stackCount = currentStackHeights.stackCount + 2;
+            }
+            mv.visitTypeInsn(Opcodes.NEW,  "java/lang/Float"); // => [Float, f, ...]
+            mv.visitInsn(Opcodes.DUP_X1);                      // => [Float, f, Float, ...]
+            mv.visitInsn(Opcodes.SWAP);                        // => [f, Float, Float, ...]
+            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Float", "<init>", "(F)V");
+        } else if (toType == Type.DOUBLE) {
+            // initial stack [i, ...]
+            mv.visitInsn(Opcodes.I2D);  // => [d1, d0, ...]
+            // this temporarily adds 4 to the stack height
+            if (currentStackHeights.stackCount + 4 > maxStackHeights.stackCount) {
+                maxStackHeights.stackCount = currentStackHeights.stackCount + 4;
+            }
+            mv.visitTypeInsn(Opcodes.NEW,  "java/lang/Double");   // => [Double, d1, d0, ...]
+            mv.visitInsn(Opcodes.DUP_X2);                         // => [Double, d1, d0, Double, ...]
+            mv.visitInsn(Opcodes.DUP_X2);                         // => [Double, d1, d0, Double, Double, ...]
+            mv.visitInsn(Opcodes.POP) ;                           // => [d1, d0, Double, Double, ...]
+            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Double", "<init>", "(D)V");
+        }
+    }
+
+    protected void compileStringConversion(Type fromType, Type toType, MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights)
+            throws CompileException
+    {
+        assert toType == Type.STRING;
+        if (fromType.isObject()) {
+            // use the toString method
+            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
+        } else if (fromType == Type.Z) {
+            // use the toString method
+            mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Boolean", "toString", "(Z)Ljava/lang/String;");
+        } else if (fromType == Type.B) {
+            // use the toString method
+            mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Byte", "toString", "(B)Ljava/lang/String;");
+        } else if (fromType == Type.S) {
+            // use the toString method
+            mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Short", "toString", "(S)Ljava/lang/String;");
+        } else if (fromType == Type.C) {
+            // use the toString method
+            mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Character", "toString", "(C)Ljava/lang/String;");
+        } else if (fromType == Type.I) {
+            // use the toString method
+            mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "toString", "(I)Ljava/lang/String;");
+        } else if (fromType == Type.J) {
+            // use the toString method
+            mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Long", "toString", "(L)Ljava/lang/String;");
+            currentStackHeights.addStackCount(-1);
+        } else if (fromType == Type.F) {
+            // use the toString method
+            mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Float", "toString", "(F)Ljava/lang/String;");
+        } else if (fromType == Type.D) {
+            // use the toString method
+            mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Double", "toString", "(D)Ljava/lang/String;");
+            currentStackHeights.addStackCount(-1);
+        }
+    }
+
+    /**
+     * compile code to convert a numeric or character primitive to a numeric or character primitive
+     * @param fromType
+     * @param toType
+     * @param mv
+     * @param currentStackHeights
+     * @param maxStackHeights
+     * @throws CompileException
+     */
+    protected void compilePrimitiveConversion(Type fromType, Type toType, MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights)
+            throws CompileException
+    {
+        if (fromType == Type.B || fromType == Type.S || fromType == Type.I) {
+            if (toType == Type.B) {
+                mv.visitInsn(Opcodes.I2B);
+            } else if (toType == Type.S) {
+                mv.visitInsn(Opcodes.I2S);
+            } else if (toType == Type.C) {
+                mv.visitInsn(Opcodes.I2C);
+            } else if (toType == Type.I) {
+                // nothing to do
+            } else if (toType == Type.J) {
+                mv.visitInsn(Opcodes.I2L);
+                currentStackHeights.addStackCount(1);
+                if (currentStackHeights.stackCount > maxStackHeights.stackCount) {
+                    maxStackHeights.stackCount = currentStackHeights.stackCount;
+                }
+            } else if (toType == Type.F) {
+                mv.visitInsn(Opcodes.I2F);
+            } else if (toType == Type.D) {
+                mv.visitInsn(Opcodes.I2D);
+                currentStackHeights.addStackCount(1);
+                if (currentStackHeights.stackCount > maxStackHeights.stackCount) {
+                    maxStackHeights.stackCount = currentStackHeights.stackCount;
+                }
+            }
+        } else if (fromType == Type.C) {
+            // convert to the relevant numeric size
+            if (toType == Type.B) {
+                mv.visitInsn(Opcodes.I2B);
+            } else if (toType == Type.S) {
+                mv.visitInsn(Opcodes.I2S);
+            } else if (toType == Type.C) {
+                // nothing to do
+            } else if (toType == Type.I) {
+                // nothing to do
+            } else  if (toType == Type.J) {
+                mv.visitInsn(Opcodes.I2L);
+                currentStackHeights.addStackCount(1);
+                if (currentStackHeights.stackCount > maxStackHeights.stackCount) {
+                    maxStackHeights.stackCount = currentStackHeights.stackCount;
+                }
+            } else if (toType == Type.F) {
+                mv.visitInsn(Opcodes.I2F);
+            } else if (toType == Type.D) {
+                mv.visitInsn(Opcodes.I2D);
+                currentStackHeights.addStackCount(1);
+                if (currentStackHeights.stackCount > maxStackHeights.stackCount) {
+                    maxStackHeights.stackCount = currentStackHeights.stackCount;
+                }
+            }
+        } else if (fromType == Type.J) {
+            if (toType == Type.B || toType ==  Type.S || toType == Type.I || toType == Type.C) {
+                mv.visitInsn(Opcodes.L2I);
+                currentStackHeights.addStackCount(-1);
+            } else if (toType == Type.J) {
+                // nothing to do
+            } else if (toType == Type.F) {
+                mv.visitInsn(Opcodes.L2F);
+                currentStackHeights.addStackCount(-1);
+            } else if (toType == Type.D) {
+                mv.visitInsn(Opcodes.L2D);
+            }
+        } else if (fromType == Type.F) {
+            if (toType == Type.B) {
+                mv.visitInsn(Opcodes.F2I);
+                mv.visitInsn(Opcodes.I2B);
+            } else if (toType == Type.S) {
+                mv.visitInsn(Opcodes.F2I);
+                mv.visitInsn(Opcodes.I2S);
+            } else if (toType == Type.C) {
+                mv.visitInsn(Opcodes.F2I);
+                mv.visitInsn(Opcodes.I2C);
+            } else if (toType == Type.I) {
+                mv.visitInsn(Opcodes.F2I);
+            } else if (toType == Type.J) {
+                mv.visitInsn(Opcodes.F2L);
+                currentStackHeights.addStackCount(1);
+                if (currentStackHeights.stackCount > maxStackHeights.stackCount) {
+                    maxStackHeights.stackCount = currentStackHeights.stackCount;
+                }
+            } else if (toType == Type.F) {
+                // nothing to do
+            } else if (toType == Type.D) {
+                mv.visitInsn(Opcodes.F2D);
+                currentStackHeights.addStackCount(1);
+                if (currentStackHeights.stackCount > maxStackHeights.stackCount) {
+                    maxStackHeights.stackCount = currentStackHeights.stackCount;
+                }
+            }
+        } else if (fromType == Type.D) {
+            if (toType == Type.B) {
+                mv.visitInsn(Opcodes.D2I);
+                mv.visitInsn(Opcodes.I2B);
+            } else if (toType == Type.S) {
+                mv.visitInsn(Opcodes.D2I);
+                mv.visitInsn(Opcodes.I2S);
+            } else if (toType == Type.C) {
+                mv.visitInsn(Opcodes.D2I);
+                mv.visitInsn(Opcodes.I2C);
+            } else if (toType == Type.I) {
+                mv.visitInsn(Opcodes.D2I);
+            } else if (toType == Type.J) {
+                mv.visitInsn(Opcodes.D2L);
+            } else if (toType == Type.F) {
+                mv.visitInsn(Opcodes.D2F);
+                currentStackHeights.addStackCount(-1);
+            } else if (toType == Type.D) {
+                // nothing to do
+            }
+        }
+    }
+
+    protected void compileBooleanConversion(Type fromType, Type toType, MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights)
+            throws CompileException
+    {
+        if (toType == Type.Z) {
+            assert fromType == Type.BOOLEAN;
+            compileUnbox(fromType, toType, mv, currentStackHeights, maxStackHeights);
+        } else {
+            assert toType == Type.BOOLEAN;
+            assert fromType == Type.Z;
+            compileBox(toType, mv, currentStackHeights, maxStackHeights);
+        }
+    }
+
+    protected void compileObjectConversion(Type fromType, Type toType, MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights)
+            throws CompileException
+    {
+        // ensure any primitive type is boxed before we go any further
+
+        if (fromType.isPrimitive()) {
+            Type boxType = Type.boxType(fromType);
+            compileBox(boxType, mv, currentStackHeights, maxStackHeights);
+            fromType = boxType;
+        }
+
+        if (toType.isAssignableFrom(fromType)) {
+            // nothing more to do
+        } else {
+            // this happens when we downcast a bound variable from Object to the variable's type
+            assert fromType.isAssignableFrom(toType);
+            mv.visitTypeInsn(Opcodes.CHECKCAST, toType.getInternalName());
+        }
+    }
+
     public String toString()
     {
         StringWriter stringWriter = new StringWriter();

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/binding/Binding.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/binding/Binding.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/binding/Binding.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -26,8 +26,14 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.expression.Expression;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
+import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
 import org.jboss.jbossts.orchestration.rule.RuleElement;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
+import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 import java.io.StringWriter;
 
@@ -84,6 +90,49 @@
         return type;
     }
 
+    public Object interpret(HelperAdapter helper) throws ExecuteException
+    {
+        if (isVar()) {
+            Object result = value.interpret(helper);
+            helper.bindVariable(getName(), result);
+            return result;
+        }
+        return null;
+    }
+
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        if (isVar()) {
+            int currentStack = currentStackHeights.stackCount;
+
+            // push the current helper instance i.e. this -- adds 1 to stack height
+            mv.visitVarInsn(Opcodes.ALOAD, 0);
+            // push the variable name -- adds 1 to stack height
+            mv.visitLdcInsn(name);
+            // increment stack count
+            currentStackHeights.addStackCount(2);
+            // compile the rhs expression for the binding -- adds 1 to stack height
+            value.compile(mv, currentStackHeights, maxStackHeights);
+            // make sure value is boxed if necessary
+            if (type.isPrimitive()) {
+                compileBox(Type.boxType(type), mv, currentStackHeights, maxStackHeights);
+            }
+            // compile a bindVariable call pops 3 from stack height
+            mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.internalName(HelperAdapter.class), "bindVariable", "(Ljava/lang/String;Ljava/lang/Object;)V");
+            currentStackHeights.addStackCount(-3);
+
+            // check the max height was enough for 3 extra values
+
+            // we needed room for 3 more values on the stack -- make sure we got it
+            int maxStack = maxStackHeights.stackCount;
+            int overflow = (currentStack + 3) - maxStack;
+
+            if (overflow > 0) {
+                maxStackHeights.addStackCount(overflow);
+            }
+        }
+    }
+
     public String getName()
     {
         return name;

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/compiler/Compiler.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/compiler/Compiler.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/compiler/Compiler.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -40,62 +40,61 @@
  */
 public class Compiler implements Opcodes
 {
-    public static Class getHelperAdapter(Class helperClass, boolean compileToBytecode) throws CompileException
+    public static Class getHelperAdapter(Rule rule, Class helperClass, boolean compileToBytecode) throws CompileException
     {
-        // for now we cannot compile to bytecode
+        Class adapterClass;
+        // for each rule with the same helper we can use the same interpreted adapter
+        // we have to use a different compiled helper per rule since it encodes the
+        // details of the rule event, condition and action into its execute method
 
-        compileToBytecode = false;
-
-        Class adapterClass;
-        if (compileToBytecode) {
-            adapterClass = compiledAdapterMap.get(helperClass);
+        if (!compileToBytecode) {
+            // try to reuse any existing adaoter
+            adapterClass = interpretedAdapterMap.get(helperClass);
         } else {
-            adapterClass = interpretedAdapterMap.get(helperClass);
+            adapterClass = null;
         }
 
-        if (adapterClass != null) {
-            return adapterClass;
-        }
-        // ok we have to create the adapter class
+        if (adapterClass == null) {
+            // ok we have to create the adapter class
 
-        // n.b. we don't bother synchronizing here -- if another rule is racing to create an adapter
-        // in parallel we don't really care about generating two of them -- we can use whichever
-        // one gets intalled last
+            // n.b. we don't bother synchronizing here -- if another rule is racing to create an adapter
+            // in parallel we don't really care about generating two of them -- we can use whichever
+            // one gets intalled last
 
-        try {
-            String helperName = Type.getInternalName(helperClass);
-            String compiledHelperName;
+            try {
+                String helperName = Type.getInternalName(helperClass);
+                String compiledHelperName;
 
-            if (compileToBytecode) {
-                compiledHelperName = helperName + "_HelperAdapter_Compiled";
-            } else {
-                compiledHelperName = helperName + "_HelperAdapter_Interpreted";
-            }
+                // we put the helper in the 
+                if (compileToBytecode) {
+                    compiledHelperName = helperName + "_HelperAdapter_Compiled_" + nextId();
+                } else {
+                    compiledHelperName = helperName + "_HelperAdapter_Interpreted";
+                }
 
-            byte[] classBytes = compileBytes(helperClass, helperName, compiledHelperName, compileToBytecode);
-            String externalName = compiledHelperName.replaceAll("/", ".");
-            // dump the compiled class bytes if required
-            Transformer.getTheTransformer().maybeDumpClass(externalName, classBytes);
-            // ensure the class is loaded
-            adapterClass = Transformer.getTheTransformer().loadHelperAdapter(helperClass, externalName, classBytes);
-        } catch(CompileException ce) {
-            throw ce;
-        } catch (Throwable th) {
-            if (compileToBytecode) {
-                throw new CompileException("Compiler.createHelperAdapter : exception creating compiled helper adapter for " + helperClass.getName(), th);
-            } else {
-                throw new CompileException("Compiler.createHelperAdapter : exception creating interpreted helper adapter for " + helperClass.getName(), th);
+                byte[] classBytes = compileBytes(rule, helperClass, helperName, compiledHelperName, compileToBytecode);
+                String externalName = compiledHelperName.replaceAll("/", ".");
+                // dump the compiled class bytes if required
+                Transformer.getTheTransformer().maybeDumpClass(externalName, classBytes);
+                // ensure the class is loaded
+                adapterClass = Transformer.getTheTransformer().loadHelperAdapter(helperClass, externalName, classBytes);
+            } catch(CompileException ce) {
+                throw ce;
+            } catch (Throwable th) {
+                if (compileToBytecode) {
+                    throw new CompileException("Compiler.createHelperAdapter : exception creating compiled helper adapter for " + helperClass.getName(), th);
+                } else {
+                    throw new CompileException("Compiler.createHelperAdapter : exception creating interpreted helper adapter for " + helperClass.getName(), th);
+                }
             }
-        }
 
-        // stash for later reuse
+            // if this is an interpreted adapter then stash it for later reuse
 
-        if(compileToBytecode) {
-            compiledAdapterMap.put(helperClass, adapterClass);
-        } else {
-            interpretedAdapterMap.put(helperClass, adapterClass);
+            if(!compileToBytecode) {
+                interpretedAdapterMap.put(helperClass, adapterClass);
+            }
         }
-
+        
         return adapterClass;
     }
 
@@ -108,16 +107,7 @@
      */
     private static HashMap<Class<?>, Class<?>> interpretedAdapterMap = new HashMap<Class<?>, Class<?>>();
 
-    /**
-     * hashmap used to retrieve previously generated compiled adapters
-     *
-     * TODO strictly this should be a weak hash map so we don't hang on to adapters after the helper
-     * has been dropped. but to make that work we probably need to worry about dropping references to
-     * rules too.
-     */
-    private static HashMap<Class<?>, Class<?>> compiledAdapterMap = new HashMap<Class<?>, Class<?>>();
-
-    private static byte[] compileBytes(Class helperClass, String helperName, String compiledHelperName, boolean compileToBytecode) throws Exception
+    private static byte[] compileBytes(Rule rule, Class helperClass, String helperName, String compiledHelperName, boolean compileToBytecode) throws Exception
     {
         ClassWriter cw = new ClassWriter(0);
         FieldVisitor fv;
@@ -401,24 +391,28 @@
         if (compileToBytecode) {
             // we generate a single execute0 method if we want to run compiled and get
             // the event, condiiton and action to insert the relevant bytecode to implement
-            // bind(), test() anf fire()
+            // bind(), test() and fire()
 
-            /*
             StackHeights maxStackHeights = new StackHeights();
+            StackHeights currentStackHeights;
             {
             // create the execute0() method
             //
             // private void execute0()
             mv = cw.visitMethod(ACC_PRIVATE, "execute0", "()V", null, new String[] { "org/jboss/jbossts/orchestration/rule/exception/ExecuteException" });
             mv.visitCode();
+            maxStackHeights.addLocalCount(3); // for this and 2 object args
             // bind();
-            rule.getEvent().createHelperAdapter(mv, compiledHelperName, helperName, maxStackHeights);
+            currentStackHeights = new StackHeights();
+            rule.getEvent().compile(mv, currentStackHeights, maxStackHeights);
             // if (test())
-            rule.getCondition().createHelperAdapter(mv, compiledHelperName, helperName, maxStackHeights);
+            currentStackHeights = new StackHeights();
+            rule.getCondition().compile(mv, currentStackHeights, maxStackHeights);
             Label l0 = new Label();
             mv.visitJumpInsn(IFEQ, l0);
             // then
-            rule.getAction().createHelperAdapter(mv, compiledHelperName, helperName, maxStackHeights);
+            currentStackHeights = new StackHeights();
+            rule.getAction().compile(mv, currentStackHeights, maxStackHeights);
             // fire();
             // end if
             mv.visitLabel(l0);
@@ -428,7 +422,6 @@
             mv.visitMaxs(maxStackHeights.stackCount, maxStackHeights.localCount);
             mv.visitEnd();
             }
-            */
         } else {
             // we generate the following methods if we want to run interpreted
             {
@@ -467,7 +460,7 @@
             mv.visitFieldInsn(GETFIELD, compiledHelperName, "rule", "Lorg/jboss/jbossts/orchestration/rule/Rule;");
             mv.visitMethodInsn(INVOKEVIRTUAL, "org/jboss/jbossts/orchestration/rule/Rule", "getEvent", "()Lorg/jboss/jbossts/orchestration/rule/Event;");
             mv.visitVarInsn(ALOAD, 0);
-            mv.visitMethodInsn(INVOKEVIRTUAL, "org/jboss/jbossts/orchestration/rule/Event", "interpret", "(Lorg/jboss/jbossts/orchestration/rule/helper/HelperAdapter;)V");
+            mv.visitMethodInsn(INVOKEVIRTUAL, "org/jboss/jbossts/orchestration/rule/Event", "interpret", "(Lorg/jboss/jbossts/orchestration/rule/helper/HelperAdapter;)Ljava/lang/Object;");
             mv.visitInsn(RETURN);
             mv.visitMaxs(2, 1);
             mv.visitEnd();
@@ -483,7 +476,10 @@
             mv.visitFieldInsn(GETFIELD, compiledHelperName, "rule", "Lorg/jboss/jbossts/orchestration/rule/Rule;");
             mv.visitMethodInsn(INVOKEVIRTUAL, "org/jboss/jbossts/orchestration/rule/Rule", "getCondition", "()Lorg/jboss/jbossts/orchestration/rule/Condition;");
             mv.visitVarInsn(ALOAD, 0);
-            mv.visitMethodInsn(INVOKEVIRTUAL, "org/jboss/jbossts/orchestration/rule/Condition", "interpret", "(Lorg/jboss/jbossts/orchestration/rule/helper/HelperAdapter;)Z");
+            mv.visitMethodInsn(INVOKEVIRTUAL, "org/jboss/jbossts/orchestration/rule/Condition", "interpret", "(Lorg/jboss/jbossts/orchestration/rule/helper/HelperAdapter;)Ljava/lang/Object;");
+            mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Boolean");
+            // unbox the returned Boolean
+            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
             // return {TOS}
             mv.visitInsn(IRETURN);
             mv.visitMaxs(2, 1);
@@ -500,7 +496,7 @@
             mv.visitFieldInsn(GETFIELD, compiledHelperName, "rule", "Lorg/jboss/jbossts/orchestration/rule/Rule;");
             mv.visitMethodInsn(INVOKEVIRTUAL, "org/jboss/jbossts/orchestration/rule/Rule", "getAction", "()Lorg/jboss/jbossts/orchestration/rule/Action;");
             mv.visitVarInsn(ALOAD, 0);
-            mv.visitMethodInsn(INVOKEVIRTUAL, "org/jboss/jbossts/orchestration/rule/Action", "interpret", "(Lorg/jboss/jbossts/orchestration/rule/helper/HelperAdapter;)V");
+            mv.visitMethodInsn(INVOKEVIRTUAL, "org/jboss/jbossts/orchestration/rule/Action", "interpret", "(Lorg/jboss/jbossts/orchestration/rule/helper/HelperAdapter;)Ljava/lang/Object;");
             // return
             mv.visitInsn(RETURN);
             mv.visitMaxs(2, 1);
@@ -512,4 +508,11 @@
 
         return cw.toByteArray();
     }
+
+    private static int nextId = 0;
+
+    private static synchronized int nextId()
+    {
+        return ++nextId;
+    }
 }

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/compiler/StackHeights.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/compiler/StackHeights.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/compiler/StackHeights.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -37,7 +37,7 @@
     /**
      * number of local variable slots
      */
-    int localCount;
+    public int localCount;
 
     /**
      * create withinitial counts 0

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ArithmeticExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ArithmeticExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ArithmeticExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -26,9 +26,13 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 /**
  * A binary arithmetic operator expression
@@ -253,4 +257,165 @@
             throw new ExecuteException("ArithmeticExpression.interpret : unexpected exception for operation " + token + getPos() + " in rule " + helper.getName(), e);
         }
     }
+
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        int currentStack = currentStackHeights.stackCount;
+        int expectedStack = 0;
+        Expression operand0 = getOperand(0);
+        Expression operand1 = getOperand(1);
+        Type type0 = operand0.getType();
+        Type type1 = operand1.getType();
+        // compile lhs -- it adds 1 or 2 to the stack height
+        operand0.compile(mv, currentStackHeights, maxStackHeights);
+        // do any required type conversion
+        compileTypeConversion(type0, type, mv, currentStackHeights, maxStackHeights);
+        // compile lhs -- it adds 1 or 2 to the stack height
+        currentStackHeights.addStackCount((type0.getNBytes() > 4 ? 2 : 1));
+        // do any required type conversion
+        compileTypeConversion(type1, type, mv, currentStackHeights, maxStackHeights);
+
+        try {
+// n.b. be careful with characters here
+            if (type == type.B || type == type.S || type == type.C || type == type.I) {
+                // TODO we should probably only respect the byte, short and char types for + and -
+                // TODO also need to decide how to handle divide by zero
+
+                expectedStack = 1;
+
+                switch (oper)
+                {
+                    case MUL:
+                        mv.visitInsn(Opcodes.IMUL);
+                        break;
+                    case DIV:
+                        mv.visitInsn(Opcodes.IDIV);
+                        break;
+                    case PLUS:
+                        mv.visitInsn(Opcodes.IADD);
+                        break;
+                    case MINUS:
+                        mv.visitInsn(Opcodes.ISUB);
+                        break;
+                    case MOD:
+                        mv.visitInsn(Opcodes.IREM);
+                        break;
+                    default:
+                        // should never happen
+                        throw new CompileException("ArithmeticExpression.compile : unexpected operator " + oper);
+                }
+                // now coerce back to appropriate type
+                if (type == type.B) {
+                    mv.visitInsn(Opcodes.I2B);
+                } else if (type == type.S) {
+                    mv.visitInsn(Opcodes.I2S);
+                } else if (type == type.C) {
+                    mv.visitInsn(Opcodes.I2C);
+                } // else if (type == type.I) { do nothing }
+                // ok, we popped two bytes but added one
+                currentStackHeights.addStackCount(-1);
+            }  else if (type == type.J) {
+
+                expectedStack = 2;
+
+                switch (oper)
+                {
+                    case MUL:
+                        mv.visitInsn(Opcodes.LMUL);
+                        break;
+                    case DIV:
+                        mv.visitInsn(Opcodes.LDIV);
+                        break;
+                    case PLUS:
+                        mv.visitInsn(Opcodes.LADD);
+                        break;
+                    case MINUS:
+                        mv.visitInsn(Opcodes.LSUB);
+                        break;
+                    case MOD:
+                        mv.visitInsn(Opcodes.LREM);
+                        break;
+                    default:
+                        // should never happen
+                        throw new CompileException("ArithmeticExpression.compile : unexpected operator " + oper);
+                }
+                // ok, we popped four bytes but added two
+                currentStackHeights.addStackCount(-2);
+            }  else if (type == type.F) {
+
+                expectedStack = 1;
+
+                switch (oper)
+                {
+                    case MUL:
+                        mv.visitInsn(Opcodes.FMUL);
+                        break;
+                    case DIV:
+                        mv.visitInsn(Opcodes.FDIV);
+                        break;
+                    case PLUS:
+                        mv.visitInsn(Opcodes.FADD);
+                        break;
+                    case MINUS:
+                        mv.visitInsn(Opcodes.FSUB);
+                        break;
+                    case MOD:
+                        mv.visitInsn(Opcodes.FREM);
+                        break;
+                    default:
+                        // should never happen
+                        throw new CompileException("ArithmeticExpression.compile : unexpected operator " + oper);
+                }
+                // ok, we popped two bytes but added one
+                currentStackHeights.addStackCount(-1);
+            }  else if (type == type.D) {
+
+                expectedStack = 2;
+
+                switch (oper)
+                {
+                    case MUL:
+                        mv.visitInsn(Opcodes.DMUL);
+                        break;
+                    case DIV:
+                        mv.visitInsn(Opcodes.DDIV);
+                        break;
+                    case PLUS:
+                        mv.visitInsn(Opcodes.DADD);
+                        break;
+                    case MINUS:
+                        mv.visitInsn(Opcodes.DSUB);
+                        break;
+                    case MOD:
+                        mv.visitInsn(Opcodes.DREM);
+                        break;
+                    default:
+                        // should never happen
+                        throw new CompileException("ArithmeticExpression.compile : unexpected operator " + oper);
+                }
+                // ok, we popped four bytes but added two
+                currentStackHeights.addStackCount(-2);
+            } else {
+                throw new CompileException("ArithmeticExpression.compile : unexpected result type " + type.getName());
+            }
+        } catch (CompileException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new CompileException("ArithmeticExpression.compile : unexpected exception for operation " + token + getPos() + " in rule " + rule.getName(), e);
+        }
+
+        // check stack heights
+        if (currentStackHeights.stackCount != currentStack + expectedStack) {
+            throw new CompileException("ArithmeticExpression.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + currentStack + expectedStack);
+        }
+
+        // we needed room for 2 * expectedStack extra values on the stack -- make sure we got it
+        int maxStack = maxStackHeights.stackCount;
+        int overflow = (currentStack + (2 * expectedStack)) - maxStack;
+
+        if (overflow > 0) {
+            maxStackHeights.addStackCount(overflow);
+        }
+    }
+
 }

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ArrayExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ArrayExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ArrayExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -26,9 +26,13 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 import java.util.List;
 import java.util.Iterator;
@@ -121,6 +125,75 @@
         }
     }
 
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        Type valueType = arrayRef.getType().getBaseType();
+        int currentStack = currentStackHeights.stackCount;
+        int expected = 0;
+
+        // compile load of array reference -- adds 1 to stack height
+        arrayRef.compile(mv, currentStackHeights, maxStackHeights);
+        // for each index expression compile the expression and the do an array load
+        Iterator<Expression> iterator = idxList.iterator();
+
+        while (iterator.hasNext()) {
+            Expression idxExpr = iterator.next();
+            // compile expression index -- adds 1 to height
+            idxExpr.compile(mv, currentStackHeights, maxStackHeights);
+            // make sure the index is an integer
+            compileTypeConversion(idxExpr.getType(), Type.I, mv, currentStackHeights, maxStackHeights);
+
+            if (valueType.isObject()) {
+                // compile load object - pops 2 and adds 1
+                mv.visitInsn(Opcodes.AALOAD);
+                expected = 1;
+            } else if (valueType == Type.Z || valueType == Type.B) {
+                // compile load byte - pops 2 and adds 1
+                mv.visitInsn(Opcodes.BALOAD);
+                expected = 1;
+            } else if (valueType == Type.S) {
+                // compile load short - pops 2 and adds 1
+                mv.visitInsn(Opcodes.SALOAD);
+                expected = 1;
+            } else if (valueType == Type.C) {
+                // compile load char - pops 2 and adds 1
+                mv.visitInsn(Opcodes.CALOAD);
+                expected = 1;
+            } else if (valueType == Type.I) {
+                // compile load int - pops 2 and adds 1
+                mv.visitInsn(Opcodes.IALOAD);
+                expected = 1;
+            } else if (valueType == Type.J) {
+                // compile load long - pops 2 and adds 2
+                mv.visitInsn(Opcodes.LALOAD);
+                expected = 2;
+            } else if (valueType == Type.F) {
+                // compile load float - pops 2 and adds 1
+                mv.visitInsn(Opcodes.FALOAD);
+                expected = 1;
+            } else if (valueType == Type.D) {
+                // compile load double - pops 2 and adds 2
+                mv.visitInsn(Opcodes.DALOAD);
+                expected = 2;
+            }
+            if (iterator.hasNext()) {
+                assert valueType.isArray();
+                valueType =valueType.getBaseType();
+            }
+        }
+        // the last value for expected is how many bytes extra should be on the stack
+        currentStackHeights.addStackCount(expected);
+
+        // check stack height
+        if (currentStackHeights.stackCount != currentStack + expected) {
+            throw new CompileException("ArrayExpression.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + currentStack + expected);
+        }
+
+        // we needed room for an aray and an index or for a one or two word result
+        // but the recursive evaluations will have made sure the max stack is big enough
+        // so there is no need to update the maximum stack height
+    }
+
     public void writeTo(StringWriter stringWriter) {
         arrayRef.writeTo(stringWriter);
         for (Expression expr : idxList) {

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/BitExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/BitExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/BitExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -26,9 +26,13 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 /**
  * A binary arithmetic operator expression
@@ -176,4 +180,100 @@
             throw new ExecuteException("BitExpression.interpret : unexpected exception for operation " + token + getPos() + " in rule " + helper.getName(), e);
         }
     }
+
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        int currentStack = currentStackHeights.stackCount;
+        int expected = 0;
+        Expression oper0 = getOperand(0);
+        Expression oper1 = getOperand(1);
+        // compile the operands and make sure the result is our target type
+        oper0.compile(mv, currentStackHeights, maxStackHeights);
+        compileTypeConversion(oper0.getType(), type, mv, currentStackHeights, maxStackHeights);
+        oper1.compile(mv, currentStackHeights, maxStackHeights);
+        compileTypeConversion(oper1.getType(), type, mv, currentStackHeights, maxStackHeights);
+
+        if (type == Type.B || type == Type.S || type == Type.C || type == Type.I) {
+            switch (oper)
+            {
+                case BOR:
+                    mv.visitInsn(Opcodes.IOR);
+                    break;
+                case BAND:
+                    mv.visitInsn(Opcodes.IAND);
+                    break;
+                case BXOR:
+                    mv.visitInsn(Opcodes.IXOR);
+                    break;
+            }
+            if (type ==  Type.B) {
+                mv.visitInsn(Opcodes.I2B);
+            } else if (type == Type.S) {
+                mv.visitInsn(Opcodes.I2S);
+            } else if (type == Type.C) {
+                mv.visitInsn(Opcodes.I2C);
+            }
+            expected =  1;
+        } else if (type == Type.J) {
+            switch (oper)
+            {
+                case BOR:
+                    mv.visitInsn(Opcodes.LOR);
+                    break;
+                case BAND:
+                    mv.visitInsn(Opcodes.LAND);
+                    break;
+                case BXOR:
+                    mv.visitInsn(Opcodes.LXOR);
+                    break;
+            }
+            expected =  2;
+        } else if (type == Type.F) {
+            mv.visitInsn(Opcodes.F2L);
+            switch (oper)
+            {
+                case BOR:
+                    mv.visitInsn(Opcodes.LOR);
+                    break;
+                case BAND:
+                    mv.visitInsn(Opcodes.LAND);
+                    break;
+                case BXOR:
+                    mv.visitInsn(Opcodes.LXOR);
+                    break;
+            }
+            expected =  2;
+        } else if (type == Type.D) {
+            mv.visitInsn(Opcodes.D2L);
+            switch (oper)
+            {
+                case BOR:
+                    mv.visitInsn(Opcodes.LOR);
+                    break;
+                case BAND:
+                    mv.visitInsn(Opcodes.LAND);
+                    break;
+                case BXOR:
+                    mv.visitInsn(Opcodes.LXOR);
+                    break;
+            }
+            expected =  2;
+        }
+        // we have either a 1 byte or a 2 byte result
+        // check that the stack height is what we expect
+
+        currentStackHeights.addStackCount(expected);
+        
+        if (currentStackHeights.stackCount != currentStack + expected) {
+            throw new CompileException("BitExpression.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + currentStack + expected);
+        }
+
+        // we needed room for 2 * expected stack values at the highest point
+        int maxStack = maxStackHeights.stackCount;
+        int overflow = (currentStack + (2 * expected)) - maxStack;
+
+        if (overflow > 0) {
+            maxStackHeights.addStackCount(overflow);
+        }
+    }
 }
\ No newline at end of file

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/BooleanLiteral.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/BooleanLiteral.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/BooleanLiteral.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -26,12 +26,18 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 import java.io.StringWriter;
 
+import com.sun.org.apache.bcel.internal.generic.BIPUSH;
+
 /**
  * A binary logical operator expression
  */
@@ -70,6 +76,17 @@
         return value;
     }
 
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException {
+        // load a boolean constant
+        mv.visitLdcInsn(value);
+        
+        // increment stack height and update maximmum if necessary
+        currentStackHeights.addStackCount(1);
+        if (currentStackHeights.stackCount > maxStackHeights.stackCount) {
+            maxStackHeights.stackCount = currentStackHeights.stackCount;
+        }
+    }
+
     public void writeTo(StringWriter stringWriter) {
         if (value) {
             stringWriter.write("TRUE");

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ComparisonExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ComparisonExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ComparisonExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -26,9 +26,15 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Label;
+import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
 
 /**
  * A binary comparison operator expression
@@ -273,6 +279,179 @@
             throw new ExecuteException("ComparisonExpression.interpret : unexpected exception for operation " + token + getPos() + " in rule " + helper.getName(), e);
         }
     }
+
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        Expression oper0 = getOperand(0);
+        Expression oper1 = getOperand(1);
+
+        int currentStack = currentStackHeights.stackCount;
+        int max = 0;
+
+        // evaluate the operands and ensure the reuslt is of the correct type for comparison adds 2
+        oper0.compile(mv, currentStackHeights, maxStackHeights);
+        compileTypeConversion(oper0.getType(), comparisonType, mv, currentStackHeights, maxStackHeights);
+        oper1.compile(mv, currentStackHeights, maxStackHeights);
+        compileTypeConversion(oper1.getType(), comparisonType, mv, currentStackHeights, maxStackHeights);
+
+        // now do the appropriate type of comparison
+        if (comparisonType.isNumeric()) {
+            if (comparisonType == type.B || comparisonType == type.S || comparisonType == type.S || comparisonType == type.I) {
+                Label elsetarget = new Label();
+                Label endtarget = new Label();
+                // we needed to stack two words for the operands
+                max = 2;
+                switch (oper)
+                {
+                    case LT:
+                        mv.visitJumpInsn(Opcodes.IF_ICMPGE, elsetarget);
+                        mv.visitLdcInsn(true); // or should we BIPUSH 1
+                        mv.visitJumpInsn(Opcodes.GOTO, endtarget);
+                        mv.visitLabel(elsetarget);
+                        mv.visitLdcInsn(false);
+                        mv.visitLabel(endtarget);
+                        break;
+                    case LE:
+                        mv.visitJumpInsn(Opcodes.IF_ICMPGT, elsetarget);
+                        mv.visitLdcInsn(true); // or should we BIPUSH 1
+                        mv.visitJumpInsn(Opcodes.GOTO, endtarget);
+                        mv.visitLabel(elsetarget);
+                        mv.visitLdcInsn(false);
+                        mv.visitLabel(endtarget);
+                        break;
+                    case GT:
+                        mv.visitJumpInsn(Opcodes.IF_ICMPLE, elsetarget);
+                        mv.visitLdcInsn(true); // or should we BIPUSH 1
+                        mv.visitJumpInsn(Opcodes.GOTO, endtarget);
+                        mv.visitLabel(elsetarget);
+                        mv.visitLdcInsn(false);
+                        mv.visitLabel(endtarget);
+                        break;
+                    case GE:
+                        mv.visitJumpInsn(Opcodes.IF_ICMPLT, elsetarget);
+                        mv.visitLdcInsn(true); // or should we BIPUSH 1
+                        mv.visitJumpInsn(Opcodes.GOTO, endtarget);
+                        mv.visitLabel(elsetarget);
+                        mv.visitLdcInsn(false);
+                        mv.visitLabel(endtarget);
+                        break;
+                    case EQ:
+                        mv.visitJumpInsn(Opcodes.IF_ICMPNE, elsetarget);
+                        mv.visitLdcInsn(true); // or should we BIPUSH 1
+                        mv.visitJumpInsn(Opcodes.GOTO, endtarget);
+                        mv.visitLabel(elsetarget);
+                        mv.visitLdcInsn(false);
+                        mv.visitLabel(endtarget);
+                        break;
+                    case NE:
+                        mv.visitJumpInsn(Opcodes.IF_ICMPEQ, elsetarget);
+                        mv.visitLdcInsn(true); // or should we BIPUSH 1
+                        mv.visitJumpInsn(Opcodes.GOTO, endtarget);
+                        mv.visitLabel(elsetarget);
+                        mv.visitLdcInsn(false);
+                        mv.visitLabel(endtarget);
+                        break;
+                }
+            } else if (comparisonType == type.J || comparisonType == type.F || comparisonType == type.D || comparable) {
+                if (comparisonType == type.J) {
+                    mv.visitInsn(Opcodes.LCMP);
+                    // we needed to stack four words for the operands
+                    max = 4;
+                } else if (comparisonType == type.F) {
+                    // we needed to stack two words for the operands
+                    max = 2;
+                    mv.visitInsn(Opcodes.FCMPG);
+                } else if (comparisonType == type.D) {
+                    // we needed to stack four words for the operands
+                    max = 4;
+                    mv.visitInsn(Opcodes.DCMPG);
+                } else {
+                    // we needed to stack two words for the operands
+                    max = 2;
+                    // comparable -- call compare to to leave an int
+                    mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/lang/Comparable", "compareTo", "(Ljava/lang/Object;)I");
+                }
+                Label elsetarget = new Label();
+                Label endtarget = new Label();
+                switch (oper)
+                {
+                    case LT:
+                        mv.visitJumpInsn(Opcodes.IFGE, elsetarget);
+                        mv.visitLdcInsn(true); // or should we BIPUSH 1
+                        mv.visitJumpInsn(Opcodes.GOTO, endtarget);
+                        mv.visitLabel(elsetarget);
+                        mv.visitLdcInsn(false);
+                        mv.visitLabel(endtarget);
+                        break;
+                    case LE:
+                        mv.visitJumpInsn(Opcodes.IFGT, elsetarget);
+                        mv.visitLdcInsn(true); // or should we BIPUSH 1
+                        mv.visitJumpInsn(Opcodes.GOTO, endtarget);
+                        mv.visitLabel(elsetarget);
+                        mv.visitLdcInsn(false);
+                        mv.visitLabel(endtarget);
+                        break;
+                    case GT:
+                        mv.visitJumpInsn(Opcodes.IFLE, elsetarget);
+                        mv.visitLdcInsn(true); // or should we BIPUSH 1
+                        mv.visitJumpInsn(Opcodes.GOTO, endtarget);
+                        mv.visitLabel(elsetarget);
+                        mv.visitLdcInsn(false);
+                        mv.visitLabel(endtarget);
+                        break;
+                    case GE:
+                        mv.visitJumpInsn(Opcodes.IFLT, elsetarget);
+                        mv.visitLdcInsn(true); // or should we BIPUSH 1
+                        mv.visitJumpInsn(Opcodes.GOTO, endtarget);
+                        mv.visitLabel(elsetarget);
+                        mv.visitLdcInsn(false);
+                        mv.visitLabel(endtarget);
+                        break;
+                    case EQ:
+                        mv.visitJumpInsn(Opcodes.IFNE, elsetarget);
+                        mv.visitLdcInsn(true); // or should we BIPUSH 1
+                        mv.visitJumpInsn(Opcodes.GOTO, endtarget);
+                        mv.visitLabel(elsetarget);
+                        mv.visitLdcInsn(false);
+                        mv.visitLabel(endtarget);
+                        break;
+                    case NE:
+                        mv.visitJumpInsn(Opcodes.IFEQ, elsetarget);
+                        mv.visitLdcInsn(true); // or should we BIPUSH 1
+                        mv.visitJumpInsn(Opcodes.GOTO, endtarget);
+                        mv.visitLabel(elsetarget);
+                        mv.visitLdcInsn(false);
+                        mv.visitLabel(endtarget);
+                        break;
+                }
+            }
+        } else {
+            // we needed to stack two words for the operands
+            max = 2;
+            Label elsetarget = new Label();
+            Label endtarget = new Label();
+            if (oper == EQ) {
+                mv.visitJumpInsn(Opcodes.IF_ACMPNE, elsetarget);
+                mv.visitLdcInsn(true); // or should we BIPUSH 1
+                mv.visitJumpInsn(Opcodes.GOTO, endtarget);
+                mv.visitLabel(elsetarget);
+                mv.visitLdcInsn(false);
+                mv.visitLabel(endtarget);
+            } else {
+                mv.visitJumpInsn(Opcodes.IF_ACMPEQ, elsetarget);
+                mv.visitLdcInsn(true); // or should we BIPUSH 1
+                mv.visitJumpInsn(Opcodes.GOTO, endtarget);
+                mv.visitLabel(elsetarget);
+                mv.visitLdcInsn(false);
+                mv.visitLabel(endtarget);
+            }
+        }
+        // we add a single boolean to the stack
+        currentStackHeights.addStackCount(1);
+        // no need to check the max heights as we stacked one or two words per operand and
+        // the compile and compileConvert calls will have already bumped the maximum stack
+    }
+
     private Type comparisonType;
     private boolean comparable;
 }
\ No newline at end of file

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ConditionalEvalExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ConditionalEvalExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ConditionalEvalExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -26,9 +26,14 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
 
 /**
  * expression representing a ternary conditional evaluation (cond ? if_expr : else_expr)
@@ -75,4 +80,46 @@
             return getOperand(2).interpret(helper);
         }
     }
+
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        Expression oper0 = getOperand(0);
+        Expression oper1 = getOperand(1);
+        Expression oper2 = getOperand(2);
+
+        int currentStack = currentStackHeights.stackCount;
+        int expected = (type.getNBytes() > 4 ? 2 : 1);
+
+        // compile the first operand to a boolean and ensure it is primitive -- adds 1 to stack
+        oper0.compile(mv, currentStackHeights, maxStackHeights);
+        if (oper0.getType() == Type.BOOLEAN) {
+            compileBooleanConversion(Type.BOOLEAN, Type.Z, mv, currentStackHeights, maxStackHeights);
+        }
+        // plant the test -- consumes 1 word
+        Label elseLabel = new Label();
+        Label endLabel = new Label();
+        mv.visitJumpInsn(Opcodes.IFEQ, elseLabel);
+        currentStackHeights.addStackCount(-1);
+        // compile the if branch
+        oper1.compile(mv, currentStackHeights, maxStackHeights);
+        // make sure we type convert to our result type so that either branch stacks the same thing
+        compileTypeConversion(oper1.getType(), type,  mv, currentStackHeights, maxStackHeights);
+        // plant a goto skipping over the else expression
+        mv.visitJumpInsn(Opcodes.GOTO, endLabel);
+        // else starts here
+        mv.visitLabel(elseLabel);
+        // compile the else branch
+        oper2.compile(mv, currentStackHeights, maxStackHeights);
+        // make sure we type convert to our result type so that either branch stacks the same thing
+        compileTypeConversion(oper2.getType(), type,  mv, currentStackHeights, maxStackHeights);
+        // the end is nigh
+        mv.visitLabel(endLabel);
+
+        // check the stack height is what we expect, either 1 or 2 words depending upon the result type
+        if (currentStackHeights.stackCount != currentStack + expected) {
+            throw new CompileException("ConditionalEvalExpression.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + currentStack + expected);
+        }
+        // no need to check max stack height as teh left and right expressions will have exceeded anything
+        // we stacked inside this call
+    }
 }

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/DollarExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/DollarExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/DollarExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -27,9 +27,13 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 import java.io.StringWriter;
 
@@ -108,6 +112,45 @@
         return helper.getBinding(name);
     }
 
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        int currentStack = currentStackHeights.stackCount;
+
+        if (index == -1) {
+            // reference to the current helper so just stack this
+            mv.visitVarInsn(Opcodes.ALOAD, 0);
+            currentStackHeights.addStackCount(1);
+            // make sure we have room for this
+            int overflow = (currentStack + 1 - maxStackHeights.stackCount);
+            if (overflow > 0) {
+                maxStackHeights.addStackCount(overflow);
+            }
+        } else {
+            // stack the current helper
+            // stack the name for the variable
+            // call the getBinding method
+            mv.visitVarInsn(Opcodes.ALOAD, 0);
+            mv.visitLdcInsn(name);
+            mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.internalName(HelperAdapter.class), "getBinding", "(Ljava/lang/String;)Ljava/lang/Object;");
+            // ok, we added 2 to the stack and then popped them leaving 1
+            currentStackHeights.addStackCount(1);
+            // perform any necessary type conversion
+            if (type.isPrimitive()) {
+                // cast down to the boxed type then do an unbox
+                compileObjectConversion(Type.OBJECT, Type.boxType(type), mv, currentStackHeights, maxStackHeights);
+                compileUnbox(Type.OBJECT, type,  mv, currentStackHeights, maxStackHeights);
+            } else {
+                // cast down to the required type
+                compileObjectConversion(Type.OBJECT, type, mv, currentStackHeights, maxStackHeights);
+            }
+            // make sure we have room for 2 working slots
+            int overflow = (currentStack + 2 - maxStackHeights.stackCount);
+            if (overflow > 0) {
+                maxStackHeights.addStackCount(overflow);
+            }
+        }
+    }
+
     public void writeTo(StringWriter stringWriter) {
         stringWriter.write("$" + name);
     }

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/Expression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/Expression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/Expression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -27,9 +27,13 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
 import org.jboss.jbossts.orchestration.rule.RuleElement;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 import java.io.StringWriter;
 

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ExpressionHelper.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ExpressionHelper.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ExpressionHelper.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -139,12 +139,12 @@
             break;
             case INTEGER_LITERAL:
             {
-                expr = new NumericLiteral(rule, Type.INTEGER, exprTree);
+                expr = new NumericLiteral(rule, Type.I, exprTree);
             }
             break;
             case FLOAT_LITERAL:
             {
-                expr = new NumericLiteral(rule, Type.FLOAT, exprTree);
+                expr = new NumericLiteral(rule, Type.F, exprTree);
             }
             break;
             case STRING_LITERAL:

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/FieldExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/FieldExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/FieldExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -28,9 +28,13 @@
 import org.jboss.jbossts.orchestration.rule.type.TypeGroup;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 import java.io.StringWriter;
 import java.lang.reflect.Field;
@@ -181,6 +185,29 @@
         }
     }
 
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        int currentStack = currentStackHeights.stackCount;
+        int expected = (type.getNBytes() > 4 ? 2 : 1);
+
+        // compile the owner expression and then ensure it is typed correctly
+        owner.compile(mv, currentStackHeights, maxStackHeights);
+        compileTypeConversion(owner.getType(), type, mv, currentStackHeights, maxStackHeights);
+        if (!indirectStatic) {
+            // compile a field access
+            mv.visitFieldInsn(Opcodes.GETFIELD, field.getDeclaringClass().getName(), field.getName(), field.getType().getName());
+        }
+        // check the stack height is ok
+        if (currentStackHeights.stackCount != currentStack + expected) {
+            throw new CompileException("FieldExpression.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + currentStack + expected);
+        }
+        // make sure we have room for the field value if it is 2 words
+        int overflow = (currentStack + expected) - maxStackHeights.stackCount;
+        if (overflow > 0) {
+            maxStackHeights.addStackCount(overflow);
+        }
+    }
+
     public String getPath(int len)
     {
         StringBuffer buffer = new StringBuffer();

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/LogicalExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/LogicalExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/LogicalExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -26,9 +26,14 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
 
 /**
  * A binary logical operator expression
@@ -60,4 +65,48 @@
             return (value || (Boolean)getOperand(1).interpret(helper));
         }
     }
+
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        Expression oper0 = getOperand(0);
+        Expression oper1 = getOperand(1);
+
+        int currentStack = currentStackHeights.stackCount;
+
+        // compile the first expression and make sure it is a boolean -- adds 1 to stack height
+        oper0.compile(mv, currentStackHeights, maxStackHeights);
+        if (oper0.getType() == Type.BOOLEAN) {
+            compileBooleanConversion(Type.BOOLEAN, type.Z, mv, currentStackHeights, maxStackHeights);
+        }
+        // plant a test and branch
+        Label nextLabel = new Label();
+        Label endLabel = new Label();
+        if (oper == AND) {
+            // only try next if we got true here
+            mv.visitJumpInsn(Opcodes.IFNE, nextLabel);
+            // ok, the first branch was false so stack a false for the result and skip to the end
+            mv.visitLdcInsn(false);
+            mv.visitJumpInsn(Opcodes.GOTO, endLabel);
+        } else {
+            // only try next if we got false here
+            mv.visitJumpInsn(Opcodes.IFEQ, nextLabel);
+            // ok, the first branch was true so stack a true for the result and skip to the end
+            mv.visitLdcInsn(true);
+            mv.visitJumpInsn(Opcodes.GOTO, endLabel);
+        }
+        // the else branch -- adds 1 to stack height
+        mv.visitLabel(nextLabel);
+        oper1.compile(mv, currentStackHeights, maxStackHeights);
+        if (oper0.getType() == Type.BOOLEAN) {
+            compileBooleanConversion(Type.BOOLEAN, type.Z, mv, currentStackHeights, maxStackHeights);
+        }
+        // the final result is the result of the second oper which is on the stack already
+        // This is the end, my beau-tiful friend
+        mv.visitLabel(endLabel);
+        // check stack height
+        if (currentStackHeights.stackCount != currentStack + 1) {
+            throw new CompileException("LogicalExpression.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + currentStack + 1);
+        }
+        // no need to check max stack height as recursive calls will have added at least 1 
+    }
 }
\ No newline at end of file

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/MethodExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/MethodExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/MethodExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -28,9 +28,14 @@
 import org.jboss.jbossts.orchestration.rule.binding.Binding;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
 import java.util.List;
 import java.util.Iterator;
 import java.util.ArrayList;
@@ -49,6 +54,7 @@
         this.recipient = recipient;
         this.arguments = arguments;
         this.argumentTypes = null;
+        this.paramTypes = null;
         this.rootType = null;
         this.pathList = pathList;
     }
@@ -148,7 +154,6 @@
         
         if (recipient == null) {
             if (rootType == null) {
-                //Type ruleType = typeGroup.create("org.jboss.jbossts.orchestration.rule.helper.Helper");
                 Type ruleType = typeGroup.create(rule.getHelperClass().getCanonicalName());
                 recipient = new DollarExpression(rule, ruleType, token, -1);
 
@@ -183,7 +188,7 @@
         }
 
         argumentTypes = new ArrayList<Type>();
-        
+
         // check each argument in turn -- if all candidates have the same argument type then
         // use that as the type to check against
         for (int i = 0; i < arguments.size() ; i++) {
@@ -221,6 +226,16 @@
 
         method = candidates.get(0);
 
+        // now go back and identify the parameter types
+
+        this. paramTypes = new ArrayList<Type>();
+        Class<?>[] paramClasses = method.getParameterTypes();
+
+        for (int i = 0; i < arguments.size(); i++) {
+            Class<?> paramClass = paramClasses[i];
+            paramTypes.add(typeGroup.ensureType(paramClass));
+        }
+
         type = typeGroup.ensureType(method.getReturnType());
 
         if (Type.dereference(expected).isDefined() && !expected.isAssignableFrom(type)) {
@@ -254,6 +269,73 @@
         }
     }
 
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        int currentStack = currentStackHeights.stackCount;
+        int extraParams = 0; // space used by stacked args after conversion
+        int expected = 0;
+        if (recipient != null) {
+            // compile code for recipient
+            recipient.compile(mv, currentStackHeights, maxStackHeights);
+
+            extraParams += 1;
+        }
+
+        int argCount = arguments.size();
+
+        for (int i = 0; i < argCount; i++) {
+            Expression argument = arguments.get(i);
+            Type argType = argumentTypes.get(i);
+            Type paramType = paramTypes.get(i);
+            // compile code to stack argument and type convert if necessary
+            argument.compile(mv, currentStackHeights, maxStackHeights);
+            compileTypeConversion(argType, paramType, mv, currentStackHeights, maxStackHeights);
+            // allow for stacked paramType value
+            extraParams += (paramType.getNBytes() > 4 ? 2 : 1);
+        }
+
+        String ownerName = Type.internalName(method.getDeclaringClass());
+
+        // ok, now just call the method -- removes extraParams words
+        if (recipient == null) {
+            mv.visitMethodInsn(Opcodes.INVOKESTATIC, ownerName, method.getName(), getDescriptor());
+        } else if (recipient.getClass().isInterface()) {
+            mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, ownerName, method.getName(), getDescriptor());
+        } else {
+            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, ownerName, method.getName(), getDescriptor());
+        }
+        // no need for type conversion as return type was derived from method
+        if (type.getNBytes() > 4) {
+            expected = 2;
+        } else {
+            expected = 1;
+        }
+
+        // decrement the stack height to account for stacked param values (removed) and return value (added)
+        currentStackHeights.addStackCount(expected - extraParams);
+
+        // ensure we have only increased the stack by the return value size
+        if (currentStackHeights.stackCount != currentStack + expected) {
+            throw new CompileException("MethodExpression.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + (currentStack + expected));
+        }
+
+        // no need to update max stack since compiling the  recipient or arguments will
+        // have done so (and there will be no change if there was no such compile call)
+    }
+
+    private String getDescriptor()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("(");
+        int nParams = paramTypes.size();
+        for (int i = 0; i < nParams; i++) {
+            buffer.append(paramTypes.get(i).getInternalName(true));
+        }
+        buffer.append(")");
+        buffer.append(type.getInternalName(true));
+        return buffer.toString();
+    }
+    
     public Class getCandidateArgClass(List<Method> candidates, int argIdx)
     {
         Class argClazz = null;
@@ -330,6 +412,7 @@
     private String name;
     private List<Expression> arguments;
     private List<Type> argumentTypes;
+    private List<Type> paramTypes;
     private Expression recipient;
     private Type rootType;
     private Method method;

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/MinusExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/MinusExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/MinusExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -26,9 +26,13 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 /**
  */
@@ -73,4 +77,45 @@
             throw new ExecuteException("MinusExpression.typeCheck() : unexpected exception : " + token.getText() + getPos(), e);
         }
     }
+
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        Expression oper = getOperand(0);
+        Type operType = oper.getType();
+
+        int currentStack = currentStackHeights.stackCount;
+        int expected = 0;
+
+        // compile code to execute the value then negate it
+        oper.compile(mv, currentStackHeights, maxStackHeights);
+        compileTypeConversion(operType, type, mv, currentStackHeights, maxStackHeights);
+
+        // ok, now negate the value
+        if (type == Type.B || type == Type.S || type == Type.I) {
+            mv.visitInsn(Opcodes.INEG);
+            expected = 1;
+        } else if (type == Type.J) {
+            mv.visitInsn(Opcodes.LNEG);
+            expected = 2;
+        } else if (type == Type.F) {
+            mv.visitInsn(Opcodes.FNEG);
+            expected = 1;
+        } else if (type == Type.D) {
+            mv.visitInsn(Opcodes.DNEG);
+            expected = 2;
+        }
+
+        // check stack height
+        if (currentStackHeights.stackCount != currentStack + expected) {
+            throw new CompileException("MinusExpression.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + currentStack + expected);
+        }
+
+        // ensure we have room for any values we stacked
+
+        int overflow = (currentStack + expected) - maxStackHeights.stackCount;
+
+        if (overflow > 0) {
+            maxStackHeights.addStackCount(overflow);
+        }
+    }
 }
\ No newline at end of file

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/NotExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/NotExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/NotExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -26,9 +26,13 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 /**
  */
@@ -52,4 +56,39 @@
         Boolean result = (Boolean) getOperand(0).interpret(helper);
         return !result;
     }
+
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        Expression oper = getOperand(0);
+        Type operType = oper.getType();
+
+        int currentStack = currentStackHeights.stackCount;
+        int expected = 0;
+
+        // compile code to execute the operand -- adds 1
+        oper.compile(mv, currentStackHeights, maxStackHeights);
+        compileTypeConversion(operType, type, mv, currentStackHeights, maxStackHeights);
+
+        // the boolean expression will leave 0 or 1 on the stack so we can negate negate this to get
+        // 0 or -1 and then add 1 to get 1 or 0
+
+        mv.visitInsn(Opcodes.INEG);
+        // adds 1
+        mv.visitInsn(Opcodes.ICONST_1);
+        mv.visitInsn(Opcodes.IADD);
+
+        // check stack height
+        if (currentStackHeights.stackCount != currentStack + expected) {
+            throw new CompileException("NotExpression.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + currentStack + expected);
+        }
+
+        // ensure we have room for the two values we stacked
+
+        int overflow = (currentStack + 2) - maxStackHeights.stackCount;
+
+        if (overflow > 0) {
+            maxStackHeights.addStackCount(overflow);
+        }
+
+    }
 }
\ No newline at end of file

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/NumericLiteral.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/NumericLiteral.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/NumericLiteral.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -26,9 +26,13 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 import java.io.StringWriter;
 
@@ -40,7 +44,7 @@
     public NumericLiteral(Rule rule, Type type, ParseNode token) {
         super(rule, type, token);
 
-        this.value = token.getChild(0);
+        this.value = (Number)token.getChild(0);
     }
 
     /**
@@ -67,9 +71,52 @@
         return value;
     }
 
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        if (type == Type.I) {
+            int val = value.intValue();
+            // compile code to stack int value
+            if (val >= -1 && val <= 5) {
+                // we can use an iconst instruction
+                mv.visitInsn(Opcodes.ICONST_0 + val);
+            } else {
+                // we have to add an integer constant to the constants pool
+                mv.visitLdcInsn(value);
+            }
+            // we have only added 1 to the stack height
+
+            currentStackHeights.addStackCount(1);
+            if (currentStackHeights.stackCount > maxStackHeights.stackCount) {
+                maxStackHeights.stackCount = currentStackHeights.stackCount;
+            }
+        } else { // type = type.F
+            float val = value.floatValue();
+            if (val == 0.0) {
+                // we can use an fconst instruction
+                mv.visitInsn(Opcodes.FCONST_0);
+            } else if (val == 1.0) {
+                    // we can use an fconst instruction
+                    mv.visitInsn(Opcodes.FCONST_1);
+            } else if (val == 2.0) {
+                    // we can use an fconst instruction
+                    mv.visitInsn(Opcodes.FCONST_2);
+            } else {
+                // we have to add a float constant to the constants pool
+                mv.visitLdcInsn(value);
+            }
+
+            // we have only added 1 to the stack height
+
+            currentStackHeights.addStackCount(1);
+            if (currentStackHeights.stackCount > maxStackHeights.stackCount) {
+                maxStackHeights.stackCount = currentStackHeights.stackCount;
+            }
+        }
+    }
+
     public void writeTo(StringWriter stringWriter) {
         stringWriter.write(value.toString());
     }
 
-    private Object value;
+    private Number value;
 }

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/PlusExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/PlusExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/PlusExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -26,9 +26,13 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 /**
  * A plus operator expression which handles the case where we do not know the type of the first
@@ -105,4 +109,70 @@
             }
         }
     }
+
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        Expression oper0 = getOperand(0);
+        Expression oper1 = getOperand(1);
+
+        int currentStack = currentStackHeights.stackCount;
+        int expected = 0;
+
+        // compile and type convert each operand -- adds 2 or 4 depending upon type
+        oper0.compile(mv, currentStackHeights, maxStackHeights);
+        compileTypeConversion(oper0.getType(), type, mv, currentStackHeights, maxStackHeights);
+        oper1.compile(mv, currentStackHeights, maxStackHeights);
+        compileTypeConversion(oper1.getType(), type, mv, currentStackHeights, maxStackHeights);
+
+        if (type == Type.S) {
+            // ok, we could optimize this for the case where the left or right operand is a String plus expression
+            // by employing a StringBuffer but for now we will just evaluate the left and right operand and
+            // then call concat to join them
+            // add two strings leaving one string
+            expected = 1;
+            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "concat", "(Ljava/lang/String;)Ljava/lang/String;");
+        } else if (type == Type.B) {
+            // add two bytes leaving one byte
+            expected = 1;
+            mv.visitInsn(Opcodes.IADD);
+            mv.visitInsn(Opcodes.I2B);
+        } else if (type == Type.S ) {
+            // add two shorts leaving one short
+            expected = 1;
+            mv.visitInsn(Opcodes.IADD);
+            mv.visitInsn(Opcodes.I2S);
+        } else if (type == Type.C) {
+            // add two chars leaving one char
+            expected = 1;
+            mv.visitInsn(Opcodes.IADD);
+            mv.visitInsn(Opcodes.I2C);
+        } else if (type == Type.I) {
+            // add two ints leaving one int
+            expected = 1;
+            mv.visitInsn(Opcodes.IADD);
+        } else if (type == Type.J) {
+            // add two longs leaving one long
+            expected = 1;
+            mv.visitInsn(Opcodes.LADD);
+        } else if (type == Type.F) {
+            // add two floats leaving one float
+            expected = 1;
+            mv.visitInsn(Opcodes.FADD);
+        } else if (type == Type.D) {
+            // add two doubles leaving one double
+            expected = 1;
+            mv.visitInsn(Opcodes.FADD);
+        }
+
+        if (currentStackHeights.stackCount != currentStack + expected) {
+            throw new CompileException("PlusExpression.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + currentStack + expected);
+        }
+
+        // we need room for 2 * expected words at our maximum
+
+        int overflow = (currentStack + 2 * expected) - maxStackHeights.stackCount;
+        if (overflow > 0) {
+            maxStackHeights.addStackCount(overflow);
+        }
+    }
 }
\ No newline at end of file

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ReturnExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ReturnExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ReturnExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -28,9 +28,13 @@
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
 import org.jboss.jbossts.orchestration.rule.exception.EarlyReturnException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 import java.io.StringWriter;
 
@@ -45,7 +49,7 @@
 
     public ReturnExpression(Rule rule, ParseNode token, Expression returnValue)
     {
-        // the trigger method may return any old tyep but the return expression can only occur
+        // the trigger method may return any old type but the return expression can only occur
         // at the top level in a rule action seuqence so it is actually a VOID expression
 
         super(rule, Type.VOID, token);
@@ -118,6 +122,54 @@
         }
     }
 
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        Type returnType = returnValue.getType();
+        int currentStack = currentStackHeights.stackCount;
+        int expected = 1;
+        int extraSlots = 3;
+
+        // ok, we need to create the EarlyReturnException instance and then
+        // initialise it using the appropriate return value or null if no
+        // return value is needed. strictly we should maybe delay the
+        // new until after computing the return expression so we avoid a new
+        // if the expression throws an error. but that means we end up doing
+        // stack manipulations so lets do it the easy way.
+
+        // create am EarlyReturnException -- adds 1 to stack
+        String exceptionClassName = Type.internalName(EarlyReturnException.class);
+        mv.visitTypeInsn(Opcodes.NEW, exceptionClassName);
+        // stack a string constant to initialise the exception with -- adds 1 to stack
+        mv.visitLdcInsn("return from " + rule.getName());
+        // stack any required return value or null -- adds 1 to stack but may use 2 slots
+        if (returnValue != null) {
+            returnValue.compile(mv, currentStackHeights, maxStackHeights);
+            if (returnType.isPrimitive()) {
+                // we need an object not a primitive
+                compileBox(returnType, mv, currentStackHeights, maxStackHeights);
+                // if the intermediate value used 2 words then at the peak we needed an extra stack slot
+                if (returnType.getNBytes() > 4) {
+                    extraSlots++;
+                }
+            }
+        } else {
+            // just push null
+            mv.visitInsn(Opcodes.ACONST_NULL);
+        }
+        // construct the exception
+        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, exceptionClassName, "<init>", "(Ljava/lang/String;Ljava/lang/Object;)V");
+
+        // check current stack and increment max stack if necessary
+        if (currentStackHeights.stackCount != currentStack + expected) {
+            throw new CompileException("ReturnExpression.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + currentStack + expected);
+        }
+
+        int overflow = ((currentStack + extraSlots) - maxStackHeights.stackCount);
+        if (overflow > 0) {
+            maxStackHeights.addStackCount(overflow);
+        }
+    }
+
     public void writeTo(StringWriter stringWriter) {
         if (returnValue != null) {
             stringWriter.write("RETURN ");

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/StaticExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/StaticExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/StaticExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -27,9 +27,13 @@
 import org.jboss.jbossts.orchestration.rule.type.TypeGroup;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 import java.io.StringWriter;
 import java.lang.reflect.Field;
@@ -98,6 +102,25 @@
         }
     }
 
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        int currentStack = currentStackHeights.stackCount;
+        int expected;
+
+        // compile a field access
+
+        mv.visitFieldInsn(Opcodes.GETSTATIC, ownerTypeName, fieldName, type.getName());
+        expected = (type.getNBytes() > 4 ? 2 : 1);
+
+        currentStackHeights.addStackCount(expected);
+
+        int overflow = ((currentStack + expected) - maxStackHeights.stackCount);
+        
+        if (overflow > 0) {
+            maxStackHeights.addStackCount(overflow);
+        }
+    }
+
     public void writeTo(StringWriter stringWriter) {
         stringWriter.write(ownerTypeName);
         stringWriter.write(".");

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/StringLiteral.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/StringLiteral.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/StringLiteral.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -26,9 +26,13 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 import java.io.StringWriter;
 
@@ -64,6 +68,26 @@
         return text;
     }
 
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        int currentStack = currentStackHeights.stackCount;
+        int expected = 1;
+
+        // compile a field access
+
+        // compile a load constant instruction
+        mv.visitLdcInsn(text);
+
+        currentStackHeights.addStackCount(expected);
+
+        int overflow = ((currentStack + expected) - maxStackHeights.stackCount);
+
+        if (overflow > 0) {
+            maxStackHeights.addStackCount(overflow);
+        }
+
+    }
+
     public void writeTo(StringWriter stringWriter) {
         stringWriter.write(text);
     }

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/StringPlusExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/StringPlusExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/StringPlusExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -26,9 +26,13 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 /**
  * A binary string concatenation operator expression
@@ -59,4 +63,39 @@
         String string2 = value2.toString();
         return string1 + string2;
     }
+
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        Expression oper0 = getOperand(0);
+        Expression oper1 = getOperand(1);
+
+        int currentStack = currentStackHeights.stackCount;
+        int expected = 2;
+
+        // compile and type convert each operand
+        oper0.compile(mv, currentStackHeights, maxStackHeights);
+        compileTypeConversion(oper0.getType(), type, mv, currentStackHeights, maxStackHeights);
+        oper1.compile(mv, currentStackHeights, maxStackHeights);
+        compileTypeConversion(oper1.getType(), type, mv, currentStackHeights, maxStackHeights);
+
+        // ok, we could optimize this for the case where the left or right operand is a String plus expression
+        // by employing a StringBuffer but for now we will just evaluate the left and right operand and
+        // then call concat to join them
+        // add two strings leaving one string
+        expected = 1;
+        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "concat", "(Ljava/lang/String;)Ljava/lang/String;");
+
+        currentStackHeights.addStackCount(-1);
+        
+        if (currentStackHeights.stackCount != currentStack + expected) {
+            throw new CompileException("StringPlusExpression.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + currentStack + expected);
+        }
+
+        // we need room for 2 * expected words at our maximum
+
+        int overflow = (currentStack + 2 * expected) - maxStackHeights.stackCount;
+        if (overflow > 0) {
+            maxStackHeights.addStackCount(overflow);
+        }
+    }
 }
\ No newline at end of file

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ThrowExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ThrowExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ThrowExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -28,9 +28,13 @@
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
 import org.jboss.jbossts.orchestration.rule.exception.ThrowException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 import java.io.StringWriter;
 import java.util.List;
@@ -48,6 +52,7 @@
     private String typeName;
     private List<Expression> arguments;
     private List<Type> argumentTypes;
+    private List<Type> paramTypes;
     private Constructor constructor;
 
     public ThrowExpression(Rule rule, ParseNode token, List<Expression> arguments) {
@@ -157,6 +162,15 @@
 
         constructor = candidates.get(0);
 
+        // make sure we know the formal parameter types and have included them in the typegroup
+
+        paramTypes = new ArrayList<Type>();
+        Class<?>[] paramClasses = constructor.getParameterTypes();
+
+        for (int i = 0; i < arguments.size() ; i++) {
+            paramTypes.add(typeGroup.ensureType(paramClasses[i]));
+        }
+
         // expected type should always be void since throw can only occur as a top level action
         // however, we need to be sure that the trigering method throws this exception type or
         // else that it is a subtype of runtime exception
@@ -239,6 +253,70 @@
         }
     }
 
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        int currentStack = currentStackHeights.stackCount;
+        int expected = 1;
+        int extraParams = 0;
+
+        // ok, we need to create the thrown exception instance and then
+        // initialise it.
+
+        // create the thrown exception instance -- adds 1 to stack
+        String exceptionClassName = type.getInternalName();
+        mv.visitTypeInsn(Opcodes.NEW, exceptionClassName);
+        currentStackHeights.addStackCount(1);
+        extraParams++;
+
+        int argCount = arguments.size();
+
+        // stack each of the arguments to the constructor
+        for (int i = 0; i < argCount; i++) {
+            Type argType = argumentTypes.get(i);
+            Type paramType = paramTypes.get(i);
+
+            arguments.get(i).compile(mv, currentStackHeights, maxStackHeights);
+            compileTypeConversion(argType, paramType, mv, currentStackHeights, maxStackHeights);
+            // track extra storage used after type conversion
+            extraParams += (paramType.getNBytes() > 4 ? 2 : 1);
+        }
+
+        // construct the exception
+        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, exceptionClassName, "<init>", getDescriptor());
+        // now throw it
+        mv.visitInsn(Opcodes.ATHROW);
+
+        // decrement the stack height to account for stacked param values (removed) and return value (added)
+        currentStackHeights.addStackCount(expected - extraParams);
+
+        // we should only have the thrown exception on the stack
+        if (currentStackHeights.stackCount != currentStack + expected) {
+            throw new CompileException("ThrowExpression.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + currentStack + expected);
+        }
+
+        // no need to update max stack unless extraParams is zero in which case the exception
+        // instance may have thrown us over the limit
+
+        if (extraParams < 1) {
+            int overflow = ((currentStack + 1) - maxStackHeights.stackCount);
+            if (overflow > 0) {
+                maxStackHeights.addStackCount(overflow);
+            }
+        }
+    }
+
+    private String getDescriptor()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("(");
+        int nParams = paramTypes.size();
+        for (int i = 0; i < nParams; i++) {
+            buffer.append(paramTypes.get(i).getInternalName(true));
+        }
+        buffer.append(")V");
+        return buffer.toString();
+    }
+
     public void writeTo(StringWriter stringWriter) {
         stringWriter.write("throw " + type.getName() + "(");
         for (Expression argument : arguments) {

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/TwiddleExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/TwiddleExpression.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/TwiddleExpression.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -26,9 +26,14 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import com.sun.org.apache.bcel.internal.generic.IXOR;
 
 /**
  */
@@ -63,10 +68,6 @@
                 return ~value.intValue();
             } else if (type == Type.J) {
                 return ~value.longValue();
-            } else if (type == Type.F) {
-                return ~value.longValue();
-            } else if (type == Type.D) {
-                return ~value.longValue();
             } else { // (type == Type.C)
                 return ~value.intValue();
             }
@@ -76,4 +77,47 @@
             throw new ExecuteException("TwiddleExpression.typeCheck() : unexpected exception : " + token.getText() + getPos(), e);
         }
     }
+
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        // compile the operand and then bit twiddle it
+        Expression oper = getOperand(0);
+        Type operType = oper.getType();
+
+        int currentStack = currentStackHeights.stackCount;
+        int expected = 0;
+
+        oper.compile(mv, currentStackHeights, maxStackHeights);
+        currentStackHeights.addStackCount((operType.getNBytes() > 4 ? 2 : 1));
+        compileTypeConversion(operType, type, mv, currentStackHeights, maxStackHeights);
+        if (type == Type.B) {
+            expected = 1;
+            mv.visitInsn(Opcodes.ICONST_1);
+            mv.visitInsn(Opcodes.IXOR);
+            mv.visitInsn(Opcodes.I2B);
+        } else if (type == Type.S) {
+            expected = 1;
+            mv.visitInsn(Opcodes.ICONST_1);
+            mv.visitInsn(Opcodes.IXOR);
+            mv.visitInsn(Opcodes.I2S);
+        } else if (type == Type.C) {
+            expected = 1;
+            mv.visitInsn(Opcodes.ICONST_1);
+            mv.visitInsn(Opcodes.IXOR);
+            mv.visitInsn(Opcodes.I2C);
+        } else if (type == Type.I) {
+            expected = 1;
+            mv.visitInsn(Opcodes.ICONST_1);
+            mv.visitInsn(Opcodes.IXOR);
+        } else if (type == Type.J) {
+            expected = 2;
+            mv.visitInsn(Opcodes.LCONST_1);
+            mv.visitInsn(Opcodes.LXOR);
+        }
+
+        // check the stack height is what we expect
+        if (currentStackHeights.stackCount != currentStack + expected) {
+            throw new CompileException("MinusExpression.compile : invalid stack height " + currentStackHeights.stackCount + " expecting " + currentStack + expected);
+        }
+    }
 }

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/Variable.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/Variable.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/Variable.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -27,9 +27,13 @@
 import org.jboss.jbossts.orchestration.rule.type.Type;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.ExecuteException;
+import org.jboss.jbossts.orchestration.rule.exception.CompileException;
 import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.compiler.StackHeights;
 import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 import java.io.StringWriter;
 
@@ -94,6 +98,34 @@
         return helper.getBinding(name);
     }
 
+    public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
+    {
+        int currentStack = currentStackHeights.stackCount;
+
+        // stack the current helper
+        // stack the name for the variable
+        // call the getBinding method
+        mv.visitVarInsn(Opcodes.ALOAD, 0);
+        mv.visitLdcInsn(name);
+        mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.internalName(HelperAdapter.class), "getBinding", "(Ljava/lang/String;)Ljava/lang/Object;");
+        // ok, we added 2 to the stack and then popped them leaving 1
+        currentStackHeights.addStackCount(1);
+        // perform any necessary type conversion
+        if (type.isPrimitive()) {
+            // cast down to the boxed type then do an unbox
+            compileObjectConversion(Type.OBJECT, Type.boxType(type), mv, currentStackHeights, maxStackHeights);
+            compileUnbox(Type.OBJECT, type,  mv, currentStackHeights, maxStackHeights);
+        } else {
+            // cast down to the required type
+            compileObjectConversion(Type.OBJECT, type, mv, currentStackHeights, maxStackHeights);
+        }
+        // make sure we have room for 2 working slots
+        int overflow = (currentStack + 2 - maxStackHeights.stackCount);
+        if (overflow > 0) {
+            maxStackHeights.addStackCount(overflow);
+        }
+    }
+
     public void writeTo(StringWriter stringWriter) {
         stringWriter.write(name);
     }

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/helper/InterpretedHelper.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/helper/InterpretedHelper.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/helper/InterpretedHelper.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -136,7 +136,7 @@
             throws ExecuteException
     {
         // System.out.println(rule.getName() + " test");
-        return rule.getCondition().interpret(this);
+        return (Boolean)rule.getCondition().interpret(this);
     }
         
     private void fire()

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/type/Type.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/type/Type.java	2009-03-20 09:57:33 UTC (rev 25762)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/type/Type.java	2009-03-20 10:16:54 UTC (rev 25763)
@@ -23,7 +23,7 @@
 */
 package org.jboss.jbossts.orchestration.rule.type;
 
-import org.jboss.jbossts.orchestration.rule.exception.TypeException;
+import org.jboss.jbossts.orchestration.rule.helper.HelperAdapter;
 
 import java.util.HashMap;
 import java.util.List;
@@ -41,7 +41,7 @@
      */
     public Type(String typeName, Class clazz)
     {
-        this(typeName, clazz, F_OBJECT, null);
+        this(typeName, clazz, F_OBJECT, 4, null);
     }
 
     /**
@@ -72,7 +72,7 @@
     public Type arrayType(Class clazz)
     {
         if (this.arrayType ==  null) {
-            arrayType = new Type(typeName + "[]", clazz, F_ARRAY, this);
+            arrayType = new Type(typeName + "[]", clazz, F_ARRAY, 1, this);
         }
         return arrayType;
     }
@@ -106,13 +106,24 @@
      */
     public String getInternalName()
     {
+        return getInternalName(false);
+    }
+
+    /**
+     * get the internal name for this type used by the class loader. this is only valid for
+     * defined types, defined array types or primitive types
+     * @return the type name
+     */
+    public String getInternalName(boolean forDescriptor)
+    {
         if (isArray()) {
-            return "[" + baseType.getInternalName();
+            return "[" + baseType.getInternalName(forDescriptor);
         } else if (isPrimitive()) {
             return internalNames.get(typeName);
         } else {
             String name = aliasFor.getTargetClass().getCanonicalName();
-            if (name.indexOf(';') == 0) {
+            name = name.replaceAll("\\.", "/");
+            if (forDescriptor) {
                 name = "L" + name + ";";
             }
             return name;
@@ -423,10 +434,19 @@
     }
 
     /**
+     * return the number of stack words occupied by instances of this type
+     * @return true if this is an array type
+     */
+    public int getNBytes()
+    {
+        return nBytes;
+    }
+
+    /**
      * return the builtin type associated with a given class
      * @return the corresponding builtin type
      */
-    public Type builtinType(Class clazz)
+    public static Type builtinType(Class clazz)
     {
         return builtinTypes.get(clazz.getName());
     }
@@ -435,27 +455,37 @@
      * return the primitive type whose boxed equivalent is associated with a given class
      * @return the corresponding primitive type
      */
-    public Type primitiveType(Class clazz)
+    public static Type boxType(Class clazz)
     {
         Type type = builtinType(clazz);
 
         return boxedTypes.get(type);
     }
 
+    /**
+     * return the primitive type for a boxed type or vice versa
+     * @return the corresponding primitive type
+     */
+    public static Type boxType(Type type)
+    {
+        return boxedTypes.get(type);
+    }
+
     private String typeName;
     private Class clazz;
     private String packageName;
     private int flags;
+    private int nBytes;
     private Type aliasFor;
     private Type baseType;
     private Type arrayType;
 
-    protected Type(String typeName, Class clazz, int flags)
+    protected Type(String typeName, Class clazz, int flags, int nBytes)
     {
-        this(typeName, clazz, flags, null);
+        this(typeName, clazz, flags, nBytes, null);
     }
 
-    protected Type(String typeName, Class clazz, int flags, Type baseType)
+    protected Type(String typeName, Class clazz, int flags, int nBytes, Type baseType)
     {
         this.typeName = typeName;
 
@@ -466,6 +496,9 @@
         this.clazz = clazz;
 
         this.flags = flags;
+
+        this.nBytes = nBytes;
+
         if ((flags & F_ARRAY) != 0) {
             this.baseType = baseType;
             baseType.arrayType = this;
@@ -514,13 +547,13 @@
             } else if (type1 == INTEGER || type2 == INTEGER || type1 == I || type2 == I) {
                 return I;
             } else if ((type1 == SHORT || type1 == S) && (type2 == SHORT || type2 == S)) {
-                return SHORT;
+                return S;
             } else if ((type1 == CHARACTER || type1 == C) && (type2 == CHARACTER || type2 == C)) {
                 return C;
             } else if ((type1 == BYTE || type1 == B) && (type2 == BYTE || type2 == B)) {
                 return B;
             } else {
-                return INTEGER;
+                return I;
             }
         }
     }
@@ -696,6 +729,11 @@
         return result;
     }
 
+    public static String internalName(Class<?> clazz)
+    {
+        return clazz.getName().replaceAll("\\.", "/");
+    }
+
     // private class used to type unknown types
     private static class Undefined {
     }
@@ -727,30 +765,31 @@
 
     // we need to cope with array types
 
-    final public static Type Z = new Type("boolean", boolean.class, F_BOOLEAN|F_PRIMITIVE);
-    final public static Type B = new Type("byte", byte.class, F_INTEGRAL|F_PRIMITIVE);
-    final public static Type S = new Type("short", short.class, F_INTEGRAL|F_PRIMITIVE);
-    final public static Type C = new Type("char", char.class, F_INTEGRAL|F_PRIMITIVE);
-    final public static Type I = new Type("int", int.class, F_INTEGRAL|F_PRIMITIVE);
-    final public static Type J = new Type("long", long.class, F_INTEGRAL|F_PRIMITIVE);
-    final public static Type F = new Type("float", float.class, F_FLOATING|F_PRIMITIVE);
-    final public static Type D = new Type("double", double.class, F_FLOATING|F_PRIMITIVE);
+    final public static Type Z = new Type("boolean", boolean.class, F_BOOLEAN|F_PRIMITIVE, 4);
+    final public static Type B = new Type("byte", byte.class, F_INTEGRAL|F_PRIMITIVE, 1);
+    final public static Type S = new Type("short", short.class, F_INTEGRAL|F_PRIMITIVE, 2);
+    final public static Type C = new Type("char", char.class, F_INTEGRAL|F_PRIMITIVE, 2);
+    final public static Type I = new Type("int", int.class, F_INTEGRAL|F_PRIMITIVE, 4);
+    final public static Type J = new Type("long", long.class, F_INTEGRAL|F_PRIMITIVE, 8);
+    final public static Type F = new Type("float", float.class, F_FLOATING|F_PRIMITIVE, 4);
+    final public static Type D = new Type("double", double.class, F_FLOATING|F_PRIMITIVE, 8);
     // pseudo type representing an undefined numeric primitive type
-    final public static Type N = new Type("", null, F_UNKNOWN|F_NUMERIC|F_PRIMITIVE);
+    final public static Type N = new Type("", null, F_UNKNOWN|F_NUMERIC|F_PRIMITIVE, 0);
 
-    final public static Type BOOLEAN = new Type("java.lang.Boolean", Boolean.class, F_BOOLEAN);
-    final public static Type BYTE = new Type("java.lang.Byte", Byte.class, F_INTEGRAL);
-    final public static Type SHORT = new Type("java.lang.Short", Short.class, F_INTEGRAL);
-    final public static Type CHARACTER = new Type("java.lang.Character", Character.class, F_INTEGRAL);
-    final public static Type INTEGER = new Type("java.lang.Integer", Integer.class, F_INTEGRAL);
-    final public static Type LONG = new Type("java.lang.Long", Long.class, F_INTEGRAL);
-    final public static Type FLOAT = new Type("java.lang.Float", Float.class, F_FLOATING);
-    final public static Type DOUBLE = new Type("java.lang.Double", Double.class, F_FLOATING);
-    final public static Type STRING = new Type("java.lang.String", String.class, F_OBJECT|F_STRING);
-    final public static Type VOID = new Type("void", void.class, F_VOID);
-    final public static Type NUMBER = new Type("java.lang.Number", Number.class, F_NUMERIC);
+    final public static Type BOOLEAN = new Type("java.lang.Boolean", Boolean.class, F_BOOLEAN, 4);
+    final public static Type BYTE = new Type("java.lang.Byte", Byte.class, F_INTEGRAL, 4);
+    final public static Type SHORT = new Type("java.lang.Short", Short.class, F_INTEGRAL, 4);
+    final public static Type CHARACTER = new Type("java.lang.Character", Character.class, F_INTEGRAL, 4);
+    final public static Type INTEGER = new Type("java.lang.Integer", Integer.class, F_INTEGRAL, 4);
+    final public static Type LONG = new Type("java.lang.Long", Long.class, F_INTEGRAL, 4);
+    final public static Type FLOAT = new Type("java.lang.Float", Float.class, F_FLOATING, 4);
+    final public static Type DOUBLE = new Type("java.lang.Double", Double.class, F_FLOATING, 4);
+    final public static Type STRING = new Type("java.lang.String", String.class, F_OBJECT|F_STRING, 4);
+    final public static Type VOID = new Type("void", void.class, F_VOID, 0);
+    final public static Type NUMBER = new Type("java.lang.Number", Number.class, F_NUMERIC, 0);
+    final public static Type OBJECT = new Type("java.lang.Object", Object.class, F_OBJECT, 0);
     // pseudo type representing an undefined primitive or object type
-    final public static Type UNDEFINED = new Type("", Undefined.class, F_UNKNOWN);
+    final public static Type UNDEFINED = new Type("", Undefined.class, F_UNKNOWN, 0);
 
     final private static HashMap<String, Type> builtinTypes;
     final private static HashMap<String, Type> primitiveTypes;
@@ -781,6 +820,7 @@
         builtinTypes.put(VOID.getTargetClass().getName(), VOID);
         builtinTypes.put(NUMBER.getTargetClass().getName(), NUMBER);
         builtinTypes.put(UNDEFINED.getTargetClass().getName(), UNDEFINED);
+        builtinTypes.put(OBJECT.getTargetClass().getName(), OBJECT);
         // nicknames
         builtinTypes.put("Boolean", BOOLEAN);
         builtinTypes.put("Byte", BYTE);
@@ -791,6 +831,7 @@
         builtinTypes.put("Float", FLOAT);
         builtinTypes.put("String", STRING);
         builtinTypes.put("Number", NUMBER);
+        builtinTypes.put("Object", OBJECT);
         builtinTypes.put("", UNDEFINED);
         // allow undefined to be spelled out
         builtinTypes.put("Undefined", UNDEFINED);




More information about the jboss-svn-commits mailing list