changeset 17425:4263c17d4b8c

Merge.
author Chris Seaton <chris.seaton@oracle.com>
date Mon, 13 Oct 2014 18:04:50 +0100
parents 34f6995b1d90 (current diff) 89f801a9b4d4 (diff)
children de120499a936
files graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java
diffstat 47 files changed, 402 insertions(+), 437 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGELOG.md	Mon Oct 13 18:04:01 2014 +0100
+++ b/CHANGELOG.md	Mon Oct 13 18:04:50 2014 +0100
@@ -7,6 +7,7 @@
 
 ### Truffle
 * Relaxed declared type restriction on child fields to allow for interface types in addition to Node subclasses.
+* The BranchProfile constructor is now private. Use BranchProfile#create() instead.
 * ...
 
 ## Version 0.5
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Mon Oct 13 18:04:50 2014 +0100
@@ -595,7 +595,7 @@
 
     @Override
     protected Value appendConstant(Constant constant) {
-        return gen.emitLoadConstant(constant);
+        return gen.emitLoadConstant(constant.getLIRKind(), constant);
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java	Mon Oct 13 18:04:50 2014 +0100
@@ -22,35 +22,47 @@
  */
 package com.oracle.graal.compiler.common.type;
 
-import static com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.*;
-
+import java.util.*;
+import java.util.function.*;
 import java.util.stream.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Add;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.And;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Div;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Mul;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Or;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Rem;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Sub;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Xor;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.ZeroExtend;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp.Neg;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp.Not;
 
 /**
  * Information about arithmetic operations.
  */
 public final class ArithmeticOpTable {
 
-    private final UnaryOp neg;
-    private final BinaryOp add;
-    private final BinaryOp sub;
+    private final UnaryOp<Neg> neg;
+    private final BinaryOp<Add> add;
+    private final BinaryOp<Sub> sub;
 
-    private final BinaryOp mul;
-    private final BinaryOp div;
-    private final BinaryOp rem;
+    private final BinaryOp<Mul> mul;
+    private final BinaryOp<Div> div;
+    private final BinaryOp<Rem> rem;
 
-    private final UnaryOp not;
-    private final BinaryOp and;
-    private final BinaryOp or;
-    private final BinaryOp xor;
+    private final UnaryOp<Not> not;
+    private final BinaryOp<And> and;
+    private final BinaryOp<Or> or;
+    private final BinaryOp<Xor> xor;
 
-    private final IntegerConvertOp zeroExtend;
-    private final IntegerConvertOp signExtend;
-    private final IntegerConvertOp narrow;
+    private final IntegerConvertOp<ZeroExtend> zeroExtend;
+    private final IntegerConvertOp<SignExtend> signExtend;
+    private final IntegerConvertOp<Narrow> narrow;
 
     private final FloatConvertOp[] floatConvert;
 
@@ -62,120 +74,57 @@
         }
     }
 
-    public static final ArithmeticOpTable EMPTY = create();
+    public static final ArithmeticOpTable EMPTY = new ArithmeticOpTable(null, null, null, null, null, null, null, null, null, null, null, null, null);
 
-    public static ArithmeticOpTable create(Op... ops) {
-        UnaryOp neg = null;
-        BinaryOp add = null;
-        BinaryOp sub = null;
+    public ArithmeticOpTable(UnaryOp<Neg> neg, BinaryOp<Add> add, BinaryOp<Sub> sub, BinaryOp<Mul> mul, BinaryOp<Div> div, BinaryOp<Rem> rem, UnaryOp<Not> not, BinaryOp<And> and, BinaryOp<Or> or,
+                    BinaryOp<Xor> xor, IntegerConvertOp<ZeroExtend> zeroExtend, IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow, FloatConvertOp... floatConvert) {
+        this(neg, add, sub, mul, div, rem, not, and, or, xor, zeroExtend, signExtend, narrow, Stream.of(floatConvert));
+    }
 
-        BinaryOp mul = null;
-        BinaryOp div = null;
-        BinaryOp rem = null;
+    public interface ArithmeticOpWrapper {
 
-        UnaryOp not = null;
-        BinaryOp and = null;
-        BinaryOp or = null;
-        BinaryOp xor = null;
+        <OP> UnaryOp<OP> wrapUnaryOp(UnaryOp<OP> op);
+
+        <OP> BinaryOp<OP> wrapBinaryOp(BinaryOp<OP> op);
 
-        IntegerConvertOp zeroExtend = null;
-        IntegerConvertOp signExtend = null;
-        IntegerConvertOp narrow = null;
+        <OP> IntegerConvertOp<OP> wrapIntegerConvertOp(IntegerConvertOp<OP> op);
 
-        FloatConvertOp[] floatConvert = new FloatConvertOp[FloatConvert.values().length];
+        FloatConvertOp wrapFloatConvertOp(FloatConvertOp op);
+    }
 
-        for (Op op : ops) {
-            if (op instanceof BinaryOp) {
-                BinaryOp binary = (BinaryOp) op;
-                switch (binary.getOperator()) {
-                    case '+':
-                        assert add == null;
-                        add = binary;
-                        break;
-                    case '-':
-                        assert sub == null;
-                        sub = binary;
-                        break;
-                    case '*':
-                        assert mul == null;
-                        mul = binary;
-                        break;
-                    case '/':
-                        assert div == null;
-                        div = binary;
-                        break;
-                    case '%':
-                        assert rem == null;
-                        rem = binary;
-                        break;
-                    case '&':
-                        assert and == null;
-                        and = binary;
-                        break;
-                    case '|':
-                        assert or == null;
-                        or = binary;
-                        break;
-                    case '^':
-                        assert xor == null;
-                        xor = binary;
-                        break;
-                    default:
-                        throw GraalInternalError.shouldNotReachHere("unknown binary operator " + binary.getOperator());
-                }
-            } else if (op instanceof IntegerConvertOp) {
-                IntegerConvertOp convert = (IntegerConvertOp) op;
-                switch (convert.getOperator()) {
-                    case IntegerConvertOp.ZERO_EXTEND:
-                        assert zeroExtend == null;
-                        zeroExtend = convert;
-                        break;
-                    case IntegerConvertOp.SIGN_EXTEND:
-                        assert signExtend == null;
-                        signExtend = convert;
-                        break;
-                    case IntegerConvertOp.NARROW:
-                        assert narrow == null;
-                        narrow = convert;
-                        break;
-                    default:
-                        throw GraalInternalError.shouldNotReachHere("unknown integer conversion operator " + convert.getOperator());
-                }
-            } else if (op instanceof FloatConvertOp) {
-                FloatConvertOp convert = (FloatConvertOp) op;
-                int idx = convert.getFloatConvert().ordinal();
-                assert floatConvert[idx] == null;
-                floatConvert[idx] = convert;
-            } else if (op instanceof UnaryOp) {
-                UnaryOp unary = (UnaryOp) op;
-                switch (unary.getOperator()) {
-                    case '-':
-                        assert neg == null;
-                        neg = unary;
-                        break;
-                    case '~':
-                        assert not == null;
-                        not = unary;
-                        break;
-                    default:
-                        throw GraalInternalError.shouldNotReachHere("unknown unary operator " + unary.getOperator());
-                }
-            } else {
-                throw GraalInternalError.shouldNotReachHere("unknown Op subclass " + op);
-            }
+    private static <T> T wrapIfNonNull(Function<T, T> wrapper, T obj) {
+        if (obj == null) {
+            return null;
+        } else {
+            return wrapper.apply(obj);
         }
+    }
+
+    public static ArithmeticOpTable wrap(ArithmeticOpWrapper wrapper, ArithmeticOpTable inner) {
+        UnaryOp<Neg> neg = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getNeg());
+        BinaryOp<Add> add = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getAdd());
+        BinaryOp<Sub> sub = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getSub());
+
+        BinaryOp<Mul> mul = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getMul());
+        BinaryOp<Div> div = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getDiv());
+        BinaryOp<Rem> rem = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getRem());
+
+        UnaryOp<Not> not = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getNot());
+        BinaryOp<And> and = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getAnd());
+        BinaryOp<Or> or = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getOr());
+        BinaryOp<Xor> xor = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getXor());
+
+        IntegerConvertOp<ZeroExtend> zeroExtend = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getZeroExtend());
+        IntegerConvertOp<SignExtend> signExtend = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getSignExtend());
+        IntegerConvertOp<Narrow> narrow = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getNarrow());
+
+        Stream<FloatConvertOp> floatConvert = Stream.of(inner.floatConvert).filter(Objects::nonNull).map(wrapper::wrapFloatConvertOp);
 
         return new ArithmeticOpTable(neg, add, sub, mul, div, rem, not, and, or, xor, zeroExtend, signExtend, narrow, floatConvert);
     }
 
-    public Stream<Op> getAllOps() {
-        Stream<Op> ops = Stream.of(neg, add, sub, mul, div, rem, not, and, or, xor, zeroExtend, signExtend, narrow);
-        Stream<Op> floatOps = Stream.of(floatConvert);
-        return Stream.concat(ops, floatOps).filter(op -> op != null);
-    }
-
-    private ArithmeticOpTable(UnaryOp neg, BinaryOp add, BinaryOp sub, BinaryOp mul, BinaryOp div, BinaryOp rem, UnaryOp not, BinaryOp and, BinaryOp or, BinaryOp xor, IntegerConvertOp zeroExtend,
-                    IntegerConvertOp signExtend, IntegerConvertOp narrow, FloatConvertOp[] floatConvert) {
+    private ArithmeticOpTable(UnaryOp<Neg> neg, BinaryOp<Add> add, BinaryOp<Sub> sub, BinaryOp<Mul> mul, BinaryOp<Div> div, BinaryOp<Rem> rem, UnaryOp<Not> not, BinaryOp<And> and, BinaryOp<Or> or,
+                    BinaryOp<Xor> xor, IntegerConvertOp<ZeroExtend> zeroExtend, IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow, Stream<FloatConvertOp> floatConvert) {
         this.neg = neg;
         this.add = add;
         this.sub = sub;
@@ -189,170 +138,142 @@
         this.zeroExtend = zeroExtend;
         this.signExtend = signExtend;
         this.narrow = narrow;
-        this.floatConvert = floatConvert;
-    }
-
-    public UnaryOp getUnaryOp(UnaryOp op) {
-        switch (op.getOperator()) {
-            case '-':
-                return getNeg();
-            case '~':
-                return getNot();
-            default:
-                return getFloatConvertOp((FloatConvertOp) op);
-        }
-    }
-
-    public BinaryOp getBinaryOp(BinaryOp op) {
-        switch (op.getOperator()) {
-            case '+':
-                return getAdd();
-            case '-':
-                return getSub();
-            case '*':
-                return getMul();
-            case '/':
-                return getDiv();
-            case '%':
-                return getRem();
-            case '&':
-                return getAnd();
-            case '|':
-                return getOr();
-            case '^':
-                return getXor();
-            default:
-                throw GraalInternalError.shouldNotReachHere("unknown binary operator " + op);
-        }
-    }
-
-    public IntegerConvertOp getIntegerConvertOp(IntegerConvertOp op) {
-        switch (op.getOperator()) {
-            case ZERO_EXTEND:
-                return getZeroExtend();
-            case SIGN_EXTEND:
-                return getSignExtend();
-            case NARROW:
-                return getNarrow();
-            default:
-                throw GraalInternalError.shouldNotReachHere("unknown integer convert operator " + op);
-        }
-    }
-
-    public FloatConvertOp getFloatConvertOp(FloatConvertOp op) {
-        return getFloatConvert(op.getFloatConvert());
+        this.floatConvert = new FloatConvertOp[FloatConvert.values().length];
+        floatConvert.forEach(op -> this.floatConvert[op.getFloatConvert().ordinal()] = op);
     }
 
     /**
      * Describes the unary negation operation.
      */
-    public final UnaryOp getNeg() {
+    public final UnaryOp<Neg> getNeg() {
         return neg;
     }
 
     /**
      * Describes the addition operation.
      */
-    public final BinaryOp getAdd() {
+    public final BinaryOp<Add> getAdd() {
         return add;
     }
 
     /**
      * Describes the subtraction operation.
      */
-    public final BinaryOp getSub() {
+    public final BinaryOp<Sub> getSub() {
         return sub;
     }
 
     /**
      * Describes the multiplication operation.
      */
-    public final BinaryOp getMul() {
+    public final BinaryOp<Mul> getMul() {
         return mul;
     }
 
     /**
      * Describes the division operation.
      */
-    public final BinaryOp getDiv() {
+    public final BinaryOp<Div> getDiv() {
         return div;
     }
 
     /**
      * Describes the remainder operation.
      */
-    public final BinaryOp getRem() {
+    public final BinaryOp<Rem> getRem() {
         return rem;
     }
 
     /**
      * Describes the bitwise not operation.
      */
-    public final UnaryOp getNot() {
+    public final UnaryOp<Not> getNot() {
         return not;
     }
 
     /**
      * Describes the bitwise and operation.
      */
-    public final BinaryOp getAnd() {
+    public final BinaryOp<And> getAnd() {
         return and;
     }
 
     /**
      * Describes the bitwise or operation.
      */
-    public final BinaryOp getOr() {
+    public final BinaryOp<Or> getOr() {
         return or;
     }
 
     /**
      * Describes the bitwise xor operation.
      */
-    public final BinaryOp getXor() {
+    public final BinaryOp<Xor> getXor() {
         return xor;
     }
 
-    public IntegerConvertOp getZeroExtend() {
+    /**
+     * Describes the zero extend conversion.
+     */
+    public IntegerConvertOp<ZeroExtend> getZeroExtend() {
         return zeroExtend;
     }
 
-    public IntegerConvertOp getSignExtend() {
+    /**
+     * Describes the sign extend conversion.
+     */
+    public IntegerConvertOp<SignExtend> getSignExtend() {
         return signExtend;
     }
 
-    public IntegerConvertOp getNarrow() {
+    /**
+     * Describes the narrowing conversion.
+     */
+    public IntegerConvertOp<Narrow> getNarrow() {
         return narrow;
     }
 
+    /**
+     * Describes integer/float/double conversions.
+     */
     public FloatConvertOp getFloatConvert(FloatConvert op) {
         return floatConvert[op.ordinal()];
     }
 
     public abstract static class Op {
 
-        private final char operator;
+        private final String operator;
 
-        protected Op(char operator) {
+        protected Op(String operator) {
             this.operator = operator;
         }
 
-        public char getOperator() {
-            return operator;
-        }
-
         @Override
         public String toString() {
-            return Character.toString(operator);
+            return operator;
         }
     }
 
     /**
      * Describes a unary arithmetic operation.
      */
-    public abstract static class UnaryOp extends Op {
+    public abstract static class UnaryOp<T> extends Op {
+
+        public abstract static class Neg extends UnaryOp<Neg> {
+
+            protected Neg() {
+                super("-");
+            }
+        }
 
-        protected UnaryOp(char operation) {
+        public abstract static class Not extends UnaryOp<Not> {
+
+            protected Not() {
+                super("~");
+            }
+        }
+
+        protected UnaryOp(String operation) {
             super(operation);
         }
 
@@ -370,12 +291,68 @@
     /**
      * Describes a binary arithmetic operation.
      */
-    public abstract static class BinaryOp extends Op {
+    public abstract static class BinaryOp<T> extends Op {
+
+        public abstract static class Add extends BinaryOp<Add> {
+
+            protected Add(boolean associative, boolean commutative) {
+                super("+", associative, commutative);
+            }
+        }
+
+        public abstract static class Sub extends BinaryOp<Sub> {
+
+            protected Sub(boolean associative, boolean commutative) {
+                super("-", associative, commutative);
+            }
+        }
+
+        public abstract static class Mul extends BinaryOp<Mul> {
+
+            protected Mul(boolean associative, boolean commutative) {
+                super("*", associative, commutative);
+            }
+        }
+
+        public abstract static class Div extends BinaryOp<Div> {
+
+            protected Div(boolean associative, boolean commutative) {
+                super("/", associative, commutative);
+            }
+        }
+
+        public abstract static class Rem extends BinaryOp<Rem> {
+
+            protected Rem(boolean associative, boolean commutative) {
+                super("%", associative, commutative);
+            }
+        }
+
+        public abstract static class And extends BinaryOp<And> {
+
+            protected And(boolean associative, boolean commutative) {
+                super("&", associative, commutative);
+            }
+        }
+
+        public abstract static class Or extends BinaryOp<Or> {
+
+            protected Or(boolean associative, boolean commutative) {
+                super("|", associative, commutative);
+            }
+        }
+
+        public abstract static class Xor extends BinaryOp<Xor> {
+
+            protected Xor(boolean associative, boolean commutative) {
+                super("^", associative, commutative);
+            }
+        }
 
         private final boolean associative;
         private final boolean commutative;
 
-        protected BinaryOp(char operation, boolean associative, boolean commutative) {
+        protected BinaryOp(String operation, boolean associative, boolean commutative) {
             super(operation);
             this.associative = associative;
             this.commutative = commutative;
@@ -435,51 +412,49 @@
         }
     }
 
-    public abstract static class FloatConvertOp extends UnaryOp {
+    public abstract static class FloatConvertOp extends UnaryOp<FloatConvertOp> {
 
         private final FloatConvert op;
 
         protected FloatConvertOp(FloatConvert op) {
-            super('\0');
+            super(op.name());
             this.op = op;
         }
 
         public FloatConvert getFloatConvert() {
             return op;
         }
-
-        @Override
-        public String toString() {
-            return op.name();
-        }
     }
 
-    public abstract static class IntegerConvertOp extends Op {
+    public abstract static class IntegerConvertOp<T> extends Op {
+
+        public abstract static class ZeroExtend extends IntegerConvertOp<ZeroExtend> {
+
+            protected ZeroExtend() {
+                super("ZeroExtend");
+            }
+        }
+
+        public abstract static class SignExtend extends IntegerConvertOp<SignExtend> {
 
-        public static final char ZERO_EXTEND = 'z';
-        public static final char SIGN_EXTEND = 's';
-        public static final char NARROW = 'n';
+            protected SignExtend() {
+                super("SignExtend");
+            }
+        }
+
+        public abstract static class Narrow extends IntegerConvertOp<Narrow> {
 
-        protected IntegerConvertOp(char op) {
+            protected Narrow() {
+                super("Narrow");
+            }
+        }
+
+        protected IntegerConvertOp(String op) {
             super(op);
         }
 
         public abstract Constant foldConstant(int inputBits, int resultBits, Constant value);
 
         public abstract Stamp foldStamp(int resultBits, Stamp stamp);
-
-        @Override
-        public String toString() {
-            switch (getOperator()) {
-                case ZERO_EXTEND:
-                    return "ZeroExtend";
-                case SIGN_EXTEND:
-                    return "SignExtend";
-                case NARROW:
-                    return "Narrow";
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        }
     }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Mon Oct 13 18:04:50 2014 +0100
@@ -255,9 +255,9 @@
         return null;
     }
 
-    private static final ArithmeticOpTable OPS = ArithmeticOpTable.create(
+    private static final ArithmeticOpTable OPS = new ArithmeticOpTable(
 
-    new UnaryOp('-') {
+    new UnaryOp.Neg() {
 
         @Override
         public Constant foldConstant(Constant value) {
@@ -278,7 +278,7 @@
         }
     },
 
-    new BinaryOp('+', false, true) {
+    new BinaryOp.Add(false, true) {
 
         @Override
         public Constant foldConstant(Constant a, Constant b) {
@@ -312,7 +312,7 @@
         }
     },
 
-    new BinaryOp('-', false, false) {
+    new BinaryOp.Sub(false, false) {
 
         @Override
         public Constant foldConstant(Constant a, Constant b) {
@@ -346,7 +346,7 @@
         }
     },
 
-    new BinaryOp('*', false, true) {
+    new BinaryOp.Mul(false, true) {
 
         @Override
         public Constant foldConstant(Constant a, Constant b) {
@@ -380,7 +380,7 @@
         }
     },
 
-    new BinaryOp('/', false, false) {
+    new BinaryOp.Div(false, false) {
 
         @Override
         public Constant foldConstant(Constant a, Constant b) {
@@ -414,7 +414,7 @@
         }
     },
 
-    new BinaryOp('%', false, false) {
+    new BinaryOp.Rem(false, false) {
 
         @Override
         public Constant foldConstant(Constant a, Constant b) {
@@ -436,6 +436,10 @@
         }
     },
 
+    null, null, null, null,
+
+    null, null, null,
+
     new FloatConvertOp(F2I) {
 
         @Override
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Mon Oct 13 18:04:50 2014 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.compiler.common.type;
 
 import static com.oracle.graal.compiler.common.calc.FloatConvert.*;
-import static com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.*;
 
 import java.util.*;
 
@@ -369,9 +368,9 @@
         return v;
     }
 
-    public static final ArithmeticOpTable OPS = ArithmeticOpTable.create(
+    public static final ArithmeticOpTable OPS = new ArithmeticOpTable(
 
-    new UnaryOp('-') {
+    new UnaryOp.Neg() {
 
         @Override
         public Constant foldConstant(Constant value) {
@@ -391,7 +390,7 @@
         }
     },
 
-    new BinaryOp('+', true, true) {
+    new BinaryOp.Add(true, true) {
 
         @Override
         public Constant foldConstant(Constant a, Constant b) {
@@ -448,7 +447,7 @@
         }
     },
 
-    new BinaryOp('-', true, false) {
+    new BinaryOp.Sub(true, false) {
 
         @Override
         public Constant foldConstant(Constant a, Constant b) {
@@ -473,7 +472,7 @@
         }
     },
 
-    new BinaryOp('*', true, true) {
+    new BinaryOp.Mul(true, true) {
 
         @Override
         public Constant foldConstant(Constant a, Constant b) {
@@ -501,7 +500,7 @@
         }
     },
 
-    new BinaryOp('/', true, false) {
+    new BinaryOp.Div(true, false) {
 
         @Override
         public Constant foldConstant(Constant a, Constant b) {
@@ -529,7 +528,7 @@
         }
     },
 
-    new BinaryOp('%', false, false) {
+    new BinaryOp.Rem(false, false) {
 
         @Override
         public Constant foldConstant(Constant a, Constant b) {
@@ -560,7 +559,7 @@
         }
     },
 
-    new UnaryOp('~') {
+    new UnaryOp.Not() {
 
         @Override
         public Constant foldConstant(Constant value) {
@@ -576,7 +575,7 @@
         }
     },
 
-    new BinaryOp('&', true, true) {
+    new BinaryOp.And(true, true) {
 
         @Override
         public Constant foldConstant(Constant a, Constant b) {
@@ -600,7 +599,7 @@
         }
     },
 
-    new BinaryOp('|', true, true) {
+    new BinaryOp.Or(true, true) {
 
         @Override
         public Constant foldConstant(Constant a, Constant b) {
@@ -622,7 +621,7 @@
         }
     },
 
-    new BinaryOp('^', true, true) {
+    new BinaryOp.Xor(true, true) {
 
         @Override
         public Constant foldConstant(Constant a, Constant b) {
@@ -654,7 +653,7 @@
         }
     },
 
-    new IntegerConvertOp(ZERO_EXTEND) {
+    new IntegerConvertOp.ZeroExtend() {
 
         @Override
         public Constant foldConstant(int inputBits, int resultBits, Constant value) {
@@ -683,7 +682,7 @@
         }
     },
 
-    new IntegerConvertOp(SIGN_EXTEND) {
+    new IntegerConvertOp.SignExtend() {
 
         @Override
         public Constant foldConstant(int inputBits, int resultBits, Constant value) {
@@ -704,7 +703,7 @@
         }
     },
 
-    new IntegerConvertOp(NARROW) {
+    new IntegerConvertOp.Narrow() {
 
         @Override
         public Constant foldConstant(int inputBits, int resultBits, Constant value) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Mon Oct 13 18:04:50 2014 +0100
@@ -118,7 +118,7 @@
     }
 
     @Override
-    public Value emitLoadConstant(Constant constant) {
+    public Value emitLoadConstant(LIRKind kind, Constant constant) {
         if (canInlineConstant(constant)) {
             return constant;
         } else {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Mon Oct 13 18:04:50 2014 +0100
@@ -52,7 +52,7 @@
 
     void doBlockEnd(AbstractBlock<?> block);
 
-    Value emitLoadConstant(Constant constant);
+    Value emitLoadConstant(LIRKind kind, Constant constant);
 
     Value emitLoad(LIRKind kind, Value address, LIRFrameState state);
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Mon Oct 13 18:04:50 2014 +0100
@@ -32,9 +32,9 @@
     private ValuePhiNode phi;
     private ValueNode init;
     private ValueNode rawStride;
-    private BinaryArithmeticNode op;
+    private BinaryArithmeticNode<?> op;
 
-    public BasicInductionVariable(LoopEx loop, ValuePhiNode phi, ValueNode init, ValueNode rawStride, BinaryArithmeticNode op) {
+    public BasicInductionVariable(LoopEx loop, ValuePhiNode phi, ValueNode init, ValueNode rawStride, BinaryArithmeticNode<?> op) {
         super(loop);
         this.phi = phi;
         this.init = init;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Mon Oct 13 18:04:50 2014 +0100
@@ -55,7 +55,7 @@
     public ValueNode maxTripCountNode(boolean assumePositive) {
         StructuredGraph graph = iv.valueNode().graph();
         Stamp stamp = iv.valueNode().stamp();
-        BinaryArithmeticNode range = BinaryArithmeticNode.sub(graph, end, iv.initNode());
+        BinaryArithmeticNode<?> range = BinaryArithmeticNode.sub(graph, end, iv.initNode());
         if (oneOff) {
             if (iv.direction() == Direction.Up) {
                 range = BinaryArithmeticNode.add(graph, range, ConstantNode.forIntegerStamp(stamp, 1, graph));
@@ -144,14 +144,14 @@
         CompareNode cond; // we use a negated guard with a < condition to achieve a >=
         ConstantNode one = ConstantNode.forIntegerStamp(stamp, 1, graph);
         if (iv.direction() == Direction.Up) {
-            BinaryArithmeticNode v1 = sub(graph, ConstantNode.forIntegerStamp(stamp, CodeUtil.maxValue(stamp.getBits()), graph), sub(graph, iv.strideNode(), one));
+            BinaryArithmeticNode<?> v1 = sub(graph, ConstantNode.forIntegerStamp(stamp, CodeUtil.maxValue(stamp.getBits()), graph), sub(graph, iv.strideNode(), one));
             if (oneOff) {
                 v1 = sub(graph, v1, one);
             }
             cond = graph.unique(IntegerLessThanNode.create(v1, end));
         } else {
             assert iv.direction() == Direction.Down;
-            BinaryArithmeticNode v1 = add(graph, ConstantNode.forIntegerStamp(stamp, CodeUtil.minValue(stamp.getBits()), graph), sub(graph, one, iv.strideNode()));
+            BinaryArithmeticNode<?> v1 = add(graph, ConstantNode.forIntegerStamp(stamp, CodeUtil.minValue(stamp.getBits()), graph), sub(graph, one, iv.strideNode()));
             if (oneOff) {
                 v1 = add(graph, v1, one);
             }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java	Mon Oct 13 18:04:50 2014 +0100
@@ -31,9 +31,9 @@
 
     private InductionVariable base;
     private ValueNode offset;
-    private BinaryArithmeticNode value;
+    private BinaryArithmeticNode<?> value;
 
-    public DerivedOffsetInductionVariable(LoopEx loop, InductionVariable base, ValueNode offset, BinaryArithmeticNode value) {
+    public DerivedOffsetInductionVariable(LoopEx loop, InductionVariable base, ValueNode offset, BinaryArithmeticNode<?> value) {
         super(loop);
         this.base = base;
         this.offset = offset;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Mon Oct 13 18:04:50 2014 +0100
@@ -57,7 +57,7 @@
             }
             ValueNode stride = addSub(backValue, phi);
             if (stride != null) {
-                BasicInductionVariable biv = new BasicInductionVariable(loop, (ValuePhiNode) phi, phi.valueAt(forwardEnd), stride, (BinaryArithmeticNode) backValue);
+                BasicInductionVariable biv = new BasicInductionVariable(loop, (ValuePhiNode) phi, phi.valueAt(forwardEnd), stride, (BinaryArithmeticNode<?>) backValue);
                 ivs.put(phi, biv);
                 bivs.add(biv);
             }
@@ -78,7 +78,7 @@
                 ValueNode offset = addSub(op, baseIvNode);
                 ValueNode scale;
                 if (offset != null) {
-                    iv = new DerivedOffsetInductionVariable(loop, baseIv, offset, (BinaryArithmeticNode) op);
+                    iv = new DerivedOffsetInductionVariable(loop, baseIv, offset, (BinaryArithmeticNode<?>) op);
                 } else if (op instanceof NegateNode) {
                     iv = new DerivedScaledInductionVariable(loop, baseIv, (NegateNode) op);
                 } else if ((scale = mul(op, baseIvNode)) != null) {
@@ -95,7 +95,7 @@
 
     private ValueNode addSub(ValueNode op, ValueNode base) {
         if (op.stamp() instanceof IntegerStamp && (op instanceof AddNode || op instanceof SubNode)) {
-            BinaryArithmeticNode aritOp = (BinaryArithmeticNode) op;
+            BinaryArithmeticNode<?> aritOp = (BinaryArithmeticNode<?>) op;
             if (aritOp.getX() == base && loop.isOutsideLoop(aritOp.getY())) {
                 return aritOp.getY();
             } else if (aritOp.getY() == base && loop.isOutsideLoop(aritOp.getX())) {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Mon Oct 13 18:04:50 2014 +0100
@@ -137,11 +137,11 @@
     public void reassociateInvariants() {
         InvariantPredicate invariant = new InvariantPredicate();
         StructuredGraph graph = loopBegin().graph();
-        for (BinaryArithmeticNode binary : whole().nodes().filter(BinaryArithmeticNode.class)) {
-            if (!binary.getOp().isAssociative()) {
+        for (BinaryArithmeticNode<?> binary : whole().nodes().filter(BinaryArithmeticNode.class)) {
+            if (!binary.isAssociative()) {
                 continue;
             }
-            BinaryArithmeticNode result = BinaryArithmeticNode.reassociate(binary, invariant, binary.getX(), binary.getY());
+            BinaryArithmeticNode<?> result = BinaryArithmeticNode.reassociate(binary, invariant, binary.getX(), binary.getY());
             if (result != binary) {
                 if (Debug.isLogEnabled()) {
                     Debug.log("%s : Reassociated %s into %s", graph.method().format("%H::%n"), binary, result);
--- a/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java	Mon Oct 13 18:04:50 2014 +0100
@@ -131,7 +131,7 @@
 
     private static Stamp narrowingKindConversion(Stamp stamp, Kind kind) {
         Stamp narrow = IntegerStamp.OPS.getNarrow().foldStamp(kind.getBitCount(), stamp);
-        IntegerConvertOp implicitExtend = kind.isUnsigned() ? IntegerStamp.OPS.getZeroExtend() : IntegerStamp.OPS.getSignExtend();
+        IntegerConvertOp<?> implicitExtend = kind.isUnsigned() ? IntegerStamp.OPS.getZeroExtend() : IntegerStamp.OPS.getSignExtend();
         return implicitExtend.foldStamp(32, narrow);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -94,7 +94,8 @@
         if (onlyUsedInVirtualState()) {
             gen.setResult(this, value);
         } else {
-            gen.setResult(this, gen.getLIRGeneratorTool().emitLoadConstant(value));
+            LIRKind kind = gen.getLIRGeneratorTool().getLIRKind(stamp());
+            gen.setResult(this, gen.getLIRGeneratorTool().emitLoadConstant(kind, value));
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AddNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AddNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -24,6 +24,8 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Add;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -31,14 +33,14 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "+")
-public class AddNode extends BinaryArithmeticNode implements NarrowableArithmeticNode {
+public class AddNode extends BinaryArithmeticNode<Add> implements NarrowableArithmeticNode {
 
     public static AddNode create(ValueNode x, ValueNode y) {
         return USE_GENERATED_NODES ? new AddNodeGen(x, y) : new AddNode(x, y);
     }
 
     protected AddNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable.forStamp(x.stamp()).getAdd(), x, y);
+        super(ArithmeticOpTable::getAdd, x, y);
     }
 
     @Override
@@ -51,7 +53,8 @@
         if (forX.isConstant() && !forY.isConstant()) {
             return AddNode.create(forY, forX);
         }
-        boolean associative = getOp().isAssociative();
+        BinaryOp<Add> op = getOp(forX, forY);
+        boolean associative = op.isAssociative();
         if (associative) {
             if (forX instanceof SubNode) {
                 SubNode sub = (SubNode) forX;
@@ -70,7 +73,7 @@
         }
         if (forY.isConstant()) {
             Constant c = forY.asConstant();
-            if (getOp().isNeutral(c)) {
+            if (op.isNeutral(c)) {
                 return forX;
             }
             if (associative) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.And;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -33,14 +34,14 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "&")
-public class AndNode extends BinaryArithmeticNode implements NarrowableArithmeticNode {
+public class AndNode extends BinaryArithmeticNode<And> implements NarrowableArithmeticNode {
 
     public static AndNode create(ValueNode x, ValueNode y) {
         return USE_GENERATED_NODES ? new AndNodeGen(x, y) : new AndNode(x, y);
     }
 
     protected AndNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable.forStamp(x.stamp()).getAnd(), x, y);
+        super(ArithmeticOpTable::getAnd, x, y);
     }
 
     @Override
@@ -58,7 +59,7 @@
         }
         if (forY.isConstant()) {
             Constant c = forY.asConstant();
-            if (getOp().isNeutral(c)) {
+            if (getOp(forX, forY).isNeutral(c)) {
                 return forX;
             }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import java.util.function.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -34,29 +36,35 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public abstract class BinaryArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
+public abstract class BinaryArithmeticNode<OP> extends BinaryNode implements ArithmeticLIRLowerable {
 
-    protected BinaryOp op;
+    protected final Function<ArithmeticOpTable, BinaryOp<OP>> getOp;
 
-    public BinaryArithmeticNode(BinaryOp op, ValueNode x, ValueNode y) {
-        super(op.foldStamp(x.stamp(), y.stamp()), x, y);
-        this.op = op;
+    public BinaryArithmeticNode(Function<ArithmeticOpTable, BinaryOp<OP>> getOp, ValueNode x, ValueNode y) {
+        super(getOp.apply(ArithmeticOpTable.forStamp(x.stamp())).foldStamp(x.stamp(), y.stamp()), x, y);
+        this.getOp = getOp;
     }
 
-    public BinaryOp getOp() {
-        return op;
+    protected final BinaryOp<OP> getOp(ValueNode forX, ValueNode forY) {
+        ArithmeticOpTable table = ArithmeticOpTable.forStamp(forX.stamp());
+        assert table == ArithmeticOpTable.forStamp(forY.stamp());
+        return getOp.apply(table);
+    }
+
+    public boolean isAssociative() {
+        return getOp(getX(), getY()).isAssociative();
     }
 
     @Override
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 2;
-        return op.foldConstant(inputs[0], inputs[1]);
+        return getOp(getX(), getY()).foldConstant(inputs[0], inputs[1]);
     }
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         if (forX.isConstant() && forY.isConstant()) {
-            Constant ret = op.foldConstant(forX.asConstant(), forY.asConstant());
+            Constant ret = getOp(forX, forY).foldConstant(forX.asConstant(), forY.asConstant());
             return ConstantNode.forPrimitive(stamp(), ret);
         }
         return this;
@@ -64,10 +72,7 @@
 
     @Override
     public boolean inferStamp() {
-        ArithmeticOpTable ops = ArithmeticOpTable.forStamp(getX().stamp());
-        assert ops == ArithmeticOpTable.forStamp(getY().stamp());
-        op = ops.getBinaryOp(op);
-        return updateStamp(op.foldStamp(getX().stamp(), getY().stamp()));
+        return updateStamp(getOp(getX(), getY()).foldStamp(getX().stamp(), getY().stamp()));
     }
 
     public static AddNode add(StructuredGraph graph, ValueNode v1, ValueNode v2) {
@@ -159,8 +164,8 @@
      * @param forY
      * @param forX
      */
-    public static BinaryArithmeticNode reassociate(BinaryArithmeticNode node, NodePredicate criterion, ValueNode forX, ValueNode forY) {
-        assert node.getOp().isAssociative();
+    public static BinaryArithmeticNode<?> reassociate(BinaryArithmeticNode<?> node, NodePredicate criterion, ValueNode forX, ValueNode forY) {
+        assert node.getOp(forX, forY).isAssociative();
         ReassociateMatch match1 = findReassociate(node, criterion);
         if (match1 == null) {
             return node;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/DivNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/DivNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Div;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -32,14 +33,14 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "/")
-public class DivNode extends BinaryArithmeticNode {
+public class DivNode extends BinaryArithmeticNode<Div> {
 
     public static DivNode create(ValueNode x, ValueNode y) {
         return USE_GENERATED_NODES ? new DivNodeGen(x, y) : new DivNode(x, y);
     }
 
     protected DivNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable.forStamp(x.stamp()).getDiv(), x, y);
+        super(ArithmeticOpTable::getDiv, x, y);
     }
 
     @Override
@@ -51,7 +52,7 @@
 
         if (forY.isConstant()) {
             Constant c = forY.asConstant();
-            if (getOp().isNeutral(c)) {
+            if (getOp(forX, forY).isNeutral(c)) {
                 return forX;
             }
             if (c.getKind().isNumericInteger()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -37,36 +37,32 @@
  * semantics.
  */
 @NodeInfo
-public class FloatConvertNode extends UnaryArithmeticNode implements ConvertNode, Lowerable, ArithmeticLIRLowerable {
+public class FloatConvertNode extends UnaryArithmeticNode<FloatConvertOp> implements ConvertNode, Lowerable, ArithmeticLIRLowerable {
 
-    protected FloatConvertOp reverseOp;
+    protected final FloatConvert op;
 
     public static FloatConvertNode create(FloatConvert op, ValueNode input) {
         return USE_GENERATED_NODES ? new FloatConvertNodeGen(op, input) : new FloatConvertNode(op, input);
     }
 
-    private FloatConvertNode(ArithmeticOpTable table, FloatConvert op, ValueNode input) {
-        super(table.getFloatConvert(op), input);
-        ArithmeticOpTable revTable = ArithmeticOpTable.forStamp(stamp());
-        reverseOp = revTable.getFloatConvert(op.reverse());
-    }
-
     protected FloatConvertNode(FloatConvert op, ValueNode input) {
-        this(ArithmeticOpTable.forStamp(input.stamp()), op, input);
+        super(table -> table.getFloatConvert(op), input);
+        this.op = op;
     }
 
     public FloatConvert getFloatConvert() {
-        return ((FloatConvertOp) getOp()).getFloatConvert();
+        return op;
     }
 
     @Override
     public Constant convert(Constant c) {
-        return op.foldConstant(c);
+        return getOp(getValue()).foldConstant(c);
     }
 
     @Override
     public Constant reverse(Constant c) {
-        return reverseOp.foldConstant(c);
+        FloatConvertOp reverse = ArithmeticOpTable.forStamp(stamp()).getFloatConvert(op.reverse());
+        return reverse.foldConstant(c);
     }
 
     @Override
@@ -89,22 +85,13 @@
 
         if (forValue instanceof FloatConvertNode) {
             FloatConvertNode other = (FloatConvertNode) forValue;
-            if (other.isLossless() && other.op == this.reverseOp) {
+            if (other.isLossless() && other.op == this.op.reverse()) {
                 return other.getValue();
             }
         }
         return this;
     }
 
-    @Override
-    public boolean inferStamp() {
-        boolean changed = super.inferStamp();
-        if (changed) {
-            reverseOp = ArithmeticOpTable.forStamp(stamp()).getFloatConvertOp(reverseOp);
-        }
-        return changed;
-    }
-
     public void lower(LoweringTool tool) {
         tool.getLowerer().lower(this, tool);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -22,9 +22,11 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import java.util.function.*;
+
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp;
-import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -34,17 +36,17 @@
  * An {@code IntegerConvert} converts an integer to an integer of different width.
  */
 @NodeInfo
-public abstract class IntegerConvertNode extends UnaryNode implements ConvertNode, ArithmeticLIRLowerable {
+public abstract class IntegerConvertNode<OP, REV> extends UnaryNode implements ConvertNode, ArithmeticLIRLowerable {
 
-    protected IntegerConvertOp op;
-    protected IntegerConvertOp reverseOp;
+    protected final Function<ArithmeticOpTable, IntegerConvertOp<OP>> getOp;
+    protected final Function<ArithmeticOpTable, IntegerConvertOp<REV>> getReverseOp;
 
     protected final int resultBits;
 
-    protected IntegerConvertNode(IntegerConvertOp op, IntegerConvertOp reverseOp, int resultBits, ValueNode input) {
-        super(op.foldStamp(resultBits, input.stamp()), input);
-        this.op = op;
-        this.reverseOp = reverseOp;
+    protected IntegerConvertNode(Function<ArithmeticOpTable, IntegerConvertOp<OP>> getOp, Function<ArithmeticOpTable, IntegerConvertOp<REV>> getReverseOp, int resultBits, ValueNode input) {
+        super(getOp.apply(ArithmeticOpTable.forStamp(input.stamp())).foldStamp(resultBits, input.stamp()), input);
+        this.getOp = getOp;
+        this.getReverseOp = getReverseOp;
         this.resultBits = resultBits;
     }
 
@@ -60,24 +62,24 @@
         }
     }
 
+    protected final IntegerConvertOp<OP> getOp(ValueNode forValue) {
+        return getOp.apply(ArithmeticOpTable.forStamp(forValue.stamp()));
+    }
+
     @Override
     public Constant convert(Constant c) {
-        return op.foldConstant(getInputBits(), getResultBits(), c);
+        return getOp(getValue()).foldConstant(getInputBits(), getResultBits(), c);
     }
 
     @Override
     public Constant reverse(Constant c) {
-        return reverseOp.foldConstant(getResultBits(), getInputBits(), c);
+        IntegerConvertOp<REV> reverse = getReverseOp.apply(ArithmeticOpTable.forStamp(stamp()));
+        return reverse.foldConstant(getResultBits(), getInputBits(), c);
     }
 
     @Override
     public boolean inferStamp() {
-        op = ArithmeticOpTable.forStamp(getValue().stamp()).getIntegerConvertOp(op);
-        boolean changed = updateStamp(op.foldStamp(resultBits, getValue().stamp()));
-        if (changed) {
-            reverseOp = ArithmeticOpTable.forStamp(stamp()).getIntegerConvertOp(reverseOp);
-        }
-        return changed;
+        return updateStamp(getOp(getValue()).foldStamp(resultBits, getValue().stamp()));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/MulNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/MulNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -25,6 +25,8 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Mul;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -32,14 +34,14 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "*")
-public class MulNode extends BinaryArithmeticNode implements NarrowableArithmeticNode {
+public class MulNode extends BinaryArithmeticNode<Mul> implements NarrowableArithmeticNode {
 
     public static MulNode create(ValueNode x, ValueNode y) {
         return USE_GENERATED_NODES ? new MulNodeGen(x, y) : new MulNode(x, y);
     }
 
     protected MulNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable.forStamp(x.stamp()).getMul(), x, y);
+        super(ArithmeticOpTable::getMul, x, y);
     }
 
     @Override
@@ -53,8 +55,9 @@
             return MulNode.create(forY, forX);
         }
         if (forY.isConstant()) {
+            BinaryOp<Mul> op = getOp(forX, forY);
             Constant c = forY.asConstant();
-            if (getOp().isNeutral(c)) {
+            if (op.isNeutral(c)) {
                 return forX;
             }
 
@@ -90,7 +93,7 @@
                 }
             }
 
-            if (getOp().isAssociative()) {
+            if (op.isAssociative()) {
                 // canonicalize expressions like "(a * 1) * 2"
                 return reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -23,6 +23,8 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -33,18 +35,14 @@
  * The {@code NarrowNode} converts an integer to a narrower integer.
  */
 @NodeInfo
-public class NarrowNode extends IntegerConvertNode {
+public class NarrowNode extends IntegerConvertNode<Narrow, SignExtend> {
 
     public static NarrowNode create(ValueNode input, int resultBits) {
         return USE_GENERATED_NODES ? new NarrowNodeGen(input, resultBits) : new NarrowNode(input, resultBits);
     }
 
-    private NarrowNode(ArithmeticOpTable ops, ValueNode input, int resultBits) {
-        super(ops.getNarrow(), ops.getSignExtend(), resultBits, input);
-    }
-
     protected NarrowNode(ValueNode input, int resultBits) {
-        this(ArithmeticOpTable.forStamp(input.stamp()), input, resultBits);
+        super(ArithmeticOpTable::getNarrow, ArithmeticOpTable::getSignExtend, resultBits, input);
     }
 
     @Override
@@ -66,7 +64,7 @@
             return NarrowNode.create(other.getValue(), getResultBits());
         } else if (forValue instanceof IntegerConvertNode) {
             // SignExtendNode or ZeroExtendNode
-            IntegerConvertNode other = (IntegerConvertNode) forValue;
+            IntegerConvertNode<?, ?> other = (IntegerConvertNode<?, ?>) forValue;
             if (getResultBits() == other.getInputBits()) {
                 // xxxx -(extend)-> yyyy xxxx -(narrow)-> xxxx
                 // ==> no-op
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp.Neg;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -33,7 +34,7 @@
  * The {@code NegateNode} node negates its operand.
  */
 @NodeInfo
-public class NegateNode extends UnaryArithmeticNode implements NarrowableArithmeticNode {
+public class NegateNode extends UnaryArithmeticNode<Neg> implements NarrowableArithmeticNode {
 
     /**
      * Creates new NegateNode instance.
@@ -45,7 +46,7 @@
     }
 
     protected NegateNode(ValueNode value) {
-        super(ArithmeticOpTable.forStamp(value.stamp()).getNeg(), value);
+        super(ArithmeticOpTable::getNeg, value);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp.Not;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -33,7 +34,7 @@
  * Binary negation of long or integer values.
  */
 @NodeInfo
-public class NotNode extends UnaryArithmeticNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
+public class NotNode extends UnaryArithmeticNode<Not> implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
 
     /**
      * Creates new NotNode instance.
@@ -45,7 +46,7 @@
     }
 
     protected NotNode(ValueNode x) {
-        super(ArithmeticOpTable.forStamp(x.stamp()).getNot(), x);
+        super(ArithmeticOpTable::getNot, x);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Or;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -33,14 +34,14 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "|")
-public class OrNode extends BinaryArithmeticNode {
+public class OrNode extends BinaryArithmeticNode<Or> {
 
     public static OrNode create(ValueNode x, ValueNode y) {
         return USE_GENERATED_NODES ? new OrNodeGen(x, y) : new OrNode(x, y);
     }
 
     protected OrNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable.forStamp(x.stamp()).getOr(), x, y);
+        super(ArithmeticOpTable::getOr, x, y);
     }
 
     @Override
@@ -58,7 +59,7 @@
         }
         if (forY.isConstant()) {
             Constant c = forY.asConstant();
-            if (getOp().isNeutral(c)) {
+            if (getOp(forX, forY).isNeutral(c)) {
                 return forX;
             }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RemNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RemNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -23,20 +23,21 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Rem;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "%")
-public class RemNode extends BinaryArithmeticNode implements Lowerable {
+public class RemNode extends BinaryArithmeticNode<Rem> implements Lowerable {
 
     public static RemNode create(ValueNode x, ValueNode y) {
         return USE_GENERATED_NODES ? new RemNodeGen(x, y) : new RemNode(x, y);
     }
 
     protected RemNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable.forStamp(x.stamp()).getRem(), x, y);
+        super(ArithmeticOpTable::getRem, x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -23,6 +23,8 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -33,18 +35,14 @@
  * The {@code SignExtendNode} converts an integer to a wider integer using sign extension.
  */
 @NodeInfo
-public class SignExtendNode extends IntegerConvertNode {
+public class SignExtendNode extends IntegerConvertNode<SignExtend, Narrow> {
 
     public static SignExtendNode create(ValueNode input, int resultBits) {
         return USE_GENERATED_NODES ? new SignExtendNodeGen(input, resultBits) : new SignExtendNode(input, resultBits);
     }
 
-    private SignExtendNode(ArithmeticOpTable ops, ValueNode input, int resultBits) {
-        super(ops.getSignExtend(), ops.getNarrow(), resultBits, input);
-    }
-
     protected SignExtendNode(ValueNode input, int resultBits) {
-        this(ArithmeticOpTable.forStamp(input.stamp()), input, resultBits);
+        super(ArithmeticOpTable::getSignExtend, ArithmeticOpTable::getNarrow, resultBits, input);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SubNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SubNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -24,6 +24,8 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Sub;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -32,14 +34,14 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "-")
-public class SubNode extends BinaryArithmeticNode implements NarrowableArithmeticNode {
+public class SubNode extends BinaryArithmeticNode<Sub> implements NarrowableArithmeticNode {
 
     public static SubNode create(ValueNode x, ValueNode y) {
         return USE_GENERATED_NODES ? new SubNodeGen(x, y) : new SubNode(x, y);
     }
 
     protected SubNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable.forStamp(x.stamp()).getSub(), x, y);
+        super(ArithmeticOpTable::getSub, x, y);
     }
 
     @SuppressWarnings("hiding")
@@ -50,13 +52,14 @@
             return ret;
         }
 
+        BinaryOp<Sub> op = getOp(forX, forY);
         if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
-            Constant zero = getOp().getZero(forX.stamp());
+            Constant zero = op.getZero(forX.stamp());
             if (zero != null) {
                 return ConstantNode.forPrimitive(stamp(), zero);
             }
         }
-        boolean associative = getOp().isAssociative();
+        boolean associative = op.isAssociative();
         if (associative) {
             if (forX instanceof AddNode) {
                 AddNode x = (AddNode) forX;
@@ -95,7 +98,7 @@
         }
         if (forY.isConstant()) {
             Constant c = forY.asConstant();
-            if (getOp().isNeutral(c)) {
+            if (op.isNeutral(c)) {
                 return forX;
             }
             if (associative) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnaryArithmeticNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnaryArithmeticNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import java.util.function.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp;
@@ -31,34 +33,33 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public abstract class UnaryArithmeticNode extends UnaryNode implements ArithmeticLIRLowerable {
+public abstract class UnaryArithmeticNode<OP> extends UnaryNode implements ArithmeticLIRLowerable {
 
-    protected UnaryOp op;
+    protected final Function<ArithmeticOpTable, UnaryOp<OP>> getOp;
 
-    protected UnaryArithmeticNode(UnaryOp op, ValueNode value) {
-        super(op.foldStamp(value.stamp()), value);
-        this.op = op;
+    protected UnaryArithmeticNode(Function<ArithmeticOpTable, UnaryOp<OP>> getOp, ValueNode value) {
+        super(getOp.apply(ArithmeticOpTable.forStamp(value.stamp())).foldStamp(value.stamp()), value);
+        this.getOp = getOp;
     }
 
-    public UnaryOp getOp() {
-        return op;
+    protected final UnaryOp<OP> getOp(ValueNode forValue) {
+        return getOp.apply(ArithmeticOpTable.forStamp(forValue.stamp()));
     }
 
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 1;
-        return op.foldConstant(inputs[0]);
+        return getOp(getValue()).foldConstant(inputs[0]);
     }
 
     @Override
     public boolean inferStamp() {
-        op = ArithmeticOpTable.forStamp(getValue().stamp()).getUnaryOp(op);
-        return updateStamp(op.foldStamp(getValue().stamp()));
+        return updateStamp(getOp(getValue()).foldStamp(getValue().stamp()));
     }
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
         if (forValue.isConstant()) {
-            return ConstantNode.forPrimitive(stamp(), op.foldConstant(forValue.asConstant()));
+            return ConstantNode.forPrimitive(stamp(), getOp(forValue).foldConstant(forValue.asConstant()));
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Xor;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -33,14 +34,14 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "^")
-public class XorNode extends BinaryArithmeticNode {
+public class XorNode extends BinaryArithmeticNode<Xor> {
 
     public static XorNode create(ValueNode x, ValueNode y) {
         return USE_GENERATED_NODES ? new XorNodeGen(x, y) : new XorNode(x, y);
     }
 
     protected XorNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable.forStamp(x.stamp()).getXor(), x, y);
+        super(ArithmeticOpTable::getXor, x, y);
         assert x.stamp().isCompatible(y.stamp());
     }
 
@@ -52,14 +53,14 @@
         }
 
         if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
-            return ConstantNode.forPrimitive(stamp(), getOp().getZero(forX.stamp()));
+            return ConstantNode.forPrimitive(stamp(), getOp(forX, forY).getZero(forX.stamp()));
         }
         if (forX.isConstant() && !forY.isConstant()) {
             return XorNode.create(forY, forX);
         }
         if (forY.isConstant()) {
             Constant c = forY.asConstant();
-            if (getOp().isNeutral(c)) {
+            if (getOp(forX, forY).isNeutral(c)) {
                 return forX;
             }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -25,6 +25,8 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.ZeroExtend;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -35,18 +37,14 @@
  * The {@code ZeroExtendNode} converts an integer to a wider integer using zero extension.
  */
 @NodeInfo
-public class ZeroExtendNode extends IntegerConvertNode {
+public class ZeroExtendNode extends IntegerConvertNode<ZeroExtend, Narrow> {
 
     public static ZeroExtendNode create(ValueNode input, int resultBits) {
         return USE_GENERATED_NODES ? new ZeroExtendNodeGen(input, resultBits) : new ZeroExtendNode(input, resultBits);
     }
 
-    private ZeroExtendNode(ArithmeticOpTable ops, ValueNode input, int resultBits) {
-        super(ops.getZeroExtend(), ops.getNarrow(), resultBits, input);
-    }
-
     protected ZeroExtendNode(ValueNode input, int resultBits) {
-        this(ArithmeticOpTable.forStamp(input.stamp()), input, resultBits);
+        super(ArithmeticOpTable::getZeroExtend, ArithmeticOpTable::getNarrow, resultBits, input);
     }
 
     @Override
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java	Mon Oct 13 18:04:50 2014 +0100
@@ -182,10 +182,10 @@
 
             Arguments args = new Arguments(key, graph.getGuardsStage(), tool.getLoweringStage());
             args.add("input", convert.getValue());
-            args.add("result", graph.unique(AMD64FloatConvertNode.create(convert.getOp(), convert.getValue())));
+            args.add("result", graph.unique(AMD64FloatConvertNode.create(convert.getFloatConvert(), convert.getValue())));
 
             SnippetTemplate template = template(args);
-            Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.getOp(), graph, convert, template, args);
+            Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.getFloatConvert(), graph, convert, template, args);
             template.instantiate(providers.getMetaAccess(), convert, DEFAULT_REPLACER, tool, args);
             graph.removeFloating(convert);
         }
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -24,8 +24,8 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.FloatConvertOp;
-import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -39,14 +39,17 @@
  * fixup code that handles the corner cases that differ between AMD64 and Java.
  */
 @NodeInfo
-public class AMD64FloatConvertNode extends UnaryArithmeticNode implements ArithmeticLIRLowerable {
+public class AMD64FloatConvertNode extends UnaryArithmeticNode<FloatConvertOp> implements ArithmeticLIRLowerable {
 
-    public static AMD64FloatConvertNode create(UnaryOp op, ValueNode value) {
+    protected final FloatConvert op;
+
+    public static AMD64FloatConvertNode create(FloatConvert op, ValueNode value) {
         return USE_GENERATED_NODES ? new AMD64FloatConvertNodeGen(op, value) : new AMD64FloatConvertNode(op, value);
     }
 
-    protected AMD64FloatConvertNode(UnaryOp op, ValueNode value) {
-        super(op, value);
+    protected AMD64FloatConvertNode(FloatConvert op, ValueNode value) {
+        super(table -> table.getFloatConvert(op), value);
+        this.op = op;
     }
 
     @Override
@@ -62,6 +65,6 @@
     }
 
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitFloatConvert(((FloatConvertOp) getOp()).getFloatConvert(), builder.operand(getValue())));
+        builder.setResult(this, gen.emitFloatConvert(op, builder.operand(getValue())));
     }
 }
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Mon Oct 13 18:04:50 2014 +0100
@@ -113,8 +113,7 @@
         } else {
             compilationPolicy = new InterpreterOnlyCompilationPolicy();
         }
-        OptimizedCallTarget target = new OptimizedCallTarget(rootNode, this, TruffleMinInvokeThreshold.getValue(), TruffleCompilationThreshold.getValue(), compilationPolicy,
-                        new HotSpotSpeculationLog());
+        OptimizedCallTarget target = new OptimizedCallTarget(rootNode, this, compilationPolicy, new HotSpotSpeculationLog());
         callTargets.put(target, null);
         return target;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java	Mon Oct 13 18:04:50 2014 +0100
@@ -33,25 +33,14 @@
      */
     private int invalidationCount;
 
-    /**
-     * Number of times a node was replaced in this tree.
-     */
-    private int nodeReplaceCount;
-
-    private long previousTimestamp;
-
     private int interpreterCallCount;
     private int interpreterCallAndLoopCount;
     private int compilationCallThreshold;
     private int compilationCallAndLoopThreshold;
 
-    private final int originalCompilationThreshold;
-
-    public CompilationProfile(final int compilationThreshold, final int initialInvokeCounter) {
-        this.previousTimestamp = System.nanoTime();
-        this.compilationCallThreshold = initialInvokeCounter;
-        this.compilationCallAndLoopThreshold = compilationThreshold;
-        this.originalCompilationThreshold = compilationThreshold;
+    public CompilationProfile() {
+        this.compilationCallThreshold = TruffleMinInvokeThreshold.getValue();
+        this.compilationCallAndLoopThreshold = TruffleCompilationThreshold.getValue();
     }
 
     @Override
@@ -64,25 +53,17 @@
         Map<String, Object> properties = new LinkedHashMap<>();
         String callsThreshold = String.format("%7d/%5d", getInterpreterCallCount(), getCompilationCallThreshold());
         String loopsThreshold = String.format("%7d/%5d", getInterpreterCallAndLoopCount(), getCompilationCallAndLoopThreshold());
-        String invalidationReplace = String.format("%5d/%5d", invalidationCount, nodeReplaceCount);
+        String invalidations = String.format("%5d", invalidationCount);
         properties.put("C/T", callsThreshold);
         properties.put("L/T", loopsThreshold);
-        properties.put("Inval#/Replace#", invalidationReplace);
+        properties.put("Inval#", invalidations);
         return properties;
     }
 
-    public long getPreviousTimestamp() {
-        return previousTimestamp;
-    }
-
     public int getInvalidationCount() {
         return invalidationCount;
     }
 
-    public int getNodeReplaceCount() {
-        return nodeReplaceCount;
-    }
-
     public int getInterpreterCallAndLoopCount() {
         return interpreterCallAndLoopCount;
     }
@@ -111,11 +92,6 @@
         }
     }
 
-    void reportTiminingFailed(long timestamp) {
-        ensureProfiling(0, originalCompilationThreshold);
-        this.previousTimestamp = timestamp;
-    }
-
     public void reportInvalidated() {
         invalidationCount++;
         int reprofile = TruffleInvalidationReprofileCount.getValue();
@@ -144,7 +120,6 @@
     }
 
     void reportNodeReplaced() {
-        nodeReplaceCount++;
         // delay compilation until tree is deemed stable enough
         int replaceBackoff = TruffleReplaceReprofileCount.getValue();
         ensureProfiling(1, replaceBackoff);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Mon Oct 13 18:04:50 2014 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -72,7 +72,7 @@
         return rootNode;
     }
 
-    public OptimizedCallTarget(RootNode rootNode, GraalTruffleRuntime runtime, int invokeCounter, int compilationThreshold, CompilationPolicy compilationPolicy, SpeculationLog speculationLog) {
+    public OptimizedCallTarget(RootNode rootNode, GraalTruffleRuntime runtime, CompilationPolicy compilationPolicy, SpeculationLog speculationLog) {
         super(rootNode.toString());
         this.runtime = runtime;
         this.speculationLog = speculationLog;
@@ -81,9 +81,9 @@
         this.rootNode.setCallTarget(this);
         this.compilationPolicy = compilationPolicy;
         if (TruffleCallTargetProfiling.getValue()) {
-            this.compilationProfile = new TraceCompilationProfile(compilationThreshold, invokeCounter);
+            this.compilationProfile = new TraceCompilationProfile();
         } else {
-            this.compilationProfile = new CompilationProfile(compilationThreshold, invokeCounter);
+            this.compilationProfile = new CompilationProfile();
         }
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java	Mon Oct 13 18:04:50 2014 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallUtils.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallUtils.java	Mon Oct 13 18:04:50 2014 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TraceCompilationProfile.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TraceCompilationProfile.java	Mon Oct 13 18:04:50 2014 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,10 +28,6 @@
     private int indirectCallCount;
     private int inlinedCallCount;
 
-    public TraceCompilationProfile(int compilationThreshold, int initialInvokeCounter) {
-        super(compilationThreshold, initialInvokeCounter);
-    }
-
     @Override
     public void reportIndirectCall() {
         indirectCallCount++;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java	Mon Oct 13 18:04:50 2014 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningDecision.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningDecision.java	Mon Oct 13 18:04:50 2014 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Mon Oct 13 18:04:50 2014 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/BranchProfileTest.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/BranchProfileTest.java	Mon Oct 13 18:04:50 2014 +0100
@@ -32,14 +32,14 @@
 
     @Test
     public void testEnter() {
-        BranchProfile profile = new BranchProfile();
+        BranchProfile profile = BranchProfile.create();
         profile.enter();
         profile.enter();
     }
 
     @Test
     public void testToString() {
-        BranchProfile profile = new BranchProfile();
+        BranchProfile profile = BranchProfile.create();
         assertTrue(profile.toString().contains(profile.getClass().getSimpleName()));
         assertTrue(profile.toString().contains("not-visited"));
         assertTrue(profile.toString().contains(Integer.toHexString(profile.hashCode())));
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/BranchProfile.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/BranchProfile.java	Mon Oct 13 18:04:50 2014 +0100
@@ -40,6 +40,9 @@
 
     @CompilationFinal private boolean visited;
 
+    private BranchProfile() {
+    }
+
     public void enter() {
         if (!visited) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
@@ -51,6 +54,10 @@
         return visited;
     }
 
+    public static BranchProfile create() {
+        return new BranchProfile();
+    }
+
     @Override
     public String toString() {
         return String.format("%s(%s)@%x", getClass().getSimpleName(), visited ? "visited" : "not-visited", hashCode());
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -47,8 +47,8 @@
      * {@link SLReturnNode explicit return statement}. This allows the compiler to generate better
      * code.
      */
-    private final BranchProfile exceptionTaken = new BranchProfile();
-    private final BranchProfile nullTaken = new BranchProfile();
+    private final BranchProfile exceptionTaken = BranchProfile.create();
+    private final BranchProfile nullTaken = BranchProfile.create();
 
     public SLFunctionBodyNode(SourceSection src, SLStatementNode bodyNode) {
         super(src);
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLRepeatingNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLRepeatingNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -46,8 +46,8 @@
      * statement was used in this loop. This allows the compiler to generate better code for loops
      * without a {@code continue}.
      */
-    private final BranchProfile continueTaken = new BranchProfile();
-    private final BranchProfile breakTaken = new BranchProfile();
+    private final BranchProfile continueTaken = BranchProfile.create();
+    private final BranchProfile breakTaken = BranchProfile.create();
 
     public SLRepeatingNode(SourceSection src, SLExpressionNode conditionNode, SLStatementNode bodyNode) {
         super(src);
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadArgumentNode.java	Mon Oct 13 18:04:01 2014 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadArgumentNode.java	Mon Oct 13 18:04:50 2014 +0100
@@ -45,7 +45,7 @@
      * Profiling information, collected by the interpreter, capturing whether the function was
      * called with fewer actual arguments than formal arguments.
      */
-    private final BranchProfile outOfBoundsTaken = new BranchProfile();
+    private final BranchProfile outOfBoundsTaken = BranchProfile.create();
 
     public SLReadArgumentNode(SourceSection src, int index) {
         super(src);