changeset 17323:5d4749f9c5f6

merge
author Josef Eisl <josef.eisl@jku.at>
date Fri, 03 Oct 2014 13:48:58 +0200
parents 8a2a809110ba (current diff) 95b879bdce67 (diff)
children 012277a579ca
files graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest3.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InstructionValueProcedureBase.java
diffstat 266 files changed, 3571 insertions(+), 2641 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGELOG.md	Fri Oct 03 11:07:44 2014 +0200
+++ b/CHANGELOG.md	Fri Oct 03 13:48:58 2014 +0200
@@ -6,6 +6,7 @@
 * ...
 
 ### Truffle
+* Relaxed declared type restriction on child fields to allow for interface types in addition to Node subclasses.
 * ...
 
 ## Version 0.5
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Fri Oct 03 13:48:58 2014 +0200
@@ -595,10 +595,7 @@
 
     @Override
     protected Value appendConstant(Constant constant) {
-        if (gen.canInlineConstant(constant)) {
-            return constant;
-        }
-        return gen.emitMove(constant);
+        return gen.emitLoadConstant(constant);
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri Oct 03 13:48:58 2014 +0200
@@ -93,21 +93,6 @@
     }
 
     @Override
-    public boolean canStoreConstant(Constant c) {
-        // there is no immediate move of 64-bit constants on Intel
-        switch (c.getKind()) {
-            case Long:
-                return Util.isInt(c.asLong()) && !getCodeCache().needsDataPatch(c);
-            case Double:
-                return false;
-            case Object:
-                return c.isNull();
-            default:
-                return true;
-        }
-    }
-
-    @Override
     public boolean canInlineConstant(Constant c) {
         switch (c.getKind()) {
             case Long:
@@ -119,13 +104,6 @@
         }
     }
 
-    @Override
-    public Variable emitMove(Value input) {
-        Variable result = newVariable(input.getLIRKind());
-        emitMove(result, input);
-        return result;
-    }
-
     protected AMD64LIRInstruction createMove(AllocatableValue dst, Value src) {
         if (src instanceof AMD64AddressValue) {
             return new LeaOp(dst, (AMD64AddressValue) src);
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Fri Oct 03 13:48:58 2014 +0200
@@ -47,9 +47,11 @@
     protected static final ConcurrentHashMap<Class<?>, FieldIntrospection> allClasses = new ConcurrentHashMap<>();
 
     private final Class<?> clazz;
-    protected long[] dataOffsets;
-    protected Map<Long, String> fieldNames;
-    protected Map<Long, Class<?>> fieldTypes;
+
+    /**
+     * The set of fields in {@link #clazz} that do long belong to a more specific category.
+     */
+    protected Fields data;
 
     public FieldIntrospection(Class<?> clazz) {
         this.clazz = clazz;
@@ -59,90 +61,71 @@
         return clazz;
     }
 
+    /**
+     * Gets the fields in {@link #getClazz()} that do long belong to specific category.
+     */
+    public Fields getData() {
+        return data;
+    }
+
+    /**
+     * Describes a field in a class during scanning.
+     */
+    public static class FieldInfo implements Comparable<FieldInfo> {
+        public final long offset;
+        public final String name;
+        public final Class<?> type;
+
+        public FieldInfo(long offset, String name, Class<?> type) {
+            this.offset = offset;
+            this.name = name;
+            this.type = type;
+        }
+
+        /**
+         * Sorts fields in ascending order by their {@link #offset}s.
+         */
+        public int compareTo(FieldInfo o) {
+            return offset < o.offset ? -1 : (offset > o.offset ? 1 : 0);
+        }
+
+        @Override
+        public String toString() {
+            return "[" + offset + "]" + name + ":" + type.getSimpleName();
+        }
+    }
+
     public abstract static class BaseFieldScanner {
 
         private final CalcOffset calc;
 
-        /** The offsets of fields that are not specially handled by subclasses. */
-        public final ArrayList<Long> dataOffsets = new ArrayList<>();
-
-        public final Map<Long, String> fieldNames = new HashMap<>();
-        public final Map<Long, Class<?>> fieldTypes = new HashMap<>();
+        /**
+         * Fields not belonging to a more specific category defined by scanner subclasses are added
+         * to this list.
+         */
+        public final ArrayList<FieldInfo> data = new ArrayList<>();
 
         protected BaseFieldScanner(CalcOffset calc) {
             this.calc = calc;
         }
 
-        public void scan(Class<?> clazz) {
+        /**
+         * Scans the fields in a class hierarchy.
+         */
+        public void scan(Class<?> clazz, boolean includeSuperclasses) {
             Class<?> currentClazz = clazz;
             do {
                 for (Field field : currentClazz.getDeclaredFields()) {
                     if (Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())) {
                         continue;
                     }
-                    Class<?> type = field.getType();
                     long offset = calc.getOffset(field);
-
-                    // scanField() may overwrite the name with a customized name.
-                    fieldNames.put(offset, field.getName());
-                    fieldTypes.put(offset, type);
-
-                    scanField(field, type, offset);
+                    scanField(field, offset);
                 }
                 currentClazz = currentClazz.getSuperclass();
-            } while (currentClazz.getSuperclass() != Object.class);
+            } while (includeSuperclasses && currentClazz.getSuperclass() != Object.class);
         }
 
-        protected abstract void scanField(Field field, Class<?> type, long offset);
-    }
-
-    protected static void copyInto(long[] dest, long[] src) {
-        assert dest.length == src.length;
-        for (int i = 0; i < dest.length; i++) {
-            dest[i] = src[i];
-        }
-    }
-
-    protected static <T> void copyInto(T[] dest, T[] src) {
-        assert dest.length == src.length;
-        for (int i = 0; i < dest.length; i++) {
-            dest[i] = src[i];
-        }
-    }
-
-    protected static <T> void copyInto(T[] dest, List<T> src) {
-        assert dest.length == src.size();
-        for (int i = 0; i < dest.length; i++) {
-            dest[i] = src.get(i);
-        }
-    }
-
-    protected static <T> T[] arrayUsingSortedOffsets(Map<Long, T> map, long[] sortedOffsets, T[] result) {
-        for (int i = 0; i < sortedOffsets.length; i++) {
-            result[i] = map.get(sortedOffsets[i]);
-        }
-        return result;
-    }
-
-    protected static long[] sortedLongCopy(ArrayList<Long> list1) {
-        Collections.sort(list1);
-        long[] result = new long[list1.size()];
-        for (int i = 0; i < list1.size(); i++) {
-            result[i] = list1.get(i);
-        }
-        return result;
-    }
-
-    protected static long[] sortedLongCopy(ArrayList<Long> list1, ArrayList<Long> list2) {
-        Collections.sort(list1);
-        Collections.sort(list2);
-        long[] result = new long[list1.size() + list2.size()];
-        for (int i = 0; i < list1.size(); i++) {
-            result[i] = list1.get(i);
-        }
-        for (int i = 0; i < list2.size(); i++) {
-            result[list1.size() + i] = list2.get(i);
-        }
-        return result;
+        protected abstract void scanField(Field field, long offset);
     }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java	Fri Oct 03 13:48:58 2014 +0200
@@ -28,25 +28,39 @@
 
 import sun.misc.*;
 
+import com.oracle.graal.compiler.common.FieldIntrospection.FieldInfo;
+
 /**
  * Describes fields in a class, primarily for access via {@link Unsafe}.
  */
 public class Fields {
 
-    protected final Class<?> clazz;
+    /**
+     * Offsets used with {@link Unsafe} to access the fields.
+     */
     protected final long[] offsets;
+
+    /**
+     * The names of the fields.
+     */
     private final String[] names;
+
+    /**
+     * The types of the fields.
+     */
     private final Class<?>[] types;
 
-    public Fields(Class<?> clazz, long[] offsets, Map<Long, String> names, Map<Long, Class<?>> types) {
-        this.clazz = clazz;
-        this.offsets = offsets;
-
+    public Fields(ArrayList<? extends FieldInfo> fields) {
+        Collections.sort(fields);
+        this.offsets = new long[fields.size()];
         this.names = new String[offsets.length];
         this.types = new Class[offsets.length];
-        for (int i = 0; i < offsets.length; i++) {
-            this.names[i] = names.get(offsets[i]);
-            this.types[i] = types.get(offsets[i]);
+        int index = 0;
+        for (FieldInfo f : fields) {
+            offsets[index] = f.offset;
+            names[index] = f.name;
+            types[index] = f.type;
+            index++;
         }
     }
 
@@ -57,6 +71,12 @@
         return offsets.length;
     }
 
+    public static void translateInto(Fields fields, ArrayList<FieldInfo> infos) {
+        for (int index = 0; index < fields.getCount(); index++) {
+            infos.add(new FieldInfo(fields.offsets[index], fields.names[index], fields.types[index]));
+        }
+    }
+
     /**
      * Gets the value of a field for a given object.
      *
@@ -126,44 +146,46 @@
      * @param index the index of the field to check
      * @param value a value that will be assigned to the field
      */
-    private boolean checkAssignableFrom(int index, Object value) {
-        assert value == null || getType(index).isAssignableFrom(value.getClass()) : String.format("%s.%s of type %s is not assignable from %s", clazz.getSimpleName(), getName(index),
-                        getType(index).getSimpleName(), value.getClass().getSimpleName());
+    private boolean checkAssignableFrom(Object object, int index, Object value) {
+        assert value == null || getType(index).isAssignableFrom(value.getClass()) : String.format("Field %s.%s of type %s is not assignable from %s", object.getClass().getSimpleName(),
+                        getName(index), getType(index).getSimpleName(), value.getClass().getSimpleName());
         return true;
     }
 
     public void set(Object object, int index, Object value) {
-        long dataOffset = offsets[index];
+        long offset = offsets[index];
         Class<?> type = types[index];
         if (type.isPrimitive()) {
             if (type == Integer.TYPE) {
-                unsafe.putInt(object, dataOffset, (Integer) value);
+                unsafe.putInt(object, offset, (Integer) value);
             } else if (type == Long.TYPE) {
-                unsafe.putLong(object, dataOffset, (Long) value);
+                unsafe.putLong(object, offset, (Long) value);
             } else if (type == Boolean.TYPE) {
-                unsafe.putBoolean(object, dataOffset, (Boolean) value);
+                unsafe.putBoolean(object, offset, (Boolean) value);
             } else if (type == Float.TYPE) {
-                unsafe.putFloat(object, dataOffset, (Float) value);
+                unsafe.putFloat(object, offset, (Float) value);
             } else if (type == Double.TYPE) {
-                unsafe.putDouble(object, dataOffset, (Double) value);
+                unsafe.putDouble(object, offset, (Double) value);
             } else if (type == Short.TYPE) {
-                unsafe.putShort(object, dataOffset, (Short) value);
+                unsafe.putShort(object, offset, (Short) value);
             } else if (type == Character.TYPE) {
-                unsafe.putChar(object, dataOffset, (Character) value);
+                unsafe.putChar(object, offset, (Character) value);
             } else if (type == Byte.TYPE) {
-                unsafe.putByte(object, dataOffset, (Byte) value);
+                unsafe.putByte(object, offset, (Byte) value);
             } else {
                 assert false : "unhandled property type: " + type;
             }
         } else {
-            assert checkAssignableFrom(index, value);
-            unsafe.putObject(object, dataOffset, value);
+            assert checkAssignableFrom(object, index, value);
+            unsafe.putObject(object, offset, value);
         }
     }
 
     @Override
     public String toString() {
-        return clazz.getSimpleName();
+        StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('[');
+        appendFields(sb);
+        return sb.append(']').toString();
     }
 
     public void appendFields(StringBuilder sb) {
@@ -216,4 +238,9 @@
         assert !types[i].isPrimitive();
         return unsafe.getObject(object, offsets[i]);
     }
+
+    public void putObject(Object object, int i, Object value) {
+        assert checkAssignableFrom(object, i, value);
+        unsafe.putObject(object, offsets[i], value);
+    }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java	Fri Oct 03 13:48:58 2014 +0200
@@ -23,27 +23,124 @@
 package com.oracle.graal.compiler.common.type;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
 
 /**
  * Information about arithmetic operations.
  */
 public final class ArithmeticOpTable {
 
-    protected UnaryOp neg;
-    protected BinaryOp add;
-    protected BinaryOp sub;
+    private final UnaryOp neg;
+    private final BinaryOp add;
+    private final BinaryOp sub;
 
-    protected BinaryOp mul;
-    protected BinaryOp div;
-    protected BinaryOp rem;
+    private final BinaryOp mul;
+    private final BinaryOp div;
+    private final BinaryOp rem;
 
-    protected UnaryOp not;
-    protected BinaryOp and;
-    protected BinaryOp or;
-    protected BinaryOp xor;
+    private final UnaryOp not;
+    private final BinaryOp and;
+    private final BinaryOp or;
+    private final BinaryOp xor;
 
     public static ArithmeticOpTable forStamp(Stamp s) {
-        return ((ArithmeticStamp) s).getOps();
+        if (s instanceof ArithmeticStamp) {
+            return ((ArithmeticStamp) s).getOps();
+        } else {
+            return EMPTY;
+        }
+    }
+
+    public static final ArithmeticOpTable EMPTY = create();
+
+    public static ArithmeticOpTable create(Op... ops) {
+        UnaryOp neg = null;
+        BinaryOp add = null;
+        BinaryOp sub = null;
+
+        BinaryOp mul = null;
+        BinaryOp div = null;
+        BinaryOp rem = null;
+
+        UnaryOp not = null;
+        BinaryOp and = null;
+        BinaryOp or = null;
+        BinaryOp xor = null;
+
+        for (Op op : ops) {
+            if (op == null) {
+                continue;
+            }
+
+            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 {
+                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());
+                }
+            }
+        }
+
+        return new ArithmeticOpTable(neg, add, sub, mul, div, rem, not, and, or, xor);
+    }
+
+    private ArithmeticOpTable(UnaryOp neg, BinaryOp add, BinaryOp sub, BinaryOp mul, BinaryOp div, BinaryOp rem, UnaryOp not, BinaryOp and, BinaryOp or, BinaryOp xor) {
+        this.neg = neg;
+        this.add = add;
+        this.sub = sub;
+        this.mul = mul;
+        this.div = div;
+        this.rem = rem;
+        this.not = not;
+        this.and = and;
+        this.or = or;
+        this.xor = xor;
     }
 
     /**
@@ -116,10 +213,32 @@
         return xor;
     }
 
+    public abstract static class Op {
+
+        private final char operator;
+
+        protected Op(char operator) {
+            this.operator = operator;
+        }
+
+        public char getOperator() {
+            return operator;
+        }
+
+        @Override
+        public String toString() {
+            return Character.toString(operator);
+        }
+    }
+
     /**
      * Describes a unary arithmetic operation.
      */
-    public abstract static class UnaryOp {
+    public abstract static class UnaryOp extends Op {
+
+        protected UnaryOp(char operation) {
+            super(operation);
+        }
 
         /**
          * Apply the operation to a {@link Constant}.
@@ -135,12 +254,13 @@
     /**
      * Describes a binary arithmetic operation.
      */
-    public abstract static class BinaryOp {
+    public abstract static class BinaryOp extends Op {
 
         private final boolean associative;
         private final boolean commutative;
 
-        protected BinaryOp(boolean associative, boolean commutative) {
+        protected BinaryOp(char operation, boolean associative, boolean commutative) {
+            super(operation);
             this.associative = associative;
             this.commutative = commutative;
         }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Fri Oct 03 13:48:58 2014 +0200
@@ -252,188 +252,184 @@
         return null;
     }
 
-    private static final ArithmeticOpTable OPS = new ArithmeticOpTable();
+    private static final ArithmeticOpTable OPS = ArithmeticOpTable.create(
 
-    static {
-        OPS.neg = new UnaryOp() {
+    new UnaryOp('-') {
 
-            @Override
-            public Constant foldConstant(Constant value) {
-                switch (value.getKind()) {
-                    case Float:
-                        return Constant.forFloat(-value.asFloat());
-                    case Double:
-                        return Constant.forDouble(-value.asDouble());
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
-            }
-
-            @Override
-            public Stamp foldStamp(Stamp s) {
-                FloatStamp stamp = (FloatStamp) s;
-                return new FloatStamp(stamp.getBits(), -stamp.upperBound(), -stamp.lowerBound(), stamp.isNonNaN());
+        @Override
+        public Constant foldConstant(Constant value) {
+            switch (value.getKind()) {
+                case Float:
+                    return Constant.forFloat(-value.asFloat());
+                case Double:
+                    return Constant.forDouble(-value.asDouble());
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
-        };
+        }
 
-        OPS.add = new BinaryOp(false, true) {
+        @Override
+        public Stamp foldStamp(Stamp s) {
+            FloatStamp stamp = (FloatStamp) s;
+            return new FloatStamp(stamp.getBits(), -stamp.upperBound(), -stamp.lowerBound(), stamp.isNonNaN());
+        }
+    },
+
+    new BinaryOp('+', false, true) {
 
-            @Override
-            public Constant foldConstant(Constant a, Constant b) {
-                assert a.getKind() == b.getKind();
-                switch (a.getKind()) {
-                    case Float:
-                        return Constant.forFloat(a.asFloat() + b.asFloat());
-                    case Double:
-                        return Constant.forDouble(a.asDouble() + b.asDouble());
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
+        @Override
+        public Constant foldConstant(Constant a, Constant b) {
+            assert a.getKind() == b.getKind();
+            switch (a.getKind()) {
+                case Float:
+                    return Constant.forFloat(a.asFloat() + b.asFloat());
+                case Double:
+                    return Constant.forDouble(a.asDouble() + b.asDouble());
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
+        }
 
-            @Override
-            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
-                // TODO
-                return stamp1.unrestricted();
-            }
+        @Override
+        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+            // TODO
+            return stamp1.unrestricted();
+        }
 
-            @Override
-            public boolean isNeutral(Constant n) {
-                switch (n.getKind()) {
-                    case Float:
-                        return Float.compare(n.asFloat(), -0.0f) == 0;
-                    case Double:
-                        return Double.compare(n.asDouble(), -0.0) == 0;
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
+        @Override
+        public boolean isNeutral(Constant n) {
+            switch (n.getKind()) {
+                case Float:
+                    return Float.compare(n.asFloat(), -0.0f) == 0;
+                case Double:
+                    return Double.compare(n.asDouble(), -0.0) == 0;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
-        };
+        }
+    },
 
-        OPS.sub = new BinaryOp(false, false) {
+    new BinaryOp('-', false, false) {
 
-            @Override
-            public Constant foldConstant(Constant a, Constant b) {
-                assert a.getKind() == b.getKind();
-                switch (a.getKind()) {
-                    case Float:
-                        return Constant.forFloat(a.asFloat() - b.asFloat());
-                    case Double:
-                        return Constant.forDouble(a.asDouble() - b.asDouble());
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
+        @Override
+        public Constant foldConstant(Constant a, Constant b) {
+            assert a.getKind() == b.getKind();
+            switch (a.getKind()) {
+                case Float:
+                    return Constant.forFloat(a.asFloat() - b.asFloat());
+                case Double:
+                    return Constant.forDouble(a.asDouble() - b.asDouble());
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
+        }
 
-            @Override
-            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
-                // TODO
-                return stamp1.unrestricted();
-            }
+        @Override
+        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+            // TODO
+            return stamp1.unrestricted();
+        }
 
-            @Override
-            public boolean isNeutral(Constant n) {
-                switch (n.getKind()) {
-                    case Float:
-                        return Float.compare(n.asFloat(), 0.0f) == 0;
-                    case Double:
-                        return Double.compare(n.asDouble(), 0.0) == 0;
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
+        @Override
+        public boolean isNeutral(Constant n) {
+            switch (n.getKind()) {
+                case Float:
+                    return Float.compare(n.asFloat(), 0.0f) == 0;
+                case Double:
+                    return Double.compare(n.asDouble(), 0.0) == 0;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
-        };
+        }
+    },
 
-        OPS.mul = new BinaryOp(false, true) {
+    new BinaryOp('*', false, true) {
 
-            @Override
-            public Constant foldConstant(Constant a, Constant b) {
-                assert a.getKind() == b.getKind();
-                switch (a.getKind()) {
-                    case Float:
-                        return Constant.forFloat(a.asFloat() * b.asFloat());
-                    case Double:
-                        return Constant.forDouble(a.asDouble() * b.asDouble());
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
+        @Override
+        public Constant foldConstant(Constant a, Constant b) {
+            assert a.getKind() == b.getKind();
+            switch (a.getKind()) {
+                case Float:
+                    return Constant.forFloat(a.asFloat() * b.asFloat());
+                case Double:
+                    return Constant.forDouble(a.asDouble() * b.asDouble());
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
+        }
 
-            @Override
-            public Stamp foldStamp(Stamp a, Stamp b) {
-                // TODO
-                return a.unrestricted();
-            }
+        @Override
+        public Stamp foldStamp(Stamp a, Stamp b) {
+            // TODO
+            return a.unrestricted();
+        }
 
-            @Override
-            public boolean isNeutral(Constant n) {
-                switch (n.getKind()) {
-                    case Float:
-                        return Float.compare(n.asFloat(), 1.0f) == 0;
-                    case Double:
-                        return Double.compare(n.asDouble(), 1.0) == 0;
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
+        @Override
+        public boolean isNeutral(Constant n) {
+            switch (n.getKind()) {
+                case Float:
+                    return Float.compare(n.asFloat(), 1.0f) == 0;
+                case Double:
+                    return Double.compare(n.asDouble(), 1.0) == 0;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
+        }
+    },
 
-            // there is no multiplicative zero, since both 0.0 and -0.0 can flip sign
-        };
-
-        OPS.div = new BinaryOp(false, false) {
+    new BinaryOp('/', false, false) {
 
-            @Override
-            public Constant foldConstant(Constant a, Constant b) {
-                assert a.getKind() == b.getKind();
-                switch (a.getKind()) {
-                    case Float:
-                        return Constant.forFloat(a.asFloat() / b.asFloat());
-                    case Double:
-                        return Constant.forDouble(a.asDouble() / b.asDouble());
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
+        @Override
+        public Constant foldConstant(Constant a, Constant b) {
+            assert a.getKind() == b.getKind();
+            switch (a.getKind()) {
+                case Float:
+                    return Constant.forFloat(a.asFloat() / b.asFloat());
+                case Double:
+                    return Constant.forDouble(a.asDouble() / b.asDouble());
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
+        }
 
-            @Override
-            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
-                // TODO
-                return stamp1.unrestricted();
-            }
+        @Override
+        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+            // TODO
+            return stamp1.unrestricted();
+        }
 
-            @Override
-            public boolean isNeutral(Constant n) {
-                switch (n.getKind()) {
-                    case Float:
-                        return Float.compare(n.asFloat(), 1.0f) == 0;
-                    case Double:
-                        return Double.compare(n.asDouble(), 1.0) == 0;
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
+        @Override
+        public boolean isNeutral(Constant n) {
+            switch (n.getKind()) {
+                case Float:
+                    return Float.compare(n.asFloat(), 1.0f) == 0;
+                case Double:
+                    return Double.compare(n.asDouble(), 1.0) == 0;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
-        };
+        }
+    },
 
-        OPS.rem = new BinaryOp(false, false) {
+    new BinaryOp('%', false, false) {
 
-            @Override
-            public Constant foldConstant(Constant a, Constant b) {
-                assert a.getKind() == b.getKind();
-                switch (a.getKind()) {
-                    case Float:
-                        return Constant.forFloat(a.asFloat() % b.asFloat());
-                    case Double:
-                        return Constant.forDouble(a.asDouble() % b.asDouble());
-                    default:
-                        throw GraalInternalError.shouldNotReachHere();
-                }
+        @Override
+        public Constant foldConstant(Constant a, Constant b) {
+            assert a.getKind() == b.getKind();
+            switch (a.getKind()) {
+                case Float:
+                    return Constant.forFloat(a.asFloat() % b.asFloat());
+                case Double:
+                    return Constant.forDouble(a.asDouble() % b.asDouble());
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
+        }
 
-            @Override
-            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
-                // TODO
-                return stamp1.unrestricted();
-            }
-        };
-    }
+        @Override
+        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+            // TODO
+            return stamp1.unrestricted();
+        }
+    });
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Fri Oct 03 13:48:58 2014 +0200
@@ -350,290 +350,288 @@
         return (x + y) ^ x ^ y;
     }
 
-    public static final ArithmeticOpTable OPS = new ArithmeticOpTable();
+    public static final ArithmeticOpTable OPS = ArithmeticOpTable.create(
 
-    static {
-        OPS.neg = new UnaryOp() {
+    new UnaryOp('-') {
 
-            @Override
-            public Constant foldConstant(Constant value) {
-                return Constant.forIntegerKind(value.getKind(), -value.asLong());
-            }
+        @Override
+        public Constant foldConstant(Constant value) {
+            return Constant.forIntegerKind(value.getKind(), -value.asLong());
+        }
 
-            @Override
-            public Stamp foldStamp(Stamp s) {
-                IntegerStamp stamp = (IntegerStamp) s;
-                int bits = stamp.getBits();
-                if (stamp.lowerBound() != CodeUtil.minValue(bits)) {
-                    // TODO(ls) check if the mask calculation is correct...
-                    return StampFactory.forInteger(bits, -stamp.upperBound(), -stamp.lowerBound());
-                } else {
-                    return stamp.unrestricted();
-                }
+        @Override
+        public Stamp foldStamp(Stamp s) {
+            IntegerStamp stamp = (IntegerStamp) s;
+            int bits = stamp.getBits();
+            if (stamp.lowerBound() != CodeUtil.minValue(bits)) {
+                // TODO(ls) check if the mask calculation is correct...
+                return StampFactory.forInteger(bits, -stamp.upperBound(), -stamp.lowerBound());
+            } else {
+                return stamp.unrestricted();
             }
-        };
+        }
+    },
 
-        OPS.add = new BinaryOp(true, true) {
+    new BinaryOp('+', true, true) {
 
-            @Override
-            public Constant foldConstant(Constant a, Constant b) {
-                assert a.getKind() == b.getKind();
-                return Constant.forIntegerKind(a.getKind(), a.asLong() + b.asLong());
-            }
+        @Override
+        public Constant foldConstant(Constant a, Constant b) {
+            assert a.getKind() == b.getKind();
+            return Constant.forIntegerKind(a.getKind(), a.asLong() + b.asLong());
+        }
 
-            @Override
-            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
-                IntegerStamp a = (IntegerStamp) stamp1;
-                IntegerStamp b = (IntegerStamp) stamp2;
+        @Override
+        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+            IntegerStamp a = (IntegerStamp) stamp1;
+            IntegerStamp b = (IntegerStamp) stamp2;
 
-                int bits = a.getBits();
-                assert bits == b.getBits();
+            int bits = a.getBits();
+            assert bits == b.getBits();
 
-                if (a.isUnrestricted()) {
-                    return a;
-                } else if (b.isUnrestricted()) {
-                    return b;
-                }
-                long defaultMask = CodeUtil.mask(bits);
-                long variableBits = (a.downMask() ^ a.upMask()) | (b.downMask() ^ b.upMask());
-                long variableBitsWithCarry = variableBits | (carryBits(a.downMask(), b.downMask()) ^ carryBits(a.upMask(), b.upMask()));
-                long newDownMask = (a.downMask() + b.downMask()) & ~variableBitsWithCarry;
-                long newUpMask = (a.downMask() + b.downMask()) | variableBitsWithCarry;
+            if (a.isUnrestricted()) {
+                return a;
+            } else if (b.isUnrestricted()) {
+                return b;
+            }
+            long defaultMask = CodeUtil.mask(bits);
+            long variableBits = (a.downMask() ^ a.upMask()) | (b.downMask() ^ b.upMask());
+            long variableBitsWithCarry = variableBits | (carryBits(a.downMask(), b.downMask()) ^ carryBits(a.upMask(), b.upMask()));
+            long newDownMask = (a.downMask() + b.downMask()) & ~variableBitsWithCarry;
+            long newUpMask = (a.downMask() + b.downMask()) | variableBitsWithCarry;
 
-                newDownMask &= defaultMask;
-                newUpMask &= defaultMask;
+            newDownMask &= defaultMask;
+            newUpMask &= defaultMask;
 
-                long newLowerBound;
-                long newUpperBound;
-                boolean lowerOverflowsPositively = addOverflowsPositively(a.lowerBound(), b.lowerBound(), bits);
-                boolean upperOverflowsPositively = addOverflowsPositively(a.upperBound(), b.upperBound(), bits);
-                boolean lowerOverflowsNegatively = addOverflowsNegatively(a.lowerBound(), b.lowerBound(), bits);
-                boolean upperOverflowsNegatively = addOverflowsNegatively(a.upperBound(), b.upperBound(), bits);
-                if ((lowerOverflowsNegatively && !upperOverflowsNegatively) || (!lowerOverflowsPositively && upperOverflowsPositively)) {
-                    newLowerBound = CodeUtil.minValue(bits);
-                    newUpperBound = CodeUtil.maxValue(bits);
-                } else {
-                    newLowerBound = CodeUtil.signExtend((a.lowerBound() + b.lowerBound()) & defaultMask, bits);
-                    newUpperBound = CodeUtil.signExtend((a.upperBound() + b.upperBound()) & defaultMask, bits);
-                }
-                IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
-                newUpMask &= limit.upMask();
-                newUpperBound = CodeUtil.signExtend(newUpperBound & newUpMask, bits);
-                newDownMask |= limit.downMask();
-                newLowerBound |= newDownMask;
-                return new IntegerStamp(bits, newLowerBound, newUpperBound, newDownMask, newUpMask);
-            }
-
-            @Override
-            public boolean isNeutral(Constant n) {
-                return n.asLong() == 0;
-            }
-        };
-
-        OPS.sub = new BinaryOp(true, false) {
-
-            @Override
-            public Constant foldConstant(Constant a, Constant b) {
-                assert a.getKind() == b.getKind();
-                return Constant.forIntegerKind(a.getKind(), a.asLong() - b.asLong());
-            }
-
-            @Override
-            public Stamp foldStamp(Stamp a, Stamp b) {
-                return OPS.add.foldStamp(a, OPS.neg.foldStamp(b));
-            }
-
-            @Override
-            public boolean isNeutral(Constant n) {
-                return n.asLong() == 0;
+            long newLowerBound;
+            long newUpperBound;
+            boolean lowerOverflowsPositively = addOverflowsPositively(a.lowerBound(), b.lowerBound(), bits);
+            boolean upperOverflowsPositively = addOverflowsPositively(a.upperBound(), b.upperBound(), bits);
+            boolean lowerOverflowsNegatively = addOverflowsNegatively(a.lowerBound(), b.lowerBound(), bits);
+            boolean upperOverflowsNegatively = addOverflowsNegatively(a.upperBound(), b.upperBound(), bits);
+            if ((lowerOverflowsNegatively && !upperOverflowsNegatively) || (!lowerOverflowsPositively && upperOverflowsPositively)) {
+                newLowerBound = CodeUtil.minValue(bits);
+                newUpperBound = CodeUtil.maxValue(bits);
+            } else {
+                newLowerBound = CodeUtil.signExtend((a.lowerBound() + b.lowerBound()) & defaultMask, bits);
+                newUpperBound = CodeUtil.signExtend((a.upperBound() + b.upperBound()) & defaultMask, bits);
             }
+            IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
+            newUpMask &= limit.upMask();
+            newUpperBound = CodeUtil.signExtend(newUpperBound & newUpMask, bits);
+            newDownMask |= limit.downMask();
+            newLowerBound |= newDownMask;
+            return new IntegerStamp(bits, newLowerBound, newUpperBound, newDownMask, newUpMask);
+        }
 
-            @Override
-            public Constant getZero(Stamp s) {
-                IntegerStamp stamp = (IntegerStamp) s;
-                return Constant.forPrimitiveInt(stamp.getBits(), 0);
-            }
-        };
+        @Override
+        public boolean isNeutral(Constant n) {
+            return n.asLong() == 0;
+        }
+    },
+
+    new BinaryOp('-', true, false) {
 
-        OPS.mul = new BinaryOp(true, true) {
+        @Override
+        public Constant foldConstant(Constant a, Constant b) {
+            assert a.getKind() == b.getKind();
+            return Constant.forIntegerKind(a.getKind(), a.asLong() - b.asLong());
+        }
 
-            @Override
-            public Constant foldConstant(Constant a, Constant b) {
-                assert a.getKind() == b.getKind();
-                return Constant.forIntegerKind(a.getKind(), a.asLong() * b.asLong());
-            }
+        @Override
+        public Stamp foldStamp(Stamp a, Stamp b) {
+            return OPS.getAdd().foldStamp(a, OPS.getNeg().foldStamp(b));
+        }
+
+        @Override
+        public boolean isNeutral(Constant n) {
+            return n.asLong() == 0;
+        }
 
-            @Override
-            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
-                IntegerStamp a = (IntegerStamp) stamp1;
-                IntegerStamp b = (IntegerStamp) stamp2;
-                if (a.upMask() == 0) {
-                    return a;
-                } else if (b.upMask() == 0) {
-                    return b;
-                } else {
-                    // TODO
-                    return a.unrestricted();
-                }
-            }
+        @Override
+        public Constant getZero(Stamp s) {
+            IntegerStamp stamp = (IntegerStamp) s;
+            return Constant.forPrimitiveInt(stamp.getBits(), 0);
+        }
+    },
+
+    new BinaryOp('*', true, true) {
+
+        @Override
+        public Constant foldConstant(Constant a, Constant b) {
+            assert a.getKind() == b.getKind();
+            return Constant.forIntegerKind(a.getKind(), a.asLong() * b.asLong());
+        }
 
-            @Override
-            public boolean isNeutral(Constant n) {
-                return n.asLong() == 1;
+        @Override
+        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+            IntegerStamp a = (IntegerStamp) stamp1;
+            IntegerStamp b = (IntegerStamp) stamp2;
+            if (a.upMask() == 0) {
+                return a;
+            } else if (b.upMask() == 0) {
+                return b;
+            } else {
+                // TODO
+                return a.unrestricted();
             }
-        };
+        }
 
-        OPS.div = new BinaryOp(true, false) {
+        @Override
+        public boolean isNeutral(Constant n) {
+            return n.asLong() == 1;
+        }
+    },
 
-            @Override
-            public Constant foldConstant(Constant a, Constant b) {
-                assert a.getKind() == b.getKind();
-                return Constant.forIntegerKind(a.getKind(), a.asLong() / b.asLong());
-            }
+    new BinaryOp('/', true, false) {
+
+        @Override
+        public Constant foldConstant(Constant a, Constant b) {
+            assert a.getKind() == b.getKind();
+            return Constant.forIntegerKind(a.getKind(), a.asLong() / b.asLong());
+        }
 
-            @Override
-            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
-                IntegerStamp a = (IntegerStamp) stamp1;
-                IntegerStamp b = (IntegerStamp) stamp2;
-                assert a.getBits() == b.getBits();
-                if (b.isStrictlyPositive()) {
-                    long newLowerBound = a.lowerBound() / b.lowerBound();
-                    long newUpperBound = a.upperBound() / b.lowerBound();
-                    return StampFactory.forInteger(a.getBits(), newLowerBound, newUpperBound);
-                } else {
-                    return a.unrestricted();
-                }
+        @Override
+        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+            IntegerStamp a = (IntegerStamp) stamp1;
+            IntegerStamp b = (IntegerStamp) stamp2;
+            assert a.getBits() == b.getBits();
+            if (b.isStrictlyPositive()) {
+                long newLowerBound = a.lowerBound() / b.lowerBound();
+                long newUpperBound = a.upperBound() / b.lowerBound();
+                return StampFactory.forInteger(a.getBits(), newLowerBound, newUpperBound);
+            } else {
+                return a.unrestricted();
             }
+        }
 
-            @Override
-            public boolean isNeutral(Constant n) {
-                return n.asLong() == 1;
-            }
-        };
+        @Override
+        public boolean isNeutral(Constant n) {
+            return n.asLong() == 1;
+        }
+    },
 
-        OPS.rem = new BinaryOp(false, false) {
+    new BinaryOp('%', false, false) {
 
-            @Override
-            public Constant foldConstant(Constant a, Constant b) {
-                assert a.getKind() == b.getKind();
-                return Constant.forIntegerKind(a.getKind(), a.asLong() % b.asLong());
-            }
+        @Override
+        public Constant foldConstant(Constant a, Constant b) {
+            assert a.getKind() == b.getKind();
+            return Constant.forIntegerKind(a.getKind(), a.asLong() % b.asLong());
+        }
 
-            @Override
-            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
-                IntegerStamp a = (IntegerStamp) stamp1;
-                IntegerStamp b = (IntegerStamp) stamp2;
-                assert a.getBits() == b.getBits();
-                // zero is always possible
-                long newLowerBound = Math.min(a.lowerBound(), 0);
-                long newUpperBound = Math.max(a.upperBound(), 0);
+        @Override
+        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+            IntegerStamp a = (IntegerStamp) stamp1;
+            IntegerStamp b = (IntegerStamp) stamp2;
+            assert a.getBits() == b.getBits();
+            // zero is always possible
+            long newLowerBound = Math.min(a.lowerBound(), 0);
+            long newUpperBound = Math.max(a.upperBound(), 0);
 
-                long magnitude; // the maximum absolute value of the result, derived from b
-                if (b.lowerBound() == CodeUtil.minValue(b.getBits())) {
-                    // Math.abs(...) - 1 does not work in a case
-                    magnitude = CodeUtil.maxValue(b.getBits());
-                } else {
-                    magnitude = Math.max(Math.abs(b.lowerBound()), Math.abs(b.upperBound())) - 1;
-                }
-                newLowerBound = Math.max(newLowerBound, -magnitude);
-                newUpperBound = Math.min(newUpperBound, magnitude);
+            long magnitude; // the maximum absolute value of the result, derived from b
+            if (b.lowerBound() == CodeUtil.minValue(b.getBits())) {
+                // Math.abs(...) - 1 does not work in a case
+                magnitude = CodeUtil.maxValue(b.getBits());
+            } else {
+                magnitude = Math.max(Math.abs(b.lowerBound()), Math.abs(b.upperBound())) - 1;
+            }
+            newLowerBound = Math.max(newLowerBound, -magnitude);
+            newUpperBound = Math.min(newUpperBound, magnitude);
 
-                return StampFactory.forInteger(a.getBits(), newLowerBound, newUpperBound);
-            }
-        };
+            return StampFactory.forInteger(a.getBits(), newLowerBound, newUpperBound);
+        }
+    },
 
-        OPS.not = new UnaryOp() {
+    new UnaryOp('~') {
 
-            @Override
-            public Constant foldConstant(Constant value) {
-                return Constant.forIntegerKind(value.getKind(), ~value.asLong());
-            }
+        @Override
+        public Constant foldConstant(Constant value) {
+            return Constant.forIntegerKind(value.getKind(), ~value.asLong());
+        }
 
-            @Override
-            public Stamp foldStamp(Stamp stamp) {
-                IntegerStamp integerStamp = (IntegerStamp) stamp;
-                int bits = integerStamp.getBits();
-                long defaultMask = CodeUtil.mask(bits);
-                return new IntegerStamp(bits, ~integerStamp.upperBound(), ~integerStamp.lowerBound(), (~integerStamp.upMask()) & defaultMask, (~integerStamp.downMask()) & defaultMask);
-            }
-        };
+        @Override
+        public Stamp foldStamp(Stamp stamp) {
+            IntegerStamp integerStamp = (IntegerStamp) stamp;
+            int bits = integerStamp.getBits();
+            long defaultMask = CodeUtil.mask(bits);
+            return new IntegerStamp(bits, ~integerStamp.upperBound(), ~integerStamp.lowerBound(), (~integerStamp.upMask()) & defaultMask, (~integerStamp.downMask()) & defaultMask);
+        }
+    },
 
-        OPS.and = new BinaryOp(true, true) {
+    new BinaryOp('&', true, true) {
 
-            @Override
-            public Constant foldConstant(Constant a, Constant b) {
-                assert a.getKind() == b.getKind();
-                return Constant.forIntegerKind(a.getKind(), a.asLong() & b.asLong());
-            }
+        @Override
+        public Constant foldConstant(Constant a, Constant b) {
+            assert a.getKind() == b.getKind();
+            return Constant.forIntegerKind(a.getKind(), a.asLong() & b.asLong());
+        }
 
-            @Override
-            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
-                IntegerStamp a = (IntegerStamp) stamp1;
-                IntegerStamp b = (IntegerStamp) stamp2;
-                assert a.getBits() == b.getBits();
-                return stampForMask(a.getBits(), a.downMask() & b.downMask(), a.upMask() & b.upMask());
-            }
+        @Override
+        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+            IntegerStamp a = (IntegerStamp) stamp1;
+            IntegerStamp b = (IntegerStamp) stamp2;
+            assert a.getBits() == b.getBits();
+            return stampForMask(a.getBits(), a.downMask() & b.downMask(), a.upMask() & b.upMask());
+        }
 
-            @Override
-            public boolean isNeutral(Constant n) {
-                int bits = n.getKind().getBitCount();
-                long mask = CodeUtil.mask(bits);
-                return (n.asLong() & mask) == mask;
-            }
-        };
+        @Override
+        public boolean isNeutral(Constant n) {
+            int bits = n.getKind().getBitCount();
+            long mask = CodeUtil.mask(bits);
+            return (n.asLong() & mask) == mask;
+        }
+    },
 
-        OPS.or = new BinaryOp(true, true) {
+    new BinaryOp('|', true, true) {
 
-            @Override
-            public Constant foldConstant(Constant a, Constant b) {
-                assert a.getKind() == b.getKind();
-                return Constant.forIntegerKind(a.getKind(), a.asLong() | b.asLong());
-            }
+        @Override
+        public Constant foldConstant(Constant a, Constant b) {
+            assert a.getKind() == b.getKind();
+            return Constant.forIntegerKind(a.getKind(), a.asLong() | b.asLong());
+        }
 
-            @Override
-            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
-                IntegerStamp a = (IntegerStamp) stamp1;
-                IntegerStamp b = (IntegerStamp) stamp2;
-                assert a.getBits() == b.getBits();
-                return stampForMask(a.getBits(), a.downMask() | b.downMask(), a.upMask() | b.upMask());
-            }
+        @Override
+        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+            IntegerStamp a = (IntegerStamp) stamp1;
+            IntegerStamp b = (IntegerStamp) stamp2;
+            assert a.getBits() == b.getBits();
+            return stampForMask(a.getBits(), a.downMask() | b.downMask(), a.upMask() | b.upMask());
+        }
 
-            @Override
-            public boolean isNeutral(Constant n) {
-                return n.asLong() == 0;
-            }
-        };
-
-        OPS.xor = new BinaryOp(true, true) {
+        @Override
+        public boolean isNeutral(Constant n) {
+            return n.asLong() == 0;
+        }
+    },
 
-            @Override
-            public Constant foldConstant(Constant a, Constant b) {
-                assert a.getKind() == b.getKind();
-                return Constant.forIntegerKind(a.getKind(), a.asLong() ^ b.asLong());
-            }
+    new BinaryOp('^', true, true) {
 
-            @Override
-            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
-                IntegerStamp a = (IntegerStamp) stamp1;
-                IntegerStamp b = (IntegerStamp) stamp2;
-                assert a.getBits() == b.getBits();
+        @Override
+        public Constant foldConstant(Constant a, Constant b) {
+            assert a.getKind() == b.getKind();
+            return Constant.forIntegerKind(a.getKind(), a.asLong() ^ b.asLong());
+        }
 
-                long variableBits = (a.downMask() ^ a.upMask()) | (b.downMask() ^ b.upMask());
-                long newDownMask = (a.downMask() ^ b.downMask()) & ~variableBits;
-                long newUpMask = (a.downMask() ^ b.downMask()) | variableBits;
-                return stampForMask(a.getBits(), newDownMask, newUpMask);
-            }
+        @Override
+        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+            IntegerStamp a = (IntegerStamp) stamp1;
+            IntegerStamp b = (IntegerStamp) stamp2;
+            assert a.getBits() == b.getBits();
+
+            long variableBits = (a.downMask() ^ a.upMask()) | (b.downMask() ^ b.upMask());
+            long newDownMask = (a.downMask() ^ b.downMask()) & ~variableBits;
+            long newUpMask = (a.downMask() ^ b.downMask()) | variableBits;
+            return stampForMask(a.getBits(), newDownMask, newUpMask);
+        }
 
-            @Override
-            public boolean isNeutral(Constant n) {
-                return n.asLong() == 0;
-            }
+        @Override
+        public boolean isNeutral(Constant n) {
+            return n.asLong() == 0;
+        }
 
-            @Override
-            public Constant getZero(Stamp s) {
-                IntegerStamp stamp = (IntegerStamp) s;
-                return Constant.forPrimitiveInt(stamp.getBits(), 0);
-            }
-        };
-    }
+        @Override
+        public Constant getZero(Stamp s) {
+            IntegerStamp stamp = (IntegerStamp) s;
+            return Constant.forPrimitiveInt(stamp.getBits(), 0);
+        }
+    });
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Fri Oct 03 13:48:58 2014 +0200
@@ -115,8 +115,4 @@
     public Constant asConstant() {
         return null;
     }
-
-    public final Stamp asStamp() {
-        return this;
-    }
 }
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Fri Oct 03 13:48:58 2014 +0200
@@ -62,12 +62,6 @@
     }
 
     @Override
-    public boolean canStoreConstant(Constant c) {
-        // Operand b must be in the .reg state space.
-        return false;
-    }
-
-    @Override
     public boolean canInlineConstant(Constant c) {
         switch (c.getKind()) {
             case Long:
@@ -79,13 +73,6 @@
         }
     }
 
-    @Override
-    public Variable emitMove(Value input) {
-        Variable result = newVariable(input.getLIRKind());
-        emitMove(result, input);
-        return result;
-    }
-
     protected HSAILLIRInstruction createMove(AllocatableValue dst, Value src) {
         if (src instanceof HSAILAddressValue) {
             return new LeaOp(dst, (HSAILAddressValue) src);
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Fri Oct 03 13:48:58 2014 +0200
@@ -93,12 +93,6 @@
     }
 
     @Override
-    public boolean canStoreConstant(Constant c) {
-        // Operand b must be in the .reg state space.
-        return false;
-    }
-
-    @Override
     public boolean canInlineConstant(Constant c) {
         switch (c.getKind()) {
             case Long:
@@ -131,13 +125,6 @@
     }
 
     @Override
-    public Variable emitMove(Value input) {
-        Variable result = newVariable(input.getLIRKind());
-        emitMove(result, input);
-        return result;
-    }
-
-    @Override
     public void emitMove(AllocatableValue dst, Value src) {
         if (isRegister(src) || isStackSlot(dst)) {
             append(new MoveFromRegOp(dst, src));
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Fri Oct 03 13:48:58 2014 +0200
@@ -83,18 +83,6 @@
     }
 
     @Override
-    public boolean canStoreConstant(Constant c) {
-        // SPARC can only store integer null constants (via g0)
-        switch (c.getKind()) {
-            case Float:
-            case Double:
-                return false;
-            default:
-                return c.isDefaultForKind();
-        }
-    }
-
-    @Override
     public boolean canInlineConstant(Constant c) {
         switch (c.getKind()) {
             case Int:
@@ -108,13 +96,6 @@
         }
     }
 
-    @Override
-    public Variable emitMove(Value input) {
-        Variable result = newVariable(input.getLIRKind());
-        emitMove(result, input);
-        return result;
-    }
-
     protected SPARCLIRInstruction createMove(AllocatableValue dst, Value src) {
         if (src instanceof SPARCAddressValue) {
             return new LoadAddressOp(dst, (SPARCAddressValue) src);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Fri Oct 03 13:48:58 2014 +0200
@@ -185,7 +185,7 @@
      */
     private static void checkClass(Class<?> c, MetaAccessProvider metaAccess) {
         if (Node.class.isAssignableFrom(c)) {
-            if (c.getAnnotation(GeneratedNode.class) == null) {
+            if (!GeneratedNode.class.isAssignableFrom(c)) {
                 if (Modifier.isFinal(c.getModifiers())) {
                     throw new AssertionError(String.format("Node subclass %s must not be final", c.getName()));
                 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NodePosIteratorTest.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NodePosIteratorTest.java	Fri Oct 03 13:48:58 2014 +0200
@@ -44,6 +44,10 @@
         public static TestNode create() {
             return USE_GENERATED_NODES ? new NodePosIteratorTest_TestNodeGen() : new TestNode();
         }
+
+        protected TestNode() {
+            // TODO Auto-generated constructor stub
+        }
     }
 
     @Test
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Fri Oct 03 13:48:58 2014 +0200
@@ -79,16 +79,12 @@
             }
         }
 
-        private ValueProcedure collectStatsProc = new ValueProcedure() {
-
-            @Override
-            public Value doValue(Value value) {
-                if (ValueUtil.isRegister(value)) {
-                    final Register reg = ValueUtil.asRegister(value);
-                    registers.add(reg);
-                }
-                return value;
+        private ValueProcedure collectStatsProc = (value, mode, flags) -> {
+            if (ValueUtil.isRegister(value)) {
+                final Register reg = ValueUtil.asRegister(value);
+                registers.add(reg);
             }
+            return value;
         };
 
         private void collectStats(final LIRInstruction instr) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Fri Oct 03 13:48:58 2014 +0200
@@ -60,8 +60,6 @@
     public static final OptionValue<String> DebugValueSummary = new OptionValue<>("Name");
     @Option(help = "Omit reporting 0-value metrics")
     public static final OptionValue<Boolean> SuppressZeroDebugValues = new OptionValue<>(false);
-    @Option(help = "Report and reset metrics after bootstrapping")
-    public static final OptionValue<Boolean> ResetDebugValuesAfterBootstrap = new OptionValue<>(true);
     @Option(help = "Send Graal IR to dump handlers on error")
     public static final OptionValue<Boolean> DumpOnError = new OptionValue<>(false);
     @Option(help = "Enable expensive assertions")
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Fri Oct 03 13:48:58 2014 +0200
@@ -612,13 +612,9 @@
         intervalsSize = operandSize();
         intervals = new Interval[intervalsSize + (intervalsSize >> SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT)];
 
-        ValueConsumer setVariableConsumer = new ValueConsumer() {
-
-            @Override
-            public void visitValue(Value value) {
-                if (isVariable(value)) {
-                    getOrCreateInterval(asVariable(value));
-                }
+        ValueConsumer setVariableConsumer = (value, mode, flags) -> {
+            if (isVariable(value)) {
+                getOrCreateInterval(asVariable(value));
             }
         };
 
@@ -678,56 +674,44 @@
                 List<LIRInstruction> instructions = ir.getLIRforBlock(block);
                 int numInst = instructions.size();
 
-                ValueConsumer useConsumer = new ValueConsumer() {
-
-                    @Override
-                    protected void visitValue(Value operand) {
-                        if (isVariable(operand)) {
-                            int operandNum = operandNumber(operand);
-                            if (!liveKill.get(operandNum)) {
-                                liveGen.set(operandNum);
-                                Debug.log("liveGen for operand %d", operandNum);
-                            }
-                            if (block.getLoop() != null) {
-                                intervalInLoop.setBit(operandNum, block.getLoop().getIndex());
-                            }
-                        }
-
-                        if (DetailedAsserts.getValue()) {
-                            verifyInput(block, liveKill, operand);
-                        }
-                    }
-                };
-                ValueConsumer stateConsumer = new ValueConsumer() {
-
-                    @Override
-                    public void visitValue(Value operand) {
+                ValueConsumer useConsumer = (operand, mode, flags) -> {
+                    if (isVariable(operand)) {
                         int operandNum = operandNumber(operand);
                         if (!liveKill.get(operandNum)) {
                             liveGen.set(operandNum);
-                            Debug.log("liveGen in state for operand %d", operandNum);
+                            Debug.log("liveGen for operand %d", operandNum);
+                        }
+                        if (block.getLoop() != null) {
+                            intervalInLoop.setBit(operandNum, block.getLoop().getIndex());
                         }
                     }
+
+                    if (DetailedAsserts.getValue()) {
+                        verifyInput(block, liveKill, operand);
+                    }
                 };
-                ValueConsumer defConsumer = new ValueConsumer() {
+                ValueConsumer stateConsumer = (operand, mode, flags) -> {
+                    int operandNum = operandNumber(operand);
+                    if (!liveKill.get(operandNum)) {
+                        liveGen.set(operandNum);
+                        Debug.log("liveGen in state for operand %d", operandNum);
+                    }
+                };
+                ValueConsumer defConsumer = (operand, mode, flags) -> {
+                    if (isVariable(operand)) {
+                        int varNum = operandNumber(operand);
+                        liveKill.set(varNum);
+                        Debug.log("liveKill for operand %d", varNum);
+                        if (block.getLoop() != null) {
+                            intervalInLoop.setBit(varNum, block.getLoop().getIndex());
+                        }
+                    }
 
-                    @Override
-                    public void visitValue(Value operand) {
-                        if (isVariable(operand)) {
-                            int varNum = operandNumber(operand);
-                            liveKill.set(varNum);
-                            Debug.log("liveKill for operand %d", varNum);
-                            if (block.getLoop() != null) {
-                                intervalInLoop.setBit(varNum, block.getLoop().getIndex());
-                            }
-                        }
-
-                        if (DetailedAsserts.getValue()) {
-                            // fixed intervals are never live at block boundaries, so
-                            // they need not be processed in live sets
-                            // process them only in debug mode so that this can be checked
-                            verifyTemp(liveKill, operand);
-                        }
+                    if (DetailedAsserts.getValue()) {
+                        // fixed intervals are never live at block boundaries, so
+                        // they need not be processed in live sets
+                        // process them only in debug mode so that this can be checked
+                        verifyTemp(liveKill, operand);
                     }
                 };
 
@@ -923,13 +907,9 @@
                                 try (Indent indent3 = Debug.logAndIndent("used in block B%d", block.getId())) {
                                     for (LIRInstruction ins : ir.getLIRforBlock(block)) {
                                         try (Indent indent4 = Debug.logAndIndent("%d: %s", ins.id(), ins)) {
-                                            ins.forEachState(new ValueProcedure() {
-
-                                                @Override
-                                                public Value doValue(Value liveStateOperand) {
-                                                    Debug.log("operand=%s", liveStateOperand);
-                                                    return liveStateOperand;
-                                                }
+                                            ins.forEachState((liveStateOperand, mode, flags) -> {
+                                                Debug.log("operand=%s", liveStateOperand);
+                                                return liveStateOperand;
                                             });
                                         }
                                     }
@@ -1124,26 +1104,22 @@
     void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
         if (flags.contains(OperandFlag.HINT) && isVariableOrRegister(targetValue)) {
 
-            op.forEachRegisterHint(targetValue, mode, new ValueProcedure() {
-
-                @Override
-                protected Value doValue(Value registerHint) {
-                    if (isVariableOrRegister(registerHint)) {
-                        Interval from = getOrCreateInterval((AllocatableValue) registerHint);
-                        Interval to = getOrCreateInterval((AllocatableValue) targetValue);
+            op.forEachRegisterHint(targetValue, mode, (registerHint, valueMode, valueFlags) -> {
+                if (isVariableOrRegister(registerHint)) {
+                    Interval from = getOrCreateInterval((AllocatableValue) registerHint);
+                    Interval to = getOrCreateInterval((AllocatableValue) targetValue);
 
-                        // hints always point from def to use
-                        if (hintAtDef) {
-                            to.setLocationHint(from);
-                        } else {
-                            from.setLocationHint(to);
-                        }
-                        Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), from.operandNumber, to.operandNumber);
+                    /* hints always point from def to use */
+                    if (hintAtDef) {
+                        to.setLocationHint(from);
+                    } else {
+                        from.setLocationHint(to);
+                    }
+                    Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), from.operandNumber, to.operandNumber);
 
-                        return registerHint;
-                    }
-                    return null;
+                    return registerHint;
                 }
+                return null;
             });
         }
     }
@@ -1151,64 +1127,44 @@
     void buildIntervals() {
 
         try (Indent indent = Debug.logAndIndent("build intervals")) {
-            InstructionValueConsumer outputConsumer = new InstructionValueConsumer() {
-
-                @Override
-                public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                    if (isVariableOrRegister(operand)) {
-                        addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getLIRKind());
-                        addRegisterHint(op, operand, mode, flags, true);
-                    }
+            InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> {
+                if (isVariableOrRegister(operand)) {
+                    addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getLIRKind());
+                    addRegisterHint(op, operand, mode, flags, true);
                 }
             };
 
-            InstructionValueConsumer tempConsumer = new InstructionValueConsumer() {
-
-                @Override
-                public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                    if (isVariableOrRegister(operand)) {
-                        addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getLIRKind());
-                        addRegisterHint(op, operand, mode, flags, false);
-                    }
+            InstructionValueConsumer tempConsumer = (op, operand, mode, flags) -> {
+                if (isVariableOrRegister(operand)) {
+                    addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getLIRKind());
+                    addRegisterHint(op, operand, mode, flags, false);
                 }
             };
 
-            InstructionValueConsumer aliveConsumer = new InstructionValueConsumer() {
-
-                @Override
-                public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                    if (isVariableOrRegister(operand)) {
-                        RegisterPriority p = registerPriorityOfInputOperand(flags);
-                        final int opId = op.id();
-                        final int blockFrom = getFirstLirInstructionId((blockForId(opId)));
-                        addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getLIRKind());
-                        addRegisterHint(op, operand, mode, flags, false);
-                    }
+            InstructionValueConsumer aliveConsumer = (op, operand, mode, flags) -> {
+                if (isVariableOrRegister(operand)) {
+                    RegisterPriority p = registerPriorityOfInputOperand(flags);
+                    int opId = op.id();
+                    int blockFrom = getFirstLirInstructionId((blockForId(opId)));
+                    addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getLIRKind());
+                    addRegisterHint(op, operand, mode, flags, false);
                 }
             };
 
-            InstructionValueConsumer inputConsumer = new InstructionValueConsumer() {
-
-                @Override
-                public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                    if (isVariableOrRegister(operand)) {
-                        final int opId = op.id();
-                        final int blockFrom = getFirstLirInstructionId((blockForId(opId)));
-                        RegisterPriority p = registerPriorityOfInputOperand(flags);
-                        addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getLIRKind());
-                        addRegisterHint(op, operand, mode, flags, false);
-                    }
+            InstructionValueConsumer inputConsumer = (op, operand, mode, flags) -> {
+                if (isVariableOrRegister(operand)) {
+                    int opId = op.id();
+                    int blockFrom = getFirstLirInstructionId((blockForId(opId)));
+                    RegisterPriority p = registerPriorityOfInputOperand(flags);
+                    addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getLIRKind());
+                    addRegisterHint(op, operand, mode, flags, false);
                 }
             };
 
-            InstructionValueConsumer stateProc = new InstructionValueConsumer() {
-
-                @Override
-                public void visitValue(LIRInstruction op, Value operand) {
-                    final int opId = op.id();
-                    final int blockFrom = getFirstLirInstructionId((blockForId(opId)));
-                    addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getLIRKind());
-                }
+            InstructionValueConsumer stateProc = (op, operand, mode, flags) -> {
+                int opId = op.id();
+                int blockFrom = getFirstLirInstructionId((blockForId(opId)));
+                addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getLIRKind());
             };
 
             // create a list with all caller-save registers (cpu, fpu, xmm)
@@ -1737,44 +1693,41 @@
         return attributes(asRegister(operand)).isCallerSave();
     }
 
-    private InstructionValueProcedure debugInfoProc = new InstructionValueProcedure() {
-
-        @Override
-        public Value doValue(LIRInstruction op, Value operand) {
-            int tempOpId = op.id();
-            OperandMode mode = OperandMode.USE;
-            AbstractBlock<?> block = blockForId(tempOpId);
-            if (block.getSuccessorCount() == 1 && tempOpId == getLastLirInstructionId(block)) {
-                // generating debug information for the last instruction of a block.
-                // if this instruction is a branch, spill moves are inserted before this branch
-                // and so the wrong operand would be returned (spill moves at block boundaries
-                // are not
-                // considered in the live ranges of intervals)
-                // Solution: use the first opId of the branch target block instead.
-                final LIRInstruction instr = ir.getLIRforBlock(block).get(ir.getLIRforBlock(block).size() - 1);
-                if (instr instanceof StandardOp.JumpOp) {
-                    if (blockData.get(block).liveOut.get(operandNumber(operand))) {
-                        tempOpId = getFirstLirInstructionId(block.getSuccessors().iterator().next());
-                        mode = OperandMode.DEF;
-                    }
+    @SuppressWarnings("unused")
+    private Value debugInfoProcedure(LIRInstruction op, Value operand, OperandMode valueMode, EnumSet<OperandFlag> flags) {
+        int tempOpId = op.id();
+        OperandMode mode = OperandMode.USE;
+        AbstractBlock<?> block = blockForId(tempOpId);
+        if (block.getSuccessorCount() == 1 && tempOpId == getLastLirInstructionId(block)) {
+            // generating debug information for the last instruction of a block.
+            // if this instruction is a branch, spill moves are inserted before this branch
+            // and so the wrong operand would be returned (spill moves at block boundaries
+            // are not
+            // considered in the live ranges of intervals)
+            // Solution: use the first opId of the branch target block instead.
+            final LIRInstruction instr = ir.getLIRforBlock(block).get(ir.getLIRforBlock(block).size() - 1);
+            if (instr instanceof StandardOp.JumpOp) {
+                if (blockData.get(block).liveOut.get(operandNumber(operand))) {
+                    tempOpId = getFirstLirInstructionId(block.getSuccessors().iterator().next());
+                    mode = OperandMode.DEF;
                 }
             }
+        }
 
-            // Get current location of operand
-            // The operand must be live because debug information is considered when building
-            // the intervals
-            // if the interval is not live, colorLirOperand will cause an assert on failure
-            Value result = colorLirOperand((Variable) operand, tempOpId, mode);
-            assert !hasCall(tempOpId) || isStackSlot(result) || isConstant(result) || !isCallerSave(result) : "cannot have caller-save register operands at calls";
-            return result;
-        }
-    };
+        // Get current location of operand
+        // The operand must be live because debug information is considered when building
+        // the intervals
+        // if the interval is not live, colorLirOperand will cause an assert on failure
+        Value result = colorLirOperand((Variable) operand, tempOpId, mode);
+        assert !hasCall(tempOpId) || isStackSlot(result) || isConstant(result) || !isCallerSave(result) : "cannot have caller-save register operands at calls";
+        return result;
+    }
 
     private void computeDebugInfo(IntervalWalker iw, final LIRInstruction op, LIRFrameState info) {
         info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !callKillsRegisters);
         markFrameLocations(iw, op, info);
 
-        info.forEachState(op, debugInfoProc);
+        info.forEachState(op, this::debugInfoProcedure);
         info.finish(op, frameMap);
     }
 
@@ -1782,23 +1735,8 @@
         int numInst = instructions.size();
         boolean hasDead = false;
 
-        InstructionValueProcedure assignProc = new InstructionValueProcedure() {
-
-            @Override
-            public Value doValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                if (isVariable(operand)) {
-                    return colorLirOperand((Variable) operand, op.id(), mode);
-                }
-                return operand;
-            }
-        };
-        InstructionStateProcedure stateProc = new InstructionStateProcedure() {
-
-            @Override
-            protected void doState(LIRInstruction op, LIRFrameState state) {
-                computeDebugInfo(iw, op, state);
-            }
-        };
+        InstructionValueProcedure assignProc = (op, operand, mode, flags) -> isVariable(operand) ? colorLirOperand((Variable) operand, op.id(), mode) : operand;
+        InstructionStateProcedure stateProc = (op, state) -> computeDebugInfo(iw, op, state);
 
         for (int j = 0; j < numInst; j++) {
             final LIRInstruction op = instructions.get(j);
@@ -2208,13 +2146,13 @@
         }
     }
 
-    class CheckConsumer extends ValueConsumer {
+    class CheckConsumer implements ValueConsumer {
 
         boolean ok;
         Interval curInterval;
 
         @Override
-        protected void visitValue(Value operand) {
+        public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
             if (isRegister(operand)) {
                 if (intervalFor(operand) == curInterval) {
                     ok = true;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java	Fri Oct 03 13:48:58 2014 +0200
@@ -202,18 +202,14 @@
             }
         };
 
-        InstructionValueConsumer defConsumer = new InstructionValueConsumer() {
+        InstructionValueConsumer defConsumer = (op, operand, mode, flags) -> {
+            if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
+                Interval interval = intervalAt(operand);
+                if (op.id() != -1) {
+                    interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
+                }
 
-            @Override
-            public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
-                    Interval interval = intervalAt(operand);
-                    if (op.id() != -1) {
-                        interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
-                    }
-
-                    statePut(inputState, interval.location(), interval.splitParent());
-                }
+                statePut(inputState, interval.location(), interval.splitParent());
             }
         };
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java	Fri Oct 03 13:48:58 2014 +0200
@@ -126,8 +126,10 @@
      */
     public void setResult(ComplexMatchResult result) {
         ComplexMatchValue value = new ComplexMatchValue(result);
-        Debug.log("matched %s %s", rule.getName(), rule.getPattern());
-        Debug.log("with nodes %s", rule.formatMatch(root));
+        if (Debug.isLogEnabled()) {
+            Debug.log("matched %s %s", rule.getName(), rule.getPattern());
+            Debug.log("with nodes %s", rule.formatMatch(root));
+        }
         if (consumed != null) {
             for (ValueNode node : consumed) {
                 // All the interior nodes should be skipped during the normal doRoot calls in
--- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeMapTest.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeMapTest.java	Fri Oct 03 13:48:58 2014 +0200
@@ -34,7 +34,7 @@
 
     @NodeInfo
     static class TestNode extends Node {
-        TestNode() {
+        protected TestNode() {
         }
 
         public static TestNode create() {
--- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeUsagesTests.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeUsagesTests.java	Fri Oct 03 13:48:58 2014 +0200
@@ -35,6 +35,10 @@
 
     @NodeInfo
     static class Def extends Node {
+        protected Def() {
+            // TODO Auto-generated constructor stub
+        }
+
         public static Def create() {
             return USE_GENERATED_NODES ? new NodeUsagesTests_DefGen() : new Def();
         }
@@ -50,7 +54,7 @@
             return USE_GENERATED_NODES ? new NodeUsagesTests_UseGen(in0, in1, in2) : new Use(in0, in1, in2);
         }
 
-        Use(Def in0, Def in1, Def in2) {
+        protected Use(Def in0, Def in1, Def in2) {
             this.in0 = in0;
             this.in1 = in1;
             this.in2 = in2;
--- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest.java	Fri Oct 03 13:48:58 2014 +0200
@@ -36,13 +36,13 @@
     @NodeInfo
     static class TestNode extends Node implements IterableNodeType, TestNodeInterface {
 
-        private final String name;
+        protected final String name;
 
         public static TestNode create(String name) {
             return USE_GENERATED_NODES ? new TypedNodeIteratorTest_TestNodeGen(name) : new TestNode(name);
         }
 
-        TestNode(String name) {
+        protected TestNode(String name) {
             this.name = name;
         }
 
--- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest2.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest2.java	Fri Oct 03 13:48:58 2014 +0200
@@ -34,13 +34,13 @@
     @NodeInfo
     static class NodeA extends Node implements TestNodeInterface {
 
-        private final String name;
+        protected final String name;
 
         public static NodeA create(String name) {
             return USE_GENERATED_NODES ? new TypedNodeIteratorTest2_NodeAGen(name) : new NodeA(name);
         }
 
-        NodeA(String name) {
+        protected NodeA(String name) {
             this.name = name;
         }
 
@@ -56,7 +56,7 @@
             return USE_GENERATED_NODES ? new TypedNodeIteratorTest2_NodeBGen(name) : new NodeB(name);
         }
 
-        NodeB(String name) {
+        protected NodeB(String name) {
             super(name);
         }
     }
@@ -67,7 +67,7 @@
             return USE_GENERATED_NODES ? new TypedNodeIteratorTest2_NodeCGen(name) : new NodeC(name);
         }
 
-        NodeC(String name) {
+        protected NodeC(String name) {
             super(name);
         }
     }
@@ -78,7 +78,7 @@
             return USE_GENERATED_NODES ? new TypedNodeIteratorTest2_NodeDGen(name) : new NodeD(name);
         }
 
-        NodeD(String name) {
+        protected NodeD(String name) {
             super(name);
         }
     }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Fri Oct 03 13:48:58 2014 +0200
@@ -28,7 +28,9 @@
 
 import java.util.*;
 
+import com.oracle.graal.compiler.common.FieldIntrospection.FieldInfo;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.NodeClass.EdgeInfo;
 
 /**
  * Describes {@link Node} fields representing the set of inputs for the node or the set of the
@@ -47,12 +49,18 @@
     private final int directCount;
     private final Type type;
 
-    public Edges(Class<?> nodeClass, Type type, int directCount, long[] offsets, Map<Long, String> names, Map<Long, Class<?>> types) {
-        super(nodeClass, offsets, names, types);
+    public Edges(Type type, int directCount, ArrayList<? extends FieldInfo> edges) {
+        super(edges);
         this.type = type;
         this.directCount = directCount;
     }
 
+    public static void translateInto(Edges edges, ArrayList<EdgeInfo> infos) {
+        for (int index = 0; index < edges.getCount(); index++) {
+            infos.add(new EdgeInfo(edges.offsets[index], edges.getName(index), edges.getType(index)));
+        }
+    }
+
     private static Node getNode(Node node, long offset) {
         return (Node) unsafe.getObject(node, offset);
     }
@@ -134,7 +142,7 @@
      * @param toNode the node to which the edges should be copied.
      */
     public void copy(Node fromNode, Node toNode) {
-        assert fromNode.getNodeClass().getClazz() == clazz && toNode.getNodeClass().getClazz() == clazz;
+        assert fromNode.getNodeClass().getClazz() == toNode.getNodeClass().getClazz();
         int index = 0;
         while (index < getDirectCount()) {
             initializeNode(toNode, index, getNode(fromNode, index));
@@ -169,7 +177,7 @@
         }
         while (index < getCount()) {
             NodeList<Node> list = getNodeList(node, index);
-            assert list != null : clazz;
+            assert list != null : this;
             if (list.replaceFirst(key, replacement)) {
                 return true;
             }
@@ -235,7 +243,7 @@
      * Determines if the edges of two given nodes are the same.
      */
     public boolean areEqualIn(Node node, Node other) {
-        assert node.getNodeClass().getClazz() == clazz && other.getNodeClass().getClazz() == clazz;
+        assert node.getNodeClass().getClazz() == other.getNodeClass().getClazz();
         int index = 0;
         while (index < directCount) {
             if (getNode(other, index) != getNode(node, index)) {
@@ -445,9 +453,4 @@
     public Type type() {
         return type;
     }
-
-    @Override
-    public String toString() {
-        return super.toString() + ":" + type;
-    }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Fri Oct 03 13:48:58 2014 +0200
@@ -78,7 +78,12 @@
     int compressions;
 
     NodeEventListener nodeEventListener;
-    private final HashMap<CacheEntry, Node> cachedNodes = new HashMap<>();
+
+    /**
+     * Used to global value number {@link ValueNumberable} {@linkplain NodeClass#isLeafNode() leaf}
+     * nodes.
+     */
+    private final HashMap<CacheEntry, Node> cachedLeafNodes = new HashMap<>();
 
     /*
      * Indicates that the graph should no longer be modified. Frozen graphs can be used my multiple
@@ -86,19 +91,22 @@
      */
     private boolean isFrozen = false;
 
+    /**
+     * Entry in {@link Graph#cachedLeafNodes}.
+     */
     private static final class CacheEntry {
 
         private final Node node;
 
         public CacheEntry(Node node) {
             assert node.getNodeClass().valueNumberable();
-            assert node.isLeafNode();
+            assert node.getNodeClass().isLeafNode();
             this.node = node;
         }
 
         @Override
         public int hashCode() {
-            return node.getNodeClass().valueNumber(node);
+            return Node.USE_GENERATED_NODES ? node.valueNumberLeaf() : node.getNodeClass().valueNumber(node);
         }
 
         @Override
@@ -108,9 +116,8 @@
             }
             if (obj instanceof CacheEntry) {
                 CacheEntry other = (CacheEntry) obj;
-                NodeClass nodeClass = node.getNodeClass();
                 if (other.node.getClass() == node.getClass()) {
-                    return nodeClass.valueEqual(node, other.node);
+                    return node.valueEquals(other.node);
                 }
             }
             return false;
@@ -447,7 +454,7 @@
             return (T) other;
         } else {
             Node result = addIfMissing ? addHelper(node) : node;
-            if (node.isLeafNode()) {
+            if (node.getNodeClass().isLeafNode()) {
                 putNodeIntoCache(result);
             }
             return (T) result;
@@ -457,15 +464,15 @@
     void putNodeIntoCache(Node node) {
         assert node.graph() == this || node.graph() == null;
         assert node.getNodeClass().valueNumberable();
-        assert node.isLeafNode() : node.getClass();
-        cachedNodes.put(new CacheEntry(node), node);
+        assert node.getNodeClass().isLeafNode() : node.getClass();
+        cachedLeafNodes.put(new CacheEntry(node), node);
     }
 
     Node findNodeInCache(Node node) {
         CacheEntry key = new CacheEntry(node);
-        Node result = cachedNodes.get(key);
+        Node result = cachedLeafNodes.get(key);
         if (result != null && result.isDeleted()) {
-            cachedNodes.remove(key);
+            cachedLeafNodes.remove(key);
             return null;
         }
         return result;
@@ -474,7 +481,8 @@
     public Node findDuplicate(Node node) {
         NodeClass nodeClass = node.getNodeClass();
         assert nodeClass.valueNumberable();
-        if (node.isLeafNode()) {
+        if (nodeClass.isLeafNode()) {
+            // Leaf node: look up in cache
             Node cachedNode = findNodeInCache(node);
             if (cachedNode != null) {
                 return cachedNode;
@@ -482,6 +490,10 @@
                 return null;
             }
         } else {
+            // Non-leaf node: look for another usage of the node's inputs that
+            // has the same data, inputs and successors as the node. To reduce
+            // the cost of this computation, only the input with estimated highest
+            // usage count is considered.
 
             int minCount = Integer.MAX_VALUE;
             Node minCountNode = null;
@@ -498,7 +510,7 @@
             }
             if (minCountNode != null) {
                 for (Node usage : minCountNode.usages()) {
-                    if (usage != node && nodeClass == usage.getNodeClass() && nodeClass.valueEqual(node, usage) && nodeClass.getEdges(Inputs).areEqualIn(node, usage) &&
+                    if (usage != node && nodeClass == usage.getNodeClass() && node.valueEquals(usage) && nodeClass.getEdges(Inputs).areEqualIn(node, usage) &&
                                     nodeClass.getEdges(Successors).areEqualIn(node, usage)) {
                         return usage;
                     }
@@ -611,7 +623,7 @@
             return new PlaceHolderNode();
         }
 
-        PlaceHolderNode() {
+        protected PlaceHolderNode() {
         }
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java	Fri Oct 03 13:48:58 2014 +0200
@@ -26,6 +26,7 @@
 
 import java.util.*;
 
+import com.oracle.graal.graph.NodeClass.InputInfo;
 import com.oracle.graal.nodeinfo.*;
 
 public final class InputEdges extends Edges {
@@ -33,14 +34,20 @@
     private final InputType[] inputTypes;
     private final boolean[] isOptional;
 
-    public InputEdges(Class<?> nodeClass, int directCount, long[] offsets, Map<Long, String> names, Map<Long, Class<?>> types, Map<Long, InputType> inputTypes, Set<Long> isOptional) {
-        super(nodeClass, Inputs, directCount, offsets, names, types);
+    public InputEdges(int directCount, ArrayList<InputInfo> edges) {
+        super(Inputs, directCount, edges);
 
-        this.inputTypes = new InputType[offsets.length];
-        this.isOptional = new boolean[offsets.length];
-        for (int i = 0; i < offsets.length; i++) {
-            this.inputTypes[i] = inputTypes.get(offsets[i]);
-            this.isOptional[i] = isOptional.contains(offsets[i]);
+        this.inputTypes = new InputType[edges.size()];
+        this.isOptional = new boolean[edges.size()];
+        for (int i = 0; i < edges.size(); i++) {
+            this.inputTypes[i] = edges.get(i).inputType;
+            this.isOptional[i] = edges.get(i).optional;
+        }
+    }
+
+    public static void translateInto(InputEdges inputs, ArrayList<InputInfo> infos) {
+        for (int index = 0; index < inputs.getCount(); index++) {
+            infos.add(new InputInfo(inputs.offsets[index], inputs.getName(index), inputs.getType(index), inputs.inputTypes[index], inputs.isOptional(index)));
         }
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri Oct 03 13:48:58 2014 +0200
@@ -143,6 +143,14 @@
         boolean setStampFromReturnType() default false;
     }
 
+    /**
+     * Marker for a node that can be replaced by another node via global value numbering. A
+     * {@linkplain NodeClass#isLeafNode() leaf} node can be replaced by another node of the same
+     * type that has exactly the same {@linkplain NodeClass#getData() data} values. A non-leaf node
+     * can be replaced by another node of the same type that has exactly the same data values as
+     * well as the same {@linkplain Node#inputs() inputs} and {@linkplain Node#successors()
+     * successors}.
+     */
     public interface ValueNumberable {
     }
 
@@ -170,8 +178,7 @@
     public static final int NOT_ITERABLE = -1;
 
     public Node() {
-        assert USE_GENERATED_NODES == (getClass().getAnnotation(GeneratedNode.class) != null) : getClass() + " is not a generated Node class - forgot @" + NodeInfo.class.getSimpleName() +
-                        " on class declaration?";
+        assert USE_GENERATED_NODES == this instanceof GeneratedNode : getClass() + " is not a generated Node class - forgot @" + NodeInfo.class.getSimpleName() + " on class declaration?";
         init();
     }
 
@@ -740,7 +747,7 @@
 
     final Node clone(Graph into, boolean clearInputsAndSuccessors) {
         NodeClass nodeClass = getNodeClass();
-        if (into != null && nodeClass.valueNumberable() && isLeafNode()) {
+        if (into != null && nodeClass.valueNumberable() && nodeClass.isLeafNode()) {
             Node otherNode = into.findNodeInCache(this);
             if (otherNode != null) {
                 return otherNode;
@@ -768,20 +775,13 @@
         newNode.extraUsages = NO_NODES;
         newNode.predecessor = null;
 
-        if (into != null && nodeClass.valueNumberable() && isLeafNode()) {
+        if (into != null && nodeClass.valueNumberable() && nodeClass.isLeafNode()) {
             into.putNodeIntoCache(newNode);
         }
         newNode.afterClone(this);
         return newNode;
     }
 
-    /**
-     * @returns true if this node has no inputs and no successors
-     */
-    public boolean isLeafNode() {
-        return USE_GENERATED_NODES || getNodeClass().isLeafNode();
-    }
-
     protected void afterClone(@SuppressWarnings("unused") Node other) {
     }
 
@@ -885,7 +885,7 @@
      */
     public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
         NodeClass nodeClass = getNodeClass();
-        Fields properties = nodeClass.getProperties();
+        Fields properties = nodeClass.getData();
         for (int i = 0; i < properties.getCount(); i++) {
             map.put(properties.getName(i), properties.get(this, i));
         }
@@ -995,4 +995,38 @@
             }
         }
     }
+
+    /**
+     * If this node is a {@linkplain NodeClass#isLeafNode() leaf} node, returns a hash for this node
+     * based on its {@linkplain NodeClass#getData() data} fields otherwise return 0.
+     *
+     * Overridden by a method generated for leaf nodes.
+     */
+    protected int valueNumberLeaf() {
+        assert !getNodeClass().isLeafNode();
+        return 0;
+    }
+
+    /**
+     * Overridden by a generated method.
+     *
+     * @param other
+     */
+    protected boolean dataEquals(Node other) {
+        return true;
+    }
+
+    /**
+     * Determines if this node's {@link NodeClass#getData() data} fields are equal to the data
+     * fields of another node of the same type. Primitive fields are compared by value and
+     * non-primitive fields are compared by {@link Objects#equals(Object, Object)}.
+     *
+     * The result of this method undefined if {@code other.getClass() != this.getClass()}.
+     *
+     * @param other a node of exactly the same type as this node
+     * @return true if the data fields of this object and {@code other} are equal
+     */
+    public boolean valueEquals(Node other) {
+        return USE_GENERATED_NODES ? dataEquals(other) : getNodeClass().dataEquals(this, other);
+    }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri Oct 03 13:48:58 2014 +0200
@@ -22,16 +22,21 @@
  */
 package com.oracle.graal.graph;
 
+import static com.oracle.graal.compiler.common.Fields.*;
+import static com.oracle.graal.graph.Edges.*;
+import static com.oracle.graal.graph.InputEdges.*;
 import static com.oracle.graal.graph.Node.*;
 import static com.oracle.graal.graph.util.CollectionsAccess.*;
 import static java.lang.reflect.Modifier.*;
 
+import java.lang.annotation.*;
 import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.internal.*;
+import com.oracle.graal.graph.Edges.Type;
 import com.oracle.graal.graph.Graph.DuplicationReplacement;
 import com.oracle.graal.graph.Node.Input;
 import com.oracle.graal.graph.Node.Successor;
@@ -53,12 +58,19 @@
     // Timers for creation of a NodeClass instance
     private static final DebugTimer Init = Debug.timer("NodeClass.Init");
     private static final DebugTimer Init_FieldScanning = Debug.timer("NodeClass.Init.FieldScanning");
+    private static final DebugTimer Init_FieldScanningInner = Debug.timer("NodeClass.Init.FieldScanning.Inner");
+    private static final DebugTimer Init_AnnotationParsing = Debug.timer("NodeClass.Init.AnnotationParsing");
     private static final DebugTimer Init_Edges = Debug.timer("NodeClass.Init.Edges");
     private static final DebugTimer Init_Data = Debug.timer("NodeClass.Init.Data");
-    private static final DebugTimer Init_Naming = Debug.timer("NodeClass.Init.Naming");
     private static final DebugTimer Init_AllowedUsages = Debug.timer("NodeClass.Init.AllowedUsages");
     private static final DebugTimer Init_IterableIds = Debug.timer("NodeClass.Init.IterableIds");
 
+    private static <T extends Annotation> T getAnnotationTimed(AnnotatedElement e, Class<T> annotationClass) {
+        try (TimerCloseable s = Init_AnnotationParsing.start()) {
+            return e.getAnnotation(annotationClass);
+        }
+    }
+
     /**
      * Gets the {@link NodeClass} associated with a given {@link Class}.
      */
@@ -76,9 +88,9 @@
                 try (TimerCloseable t = Init.start()) {
                     value = (NodeClass) allClasses.get(key);
                     if (value == null) {
-                        GeneratedNode gen = c.getAnnotation(GeneratedNode.class);
-                        if (gen != null) {
-                            Class<? extends Node> originalNodeClass = (Class<? extends Node>) gen.value();
+                        Class<?> superclass = c.getSuperclass();
+                        if (GeneratedNode.class.isAssignableFrom(c)) {
+                            Class<? extends Node> originalNodeClass = (Class<? extends Node>) superclass;
                             value = (NodeClass) allClasses.get(originalNodeClass);
                             assert value != null;
                             if (value.genClass == null) {
@@ -87,12 +99,12 @@
                                 assert value.genClass == c;
                             }
                         } else {
-                            Class<?> superclass = c.getSuperclass();
+                            NodeClass superNodeClass = null;
                             if (superclass != NODE_CLASS) {
                                 // Ensure NodeClass for superclass exists
-                                get(superclass);
+                                superNodeClass = get(superclass);
                             }
-                            value = new NodeClass(key);
+                            value = new NodeClass(key, superNodeClass);
                         }
                         Object old = allClasses.putIfAbsent(key, value);
                         assert old == null : old + "   " + key;
@@ -109,13 +121,12 @@
 
     private static int nextIterableId = 0;
 
-    private final Edges inputs;
-    private final Edges successors;
-    private final Fields properties;
+    private final InputEdges inputs;
+    private final SuccessorEdges successors;
+    private final NodeClass superNodeClass;
 
     private final boolean canGVN;
     private final int startGVNNumber;
-    private final String shortName;
     private final String nameTemplate;
     private final int iterableId;
     private final EnumSet<InputType> allowedUsageTypes;
@@ -142,19 +153,13 @@
     private final boolean isSimplifiable;
     private final boolean isLeafNode;
 
-    public NodeClass(Class<?> clazz) {
-        this(clazz, new DefaultCalcOffset(), null, 0);
+    public NodeClass(Class<?> clazz, NodeClass superNodeClass) {
+        this(clazz, superNodeClass, new DefaultCalcOffset(), null, 0);
     }
 
-    private static long[] sortedOffsets(ArrayList<Long> list1, ArrayList<Long> list2) {
-        if (list1.isEmpty() && list2.isEmpty()) {
-            return new long[0];
-        }
-        return sortedLongCopy(list1, list2);
-    }
-
-    public NodeClass(Class<?> clazz, CalcOffset calcOffset, int[] presetIterableIds, int presetIterableId) {
+    public NodeClass(Class<?> clazz, NodeClass superNodeClass, CalcOffset calcOffset, int[] presetIterableIds, int presetIterableId) {
         super(clazz);
+        this.superNodeClass = superNodeClass;
         assert NODE_CLASS.isAssignableFrom(clazz);
 
         this.isCanonicalizable = Canonicalizable.class.isAssignableFrom(clazz);
@@ -164,58 +169,32 @@
 
         this.isSimplifiable = Simplifiable.class.isAssignableFrom(clazz);
 
-        FieldScanner fs = new FieldScanner(calcOffset);
+        FieldScanner fs = new FieldScanner(calcOffset, superNodeClass);
         try (TimerCloseable t = Init_FieldScanning.start()) {
-            fs.scan(clazz);
+            fs.scan(clazz, false);
         }
 
         try (TimerCloseable t1 = Init_Edges.start()) {
-            successors = new SuccessorEdges(clazz, fs.successorOffsets.size(), sortedOffsets(fs.successorOffsets, fs.successorListOffsets), fs.fieldNames, fs.fieldTypes);
-            inputs = new InputEdges(clazz, fs.inputOffsets.size(), sortedOffsets(fs.inputOffsets, fs.inputListOffsets), fs.fieldNames, fs.fieldTypes, fs.types, fs.optionalInputs);
+            successors = new SuccessorEdges(fs.directSuccessors, fs.successors);
+            inputs = new InputEdges(fs.directInputs, fs.inputs);
         }
         try (TimerCloseable t1 = Init_Data.start()) {
-            properties = new Fields(clazz, sortedLongCopy(fs.dataOffsets), fs.fieldNames, fs.fieldTypes);
+            data = new Fields(fs.data);
         }
 
         isLeafNode = inputs.getCount() + successors.getCount() == 0;
-        fieldNames = fs.fieldNames;
-        fieldTypes = fs.fieldTypes;
 
         canGVN = Node.ValueNumberable.class.isAssignableFrom(clazz);
         startGVNNumber = clazz.hashCode();
 
-        String newNameTemplate = null;
-        String newShortName;
-        try (TimerCloseable t1 = Init_Naming.start()) {
-            newShortName = clazz.getSimpleName();
-            if (newShortName.endsWith("Node") && !newShortName.equals("StartNode") && !newShortName.equals("EndNode")) {
-                newShortName = newShortName.substring(0, newShortName.length() - 4);
-            }
-            NodeInfo info = clazz.getAnnotation(NodeInfo.class);
-            assert info != null : "missing " + NodeInfo.class.getSimpleName() + " annotation on " + clazz;
-            if (!info.shortName().isEmpty()) {
-                newShortName = info.shortName();
-            }
-            if (!info.nameTemplate().isEmpty()) {
-                newNameTemplate = info.nameTemplate();
-            }
+        NodeInfo info = getAnnotationTimed(clazz, NodeInfo.class);
+        this.nameTemplate = info.nameTemplate();
+
+        try (TimerCloseable t1 = Init_AllowedUsages.start()) {
+            allowedUsageTypes = superNodeClass == null ? EnumSet.noneOf(InputType.class) : superNodeClass.allowedUsageTypes.clone();
+            allowedUsageTypes.addAll(Arrays.asList(info.allowedUsageTypes()));
         }
-        EnumSet<InputType> newAllowedUsageTypes = EnumSet.noneOf(InputType.class);
-        try (TimerCloseable t1 = Init_AllowedUsages.start()) {
-            Class<?> current = clazz;
-            do {
-                NodeInfo currentInfo = current.getAnnotation(NodeInfo.class);
-                if (currentInfo != null) {
-                    if (currentInfo.allowedUsageTypes().length > 0) {
-                        newAllowedUsageTypes.addAll(Arrays.asList(currentInfo.allowedUsageTypes()));
-                    }
-                }
-                current = current.getSuperclass();
-            } while (current != Node.class);
-        }
-        this.nameTemplate = newNameTemplate == null ? newShortName : newNameTemplate;
-        this.allowedUsageTypes = newAllowedUsageTypes;
-        this.shortName = newShortName;
+
         if (presetIterableIds != null) {
             this.iterableIds = presetIterableIds;
             this.iterableId = presetIterableId;
@@ -224,15 +203,12 @@
             try (TimerCloseable t1 = Init_IterableIds.start()) {
                 this.iterableId = nextIterableId++;
 
-                Class<?> superclass = clazz.getSuperclass();
-                while (superclass != NODE_CLASS) {
-                    if (IterableNodeType.class.isAssignableFrom(superclass)) {
-                        NodeClass superNodeClass = NodeClass.get(superclass);
-                        assert !containsId(this.iterableId, superNodeClass.iterableIds);
-                        superNodeClass.iterableIds = Arrays.copyOf(superNodeClass.iterableIds, superNodeClass.iterableIds.length + 1);
-                        superNodeClass.iterableIds[superNodeClass.iterableIds.length - 1] = this.iterableId;
-                    }
-                    superclass = superclass.getSuperclass();
+                NodeClass snc = superNodeClass;
+                while (snc != null && IterableNodeType.class.isAssignableFrom(snc.getClazz())) {
+                    assert !containsId(this.iterableId, snc.iterableIds);
+                    snc.iterableIds = Arrays.copyOf(snc.iterableIds, snc.iterableIds.length + 1);
+                    snc.iterableIds[snc.iterableIds.length - 1] = this.iterableId;
+                    snc = snc.superNodeClass;
                 }
 
                 this.iterableIds = new int[]{iterableId};
@@ -241,7 +217,7 @@
             this.iterableId = Node.NOT_ITERABLE;
             this.iterableIds = null;
         }
-        nodeIterableCount = Debug.metric("NodeIterable_%s", shortName);
+        nodeIterableCount = Debug.metric("NodeIterable_%s", clazz);
     }
 
     /**
@@ -284,7 +260,7 @@
      *
      * <pre>
      *     if (node.getNodeClass().is(BeginNode.class)) { ... }
-     * 
+     *
      *     // Due to generated Node classes, the test below
      *     // is *not* the same as the test above:
      *     if (node.getClass() == BeginNode.class) { ... }
@@ -293,11 +269,24 @@
      * @param nodeClass a {@linkplain GeneratedNode non-generated} {@link Node} class
      */
     public boolean is(Class<? extends Node> nodeClass) {
-        assert nodeClass.getAnnotation(GeneratedNode.class) == null : "cannot test NodeClas against generated " + nodeClass;
+        assert !GeneratedNode.class.isAssignableFrom(nodeClass) : "cannot test NodeClass against generated " + nodeClass;
         return nodeClass == getClazz();
     }
 
+    private String shortName;
+
     public String shortName() {
+        if (shortName == null) {
+            NodeInfo info = getClazz().getAnnotation(NodeInfo.class);
+            if (!info.shortName().isEmpty()) {
+                shortName = info.shortName();
+            } else {
+                shortName = getClazz().getSimpleName();
+                if (shortName.endsWith("Node") && !shortName.equals("StartNode") && !shortName.equals("EndNode")) {
+                    shortName = shortName.substring(0, shortName.length() - 4);
+                }
+            }
+        }
         return shortName;
     }
 
@@ -336,60 +325,117 @@
         return allowedUsageTypes;
     }
 
-    protected static class FieldScanner extends BaseFieldScanner {
+    /**
+     * Describes a field representing an input or successor edge in a node.
+     */
+    protected static class EdgeInfo extends FieldInfo {
+
+        public EdgeInfo(long offset, String name, Class<?> type) {
+            super(offset, name, type);
+        }
 
-        public final ArrayList<Long> inputOffsets = new ArrayList<>();
-        public final ArrayList<Long> inputListOffsets = new ArrayList<>();
-        public final ArrayList<Long> successorOffsets = new ArrayList<>();
-        public final ArrayList<Long> successorListOffsets = new ArrayList<>();
-        public final HashMap<Long, InputType> types = new HashMap<>();
-        public final HashSet<Long> optionalInputs = new HashSet<>();
+        /**
+         * Sorts non-list edges before list edges.
+         */
+        @Override
+        public int compareTo(FieldInfo o) {
+            if (NodeList.class.isAssignableFrom(o.type)) {
+                if (!NodeList.class.isAssignableFrom(type)) {
+                    return -1;
+                }
+            } else {
+                if (NodeList.class.isAssignableFrom(type)) {
+                    return 1;
+                }
+            }
+            return super.compareTo(o);
+        }
+    }
 
-        protected FieldScanner(CalcOffset calc) {
-            super(calc);
+    /**
+     * Describes a field representing an {@linkplain Type#Inputs input} edge in a node.
+     */
+    protected static class InputInfo extends EdgeInfo {
+        final InputType inputType;
+        final boolean optional;
+
+        public InputInfo(long offset, String name, Class<?> type, InputType inputType, boolean optional) {
+            super(offset, name, type);
+            this.inputType = inputType;
+            this.optional = optional;
         }
 
         @Override
-        protected void scanField(Field field, Class<?> type, long offset) {
-            if (field.isAnnotationPresent(Node.Input.class) || field.isAnnotationPresent(Node.OptionalInput.class)) {
-                assert !field.isAnnotationPresent(Node.Successor.class) : "field cannot be both input and successor";
-                assert field.isAnnotationPresent(Node.Input.class) ^ field.isAnnotationPresent(Node.OptionalInput.class) : "inputs can either be optional or non-optional";
-                if (INPUT_LIST_CLASS.isAssignableFrom(type)) {
-                    // NodeInputList fields should not be final since they are
-                    // written (via Unsafe) in clearInputs()
-                    GraalInternalError.guarantee(!Modifier.isFinal(field.getModifiers()), "NodeInputList input field %s should not be final", field);
-                    GraalInternalError.guarantee(!Modifier.isPublic(field.getModifiers()), "NodeInputList input field %s should not be public", field);
-                    inputListOffsets.add(offset);
+        public String toString() {
+            return super.toString() + "{inputType=" + inputType + ", optional=" + optional + "}";
+        }
+    }
+
+    protected static class FieldScanner extends BaseFieldScanner {
+
+        public final ArrayList<InputInfo> inputs = new ArrayList<>();
+        public final ArrayList<EdgeInfo> successors = new ArrayList<>();
+        int directInputs;
+        int directSuccessors;
+
+        protected FieldScanner(CalcOffset calc, NodeClass superNodeClass) {
+            super(calc);
+            if (superNodeClass != null) {
+                translateInto(superNodeClass.inputs, inputs);
+                translateInto(superNodeClass.successors, successors);
+                translateInto(superNodeClass.data, data);
+                directInputs = superNodeClass.inputs.getDirectCount();
+                directSuccessors = superNodeClass.successors.getDirectCount();
+            }
+        }
+
+        @Override
+        protected void scanField(Field field, long offset) {
+            Input inputAnnotation = getAnnotationTimed(field, Node.Input.class);
+            OptionalInput optionalInputAnnotation = getAnnotationTimed(field, Node.OptionalInput.class);
+            Successor successorAnnotation = getAnnotationTimed(field, Successor.class);
+            try (TimerCloseable s = Init_FieldScanningInner.start()) {
+                Class<?> type = field.getType();
+                int modifiers = field.getModifiers();
+
+                if (inputAnnotation != null || optionalInputAnnotation != null) {
+                    assert successorAnnotation == null : "field cannot be both input and successor";
+                    if (INPUT_LIST_CLASS.isAssignableFrom(type)) {
+                        // NodeInputList fields should not be final since they are
+                        // written (via Unsafe) in clearInputs()
+                        GraalInternalError.guarantee(!Modifier.isFinal(modifiers), "NodeInputList input field %s should not be final", field);
+                        GraalInternalError.guarantee(!Modifier.isPublic(modifiers), "NodeInputList input field %s should not be public", field);
+                    } else {
+                        GraalInternalError.guarantee(NODE_CLASS.isAssignableFrom(type) || type.isInterface(), "invalid input type: %s", type);
+                        GraalInternalError.guarantee(!Modifier.isFinal(modifiers), "Node input field %s should not be final", field);
+                        directInputs++;
+                    }
+                    InputType inputType;
+                    if (inputAnnotation != null) {
+                        assert optionalInputAnnotation == null : "inputs can either be optional or non-optional";
+                        inputType = inputAnnotation.value();
+                    } else {
+                        inputType = optionalInputAnnotation.value();
+                    }
+                    inputs.add(new InputInfo(offset, field.getName(), type, inputType, field.isAnnotationPresent(Node.OptionalInput.class)));
+                } else if (successorAnnotation != null) {
+                    if (SUCCESSOR_LIST_CLASS.isAssignableFrom(type)) {
+                        // NodeSuccessorList fields should not be final since they are
+                        // written (via Unsafe) in clearSuccessors()
+                        GraalInternalError.guarantee(!Modifier.isFinal(modifiers), "NodeSuccessorList successor field % should not be final", field);
+                        GraalInternalError.guarantee(!Modifier.isPublic(modifiers), "NodeSuccessorList successor field %s should not be public", field);
+                    } else {
+                        GraalInternalError.guarantee(NODE_CLASS.isAssignableFrom(type), "invalid successor type: %s", type);
+                        GraalInternalError.guarantee(!Modifier.isFinal(modifiers), "Node successor field %s should not be final", field);
+                        directSuccessors++;
+                    }
+                    successors.add(new EdgeInfo(offset, field.getName(), type));
                 } else {
-                    GraalInternalError.guarantee(NODE_CLASS.isAssignableFrom(type) || type.isInterface(), "invalid input type: %s", type);
-                    GraalInternalError.guarantee(!Modifier.isFinal(field.getModifiers()), "Node input field %s should not be final", field);
-                    inputOffsets.add(offset);
-                }
-                if (field.isAnnotationPresent(Node.Input.class)) {
-                    types.put(offset, field.getAnnotation(Node.Input.class).value());
-                } else {
-                    types.put(offset, field.getAnnotation(Node.OptionalInput.class).value());
+                    GraalInternalError.guarantee(!NODE_CLASS.isAssignableFrom(type) || field.getName().equals("Null"), "suspicious node field: %s", field);
+                    GraalInternalError.guarantee(!INPUT_LIST_CLASS.isAssignableFrom(type), "suspicious node input list field: %s", field);
+                    GraalInternalError.guarantee(!SUCCESSOR_LIST_CLASS.isAssignableFrom(type), "suspicious node successor list field: %s", field);
+                    data.add(new FieldInfo(offset, field.getName(), type));
                 }
-                if (field.isAnnotationPresent(Node.OptionalInput.class)) {
-                    optionalInputs.add(offset);
-                }
-            } else if (field.isAnnotationPresent(Node.Successor.class)) {
-                if (SUCCESSOR_LIST_CLASS.isAssignableFrom(type)) {
-                    // NodeSuccessorList fields should not be final since they are
-                    // written (via Unsafe) in clearSuccessors()
-                    GraalInternalError.guarantee(!Modifier.isFinal(field.getModifiers()), "NodeSuccessorList successor field % should not be final", field);
-                    GraalInternalError.guarantee(!Modifier.isPublic(field.getModifiers()), "NodeSuccessorList successor field %s should not be public", field);
-                    successorListOffsets.add(offset);
-                } else {
-                    GraalInternalError.guarantee(NODE_CLASS.isAssignableFrom(type), "invalid successor type: %s", type);
-                    GraalInternalError.guarantee(!Modifier.isFinal(field.getModifiers()), "Node successor field %s should not be final", field);
-                    successorOffsets.add(offset);
-                }
-            } else {
-                GraalInternalError.guarantee(!NODE_CLASS.isAssignableFrom(type) || field.getName().equals("Null"), "suspicious node field: %s", field);
-                GraalInternalError.guarantee(!INPUT_LIST_CLASS.isAssignableFrom(type), "suspicious node input list field: %s", field);
-                GraalInternalError.guarantee(!SUCCESSOR_LIST_CLASS.isAssignableFrom(type), "suspicious node successor list field: %s", field);
-                dataOffsets.add(offset);
             }
         }
     }
@@ -402,7 +448,7 @@
         str.append("] [");
         successors.appendFields(str);
         str.append("] [");
-        properties.appendFields(str);
+        data.appendFields(str);
         str.append("]");
         return str.toString();
     }
@@ -437,41 +483,41 @@
         int number = 0;
         if (canGVN) {
             number = startGVNNumber;
-            for (int i = 0; i < properties.getCount(); ++i) {
-                Class<?> type = properties.getType(i);
+            for (int i = 0; i < data.getCount(); ++i) {
+                Class<?> type = data.getType(i);
                 if (type.isPrimitive()) {
                     if (type == Integer.TYPE) {
-                        int intValue = properties.getInt(n, i);
+                        int intValue = data.getInt(n, i);
                         number += intValue;
                     } else if (type == Long.TYPE) {
-                        long longValue = properties.getLong(n, i);
+                        long longValue = data.getLong(n, i);
                         number += longValue ^ (longValue >>> 32);
                     } else if (type == Boolean.TYPE) {
-                        boolean booleanValue = properties.getBoolean(n, i);
+                        boolean booleanValue = data.getBoolean(n, i);
                         if (booleanValue) {
                             number += 7;
                         }
                     } else if (type == Float.TYPE) {
-                        float floatValue = properties.getFloat(n, i);
+                        float floatValue = data.getFloat(n, i);
                         number += Float.floatToRawIntBits(floatValue);
                     } else if (type == Double.TYPE) {
-                        double doubleValue = properties.getDouble(n, i);
+                        double doubleValue = data.getDouble(n, i);
                         long longValue = Double.doubleToRawLongBits(doubleValue);
                         number += longValue ^ (longValue >>> 32);
                     } else if (type == Short.TYPE) {
-                        short shortValue = properties.getShort(n, i);
+                        short shortValue = data.getShort(n, i);
                         number += shortValue;
                     } else if (type == Character.TYPE) {
-                        char charValue = properties.getChar(n, i);
+                        char charValue = data.getChar(n, i);
                         number += charValue;
                     } else if (type == Byte.TYPE) {
-                        byte byteValue = properties.getByte(n, i);
+                        byte byteValue = data.getByte(n, i);
                         number += byteValue;
                     } else {
                         assert false : "unhandled property type: " + type;
                     }
                 } else {
-                    Object o = properties.getObject(n, i);
+                    Object o = data.getObject(n, i);
                     number += deepHashCode0(o);
                 }
                 number *= 13;
@@ -507,58 +553,56 @@
         return eq;
     }
 
-    public boolean valueEqual(Node a, Node b) {
-        if (a.getClass() != b.getClass()) {
-            return a == b;
-        }
-        for (int i = 0; i < properties.getCount(); ++i) {
-            Class<?> type = properties.getType(i);
+    public boolean dataEquals(Node a, Node b) {
+        assert a.getClass() == b.getClass();
+        for (int i = 0; i < data.getCount(); ++i) {
+            Class<?> type = data.getType(i);
             if (type.isPrimitive()) {
                 if (type == Integer.TYPE) {
-                    int aInt = properties.getInt(a, i);
-                    int bInt = properties.getInt(b, i);
+                    int aInt = data.getInt(a, i);
+                    int bInt = data.getInt(b, i);
                     if (aInt != bInt) {
                         return false;
                     }
                 } else if (type == Boolean.TYPE) {
-                    boolean aBoolean = properties.getBoolean(a, i);
-                    boolean bBoolean = properties.getBoolean(b, i);
+                    boolean aBoolean = data.getBoolean(a, i);
+                    boolean bBoolean = data.getBoolean(b, i);
                     if (aBoolean != bBoolean) {
                         return false;
                     }
                 } else if (type == Long.TYPE) {
-                    long aLong = properties.getLong(a, i);
-                    long bLong = properties.getLong(b, i);
+                    long aLong = data.getLong(a, i);
+                    long bLong = data.getLong(b, i);
                     if (aLong != bLong) {
                         return false;
                     }
                 } else if (type == Float.TYPE) {
-                    float aFloat = properties.getFloat(a, i);
-                    float bFloat = properties.getFloat(b, i);
+                    float aFloat = data.getFloat(a, i);
+                    float bFloat = data.getFloat(b, i);
                     if (aFloat != bFloat) {
                         return false;
                     }
                 } else if (type == Double.TYPE) {
-                    double aDouble = properties.getDouble(a, i);
-                    double bDouble = properties.getDouble(b, i);
+                    double aDouble = data.getDouble(a, i);
+                    double bDouble = data.getDouble(b, i);
                     if (aDouble != bDouble) {
                         return false;
                     }
                 } else if (type == Short.TYPE) {
-                    short aShort = properties.getShort(a, i);
-                    short bShort = properties.getShort(b, i);
+                    short aShort = data.getShort(a, i);
+                    short bShort = data.getShort(b, i);
                     if (aShort != bShort) {
                         return false;
                     }
                 } else if (type == Character.TYPE) {
-                    char aChar = properties.getChar(a, i);
-                    char bChar = properties.getChar(b, i);
+                    char aChar = data.getChar(a, i);
+                    char bChar = data.getChar(b, i);
                     if (aChar != bChar) {
                         return false;
                     }
                 } else if (type == Byte.TYPE) {
-                    byte aByte = properties.getByte(a, i);
-                    byte bByte = properties.getByte(b, i);
+                    byte aByte = data.getByte(a, i);
+                    byte bByte = data.getByte(b, i);
                     if (aByte != bByte) {
                         return false;
                     }
@@ -566,8 +610,8 @@
                     assert false : "unhandled type: " + type;
                 }
             } else {
-                Object objectA = properties.getObject(a, i);
-                Object objectB = properties.getObject(b, i);
+                Object objectA = data.getObject(a, i);
+                Object objectB = data.getObject(b, i);
                 if (objectA != objectB) {
                     if (objectA != null && objectB != null) {
                         if (!deepEquals0(objectA, objectB)) {
@@ -596,13 +640,6 @@
         return toEdges.isSame(fromEdges, pos.getIndex());
     }
 
-    /**
-     * Gets the non-edge properties defined by this node class.
-     */
-    public Fields getProperties() {
-        return properties;
-    }
-
     static void updateEdgesInPlace(Node node, InplaceUpdateClosure duplicationReplacement, Edges edges) {
         int index = 0;
         while (index < edges.getDirectCount()) {
@@ -677,11 +714,11 @@
     }
 
     /**
-     * The template used to build the {@link Verbosity#Name} version. Variable part are specified
+     * The template used to build the {@link Verbosity#Name} version. Variable parts are specified
      * using &#123;i#inputName&#125; or &#123;p#propertyName&#125;.
      */
     public String getNameTemplate() {
-        return nameTemplate;
+        return nameTemplate.isEmpty() ? shortName() : nameTemplate;
     }
 
     interface InplaceUpdateClosure {
@@ -790,6 +827,9 @@
         }
     }
 
+    /**
+     * @returns true if the node has no inputs and no successors
+     */
     public boolean isLeafNode() {
         return isLeafNode;
     }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/SuccessorEdges.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/SuccessorEdges.java	Fri Oct 03 13:48:58 2014 +0200
@@ -26,10 +26,12 @@
 
 import java.util.*;
 
+import com.oracle.graal.graph.NodeClass.EdgeInfo;
+
 public final class SuccessorEdges extends Edges {
 
-    public SuccessorEdges(Class<?> nodeClass, int directCount, long[] offsets, Map<Long, String> names, Map<Long, Class<?>> types) {
-        super(nodeClass, Successors, directCount, offsets, names, types);
+    public SuccessorEdges(int directCount, ArrayList<EdgeInfo> edges) {
+        super(Successors, directCount, edges);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri Oct 03 13:48:58 2014 +0200
@@ -51,6 +51,7 @@
 import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StoreOp;
 import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.phases.util.*;
 
 /**
  * LIR generator specialized for AMD64 HotSpot.
@@ -459,6 +460,28 @@
         return result;
     }
 
+    /**
+     * Checks whether the supplied constant can be used without loading it into a register for store
+     * operations, i.e., on the right hand side of a memory access.
+     *
+     * @param c The constant to check.
+     * @return True if the constant can be used directly, false if the constant needs to be in a
+     *         register.
+     */
+    protected boolean canStoreConstant(Constant c) {
+        // there is no immediate move of 64-bit constants on Intel
+        switch (c.getKind()) {
+            case Long:
+                return Util.isInt(c.asLong()) && !getCodeCache().needsDataPatch(c);
+            case Double:
+                return false;
+            case Object:
+                return c.isNull();
+            default:
+                return true;
+        }
+    }
+
     @Override
     public void emitStore(LIRKind kind, Value address, Value inputVal, LIRFrameState state) {
         AMD64AddressValue storeAddress = asAddressValue(address);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -35,7 +35,7 @@
 @NodeInfo
 public class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
 
-    private final Constant functionPointer;
+    protected final Constant functionPointer;
     @Input NodeInputList<ValueNode> args;
 
     public static AMD64RawNativeCallNode create(Kind returnType, Constant functionPointer, ValueNode[] args) {
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Fri Oct 03 13:48:58 2014 +0200
@@ -93,8 +93,7 @@
         return config.narrowKlassBase;
     }
 
-    @Override
-    public boolean canStoreConstant(Constant c) {
+    private static boolean canStoreConstant(Constant c) {
         return !(c instanceof HotSpotObjectConstant);
     }
 
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILDirectStoreReleaseNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILDirectStoreReleaseNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -45,8 +45,8 @@
     public void generate(NodeLIRBuilderTool gen) {
         HSAILHotSpotLIRGenerator hsailgen = (HSAILHotSpotLIRGenerator) (gen.getLIRGeneratorTool());
         Value v = gen.operand(getValue());
-        LIRKind kind = hsailgen.getLIRKind(getValue().stamp());
-        hsailgen.emitStoreRelease(kind, gen.operand(getAddress()), v, null);
+        LIRKind lirKind = hsailgen.getLIRKind(getValue().stamp());
+        hsailgen.emitStoreRelease(lirKind, gen.operand(getAddress()), v, null);
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java	Fri Oct 03 13:48:58 2014 +0200
@@ -224,7 +224,7 @@
         return kernel;
     }
 
-    static final class RegisterAnalysis extends ValueConsumer {
+    static final class RegisterAnalysis implements ValueConsumer {
         private final SortedSet<Integer> signed32 = new TreeSet<>();
         private final SortedSet<Integer> signed64 = new TreeSet<>();
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Fri Oct 03 13:48:58 2014 +0200
@@ -25,8 +25,8 @@
 import static com.oracle.graal.api.code.CallingConvention.Type.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.sparc.SPARC.*;
-import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 
 import java.util.*;
 
@@ -345,16 +345,13 @@
         private final Set<Object> inputs = new HashSet<>(10);
         private boolean overlap = false;
 
-        private final InstructionValueConsumer valueConsumer = new InstructionValueConsumer() {
-            @Override
-            protected void visitValue(LIRInstruction instruction, Value value) {
-                Object valueObject = value;
-                if (isRegister(value)) { // Canonicalize registers
-                    valueObject = asRegister(value);
-                }
-                if (!inputs.add(valueObject)) {
-                    overlap = true;
-                }
+        private final InstructionValueConsumer valueConsumer = (instruction, value, mode, flags) -> {
+            Object valueObject = value;
+            if (isRegister(value)) { // Canonicalize registers
+                valueObject = asRegister(value);
+            }
+            if (!inputs.add(valueObject)) {
+                overlap = true;
             }
         };
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Fri Oct 03 13:48:58 2014 +0200
@@ -191,6 +191,17 @@
         return result;
     }
 
+    private static boolean canStoreConstant(Constant c) {
+        // SPARC can only store integer null constants (via g0)
+        switch (c.getKind()) {
+            case Float:
+            case Double:
+                return false;
+            default:
+                return c.isDefaultForKind();
+        }
+    }
+
     @Override
     public void emitStore(LIRKind kind, Value address, Value inputVal, LIRFrameState state) {
         SPARCAddressValue storeAddress = asAddressValue(address);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/DebugValuesPrinter.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/DebugValuesPrinter.java	Fri Oct 03 13:48:58 2014 +0200
@@ -37,77 +37,65 @@
  */
 public class DebugValuesPrinter {
 
-    public void printDebugValues(String phase, boolean reset) throws GraalInternalError {
-        if (Debug.areUnconditionalMetricsEnabled() || Debug.areUnconditionalTimersEnabled() || (Debug.isEnabled() && areMetricsOrTimersEnabled())) {
-            TTY.println();
-            if (phase != null) {
-                TTY.println("<DebugValues:" + phase + ">");
-            } else {
-                TTY.println("<DebugValues>");
-            }
-            List<DebugValueMap> topLevelMaps = DebugValueMap.getTopLevelMaps();
-            List<DebugValue> debugValues = KeyRegistry.getDebugValues();
-            if (debugValues.size() > 0) {
-                try {
-                    ArrayList<DebugValue> sortedValues = new ArrayList<>(debugValues);
-                    Collections.sort(sortedValues);
+    public void printDebugValues() throws GraalInternalError {
+        TTY.println();
+        TTY.println("<DebugValues>");
+        List<DebugValueMap> topLevelMaps = DebugValueMap.getTopLevelMaps();
+        List<DebugValue> debugValues = KeyRegistry.getDebugValues();
+        if (debugValues.size() > 0) {
+            try {
+                ArrayList<DebugValue> sortedValues = new ArrayList<>(debugValues);
+                Collections.sort(sortedValues);
 
-                    String summary = DebugValueSummary.getValue();
-                    if (summary == null) {
-                        summary = "Complete";
-                    }
-                    switch (summary) {
-                        case "Name":
-                            printSummary(topLevelMaps, sortedValues);
-                            break;
-                        case "Partial": {
-                            DebugValueMap globalMap = new DebugValueMap("Global");
-                            for (DebugValueMap map : topLevelMaps) {
-                                flattenChildren(map, globalMap);
-                            }
-                            globalMap.normalize();
-                            printMap(new DebugValueScope(null, globalMap), sortedValues);
-                            break;
+                String summary = DebugValueSummary.getValue();
+                if (summary == null) {
+                    summary = "Complete";
+                }
+                switch (summary) {
+                    case "Name":
+                        printSummary(topLevelMaps, sortedValues);
+                        break;
+                    case "Partial": {
+                        DebugValueMap globalMap = new DebugValueMap("Global");
+                        for (DebugValueMap map : topLevelMaps) {
+                            flattenChildren(map, globalMap);
                         }
-                        case "Complete": {
-                            DebugValueMap globalMap = new DebugValueMap("Global");
-                            for (DebugValueMap map : topLevelMaps) {
-                                globalMap.addChild(map);
-                            }
-                            globalMap.group();
-                            globalMap.normalize();
-                            printMap(new DebugValueScope(null, globalMap), sortedValues);
-                            break;
+                        globalMap.normalize();
+                        printMap(new DebugValueScope(null, globalMap), sortedValues);
+                        break;
+                    }
+                    case "Complete": {
+                        DebugValueMap globalMap = new DebugValueMap("Global");
+                        for (DebugValueMap map : topLevelMaps) {
+                            globalMap.addChild(map);
                         }
-                        case "Thread":
-                            for (DebugValueMap map : topLevelMaps) {
-                                TTY.println("Showing the results for thread: " + map.getName());
-                                map.group();
-                                map.normalize();
-                                printMap(new DebugValueScope(null, map), sortedValues);
-                            }
-                            break;
-                        default:
-                            throw new GraalInternalError("Unknown summary type: %s", summary);
+                        globalMap.group();
+                        globalMap.normalize();
+                        printMap(new DebugValueScope(null, globalMap), sortedValues);
+                        break;
                     }
-                    if (reset) {
-                        for (DebugValueMap topLevelMap : topLevelMaps) {
-                            topLevelMap.reset();
+                    case "Thread":
+                        for (DebugValueMap map : topLevelMaps) {
+                            TTY.println("Showing the results for thread: " + map.getName());
+                            map.group();
+                            map.normalize();
+                            printMap(new DebugValueScope(null, map), sortedValues);
                         }
-                    }
-                } catch (Throwable e) {
-                    // Don't want this to change the exit status of the VM
-                    PrintStream err = System.err;
-                    err.println("Error while printing debug values:");
-                    e.printStackTrace();
+                        break;
+                    default:
+                        throw new GraalInternalError("Unknown summary type: %s", summary);
                 }
-            }
-            if (phase != null) {
-                TTY.println("</DebugValues:" + phase + ">");
-            } else {
-                TTY.println("</DebugValues>");
+                for (DebugValueMap topLevelMap : topLevelMaps) {
+                    topLevelMap.reset();
+                }
+            } catch (Throwable e) {
+                // Don't want this to change the exit status of the VM
+                PrintStream err = System.err;
+                err.println("Error while printing debug values:");
+                e.printStackTrace();
             }
         }
+        TTY.println("</DebugValues>");
     }
 
     private void flattenChildren(DebugValueMap map, DebugValueMap globalMap) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Fri Oct 03 13:48:58 2014 +0200
@@ -36,6 +36,8 @@
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.StandardOp.LabelOp;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.nodes.*;
@@ -154,7 +156,7 @@
         ValueConsumer defConsumer = new ValueConsumer() {
 
             @Override
-            public void visitValue(Value value) {
+            public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
                 if (ValueUtil.isRegister(value)) {
                     final Register reg = ValueUtil.asRegister(value);
                     definedRegisters.add(reg);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Fri Oct 03 13:48:58 2014 +0200
@@ -134,6 +134,12 @@
             }
         }
 
+        if (Debug.areUnconditionalMetricsEnabled() || Debug.areUnconditionalTimersEnabled() || (Debug.isEnabled() && areMetricsOrTimersEnabled())) {
+            // This must be created here to avoid loading the DebugValuesPrinter class
+            // during shutdown() which in turn can cause a deadlock
+            debugValuesPrinter = new DebugValuesPrinter();
+        }
+
         // Complete initialization of backends
         try (InitTimer st = timer(hostBackend.getTarget().arch.getName(), ".completeInitialization")) {
             hostBackend.completeInitialization();
@@ -247,6 +253,7 @@
 
     protected final HotSpotVMConfig config;
     private final HotSpotBackend hostBackend;
+    private DebugValuesPrinter debugValuesPrinter;
 
     /**
      * Graal mirrors are stored as a {@link ClassValue} associated with the {@link Class} of the
@@ -581,7 +588,9 @@
      */
     @SuppressWarnings("unused")
     private void shutdown() throws Exception {
-        new DebugValuesPrinter().printDebugValues(ResetDebugValuesAfterBootstrap.getValue() ? "application" : null, false);
+        if (debugValuesPrinter != null) {
+            debugValuesPrinter.printDebugValues();
+        }
         phaseTransition("final");
 
         SnippetCounter.printGroups(TTY.out().out());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRFrameState.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRFrameState.java	Fri Oct 03 13:48:58 2014 +0200
@@ -38,11 +38,11 @@
     }
 
     @Override
-    protected Value processValue(LIRInstruction inst, InstructionValueProcedureBase proc, Value value) {
+    protected Value processValue(LIRInstruction inst, InstructionValueProcedure proc, Value value) {
         if (value instanceof HotSpotMonitorValue) {
             HotSpotMonitorValue monitor = (HotSpotMonitorValue) value;
             if (processed(monitor.getOwner())) {
-                monitor.setOwner(proc.processValue(inst, monitor.getOwner(), OperandMode.ALIVE, STATE_FLAGS));
+                monitor.setOwner(proc.doValue(inst, monitor.getOwner(), OperandMode.ALIVE, STATE_FLAGS));
             }
             return value;
         } else {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/data/DataSection.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/data/DataSection.java	Fri Oct 03 13:48:58 2014 +0200
@@ -56,6 +56,8 @@
         int patchCount = 0;
         List<DataPatch> externalDataList = new ArrayList<>();
 
+        Map<Data, Integer> dataMap = new HashMap<>();
+
         // find all external data items and determine total size of data section
         for (Site site : sites) {
             if (site instanceof DataPatch) {
@@ -64,12 +66,16 @@
                 if (dataPatch.inline) {
                     assert d instanceof PatchedData : "unnecessary data patch";
                 } else {
-                    size = NumUtil.roundUp(size, d.getAlignment());
-                    size += d.getSize(target);
+                    Integer existingPos = dataMap.get(d);
+                    if (existingPos == null) {
+                        size = NumUtil.roundUp(size, d.getAlignment());
+                        size += d.getSize(target);
+                        if (d instanceof PatchedData) {
+                            patchCount++;
+                        }
+                        dataMap.put(d, externalDataList.size());
+                    }
                     externalDataList.add(dataPatch);
-                    if (d instanceof PatchedData) {
-                        patchCount++;
-                    }
                 }
             }
         }
@@ -82,23 +88,29 @@
         int alignment = 0;
 
         // build data section
-        for (DataPatch dataPatch : externalDataList) {
+        for (int i = 0; i < externalDataList.size(); i++) {
+            DataPatch dataPatch = externalDataList.get(i);
             assert !dataPatch.inline;
             Data d = dataPatch.data;
 
-            alignment = Math.max(alignment, d.getAlignment());
-            index = NumUtil.roundUp(index, d.getAlignment());
-            buffer.position(index);
+            Integer existingPos = dataMap.get(d);
+            if (existingPos == i) {
+                alignment = Math.max(alignment, d.getAlignment());
+                index = NumUtil.roundUp(index, d.getAlignment());
+                buffer.position(index);
 
-            DataSectionReference reference = new DataSectionReference(index);
-            if (d instanceof PatchedData) {
-                // record patch location
-                patches[patchIndex++] = new DataPatch(index, d, true);
+                DataSectionReference reference = new DataSectionReference(index);
+                if (d instanceof PatchedData) {
+                    // record patch location
+                    patches[patchIndex++] = new DataPatch(index, d, true);
+                }
+                dataPatch.data = reference;
+
+                index += d.getSize(target);
+                d.emit(target, buffer);
+            } else {
+                dataPatch.data = externalDataList.get(existingPos).data;
             }
-            dataPatch.data = reference;
-
-            index += d.getSize(target);
-            d.emit(target, buffer);
         }
 
         this.sectionAlignment = alignment;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -42,14 +42,14 @@
     /**
      * The number of slots in block.
      */
-    private final int slots;
+    protected final int slots;
 
     /**
      * The indexes of the object pointer slots in the block. Each such object pointer slot must be
      * initialized before any safepoint in the method otherwise the garbage collector will see
      * garbage values when processing these slots.
      */
-    private final BitSet objects;
+    protected final BitSet objects;
 
     public static AllocaNode create(int slots, BitSet objects) {
         return USE_GENERATED_NODES ? new AllocaNodeGen(slots, objects) : new AllocaNode(slots, objects);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -40,13 +40,13 @@
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public class BeginLockScopeNode extends AbstractMemoryCheckpoint implements LIRLowerable, MonitorEnter, MemoryCheckpoint.Single {
 
-    private int lockDepth;
+    protected int lockDepth;
 
     public static BeginLockScopeNode create(int lockDepth) {
         return USE_GENERATED_NODES ? new BeginLockScopeNodeGen(lockDepth) : new BeginLockScopeNode(lockDepth);
     }
 
-    BeginLockScopeNode(int lockDepth) {
+    protected BeginLockScopeNode(int lockDepth) {
         super(null);
         this.lockDepth = lockDepth;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -34,13 +34,13 @@
 @NodeInfo
 public class CStringNode extends FloatingNode implements LIRLowerable {
 
-    private final String string;
+    protected final String string;
 
     public static CStringNode create(String string) {
         return USE_GENERATED_NODES ? new CStringNodeGen(string) : new CStringNode(string);
     }
 
-    CStringNode(String string) {
+    protected CStringNode(String string) {
         super(null);
         this.string = string;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -47,14 +47,14 @@
         Uncompress
     }
 
-    private final CompressionOp op;
-    private final CompressEncoding encoding;
+    protected final CompressionOp op;
+    protected final CompressEncoding encoding;
 
     public static CompressionNode create(CompressionOp op, ValueNode input, CompressEncoding encoding) {
         return USE_GENERATED_NODES ? new CompressionNodeGen(op, input, encoding) : new CompressionNode(op, input, encoding);
     }
 
-    CompressionNode(CompressionOp op, ValueNode input, CompressEncoding encoding) {
+    protected CompressionNode(CompressionOp op, ValueNode input, CompressEncoding encoding) {
         super(mkStamp(op, input.stamp(), encoding), input);
         this.op = op;
         this.encoding = encoding;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -40,13 +40,13 @@
 @NodeInfo
 public class CurrentJavaThreadNode extends FloatingNode implements LIRLowerable {
 
-    private LIRKind wordKind;
+    protected LIRKind wordKind;
 
     public static CurrentJavaThreadNode create(Kind kind) {
         return USE_GENERATED_NODES ? new CurrentJavaThreadNodeGen(kind) : new CurrentJavaThreadNode(kind);
     }
 
-    CurrentJavaThreadNode(Kind kind) {
+    protected CurrentJavaThreadNode(Kind kind) {
         super(StampFactory.forKind(kind));
         this.wordKind = LIRKind.value(kind);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -36,13 +36,13 @@
 @NodeInfo
 public class CurrentLockNode extends FixedWithNextNode implements LIRLowerable {
 
-    private int lockDepth;
+    protected int lockDepth;
 
     public static CurrentLockNode create(int lockDepth) {
         return USE_GENERATED_NODES ? new CurrentLockNodeGen(lockDepth) : new CurrentLockNode(lockDepth);
     }
 
-    CurrentLockNode(int lockDepth) {
+    protected CurrentLockNode(int lockDepth) {
         super(null);
         this.lockDepth = lockDepth;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -42,7 +42,7 @@
 public class DeoptimizationFetchUnrollInfoCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi {
 
     @Input SaveAllRegistersNode registerSaver;
-    private final ForeignCallsProvider foreignCalls;
+    protected final ForeignCallsProvider foreignCalls;
 
     public static DeoptimizationFetchUnrollInfoCallNode create(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode registerSaver) {
         return USE_GENERATED_NODES ? new DeoptimizationFetchUnrollInfoCallNodeGen(foreignCalls, registerSaver) : new DeoptimizationFetchUnrollInfoCallNode(foreignCalls, registerSaver);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -35,8 +35,8 @@
 @NodeInfo(shortName = "DeoptCaller", nameTemplate = "DeoptCaller {p#reason/s}")
 public class DeoptimizeCallerNode extends ControlSinkNode implements LIRLowerable {
 
-    private final DeoptimizationAction action;
-    private final DeoptimizationReason reason;
+    protected final DeoptimizationAction action;
+    protected final DeoptimizationReason reason;
 
     public static DeoptimizeCallerNode create(DeoptimizationAction action, DeoptimizationReason reason) {
         return USE_GENERATED_NODES ? new DeoptimizeCallerNodeGen(action, reason) : new DeoptimizeCallerNode(action, reason);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -41,13 +41,13 @@
 @NodeInfo
 public class DimensionsNode extends FixedWithNextNode implements LIRLowerable {
 
-    private final int rank;
+    protected final int rank;
 
     public static DimensionsNode create(int rank) {
         return USE_GENERATED_NODES ? new DimensionsNodeGen(rank) : new DimensionsNode(rank);
     }
 
-    DimensionsNode(int rank) {
+    protected DimensionsNode(int rank) {
         super(null);
         this.rank = rank;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -45,7 +45,7 @@
     @Input ValueNode expectedValue;
     @Input ValueNode newValue;
 
-    private final LocationIdentity locationIdentity;
+    protected final LocationIdentity locationIdentity;
 
     public static DirectCompareAndSwapNode create(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, LocationIdentity locationIdentity) {
         return USE_GENERATED_NODES ? new DirectCompareAndSwapNodeGen(object, offset, expected, newValue, locationIdentity) : new DirectCompareAndSwapNode(object, offset, expected, newValue,
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PostWriteBarrier.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PostWriteBarrier.java	Fri Oct 03 13:48:58 2014 +0200
@@ -29,7 +29,7 @@
 @NodeInfo
 public class G1PostWriteBarrier extends WriteBarrier {
 
-    private final boolean alwaysNull;
+    protected final boolean alwaysNull;
 
     public static G1PostWriteBarrier create(ValueNode object, ValueNode value, LocationNode location, boolean precise, boolean alwaysNull) {
         return USE_GENERATED_NODES ? new G1PostWriteBarrierGen(object, value, location, precise, alwaysNull) : new G1PostWriteBarrier(object, value, location, precise, alwaysNull);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PreWriteBarrier.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PreWriteBarrier.java	Fri Oct 03 13:48:58 2014 +0200
@@ -30,8 +30,8 @@
 public class G1PreWriteBarrier extends WriteBarrier implements DeoptimizingNode.DeoptBefore {
 
     @OptionalInput(InputType.State) FrameState stateBefore;
-    private final boolean nullCheck;
-    private final boolean doLoad;
+    protected final boolean nullCheck;
+    protected final boolean doLoad;
 
     public static G1PreWriteBarrier create(ValueNode object, ValueNode expectedObject, LocationNode location, boolean doLoad, boolean nullCheck) {
         return USE_GENERATED_NODES ? new G1PreWriteBarrierGen(object, expectedObject, location, doLoad, nullCheck) : new G1PreWriteBarrier(object, expectedObject, location, doLoad, nullCheck);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1ReferentFieldReadBarrier.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1ReferentFieldReadBarrier.java	Fri Oct 03 13:48:58 2014 +0200
@@ -35,7 +35,7 @@
 @NodeInfo
 public class G1ReferentFieldReadBarrier extends WriteBarrier {
 
-    private final boolean doLoad;
+    protected final boolean doLoad;
 
     public static G1ReferentFieldReadBarrier create(ValueNode object, ValueNode expectedObject, LocationNode location, boolean doLoad) {
         return USE_GENERATED_NODES ? new G1ReferentFieldReadBarrierGen(object, expectedObject, location, doLoad) : new G1ReferentFieldReadBarrier(object, expectedObject, location, doLoad);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -41,7 +41,7 @@
         return USE_GENERATED_NODES ? new MonitorCounterNodeGen() : new MonitorCounterNode();
     }
 
-    MonitorCounterNode() {
+    protected MonitorCounterNode() {
         super(null);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Fri Oct 03 13:48:58 2014 +0200
@@ -44,7 +44,7 @@
 
     @Input ValueNode hub;
     @Input ValueNode dims;
-    private final int rank;
+    protected final int rank;
 
     public static NewMultiArrayStubCall create(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode hub, int rank, ValueNode dims) {
         return USE_GENERATED_NODES ? new NewMultiArrayStubCallGen(foreignCalls, hub, rank, dims) : new NewMultiArrayStubCall(foreignCalls, hub, rank, dims);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -37,7 +37,7 @@
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public class SaveAllRegistersNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
 
-    private SaveRegistersOp saveRegistersOp;
+    protected SaveRegistersOp saveRegistersOp;
 
     public static SaveAllRegistersNode create() {
         return USE_GENERATED_NODES ? new SaveAllRegistersNodeGen() : new SaveAllRegistersNode();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SerialWriteBarrier.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SerialWriteBarrier.java	Fri Oct 03 13:48:58 2014 +0200
@@ -29,7 +29,7 @@
 @NodeInfo
 public class SerialWriteBarrier extends WriteBarrier {
 
-    private final boolean alwaysNull;
+    protected final boolean alwaysNull;
 
     public static SerialWriteBarrier create(ValueNode object, LocationNode location, boolean precise, boolean alwaysNull) {
         return USE_GENERATED_NODES ? new SerialWriteBarrierGen(object, location, precise, alwaysNull) : new SerialWriteBarrier(object, location, precise, alwaysNull);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -41,9 +41,9 @@
 public class StubForeignCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi {
 
     @Input NodeInputList<ValueNode> arguments;
-    private final ForeignCallsProvider foreignCalls;
+    protected final ForeignCallsProvider foreignCalls;
 
-    private final ForeignCallDescriptor descriptor;
+    protected final ForeignCallDescriptor descriptor;
 
     public static StubForeignCallNode create(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
         return USE_GENERATED_NODES ? new StubForeignCallNodeGen(foreignCalls, descriptor, arguments) : new StubForeignCallNode(foreignCalls, descriptor, arguments);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubStartNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubStartNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -32,7 +32,7 @@
 @NodeInfo
 public class StubStartNode extends StartNode {
 
-    private final Stub stub;
+    protected final Stub stub;
 
     public static StubStartNode create(Stub stub) {
         return USE_GENERATED_NODES ? new StubStartNodeGen(stub) : new StubStartNode(stub);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -43,7 +43,7 @@
 
     @Input ValueNode trapRequest;
     @Input SaveAllRegistersNode registerSaver;
-    private final ForeignCallsProvider foreignCalls;
+    protected final ForeignCallsProvider foreignCalls;
 
     public static UncommonTrapCallNode create(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode registerSaver, ValueNode trapRequest) {
         return USE_GENERATED_NODES ? new UncommonTrapCallNodeGen(foreignCalls, registerSaver, trapRequest) : new UncommonTrapCallNode(foreignCalls, registerSaver, trapRequest);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -40,7 +40,7 @@
 @NodeInfo
 public class VMErrorNode extends DeoptimizingStubCall implements LIRLowerable {
 
-    private final String format;
+    protected final String format;
     @Input ValueNode value;
 
     public static VMErrorNode create(String format, ValueNode value) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java	Fri Oct 03 13:48:58 2014 +0200
@@ -34,7 +34,7 @@
     @Input protected ValueNode object;
     @OptionalInput protected ValueNode value;
     @OptionalInput(InputType.Association) protected LocationNode location;
-    private final boolean precise;
+    protected final boolean precise;
 
     public WriteBarrier(ValueNode object, ValueNode value, LocationNode location, boolean precise) {
         super(StampFactory.forVoid());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyCallNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyCallNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -49,14 +49,14 @@
     @Input ValueNode destPos;
     @Input ValueNode length;
 
-    private Kind elementKind;
+    protected Kind elementKind;
 
     /**
      * Aligned means that the offset of the copy is heap word aligned.
      */
-    private boolean aligned;
-    private boolean disjoint;
-    private boolean uninitialized;
+    protected boolean aligned;
+    protected boolean disjoint;
+    protected boolean uninitialized;
 
     public static ArrayCopyCallNode create(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, boolean aligned, boolean disjoint,
                     boolean uninitialized) {
@@ -64,7 +64,7 @@
                         length, elementKind, aligned, disjoint, uninitialized);
     }
 
-    ArrayCopyCallNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, boolean aligned, boolean disjoint, boolean uninitialized) {
+    protected ArrayCopyCallNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, boolean aligned, boolean disjoint, boolean uninitialized) {
         super(StampFactory.forVoid());
         assert elementKind != null;
         this.src = src;
@@ -83,7 +83,7 @@
                         disjoint);
     }
 
-    ArrayCopyCallNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, boolean disjoint) {
+    protected ArrayCopyCallNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, boolean disjoint) {
         this(src, srcPos, dest, destPos, length, elementKind, false, disjoint, false);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -49,11 +49,11 @@
 public class MethodHandleNode extends MacroStateSplitNode implements Simplifiable {
 
     /** The method that this node is representing. */
-    private final IntrinsicMethod intrinsicMethod;
+    protected final IntrinsicMethod intrinsicMethod;
 
     // Replacement method data
-    private ResolvedJavaMethod replacementTargetMethod;
-    private JavaType replacementReturnType;
+    protected ResolvedJavaMethod replacementTargetMethod;
+    protected JavaType replacementReturnType;
     @Input NodeInputList<ValueNode> replacementArguments;
 
     public static MethodHandleNode create(Invoke invoke) {
@@ -171,11 +171,11 @@
      * Helper function to get the {@link InvokeNode} for the targetMethod of a
      * java.lang.invoke.MemberName.
      *
-     * @param targetMethod the target, already loaded from the member name node
+     * @param target the target, already loaded from the member name node
      * @return invoke node for the member name target
      */
-    private InvokeNode getTargetInvokeNode(ResolvedJavaMethod targetMethod) {
-        if (targetMethod == null) {
+    private InvokeNode getTargetInvokeNode(ResolvedJavaMethod target) {
+        if (target == null) {
             return null;
         }
 
@@ -183,19 +183,19 @@
         // involving class loaders. When we optimize a method handle invoke
         // to a direct call we must cast the receiver and arguments to its
         // actual types.
-        Signature signature = targetMethod.getSignature();
-        final boolean isStatic = targetMethod.isStatic();
+        Signature signature = target.getSignature();
+        final boolean isStatic = target.isStatic();
         final int receiverSkip = isStatic ? 0 : 1;
 
         // Cast receiver to its type.
         if (!isStatic) {
-            JavaType receiverType = targetMethod.getDeclaringClass();
+            JavaType receiverType = target.getDeclaringClass();
             maybeCastArgument(0, receiverType);
         }
 
         // Cast reference arguments to its type.
         for (int index = 0; index < signature.getParameterCount(false); index++) {
-            JavaType parameterType = signature.getParameterType(index, targetMethod.getDeclaringClass());
+            JavaType parameterType = signature.getParameterType(index, target.getDeclaringClass());
             maybeCastArgument(receiverSkip + index, parameterType);
         }
 
@@ -203,18 +203,18 @@
         if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
             ResolvedJavaType receiverType = StampTool.typeOrNull(getReceiver().stamp());
             if (receiverType != null) {
-                ResolvedJavaMethod concreteMethod = receiverType.findUniqueConcreteMethod(targetMethod);
+                ResolvedJavaMethod concreteMethod = receiverType.findUniqueConcreteMethod(target);
                 if (concreteMethod != null) {
                     return createTargetInvokeNode(concreteMethod);
                 }
             }
         }
 
-        if (targetMethod.canBeStaticallyBound()) {
-            return createTargetInvokeNode(targetMethod);
+        if (target.canBeStaticallyBound()) {
+            return createTargetInvokeNode(target);
         }
 
-        ResolvedJavaMethod concreteMethod = targetMethod.getDeclaringClass().findUniqueConcreteMethod(targetMethod);
+        ResolvedJavaMethod concreteMethod = target.getDeclaringClass().findUniqueConcreteMethod(target);
         if (concreteMethod != null) {
             return createTargetInvokeNode(concreteMethod);
         }
@@ -247,12 +247,12 @@
      * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed
      * to the InvokeNode is in fact a {@link SelfReplacingMethodCallTargetNode}.
      *
-     * @param targetMethod the method the be called
+     * @param target the method to be called
      * @return invoke node for the member name target
      */
-    private InvokeNode createTargetInvokeNode(ResolvedJavaMethod targetMethod) {
-        InvokeKind invokeKind = targetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
-        JavaType returnType = targetMethod.getSignature().getReturnType(null);
+    private InvokeNode createTargetInvokeNode(ResolvedJavaMethod target) {
+        InvokeKind targetInvokeKind = target.isStatic() ? InvokeKind.Static : InvokeKind.Special;
+        JavaType targetReturnType = target.getSignature().getReturnType(null);
 
         // MethodHandleLinkTo* nodes have a trailing MemberName argument which
         // needs to be popped.
@@ -275,10 +275,10 @@
         // If there is already replacement information, use that instead.
         MethodCallTargetNode callTarget;
         if (replacementTargetMethod == null) {
-            callTarget = SelfReplacingMethodCallTargetNode.create(invokeKind, targetMethod, targetArguments, returnType, getTargetMethod(), originalArguments, getReturnType());
+            callTarget = SelfReplacingMethodCallTargetNode.create(targetInvokeKind, target, targetArguments, targetReturnType, getTargetMethod(), originalArguments, getReturnType());
         } else {
             ValueNode[] args = replacementArguments.toArray(new ValueNode[replacementArguments.size()]);
-            callTarget = SelfReplacingMethodCallTargetNode.create(invokeKind, targetMethod, targetArguments, returnType, replacementTargetMethod, args, replacementReturnType);
+            callTarget = SelfReplacingMethodCallTargetNode.create(targetInvokeKind, target, targetArguments, targetReturnType, replacementTargetMethod, args, replacementReturnType);
         }
         graph().add(callTarget);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopyNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopyNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -42,14 +42,14 @@
     @Input ValueNode length;
     @OptionalInput ValueNode layoutHelper;
 
-    private Kind elementKind;
+    protected Kind elementKind;
 
     public static UnsafeArrayCopyNode create(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper, Kind elementKind) {
         return USE_GENERATED_NODES ? new UnsafeArrayCopyNodeGen(src, srcPos, dest, destPos, length, layoutHelper, elementKind) : new UnsafeArrayCopyNode(src, srcPos, dest, destPos, length,
                         layoutHelper, elementKind);
     }
 
-    UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper, Kind elementKind) {
+    protected UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper, Kind elementKind) {
         super(StampFactory.forVoid());
         assert layoutHelper == null || elementKind == null;
         this.src = src;
@@ -65,7 +65,7 @@
         return USE_GENERATED_NODES ? new UnsafeArrayCopyNodeGen(src, srcPos, dest, destPos, length, elementKind) : new UnsafeArrayCopyNode(src, srcPos, dest, destPos, length, elementKind);
     }
 
-    UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind) {
+    protected UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind) {
         this(src, srcPos, dest, destPos, length, null, elementKind);
     }
 
@@ -73,7 +73,7 @@
         return USE_GENERATED_NODES ? new UnsafeArrayCopyNodeGen(src, srcPos, dest, destPos, length, layoutHelper) : new UnsafeArrayCopyNode(src, srcPos, dest, destPos, length, layoutHelper);
     }
 
-    UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper) {
+    protected UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper) {
         this(src, srcPos, dest, destPos, length, layoutHelper, null);
     }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Oct 03 13:48:58 2014 +0200
@@ -108,7 +108,7 @@
              * the !NODE_CLASS.isAssignableFrom(type) guarantee in
              * NodeClass.FieldScanner.scanField() to fail.
              */
-            private final Object nextPlaceholder;
+            protected final Object nextPlaceholder;
 
             public static BlockPlaceholderNode create(BytecodeParser builder) {
                 return USE_GENERATED_NODES ? new GraphBuilderPhase_Instance_BlockPlaceholderNodeGen(builder) : new BlockPlaceholderNode(builder);
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest1.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest1.java	Fri Oct 03 13:48:58 2014 +0200
@@ -126,35 +126,18 @@
         LIRInstruction op1 = new TestOp(compValue1);
         LIRInstruction op2 = new TestOp(compValue1);
 
-        op1.forEachInput(new InstructionValueProcedure() {
-            @Override
-            public Value doValue(LIRInstruction instruction, Value value) {
-                assertEquals(dummyValue1, value);
-                return dummyValue2;
-            }
+        op1.forEachInput((instruction, value, mode, flags) -> {
+            assertEquals(dummyValue1, value);
+            return dummyValue2;
         });
 
-        op2.forEachInput(new InstructionValueProcedure() {
-            @Override
-            public Value doValue(LIRInstruction instruction, Value value) {
-                assertEquals(dummyValue1, value);
-                return dummyValue3;
-            }
+        op2.forEachInput((instruction, value, mode, flags) -> {
+            assertEquals(dummyValue1, value);
+            return dummyValue3;
         });
 
-        op1.visitEachInput(new InstructionValueConsumer() {
-            @Override
-            public void visitValue(LIRInstruction instruction, Value value) {
-                assertEquals(dummyValue2, value);
-            }
-        });
-
-        op2.visitEachInput(new InstructionValueConsumer() {
-            @Override
-            public void visitValue(LIRInstruction instruction, Value value) {
-                assertEquals(dummyValue3, value);
-            }
-        });
+        op1.visitEachInput((instruction, value, mode, flags) -> assertEquals(dummyValue2, value));
+        op2.visitEachInput((instruction, value, mode, flags) -> assertEquals(dummyValue3, value));
     }
 
     @Test
@@ -166,34 +149,17 @@
         LIRInstruction op1 = new TestOp(compValue1);
         LIRInstruction op2 = new TestOp(compValue1);
 
-        op1.forEachInput(new InstructionValueProcedure() {
-            @Override
-            public Value doValue(LIRInstruction instruction, Value value) {
-                assertEquals(dummyValue1, value);
-                return dummyValue2;
-            }
-        });
-
-        op2.forEachInput(new InstructionValueProcedure() {
-            @Override
-            public Value doValue(LIRInstruction instruction, Value value) {
-                assertEquals(dummyValue1, value);
-                return dummyValue3;
-            }
+        op1.forEachInput((instruction, value, mode, flags) -> {
+            assertEquals(dummyValue1, value);
+            return dummyValue2;
         });
 
-        op1.visitEachInput(new InstructionValueConsumer() {
-            @Override
-            public void visitValue(LIRInstruction instruction, Value value) {
-                assertEquals(dummyValue2, value);
-            }
+        op2.forEachInput((instruction, value, mode, flags) -> {
+            assertEquals(dummyValue1, value);
+            return dummyValue3;
         });
 
-        op2.visitEachInput(new InstructionValueConsumer() {
-            @Override
-            public void visitValue(LIRInstruction instruction, Value value) {
-                assertEquals(dummyValue3, value);
-            }
-        });
+        op1.visitEachInput((instruction, value, mode, flags) -> assertEquals(dummyValue2, value));
+        op2.visitEachInput((instruction, value, mode, flags) -> assertEquals(dummyValue3, value));
     }
 }
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest2.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest2.java	Fri Oct 03 13:48:58 2014 +0200
@@ -127,35 +127,18 @@
         LIRInstruction op1 = new TestOp(compValue1);
         LIRInstruction op2 = new TestOp(compValue1);
 
-        op1.forEachInput(new InstructionValueProcedure() {
-            @Override
-            public Value doValue(LIRInstruction instruction, Value value) {
-                assertEquals(dummyValue1, value);
-                return dummyValue2;
-            }
+        op1.forEachInput((instruction, value, mode, flags) -> {
+            assertEquals(dummyValue1, value);
+            return dummyValue2;
         });
 
-        op2.forEachInput(new InstructionValueProcedure() {
-            @Override
-            public Value doValue(LIRInstruction instruction, Value value) {
-                assertEquals(dummyValue1, value);
-                return dummyValue3;
-            }
+        op2.forEachInput((instruction, value, mode, flags) -> {
+            assertEquals(dummyValue1, value);
+            return dummyValue3;
         });
 
-        op1.visitEachInput(new InstructionValueConsumer() {
-            @Override
-            public void visitValue(LIRInstruction instruction, Value value) {
-                assertEquals(dummyValue2, value);
-            }
-        });
-
-        op2.visitEachInput(new InstructionValueConsumer() {
-            @Override
-            public void visitValue(LIRInstruction instruction, Value value) {
-                assertEquals(dummyValue3, value);
-            }
-        });
+        op1.visitEachInput((instruction, value, mode, flags) -> assertEquals(dummyValue2, value));
+        op2.visitEachInput((instruction, value, mode, flags) -> assertEquals(dummyValue3, value));
     }
 
     @Test
@@ -167,34 +150,17 @@
         LIRInstruction op1 = new TestOp(compValue1);
         LIRInstruction op2 = new TestOp(compValue1);
 
-        op1.forEachInput(new InstructionValueProcedure() {
-            @Override
-            public Value doValue(LIRInstruction instruction, Value value) {
-                assertEquals(dummyValue1, value);
-                return dummyValue2;
-            }
-        });
-
-        op2.forEachInput(new InstructionValueProcedure() {
-            @Override
-            public Value doValue(LIRInstruction instruction, Value value) {
-                assertEquals(dummyValue1, value);
-                return dummyValue3;
-            }
+        op1.forEachInput((instruction, value, mode, flags) -> {
+            assertEquals(dummyValue1, value);
+            return dummyValue2;
         });
 
-        op1.visitEachInput(new InstructionValueConsumer() {
-            @Override
-            public void visitValue(LIRInstruction instruction, Value value) {
-                assertEquals(dummyValue2, value);
-            }
+        op2.forEachInput((instruction, value, mode, flags) -> {
+            assertEquals(dummyValue1, value);
+            return dummyValue3;
         });
 
-        op2.visitEachInput(new InstructionValueConsumer() {
-            @Override
-            public void visitValue(LIRInstruction instruction, Value value) {
-                assertEquals(dummyValue3, value);
-            }
-        });
+        op1.visitEachInput((instruction, value, mode, flags) -> assertEquals(dummyValue2, value));
+        op2.visitEachInput((instruction, value, mode, flags) -> assertEquals(dummyValue3, value));
     }
 }
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest3.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest3.java	Fri Oct 03 13:48:58 2014 +0200
@@ -127,39 +127,26 @@
         LIRInstruction op1 = new TestOp(compValue1);
         LIRInstruction op2 = new TestOp(compValue1);
 
-        op1.forEachInput(new ValuePositionProcedure() {
-
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                Value value = position.get(instruction);
-                assertEquals(dummyValue1, value);
-                position.set(instruction, dummyValue2);
-            }
+        op1.forEachInputPos((instruction, position) -> {
+            Value value = position.get(instruction);
+            assertEquals(dummyValue1, value);
+            position.set(instruction, dummyValue2);
         });
 
-        op2.forEachInput(new ValuePositionProcedure() {
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                Value value = position.get(instruction);
-                assertEquals(dummyValue1, value);
-                position.set(instruction, dummyValue3);
-            }
+        op2.forEachInputPos((instruction, position) -> {
+            Value value = position.get(instruction);
+            assertEquals(dummyValue1, value);
+            position.set(instruction, dummyValue3);
         });
 
-        op1.forEachInput(new ValuePositionProcedure() {
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                Value value = position.get(instruction);
-                assertEquals(dummyValue2, value);
-            }
+        op1.forEachInputPos((instruction, position) -> {
+            Value value = position.get(instruction);
+            assertEquals(dummyValue2, value);
         });
 
-        op2.forEachInput(new ValuePositionProcedure() {
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                Value value = position.get(instruction);
-                assertEquals(dummyValue3, value);
-            }
+        op2.forEachInputPos((instruction, position) -> {
+            Value value = position.get(instruction);
+            assertEquals(dummyValue3, value);
         });
     }
 
@@ -172,39 +159,26 @@
         LIRInstruction op1 = new TestOp(compValue1);
         LIRInstruction op2 = new TestOp(compValue1);
 
-        op1.forEachInput(new ValuePositionProcedure() {
-
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                Value value = position.get(instruction);
-                assertEquals(dummyValue1, value);
-                position.set(instruction, dummyValue2);
-            }
+        op1.forEachInputPos((instruction, position) -> {
+            Value value = position.get(instruction);
+            assertEquals(dummyValue1, value);
+            position.set(instruction, dummyValue2);
         });
 
-        op2.forEachInput(new ValuePositionProcedure() {
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                Value value = position.get(instruction);
-                assertEquals(dummyValue1, value);
-                position.set(instruction, dummyValue3);
-            }
+        op2.forEachInputPos((instruction, position) -> {
+            Value value = position.get(instruction);
+            assertEquals(dummyValue1, value);
+            position.set(instruction, dummyValue3);
         });
 
-        op1.forEachInput(new ValuePositionProcedure() {
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                Value value = position.get(instruction);
-                assertEquals(dummyValue2, value);
-            }
+        op1.forEachInputPos((instruction, position) -> {
+            Value value = position.get(instruction);
+            assertEquals(dummyValue2, value);
         });
 
-        op2.forEachInput(new ValuePositionProcedure() {
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                Value value = position.get(instruction);
-                assertEquals(dummyValue3, value);
-            }
+        op2.forEachInputPos((instruction, position) -> {
+            Value value = position.get(instruction);
+            assertEquals(dummyValue3, value);
         });
     }
 }
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest4.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest4.java	Fri Oct 03 13:48:58 2014 +0200
@@ -127,39 +127,26 @@
         LIRInstruction op1 = new TestOp(compValue1);
         LIRInstruction op2 = new TestOp(compValue1);
 
-        op1.forEachInput(new ValuePositionProcedure() {
-
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                Value value = position.get(instruction);
-                assertEquals(dummyValue1, value);
-                position.set(instruction, dummyValue2);
-            }
+        op1.forEachInputPos((instruction, position) -> {
+            Value value = position.get(instruction);
+            assertEquals(dummyValue1, value);
+            position.set(instruction, dummyValue2);
         });
 
-        op2.forEachInput(new ValuePositionProcedure() {
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                Value value = position.get(instruction);
-                assertEquals(dummyValue1, value);
-                position.set(instruction, dummyValue3);
-            }
+        op2.forEachInputPos((instruction, position) -> {
+            Value value = position.get(instruction);
+            assertEquals(dummyValue1, value);
+            position.set(instruction, dummyValue3);
         });
 
-        op1.forEachInput(new ValuePositionProcedure() {
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                Value value = position.get(instruction);
-                assertEquals(dummyValue2, value);
-            }
+        op1.forEachInputPos((instruction, position) -> {
+            Value value = position.get(instruction);
+            assertEquals(dummyValue2, value);
         });
 
-        op2.forEachInput(new ValuePositionProcedure() {
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                Value value = position.get(instruction);
-                assertEquals(dummyValue3, value);
-            }
+        op2.forEachInputPos((instruction, position) -> {
+            Value value = position.get(instruction);
+            assertEquals(dummyValue3, value);
         });
     }
 
@@ -172,39 +159,26 @@
         LIRInstruction op1 = new TestOp(compValue1);
         LIRInstruction op2 = new TestOp(compValue1);
 
-        op1.forEachInput(new ValuePositionProcedure() {
-
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                Value value = position.get(instruction);
-                assertEquals(dummyValue1, value);
-                position.set(instruction, dummyValue2);
-            }
+        op1.forEachInputPos((instruction, position) -> {
+            Value value = position.get(instruction);
+            assertEquals(dummyValue1, value);
+            position.set(instruction, dummyValue2);
         });
 
-        op2.forEachInput(new ValuePositionProcedure() {
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                Value value = position.get(instruction);
-                assertEquals(dummyValue1, value);
-                position.set(instruction, dummyValue3);
-            }
+        op2.forEachInputPos((instruction, position) -> {
+            Value value = position.get(instruction);
+            assertEquals(dummyValue1, value);
+            position.set(instruction, dummyValue3);
         });
 
-        op1.forEachInput(new ValuePositionProcedure() {
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                Value value = position.get(instruction);
-                assertEquals(dummyValue2, value);
-            }
+        op1.forEachInputPos((instruction, position) -> {
+            Value value = position.get(instruction);
+            assertEquals(dummyValue2, value);
         });
 
-        op2.forEachInput(new ValuePositionProcedure() {
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                Value value = position.get(instruction);
-                assertEquals(dummyValue3, value);
-            }
+        op2.forEachInputPos((instruction, position) -> {
+            Value value = position.get(instruction);
+            assertEquals(dummyValue3, value);
         });
     }
 }
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest1.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest1.java	Fri Oct 03 13:48:58 2014 +0200
@@ -117,13 +117,7 @@
 
         List<ValuePosition> positions = new ArrayList<>();
 
-        op.forEachInput(new ValuePositionProcedure() {
-
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                positions.add(position);
-            }
-        });
+        op.forEachInputPos((instruction, position) -> positions.add(position));
 
         assertEquals(1, positions.size());
         assertEquals(dummyValue, positions.get(0).get(op));
@@ -136,13 +130,7 @@
 
         List<ValuePosition> positions = new ArrayList<>();
 
-        op.forEachInput(new ValuePositionProcedure() {
-
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                positions.add(position);
-            }
-        });
+        op.forEachInputPos((instruction, position) -> positions.add(position));
 
         assertEquals(1, positions.size());
         assertEquals(dummyValue, positions.get(0).get(op));
@@ -155,13 +143,7 @@
 
         List<ValuePosition> positions = new ArrayList<>();
 
-        op.forEachInput(new ValuePositionProcedure() {
-
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                positions.add(position);
-            }
-        });
+        op.forEachInputPos((instruction, position) -> positions.add(position));
 
         assertEquals(1, positions.size());
         assertEquals(dummyValue, positions.get(0).get(op));
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest2.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest2.java	Fri Oct 03 13:48:58 2014 +0200
@@ -117,13 +117,7 @@
         LIRInstruction op = new TestOp(compValue2);
         List<ValuePosition> positions = new ArrayList<>();
 
-        op.forEachInput(new ValuePositionProcedure() {
-
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                positions.add(position);
-            }
-        });
+        op.forEachInputPos((instruction, position) -> positions.add(position));
 
         assertEquals(4, positions.size());
 
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest3.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest3.java	Fri Oct 03 13:48:58 2014 +0200
@@ -131,11 +131,11 @@
         HashMap<Value, EnumSet<OperandFlag>> positionMap = new HashMap<>();
         HashMap<Value, EnumSet<OperandFlag>> normalMap = new HashMap<>();
 
-        op.forEachInput(new ValuePositionProcedure() {
+        op.forEachInputPos(new ValuePositionProcedure() {
 
             @Override
             public void doValue(LIRInstruction instruction, ValuePosition position) {
-                positionMap.put(position.get(instruction), position.getFlags(instruction));
+                positionMap.put(position.get(instruction), position.getFlags());
             }
         });
         op.visitEachInput(new InstructionValueConsumer() {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Fri Oct 03 13:48:58 2014 +0200
@@ -54,7 +54,7 @@
         valueClass = CompositeValueClass.get(getClass());
     }
 
-    final CompositeValue forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedureBase proc) {
+    final CompositeValue forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedure proc) {
         return valueClass.forEachComponent(inst, this, mode, proc);
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Fri Oct 03 13:48:58 2014 +0200
@@ -57,46 +57,28 @@
         }
     }
 
-    private final int directComponentCount;
-    private final long[] componentOffsets;
-    private final EnumSet<OperandFlag>[] componentFlags;
-
     public CompositeValueClass(Class<? extends CompositeValue> clazz) {
         this(clazz, new DefaultCalcOffset());
     }
 
-    @SuppressWarnings("unchecked")
     public CompositeValueClass(Class<? extends CompositeValue> clazz, CalcOffset calcOffset) {
         super(clazz);
 
-        ValueFieldScanner scanner = new ValueFieldScanner(calcOffset);
-        scanner.scan(clazz);
+        ValueFieldScanner vfs = new ValueFieldScanner(calcOffset);
+        vfs.scan(clazz, true);
 
-        OperandModeAnnotation mode = scanner.valueAnnotations.get(CompositeValue.Component.class);
-        directComponentCount = mode.scalarOffsets.size();
-        componentOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets);
-        componentFlags = arrayUsingSortedOffsets(mode.flags, componentOffsets, new EnumSet[componentOffsets.length]);
-
-        dataOffsets = sortedLongCopy(scanner.dataOffsets);
-
-        fieldNames = scanner.fieldNames;
-        fieldTypes = scanner.fieldTypes;
+        values = new Values(vfs.valueAnnotations.get(CompositeValue.Component.class));
+        data = new Fields(vfs.data);
     }
 
     private static class ValueFieldScanner extends FieldScanner {
 
         public ValueFieldScanner(CalcOffset calc) {
             super(calc);
-
             valueAnnotations.put(CompositeValue.Component.class, new OperandModeAnnotation());
         }
 
         @Override
-        public void scan(Class<?> clazz) {
-            super.scan(clazz);
-        }
-
-        @Override
         protected EnumSet<OperandFlag> getFlags(Field field) {
             EnumSet<OperandFlag> result = EnumSet.noneOf(OperandFlag.class);
             if (field.isAnnotationPresent(CompositeValue.Component.class)) {
@@ -111,57 +93,53 @@
     @Override
     public String toString() {
         StringBuilder str = new StringBuilder();
-        str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" component[");
-        for (int i = 0; i < componentOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(componentOffsets[i]);
-        }
+        str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" components[");
+        values.appendFields(str);
         str.append("] data[");
-        for (int i = 0; i < dataOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(dataOffsets[i]);
-        }
+        data.appendFields(str);
         str.append("]");
         return str.toString();
     }
 
-    final CompositeValue forEachComponent(LIRInstruction inst, CompositeValue obj, OperandMode mode, InstructionValueProcedureBase proc) {
-        return forEachComponent(inst, obj, directComponentCount, componentOffsets, mode, componentFlags, proc);
+    final CompositeValue forEachComponent(LIRInstruction inst, CompositeValue obj, OperandMode mode, InstructionValueProcedure proc) {
+        return super.forEachComponent(inst, obj, values, mode, proc);
     }
 
     final void forEachComponent(LIRInstruction inst, CompositeValue obj, OperandMode mode, ValuePositionProcedure proc, ValuePosition outerPosition) {
-        forEach(inst, obj, directComponentCount, componentOffsets, mode, componentFlags, proc, outerPosition);
+        forEach(inst, obj, values, mode, proc, outerPosition);
     }
 
     public String toString(CompositeValue obj) {
         StringBuilder result = new StringBuilder();
 
-        appendValues(result, obj, "", "", "{", "}", new String[]{""}, componentOffsets);
+        appendValues(result, obj, "", "", "{", "}", new String[]{""}, values);
 
-        for (int i = 0; i < dataOffsets.length; i++) {
-            result.append(" ").append(fieldNames.get(dataOffsets[i])).append(": ").append(getFieldString(obj, dataOffsets[i]));
+        for (int i = 0; i < data.getCount(); i++) {
+            result.append(" ").append(data.getName(i)).append(": ").append(getFieldString(obj, i, data));
         }
 
         return result.toString();
     }
 
     Value getValue(CompositeValue obj, ValuePosition pos) {
-        return getValueForPosition(obj, componentOffsets, directComponentCount, pos);
+        return getValueForPosition(obj, values, pos);
     }
 
     CompositeValue createUpdatedValue(CompositeValue compValue, ValuePosition pos, Value value) {
         CompositeValue newCompValue = compValue.clone();
-        setValueForPosition(newCompValue, componentOffsets, directComponentCount, pos, value);
+        setValueForPosition(newCompValue, values, pos, value);
         return newCompValue;
     }
 
     EnumSet<OperandFlag> getFlags(ValuePosition pos) {
-        return componentFlags[pos.getIndex()];
+        return values.getFlags(pos.getIndex());
     }
 
     void copyValueArrays(CompositeValue compositeValue) {
-        for (int i = directComponentCount; i < componentOffsets.length; i++) {
-            Value[] valueArray = getValueArray(compositeValue, componentOffsets[i]);
+        for (int i = values.getDirectCount(); i < values.getCount(); i++) {
+            Value[] valueArray = values.getValueArray(compositeValue, i);
             Value[] newValueArray = Arrays.copyOf(valueArray, valueArray.length);
-            setValueArray(compositeValue, componentOffsets[i], newValueArray);
+            values.setValueArray(compositeValue, i, newValueArray);
         }
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InstructionStateProcedure.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InstructionStateProcedure.java	Fri Oct 03 13:48:58 2014 +0200
@@ -22,7 +22,8 @@
  */
 package com.oracle.graal.lir;
 
-public abstract class InstructionStateProcedure {
+@FunctionalInterface
+public interface InstructionStateProcedure {
 
-    protected abstract void doState(LIRInstruction instruction, LIRFrameState state);
-}
\ No newline at end of file
+    void doState(LIRInstruction instruction, LIRFrameState state);
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InstructionValueConsumer.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InstructionValueConsumer.java	Fri Oct 03 13:48:58 2014 +0200
@@ -25,42 +25,27 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.lir.LIRInstruction.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
 
 /**
  * Non-modifying version of {@link InstructionValueProcedure}.
  */
-public abstract class InstructionValueConsumer extends InstructionValueProcedureBase {
+@FunctionalInterface
+public interface InstructionValueConsumer extends InstructionValueProcedure {
 
     /**
-     * Iterator method to be overwritten. This version of the iterator does not take additional
-     * parameters to keep the signature short.
-     *
-     * @param instruction The current instruction.
-     * @param value The value that is iterated.
-     */
-    protected void visitValue(LIRInstruction instruction, Value value) {
-        throw GraalInternalError.shouldNotReachHere("One of the visitValue() methods must be overwritten");
-    }
-
-    /**
-     * Iterator method to be overwritten. This version of the iterator gets additional parameters
-     * about the processed value.
+     * Iterator method to be overwritten.
      *
      * @param instruction The current instruction.
      * @param value The value that is iterated.
      * @param mode The operand mode for the value.
      * @param flags A set of flags for the value.
      */
-    protected void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-        visitValue(instruction, value);
-    }
+    void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags);
 
-    @Override
-    public final Value processValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-        assert !(value instanceof CompositeValue) : String.format("Must not visit CompositeValues! Instruction: %s Value: %s", instruction, value);
+    default Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
         visitValue(instruction, value, mode, flags);
         return value;
     }
-}
\ No newline at end of file
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InstructionValueProcedure.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InstructionValueProcedure.java	Fri Oct 03 13:48:58 2014 +0200
@@ -25,31 +25,17 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.lir.LIRInstruction.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
 
 /**
- * Iterator for iterating over a list of values. Subclasses must overwrite one of the doValue
- * methods. Clients should not use this class directly but call
- * {@link InstructionValueProcedureBase#processValue} instead.
+ * Functional interface for iterating over a list of values.
  */
-public abstract class InstructionValueProcedure extends InstructionValueProcedureBase {
+@FunctionalInterface
+public interface InstructionValueProcedure {
 
     /**
-     * Iterator method to be overwritten. This version of the iterator does not take additional
-     * parameters to keep the signature short.
-     *
-     * @param instruction The current instruction.
-     * @param value The value that is iterated.
-     * @return The new value to replace the value that was passed in.
-     */
-    protected Value doValue(LIRInstruction instruction, Value value) {
-        throw GraalInternalError.shouldNotReachHere("One of the doValue() methods must be overwritten");
-    }
-
-    /**
-     * Iterator method to be overwritten. This version of the iterator gets additional parameters
-     * about the processed value.
+     * Iterator method to be overwritten.
      *
      * @param instruction The current instruction.
      * @param value The value that is iterated.
@@ -57,13 +43,6 @@
      * @param flags A set of flags for the value.
      * @return The new value to replace the value that was passed in.
      */
-    protected Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-        return doValue(instruction, value);
-    }
+    Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags);
 
-    @Override
-    public final Value processValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-        assert !(value instanceof CompositeValue) : String.format("Must not visit CompositeValues! Instruction: %s Value: %s", instruction, value);
-        return doValue(instruction, value, mode, flags);
-    }
-}
\ No newline at end of file
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InstructionValueProcedureBase.java	Fri Oct 03 11:07:44 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2014, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.lir.LIRInstruction.*;
-
-/**
- * Common base class for modifying and non-modifying {@link Value value} iterators.
- *
- * This type should not be sub-classed directly. Use {@link InstructionValueProcedureBase} or
- * {@link InstructionValueConsumer} instead.
- *
- * @see InstructionValueProcedure
- * @see InstructionValueConsumer
- */
-public abstract class InstructionValueProcedureBase {
-
-    /**
-     * Iterator method to be overwritten. This version of the iterator gets additional parameters
-     * about the processed value.
-     *
-     * @param instruction The current instruction.
-     * @param value The value that is iterated.
-     * @param mode The operand mode for the value.
-     * @param flags A set of flags for the value.
-     * @return The new value to replace the value that was passed in.
-     */
-    abstract public Value processValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags);
-}
\ No newline at end of file
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Fri Oct 03 13:48:58 2014 +0200
@@ -144,13 +144,10 @@
      */
     public static LabelRef getExceptionEdge(LIRInstruction op) {
         final LabelRef[] exceptionEdge = {null};
-        op.forEachState(new StateProcedure() {
-            @Override
-            protected void doState(LIRFrameState state) {
-                if (state.exceptionEdge != null) {
-                    assert exceptionEdge[0] == null;
-                    exceptionEdge[0] = state.exceptionEdge;
-                }
+        op.forEachState(state -> {
+            if (state.exceptionEdge != null) {
+                assert exceptionEdge[0] == null;
+                exceptionEdge[0] = state.exceptionEdge;
             }
         });
         return exceptionEdge[0];
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Fri Oct 03 13:48:58 2014 +0200
@@ -62,7 +62,7 @@
      *
      * @param proc The procedure called for variables.
      */
-    public void forEachState(LIRInstruction inst, InstructionValueProcedureBase proc) {
+    public void forEachState(LIRInstruction inst, InstructionValueProcedure proc) {
         for (BytecodeFrame cur = topFrame; cur != null; cur = cur.caller()) {
             processValues(inst, cur.values, proc);
         }
@@ -79,16 +79,16 @@
      */
     protected static final EnumSet<OperandFlag> STATE_FLAGS = EnumSet.of(OperandFlag.REG, OperandFlag.STACK);
 
-    protected void processValues(LIRInstruction inst, Value[] values, InstructionValueProcedureBase proc) {
+    protected void processValues(LIRInstruction inst, Value[] values, InstructionValueProcedure proc) {
         for (int i = 0; i < values.length; i++) {
             Value value = values[i];
             values[i] = processValue(inst, proc, value);
         }
     }
 
-    protected Value processValue(LIRInstruction inst, InstructionValueProcedureBase proc, Value value) {
+    protected Value processValue(LIRInstruction inst, InstructionValueProcedure proc, Value value) {
         if (processed(value)) {
-            return proc.processValue(inst, value, OperandMode.ALIVE, STATE_FLAGS);
+            return proc.doValue(inst, value, OperandMode.ALIVE, STATE_FLAGS);
         }
         return value;
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Fri Oct 03 13:48:58 2014 +0200
@@ -218,20 +218,20 @@
     }
 
     // ValuePositionProcedures
-    public final void forEachInput(ValuePositionProcedure proc) {
-        instructionClass.forEachUse(this, proc);
+    public final void forEachInputPos(ValuePositionProcedure proc) {
+        instructionClass.forEachUsePos(this, proc);
     }
 
-    public final void forEachAlive(ValuePositionProcedure proc) {
-        instructionClass.forEachAlive(this, proc);
+    public final void forEachAlivePos(ValuePositionProcedure proc) {
+        instructionClass.forEachAlivePos(this, proc);
     }
 
     public final void forEachTemp(ValuePositionProcedure proc) {
-        instructionClass.forEachTemp(this, proc);
+        instructionClass.forEachTempPos(this, proc);
     }
 
     public final void forEachOutput(ValuePositionProcedure proc) {
-        instructionClass.forEachDef(this, proc);
+        instructionClass.forEachDefPos(this, proc);
     }
 
     // InstructionValueProcedures
@@ -251,16 +251,41 @@
         instructionClass.forEachDef(this, proc);
     }
 
-    // States
     public final void forEachState(InstructionValueProcedure proc) {
         instructionClass.forEachState(this, proc);
     }
 
+    // ValueProcedures
+    public final void forEachInput(ValueProcedure proc) {
+        instructionClass.forEachUse(this, proc);
+    }
+
+    public final void forEachAlive(ValueProcedure proc) {
+        instructionClass.forEachAlive(this, proc);
+    }
+
+    public final void forEachTemp(ValueProcedure proc) {
+        instructionClass.forEachTemp(this, proc);
+    }
+
+    public final void forEachOutput(ValueProcedure proc) {
+        instructionClass.forEachDef(this, proc);
+    }
+
+    public final void forEachState(ValueProcedure proc) {
+        instructionClass.forEachState(this, proc);
+    }
+
+    // States
     public final void forEachState(InstructionStateProcedure proc) {
         instructionClass.forEachState(this, proc);
     }
 
-    // Consumers
+    public final void forEachState(StateProcedure proc) {
+        instructionClass.forEachState(this, proc);
+    }
+
+    // InstructionValueConsumers
     public final void visitEachInput(InstructionValueConsumer proc) {
         instructionClass.forEachUse(this, proc);
     }
@@ -281,6 +306,27 @@
         instructionClass.forEachState(this, proc);
     }
 
+    // ValueConsumers
+    public final void visitEachInput(ValueConsumer proc) {
+        instructionClass.forEachUse(this, proc);
+    }
+
+    public final void visitEachAlive(ValueConsumer proc) {
+        instructionClass.forEachAlive(this, proc);
+    }
+
+    public final void visitEachTemp(ValueConsumer proc) {
+        instructionClass.forEachTemp(this, proc);
+    }
+
+    public final void visitEachOutput(ValueConsumer proc) {
+        instructionClass.forEachDef(this, proc);
+    }
+
+    public final void visitEachState(ValueConsumer proc) {
+        instructionClass.forEachState(this, proc);
+    }
+
     /**
      * Iterates all register hints for the specified value, i.e., all preferred candidates for the
      * register to be assigned to the value.
@@ -300,6 +346,19 @@
         return instructionClass.forEachRegisterHint(this, mode, proc);
     }
 
+    /**
+     * @see #forEachRegisterHint(Value, OperandMode, InstructionValueProcedure)
+     * @param value The value the hints are needed for.
+     * @param mode The operand mode of the value.
+     * @param proc The procedure invoked for all the hints. If the procedure returns a non-null
+     *            value, the iteration is stopped and the value is returned by this method, i.e.,
+     *            clients can stop the iteration once a suitable hint has been found.
+     * @return The non-null value returned by the procedure, or null.
+     */
+    public Value forEachRegisterHint(Value value, OperandMode mode, ValueProcedure proc) {
+        return instructionClass.forEachRegisterHint(this, mode, proc);
+    }
+
     protected void verify() {
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Fri Oct 03 13:48:58 2014 +0200
@@ -53,70 +53,50 @@
     private static final Class<LIRInstruction> INSTRUCTION_CLASS = LIRInstruction.class;
     private static final Class<LIRFrameState> STATE_CLASS = LIRFrameState.class;
 
-    private final int directUseCount;
-    private final long[] useOffsets;
-    private final EnumSet<OperandFlag>[] useFlags;
-    private final int directAliveCount;
-    private final long[] aliveOffsets;
-    private final EnumSet<OperandFlag>[] aliveFlags;
-    private final int directTempCount;
-    private final long[] tempOffsets;
-    private final EnumSet<OperandFlag>[] tempFlags;
-    private final int directDefCount;
-    private final long[] defOffsets;
-    private final EnumSet<OperandFlag>[] defFlags;
-
-    private final long[] stateOffsets;
+    private final Values uses;
+    private final Values alives;
+    private final Values temps;
+    private final Values defs;
+    private final Fields states;
 
     private String opcodeConstant;
-    private long opcodeOffset;
+    private int opcodeIndex;
 
     private LIRInstructionClass(Class<? extends LIRInstruction> clazz) {
         this(clazz, new DefaultCalcOffset());
     }
 
-    @SuppressWarnings("unchecked")
     public LIRInstructionClass(Class<? extends LIRInstruction> clazz, CalcOffset calcOffset) {
         super(clazz);
         assert INSTRUCTION_CLASS.isAssignableFrom(clazz);
 
-        InstructionFieldScanner scanner = new InstructionFieldScanner(calcOffset);
-        scanner.scan(clazz);
+        InstructionFieldScanner ifs = new InstructionFieldScanner(calcOffset);
+        ifs.scan(clazz);
 
-        OperandModeAnnotation mode = scanner.valueAnnotations.get(LIRInstruction.Use.class);
-        directUseCount = mode.scalarOffsets.size();
-        useOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets);
-        useFlags = arrayUsingSortedOffsets(mode.flags, useOffsets, new EnumSet[useOffsets.length]);
-
-        mode = scanner.valueAnnotations.get(LIRInstruction.Alive.class);
-        directAliveCount = mode.scalarOffsets.size();
-        aliveOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets);
-        aliveFlags = arrayUsingSortedOffsets(mode.flags, aliveOffsets, new EnumSet[aliveOffsets.length]);
+        uses = new Values(ifs.valueAnnotations.get(LIRInstruction.Use.class));
+        alives = new Values(ifs.valueAnnotations.get(LIRInstruction.Alive.class));
+        temps = new Values(ifs.valueAnnotations.get(LIRInstruction.Temp.class));
+        defs = new Values(ifs.valueAnnotations.get(LIRInstruction.Def.class));
 
-        mode = scanner.valueAnnotations.get(LIRInstruction.Temp.class);
-        directTempCount = mode.scalarOffsets.size();
-        tempOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets);
-        tempFlags = arrayUsingSortedOffsets(mode.flags, tempOffsets, new EnumSet[tempOffsets.length]);
+        states = new Fields(ifs.states);
+        data = new Fields(ifs.data);
 
-        mode = scanner.valueAnnotations.get(LIRInstruction.Def.class);
-        directDefCount = mode.scalarOffsets.size();
-        defOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets);
-        defFlags = arrayUsingSortedOffsets(mode.flags, defOffsets, new EnumSet[defOffsets.length]);
-
-        stateOffsets = sortedLongCopy(scanner.stateOffsets);
-        dataOffsets = sortedLongCopy(scanner.dataOffsets);
-
-        fieldNames = scanner.fieldNames;
-        fieldTypes = scanner.fieldTypes;
-
-        opcodeConstant = scanner.opcodeConstant;
-        opcodeOffset = scanner.opcodeOffset;
+        opcodeConstant = ifs.opcodeConstant;
+        if (ifs.opcodeField == null) {
+            opcodeIndex = -1;
+        } else {
+            opcodeIndex = ifs.data.indexOf(ifs.opcodeField);
+        }
     }
 
     private static class InstructionFieldScanner extends FieldScanner {
 
         private String opcodeConstant;
-        private long opcodeOffset;
+
+        /**
+         * Field (if any) annotated by {@link Opcode}.
+         */
+        private FieldInfo opcodeField;
 
         public InstructionFieldScanner(CalcOffset calc) {
             super(calc);
@@ -148,16 +128,15 @@
             return result;
         }
 
-        @Override
         public void scan(Class<?> clazz) {
             if (clazz.getAnnotation(Opcode.class) != null) {
                 opcodeConstant = clazz.getAnnotation(Opcode.class).value();
             }
-            opcodeOffset = -1;
+            opcodeField = null;
 
-            super.scan(clazz);
+            super.scan(clazz, true);
 
-            if (opcodeConstant == null && opcodeOffset == -1) {
+            if (opcodeConstant == null && opcodeField == null) {
                 opcodeConstant = clazz.getSimpleName();
                 if (opcodeConstant.endsWith("Op")) {
                     opcodeConstant = opcodeConstant.substring(0, opcodeConstant.length() - 2);
@@ -166,18 +145,20 @@
         }
 
         @Override
-        protected void scanField(Field field, Class<?> type, long offset) {
+        protected void scanField(Field field, long offset) {
+            Class<?> type = field.getType();
             if (STATE_CLASS.isAssignableFrom(type)) {
                 assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
                 assert field.getAnnotation(LIRInstruction.State.class) != null : "Field must have state annotation: " + field;
-                stateOffsets.add(offset);
+                states.add(new FieldInfo(offset, field.getName(), type));
             } else {
-                super.scanField(field, type, offset);
+                super.scanField(field, offset);
             }
 
             if (field.getAnnotation(Opcode.class) != null) {
-                assert opcodeConstant == null && opcodeOffset == -1 : "Can have only one Opcode definition: " + field.getType();
-                opcodeOffset = offset;
+                assert opcodeConstant == null && opcodeField == null : "Can have only one Opcode definition: " + type;
+                assert data.get(data.size() - 1).offset == offset;
+                opcodeField = data.get(data.size() - 1);
             }
         }
     }
@@ -186,97 +167,33 @@
     public String toString() {
         StringBuilder str = new StringBuilder();
         str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" use[");
-        for (int i = 0; i < useOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(useOffsets[i]);
-        }
+        uses.appendFields(str);
         str.append("] alive[");
-        for (int i = 0; i < aliveOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(aliveOffsets[i]);
-        }
+        alives.appendFields(str);
         str.append("] temp[");
-        for (int i = 0; i < tempOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(tempOffsets[i]);
-        }
+        temps.appendFields(str);
         str.append("] def[");
-        for (int i = 0; i < defOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(defOffsets[i]);
-        }
+        defs.appendFields(str);
         str.append("] state[");
-        for (int i = 0; i < stateOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(stateOffsets[i]);
-        }
+        states.appendFields(str);
         str.append("] data[");
-        for (int i = 0; i < dataOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(dataOffsets[i]);
-        }
+        data.appendFields(str);
         str.append("]");
         return str.toString();
     }
 
-    Value getValue(LIRInstruction obj, ValuePosition pos) {
-        long[] offsets;
-        int directCount;
-        switch (pos.getMode()) {
-            case USE:
-                directCount = directUseCount;
-                offsets = useOffsets;
-                break;
-            case ALIVE:
-                directCount = directAliveCount;
-                offsets = aliveOffsets;
-                break;
-            case TEMP:
-                directCount = directTempCount;
-                offsets = tempOffsets;
-                break;
-            case DEF:
-                directCount = directDefCount;
-                offsets = defOffsets;
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere("unkown OperandMode: " + pos.getMode());
-        }
-        return getValueForPosition(obj, offsets, directCount, pos);
-    }
-
-    void setValue(LIRInstruction obj, ValuePosition pos, Value value) {
-        long[] offsets;
-        int directCount;
-        switch (pos.getMode()) {
+    Values getValues(OperandMode mode) {
+        switch (mode) {
             case USE:
-                directCount = directUseCount;
-                offsets = useOffsets;
-                break;
+                return uses;
             case ALIVE:
-                directCount = directAliveCount;
-                offsets = aliveOffsets;
-                break;
+                return alives;
             case TEMP:
-                directCount = directTempCount;
-                offsets = tempOffsets;
-                break;
+                return temps;
             case DEF:
-                directCount = directDefCount;
-                offsets = defOffsets;
-                break;
+                return defs;
             default:
-                throw GraalInternalError.shouldNotReachHere("unkown OperandMode: " + pos.getMode());
-        }
-        setValueForPosition(obj, offsets, directCount, pos, value);
-    }
-
-    EnumSet<OperandFlag> getFlags(ValuePosition pos) {
-        switch (pos.getMode()) {
-            case USE:
-                return useFlags[pos.getIndex()];
-            case ALIVE:
-                return aliveFlags[pos.getIndex()];
-            case TEMP:
-                return tempFlags[pos.getIndex()];
-            case DEF:
-                return defFlags[pos.getIndex()];
-            default:
-                throw GraalInternalError.shouldNotReachHere("unkown OperandMode: " + pos.getMode());
+                throw GraalInternalError.shouldNotReachHere("unknown OperandMode: " + mode);
         }
     }
 
@@ -284,58 +201,58 @@
         if (opcodeConstant != null) {
             return opcodeConstant;
         }
-        assert opcodeOffset != -1;
-        return unsafe.getObject(obj, opcodeOffset).toString();
+        assert opcodeIndex != -1;
+        return data.getObject(obj, opcodeIndex).toString();
     }
 
     final boolean hasOperands() {
-        return useOffsets.length > 0 || aliveOffsets.length > 0 || tempOffsets.length > 0 || defOffsets.length > 0;
+        return uses.getCount() > 0 || alives.getCount() > 0 || temps.getCount() > 0 || defs.getCount() > 0;
     }
 
     final boolean hasState(LIRInstruction obj) {
-        for (int i = 0; i < stateOffsets.length; i++) {
-            if (getState(obj, stateOffsets[i]) != null) {
+        for (int i = 0; i < states.getCount(); i++) {
+            if (states.getObject(obj, i) != null) {
                 return true;
             }
         }
         return false;
     }
 
-    final void forEachUse(LIRInstruction obj, ValuePositionProcedure proc) {
-        forEach(obj, obj, directUseCount, useOffsets, OperandMode.USE, useFlags, proc, ValuePosition.ROOT_VALUE_POSITION);
+    final void forEachUsePos(LIRInstruction obj, ValuePositionProcedure proc) {
+        forEach(obj, obj, uses, OperandMode.USE, proc, ValuePosition.ROOT_VALUE_POSITION);
     }
 
-    final void forEachAlive(LIRInstruction obj, ValuePositionProcedure proc) {
-        forEach(obj, obj, directAliveCount, aliveOffsets, OperandMode.ALIVE, aliveFlags, proc, ValuePosition.ROOT_VALUE_POSITION);
+    final void forEachAlivePos(LIRInstruction obj, ValuePositionProcedure proc) {
+        forEach(obj, obj, alives, OperandMode.ALIVE, proc, ValuePosition.ROOT_VALUE_POSITION);
     }
 
-    final void forEachTemp(LIRInstruction obj, ValuePositionProcedure proc) {
-        forEach(obj, obj, directTempCount, tempOffsets, OperandMode.TEMP, tempFlags, proc, ValuePosition.ROOT_VALUE_POSITION);
+    final void forEachTempPos(LIRInstruction obj, ValuePositionProcedure proc) {
+        forEach(obj, obj, temps, OperandMode.TEMP, proc, ValuePosition.ROOT_VALUE_POSITION);
     }
 
-    final void forEachDef(LIRInstruction obj, ValuePositionProcedure proc) {
-        forEach(obj, obj, directDefCount, defOffsets, OperandMode.DEF, defFlags, proc, ValuePosition.ROOT_VALUE_POSITION);
+    final void forEachDefPos(LIRInstruction obj, ValuePositionProcedure proc) {
+        forEach(obj, obj, defs, OperandMode.DEF, proc, ValuePosition.ROOT_VALUE_POSITION);
     }
 
-    final void forEachUse(LIRInstruction obj, InstructionValueProcedureBase proc) {
-        forEach(obj, directUseCount, useOffsets, OperandMode.USE, useFlags, proc);
+    final void forEachUse(LIRInstruction obj, InstructionValueProcedure proc) {
+        forEach(obj, uses, OperandMode.USE, proc);
     }
 
-    final void forEachAlive(LIRInstruction obj, InstructionValueProcedureBase proc) {
-        forEach(obj, directAliveCount, aliveOffsets, OperandMode.ALIVE, aliveFlags, proc);
+    final void forEachAlive(LIRInstruction obj, InstructionValueProcedure proc) {
+        forEach(obj, alives, OperandMode.ALIVE, proc);
     }
 
-    final void forEachTemp(LIRInstruction obj, InstructionValueProcedureBase proc) {
-        forEach(obj, directTempCount, tempOffsets, OperandMode.TEMP, tempFlags, proc);
+    final void forEachTemp(LIRInstruction obj, InstructionValueProcedure proc) {
+        forEach(obj, temps, OperandMode.TEMP, proc);
     }
 
-    final void forEachDef(LIRInstruction obj, InstructionValueProcedureBase proc) {
-        forEach(obj, directDefCount, defOffsets, OperandMode.DEF, defFlags, proc);
+    final void forEachDef(LIRInstruction obj, InstructionValueProcedure proc) {
+        forEach(obj, defs, OperandMode.DEF, proc);
     }
 
-    final void forEachState(LIRInstruction obj, InstructionValueProcedureBase proc) {
-        for (int i = 0; i < stateOffsets.length; i++) {
-            LIRFrameState state = getState(obj, stateOffsets[i]);
+    final void forEachState(LIRInstruction obj, InstructionValueProcedure proc) {
+        for (int i = 0; i < states.getCount(); i++) {
+            LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
             if (state != null) {
                 state.forEachState(obj, proc);
             }
@@ -343,8 +260,8 @@
     }
 
     final void forEachState(LIRInstruction obj, InstructionStateProcedure proc) {
-        for (int i = 0; i < stateOffsets.length; i++) {
-            LIRFrameState state = getState(obj, stateOffsets[i]);
+        for (int i = 0; i < states.getCount(); i++) {
+            LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
             if (state != null) {
                 proc.doState(obj, state);
             }
@@ -352,30 +269,27 @@
     }
 
     final Value forEachRegisterHint(LIRInstruction obj, OperandMode mode, InstructionValueProcedure proc) {
-        int hintDirectCount = 0;
-        long[] hintOffsets = null;
+        Values hints;
         if (mode == OperandMode.USE) {
-            hintDirectCount = directDefCount;
-            hintOffsets = defOffsets;
+            hints = defs;
         } else if (mode == OperandMode.DEF) {
-            hintDirectCount = directUseCount;
-            hintOffsets = useOffsets;
+            hints = uses;
         } else {
             return null;
         }
 
-        for (int i = 0; i < hintOffsets.length; i++) {
-            if (i < hintDirectCount) {
-                Value hintValue = getValue(obj, hintOffsets[i]);
-                Value result = proc.processValue(obj, hintValue, null, null);
+        for (int i = 0; i < hints.getCount(); i++) {
+            if (i < hints.getDirectCount()) {
+                Value hintValue = hints.getValue(obj, i);
+                Value result = proc.doValue(obj, hintValue, null, null);
                 if (result != null) {
                     return result;
                 }
             } else {
-                Value[] hintValues = getValueArray(obj, hintOffsets[i]);
+                Value[] hintValues = hints.getValueArray(obj, i);
                 for (int j = 0; j < hintValues.length; j++) {
                     Value hintValue = hintValues[j];
-                    Value result = proc.processValue(obj, hintValue, null, null);
+                    Value result = proc.doValue(obj, hintValue, null, null);
                     if (result != null) {
                         return result;
                     }
@@ -385,29 +299,25 @@
         return null;
     }
 
-    private static LIRFrameState getState(LIRInstruction obj, long offset) {
-        return (LIRFrameState) unsafe.getObject(obj, offset);
-    }
-
     String toString(LIRInstruction obj) {
         StringBuilder result = new StringBuilder();
 
-        appendValues(result, obj, "", " = ", "(", ")", new String[]{""}, defOffsets);
-        result.append(getOpcode(obj).toUpperCase());
-        appendValues(result, obj, " ", "", "(", ")", new String[]{"", "~"}, useOffsets, aliveOffsets);
-        appendValues(result, obj, " ", "", "{", "}", new String[]{""}, tempOffsets);
+        appendValues(result, obj, "", " = ", "(", ")", new String[]{""}, defs);
+        result.append(String.valueOf(getOpcode(obj)).toUpperCase());
+        appendValues(result, obj, " ", "", "(", ")", new String[]{"", "~"}, uses, alives);
+        appendValues(result, obj, " ", "", "{", "}", new String[]{""}, temps);
 
-        for (int i = 0; i < dataOffsets.length; i++) {
-            if (dataOffsets[i] == opcodeOffset) {
+        for (int i = 0; i < data.getCount(); i++) {
+            if (i == opcodeIndex) {
                 continue;
             }
-            result.append(" ").append(fieldNames.get(dataOffsets[i])).append(": ").append(getFieldString(obj, dataOffsets[i]));
+            result.append(" ").append(data.getName(i)).append(": ").append(getFieldString(obj, i, data));
         }
 
-        for (int i = 0; i < stateOffsets.length; i++) {
-            LIRFrameState state = getState(obj, stateOffsets[i]);
+        for (int i = 0; i < states.getCount(); i++) {
+            LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
             if (state != null) {
-                result.append(" ").append(fieldNames.get(stateOffsets[i])).append(" [bci:");
+                result.append(" ").append(states.getName(i)).append(" [bci:");
                 String sep = "";
                 for (BytecodeFrame cur = state.topFrame; cur != null; cur = cur.caller()) {
                     result.append(sep).append(cur.getBCI());
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Fri Oct 03 13:48:58 2014 +0200
@@ -48,21 +48,117 @@
         super(clazz);
     }
 
+    protected static class Values extends Fields {
+        private final int directCount;
+        private final OperandMode mode;
+        private final EnumSet<OperandFlag>[] flags;
+
+        public Values(OperandModeAnnotation mode) {
+            this(mode.directCount, null, mode.values);
+        }
+
+        @SuppressWarnings("unchecked")
+        public Values(int directCount, OperandMode mode, ArrayList<ValueFieldInfo> fields) {
+            super(fields);
+            this.mode = mode;
+            this.directCount = directCount;
+            flags = new EnumSet[fields.size()];
+            for (int i = 0; i < fields.size(); i++) {
+                flags[i] = fields.get(i).flags;
+            }
+        }
+
+        public int getDirectCount() {
+            return directCount;
+        }
+
+        public OperandMode getMode() {
+            return mode;
+        }
+
+        public EnumSet<OperandFlag> getFlags(int i) {
+            return flags[i];
+        }
+
+        protected Value getValue(Object obj, int index) {
+            return (Value) getObject(obj, index);
+        }
+
+        protected void setValue(Object obj, int index, Value value) {
+            putObject(obj, index, value);
+        }
+
+        protected Value[] getValueArray(Object obj, int index) {
+            return (Value[]) getObject(obj, index);
+        }
+
+        protected void setValueArray(Object obj, int index, Value[] valueArray) {
+            putObject(obj, index, valueArray);
+        }
+
+        @Override
+        public String toString() {
+            if (mode != null) {
+                return super.toString() + ":" + mode;
+            }
+            return super.toString();
+        }
+    }
+
+    /**
+     * The component values in an {@link LIRInstruction} or {@link CompositeValue}.
+     */
+    protected Values values;
+
+    protected static class ValueFieldInfo extends FieldInfo {
+
+        final EnumSet<OperandFlag> flags;
+
+        public ValueFieldInfo(long offset, String name, Class<?> type, EnumSet<OperandFlag> flags) {
+            super(offset, name, type);
+            assert VALUE_ARRAY_CLASS.isAssignableFrom(type) || VALUE_CLASS.isAssignableFrom(type);
+            this.flags = flags;
+        }
+
+        /**
+         * Sorts non-array fields before array fields.
+         */
+        @Override
+        public int compareTo(FieldInfo o) {
+            if (VALUE_ARRAY_CLASS.isAssignableFrom(o.type)) {
+                if (!VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
+                    return -1;
+                }
+            } else {
+                if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
+                    return 1;
+                }
+            }
+            return super.compareTo(o);
+        }
+
+        @Override
+        public String toString() {
+            return super.toString() + flags;
+        }
+    }
+
     protected static class OperandModeAnnotation {
 
-        public final ArrayList<Long> scalarOffsets = new ArrayList<>();
-        public final ArrayList<Long> arrayOffsets = new ArrayList<>();
-        public final Map<Long, EnumSet<OperandFlag>> flags = new HashMap<>();
+        /**
+         * Number of non-array fields in {@link #values}.
+         */
+        public int directCount;
+        public final ArrayList<ValueFieldInfo> values = new ArrayList<>();
     }
 
     protected abstract static class FieldScanner extends BaseFieldScanner {
 
         public final Map<Class<? extends Annotation>, OperandModeAnnotation> valueAnnotations;
-        public final ArrayList<Long> stateOffsets = new ArrayList<>();
+        public final ArrayList<FieldInfo> states = new ArrayList<>();
 
         public FieldScanner(CalcOffset calc) {
             super(calc);
-
             valueAnnotations = new HashMap<>();
         }
 
@@ -81,26 +177,26 @@
         protected abstract EnumSet<OperandFlag> getFlags(Field field);
 
         @Override
-        protected void scanField(Field field, Class<?> type, long offset) {
+        protected void scanField(Field field, long offset) {
+            Class<?> type = field.getType();
             if (VALUE_CLASS.isAssignableFrom(type) && type != CONSTANT_CLASS) {
                 assert !Modifier.isFinal(field.getModifiers()) : "Value field must not be declared final because it is modified by register allocator: " + field;
                 OperandModeAnnotation annotation = getOperandModeAnnotation(field);
                 assert annotation != null : "Field must have operand mode annotation: " + field;
-                annotation.scalarOffsets.add(offset);
                 EnumSet<OperandFlag> flags = getFlags(field);
                 assert verifyFlags(field, type, flags);
-                annotation.flags.put(offset, getFlags(field));
+                annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, flags));
+                annotation.directCount++;
             } else if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
                 OperandModeAnnotation annotation = getOperandModeAnnotation(field);
                 assert annotation != null : "Field must have operand mode annotation: " + field;
-                annotation.arrayOffsets.add(offset);
                 EnumSet<OperandFlag> flags = getFlags(field);
                 assert verifyFlags(field, type.getComponentType(), flags);
-                annotation.flags.put(offset, getFlags(field));
+                annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, flags));
             } else {
                 assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
                 assert field.getAnnotation(LIRInstruction.State.class) == null : "Field must not have state annotation: " + field;
-                dataOffsets.add(offset);
+                data.add(new FieldInfo(offset, field.getName(), type));
             }
         }
 
@@ -118,74 +214,73 @@
         }
     }
 
-    protected static void forEach(LIRInstruction inst, int directCount, long[] offsets, OperandMode mode, EnumSet<OperandFlag>[] flags, InstructionValueProcedureBase proc) {
-        for (int i = 0; i < offsets.length; i++) {
-            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(flags[i]);
+    protected static void forEach(LIRInstruction inst, Values values, OperandMode mode, InstructionValueProcedure proc) {
+        for (int i = 0; i < values.getCount(); i++) {
+            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i));
 
-            if (i < directCount) {
-                Value value = getValue(inst, offsets[i]);
+            if (i < values.getDirectCount()) {
+                Value value = values.getValue(inst, i);
                 Value newValue;
                 if (value instanceof CompositeValue) {
                     CompositeValue composite = (CompositeValue) value;
                     newValue = composite.forEachComponent(inst, mode, proc);
                 } else {
-                    newValue = proc.processValue(inst, value, mode, flags[i]);
+                    newValue = proc.doValue(inst, value, mode, values.getFlags(i));
                 }
                 if (!value.identityEquals(newValue)) {
-                    setValue(inst, offsets[i], newValue);
+                    values.setValue(inst, i, newValue);
                 }
             } else {
-                Value[] values = getValueArray(inst, offsets[i]);
-                for (int j = 0; j < values.length; j++) {
-                    Value value = values[j];
+                Value[] valueArray = values.getValueArray(inst, i);
+                for (int j = 0; j < valueArray.length; j++) {
+                    Value value = valueArray[j];
                     Value newValue;
                     if (value instanceof CompositeValue) {
                         CompositeValue composite = (CompositeValue) value;
                         newValue = composite.forEachComponent(inst, mode, proc);
                     } else {
-                        newValue = proc.processValue(inst, value, mode, flags[i]);
+                        newValue = proc.doValue(inst, value, mode, values.getFlags(i));
                     }
                     if (!value.identityEquals(newValue)) {
-                        values[j] = newValue;
+                        valueArray[j] = newValue;
                     }
                 }
             }
         }
     }
 
-    protected static CompositeValue forEachComponent(LIRInstruction inst, CompositeValue obj, int directCount, long[] offsets, OperandMode mode, EnumSet<OperandFlag>[] flags,
-                    InstructionValueProcedureBase proc) {
+    protected static CompositeValue forEachComponent(LIRInstruction inst, CompositeValue obj, Values values, OperandMode mode, InstructionValueProcedure proc) {
         CompositeValue newCompValue = null;
-        for (int i = 0; i < offsets.length; i++) {
-            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(flags[i]);
+        for (int i = 0; i < values.getCount(); i++) {
+            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i));
 
-            if (i < directCount) {
-                Value value = getValue(obj, offsets[i]);
+            if (i < values.getDirectCount()) {
+                Value value = values.getValue(obj, i);
                 Value newValue;
                 if (value instanceof CompositeValue) {
                     CompositeValue composite = (CompositeValue) value;
                     newValue = composite.forEachComponent(inst, mode, proc);
                 } else {
-                    newValue = proc.processValue(inst, value, mode, flags[i]);
+                    newValue = proc.doValue(inst, value, mode, values.getFlags(i));
                 }
                 if (!value.identityEquals(newValue)) {
                     // lazy initialize
                     if (newCompValue == null) {
                         newCompValue = obj.clone();
                     }
-                    setValue(newCompValue, offsets[i], newValue);
+                    values.setValue(newCompValue, i, newValue);
                 }
             } else {
-                Value[] values = getValueArray(obj, offsets[i]);
+                Value[] valueArray = values.getValueArray(obj, i);
                 Value[] newValues = null;
-                for (int j = 0; j < values.length; j++) {
-                    Value value = values[j];
+                for (int j = 0; j < valueArray.length; j++) {
+                    Value value = valueArray[j];
                     Value newValue;
                     if (value instanceof CompositeValue) {
                         CompositeValue composite = (CompositeValue) value;
                         newValue = composite.forEachComponent(inst, mode, proc);
                     } else {
-                        newValue = proc.processValue(inst, value, mode, flags[i]);
+                        newValue = proc.doValue(inst, value, mode, values.getFlags(i));
                     }
                     if (!value.identityEquals(newValue)) {
                         // lazy initialize
@@ -193,7 +288,7 @@
                             if (newCompValue == null) {
                                 newCompValue = obj.clone();
                             }
-                            newValues = getValueArray(newCompValue, offsets[i]);
+                            newValues = values.getValueArray(newCompValue, i);
                         }
                         newValues[j] = newValue;
                     }
@@ -203,18 +298,17 @@
         return newCompValue != null ? newCompValue : obj;
     }
 
-    protected static void forEach(LIRInstruction inst, Object obj, int directCount, long[] offsets, OperandMode mode, EnumSet<OperandFlag>[] flags, ValuePositionProcedure proc,
-                    ValuePosition outerPosition) {
-        for (int i = 0; i < offsets.length; i++) {
-            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(flags[i]);
+    protected static void forEach(LIRInstruction inst, Object obj, Values values, OperandMode mode, ValuePositionProcedure proc, ValuePosition outerPosition) {
+        for (int i = 0; i < values.getCount(); i++) {
+            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i));
 
-            if (i < directCount) {
-                Value value = getValue(obj, offsets[i]);
+            if (i < values.getDirectCount()) {
+                Value value = values.getValue(obj, i);
                 doForValue(inst, mode, proc, outerPosition, i, ValuePosition.NO_SUBINDEX, value);
             } else {
-                Value[] values = getValueArray(obj, offsets[i]);
-                for (int j = 0; j < values.length; j++) {
-                    Value value = values[j];
+                Value[] valueArray = values.getValueArray(obj, i);
+                for (int j = 0; j < valueArray.length; j++) {
+                    Value value = valueArray[j];
                     doForValue(inst, mode, proc, outerPosition, i, j, value);
                 }
             }
@@ -222,7 +316,8 @@
     }
 
     private static void doForValue(LIRInstruction inst, OperandMode mode, ValuePositionProcedure proc, ValuePosition outerPosition, int index, int subIndex, Value value) {
-        ValuePosition position = new ValuePosition(mode, index, subIndex, outerPosition);
+        Values values = inst.getLIRInstructionClass().getValues(mode);
+        ValuePosition position = new ValuePosition(values, index, subIndex, outerPosition);
         if (value instanceof CompositeValue) {
             CompositeValue composite = (CompositeValue) value;
             composite.forEachComponent(inst, mode, proc, position);
@@ -231,102 +326,72 @@
         }
     }
 
-    protected static Value getValueForPosition(Object obj, long[] offsets, int directCount, ValuePosition pos) {
-        if (pos.getIndex() < directCount) {
-            return getValue(obj, offsets[pos.getIndex()]);
+    protected static Value getValueForPosition(Object obj, Values values, ValuePosition pos) {
+        if (pos.getIndex() < values.getDirectCount()) {
+            return values.getValue(obj, pos.getIndex());
         }
-        return getValueArray(obj, offsets[pos.getIndex()])[pos.getSubIndex()];
+        return values.getValueArray(obj, pos.getIndex())[pos.getSubIndex()];
     }
 
-    protected static void setValueForPosition(Object obj, long[] offsets, int directCount, ValuePosition pos, Value value) {
-        if (pos.getIndex() < directCount) {
-            setValue(obj, offsets[pos.getIndex()], value);
+    protected static void setValueForPosition(Object obj, Values values, ValuePosition pos, Value value) {
+        if (pos.getIndex() < values.getDirectCount()) {
+            values.setValue(obj, pos.getIndex(), value);
         } else {
-            getValueArray(obj, offsets[pos.getIndex()])[pos.getSubIndex()] = value;
+            values.getValueArray(obj, pos.getIndex())[pos.getSubIndex()] = value;
         }
     }
 
-    protected static Value getValue(Object obj, long offset) {
-        return (Value) unsafe.getObject(obj, offset);
-    }
-
-    protected static void setValue(Object obj, long offset, Value value) {
-        unsafe.putObject(obj, offset, value);
-    }
-
-    protected static Value[] getValueArray(Object obj, long offset) {
-        return (Value[]) unsafe.getObject(obj, offset);
-    }
-
-    protected static void setValueArray(Object obj, long offset, Value[] valueArray) {
-        unsafe.putObject(obj, offset, valueArray);
-    }
-
-    protected void appendValues(StringBuilder result, Object obj, String start, String end, String startMultiple, String endMultiple, String[] prefix, long[]... moffsets) {
+    protected void appendValues(StringBuilder sb, Object obj, String start, String end, String startMultiple, String endMultiple, String[] prefix, Fields... fieldsList) {
         int total = 0;
-        for (long[] offsets : moffsets) {
-            total += offsets.length;
+        for (Fields fields : fieldsList) {
+            total += fields.getCount();
         }
         if (total == 0) {
             return;
         }
 
-        result.append(start);
+        sb.append(start);
         if (total > 1) {
-            result.append(startMultiple);
+            sb.append(startMultiple);
         }
         String sep = "";
-        for (int i = 0; i < moffsets.length; i++) {
-            long[] offsets = moffsets[i];
-
-            for (int j = 0; j < offsets.length; j++) {
-                result.append(sep).append(prefix[i]);
-                long offset = offsets[j];
+        int i = 0;
+        for (Fields fields : fieldsList) {
+            for (int j = 0; j < fields.getCount(); j++) {
+                sb.append(sep).append(prefix[i]);
                 if (total > 1) {
-                    result.append(fieldNames.get(offset)).append(": ");
+                    sb.append(fields.getName(j)).append(": ");
                 }
-                result.append(getFieldString(obj, offset));
+                sb.append(getFieldString(obj, j, fields));
                 sep = ", ";
             }
+            i++;
         }
         if (total > 1) {
-            result.append(endMultiple);
+            sb.append(endMultiple);
         }
-        result.append(end);
+        sb.append(end);
     }
 
-    protected String getFieldString(Object obj, long offset) {
-        Class<?> type = fieldTypes.get(offset);
-        if (type == int.class) {
-            return String.valueOf(unsafe.getInt(obj, offset));
-        } else if (type == long.class) {
-            return String.valueOf(unsafe.getLong(obj, offset));
-        } else if (type == boolean.class) {
-            return String.valueOf(unsafe.getBoolean(obj, offset));
-        } else if (type == float.class) {
-            return String.valueOf(unsafe.getFloat(obj, offset));
-        } else if (type == double.class) {
-            return String.valueOf(unsafe.getDouble(obj, offset));
-        } else if (type == byte.class) {
-            return String.valueOf(unsafe.getByte(obj, offset));
-        } else if (!type.isPrimitive()) {
-            Object value = unsafe.getObject(obj, offset);
-            if (!type.isArray()) {
-                return String.valueOf(value);
-            } else if (type == int[].class) {
-                return Arrays.toString((int[]) value);
-            } else if (type == double[].class) {
-                return Arrays.toString((double[]) value);
-            } else if (type == byte[].class) {
-                byte[] byteValue = (byte[]) value;
-                if (isPrintableAsciiString(byteValue)) {
-                    return toString(byteValue);
-                } else {
-                    return Arrays.toString(byteValue);
-                }
-            } else if (!type.getComponentType().isPrimitive()) {
-                return Arrays.toString((Object[]) value);
+    protected String getFieldString(Object obj, int index, Fields fields) {
+        Object value = fields.get(obj, index);
+        Class<?> type = fields.getType(index);
+        if (value == null || type.isPrimitive() || !type.isArray()) {
+            return String.valueOf(value);
+        }
+        if (type == int[].class) {
+            return Arrays.toString((int[]) value);
+        } else if (type == double[].class) {
+            return Arrays.toString((double[]) value);
+        } else if (type == byte[].class) {
+            byte[] byteValue = (byte[]) value;
+            if (isPrintableAsciiString(byteValue)) {
+                return toString(byteValue);
+            } else {
+                return Arrays.toString(byteValue);
             }
+        } else if (!type.getComponentType().isPrimitive()) {
+            return Arrays.toString((Object[]) value);
         }
         assert false : "unhandled field type: " + type;
         return "";
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Fri Oct 03 13:48:58 2014 +0200
@@ -61,21 +61,13 @@
         return isRegister(value) && frameMap.registerConfig.getAttributesMap()[asRegister(value).number].isAllocatable();
     }
 
-    private static InstructionValueConsumer allowedConsumer = new InstructionValueConsumer() {
-
-        @Override
-        public void visitValue(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-            allowed(op, value, mode, flags);
-        }
-    };
-
     public static boolean verify(final LIRInstruction op) {
 
-        op.visitEachInput(allowedConsumer);
-        op.visitEachAlive(allowedConsumer);
-        op.visitEachState(allowedConsumer);
-        op.visitEachTemp(allowedConsumer);
-        op.visitEachOutput(allowedConsumer);
+        op.visitEachInput(LIRVerifier::allowed);
+        op.visitEachAlive(LIRVerifier::allowed);
+        op.visitEachState(LIRVerifier::allowed);
+        op.visitEachTemp(LIRVerifier::allowed);
+        op.visitEachOutput(LIRVerifier::allowed);
 
         op.verify();
         return true;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Fri Oct 03 13:48:58 2014 +0200
@@ -362,7 +362,7 @@
             /*
              * Value procedure for the instruction's output and temp values
              */
-            class OutputValueConsumer extends ValueConsumer {
+            class OutputValueConsumer implements ValueConsumer {
 
                 int opValueNum;
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StateProcedure.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StateProcedure.java	Fri Oct 03 13:48:58 2014 +0200
@@ -22,12 +22,13 @@
  */
 package com.oracle.graal.lir;
 
-public abstract class StateProcedure extends InstructionStateProcedure {
+@FunctionalInterface
+public interface StateProcedure extends InstructionStateProcedure {
 
-    protected abstract void doState(LIRFrameState state);
+    void doState(LIRFrameState state);
 
     @Override
-    protected final void doState(LIRInstruction instruction, LIRFrameState state) {
+    default void doState(LIRInstruction instruction, LIRFrameState state) {
         doState(state);
     }
 }
\ No newline at end of file
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValueConsumer.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValueConsumer.java	Fri Oct 03 13:48:58 2014 +0200
@@ -25,43 +25,26 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.lir.LIRInstruction.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
 
 /**
  * Non-modifying version of {@link ValueProcedure}.
  */
-public abstract class ValueConsumer extends InstructionValueConsumer {
+@FunctionalInterface
+public interface ValueConsumer extends InstructionValueProcedure {
 
     /**
-     * Iterator method to be overwritten. This version of the iterator does not take additional
-     * parameters to keep the signature short.
-     *
-     * @param value The value that is iterated.
-     */
-    protected void visitValue(Value value) {
-        throw GraalInternalError.shouldNotReachHere("One of the visitValue() methods must be overwritten");
-    }
-
-    /**
-     * Iterator method to be overwritten. This version of the iterator gets additional parameters
-     * about the processed value.
+     * Iterator method to be overwritten.
      *
      * @param value The value that is iterated.
      * @param mode The operand mode for the value.
      * @param flags A set of flags for the value.
      */
-    protected void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-        visitValue(value);
-    }
+    void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags);
 
-    @Override
-    protected final void visitValue(LIRInstruction instruction, Value value) {
-        throw GraalInternalError.shouldNotReachHere("This visitValue() method should never be called");
+    default Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        visitValue(value, mode, flags);
+        return value;
     }
-
-    @Override
-    protected void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-        visitValue(value, mode, flags);
-    }
-}
\ No newline at end of file
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValuePosition.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValuePosition.java	Fri Oct 03 13:48:58 2014 +0200
@@ -25,14 +25,15 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.lir.LIRInstruction.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRIntrospection.Values;
 
 /**
  * Describes an operand slot for a {@link LIRInstructionClass}.
  */
 public final class ValuePosition {
 
-    private final OperandMode mode;
+    private final Values values;
     private final int index;
     private final int subIndex;
     private final ValuePosition outerPosition;
@@ -40,8 +41,8 @@
     public static final int NO_SUBINDEX = -1;
     public static final ValuePosition ROOT_VALUE_POSITION = null;
 
-    public ValuePosition(OperandMode mode, int index, int subIndex, ValuePosition outerPosition) {
-        this.mode = mode;
+    public ValuePosition(Values values, int index, int subIndex, ValuePosition outerPosition) {
+        this.values = values;
         this.index = index;
         this.subIndex = subIndex;
         this.outerPosition = outerPosition;
@@ -51,20 +52,12 @@
         return outerPosition != ROOT_VALUE_POSITION;
     }
 
-    public Value get(LIRInstruction inst) {
+    public Value get(Object inst) {
         if (isCompositePosition()) {
             CompositeValue compValue = (CompositeValue) outerPosition.get(inst);
             return compValue.getValueClass().getValue(compValue, this);
         }
-        return inst.getLIRInstructionClass().getValue(inst, this);
-    }
-
-    public EnumSet<OperandFlag> getFlags(LIRInstruction inst) {
-        if (isCompositePosition()) {
-            CompositeValue compValue = (CompositeValue) outerPosition.get(inst);
-            return compValue.getValueClass().getFlags(this);
-        }
-        return inst.getLIRInstructionClass().getFlags(this);
+        return getValue(inst);
     }
 
     public void set(LIRInstruction inst, Value value) {
@@ -73,7 +66,7 @@
             CompositeValue newCompValue = compValue.getValueClass().createUpdatedValue(compValue, this, value);
             outerPosition.set(inst, newCompValue);
         } else {
-            inst.getLIRInstructionClass().setValue(inst, this, value);
+            setValue(inst, value);
         }
     }
 
@@ -85,8 +78,23 @@
         return index;
     }
 
-    public OperandMode getMode() {
-        return mode;
+    public EnumSet<OperandFlag> getFlags() {
+        return values.getFlags(index);
+    }
+
+    public Value getValue(Object obj) {
+        if (index < values.getDirectCount()) {
+            return values.getValue(obj, index);
+        }
+        return values.getValueArray(obj, index)[subIndex];
+    }
+
+    public void setValue(Object obj, Value value) {
+        if (index < values.getDirectCount()) {
+            values.setValue(obj, index, value);
+        } else {
+            values.getValueArray(obj, index)[subIndex] = value;
+        }
     }
 
     public ValuePosition getSuperPosition() {
@@ -96,9 +104,9 @@
     @Override
     public String toString() {
         if (outerPosition == ROOT_VALUE_POSITION) {
-            return mode.toString() + "(" + index + (subIndex < 0 ? "" : "/" + subIndex) + ")";
+            return values.getMode() + "(" + index + (subIndex < 0 ? "" : "/" + subIndex) + ")";
         }
-        return outerPosition.toString() + "[" + mode.toString() + "(" + index + (subIndex < 0 ? "" : "/" + subIndex) + ")]";
+        return outerPosition.toString() + "[" + values.getMode() + "(" + index + (subIndex < 0 ? "" : "/" + subIndex) + ")]";
     }
 
     @Override
@@ -106,7 +114,7 @@
         final int prime = 31;
         int result = 1;
         result = prime * result + index;
-        result = prime * result + ((mode == null) ? 0 : mode.hashCode());
+        result = prime * result + ((values.getMode() == null) ? 0 : values.getMode().hashCode());
         result = prime * result + subIndex;
         result = prime * result + ((outerPosition == null) ? 0 : outerPosition.hashCode());
         return result;
@@ -127,7 +135,7 @@
         if (index != other.index) {
             return false;
         }
-        if (mode != other.mode) {
+        if (values.getMode() != other.values.getMode()) {
             return false;
         }
         if (subIndex != other.subIndex) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValuePositionProcedure.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValuePositionProcedure.java	Fri Oct 03 13:48:58 2014 +0200
@@ -25,7 +25,8 @@
 /**
  * Iterator for iterating over a list of {@linkplain ValuePosition value positions}.
  */
-public abstract class ValuePositionProcedure {
+@FunctionalInterface
+public interface ValuePositionProcedure {
 
     /**
      * Iterator method to be overwritten. This version of the iterator does not take additional
@@ -34,6 +35,5 @@
      * @param instruction The current instruction.
      * @param position The position of the value that is iterated.
      */
-
-    public abstract void doValue(LIRInstruction instruction, ValuePosition position);
-}
\ No newline at end of file
+    void doValue(LIRInstruction instruction, ValuePosition position);
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValueProcedure.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValueProcedure.java	Fri Oct 03 13:48:58 2014 +0200
@@ -25,45 +25,26 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.lir.LIRInstruction.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
 
 /**
  * Similar to {@link InstructionValueProcedure} but without an {@link LIRInstruction} parameter.
  */
-public abstract class ValueProcedure extends InstructionValueProcedure {
+@FunctionalInterface
+public interface ValueProcedure extends InstructionValueProcedure {
 
     /**
-     * Iterator method to be overwritten. This version of the iterator does not take additional
-     * parameters to keep the signature short.
-     *
-     * @param value The value that is iterated.
-     * @return The new value to replace the value that was passed in.
-     */
-    protected Value doValue(Value value) {
-        throw GraalInternalError.shouldNotReachHere("One of the doValue() methods must be overwritten");
-    }
-
-    /**
-     * Iterator method to be overwritten. This version of the iterator gets additional parameters
-     * about the processed value.
+     * Iterator method to be overwritten.
      *
      * @param value The value that is iterated.
      * @param mode The operand mode for the value.
      * @param flags A set of flags for the value.
      * @return The new value to replace the value that was passed in.
      */
-    protected Value doValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-        return doValue(value);
-    }
+    Value doValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags);
 
-    @Override
-    protected final Value doValue(LIRInstruction instruction, Value value) {
-        throw GraalInternalError.shouldNotReachHere("This doValue() method should never be called");
-    }
-
-    @Override
-    public final Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+    default Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
         return doValue(value, mode, flags);
     }
-}
\ No newline at end of file
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Fri Oct 03 13:48:58 2014 +0200
@@ -32,6 +32,8 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.constopt.ConstantTree.Flags;
 import com.oracle.graal.lir.constopt.ConstantTree.NodeCost;
@@ -125,7 +127,7 @@
         ValueConsumer stateConsumer = new ValueConsumer() {
 
             @Override
-            public void visitValue(Value operand) {
+            public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
                 assert !operand.equals(var) : "constant usage through variable in frame state " + var;
             }
         };
@@ -161,55 +163,46 @@
     private void analyzeBlock(AbstractBlock<?> block) {
         try (Indent indent = Debug.logAndIndent("Block: %s", block)) {
 
-            InstructionValueConsumer loadConsumer = new InstructionValueConsumer() {
-                @Override
-                public void visitValue(LIRInstruction instruction, Value value) {
-                    if (isVariable(value)) {
-                        Variable var = (Variable) value;
+            InstructionValueConsumer loadConsumer = (instruction, value, mode, flags) -> {
+                if (isVariable(value)) {
+                    Variable var = (Variable) value;
 
-                        if (!phiConstants.get(var.index)) {
-                            if (!defined.get(var.index)) {
-                                defined.set(var.index);
-                                if (isConstantLoad(instruction)) {
-                                    Debug.log("constant load: %s", instruction);
-                                    map.put(var, new DefUseTree(instruction, block));
-                                    constantsTotal.increment();
-                                }
-                            } else {
-                                // Variable is redefined, this only happens for constant loads
-                                // introduced by phi resolution -> ignore.
-                                DefUseTree removed = map.remove(var);
-                                if (removed != null) {
-                                    phiConstantsSkipped.increment();
-                                }
-                                phiConstants.set(var.index);
-                                Debug.log(3, "Removing phi variable: %s", var);
+                    if (!phiConstants.get(var.index)) {
+                        if (!defined.get(var.index)) {
+                            defined.set(var.index);
+                            if (isConstantLoad(instruction)) {
+                                Debug.log("constant load: %s", instruction);
+                                map.put(var, new DefUseTree(instruction, block));
+                                constantsTotal.increment();
                             }
                         } else {
-                            assert defined.get(var.index) : "phi but not defined? " + var;
+                            // Variable is redefined, this only happens for constant loads
+                            // introduced by phi resolution -> ignore.
+                            DefUseTree removed = map.remove(var);
+                            if (removed != null) {
+                                phiConstantsSkipped.increment();
+                            }
+                            phiConstants.set(var.index);
+                            Debug.log(3, "Removing phi variable: %s", var);
                         }
-
+                    } else {
+                        assert defined.get(var.index) : "phi but not defined? " + var;
                     }
                 }
-
             };
 
-            ValuePositionProcedure useProcedure = new ValuePositionProcedure() {
-                @Override
-                public void doValue(LIRInstruction instruction, ValuePosition position) {
-                    Value value = position.get(instruction);
-                    if (isVariable(value)) {
-                        Variable var = (Variable) value;
-                        if (!phiConstants.get(var.index)) {
-                            DefUseTree tree = map.get(var);
-                            if (tree != null) {
-                                tree.addUsage(block, instruction, position);
-                                Debug.log("usage of %s : %s", var, instruction);
-                            }
+            ValuePositionProcedure useProcedure = (instruction, position) -> {
+                Value value = position.get(instruction);
+                if (isVariable(value)) {
+                    Variable var = (Variable) value;
+                    if (!phiConstants.get(var.index)) {
+                        DefUseTree tree = map.get(var);
+                        if (tree != null) {
+                            tree.addUsage(block, instruction, position);
+                            Debug.log("usage of %s : %s", var, instruction);
                         }
                     }
                 }
-
             };
 
             int opId = 0;
@@ -217,8 +210,8 @@
                 // set instruction id to the index in the lir instruction list
                 inst.setId(opId++);
                 inst.visitEachOutput(loadConsumer);
-                inst.forEachInput(useProcedure);
-                inst.forEachAlive(useProcedure);
+                inst.forEachInputPos(useProcedure);
+                inst.forEachAlivePos(useProcedure);
 
             }
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Fri Oct 03 13:48:58 2014 +0200
@@ -111,7 +111,20 @@
     }
 
     @Override
-    public abstract Variable emitMove(Value input);
+    public Variable emitMove(Value input) {
+        Variable result = newVariable(input.getLIRKind());
+        emitMove(result, input);
+        return result;
+    }
+
+    @Override
+    public Value emitLoadConstant(Constant constant) {
+        if (canInlineConstant(constant)) {
+            return constant;
+        } else {
+            return emitMove(constant);
+        }
+    }
 
     public AllocatableValue asAllocatable(Value value) {
         if (isAllocatableValue(value)) {
@@ -128,6 +141,16 @@
         return (Variable) value;
     }
 
+    /**
+     * Checks whether the supplied constant can be used without loading it into a register for most
+     * operations, i.e., for commonly used arithmetic, logical, and comparison operations.
+     *
+     * @param c The constant to check.
+     * @return True if the constant can be used directly, false if the constant needs to be in a
+     *         register.
+     */
+    protected abstract boolean canInlineConstant(Constant c);
+
     public Value loadNonConst(Value value) {
         if (isConstant(value) && !canInlineConstant((Constant) value)) {
             return emitMove(value);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Fri Oct 03 13:48:58 2014 +0200
@@ -52,6 +52,8 @@
 
     void doBlockEnd(AbstractBlock<?> block);
 
+    Value emitLoadConstant(Constant constant);
+
     Value emitLoad(LIRKind kind, Value address, LIRFrameState state);
 
     void emitStore(LIRKind kind, Value address, Value input, LIRFrameState state);
@@ -84,26 +86,6 @@
 
     Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args);
 
-    /**
-     * Checks whether the supplied constant can be used without loading it into a register for most
-     * operations, i.e., for commonly used arithmetic, logical, and comparison operations.
-     *
-     * @param c The constant to check.
-     * @return True if the constant can be used directly, false if the constant needs to be in a
-     *         register.
-     */
-    boolean canInlineConstant(Constant c);
-
-    /**
-     * Checks whether the supplied constant can be used without loading it into a register for store
-     * operations, i.e., on the right hand side of a memory access.
-     *
-     * @param c The constant to check.
-     * @return True if the constant can be used directly, false if the constant needs to be in a
-     *         register.
-     */
-    boolean canStoreConstant(Constant c);
-
     RegisterAttributes attributes(Register register);
 
     /**
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Fri Oct 03 13:48:58 2014 +0200
@@ -50,7 +50,7 @@
         List<BasicInductionVariable> bivs = new LinkedList<>();
         LoopBeginNode loopBegin = loop.loopBegin();
         AbstractEndNode forwardEnd = loopBegin.forwardEnd();
-        for (PhiNode phi : loopBegin.phis()) {
+        for (PhiNode phi : loopBegin.phis().filter(ValuePhiNode.class)) {
             ValueNode backValue = phi.singleBackValue();
             if (backValue == PhiNode.MULTIPLE_VALUES) {
                 continue;
--- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeGenerator.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeGenerator.java	Fri Oct 03 13:48:58 2014 +0200
@@ -46,8 +46,6 @@
  */
 public class GraphNodeGenerator {
 
-    @SuppressWarnings("unused") private static final boolean GENERATE_ASSERTIONS = false;
-
     private final GraphNodeProcessor env;
     private final Types types;
     private final Elements elements;
@@ -57,10 +55,9 @@
     private final TypeElement Successor;
 
     final TypeElement Node;
-    @SuppressWarnings("unused") private final TypeElement NodeList;
     private final TypeElement NodeInputList;
     private final TypeElement NodeSuccessorList;
-    @SuppressWarnings("unused") private final TypeElement Position;
+    private final TypeElement ValueNumberable;
 
     private final List<VariableElement> inputFields = new ArrayList<>();
     private final List<VariableElement> inputListFields = new ArrayList<>();
@@ -83,10 +80,9 @@
         this.OptionalInput = getTypeElement("com.oracle.graal.graph.Node.OptionalInput");
         this.Successor = getTypeElement("com.oracle.graal.graph.Node.Successor");
         this.Node = getTypeElement("com.oracle.graal.graph.Node");
-        this.NodeList = getTypeElement("com.oracle.graal.graph.NodeList");
         this.NodeInputList = getTypeElement("com.oracle.graal.graph.NodeInputList");
         this.NodeSuccessorList = getTypeElement("com.oracle.graal.graph.NodeSuccessorList");
-        this.Position = getTypeElement("com.oracle.graal.graph.Position");
+        this.ValueNumberable = getTypeElement("com.oracle.graal.graph.Node.ValueNumberable");
     }
 
     @SafeVarargs
@@ -243,6 +239,13 @@
                     if (isAssignableWithErasure(field, NodeSuccessorList)) {
                         throw new ElementException(field, "NodeSuccessorList field must be annotated with @" + Successor.getSimpleName());
                     }
+                    if (modifiers.contains(PUBLIC)) {
+                        if (!modifiers.contains(FINAL)) {
+                            throw new ElementException(field, "Data field must be final if public otherwise it must be protected");
+                        }
+                    } else if (!modifiers.contains(PROTECTED)) {
+                        throw new ElementException(field, "Data field must be protected");
+                    }
                     dataFields.add(field);
                 }
             }
@@ -311,6 +314,8 @@
         for (ExecutableElement constructor : ElementFilter.constructorsIn(node.getEnclosedElements())) {
             if (constructor.getModifiers().contains(PUBLIC)) {
                 throw new ElementException(constructor, "Node class constructor must not be public");
+            } else if (!constructor.getModifiers().contains(PROTECTED)) {
+                throw new ElementException(constructor, "Node class constructor must be protected");
             }
 
             checkFactoryMethodExists(node, constructor);
@@ -322,18 +327,19 @@
 
         if (!constructorsOnly) {
             DeclaredType generatedNode = (DeclaredType) getType(GeneratedNode.class);
-            CodeAnnotationMirror generatedNodeMirror = new CodeAnnotationMirror(generatedNode);
-            generatedNodeMirror.setElementValue(generatedNodeMirror.findExecutableElement("value"), new CodeAnnotationValue(node.asType()));
-            genClass.getAnnotationMirrors().add(generatedNodeMirror);
+            genClass.getImplements().add(generatedNode);
 
             scanFields(node);
 
             boolean hasInputs = !inputFields.isEmpty() || !inputListFields.isEmpty();
             boolean hasSuccessors = !successorFields.isEmpty() || !successorListFields.isEmpty();
 
-            if (hasInputs || hasSuccessors) {
-                createIsLeafNodeMethod();
+            boolean isLeaf = !(hasInputs || hasSuccessors);
+
+            if (isLeaf && isAssignableWithErasure(node, ValueNumberable)) {
+                createValueNumberLeafMethod(node);
             }
+            createDataEqualsMethod();
         }
         compilationUnit.add(genClass);
         return compilationUnit;
@@ -395,7 +401,6 @@
         genClassName = null;
     }
 
-    @SuppressWarnings("unused")
     private CodeVariableElement addParameter(CodeExecutableElement method, TypeMirror type, String name) {
         return addParameter(method, type, name, true);
     }
@@ -425,9 +430,95 @@
         }
     }
 
-    private void createIsLeafNodeMethod() {
-        CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(boolean.class), "isLeafNode");
-        method.createBuilder().startReturn().string("false").end();
+    private void createValueNumberLeafMethod(TypeElement node) {
+        CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(int.class), "valueNumberLeaf");
+        CodeTreeBuilder b = method.createBuilder();
+        b.startStatement().string("int number = " + node.hashCode()).end();
+        for (VariableElement f : dataFields) {
+            String fname = f.getSimpleName().toString();
+            switch (f.asType().getKind()) {
+                case BOOLEAN:
+                    b.startIf().string(fname).end().startBlock();
+                    b.startStatement().string("number += 7").end();
+                    b.end();
+                    break;
+                case BYTE:
+                case SHORT:
+                case CHAR:
+                case INT:
+                    b.startStatement().string("number += 13 * ", fname).end();
+                    break;
+                case FLOAT:
+                    b.startStatement().string("number += 17 * Float.floatToRawIntBits(", fname, ")").end();
+                    break;
+                case LONG:
+                    b.startStatement().string("number += 19 * ", fname + " ^ (", fname, " >>> 32)").end();
+                    break;
+                case DOUBLE:
+                    b.startStatement().string("long longValue = Double.doubleToRawLongBits(", fname, ")").end();
+                    b.startStatement().string("number += 23 * longValue ^ (longValue >>> 32)").end();
+                    break;
+                case ARRAY:
+                    if (((ArrayType) f.asType()).getComponentType().getKind().isPrimitive()) {
+                        b.startStatement().string("number += 31 * Arrays.hashCode(", fname, ")").end();
+                    } else {
+                        b.startStatement().string("number += 31 * Arrays.deepHashCode(", fname, ")").end();
+                    }
+                    break;
+                default:
+                    b.startIf().string(fname, " != null").end().startBlock();
+                    b.startStatement().string("number += 29 * ", fname + ".hashCode()").end();
+                    b.end();
+                    break;
+            }
+        }
+        b.end();
+        b.startReturn().string("number").end();
+        genClass.add(method);
+        checkOnlyInGenNode(method);
+    }
+
+    private void createDataEqualsMethod() {
+        CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(boolean.class), "dataEquals");
+        addParameter(method, Node.asType(), "other");
+        CodeTreeBuilder b = method.createBuilder();
+        if (!dataFields.isEmpty()) {
+            String other = "o";
+            b.declaration(genClassName, other, "(" + genClassName + ") other");
+
+            for (VariableElement f : dataFields) {
+                String fname = f.getSimpleName().toString();
+                switch (f.asType().getKind()) {
+                    case BOOLEAN:
+                    case BYTE:
+                    case SHORT:
+                    case CHAR:
+                    case INT:
+                    case FLOAT:
+                    case LONG:
+                    case DOUBLE:
+                        b.startIf().string(other, ".", fname, " != ", fname).end().startBlock();
+                        b.startStatement().string("return false").end();
+                        b.end();
+                        break;
+                    case ARRAY:
+                        if (((ArrayType) f.asType()).getComponentType().getKind().isPrimitive()) {
+                            b.startIf().string("!").type(getType(Arrays.class)).string(".equals(", other, ".", fname, ", ", fname, ")").end().startBlock();
+                        } else {
+                            b.startIf().string("!").type(getType(Arrays.class)).string(".deepEquals(", other, ".", fname, ", ", fname, ")").end().startBlock();
+                        }
+                        b.startStatement().string("return false").end();
+                        b.end();
+                        break;
+                    default:
+                        b.startIf().string("!").type(getType(Objects.class)).string(".equals(", other, ".", fname, ", ", fname, ")").end().startBlock();
+                        b.startStatement().string("return false").end();
+                        b.end();
+                        break;
+                }
+            }
+        }
+        b.startReturn().string("true").end();
         genClass.add(method);
         checkOnlyInGenNode(method);
     }
--- a/graal/com.oracle.graal.nodeinfo/src/com/oracle/graal/nodeinfo/GeneratedNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodeinfo/src/com/oracle/graal/nodeinfo/GeneratedNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -22,17 +22,27 @@
  */
 package com.oracle.graal.nodeinfo;
 
-import java.lang.annotation.*;
-
 /**
- * Denotes a Node subclass generated on the basis of a {@link NodeInfo} annotation on a Node type.
+ * Marker for a Node class generated on the basis of a {@link NodeInfo} annotation on its super
+ * class.
+ *
+ * Testing whether a node class is generated:
+ *
+ * <pre>
+ * Class<? extends Node> c = ...;
+ * if (GeneratedNode.class.isAssignableFrom(c)) { ... }
+ * </pre>
+ *
+ * Since a generated node class always subclasses the node from which it is generated:
+ *
+ * <pre>
+ * if (GeneratedNode.class.isAssignableFrom(c)) {
+ *     Class&lt;?&gt; original = c.getSuperclass();
+ * }
+ * </pre>
+ *
+ * Note: This used to be an annotation but was converted to an interface to avoid annotation parsing
+ * when creating a NodeClass instance.
  */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
-public @interface GeneratedNode {
-
-    /**
-     * The Node class from which the annotated type was generated.
-     */
-    Class<?> value();
+public interface GeneratedNode {
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -33,9 +33,9 @@
 public abstract class AbstractFixedGuardNode extends DeoptimizingFixedWithNextNode implements Simplifiable, GuardingNode {
 
     @Input(InputType.Condition) protected LogicNode condition;
-    private final DeoptimizationReason reason;
-    private final DeoptimizationAction action;
-    private boolean negated;
+    protected final DeoptimizationReason reason;
+    protected final DeoptimizationAction action;
+    protected boolean negated;
 
     public LogicNode condition() {
         return condition;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractLocalNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractLocalNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -29,7 +29,7 @@
 @NodeInfo
 public abstract class AbstractLocalNode extends FloatingNode {
 
-    private final int index;
+    protected final int index;
 
     public AbstractLocalNode(int index, Stamp stamp) {
         super(stamp);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -44,8 +44,8 @@
     }
 
     @Input protected NodeInputList<ValueNode> arguments;
-    private ResolvedJavaMethod targetMethod;
-    private InvokeKind invokeKind;
+    protected ResolvedJavaMethod targetMethod;
+    protected InvokeKind invokeKind;
 
     public CallTargetNode(ValueNode[] arguments, ResolvedJavaMethod targetMethod, InvokeKind invokeKind) {
         super(StampFactory.forVoid());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -33,7 +33,7 @@
 public class ConditionAnchorNode extends FixedWithNextNode implements Canonicalizable.Unary<Node>, Lowerable, GuardingNode {
 
     @Input(InputType.Condition) LogicNode condition;
-    private boolean negated;
+    protected boolean negated;
 
     public static ConditionAnchorNode create(LogicNode condition) {
         return USE_GENERATED_NODES ? new ConditionAnchorNodeGen(condition) : new ConditionAnchorNode(condition);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -43,7 +43,7 @@
 
     private static final DebugMetric ConstantNodes = Debug.metric("ConstantNodes");
 
-    private final Constant value;
+    protected final Constant value;
 
     private static ConstantNode createPrimitive(Constant value) {
         assert value.getKind() != Kind.Object;
@@ -91,10 +91,10 @@
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        if (gen.getLIRGeneratorTool().canInlineConstant(value) || onlyUsedInVirtualState()) {
+        if (onlyUsedInVirtualState()) {
             gen.setResult(this, value);
         } else {
-            gen.setResult(this, gen.getLIRGeneratorTool().emitMove(value));
+            gen.setResult(this, gen.getLIRGeneratorTool().emitLoadConstant(value));
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -29,10 +29,10 @@
 @NodeInfo(shortName = "Deopt", nameTemplate = "Deopt {p#reason/s}")
 public class DeoptimizeNode extends AbstractDeoptimizeNode implements Lowerable, LIRLowerable {
 
-    private final DeoptimizationAction action;
-    private final DeoptimizationReason reason;
-    private final int debugId;
-    private final Constant speculation;
+    protected final DeoptimizationAction action;
+    protected final DeoptimizationReason reason;
+    protected final int debugId;
+    protected final Constant speculation;
 
     public static DeoptimizeNode create(DeoptimizationAction action, DeoptimizationReason reason) {
         return USE_GENERATED_NODES ? new DeoptimizeNodeGen(action, reason) : new DeoptimizeNode(action, reason);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -30,6 +30,6 @@
         return USE_GENERATED_NODES ? new EndNodeGen() : new EndNode();
     }
 
-    EndNode() {
+    protected EndNode() {
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -39,7 +39,7 @@
         return USE_GENERATED_NODES ? new EntryMarkerNodeGen() : new EntryMarkerNode();
     }
 
-    EntryMarkerNode() {
+    protected EntryMarkerNode() {
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Fri Oct 03 13:48:58 2014 +0200
@@ -51,9 +51,9 @@
     /**
      * @see BytecodeFrame#rethrowException
      */
-    private boolean rethrowException;
+    protected boolean rethrowException;
 
-    private boolean duringCall;
+    protected boolean duringCall;
 
     @OptionalInput(value = InputType.State) FrameState outerFrameState;
 
@@ -71,7 +71,7 @@
      */
     public final int bci;
 
-    private final ResolvedJavaMethod method;
+    protected final ResolvedJavaMethod method;
 
     /**
      * Creates a {@code FrameState} with the given locals, stack expressions and locked monitors.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -45,10 +45,10 @@
 public class GuardNode extends FloatingAnchoredNode implements Canonicalizable, IterableNodeType, GuardingNode {
 
     @Input(InputType.Condition) protected LogicNode condition;
-    private final DeoptimizationReason reason;
-    private Constant speculation;
-    private DeoptimizationAction action;
-    private boolean negated;
+    protected final DeoptimizationReason reason;
+    protected Constant speculation;
+    protected DeoptimizationAction action;
+    protected boolean negated;
 
     public static GuardNode create(LogicNode condition, AnchoringNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated, Constant speculation) {
         return USE_GENERATED_NODES ? new GuardNodeGen(condition, anchor, reason, action, negated, speculation) : new GuardNode(condition, anchor, reason, action, negated, speculation);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -40,7 +40,7 @@
 public class GuardedValueNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, IterableNodeType, Canonicalizable, ValueProxy {
 
     @Input ValueNode object;
-    private final Stamp piStamp;
+    protected final Stamp piStamp;
 
     public static GuardedValueNode create(ValueNode object, GuardingNode guard, Stamp stamp) {
         return USE_GENERATED_NODES ? new GuardedValueNodeGen(object, guard, stamp) : new GuardedValueNode(object, guard, stamp);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -40,10 +40,10 @@
 
     @Input ValueNode object;
     @Input(InputType.Condition) LogicNode condition;
-    private final DeoptimizationReason reason;
-    private final DeoptimizationAction action;
-    private final Stamp piStamp;
-    private boolean negated;
+    protected final DeoptimizationReason reason;
+    protected final DeoptimizationAction action;
+    protected final Stamp piStamp;
+    protected boolean negated;
 
     public ValueNode object() {
         return object;
@@ -72,7 +72,7 @@
         return USE_GENERATED_NODES ? new GuardingPiNodeGen(object) : new GuardingPiNode(object);
     }
 
-    GuardingPiNode(ValueNode object) {
+    protected GuardingPiNode(ValueNode object) {
         this(object, object.graph().unique(IsNullNode.create(object)), true, DeoptimizationReason.NullCheckException, DeoptimizationAction.None, object.stamp().join(StampFactory.objectNonNull()));
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -52,7 +52,7 @@
     @Successor BeginNode trueSuccessor;
     @Successor BeginNode falseSuccessor;
     @Input(InputType.Condition) LogicNode condition;
-    private double trueSuccessorProbability;
+    protected double trueSuccessorProbability;
 
     public LogicNode condition() {
         return condition;
@@ -228,14 +228,15 @@
                 FixedWithNextNode falseNext = (FixedWithNextNode) falseSucc.next();
                 NodeClass nodeClass = trueNext.getNodeClass();
                 if (trueNext.getClass() == falseNext.getClass()) {
-                    if (nodeClass.getEdges(Inputs).areEqualIn(trueNext, falseNext) && nodeClass.valueEqual(trueNext, falseNext)) {
+                    if (nodeClass.getEdges(Inputs).areEqualIn(trueNext, falseNext) && trueNext.valueEquals(falseNext)) {
                         falseNext.replaceAtUsages(trueNext);
                         graph().removeFixed(falseNext);
                         GraphUtil.unlinkFixedNode(trueNext);
                         graph().addBeforeFixed(this, trueNext);
                         for (Node usage : trueNext.usages().snapshot()) {
                             if (usage.isAlive()) {
-                                if (usage.getNodeClass().valueNumberable() && !usage.isLeafNode()) {
+                                NodeClass usageNodeClass = usage.getNodeClass();
+                                if (usageNodeClass.valueNumberable() && !usageNodeClass.isLeafNode()) {
                                     Node newNode = graph().findDuplicate(usage);
                                     if (newNode != null) {
                                         usage.replaceAtUsages(newNode);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -28,7 +28,7 @@
 
 @NodeInfo
 public abstract class InfopointNode extends FixedWithNextNode {
-    private final InfopointReason reason;
+    protected final InfopointReason reason;
 
     public InfopointNode(InfopointReason reason) {
         super(StampFactory.forVoid());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -42,9 +42,9 @@
     @Input(InputType.Extension) CallTargetNode callTarget;
     @OptionalInput(InputType.State) FrameState stateDuring;
     @OptionalInput(InputType.Guard) GuardingNode guard;
-    private final int bci;
-    private boolean polymorphic;
-    private boolean useForInlining;
+    protected final int bci;
+    protected boolean polymorphic;
+    protected boolean useForInlining;
 
     /**
      * Constructs a new Invoke instruction.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -43,10 +43,10 @@
     @OptionalInput(InputType.State) FrameState stateDuring;
     @OptionalInput(InputType.State) FrameState stateAfter;
     @OptionalInput(InputType.Guard) GuardingNode guard;
-    private final int bci;
-    private boolean polymorphic;
-    private boolean useForInlining;
-    private double exceptionProbability;
+    protected final int bci;
+    protected boolean polymorphic;
+    protected boolean useForInlining;
+    protected double exceptionProbability;
 
     public static InvokeWithExceptionNode create(CallTargetNode callTarget, BeginNode exceptionEdge, int bci) {
         return USE_GENERATED_NODES ? new InvokeWithExceptionNodeGen(callTarget, exceptionEdge, bci) : new InvokeWithExceptionNode(callTarget, exceptionEdge, bci);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -29,7 +29,7 @@
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public class KillingBeginNode extends BeginNode implements MemoryCheckpoint.Single {
 
-    private LocationIdentity locationIdentity;
+    protected LocationIdentity locationIdentity;
 
     public static KillingBeginNode create(LocationIdentity locationIdentity) {
         return USE_GENERATED_NODES ? new KillingBeginNodeGen(locationIdentity) : new KillingBeginNode(locationIdentity);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicConstantNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicConstantNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -32,7 +32,7 @@
 @NodeInfo(nameTemplate = "{p#value}")
 public class LogicConstantNode extends LogicNode implements LIRLowerable {
 
-    public final boolean value;
+    protected final boolean value;
 
     public static LogicConstantNode create(boolean value) {
         return USE_GENERATED_NODES ? new LogicConstantNodeGen(value) : new LogicConstantNode(value);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -39,9 +39,9 @@
 @NodeInfo
 public class LoopBeginNode extends MergeNode implements IterableNodeType, LIRLowerable {
 
-    private double loopFrequency;
-    private int nextEndIndex;
-    private int unswitches;
+    protected double loopFrequency;
+    protected int nextEndIndex;
+    protected int unswitches;
     @OptionalInput(InputType.Guard) GuardingNode overflowGuard;
 
     public static LoopBeginNode create() {
@@ -283,7 +283,7 @@
                 if (phi != null) {
                     nextPhi: for (int otherPhiIndex = phiIndex + 1; otherPhiIndex < phiCount; otherPhiIndex++) {
                         PhiNode otherPhi = phis[otherPhiIndex];
-                        if (otherPhi == null || phi.getNodeClass() != otherPhi.getNodeClass() || !phi.getNodeClass().valueEqual(phi, otherPhi)) {
+                        if (otherPhi == null || phi.getNodeClass() != otherPhi.getNodeClass() || !phi.valueEquals(otherPhi)) {
                             continue nextPhi;
                         }
                         if (selfIncrement[phiIndex] == null) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -32,8 +32,8 @@
 public class LoopEndNode extends AbstractEndNode {
 
     @Input(InputType.Association) LoopBeginNode loopBegin;
-    private boolean canSafepoint;
-    private int endIndex;
+    protected boolean canSafepoint;
+    protected int endIndex;
 
     public static LoopEndNode create(LoopBeginNode begin) {
         return USE_GENERATED_NODES ? new LoopEndNodeGen(begin) : new LoopEndNode(begin);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoweredCallTargetNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoweredCallTargetNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -32,9 +32,9 @@
 @NodeInfo
 public abstract class LoweredCallTargetNode extends CallTargetNode {
 
-    private final Stamp returnStamp;
-    private final JavaType[] signature;
-    private final CallingConvention.Type callType;
+    protected final Stamp returnStamp;
+    protected final JavaType[] signature;
+    protected final CallingConvention.Type callType;
 
     public LoweredCallTargetNode(List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) {
         super(arguments, target, invokeKind);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -37,7 +37,7 @@
 @NodeInfo(allowedUsageTypes = {InputType.Extension})
 public class MemoryMapNode extends FloatingNode implements MemoryMap, LIRLowerable {
 
-    private final List<LocationIdentity> locationIdentities;
+    protected final List<LocationIdentity> locationIdentities;
     @Input(InputType.Memory) NodeInputList<ValueNode> nodes;
 
     private boolean checkOrder(Map<LocationIdentity, MemoryNode> mmap) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -35,7 +35,7 @@
 public class MemoryPhiNode extends PhiNode implements MemoryNode {
 
     @Input(InputType.Memory) NodeInputList<ValueNode> values;
-    private final LocationIdentity locationIdentity;
+    protected final LocationIdentity locationIdentity;
 
     public static MemoryPhiNode create(MergeNode merge, LocationIdentity locationIdentity) {
         return USE_GENERATED_NODES ? new MemoryPhiNodeGen(merge, locationIdentity) : new MemoryPhiNode(merge, locationIdentity);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -45,7 +45,7 @@
 public class PiNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, IterableNodeType, Canonicalizable, ValueProxy {
 
     @Input ValueNode object;
-    private final Stamp piStamp;
+    protected final Stamp piStamp;
 
     public ValueNode object() {
         return object;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ShortCircuitOrNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ShortCircuitOrNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -31,9 +31,9 @@
 
     @Input(InputType.Condition) LogicNode x;
     @Input(InputType.Condition) LogicNode y;
-    private boolean xNegated;
-    private boolean yNegated;
-    private double shortCircuitProbability;
+    protected boolean xNegated;
+    protected boolean yNegated;
+    protected double shortCircuitProbability;
 
     public static ShortCircuitOrNode create(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, double shortCircuitProbability) {
         return USE_GENERATED_NODES ? new ShortCircuitOrNodeGen(x, xNegated, y, yNegated, shortCircuitProbability) : new ShortCircuitOrNode(x, xNegated, y, yNegated, shortCircuitProbability);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimpleInfopointNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimpleInfopointNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -30,7 +30,7 @@
 
 @NodeInfo
 public class SimpleInfopointNode extends InfopointNode implements LIRLowerable, IterableNodeType, Simplifiable {
-    private BytecodePosition position;
+    protected BytecodePosition position;
 
     public static SimpleInfopointNode create(InfopointReason reason, BytecodePosition position) {
         return USE_GENERATED_NODES ? new SimpleInfopointNodeGen(reason, position) : new SimpleInfopointNode(reason, position);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -39,9 +39,9 @@
 @NodeInfo
 public class TypeProfileProxyNode extends UnaryNode implements IterableNodeType, ValueProxy {
 
-    private final JavaTypeProfile profile;
-    private transient ResolvedJavaType lastCheckedType;
-    private transient JavaTypeProfile lastCheckedProfile;
+    protected final JavaTypeProfile profile;
+    protected transient ResolvedJavaType lastCheckedType;
+    protected transient JavaTypeProfile lastCheckedProfile;
 
     public static ValueNode proxify(ValueNode object, JavaTypeProfile profile) {
         if (StampTool.isExactType(object)) {
@@ -62,7 +62,7 @@
         return USE_GENERATED_NODES ? new TypeProfileProxyNodeGen(object, profile) : new TypeProfileProxyNode(object, profile);
     }
 
-    TypeProfileProxyNode(ValueNode value, JavaTypeProfile profile) {
+    protected TypeProfileProxyNode(ValueNode value, JavaTypeProfile profile) {
         super(value.stamp(), value);
         this.profile = profile;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -38,7 +38,7 @@
      * The kind of this value. This is {@link Kind#Void} for instructions that produce no value.
      * This kind is guaranteed to be a {@linkplain Kind#getStackKind() stack kind}.
      */
-    private Stamp stamp;
+    protected Stamp stamp;
 
     public ValueNode(Stamp stamp) {
         this.stamp = stamp;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AddNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AddNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -95,9 +95,9 @@
         assert op1 != null : getX() + ", this=" + this;
         Value op2 = builder.operand(getY());
         if (!getY().isConstant() && !BinaryArithmeticNode.livesLonger(this, getY(), builder)) {
-            Value op = op1;
+            Value tmp = op1;
             op1 = op2;
-            op2 = op;
+            op2 = tmp;
         }
         builder.setResult(this, gen.emitAdd(op1, op2));
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -39,7 +39,7 @@
         return USE_GENERATED_NODES ? new AndNodeGen(x, y) : new AndNode(x, y);
     }
 
-    AndNode(ValueNode x, ValueNode y) {
+    protected AndNode(ValueNode x, ValueNode y) {
         super(ArithmeticOpTable.forStamp(x.stamp()).getAnd(), x, y);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -35,7 +35,7 @@
 @NodeInfo
 public abstract class BinaryArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
 
-    private final BinaryOp op;
+    protected final BinaryOp op;
 
     public BinaryArithmeticNode(BinaryOp op, ValueNode x, ValueNode y) {
         super(op.foldStamp(x.stamp(), y.stamp()), x, y);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -131,7 +131,7 @@
         return USE_GENERATED_NODES ? new ConditionalNodeGen(graph, condition, x, y) : new ConditionalNode(graph, condition, x, y);
     }
 
-    ConditionalNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y) {
+    protected ConditionalNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y) {
         this(createCompareNode(graph, condition, x, y));
     }
 
@@ -139,7 +139,7 @@
         return USE_GENERATED_NODES ? new ConditionalNodeGen(type, object) : new ConditionalNode(type, object);
     }
 
-    ConditionalNode(ValueNode type, ValueNode object) {
+    protected ConditionalNode(ValueNode type, ValueNode object) {
         this(type.graph().unique(InstanceOfDynamicNode.create(type, object)));
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -39,7 +39,7 @@
 @NodeInfo
 public class FloatConvertNode extends ConvertNode implements Lowerable, ArithmeticLIRLowerable {
 
-    private final FloatConvert op;
+    protected final FloatConvert op;
 
     public static FloatConvertNode create(FloatConvert op, ValueNode input) {
         return USE_GENERATED_NODES ? new FloatConvertNodeGen(op, input) : new FloatConvertNode(op, input);
@@ -83,10 +83,12 @@
                 return StampFactory.forKind(Kind.Long);
             case I2F:
             case L2F:
+                return StampFactory.forFloat(Kind.Float, ((IntegerStamp) input.stamp()).lowerBound(), ((IntegerStamp) input.stamp()).upperBound(), true);
             case D2F:
                 return StampFactory.forKind(Kind.Float);
             case I2D:
             case L2D:
+                return StampFactory.forFloat(Kind.Double, ((IntegerStamp) input.stamp()).lowerBound(), ((IntegerStamp) input.stamp()).upperBound(), true);
             case F2D:
                 return StampFactory.forKind(Kind.Double);
             default:
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -33,7 +33,7 @@
 @NodeInfo(shortName = "<")
 public class FloatLessThanNode extends CompareNode {
 
-    private final boolean unorderedIsTrue;
+    protected final boolean unorderedIsTrue;
 
     /**
      * Constructs a new floating point comparison node.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -33,7 +33,7 @@
 @NodeInfo
 public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable {
 
-    private final int resultBits;
+    protected final int resultBits;
 
     protected IntegerConvertNode(Stamp stamp, ValueNode input, int resultBits) {
         super(stamp, input);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -99,7 +99,7 @@
 
         if (next() instanceof IntegerDivNode) {
             NodeClass nodeClass = getNodeClass();
-            if (next().getClass() == this.getClass() && nodeClass.getEdges(Inputs).areEqualIn(this, next()) && nodeClass.valueEqual(this, next())) {
+            if (next().getClass() == this.getClass() && nodeClass.getEdges(Inputs).areEqualIn(this, next()) && valueEquals(next())) {
                 return next();
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/MulNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/MulNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -103,9 +103,9 @@
         Value op1 = builder.operand(getX());
         Value op2 = builder.operand(getY());
         if (!getY().isConstant() && !BinaryArithmeticNode.livesLonger(this, getY(), builder)) {
-            Value op = op1;
+            Value tmp = op1;
             op1 = op2;
-            op2 = op;
+            op2 = tmp;
         }
         builder.setResult(this, gen.emitMul(op1, op2));
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -44,7 +44,7 @@
         return USE_GENERATED_NODES ? new NegateNodeGen(value) : new NegateNode(value);
     }
 
-    NegateNode(ValueNode value) {
+    protected NegateNode(ValueNode value) {
         super(ArithmeticOpTable.forStamp(value.stamp()).getNeg(), value);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -37,7 +37,7 @@
 @NodeInfo
 public class NormalizeCompareNode extends BinaryNode implements Lowerable {
 
-    public final boolean isUnorderedLess;
+    protected final boolean isUnorderedLess;
 
     /**
      * Creates a new compare operation.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -39,7 +39,7 @@
         return USE_GENERATED_NODES ? new OrNodeGen(x, y) : new OrNode(x, y);
     }
 
-    OrNode(ValueNode x, ValueNode y) {
+    protected OrNode(ValueNode x, ValueNode y) {
         super(ArithmeticOpTable.forStamp(x.stamp()).getOr(), x, y);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -43,7 +43,7 @@
         return USE_GENERATED_NODES ? new ReinterpretNodeGen(to, value) : new ReinterpretNode(to, value);
     }
 
-    ReinterpretNode(Kind to, ValueNode value) {
+    protected ReinterpretNode(Kind to, ValueNode value) {
         this(StampFactory.forKind(to), value);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnaryArithmeticNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnaryArithmeticNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -32,7 +32,7 @@
 @NodeInfo
 public abstract class UnaryArithmeticNode extends UnaryNode implements ArithmeticLIRLowerable {
 
-    private final UnaryOp op;
+    protected final UnaryOp op;
 
     protected UnaryArithmeticNode(UnaryOp op, ValueNode value) {
         super(op.foldStamp(value.stamp()), value);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -40,15 +40,15 @@
 
     @Input ValueNode increment;
 
-    private final String name;
-    private final String group;
-    private final boolean withContext;
+    protected final String name;
+    protected final String group;
+    protected final boolean withContext;
 
     public static DynamicCounterNode create(String name, String group, ValueNode increment, boolean withContext) {
         return USE_GENERATED_NODES ? new DynamicCounterNodeGen(name, group, increment, withContext) : new DynamicCounterNode(name, group, increment, withContext);
     }
 
-    DynamicCounterNode(String name, String group, ValueNode increment, boolean withContext) {
+    protected DynamicCounterNode(String name, String group, ValueNode increment, boolean withContext) {
         super(StampFactory.forVoid());
         this.name = name;
         this.group = group;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/WeakCounterNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/WeakCounterNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -42,7 +42,7 @@
         return USE_GENERATED_NODES ? new WeakCounterNodeGen(group, name, increment, addContext, checkedValue) : new WeakCounterNode(group, name, increment, addContext, checkedValue);
     }
 
-    WeakCounterNode(String group, String name, ValueNode increment, boolean addContext, ValueNode checkedValue) {
+    protected WeakCounterNode(String group, String name, ValueNode increment, boolean addContext, ValueNode checkedValue) {
         super(group, name, increment, addContext);
         this.checkedValue = checkedValue;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractWriteNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractWriteNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -35,7 +35,7 @@
     @OptionalInput(InputType.State) FrameState stateAfter;
     @OptionalInput(InputType.Memory) Node lastLocationAccess;
 
-    private final boolean initialization;
+    protected final boolean initialization;
 
     public FrameState stateAfter() {
         return stateAfter;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -59,7 +59,7 @@
         return USE_GENERATED_NODES ? new AddLocationNodeGen(x, y) : new AddLocationNode(x, y);
     }
 
-    AddLocationNode(ValueNode x, ValueNode y) {
+    protected AddLocationNode(ValueNode x, ValueNode y) {
         super(StampFactory.forVoid());
         this.x = x;
         this.y = y;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -42,13 +42,13 @@
 @NodeInfo
 public class BoxNode extends UnaryNode implements VirtualizableAllocation, Lowerable {
 
-    private final Kind boxingKind;
+    protected final Kind boxingKind;
 
     public static BoxNode create(ValueNode value, ResolvedJavaType resultType, Kind boxingKind) {
         return USE_GENERATED_NODES ? new BoxNodeGen(value, resultType, boxingKind) : new BoxNode(value, resultType, boxingKind);
     }
 
-    BoxNode(ValueNode value, ResolvedJavaType resultType, Kind boxingKind) {
+    protected BoxNode(ValueNode value, ResolvedJavaType resultType, Kind boxingKind) {
         super(StampFactory.exactNonNull(resultType), value);
         this.boxingKind = boxingKind;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BranchProbabilityNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BranchProbabilityNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -57,7 +57,7 @@
         return USE_GENERATED_NODES ? new BranchProbabilityNodeGen(probability, condition) : new BranchProbabilityNode(probability, condition);
     }
 
-    BranchProbabilityNode(ValueNode probability, ValueNode condition) {
+    protected BranchProbabilityNode(ValueNode probability, ValueNode condition) {
         super(condition.stamp());
         this.probability = probability;
         this.condition = condition;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -36,14 +36,14 @@
 @NodeInfo
 public class BytecodeExceptionNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
 
-    private final Class<? extends Throwable> exceptionClass;
+    protected final Class<? extends Throwable> exceptionClass;
     @Input NodeInputList<ValueNode> arguments;
 
     public static BytecodeExceptionNode create(MetaAccessProvider metaAccess, Class<? extends Throwable> exceptionClass, ValueNode... arguments) {
         return USE_GENERATED_NODES ? new BytecodeExceptionNodeGen(metaAccess, exceptionClass, arguments) : new BytecodeExceptionNode(metaAccess, exceptionClass, arguments);
     }
 
-    BytecodeExceptionNode(MetaAccessProvider metaAccess, Class<? extends Throwable> exceptionClass, ValueNode... arguments) {
+    protected BytecodeExceptionNode(MetaAccessProvider metaAccess, Class<? extends Throwable> exceptionClass, ValueNode... arguments) {
         super(StampFactory.exactNonNull(metaAccess.lookupJavaType(exceptionClass)));
         this.exceptionClass = exceptionClass;
         this.arguments = new NodeInputList<>(this, arguments);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -47,7 +47,7 @@
         return USE_GENERATED_NODES ? new ComputeAddressNodeGen(object, location, stamp) : new ComputeAddressNode(object, location, stamp);
     }
 
-    ComputeAddressNode(ValueNode object, ValueNode location, Stamp stamp) {
+    protected ComputeAddressNode(ValueNode object, ValueNode location, Stamp stamp) {
         super(stamp);
         this.object = object;
         this.location = location;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -36,9 +36,9 @@
 @NodeInfo(nameTemplate = "Loc {p#locationIdentity/s}")
 public class ConstantLocationNode extends LocationNode {
 
-    private final Kind valueKind;
-    private final LocationIdentity locationIdentity;
-    private final long displacement;
+    protected final Kind valueKind;
+    protected final LocationIdentity locationIdentity;
+    protected final long displacement;
 
     public static ConstantLocationNode create(LocationIdentity identity, Kind kind, long displacement, Graph graph) {
         return graph.unique(ConstantLocationNode.create(identity, kind, displacement));
@@ -48,7 +48,7 @@
         return USE_GENERATED_NODES ? new ConstantLocationNodeGen(identity, kind, displacement) : new ConstantLocationNode(identity, kind, displacement);
     }
 
-    ConstantLocationNode(LocationIdentity identity, Kind kind, long displacement) {
+    protected ConstantLocationNode(LocationIdentity identity, Kind kind, long displacement) {
         super(StampFactory.forVoid());
         assert kind != Kind.Illegal && kind != Kind.Void;
         this.valueKind = kind;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -36,8 +36,8 @@
     @OptionalInput(InputType.Guard) protected GuardingNode guard;
     @Input protected ValueNode object;
     @Input(InputType.Association) protected ValueNode location;
-    private boolean nullCheck;
-    private BarrierType barrierType;
+    protected boolean nullCheck;
+    protected BarrierType barrierType;
 
     public ValueNode object() {
         return object;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedValueAnchorNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedValueAnchorNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -40,7 +40,7 @@
         return USE_GENERATED_NODES ? new FixedValueAnchorNodeGen(object) : new FixedValueAnchorNode(object);
     }
 
-    FixedValueAnchorNode(ValueNode object) {
+    protected FixedValueAnchorNode(ValueNode object) {
         super(StampFactory.forNodeIntrinsic());
         this.object = object;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -32,7 +32,7 @@
 
     @Input ValueNode object;
     @Input(InputType.Association) LocationNode location;
-    private BarrierType barrierType;
+    protected BarrierType barrierType;
 
     public ValueNode object() {
         return object;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -43,7 +43,7 @@
         return USE_GENERATED_NODES ? new FloatingReadNodeGen(object, location, lastLocationAccess, stamp) : new FloatingReadNode(object, location, lastLocationAccess, stamp);
     }
 
-    FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp) {
+    protected FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp) {
         this(object, location, lastLocationAccess, stamp, null, BarrierType.NONE);
     }
 
@@ -51,7 +51,7 @@
         return USE_GENERATED_NODES ? new FloatingReadNodeGen(object, location, lastLocationAccess, stamp, guard) : new FloatingReadNode(object, location, lastLocationAccess, stamp, guard);
     }
 
-    FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard) {
+    protected FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard) {
         this(object, location, lastLocationAccess, stamp, guard, BarrierType.NONE);
     }
 
@@ -60,7 +60,7 @@
                         guard, barrierType);
     }
 
-    FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
+    protected FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
         super(object, location, stamp, guard, barrierType);
         this.lastLocationAccess = lastLocationAccess;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -40,9 +40,9 @@
 
     @Input protected NodeInputList<ValueNode> arguments;
     @OptionalInput(InputType.State) protected FrameState stateDuring;
-    private final ForeignCallsProvider foreignCalls;
+    protected final ForeignCallsProvider foreignCalls;
 
-    private final ForeignCallDescriptor descriptor;
+    protected final ForeignCallDescriptor descriptor;
 
     public static ForeignCallNode create(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
         return USE_GENERATED_NODES ? new ForeignCallNodeGen(foreignCalls, descriptor, arguments) : new ForeignCallNode(foreignCalls, descriptor, arguments);
@@ -59,7 +59,7 @@
         return USE_GENERATED_NODES ? new ForeignCallNodeGen(foreignCalls, descriptor, arguments) : new ForeignCallNode(foreignCalls, descriptor, arguments);
     }
 
-    ForeignCallNode(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, List<ValueNode> arguments) {
+    protected ForeignCallNode(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, List<ValueNode> arguments) {
         this(foreignCalls, descriptor, StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())), arguments);
     }
 
@@ -67,7 +67,7 @@
         return USE_GENERATED_NODES ? new ForeignCallNodeGen(foreignCalls, descriptor, stamp, arguments) : new ForeignCallNode(foreignCalls, descriptor, stamp, arguments);
     }
 
-    ForeignCallNode(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp, List<ValueNode> arguments) {
+    protected ForeignCallNode(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp, List<ValueNode> arguments) {
         super(stamp);
         this.arguments = new NodeInputList<>(this, arguments);
         this.descriptor = descriptor;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -41,11 +41,11 @@
 @NodeInfo(nameTemplate = "IdxLoc {p#locationIdentity/s}")
 public class IndexedLocationNode extends LocationNode implements Canonicalizable {
 
-    private final Kind valueKind;
-    private final LocationIdentity locationIdentity;
-    private final long displacement;
+    protected final Kind valueKind;
+    protected final LocationIdentity locationIdentity;
+    protected final long displacement;
     @Input ValueNode index;
-    private final int indexScaling;
+    protected final int indexScaling;
 
     /**
      * Gets the index or offset of this location.
@@ -73,7 +73,7 @@
         return USE_GENERATED_NODES ? new IndexedLocationNodeGen(identity, kind, displacement, index, indexScaling) : new IndexedLocationNode(identity, kind, displacement, index, indexScaling);
     }
 
-    IndexedLocationNode(LocationIdentity identity, Kind kind, long displacement, ValueNode index, int indexScaling) {
+    protected IndexedLocationNode(LocationIdentity identity, Kind kind, long displacement, ValueNode index, int indexScaling) {
         super(StampFactory.forVoid());
         assert index != null;
         assert indexScaling != 0;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -39,7 +39,7 @@
 @NodeInfo
 public class IntegerSwitchNode extends SwitchNode implements LIRLowerable, Simplifiable {
 
-    private final int[] keys;
+    protected final int[] keys;
 
     /**
      * Constructs a integer switch instruction. The keyProbabilities and keySuccessors array contain
@@ -56,7 +56,7 @@
                         keySuccessors);
     }
 
-    IntegerSwitchNode(ValueNode value, BeginNode[] successors, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
+    protected IntegerSwitchNode(ValueNode value, BeginNode[] successors, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
         super(value, successors, keySuccessors, keyProbabilities);
         assert keySuccessors.length == keys.length + 1;
         assert keySuccessors.length == keyProbabilities.length;
@@ -87,7 +87,7 @@
                         keySuccessors);
     }
 
-    IntegerSwitchNode(ValueNode value, int successorCount, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
+    protected IntegerSwitchNode(ValueNode value, int successorCount, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
         this(value, new BeginNode[successorCount], keys, keyProbabilities, keySuccessors);
     }
 
@@ -148,11 +148,11 @@
             tool.addToWorkList(blockSuccessor(survivingEdge));
             graph().removeSplit(this, blockSuccessor(survivingEdge));
         } else if (value().stamp() instanceof IntegerStamp) {
-            IntegerStamp stamp = (IntegerStamp) value().stamp();
-            if (!stamp.isUnrestricted()) {
+            IntegerStamp integerStamp = (IntegerStamp) value().stamp();
+            if (!integerStamp.isUnrestricted()) {
                 int validKeys = 0;
                 for (int i = 0; i < keyCount(); i++) {
-                    if (stamp.contains(keys[i])) {
+                    if (integerStamp.contains(keys[i])) {
                         validKeys++;
                     }
                 }
@@ -167,7 +167,7 @@
                     double totalProbability = 0;
                     int current = 0;
                     for (int i = 0; i < keyCount() + 1; i++) {
-                        if (i == keyCount() || stamp.contains(keys[i])) {
+                        if (i == keyCount() || integerStamp.contains(keys[i])) {
                             int index = newSuccessors.indexOf(keySuccessor(i));
                             if (index == -1) {
                                 index = newSuccessors.size();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaReadNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaReadNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -34,13 +34,13 @@
 @NodeInfo
 public class JavaReadNode extends FixedAccessNode implements Lowerable, GuardingNode {
 
-    private final boolean compressible;
+    protected final boolean compressible;
 
     public static JavaReadNode create(ValueNode object, LocationNode location, BarrierType barrierType, boolean compressible) {
         return USE_GENERATED_NODES ? new JavaReadNodeGen(object, location, barrierType, compressible) : new JavaReadNode(object, location, barrierType, compressible);
     }
 
-    JavaReadNode(ValueNode object, LocationNode location, BarrierType barrierType, boolean compressible) {
+    protected JavaReadNode(ValueNode object, LocationNode location, BarrierType barrierType, boolean compressible) {
         super(object, location, StampFactory.forKind(location.getValueKind()), barrierType);
         this.compressible = compressible;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaWriteNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaWriteNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -33,14 +33,14 @@
 @NodeInfo
 public class JavaWriteNode extends AbstractWriteNode implements Lowerable, StateSplit, MemoryAccess, MemoryCheckpoint.Single {
 
-    private final boolean compressible;
+    protected final boolean compressible;
 
     public static JavaWriteNode create(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean compressible, boolean initialization) {
         return USE_GENERATED_NODES ? new JavaWriteNodeGen(object, value, location, barrierType, compressible, initialization) : new JavaWriteNode(object, value, location, barrierType, compressible,
                         initialization);
     }
 
-    JavaWriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean compressible, boolean initialization) {
+    protected JavaWriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean compressible, boolean initialization) {
         super(object, value, location, barrierType, initialization);
         this.compressible = compressible;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -47,7 +47,7 @@
         return USE_GENERATED_NODES ? new LoadHubNodeGen(value, kind) : new LoadHubNode(value, kind);
     }
 
-    LoadHubNode(ValueNode value, Kind kind) {
+    protected LoadHubNode(ValueNode value, Kind kind) {
         super(getKind(kind), null);
         this.value = value;
     }
@@ -56,7 +56,7 @@
         return USE_GENERATED_NODES ? new LoadHubNodeGen(value, kind, guard) : new LoadHubNode(value, kind, guard);
     }
 
-    LoadHubNode(ValueNode value, Kind kind, ValueNode guard) {
+    protected LoadHubNode(ValueNode value, Kind kind, ValueNode guard) {
         super(getKind(kind), (GuardingNode) guard);
         assert value != guard;
         this.value = value;
@@ -75,15 +75,15 @@
     public ValueNode canonical(CanonicalizerTool tool) {
         MetaAccessProvider metaAccess = tool.getMetaAccess();
         if (metaAccess != null && getValue().stamp() instanceof ObjectStamp) {
-            ObjectStamp stamp = (ObjectStamp) getValue().stamp();
+            ObjectStamp objectStamp = (ObjectStamp) getValue().stamp();
 
             ResolvedJavaType exactType;
-            if (stamp.isExactType()) {
-                exactType = stamp.type();
-            } else if (stamp.type() != null && tool.assumptions().useOptimisticAssumptions()) {
-                exactType = stamp.type().findUniqueConcreteSubtype();
+            if (objectStamp.isExactType()) {
+                exactType = objectStamp.type();
+            } else if (objectStamp.type() != null && tool.assumptions().useOptimisticAssumptions()) {
+                exactType = objectStamp.type().findUniqueConcreteSubtype();
                 if (exactType != null) {
-                    tool.assumptions().recordConcreteSubtype(stamp.type(), exactType);
+                    tool.assumptions().recordConcreteSubtype(objectStamp.type(), exactType);
                 }
             } else {
                 exactType = null;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -38,8 +38,8 @@
 public class LoadMethodNode extends FixedWithNextNode implements Lowerable, Canonicalizable {
 
     @Input ValueNode hub;
-    private final ResolvedJavaMethod method;
-    private final ResolvedJavaType receiverType;
+    protected final ResolvedJavaMethod method;
+    protected final ResolvedJavaType receiverType;
 
     public ValueNode getHub() {
         return hub;
@@ -49,7 +49,7 @@
         return USE_GENERATED_NODES ? new LoadMethodNodeGen(method, receiverType, hub, kind) : new LoadMethodNode(method, receiverType, hub, kind);
     }
 
-    LoadMethodNode(ResolvedJavaMethod method, ResolvedJavaType receiverType, ValueNode hub, Kind kind) {
+    protected LoadMethodNode(ResolvedJavaMethod method, ResolvedJavaType receiverType, ValueNode hub, Kind kind) {
         super(kind == Kind.Object ? StampFactory.objectNonNull() : StampFactory.forKind(kind));
         this.receiverType = receiverType;
         this.hub = hub;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -42,7 +42,7 @@
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public class MembarNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
 
-    private final int barriers;
+    protected final int barriers;
 
     /**
      * @param barriers a mask of the barrier constants defined in {@link MemoryBarriers}
@@ -51,7 +51,7 @@
         return USE_GENERATED_NODES ? new MembarNodeGen(barriers) : new MembarNode(barriers);
     }
 
-    MembarNode(int barriers) {
+    protected MembarNode(int barriers) {
         super(StampFactory.forVoid());
         this.barriers = barriers;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -36,7 +36,7 @@
         return USE_GENERATED_NODES ? new NullCheckNodeGen(object) : new NullCheckNode(object);
     }
 
-    NullCheckNode(ValueNode object) {
+    protected NullCheckNode(ValueNode object) {
         super(StampFactory.forVoid());
         this.object = object;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRLocalNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRLocalNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -34,7 +34,7 @@
         return USE_GENERATED_NODES ? new OSRLocalNodeGen(index, stamp) : new OSRLocalNode(index, stamp);
     }
 
-    OSRLocalNode(int index, Stamp stamp) {
+    protected OSRLocalNode(int index, Stamp stamp) {
         super(index, stamp);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRStartNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRStartNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -33,7 +33,7 @@
         return USE_GENERATED_NODES ? new OSRStartNodeGen() : new OSRStartNode();
     }
 
-    OSRStartNode() {
+    protected OSRStartNode() {
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -42,7 +42,7 @@
         return USE_GENERATED_NODES ? new ReadNodeGen(object, location, stamp, barrierType) : new ReadNode(object, location, stamp, barrierType);
     }
 
-    ReadNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) {
+    protected ReadNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) {
         super(object, location, stamp, null, barrierType);
     }
 
@@ -50,7 +50,7 @@
         return USE_GENERATED_NODES ? new ReadNodeGen(object, location, stamp, guard, barrierType) : new ReadNode(object, location, stamp, guard, barrierType);
     }
 
-    ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
+    protected ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
         super(object, location, stamp, guard, barrierType);
     }
 
@@ -59,7 +59,7 @@
                         stateBefore);
     }
 
-    ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, FrameState stateBefore) {
+    protected ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, FrameState stateBefore) {
         super(object, location, stamp, guard, barrierType, nullCheck, stateBefore);
     }
 
@@ -67,7 +67,7 @@
         return USE_GENERATED_NODES ? new ReadNodeGen(object, location, guard, barrierType) : new ReadNode(object, location, guard, barrierType);
     }
 
-    ReadNode(ValueNode object, ValueNode location, ValueNode guard, BarrierType barrierType) {
+    protected ReadNode(ValueNode object, ValueNode location, ValueNode guard, BarrierType barrierType) {
         /*
          * Used by node intrinsics. Really, you can trust me on that! Since the initial value for
          * location is a parameter, i.e., a ParameterNode, the constructor cannot use the declared
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/StoreHubNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/StoreHubNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -45,7 +45,7 @@
         return USE_GENERATED_NODES ? new StoreHubNodeGen(object, value) : new StoreHubNode(object, value);
     }
 
-    StoreHubNode(ValueNode object, ValueNode value) {
+    protected StoreHubNode(ValueNode object, ValueNode value) {
         super(StampFactory.forVoid());
         this.value = value;
         this.object = object;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -41,8 +41,8 @@
     @Input protected ValueNode value;
 
     // do not change the contents of these arrays:
-    private final double[] keyProbabilities;
-    private final int[] keySuccessors;
+    protected final double[] keyProbabilities;
+    protected final int[] keySuccessors;
 
     /**
      * Constructs a new Switch.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -33,13 +33,13 @@
 @NodeInfo
 public class UnboxNode extends UnaryNode implements Virtualizable, Lowerable {
 
-    private final Kind boxingKind;
+    protected final Kind boxingKind;
 
     public static UnboxNode create(ValueNode value, Kind boxingKind) {
         return USE_GENERATED_NODES ? new UnboxNodeGen(value, boxingKind) : new UnboxNode(value, boxingKind);
     }
 
-    UnboxNode(ValueNode value, Kind boxingKind) {
+    protected UnboxNode(ValueNode value, Kind boxingKind) {
         super(StampFactory.forKind(boxingKind.getStackKind()), value);
         this.boxingKind = boxingKind;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -35,8 +35,8 @@
 
     @Input ValueNode object;
     @Input ValueNode offset;
-    private final Kind accessKind;
-    private final LocationIdentity locationIdentity;
+    protected final Kind accessKind;
+    protected final LocationIdentity locationIdentity;
 
     public UnsafeAccessNode(Stamp stamp, ValueNode object, ValueNode offset, Kind accessKind, LocationIdentity locationIdentity) {
         super(stamp);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -46,7 +46,7 @@
         return USE_GENERATED_NODES ? new UnsafeCastNodeGen(object, stamp) : new UnsafeCastNode(object, stamp);
     }
 
-    UnsafeCastNode(ValueNode object, Stamp stamp) {
+    protected UnsafeCastNode(ValueNode object, Stamp stamp) {
         super(stamp);
         this.object = object;
     }
@@ -55,7 +55,7 @@
         return USE_GENERATED_NODES ? new UnsafeCastNodeGen(object, stamp, anchor) : new UnsafeCastNode(object, stamp, anchor);
     }
 
-    UnsafeCastNode(ValueNode object, Stamp stamp, ValueNode anchor) {
+    protected UnsafeCastNode(ValueNode object, Stamp stamp, ValueNode anchor) {
         super(stamp, (GuardingNode) anchor);
         this.object = object;
     }
@@ -64,7 +64,7 @@
         return USE_GENERATED_NODES ? new UnsafeCastNodeGen(object, toType, exactType, nonNull) : new UnsafeCastNode(object, toType, exactType, nonNull);
     }
 
-    UnsafeCastNode(ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) {
+    protected UnsafeCastNode(ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) {
         this(object, toType.getKind() == Kind.Object ? StampFactory.object(toType, exactType, nonNull || StampTool.isObjectNonNull(object.stamp()), true) : StampFactory.forKind(toType.getKind()));
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -43,7 +43,7 @@
         return USE_GENERATED_NODES ? new UnsafeLoadNodeGen(object, offset, accessKind, locationIdentity) : new UnsafeLoadNode(object, offset, accessKind, locationIdentity);
     }
 
-    UnsafeLoadNode(ValueNode object, ValueNode offset, Kind accessKind, LocationIdentity locationIdentity) {
+    protected UnsafeLoadNode(ValueNode object, ValueNode offset, Kind accessKind, LocationIdentity locationIdentity) {
         this(object, offset, accessKind, locationIdentity, null);
     }
 
@@ -51,7 +51,7 @@
         return USE_GENERATED_NODES ? new UnsafeLoadNodeGen(object, offset, accessKind, locationIdentity, condition) : new UnsafeLoadNode(object, offset, accessKind, locationIdentity, condition);
     }
 
-    UnsafeLoadNode(ValueNode object, ValueNode offset, Kind accessKind, LocationIdentity locationIdentity, LogicNode condition) {
+    protected UnsafeLoadNode(ValueNode object, ValueNode offset, Kind accessKind, LocationIdentity locationIdentity, LogicNode condition) {
         super(StampFactory.forKind(accessKind.getStackKind()), object, offset, accessKind, locationIdentity);
         this.guardingCondition = condition;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -45,7 +45,7 @@
         return USE_GENERATED_NODES ? new UnsafeStoreNodeGen(object, offset, value, accessKind, locationIdentity) : new UnsafeStoreNode(object, offset, value, accessKind, locationIdentity);
     }
 
-    UnsafeStoreNode(ValueNode object, ValueNode offset, ValueNode value, Kind accessKind, LocationIdentity locationIdentity) {
+    protected UnsafeStoreNode(ValueNode object, ValueNode offset, ValueNode value, Kind accessKind, LocationIdentity locationIdentity) {
         this(object, offset, value, accessKind, locationIdentity, null);
     }
 
@@ -54,7 +54,7 @@
                         stateAfter);
     }
 
-    UnsafeStoreNode(ValueNode object, ValueNode offset, ValueNode value, Kind accessKind, LocationIdentity locationIdentity, FrameState stateAfter) {
+    protected UnsafeStoreNode(ValueNode object, ValueNode offset, ValueNode value, Kind accessKind, LocationIdentity locationIdentity, FrameState stateAfter) {
         super(StampFactory.forVoid(), object, offset, accessKind, locationIdentity);
         this.value = value;
         this.stateAfter = stateAfter;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -42,7 +42,7 @@
         return USE_GENERATED_NODES ? new ValueAnchorNodeGen(value) : new ValueAnchorNode(value);
     }
 
-    ValueAnchorNode(ValueNode value) {
+    protected ValueAnchorNode(ValueNode value) {
         super(StampFactory.forVoid());
         this.anchored = value;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -40,7 +40,7 @@
         return USE_GENERATED_NODES ? new WriteNodeGen(object, value, location, barrierType) : new WriteNode(object, value, location, barrierType);
     }
 
-    WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType) {
+    protected WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType) {
         super(object, value, location, barrierType);
     }
 
@@ -48,7 +48,7 @@
         return USE_GENERATED_NODES ? new WriteNodeGen(object, value, location, barrierType, initialization) : new WriteNode(object, value, location, barrierType, initialization);
     }
 
-    WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean initialization) {
+    protected WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean initialization) {
         super(object, value, location, barrierType, initialization);
     }
 
@@ -56,7 +56,7 @@
         return USE_GENERATED_NODES ? new WriteNodeGen(object, value, location, barrierType, guard, initialization) : new WriteNode(object, value, location, barrierType, guard, initialization);
     }
 
-    WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, GuardingNode guard, boolean initialization) {
+    protected WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, GuardingNode guard, boolean initialization) {
         super(object, value, location, barrierType, guard, initialization);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewArrayNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewArrayNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -74,8 +74,8 @@
 
     @Override
     public void simplify(SimplifierTool tool) {
-        Stamp stamp = length.stamp();
-        if (stamp instanceof IntegerStamp && ((IntegerStamp) stamp).isPositive()) {
+        Stamp lengthStamp = length.stamp();
+        if (lengthStamp instanceof IntegerStamp && ((IntegerStamp) lengthStamp).isPositive()) {
             // otherwise, removing the allocation might swallow a NegativeArraySizeException
             super.simplify(tool);
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -38,7 +38,7 @@
 @NodeInfo
 public class AbstractNewObjectNode extends DeoptimizingFixedWithNextNode implements Simplifiable, Lowerable {
 
-    private final boolean fillContents;
+    protected final boolean fillContents;
 
     /**
      * Constructs a new AbstractNewObjectNode.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -36,7 +36,7 @@
 public abstract class AccessIndexedNode extends AccessArrayNode implements Lowerable {
 
     @Input protected ValueNode index;
-    private final Kind elementKind;
+    protected final Kind elementKind;
 
     public ValueNode index() {
         return index;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -50,7 +50,7 @@
         return USE_GENERATED_NODES ? new ArrayLengthNodeGen(array) : new ArrayLengthNode(array);
     }
 
-    ArrayLengthNode(ValueNode array) {
+    protected ArrayLengthNode(ValueNode array) {
         super(StampFactory.positiveInt());
         this.array = array;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndAddNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndAddNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -42,13 +42,13 @@
     @Input ValueNode offset;
     @Input ValueNode delta;
 
-    private final LocationIdentity locationIdentity;
+    protected final LocationIdentity locationIdentity;
 
     public static AtomicReadAndAddNode create(ValueNode object, ValueNode offset, ValueNode delta, LocationIdentity locationIdentity) {
         return USE_GENERATED_NODES ? new AtomicReadAndAddNodeGen(object, offset, delta, locationIdentity) : new AtomicReadAndAddNode(object, offset, delta, locationIdentity);
     }
 
-    AtomicReadAndAddNode(ValueNode object, ValueNode offset, ValueNode delta, LocationIdentity locationIdentity) {
+    protected AtomicReadAndAddNode(ValueNode object, ValueNode offset, ValueNode delta, LocationIdentity locationIdentity) {
         super(StampFactory.forKind(delta.getKind()));
         this.object = object;
         this.offset = offset;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndWriteNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndWriteNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -43,15 +43,15 @@
     @Input ValueNode offset;
     @Input ValueNode newValue;
 
-    private final Kind valueKind;
-    private final LocationIdentity locationIdentity;
+    protected final Kind valueKind;
+    protected final LocationIdentity locationIdentity;
 
     public static AtomicReadAndWriteNode create(ValueNode object, ValueNode offset, ValueNode newValue, Kind valueKind, LocationIdentity locationIdentity) {
         return USE_GENERATED_NODES ? new AtomicReadAndWriteNodeGen(object, offset, newValue, valueKind, locationIdentity) : new AtomicReadAndWriteNode(object, offset, newValue, valueKind,
                         locationIdentity);
     }
 
-    AtomicReadAndWriteNode(ValueNode object, ValueNode offset, ValueNode newValue, Kind valueKind, LocationIdentity locationIdentity) {
+    protected AtomicReadAndWriteNode(ValueNode object, ValueNode offset, ValueNode newValue, Kind valueKind, LocationIdentity locationIdentity) {
         super(StampFactory.forKind(newValue.getKind()));
         this.object = object;
         this.offset = offset;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -43,7 +43,7 @@
      * Determines the exception thrown by this node if the check fails: {@link ClassCastException}
      * if false; {@link ArrayStoreException} if true.
      */
-    private final boolean forStoreCheck;
+    protected final boolean forStoreCheck;
 
     /**
      * @param hub the type being cast to
@@ -53,7 +53,7 @@
         return USE_GENERATED_NODES ? new CheckCastDynamicNodeGen(hub, object, forStoreCheck) : new CheckCastDynamicNode(hub, object, forStoreCheck);
     }
 
-    CheckCastDynamicNode(ValueNode hub, ValueNode object, boolean forStoreCheck) {
+    protected CheckCastDynamicNode(ValueNode hub, ValueNode object, boolean forStoreCheck) {
         super(object.stamp());
         this.hub = hub;
         this.object = object;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -44,14 +44,14 @@
 public class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Simplifiable, Lowerable, Virtualizable, ValueProxy {
 
     @Input protected ValueNode object;
-    private final ResolvedJavaType type;
-    private final JavaTypeProfile profile;
+    protected final ResolvedJavaType type;
+    protected final JavaTypeProfile profile;
 
     /**
      * Determines the exception thrown by this node if the check fails: {@link ClassCastException}
      * if false; {@link ArrayStoreException} if true.
      */
-    private final boolean forStoreCheck;
+    protected final boolean forStoreCheck;
 
     /**
      * Creates a new CheckCast instruction.
@@ -104,16 +104,16 @@
      */
     @Override
     public void lower(LoweringTool tool) {
-        Stamp stamp = StampFactory.declared(type, false, true);
+        Stamp newStamp = StampFactory.declared(type, false, true);
         if (stamp() instanceof ObjectStamp && object().stamp() instanceof ObjectStamp) {
-            stamp = ((ObjectStamp) object().stamp()).castTo((ObjectStamp) stamp);
+            newStamp = ((ObjectStamp) object().stamp()).castTo((ObjectStamp) newStamp);
         }
         ValueNode condition;
         ValueNode theValue = object;
-        if (stamp instanceof IllegalStamp) {
+        if (newStamp instanceof IllegalStamp) {
             // This is a check cast that will always fail
             condition = LogicConstantNode.contradiction(graph());
-            stamp = StampFactory.declared(type, false, true);
+            newStamp = StampFactory.declared(type, false, true);
         } else if (StampTool.isObjectNonNull(object)) {
             condition = graph().addWithoutUnique(InstanceOfNode.create(type, object, profile));
         } else {
@@ -129,7 +129,7 @@
                  * optimized away.
                  */
                 theValue = nullGuarded;
-                stamp = stamp.join(StampFactory.objectNonNull());
+                newStamp = newStamp.join(StampFactory.objectNonNull());
                 nullCheck.lower(tool);
             } else {
                 // TODO (ds) replace with probability of null-seen when available
@@ -138,7 +138,7 @@
                 condition = LogicNode.or(graph().unique(IsNullNode.create(object)), typeTest, shortCircuitProbability);
             }
         }
-        GuardingPiNode checkedObject = graph().add(GuardingPiNode.create(theValue, condition, false, forStoreCheck ? ArrayStoreException : ClassCastException, InvalidateReprofile, stamp));
+        GuardingPiNode checkedObject = graph().add(GuardingPiNode.create(theValue, condition, false, forStoreCheck ? ArrayStoreException : ClassCastException, InvalidateReprofile, newStamp));
         graph().replaceFixedWithFixed(this, checkedObject);
         checkedObject.lower(tool);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -43,15 +43,15 @@
     @Input ValueNode expected;
     @Input ValueNode newValue;
 
-    private final Kind valueKind;
-    private final LocationIdentity locationIdentity;
+    protected final Kind valueKind;
+    protected final LocationIdentity locationIdentity;
 
     public static CompareAndSwapNode create(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, Kind valueKind, LocationIdentity locationIdentity) {
         return USE_GENERATED_NODES ? new CompareAndSwapNodeGen(object, offset, expected, newValue, valueKind, locationIdentity) : new CompareAndSwapNode(object, offset, expected, newValue, valueKind,
                         locationIdentity);
     }
 
-    CompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, Kind valueKind, LocationIdentity locationIdentity) {
+    protected CompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, Kind valueKind, LocationIdentity locationIdentity) {
         super(StampFactory.forKind(Kind.Boolean.getStackKind()));
         assert expected.stamp().isCompatible(newValue.stamp());
         this.object = object;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -46,7 +46,7 @@
         return USE_GENERATED_NODES ? new DynamicNewArrayNodeGen(elementType, length) : new DynamicNewArrayNode(elementType, length);
     }
 
-    DynamicNewArrayNode(ValueNode elementType, ValueNode length) {
+    protected DynamicNewArrayNode(ValueNode elementType, ValueNode length) {
         this(elementType, length, true);
     }
 
@@ -54,7 +54,7 @@
         return USE_GENERATED_NODES ? new DynamicNewArrayNodeGen(elementType, length, fillContents) : new DynamicNewArrayNode(elementType, length, fillContents);
     }
 
-    DynamicNewArrayNode(ValueNode elementType, ValueNode length, boolean fillContents) {
+    protected DynamicNewArrayNode(ValueNode elementType, ValueNode length, boolean fillContents) {
         super(StampFactory.objectNonNull(), length, fillContents);
         this.elementType = elementType;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -38,7 +38,7 @@
         return USE_GENERATED_NODES ? new DynamicNewInstanceNodeGen(clazz, fillContents) : new DynamicNewInstanceNode(clazz, fillContents);
     }
 
-    DynamicNewInstanceNode(ValueNode clazz, boolean fillContents) {
+    protected DynamicNewInstanceNode(ValueNode clazz, boolean fillContents) {
         super(StampFactory.objectNonNull(), fillContents);
         this.clazz = clazz;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -40,7 +40,7 @@
         return USE_GENERATED_NODES ? new ExceptionObjectNodeGen(metaAccess) : new ExceptionObjectNode(metaAccess);
     }
 
-    ExceptionObjectNode(MetaAccessProvider metaAccess) {
+    protected ExceptionObjectNode(MetaAccessProvider metaAccess) {
         super(StampFactory.declaredNonNull(metaAccess.lookupJavaType(Throwable.class)));
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -48,7 +48,7 @@
         return USE_GENERATED_NODES ? new InstanceOfDynamicNodeGen(mirror, object) : new InstanceOfDynamicNode(mirror, object);
     }
 
-    InstanceOfDynamicNode(ValueNode mirror, ValueNode object) {
+    protected InstanceOfDynamicNode(ValueNode mirror, ValueNode object) {
         this.mirror = mirror;
         this.object = object;
         assert mirror.getKind() == Kind.Object : mirror.getKind();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -36,8 +36,8 @@
 @NodeInfo
 public class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable {
 
-    private final ResolvedJavaType type;
-    private JavaTypeProfile profile;
+    protected final ResolvedJavaType type;
+    protected JavaTypeProfile profile;
 
     /**
      * Constructs a new InstanceOfNode.
@@ -63,11 +63,10 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
-        Stamp stamp = forValue.stamp();
-        if (!(stamp instanceof ObjectStamp)) {
+        if (!(forValue.stamp() instanceof ObjectStamp)) {
             return this;
         }
-        ObjectStamp objectStamp = (ObjectStamp) stamp;
+        ObjectStamp objectStamp = (ObjectStamp) forValue.stamp();
         if (objectStamp.alwaysNull()) {
             return LogicConstantNode.contradiction();
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -34,7 +34,7 @@
         return USE_GENERATED_NODES ? new LoadExceptionObjectNodeGen(stamp) : new LoadExceptionObjectNode(stamp);
     }
 
-    LoadExceptionObjectNode(Stamp stamp) {
+    protected LoadExceptionObjectNode(Stamp stamp) {
         super(stamp);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -46,7 +46,7 @@
         return USE_GENERATED_NODES ? new LoadIndexedNodeGen(array, index, elementKind) : new LoadIndexedNode(array, index, elementKind);
     }
 
-    LoadIndexedNode(ValueNode array, ValueNode index, Kind elementKind) {
+    protected LoadIndexedNode(ValueNode array, ValueNode index, Kind elementKind) {
         super(createStamp(array, elementKind), array, index, elementKind);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredAtomicReadAndWriteNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredAtomicReadAndWriteNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -44,7 +44,7 @@
         return USE_GENERATED_NODES ? new LoweredAtomicReadAndWriteNodeGen(object, location, newValue, barrierType) : new LoweredAtomicReadAndWriteNode(object, location, newValue, barrierType);
     }
 
-    LoweredAtomicReadAndWriteNode(ValueNode object, LocationNode location, ValueNode newValue, BarrierType barrierType) {
+    protected LoweredAtomicReadAndWriteNode(ValueNode object, LocationNode location, ValueNode newValue, BarrierType barrierType) {
         super(object, location, newValue.stamp().unrestricted(), barrierType);
         this.newValue = newValue;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -66,7 +66,7 @@
                         newValue, barrierType);
     }
 
-    LoweredCompareAndSwapNode(ValueNode object, LocationNode location, ValueNode expectedValue, ValueNode newValue, BarrierType barrierType) {
+    protected LoweredCompareAndSwapNode(ValueNode object, LocationNode location, ValueNode expectedValue, ValueNode newValue, BarrierType barrierType) {
         super(object, location, StampFactory.forKind(Kind.Boolean.getStackKind()), barrierType);
         assert expectedValue.getKind() == newValue.getKind();
         this.expectedValue = expectedValue;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -32,7 +32,7 @@
 
 @NodeInfo
 public class MethodCallTargetNode extends CallTargetNode implements IterableNodeType, Canonicalizable {
-    private final JavaType returnType;
+    protected final JavaType returnType;
 
     /**
      * @param arguments
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -44,7 +44,7 @@
         return USE_GENERATED_NODES ? new MonitorEnterNodeGen(object, monitorId) : new MonitorEnterNode(object, monitorId);
     }
 
-    MonitorEnterNode(ValueNode object, MonitorIdNode monitorId) {
+    protected MonitorEnterNode(ValueNode object, MonitorIdNode monitorId) {
         super(object, monitorId);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -48,7 +48,7 @@
         return USE_GENERATED_NODES ? new MonitorExitNodeGen(object, monitorId, escapedReturnValue) : new MonitorExitNode(object, monitorId, escapedReturnValue);
     }
 
-    MonitorExitNode(ValueNode object, MonitorIdNode monitorId, ValueNode escapedReturnValue) {
+    protected MonitorExitNode(ValueNode object, MonitorIdNode monitorId, ValueNode escapedReturnValue) {
         super(object, monitorId);
         this.escapedReturnValue = escapedReturnValue;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -36,7 +36,7 @@
 @NodeInfo(allowedUsageTypes = {InputType.Association})
 public class MonitorIdNode extends ValueNode implements IterableNodeType, LIRLowerable {
 
-    private int lockDepth;
+    protected int lockDepth;
 
     public static MonitorIdNode create(int lockDepth) {
         return USE_GENERATED_NODES ? new MonitorIdNodeGen(lockDepth) : new MonitorIdNode(lockDepth);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -38,7 +38,7 @@
 @NodeInfo(nameTemplate = "New {p#instanceClass/s}")
 public class NewInstanceNode extends AbstractNewObjectNode implements VirtualizableAllocation {
 
-    private final ResolvedJavaType instanceClass;
+    protected final ResolvedJavaType instanceClass;
 
     /**
      * Constructs a NewInstanceNode.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -36,7 +36,7 @@
 public class NewMultiArrayNode extends DeoptimizingFixedWithNextNode implements Lowerable, ArrayLengthProvider {
 
     @Input protected NodeInputList<ValueNode> dimensions;
-    private final ResolvedJavaType type;
+    protected final ResolvedJavaType type;
 
     public ValueNode dimension(int index) {
         return dimensions.get(index);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -45,7 +45,7 @@
         return USE_GENERATED_NODES ? new RegisterFinalizerNodeGen(value) : new RegisterFinalizerNode(value);
     }
 
-    RegisterFinalizerNode(ValueNode value) {
+    protected RegisterFinalizerNode(ValueNode value) {
         super(StampFactory.forVoid());
         this.value = value;
     }
@@ -66,16 +66,16 @@
             return this;
         }
 
-        ObjectStamp stamp = (ObjectStamp) forValue.stamp();
+        ObjectStamp objectStamp = (ObjectStamp) forValue.stamp();
 
         boolean needsCheck = true;
-        if (stamp.isExactType()) {
-            needsCheck = stamp.type().hasFinalizer();
-        } else if (stamp.type() != null && !stamp.type().hasFinalizableSubclass()) {
+        if (objectStamp.isExactType()) {
+            needsCheck = objectStamp.type().hasFinalizer();
+        } else if (objectStamp.type() != null && !objectStamp.type().hasFinalizableSubclass()) {
             // if either the declared type of receiver or the holder
             // can be assumed to have no finalizers
             if (tool.assumptions().useOptimisticAssumptions()) {
-                tool.assumptions().recordNoFinalizableSubclassAssumption(stamp.type());
+                tool.assumptions().recordNoFinalizableSubclassAssumption(objectStamp.type());
                 needsCheck = false;
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -40,8 +40,8 @@
 public class SelfReplacingMethodCallTargetNode extends MethodCallTargetNode implements Lowerable {
 
     // Replacement method data
-    private final ResolvedJavaMethod replacementTargetMethod;
-    private final JavaType replacementReturnType;
+    protected final ResolvedJavaMethod replacementTargetMethod;
+    protected final JavaType replacementReturnType;
     @Input NodeInputList<ValueNode> replacementArguments;
 
     public static SelfReplacingMethodCallTargetNode create(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType,
@@ -50,7 +50,7 @@
                         : new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, arguments, returnType, replacementTargetMethod, replacementArguments, replacementReturnType);
     }
 
-    SelfReplacingMethodCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod replacementTargetMethod,
+    protected SelfReplacingMethodCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod replacementTargetMethod,
                     ValueNode[] replacementArguments, JavaType replacementReturnType) {
         super(invokeKind, targetMethod, arguments, returnType);
         this.replacementTargetMethod = replacementTargetMethod;
@@ -72,9 +72,9 @@
 
     @Override
     public void lower(LoweringTool tool) {
-        InvokeKind invokeKind = replacementTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
+        InvokeKind replacementInvokeKind = replacementTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
         MethodCallTargetNode replacement = graph().add(
-                        MethodCallTargetNode.create(invokeKind, replacementTargetMethod, replacementArguments.toArray(new ValueNode[replacementArguments.size()]), replacementReturnType));
+                        MethodCallTargetNode.create(replacementInvokeKind, replacementTargetMethod, replacementArguments.toArray(new ValueNode[replacementArguments.size()]), replacementReturnType));
 
         // Replace myself...
         this.replaceAndDelete(replacement);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -67,7 +67,7 @@
         return USE_GENERATED_NODES ? new StoreFieldNodeGen(object, field, value) : new StoreFieldNode(object, field, value);
     }
 
-    StoreFieldNode(ValueNode object, ResolvedJavaField field, ValueNode value) {
+    protected StoreFieldNode(ValueNode object, ResolvedJavaField field, ValueNode value) {
         super(StampFactory.forVoid(), object, field);
         this.value = value;
     }
@@ -76,7 +76,7 @@
         return USE_GENERATED_NODES ? new StoreFieldNodeGen(object, field, value, stateAfter) : new StoreFieldNode(object, field, value, stateAfter);
     }
 
-    StoreFieldNode(ValueNode object, ResolvedJavaField field, ValueNode value, FrameState stateAfter) {
+    protected StoreFieldNode(ValueNode object, ResolvedJavaField field, ValueNode value, FrameState stateAfter) {
         super(StampFactory.forVoid(), object, field);
         this.value = value;
         this.stateAfter = stateAfter;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -68,7 +68,7 @@
         return USE_GENERATED_NODES ? new StoreIndexedNodeGen(array, index, elementKind, value) : new StoreIndexedNode(array, index, elementKind, value);
     }
 
-    StoreIndexedNode(ValueNode array, ValueNode index, Kind elementKind, ValueNode value) {
+    protected StoreIndexedNode(ValueNode array, ValueNode index, Kind elementKind, ValueNode value) {
         super(StampFactory.forVoid(), array, index, elementKind);
         this.value = value;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -41,7 +41,7 @@
 @NodeInfo
 public class TypeSwitchNode extends SwitchNode implements LIRLowerable, Simplifiable {
 
-    private final ResolvedJavaType[] keys;
+    protected final ResolvedJavaType[] keys;
 
     /**
      * Constructs a type switch instruction. The keyProbabilities array contain key.length + 1
@@ -57,7 +57,7 @@
         return USE_GENERATED_NODES ? new TypeSwitchNodeGen(value, successors, keys, keyProbabilities, keySuccessors) : new TypeSwitchNode(value, successors, keys, keyProbabilities, keySuccessors);
     }
 
-    TypeSwitchNode(ValueNode value, BeginNode[] successors, ResolvedJavaType[] keys, double[] keyProbabilities, int[] keySuccessors) {
+    protected TypeSwitchNode(ValueNode value, BeginNode[] successors, ResolvedJavaType[] keys, double[] keyProbabilities, int[] keySuccessors) {
         super(value, successors, keySuccessors, keyProbabilities);
         assert successors.length <= keys.length + 1;
         assert keySuccessors.length == keyProbabilities.length;
@@ -152,11 +152,11 @@
             graph().removeSplit(this, blockSuccessor(survivingEdge));
         }
         if (value() instanceof LoadHubNode && ((LoadHubNode) value()).getValue().stamp() instanceof ObjectStamp) {
-            ObjectStamp stamp = (ObjectStamp) ((LoadHubNode) value()).getValue().stamp();
-            if (stamp.type() != null) {
+            ObjectStamp objectStamp = (ObjectStamp) ((LoadHubNode) value()).getValue().stamp();
+            if (objectStamp.type() != null) {
                 int validKeys = 0;
                 for (int i = 0; i < keyCount(); i++) {
-                    if (stamp.type().isAssignableFrom(keys[i])) {
+                    if (objectStamp.type().isAssignableFrom(keys[i])) {
                         validKeys++;
                     }
                 }
@@ -171,7 +171,7 @@
                     double totalProbability = 0;
                     int current = 0;
                     for (int i = 0; i < keyCount() + 1; i++) {
-                        if (i == keyCount() || stamp.type().isAssignableFrom(keys[i])) {
+                        if (i == keyCount() || objectStamp.type().isAssignableFrom(keys[i])) {
                             int index = newSuccessors.indexOf(keySuccessor(i));
                             if (index == -1) {
                                 index = newSuccessors.size();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/AllocatedObjectNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/AllocatedObjectNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -42,7 +42,7 @@
         return USE_GENERATED_NODES ? new AllocatedObjectNodeGen(virtualObject) : new AllocatedObjectNode(virtualObject);
     }
 
-    AllocatedObjectNode(VirtualObjectNode virtualObject) {
+    protected AllocatedObjectNode(VirtualObjectNode virtualObject) {
         super(StampFactory.exactNonNull(virtualObject.type()));
         this.virtualObject = virtualObject;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -38,13 +38,13 @@
     @Input NodeInputList<VirtualObjectNode> virtualObjects = new NodeInputList<>(this);
     @Input NodeInputList<ValueNode> values = new NodeInputList<>(this);
     @Input(InputType.Association) NodeInputList<MonitorIdNode> locks = new NodeInputList<>(this);
-    private ArrayList<Integer> lockIndexes = new ArrayList<>(Arrays.asList(0));
+    protected ArrayList<Integer> lockIndexes = new ArrayList<>(Arrays.asList(0));
 
     public static CommitAllocationNode create() {
         return USE_GENERATED_NODES ? new CommitAllocationNodeGen() : new CommitAllocationNode();
     }
 
-    CommitAllocationNode() {
+    protected CommitAllocationNode() {
         super(StampFactory.forVoid());
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -30,13 +30,13 @@
 @NodeInfo
 public class VirtualBoxingNode extends VirtualInstanceNode {
 
-    private final Kind boxingKind;
+    protected final Kind boxingKind;
 
     public static VirtualBoxingNode create(ResolvedJavaType type, Kind boxingKind) {
         return USE_GENERATED_NODES ? new VirtualBoxingNodeGen(type, boxingKind) : new VirtualBoxingNode(type, boxingKind);
     }
 
-    VirtualBoxingNode(ResolvedJavaType type, Kind boxingKind) {
+    protected VirtualBoxingNode(ResolvedJavaType type, Kind boxingKind) {
         super(type, false);
         this.boxingKind = boxingKind;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -32,7 +32,7 @@
 @NodeInfo
 public abstract class VirtualObjectNode extends ValueNode implements LIRLowerable, IterableNodeType {
 
-    private boolean hasIdentity;
+    protected boolean hasIdentity;
 
     public VirtualObjectNode(ResolvedJavaType type, boolean hasIdentity) {
         super(StampFactory.exactNonNull(type));
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Fri Oct 03 13:48:58 2014 +0200
@@ -213,7 +213,7 @@
         }
 
         public static boolean tryGlobalValueNumbering(Node node, NodeClass nodeClass) {
-            if (nodeClass.valueNumberable() && !node.isLeafNode()) {
+            if (nodeClass.valueNumberable() && !nodeClass.isLeafNode()) {
                 Node newNode = node.graph().findDuplicate(node);
                 if (newNode != null) {
                     assert !(node instanceof FixedNode || newNode instanceof FixedNode);
@@ -270,7 +270,7 @@
             }
 
             if (nodeClass.isSimplifiable()) {
-                Debug.log("Canonicalizer: simplifying %s", node);
+                Debug.log(3, "Canonicalizer: simplifying %s", node);
                 METRIC_SIMPLIFICATION_CONSIDERED_NODES.increment();
                 try (Scope s = Debug.scope("SimplifyNode", node)) {
                     node.simplify(tool);
@@ -300,7 +300,7 @@
 // @formatter:on
         private boolean performReplacement(final Node node, Node newCanonical) {
             if (newCanonical == node) {
-                Debug.log("Canonicalizer: work on %1s", node);
+                Debug.log(3, "Canonicalizer: work on %1s", node);
                 return false;
             } else {
                 Node canonical = newCanonical;
@@ -310,6 +310,9 @@
                 if (canonical != null && !canonical.isAlive()) {
                     assert !canonical.isDeleted();
                     canonical = graph.addOrUniqueWithInputs(canonical);
+                    if (canonical == node) {
+                        graph.addOrUniqueWithInputs(newCanonical);
+                    }
                 }
                 if (node instanceof FloatingNode) {
                     if (canonical == null) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Fri Oct 03 13:48:58 2014 +0200
@@ -211,8 +211,8 @@
                         if (node instanceof AbstractEndNode) {
                             MergeNode merge = ((AbstractEndNode) node).merge();
                             for (PhiNode phi : merge.phis()) {
-                                assert currentState.isMarked(phi.valueAt((AbstractEndNode) node)) : phi.valueAt((AbstractEndNode) node) + " not available at phi " + phi + " / end " + node +
-                                                " in block " + block;
+                                ValueNode phiValue = phi.valueAt((AbstractEndNode) node);
+                                assert phiValue == null || currentState.isMarked(phiValue) : phiValue + " not available at phi " + phi + " / end " + node + " in block " + block;
                             }
                         }
                         if (stateAfter != null) {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Fri Oct 03 13:48:58 2014 +0200
@@ -457,16 +457,12 @@
                 out.printf("nr %4d ", inst.id()).print(COLUMN_END);
 
                 final StringBuilder stateString = new StringBuilder();
-                inst.forEachState(new StateProcedure() {
-
-                    @Override
-                    protected void doState(LIRFrameState state) {
-                        if (state.hasDebugInfo()) {
-                            DebugInfo di = state.debugInfo();
-                            stateString.append(debugInfoToString(di.getBytecodePosition(), di.getReferenceMap(), di.getCalleeSaveInfo(), target.arch));
-                        } else {
-                            stateString.append(debugInfoToString(state.topFrame, null, null, target.arch));
-                        }
+                inst.forEachState(state -> {
+                    if (state.hasDebugInfo()) {
+                        DebugInfo di = state.debugInfo();
+                        stateString.append(debugInfoToString(di.getBytecodePosition(), di.getReferenceMap(), di.getCalleeSaveInfo(), target.arch));
+                    } else {
+                        stateString.append(debugInfoToString(state.topFrame, null, null, target.arch));
                     }
                 });
                 if (stateString.length() > 0) {
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -41,7 +41,7 @@
 @NodeInfo
 public class AMD64FloatConvertNode extends UnaryNode implements ArithmeticLIRLowerable {
 
-    private final FloatConvert op;
+    protected final FloatConvert op;
 
     public static AMD64FloatConvertNode create(Stamp stamp, FloatConvert op, ValueNode value) {
         return USE_GENERATED_NODES ? new AMD64FloatConvertNodeGen(stamp, op, value) : new AMD64FloatConvertNode(stamp, op, value);
--- a/graal/com.oracle.graal.replacements.hsail/src/com/oracle/graal/replacements/hsail/HSAILMathIntrinsicsNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.replacements.hsail/src/com/oracle/graal/replacements/hsail/HSAILMathIntrinsicsNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -49,7 +49,7 @@
     /**
      * The math operation that this Node represents.
      */
-    private final HSAILArithmetic operation;
+    protected final HSAILArithmetic operation;
 
     /**
      * Gets the parameter passed to the math operation that this node represents.
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/EdgesTest.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/EdgesTest.java	Fri Oct 03 13:48:58 2014 +0200
@@ -50,6 +50,10 @@
         public static TestNode create() {
             return USE_GENERATED_NODES ? new EdgesTest_TestNodeGen() : new TestNode();
         }
+
+        protected TestNode() {
+            // TODO Auto-generated constructor stub
+        }
     }
 
     StructuredGraph graph = new StructuredGraph();
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Fri Oct 03 13:48:58 2014 +0200
@@ -384,7 +384,7 @@
     @NodeInfo
     static class VarargsPlaceholderNode extends FloatingNode implements ArrayLengthProvider {
 
-        final Varargs varargs;
+        protected final Varargs varargs;
 
         public static VarargsPlaceholderNode create(Varargs varargs, MetaAccessProvider metaAccess) {
             return USE_GENERATED_NODES ? new SnippetTemplate_VarargsPlaceholderNodeGen(varargs, metaAccess) : new VarargsPlaceholderNode(varargs, metaAccess);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -39,7 +39,7 @@
 public class ArrayEqualsNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, Virtualizable, MemoryAccess {
 
     /** {@link Kind} of the arrays to compare. */
-    private final Kind kind;
+    protected final Kind kind;
 
     /** One array to be tested for equality. */
     @Input ValueNode array1;
@@ -58,8 +58,8 @@
         super(StampFactory.forKind(Kind.Boolean));
 
         assert array1.stamp().equals(array2.stamp());
-        ObjectStamp stamp = (ObjectStamp) array1.stamp();
-        ResolvedJavaType componentType = stamp.type().getComponentType();
+        ObjectStamp array1Stamp = (ObjectStamp) array1.stamp();
+        ResolvedJavaType componentType = array1Stamp.type().getComponentType();
         this.kind = componentType.getKind();
 
         this.array1 = array1;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/AssertionNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/AssertionNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -40,8 +40,8 @@
 
     @Input ValueNode value;
 
-    private final boolean compileTimeAssertion;
-    private final String message;
+    protected final boolean compileTimeAssertion;
+    protected final String message;
 
     public static AssertionNode create(boolean compileTimeAssertion, ValueNode value, String message) {
         return USE_GENERATED_NODES ? new AssertionNodeGen(compileTimeAssertion, value, message) : new AssertionNode(compileTimeAssertion, value, message);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -40,8 +40,8 @@
     @Input ValueNode object;
     @Input ValueNode value;
     @Input ValueNode offset;
-    private final int displacement;
-    private final LocationIdentity locationIdentity;
+    protected final int displacement;
+    protected final LocationIdentity locationIdentity;
 
     public static DirectObjectStoreNode create(ValueNode object, int displacement, ValueNode offset, ValueNode value, LocationIdentity locationIdentity) {
         return USE_GENERATED_NODES ? new DirectObjectStoreNodeGen(object, displacement, offset, value, locationIdentity) : new DirectObjectStoreNode(object, displacement, offset, value,
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -39,7 +39,7 @@
 public class DirectReadNode extends FixedWithNextNode implements LIRLowerable {
 
     @Input protected ValueNode address;
-    private final Kind readKind;
+    protected final Kind readKind;
 
     public static DirectReadNode create(ValueNode address, Kind readKind) {
         return USE_GENERATED_NODES ? new DirectReadNodeGen(address, readKind) : new DirectReadNode(address, readKind);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -40,7 +40,7 @@
 
     @Input protected ValueNode address;
     @Input protected ValueNode value;
-    private final Kind kind;
+    protected final Kind kind;
 
     public static DirectStoreNode create(ValueNode address, ValueNode value, Kind kind) {
         return USE_GENERATED_NODES ? new DirectStoreNodeGen(address, value, kind) : new DirectStoreNode(address, value, kind);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -61,10 +61,10 @@
 
     @Input protected NodeInputList<ValueNode> arguments;
 
-    private final int bci;
-    private final ResolvedJavaMethod targetMethod;
-    private final JavaType returnType;
-    private final InvokeKind invokeKind;
+    protected final int bci;
+    protected final ResolvedJavaMethod targetMethod;
+    protected final JavaType returnType;
+    protected final InvokeKind invokeKind;
 
     public static MacroNode create(Invoke invoke) {
         return USE_GENERATED_NODES ? new MacroNodeGen(invoke) : new MacroNode(invoke);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -35,7 +35,7 @@
 @NodeInfo
 public class MathIntrinsicNode extends UnaryNode implements ArithmeticLIRLowerable {
 
-    private final Operation operation;
+    protected final Operation operation;
 
     public enum Operation {
         ABS,
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -38,20 +38,20 @@
     /**
      * The fixed register to access.
      */
-    private final Register register;
+    protected final Register register;
 
     /**
      * When true, subsequent uses of this node use the fixed register; when false, the value is
      * moved into a new virtual register so that the fixed register is not seen by uses.
      */
-    private final boolean directUse;
+    protected final boolean directUse;
 
     /**
      * When true, this node is also an implicit definition of the value for the register allocator,
      * i.e., the register is an implicit incoming value; when false, the register must be defined in
      * the same method or must be an register excluded from register allocation.
      */
-    private final boolean incoming;
+    protected final boolean incoming;
 
     public static ReadRegisterNode create(Register register, Kind kind, boolean directUse, boolean incoming) {
         return USE_GENERATED_NODES ? new ReadRegisterNodeGen(register, kind, directUse, incoming) : new ReadRegisterNode(register, kind, directUse, incoming);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -38,7 +38,7 @@
     /**
      * The fixed register to access.
      */
-    private final Register register;
+    protected final Register register;
 
     /**
      * The new value assigned to the register.
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Fri Oct 03 13:48:58 2014 +0200
@@ -76,6 +76,7 @@
 
     private HotSpotTruffleRuntime() {
         installOptimizedCallTargetCallMethod();
+        installOptimizedCallTargetCallDirect();
         lookupCallMethods(getGraalProviders().getMetaAccess());
 
         // Create compilation queue.
@@ -93,6 +94,12 @@
         compileQueue = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), factory);
     }
 
+    private static void installOptimizedCallTargetCallDirect() {
+        if (TruffleCompilerOptions.TruffleContextSensitiveInlining.getValue()) {
+            ((HotSpotResolvedJavaMethod) getGraalProviders().getMetaAccess().lookupJavaMethod(OptimizedCallTarget.getCallDirectMethod())).setNotInlineable();
+        }
+    }
+
     @Override
     public String getName() {
         return "Graal Truffle Runtime";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/sl/TestInlining.sl	Fri Oct 03 13:48:58 2014 +0200
@@ -0,0 +1,20 @@
+/* 
+ * This tests that simple arithmetic gets inlined.
+ */
+function add(a, b) { 
+    return a + b;
+}
+
+
+function test() {
+    i = 0;
+    while (i < 100) {
+        i = add(i, 1);
+    }
+    return i;
+}
+
+function main() {
+    waitForOptimization(callUntilOptimized(test));
+    assertTrue(isInlined(test, test, add), "add is not inlined");
+}  
--- a/graal/com.oracle.graal.truffle.test/sl/TestInliningMaxCallerSize.sl	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle.test/sl/TestInliningMaxCallerSize.sl	Fri Oct 03 13:48:58 2014 +0200
@@ -19,8 +19,8 @@
 
 function main() {
     waitForOptimization(callUntilOptimized(test1));
-    assertTrue(isInlined(test1, inlinableFunction), "inlinableFunction is not inlined");
+    assertTrue(isInlined(test1, test1, inlinableFunction), "inlinableFunction is not inlined");
     
     waitForOptimization(callUntilOptimized(test2));
-    assertFalse(isInlined(test2, notInlinableFunction), "notInlinableFunction is inlined");
+    assertFalse(isInlined(test2, test2, notInlinableFunction), "notInlinableFunction is inlined");
 }  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/sl/TestInliningRecursive1.sl	Fri Oct 03 13:48:58 2014 +0200
@@ -0,0 +1,25 @@
+/* 
+ * Test recursive calls do not get inlined and do not crash.
+ */
+function fib(a) { 
+    if (a == 2 || a == 1) {
+        return 1;
+    }
+    return fib(a-1) + fib(a-2);
+}
+
+function test() {
+    i = 0;
+    sum = 0;
+    while (i < 100) {
+        sum = sum + fib(7);
+        i = i + 1;
+    }
+    return sum;
+}
+
+function main() {
+    waitForOptimization(callUntilOptimized(test));
+    assertTrue(isInlined(test, test, fib), "fib is not inlined");
+    assertFalse(isInlined(test, fib, fib), "fib -> fib is not inlined");
+}  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/sl/TestInliningRecursive2.sl	Fri Oct 03 13:48:58 2014 +0200
@@ -0,0 +1,37 @@
+/* 
+ * Tests that indirect recursions are not inlined.
+ */
+function fib(a) { 
+    if (a == 2 || a == 1) {
+        return 1;
+    }
+    return call(fib, a-1) + call(fib, a-2) + call(void, 0);
+}
+
+function call(f, a) {
+    return f(a);
+}
+
+function void(a) {
+    return a;
+}
+
+function test() {
+    i = 0;
+    sum = 0;
+    while (i < 100) {
+        sum = sum + fib(7);
+        i = i + 1;
+    }
+    return sum;
+}
+
+function main() {
+    waitForOptimization(callUntilOptimized(test));
+    assertTrue(isInlined(test, test, fib), "not inlined: test -> fib");
+    if (getOption("TruffleContextSensitiveInlining")) {
+      assertTrue(isInlined(test, fib, call), "not inlined: fib -> call");
+      assertFalse(isInlined(test, call, fib), "inlined: call -> fib"); 
+      assertTrue(isInlined(test, call, void), "inlined: call -> void");
+    }
+}  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/sl/TestSlowPath01.sl	Fri Oct 03 13:48:58 2014 +0200
@@ -0,0 +1,11 @@
+/* 
+ * This test verifies that CallTargets cannot exceed the TruffleInliningMaxCallerSize limit when inlining.
+ */
+
+function test1() {
+    testSlowPath01();
+}
+function main() {
+    waitForOptimization(callUntilOptimized(test1));
+    assertTrue(isOptimized(test1), "inlinableFunction must be compiled properly");
+}  
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Fri Oct 03 13:48:58 2014 +0200
@@ -97,7 +97,7 @@
 
         try (Scope s = Debug.scope("TruffleCompilation", new TruffleDebugJavaMethod(compilable))) {
 
-            StructuredGraph resultGraph = truffleCompiler.getPartialEvaluator().createGraph(compilable, assumptions);
+            StructuredGraph resultGraph = truffleCompiler.getPartialEvaluator().createGraph(compilable, assumptions, null);
             CanonicalizerPhase canonicalizer = new CanonicalizerPhase(canonicalizeReads);
             PhaseContext context = new PhaseContext(getProviders(), assumptions);
 
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/SLTruffleGraalTestSuite.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/SLTruffleGraalTestSuite.java	Fri Oct 03 13:48:58 2014 +0200
@@ -47,6 +47,9 @@
         SLTestRunner.installBuiltin(SLCallUntilOptimizedBuiltinFactory.getInstance());
         SLTestRunner.installBuiltin(SLIsInlinedBuiltinFactory.getInstance());
         SLTestRunner.installBuiltin(SLGenerateDummyNodesBuiltinFactory.getInstance());
+
+        /* test specific builtins */
+        SLTestRunner.installBuiltin(SLTestSlowPath01BuiltinFactory.getInstance());
     }
 
     /*
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLIsInlinedBuiltin.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLIsInlinedBuiltin.java	Fri Oct 03 13:48:58 2014 +0200
@@ -40,28 +40,57 @@
 
     @Specialization
     @SlowPath
-    public Object isInlined(SLFunction parent, SLFunction inlinedFunction) {
-        boolean allFalse = true;
-        boolean allTrue = true;
-        for (OptimizedCallTarget parentTarget : findDuplicateCallTargets((OptimizedCallTarget) parent.getCallTarget())) {
-            Set<DirectCallNode> callNodes = findCallsTo(parentTarget.getRootNode(), (OptimizedCallTarget) inlinedFunction.getCallTarget());
-            for (DirectCallNode directCall : callNodes) {
-                if (directCall.isInlined()) {
-                    allFalse = false;
-                } else {
-                    allTrue = false;
-                }
+    public Object isInlined(SLFunction rootFunction, SLFunction parentFunction, SLFunction inlinedFunction) {
+        InliningTrace trace = new InliningTrace();
+
+        for (OptimizedCallTarget target : findDuplicateCallTargets((OptimizedCallTarget) rootFunction.getCallTarget())) {
+            if (target.isValid()) {
+                searchInlined(trace, target, new ArrayList<>(), parentFunction, inlinedFunction);
             }
         }
-        if (allFalse && allTrue) {
-            throw new AssertionError(String.format("No calls found from %s to %s .", parent, inlinedFunction));
-        } else if (!allFalse && !allTrue) {
-            throw new AssertionError(String.format("Some calls from %s to %s are inlined and some are not.", parent, inlinedFunction));
+
+        if (trace.allFalse && trace.allTrue) {
+            throw new AssertionError(String.format("No optimized calls found from %s to %s .", parentFunction, inlinedFunction));
+        } else if (!trace.allFalse && !trace.allTrue) {
+            throw new AssertionError(String.format("Some optimized calls from %s to %s are inlined and some are not.", parentFunction, inlinedFunction));
         }
-        if (allTrue) {
+        if (trace.allTrue) {
             return true;
         } else {
             return false;
         }
     }
+
+    private void searchInlined(InliningTrace trace, OptimizedCallTarget rootTarget, List<OptimizedDirectCallNode> stack, SLFunction parent, SLFunction inlinedFunction) {
+        OptimizedCallTarget root;
+        if (stack.isEmpty()) {
+            root = rootTarget;
+        } else {
+            root = stack.get(stack.size() - 1).getCurrentCallTarget();
+        }
+
+        for (OptimizedDirectCallNode callNode : root.getCallNodes()) {
+            stack.add(callNode);
+
+            boolean inlined = rootTarget.isInlined(stack);
+            if (callNode.getRootNode().getCallTarget() == parent.getCallTarget() && callNode.getCallTarget() == inlinedFunction.getCallTarget()) {
+                if (inlined) {
+                    trace.allFalse = false;
+                } else {
+                    trace.allTrue = false;
+                }
+            }
+
+            if (inlined) {
+                searchInlined(trace, rootTarget, stack, parent, inlinedFunction);
+            }
+
+            stack.remove(stack.size() - 1);
+        }
+    }
+
+    private static final class InliningTrace {
+        boolean allFalse = true;
+        boolean allTrue = true;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLTestSlowPath01Builtin.java	Fri Oct 03 13:48:58 2014 +0200
@@ -0,0 +1,72 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle.test.builtins;
+
+import java.util.concurrent.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.SlowPath;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.runtime.*;
+
+/**
+ * Just used in TestSlowPath01.sl. Verifies that all intrinsics have no effect inside of a @SlowPath
+ * annotated method.
+ */
+@NodeInfo(shortName = "testSlowPath01")
+public abstract class SLTestSlowPath01Builtin extends SLGraalRuntimeBuiltin {
+
+    private static Object nonConstantValue = new Object();
+
+    @Specialization
+    @SlowPath
+    public Object testSlowPath() {
+        CompilerAsserts.neverPartOfCompilation();
+        CompilerAsserts.neverPartOfCompilation("Should never throw an exception when compiling.");
+        CompilerAsserts.compilationConstant(nonConstantValue);
+        CompilerDirectives.transferToInterpreter();
+        CompilerDirectives.transferToInterpreterAndInvalidate();
+        CompilerDirectives.bailout("Should not fail");
+        if (CompilerDirectives.inCompiledCode()) {
+            throw new AssertionError();
+        }
+        if (!CompilerDirectives.inInterpreter()) {
+            throw new AssertionError();
+        }
+        try {
+            int result = (int) CompilerDirectives.interpreterOnly(new Callable<Object>() {
+                public Object call() throws Exception {
+                    return 1;
+                }
+            });
+            if (result != 1) {
+                throw new AssertionError();
+            }
+        } catch (Exception e) {
+            throw new AssertionError();
+        }
+
+        return SLNull.SINGLETON;
+    }
+}
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLWaitForOptimizationBuiltin.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLWaitForOptimizationBuiltin.java	Fri Oct 03 13:48:58 2014 +0200
@@ -54,7 +54,7 @@
 
     @Specialization
     public SLFunction waitForCompilation(SLFunction function, @SuppressWarnings("unused") SLNull timeout) {
-        return waitForOptimization(function, 120000);
+        return waitForOptimization(function, 640000);
     }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/ContextSensitiveInlining.java	Fri Oct 03 13:48:58 2014 +0200
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2013, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle;
+
+import java.util.*;
+import java.util.stream.*;
+
+import com.oracle.graal.truffle.ContextSensitiveInlining.InliningDecision;
+
+public class ContextSensitiveInlining implements Iterable<InliningDecision> {
+
+    private final List<InliningDecision> callSites;
+
+    private ContextSensitiveInlining(List<InliningDecision> callSites) {
+        this.callSites = callSites;
+    }
+
+    public ContextSensitiveInlining(OptimizedCallTarget sourceTarget, TruffleInliningPolicy policy) {
+        this(decideInlining(OptimizedCallUtils.countNonTrivialNodes(sourceTarget, false), exploreCallSites(new ArrayList<>(Arrays.asList(sourceTarget)), policy), policy));
+    }
+
+    private static List<InliningDecision> exploreCallSites(List<OptimizedCallTarget> stack, TruffleInliningPolicy policy) {
+        List<InliningDecision> exploredCallSites = new ArrayList<>();
+        OptimizedCallTarget parentTarget = stack.get(stack.size() - 1);
+        for (OptimizedDirectCallNode callNode : parentTarget.getCallNodes()) {
+            OptimizedCallTarget currentTarget = callNode.getCurrentCallTarget();
+            stack.add(currentTarget); // push
+            exploredCallSites.add(exploreCallSite(stack, policy, callNode));
+            stack.remove(stack.size() - 1); // pop
+        }
+        return exploredCallSites;
+    }
+
+    private static InliningDecision exploreCallSite(List<OptimizedCallTarget> callStack, TruffleInliningPolicy policy, OptimizedDirectCallNode callNode) {
+        OptimizedCallTarget parentTarget = callStack.get(callStack.size() - 2);
+        OptimizedCallTarget currentTarget = callStack.get(callStack.size() - 1);
+
+        boolean recursive = isRecursiveStack(callStack);
+        boolean maxDepth = callStack.size() >= 15;
+
+        List<InliningDecision> childCallSites;
+        double frequency = TruffleInliningHandler.calculateFrequency(parentTarget, callNode);
+        int nodeCount = OptimizedCallUtils.countNonTrivialNodes(callNode.getCurrentCallTarget(), false);
+        int deepNodeCount;
+        if (recursive || maxDepth) {
+            deepNodeCount = nodeCount;
+            childCallSites = Collections.emptyList();
+        } else {
+            childCallSites = decideInlining(nodeCount, exploreCallSites(callStack, policy), policy);
+            deepNodeCount = nodeCount;
+            for (InliningDecision childCallSite : childCallSites) {
+                if (childCallSite.isInline()) {
+                    deepNodeCount += childCallSite.getProfile().getDeepNodeCount();
+                }
+            }
+        }
+
+        TruffleInliningProfile profile = new TruffleInliningProfile(callNode, nodeCount, deepNodeCount, frequency, recursive, null);
+        profile.setScore(policy.calculateScore(profile));
+        return new InliningDecision(currentTarget, profile, childCallSites);
+    }
+
+    private static boolean isRecursiveStack(List<OptimizedCallTarget> stack) {
+        OptimizedCallTarget top = stack.get(stack.size() - 1);
+        for (int i = 0; i < stack.size() - 1; i++) {
+            if (stack.get(i) == top) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static List<InliningDecision> decideInlining(int nodeCount, List<InliningDecision> callSites, TruffleInliningPolicy policy) {
+        int deepNodeCount = nodeCount;
+        int index = 0;
+        for (InliningDecision callSite : callSites.stream().sorted().collect(Collectors.toList())) {
+            TruffleInliningProfile profile = callSite.getProfile();
+            profile.setQueryIndex(index++);
+            if (policy.isAllowed(profile, deepNodeCount)) {
+                callSite.setInline(true);
+                deepNodeCount += profile.getDeepNodeCount();
+            }
+        }
+        return callSites;
+    }
+
+    public boolean isInlined(List<OptimizedDirectCallNode> callNodeTrace) {
+        if (callNodeTrace.isEmpty()) {
+            return false;
+        }
+
+        InliningDecision prev = null;
+        for (int i = 0; i < callNodeTrace.size(); i++) {
+            if (prev == null) {
+                prev = findByCall(callNodeTrace.get(i));
+            } else {
+                prev = prev.findByCall(callNodeTrace.get(i));
+            }
+            if (prev == null || !prev.isInline()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public int countCalls() {
+        return callSites.stream().mapToInt(callSite -> callSite.isInline() ? callSite.countCalls() + 1 : 1).sum();
+    }
+
+    public int countInlinedCalls() {
+        return callSites.stream().filter(InliningDecision::isInline).mapToInt(callSite -> callSite.countInlinedCalls() + 1).sum();
+    }
+
+    public List<InliningDecision> getCallSites() {
+        return callSites;
+    }
+
+    public Iterator<InliningDecision> iterator() {
+        return callSites.iterator();
+    }
+
+    public InliningDecision findByCall(OptimizedDirectCallNode callNode) {
+        return getCallSites().stream().filter(c -> c.getProfile().getCallNode() == callNode).findFirst().orElse(null);
+    }
+
+    public static final class InliningDecision extends ContextSensitiveInlining implements Comparable<InliningDecision> {
+
+        private final OptimizedCallTarget target;
+        private final TruffleInliningProfile profile;
+        private boolean inline;
+
+        public InliningDecision(OptimizedCallTarget target, TruffleInliningProfile profile, List<InliningDecision> children) {
+            super(children);
+            this.target = target;
+            this.profile = profile;
+        }
+
+        public OptimizedCallTarget getTarget() {
+            return target;
+        }
+
+        public void setInline(boolean inline) {
+            this.inline = inline;
+        }
+
+        public boolean isInline() {
+            return inline;
+        }
+
+        public TruffleInliningProfile getProfile() {
+            return profile;
+        }
+
+        public int compareTo(InliningDecision o) {
+            return Double.compare(o.getProfile().getScore(), getProfile().getScore());
+        }
+
+        public boolean isSameAs(InliningDecision other) {
+            if (getTarget() != other.getTarget()) {
+                return false;
+            } else if (isInline() != other.isInline()) {
+                return false;
+            } else if (!isInline()) {
+                assert !other.isInline();
+                return true;
+            } else {
+                Iterator<InliningDecision> i1 = iterator();
+                Iterator<InliningDecision> i2 = other.iterator();
+                while (i1.hasNext() && i2.hasNext()) {
+                    if (!i1.next().isSameAs(i2.next())) {
+                        return false;
+                    }
+                }
+                return !i1.hasNext() && !i2.hasNext();
+            }
+        }
+
+    }
+
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultInliningPolicy.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultInliningPolicy.java	Fri Oct 03 13:48:58 2014 +0200
@@ -40,15 +40,15 @@
             return false;
         }
 
-        if (profile.isForced()) {
-            return true;
-        }
-
         if (currentNodeCount + profile.getDeepNodeCount() > TruffleInliningMaxCallerSize.getValue()) {
             profile.setFailedReason(REASON_MAXIMUM_TOTAL_NODE_COUNT);
             return false;
         }
 
+        if (profile.isForced()) {
+            return true;
+        }
+
         int cappedCallSites = Math.min(Math.max(profile.getCallSites(), 1), 10);
         if (profile.getDeepNodeCount() * cappedCallSites > TruffleInliningMaxCallerSize.getValue()) {
             profile.setFailedReason(REASON_MAXIMUM_NODE_COUNT);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Fri Oct 03 13:48:58 2014 +0200
@@ -26,11 +26,14 @@
 import static com.oracle.graal.truffle.TruffleCompilerOptions.*;
 
 import java.io.*;
+import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.atomic.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.truffle.ContextSensitiveInlining.InliningDecision;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.frame.*;
@@ -58,9 +61,13 @@
 
     private final RootNode rootNode;
 
+    /* Experimental fields for new splitting. */
     private final Map<TruffleStamp, OptimizedCallTarget> splitVersions = new HashMap<>();
     private TruffleStamp argumentStamp = DefaultTruffleStamp.getInstance();
 
+    /* Experimental field for context sensitive inlining. */
+    private ContextSensitiveInlining inliningDecision;
+
     public final RootNode getRootNode() {
         return rootNode;
     }
@@ -121,7 +128,7 @@
         return doInvoke(args);
     }
 
-    public Object callDirect(Object... args) {
+    public final Object callDirect(Object... args) {
         profileArguments(args);
         Object result = doInvoke(args);
         Class<?> klass = profiledReturnType;
@@ -131,6 +138,14 @@
         return result;
     }
 
+    public final Object callInlined(Object... arguments) {
+        if (CompilerDirectives.inInterpreter()) {
+            compilationProfile.reportInlinedCall();
+        }
+        VirtualFrame frame = createFrame(getRootNode().getFrameDescriptor(), arguments);
+        return callProxy(frame);
+    }
+
     @ExplodeLoop
     private void profileArguments(Object[] args) {
         if (profiledArgumentTypesAssumption == null) {
@@ -204,7 +219,32 @@
             // We come here from compiled code (i.e., we have been inlined).
         }
 
-        return callRoot(args);
+        Object[] args1 = args;
+        if (this.profiledArgumentTypesAssumption != null && CompilerDirectives.inCompiledCode() && profiledArgumentTypesAssumption.isValid()) {
+            args1 = CompilerDirectives.unsafeCast(castArrayFixedLength(args1, profiledArgumentTypes.length), Object[].class, true, true);
+            if (TruffleArgumentTypeSpeculation.getValue()) {
+                args1 = castArguments(args1);
+            }
+        }
+        VirtualFrame frame = createFrame(getRootNode().getFrameDescriptor(), args1);
+        Object result = callProxy(frame);
+
+        // Profile call return type
+        if (profiledReturnTypeAssumption == null) {
+            if (TruffleReturnTypeSpeculation.getValue()) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                profiledReturnType = (result == null ? null : result.getClass());
+                profiledReturnTypeAssumption = runtime.createAssumption("Profiled Return Type");
+            }
+        } else if (profiledReturnType != null) {
+            if (result == null || profiledReturnType != result.getClass()) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                profiledReturnType = null;
+                profiledReturnTypeAssumption.invalidate();
+            }
+        }
+
+        return result;
     }
 
     @Override
@@ -241,6 +281,26 @@
         }
     }
 
+    public ContextSensitiveInlining getInliningDecision() {
+        return inliningDecision;
+    }
+
+    public void setInliningDecision(ContextSensitiveInlining inliningDecision) {
+        this.inliningDecision = inliningDecision;
+    }
+
+    public boolean isInlined(List<OptimizedDirectCallNode> callNodeTrace) {
+        if (TruffleCompilerOptions.TruffleContextSensitiveInlining.getValue()) {
+            if (inliningDecision == null) {
+                return false;
+            } else {
+                return inliningDecision.isInlined(callNodeTrace);
+            }
+        } else {
+            return callNodeTrace.get(callNodeTrace.size() - 1).isInlined();
+        }
+    }
+
     private void cancelInstalledTask(Node oldNode, Node newNode, CharSequence reason) {
         if (this.runtime.cancelInstalledTask(this)) {
             logOptimizingUnqueued(this, oldNode, newNode, reason);
@@ -275,6 +335,9 @@
     public void compilationFinished(Throwable t) {
         if (t == null) {
             // Compilation was successful.
+            if (inliningDecision != null) {
+                dequeueInlinedCallSites(inliningDecision);
+            }
         } else {
             compilationPolicy.recordCompilationFailure(t);
 
@@ -291,6 +354,18 @@
         }
     }
 
+    private void dequeueInlinedCallSites(ContextSensitiveInlining parentDecision) {
+        for (InliningDecision decision : parentDecision) {
+            if (decision.isInline()) {
+                OptimizedCallTarget target = decision.getProfile().getCallNode().getCurrentCallTarget();
+                if (runtime.cancelInstalledTask(target)) {
+                    logOptimizingUnqueued(target, null, null, "Inlining caller compiled.");
+                }
+                dequeueInlinedCallSites(decision);
+            }
+        }
+    }
+
     protected final Object callProxy(VirtualFrame frame) {
         try {
             return getRootNode().execute(frame);
@@ -336,16 +411,8 @@
         return compilationProfile;
     }
 
-    public final Object callInlined(Object[] arguments) {
-        if (CompilerDirectives.inInterpreter()) {
-            compilationProfile.reportInlinedCall();
-        }
-        VirtualFrame frame = createFrame(getRootNode().getFrameDescriptor(), arguments);
-        return callProxy(frame);
-    }
-
     public final void performInlining() {
-        if (!TruffleFunctionInlining.getValue()) {
+        if (!TruffleFunctionInlining.getValue() || TruffleContextSensitiveInlining.getValue()) {
             return;
         }
         if (inliningPerformed) {
@@ -371,36 +438,6 @@
         }
     }
 
-    public final Object callRoot(Object[] originalArguments) {
-        Object[] args = originalArguments;
-        if (this.profiledArgumentTypesAssumption != null && CompilerDirectives.inCompiledCode() && profiledArgumentTypesAssumption.isValid()) {
-            args = CompilerDirectives.unsafeCast(castArrayFixedLength(args, profiledArgumentTypes.length), Object[].class, true, true);
-            if (TruffleArgumentTypeSpeculation.getValue()) {
-                args = castArguments(args);
-            }
-        }
-
-        VirtualFrame frame = createFrame(getRootNode().getFrameDescriptor(), args);
-        Object result = callProxy(frame);
-
-        // Profile call return type
-        if (profiledReturnTypeAssumption == null) {
-            if (TruffleReturnTypeSpeculation.getValue()) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                profiledReturnType = (result == null ? null : result.getClass());
-                profiledReturnTypeAssumption = Truffle.getRuntime().createAssumption("Profiled Return Type");
-            }
-        } else if (profiledReturnType != null) {
-            if (result == null || profiledReturnType != result.getClass()) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                profiledReturnType = null;
-                profiledReturnTypeAssumption.invalidate();
-            }
-        }
-
-        return result;
-    }
-
     @ExplodeLoop
     private Object[] castArguments(Object[] originalArguments) {
         Object[] castArguments = new Object[profiledArgumentTypes.length];
@@ -418,6 +455,10 @@
         return new FrameWithoutBoxing(descriptor, args);
     }
 
+    public List<OptimizedDirectCallNode> getCallNodes() {
+        return NodeUtil.findAllNodeInstances(getRootNode(), OptimizedDirectCallNode.class);
+    }
+
     @Override
     public void reportLoopCount(int count) {
         compilationProfile.reportLoopCount(count);
@@ -437,4 +478,20 @@
 
     }
 
+    public static Method getCallDirectMethod() {
+        try {
+            return OptimizedCallTarget.class.getDeclaredMethod("callDirect", Object[].class);
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new GraalInternalError(e);
+        }
+    }
+
+    public static Method getCallInlinedMethod() {
+        try {
+            return OptimizedCallTarget.class.getDeclaredMethod("callInlined", Object[].class);
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new GraalInternalError(e);
+        }
+    }
+
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java	Fri Oct 03 13:48:58 2014 +0200
@@ -28,6 +28,7 @@
 import java.util.*;
 
 import com.oracle.graal.debug.*;
+import com.oracle.graal.truffle.ContextSensitiveInlining.InliningDecision;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.nodes.NodeUtil.NodeCountFilter;
 
@@ -53,6 +54,29 @@
     private OptimizedCallTargetLog() {
     }
 
+    public static void logInliningDecision(OptimizedCallTarget target) {
+        ContextSensitiveInlining inlining = target.getInliningDecision();
+        if (!TraceTruffleInlining.getValue() || inlining == null) {
+            return;
+        }
+
+        logInliningStart(target);
+        logInliningDecisionRecursive(inlining, 1);
+        logInliningDone(target);
+    }
+
+    private static void logInliningDecisionRecursive(ContextSensitiveInlining result, int depth) {
+        for (InliningDecision decision : result) {
+            TruffleInliningProfile profile = decision.getProfile();
+            boolean inlined = decision.isInline();
+            String msg = inlined ? "inline success" : "inline failed";
+            logInlinedImpl(msg, decision.getProfile().getCallNode(), profile, depth);
+            if (inlined) {
+                logInliningDecisionRecursive(decision, depth + 1);
+            }
+        }
+    }
+
     public static void logInliningDecision(TruffleInliningDecision result) {
         if (!TraceTruffleInlining.getValue()) {
             return;
@@ -119,7 +143,6 @@
 
     private static void logInlinedImpl(String status, OptimizedDirectCallNode callNode, TruffleInliningProfile profile, int depth) {
         Map<String, Object> properties = new LinkedHashMap<>();
-        addASTSizeProperty(callNode.getCurrentCallTarget(), properties);
         if (profile != null) {
             properties.putAll(profile.getDebugProperties());
         }
@@ -224,20 +247,31 @@
     }
 
     public static void addASTSizeProperty(OptimizedCallTarget target, Map<String, Object> properties) {
-        int polymorphicCount = NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() {
-            public boolean isCounted(Node node) {
-                return node.getCost() == NodeCost.POLYMORPHIC;
-            }
-        }, true);
+        if (TruffleContextSensitiveInlining.getValue() && target.getInliningDecision() != null) {
+            int deepCount = target.getInliningDecision().getCallSites().stream().filter(callSite -> callSite.isInline()).mapToInt(callSite -> callSite.getProfile().getDeepNodeCount()).sum();
+            long nodeCount = OptimizedCallUtils.countNonTrivialNodes(target, false);
+            properties.put("ASTSize", String.format("%5d/%5d", nodeCount, nodeCount + deepCount));
+        } else {
+            int polymorphicCount = NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() {
+                public boolean isCounted(Node node) {
+                    return node.getCost() == NodeCost.POLYMORPHIC;
+                }
+            }, true);
 
-        int megamorphicCount = NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() {
-            public boolean isCounted(Node node) {
-                return node.getCost() == NodeCost.MEGAMORPHIC;
-            }
-        }, true);
+            int megamorphicCount = NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() {
+                public boolean isCounted(Node node) {
+                    return node.getCost() == NodeCost.MEGAMORPHIC;
+                }
+            }, true);
 
-        String value = String.format("%4d (%d/%d)", OptimizedCallUtils.countNonTrivialNodes(target, true), polymorphicCount, megamorphicCount);
-        properties.put("ASTSize", value);
+            String value = String.format("%4d (%d/%d)", OptimizedCallUtils.countNonTrivialNodes(target, true), polymorphicCount, megamorphicCount);
+            properties.put("ASTSize", value);
+        }
+
+    }
+
+    public static void logPerformanceWarning(String details, Map<String, Object> properties) {
+        log(0, "perf warn", details, properties);
     }
 
     static void log(int indent, String msg, String details, Map<String, Object> properties) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallUtils.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallUtils.java	Fri Oct 03 13:48:58 2014 +0200
@@ -32,19 +32,29 @@
 public class OptimizedCallUtils {
 
     public static int countCalls(OptimizedCallTarget target) {
-        return NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() {
-            public boolean isCounted(Node node) {
-                return node instanceof DirectCallNode;
-            }
-        }, true);
+        ContextSensitiveInlining inlining = target.getInliningDecision();
+        if (inlining != null) {
+            return inlining.countCalls();
+        } else {
+            return NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() {
+                public boolean isCounted(Node node) {
+                    return node instanceof DirectCallNode;
+                }
+            }, true);
+        }
     }
 
     public static int countCallsInlined(OptimizedCallTarget target) {
-        return NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() {
-            public boolean isCounted(Node node) {
-                return (node instanceof OptimizedDirectCallNode) && ((OptimizedDirectCallNode) node).isInlined();
-            }
-        }, true);
+        ContextSensitiveInlining inlining = target.getInliningDecision();
+        if (inlining != null) {
+            return inlining.countInlinedCalls();
+        } else {
+            return NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() {
+                public boolean isCounted(Node node) {
+                    return (node instanceof OptimizedDirectCallNode) && ((OptimizedDirectCallNode) node).isInlined();
+                }
+            }, true);
+        }
     }
 
     public static int countNonTrivialNodes(final OptimizedCallTarget target, final boolean inlined) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedDirectCallNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedDirectCallNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -57,7 +57,14 @@
         if (CompilerDirectives.inInterpreter()) {
             onInterpreterCall(arguments);
         }
-        Object result = callProxy(this, getCurrentCallTarget(), frame, arguments, inlined, true);
+        boolean isInlined;
+        if (TruffleCompilerOptions.TruffleContextSensitiveInlining.getValue()) {
+            /* Inlining done during partial evalulation. */
+            isInlined = false;
+        } else {
+            isInlined = this.inlined;
+        }
+        Object result = callProxy(this, getCurrentCallTarget(), frame, arguments, isInlined, true);
 
         if (CompilerDirectives.inInterpreter()) {
             afterInterpreterCall(result);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Fri Oct 03 13:48:58 2014 +0200
@@ -51,6 +51,7 @@
 import com.oracle.graal.phases.common.inlining.info.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
+import com.oracle.graal.truffle.ContextSensitiveInlining.InliningDecision;
 import com.oracle.graal.truffle.nodes.asserts.*;
 import com.oracle.graal.truffle.nodes.frame.*;
 import com.oracle.graal.truffle.nodes.frame.NewFrameNode.VirtualOnlyInstanceNode;
@@ -58,6 +59,9 @@
 import com.oracle.graal.virtual.phases.ea.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.Node.Child;
+import com.oracle.truffle.api.nodes.Node.Children;
+import static com.oracle.graal.truffle.OptimizedCallTargetLog.*;
 
 /**
  * Class performing the partial evaluation starting from the root node of an AST.
@@ -68,53 +72,45 @@
     private final CanonicalizerPhase canonicalizer;
     private Set<Constant> constantReceivers;
     private final TruffleCache truffleCache;
+    private final SnippetReflectionProvider snippetReflection;
+    private final ResolvedJavaMethod callDirectMethod;
+    private final ResolvedJavaMethod callSiteProxyMethod;
 
     public PartialEvaluator(Providers providers, TruffleCache truffleCache) {
         this.providers = providers;
         CustomCanonicalizer customCanonicalizer = new PartialEvaluatorCanonicalizer(providers.getMetaAccess(), providers.getConstantReflection());
         this.canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue(), customCanonicalizer);
+        this.snippetReflection = Graal.getRequiredCapability(SnippetReflectionProvider.class);
         this.truffleCache = truffleCache;
+        this.callDirectMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.getCallDirectMethod());
+        this.callSiteProxyMethod = providers.getMetaAccess().lookupJavaMethod(GraalFrameInstance.CallNodeFrame.METHOD);
     }
 
-    public StructuredGraph createGraph(final OptimizedCallTarget callTarget, final Assumptions assumptions) {
-        try (Scope s = Debug.scope("TruffleTree")) {
+    public StructuredGraph createGraph(final OptimizedCallTarget callTarget, final Assumptions assumptions, ContextSensitiveInlining inlining) {
+        if (TraceTruffleCompilationHistogram.getValue() || TraceTruffleCompilationDetails.getValue()) {
+            constantReceivers = new HashSet<>();
+        }
+
+        try (Scope c = Debug.scope("TruffleTree")) {
             Debug.dump(callTarget, "truffle tree");
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
-
-        if (TraceTruffleCompilationHistogram.getValue() || TraceTruffleCompilationDetails.getValue()) {
-            constantReceivers = new HashSet<>();
-        }
-
         final StructuredGraph graph = truffleCache.createRootGraph(callTarget.toString());
         assert graph != null : "no graph for root method";
 
         try (Scope s = Debug.scope("CreateGraph", graph); Indent indent = Debug.logAndIndent("createGraph %s", graph.method())) {
-
-            // Replace thisNode with constant.
-            ParameterNode thisNode = graph.getParameter(0);
-
-            /*
-             * Converting the call target to a Constant using the SnippetReflectionProvider is a
-             * workaround, we should think about a better solution. Since object constants are
-             * VM-specific, only the hosting VM knows how to do the conversion.
-             */
-            SnippetReflectionProvider snippetReflection = Graal.getRequiredCapability(SnippetReflectionProvider.class);
-            thisNode.replaceAndDelete(ConstantNode.forConstant(snippetReflection.forObject(callTarget), providers.getMetaAccess(), graph));
-
             // Canonicalize / constant propagate.
             PhaseContext baseContext = new PhaseContext(providers, assumptions);
-            canonicalizer.apply(graph, baseContext);
 
-            // Intrinsify methods.
-            new IncrementalCanonicalizerPhase<>(canonicalizer, new ReplaceIntrinsicsPhase(providers.getReplacements())).apply(graph, baseContext);
+            injectConstantCallTarget(graph, callTarget, baseContext);
 
-            Debug.dump(graph, "Before inlining");
+            Debug.dump(graph, "Before expansion");
 
-            // Make sure frame does not escape.
             expandTree(graph, assumptions);
 
+            expandDirectCalls(graph, assumptions, inlining != null ? new TruffleInliningCache() : null, inlining);
+
             if (Thread.currentThread().isInterrupted()) {
                 return null;
             }
@@ -170,6 +166,7 @@
                     }
                 }
             }
+
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
@@ -177,6 +174,49 @@
         return graph;
     }
 
+    private void expandDirectCalls(StructuredGraph graph, Assumptions assumptions, TruffleInliningCache inliningCache, ContextSensitiveInlining inlining) {
+        if (inlining == null) {
+            return;
+        }
+        PhaseContext phaseContext = new PhaseContext(providers, assumptions);
+        TruffleExpansionLogger expansionLogger = new TruffleExpansionLogger(providers, graph);
+
+        for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.class).snapshot()) {
+            StructuredGraph inlineGraph = parseDirectCallGraph(phaseContext, assumptions, inliningCache, inlining, methodCallTargetNode);
+
+            if (inlineGraph != null) {
+                expandTreeInline(graph, phaseContext, expansionLogger, methodCallTargetNode, inlineGraph);
+            }
+        }
+        // non inlined direct calls need to be expanded until TruffleCallBoundary.
+        expandTree(graph, assumptions);
+        assert noDirectCallsLeft(graph);
+    }
+
+    private boolean noDirectCallsLeft(StructuredGraph graph) {
+        for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.class).snapshot()) {
+            if (methodCallTargetNode.targetMethod().equals(callDirectMethod)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void injectConstantCallTarget(final StructuredGraph graph, final OptimizedCallTarget constantCallTarget, PhaseContext baseContext) {
+        ParameterNode thisNode = graph.getParameter(0);
+
+        /*
+         * Converting the call target to a Constant using the SnippetReflectionProvider is a
+         * workaround, we should think about a better solution. Since object constants are
+         * VM-specific, only the hosting VM knows how to do the conversion.
+         */
+        thisNode.replaceAndDelete(ConstantNode.forConstant(snippetReflection.forObject(constantCallTarget), providers.getMetaAccess(), graph));
+
+        canonicalizer.apply(graph, baseContext);
+
+        new IncrementalCanonicalizerPhase<>(canonicalizer, new ReplaceIntrinsicsPhase(providers.getReplacements())).apply(graph, baseContext);
+    }
+
     private void createHistogram() {
         DebugHistogram histogram = Debug.createHistogram("Expanded Truffle Nodes");
         for (Constant c : constantReceivers) {
@@ -219,9 +259,10 @@
                             changed = changedInIteration = true;
                             continue;
                         }
+                        StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod());
 
-                        StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod());
-                        if (inlineGraph == null && !methodCallTargetNode.targetMethod().isNative() && methodCallTargetNode.targetMethod().canBeInlined()) {
+                        ResolvedJavaMethod targetMethod = methodCallTargetNode.targetMethod();
+                        if (inlineGraph == null && !targetMethod.isNative() && targetMethod.canBeInlined()) {
                             inlineGraph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), assumptions, phaseContext);
                         }
 
@@ -236,6 +277,7 @@
                     throw new BailoutException("Truffle compilation is exceeding maximum node count: " + graph.getNodeCount());
                 }
             }
+
         } while (changedInIteration);
 
         if (TraceTruffleExpansion.getValue()) {
@@ -244,20 +286,113 @@
         return changed;
     }
 
+    private StructuredGraph parseDirectCallGraph(PhaseContext phaseContext, Assumptions assumptions, TruffleInliningCache inliningCache, ContextSensitiveInlining inlining,
+                    MethodCallTargetNode methodCallTargetNode) {
+        OptimizedDirectCallNode callNode = resolveConstantCallNode(methodCallTargetNode);
+        if (callNode == null) {
+            return null;
+        }
+
+        InliningDecision decision = inlining.findByCall(callNode);
+        if (decision == null) {
+            if (TruffleCompilerOptions.PrintTrufflePerformanceWarnings.getValue()) {
+                logPerformanceWarning(String.format("%s '%s' is reached using partial evaluation but it is not reachable in the Truffle AST.  Did you miss @%s or @%s annotation on a node field?. ",
+                                DirectCallNode.class.getSimpleName(), callNode, Child.class.getSimpleName(), Children.class.getSimpleName()), callNode.getRootNode().getDebugProperties());
+            }
+            return null;
+        }
+
+        assert decision.getProfile().getCallNode() == callNode;
+
+        OptimizedCallTarget currentTarget = decision.getProfile().getCallNode().getCurrentCallTarget();
+        if (decision.getTarget() != currentTarget) {
+            if (TruffleCompilerOptions.PrintTrufflePerformanceWarnings.getValue()) {
+                logPerformanceWarning(
+                                String.format("CallTarget '%s' changed to '%s' during compilation for call node '%s'. Call node was not inlined.", decision.getTarget(), currentTarget, callNode), null);
+
+            }
+            return null;
+        }
+
+        StructuredGraph graph;
+        if (decision.isInline()) {
+            if (inliningCache == null) {
+                graph = createInlineGraph(phaseContext, assumptions, null, decision);
+            } else {
+                graph = inliningCache.getCachedGraph(phaseContext, assumptions, decision);
+            }
+            decision.getProfile().setGraalDeepNodeCount(graph.getNodeCount());
+        } else {
+            graph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), assumptions, phaseContext);
+        }
+
+        return graph;
+    }
+
+    private StructuredGraph createInlineGraph(PhaseContext phaseContext, Assumptions assumptions, TruffleInliningCache cache, InliningDecision decision) {
+        OptimizedCallTarget target = decision.getTarget();
+        StructuredGraph inlineGraph = truffleCache.createInlineGraph(target.toString());
+        injectConstantCallTarget(inlineGraph, decision.getTarget(), phaseContext);
+        expandTree(inlineGraph, assumptions);
+        expandDirectCalls(inlineGraph, assumptions, cache, decision);
+        return inlineGraph;
+    }
+
+    private OptimizedDirectCallNode resolveConstantCallNode(MethodCallTargetNode methodCallTargetNode) {
+        if (!methodCallTargetNode.targetMethod().equals(callDirectMethod)) {
+            return null;
+        }
+
+        Invoke invoke = methodCallTargetNode.invoke();
+        if (invoke == null) {
+            return null;
+        }
+
+        FrameState directCallState = invoke.stateAfter();
+        while (directCallState != null && directCallState.method() != callSiteProxyMethod) {
+            directCallState = directCallState.outerFrameState();
+        }
+
+        if (directCallState == null) {
+            // not a direct call. May be indirect call.
+            return null;
+        }
+
+        if (directCallState.values().isEmpty()) {
+            throw new AssertionError(String.format("Frame state of method '%s' is invalid.", callDirectMethod.toString()));
+        }
+
+        ValueNode node = directCallState.values().get(0);
+        if (!node.isConstant()) {
+            throw new AssertionError(String.format("Method argument for method '%s' is not constant.", callDirectMethod.toString()));
+        }
+
+        Constant constantCallNode = node.asConstant();
+        Object value = snippetReflection.asObject(constantCallNode);
+
+        if (!(value instanceof OptimizedDirectCallNode)) {
+            // might be an indirect call.
+            return null;
+        }
+
+        return (OptimizedDirectCallNode) value;
+    }
+
     private void expandTreeInline(StructuredGraph graph, PhaseContext phaseContext, TruffleExpansionLogger expansionLogger, MethodCallTargetNode methodCallTargetNode, StructuredGraph inlineGraph) {
-        try (Indent indent = Debug.logAndIndent("inline graph %s", methodCallTargetNode.targetMethod())) {
+        try (Indent indent = Debug.logAndIndent("expand graph %s", methodCallTargetNode.targetMethod())) {
             int nodeCountBefore = graph.getNodeCount();
             if (TraceTruffleExpansion.getValue()) {
                 expansionLogger.preExpand(methodCallTargetNode, inlineGraph);
             }
             List<Node> canonicalizedNodes = methodCallTargetNode.invoke().asNode().usages().snapshot();
+
             Map<Node, Node> inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false, canonicalizedNodes);
             if (TraceTruffleExpansion.getValue()) {
                 expansionLogger.postExpand(inlined);
             }
             if (Debug.isDumpEnabled()) {
                 int nodeCountAfter = graph.getNodeCount();
-                Debug.dump(graph, "After inlining %s %+d (%d)", methodCallTargetNode.targetMethod().toString(), nodeCountAfter - nodeCountBefore, nodeCountAfter);
+                Debug.dump(graph, "After expand %s %+d (%d)", methodCallTargetNode.targetMethod().toString(), nodeCountAfter - nodeCountBefore, nodeCountAfter);
             }
             AbstractInlineInfo.getInlinedParameterUsages(canonicalizedNodes, inlineGraph, inlined);
             canonicalizer.applyIncremental(graph, phaseContext, canonicalizedNodes);
@@ -325,4 +460,51 @@
         return sortedLoops;
     }
 
+    private final class TruffleInliningCache {
+
+        private final Map<CacheKey, StructuredGraph> cache;
+
+        public TruffleInliningCache() {
+            this.cache = new HashMap<>();
+        }
+
+        public StructuredGraph getCachedGraph(PhaseContext phaseContext, Assumptions assumptions, InliningDecision decision) {
+            CacheKey cacheKey = new CacheKey(decision);
+            StructuredGraph inlineGraph = cache.get(cacheKey);
+            if (inlineGraph == null) {
+                inlineGraph = createInlineGraph(phaseContext, assumptions, this, decision);
+                cache.put(cacheKey, inlineGraph);
+            }
+            return inlineGraph;
+        }
+
+        private final class CacheKey {
+
+            public final InliningDecision decision;
+
+            public CacheKey(InliningDecision decision) {
+                this.decision = decision;
+                /*
+                 * If decision.isInline() is not true CacheKey#hashCode does not match
+                 * CacheKey#equals
+                 */
+                assert decision.isInline();
+            }
+
+            @Override
+            public int hashCode() {
+                return decision.getTarget().hashCode();
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                if (!(obj instanceof CacheKey)) {
+                    return false;
+                }
+                CacheKey other = (CacheKey) obj;
+                return decision.isSameAs(other.decision);
+            }
+        }
+    }
+
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Fri Oct 03 13:48:58 2014 +0200
@@ -35,6 +35,8 @@
      */
     StructuredGraph createRootGraph(String name);
 
+    StructuredGraph createInlineGraph(String name);
+
     /**
      * Returns a cached graph for a method with given arguments.
      */
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Fri Oct 03 13:48:58 2014 +0200
@@ -56,7 +56,7 @@
 
     private final Providers providers;
     private final GraphBuilderConfiguration config;
-    private final GraphBuilderConfiguration configForRootGraph;
+    private final GraphBuilderConfiguration configForRoot;
     private final OptimisticOptimizations optimisticOptimizations;
 
     private final HashMap<List<Object>, StructuredGraph> cache = new HashMap<>();
@@ -69,12 +69,14 @@
     private final ResolvedJavaType controlFlowExceptionClass;
 
     private final ResolvedJavaMethod callBoundaryMethod;
+    private final ResolvedJavaMethod callInlinedMethod;
+
     private long counter;
 
-    public TruffleCacheImpl(Providers providers, GraphBuilderConfiguration config, GraphBuilderConfiguration configForRootGraph, OptimisticOptimizations optimisticOptimizations) {
+    public TruffleCacheImpl(Providers providers, GraphBuilderConfiguration config, GraphBuilderConfiguration configForRoot, OptimisticOptimizations optimisticOptimizations) {
         this.providers = providers;
         this.config = config;
-        this.configForRootGraph = configForRootGraph;
+        this.configForRoot = configForRoot;
         this.optimisticOptimizations = optimisticOptimizations;
 
         this.stringBuilderClass = providers.getMetaAccess().lookupJavaType(StringBuilder.class);
@@ -83,15 +85,22 @@
         this.controlFlowExceptionClass = providers.getMetaAccess().lookupJavaType(ControlFlowException.class);
 
         try {
-            callBoundaryMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("callRoot", Object[].class));
+            callBoundaryMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("callBoundary", Object[].class));
         } catch (NoSuchMethodException ex) {
             throw new RuntimeException(ex);
         }
+        this.callInlinedMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.getCallInlinedMethod());
+    }
+
+    public StructuredGraph createInlineGraph(String name) {
+        StructuredGraph graph = new StructuredGraph(name, callInlinedMethod);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), config, TruffleCompilerImpl.Optimizations).apply(graph);
+        return graph;
     }
 
     public StructuredGraph createRootGraph(String name) {
         StructuredGraph graph = new StructuredGraph(name, callBoundaryMethod);
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), configForRootGraph, TruffleCompilerImpl.Optimizations).apply(graph);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), configForRoot, TruffleCompilerImpl.Optimizations).apply(graph);
         return graph;
     }
 
@@ -183,6 +192,16 @@
                 }
             }
 
+            if (TruffleCompilerOptions.PrintTrufflePerformanceWarnings.getValue()) {
+                int warnNodeCount = TruffleCompilerOptions.TrufflePerformanceWarningGraalNodeCount.getValue();
+                if (graph.getNodeCount() > warnNodeCount) {
+                    Map<String, Object> map = new LinkedHashMap<>();
+                    map.put("nodeCount", graph.getNodeCount());
+                    map.put("method", method.toString());
+                    OptimizedCallTargetLog.logPerformanceWarning(String.format("Method on fast path contains more than %d graal nodes.", warnNodeCount), map);
+                }
+            }
+
             cache.put(key, graph);
             if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) {
                 TTY.println(String.format("[truffle] added to graph cache method %s with %d nodes.", method, graph.getNodeCount()));
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Fri Oct 03 13:48:58 2014 +0200
@@ -80,7 +80,6 @@
         ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess());
         GraphBuilderConfiguration eagerConfig = GraphBuilderConfiguration.getEagerDefault().withSkippedExceptionTypes(skippedExceptionTypes);
         this.config = GraphBuilderConfiguration.getDefault().withSkippedExceptionTypes(skippedExceptionTypes);
-
         this.truffleCache = new TruffleCacheImpl(providers, eagerConfig, config, TruffleCompilerImpl.Optimizations);
 
         this.partialEvaluator = new PartialEvaluator(providers, truffleCache);
@@ -122,8 +121,9 @@
 
         long timeCompilationStarted = System.nanoTime();
         Assumptions assumptions = new Assumptions(true);
+        ContextSensitiveInlining inlining = TruffleCompilerOptions.TruffleContextSensitiveInlining.getValue() ? new ContextSensitiveInlining(compilable, new DefaultInliningPolicy()) : null;
         try (TimerCloseable a = PartialEvaluationTime.start(); Closeable c = PartialEvaluationMemUse.start()) {
-            graph = partialEvaluator.createGraph(compilable, assumptions);
+            graph = partialEvaluator.createGraph(compilable, assumptions, inlining);
         }
 
         if (Thread.currentThread().isInterrupted()) {
@@ -136,13 +136,15 @@
         long timeCompilationFinished = System.nanoTime();
         int nodeCountLowered = graph.getNodeCount();
 
-        if (Thread.currentThread().isInterrupted()) {
-            return;
+        compilable.setInliningDecision(inlining);
+
+        if (TraceTruffleInlining.getValue() && inlining != null) {
+            OptimizedCallTargetLog.logInliningDecision(compilable);
         }
-
         if (TraceTruffleCompilation.getValue()) {
             printTruffleCompilation(compilable, timeCompilationStarted, timePartialEvaluationFinished, nodeCountPartialEval, compilationResult, timeCompilationFinished, nodeCountLowered);
         }
+
     }
 
     private static void printTruffleCompilation(final OptimizedCallTarget compilable, long timeCompilationStarted, long timePartialEvaluationFinished, int nodeCountPartialEval,
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Fri Oct 03 13:48:58 2014 +0200
@@ -53,6 +53,10 @@
     public static final OptionValue<Integer> TruffleReplaceReprofileCount = new OptionValue<>(10);
     @Option(help = "Enable automatic inlining of call targets")
     public static final OptionValue<Boolean> TruffleFunctionInlining = new OptionValue<>(true);
+    @Option(help = "Experimental: Enable context senstive inlining decisions.")
+    public static final StableOptionValue<Boolean> TruffleContextSensitiveInlining = new StableOptionValue<>(false);
+    @Option(help = "Experimental: Enable an expansion cache per CallTarget. Only functionable with TruffleContextSensitiveInlining enabled.")
+    public static final OptionValue<Boolean> TruffleCallTargetExpansionCache = new OptionValue<>(true);
     @Option(help = "Maximum number of Graal IR nodes during partial evaluation")
     public static final OptionValue<Integer> TruffleGraphMaxNodes = new OptionValue<>(200000);
     @Option(help = "Stop inlining if caller's cumulative tree size would exceed this limit")
@@ -64,6 +68,9 @@
     @Option(help = "Allow inlining of less hot candidates if tree size is small")
     public static final OptionValue<Integer> TruffleInliningTrivialSize = new OptionValue<>(10);
 
+    @Option(help = "Defines the number of graal nodes that triggers a performance warning.")
+    public static final OptionValue<Integer> TrufflePerformanceWarningGraalNodeCount = new OptionValue<>(1000);
+
     @Option(help = "Enable call target splitting")
     public static final OptionValue<Boolean> TruffleSplitting = new OptionValue<>(true);
     @Option(help = "Experimental: Enable the new version of truffle splitting.")
@@ -95,6 +102,8 @@
     public static final OptionValue<Boolean> TruffleArgumentTypeSpeculation = new StableOptionValue<>(true);
 
     // tracing
+    @Option(help = "Prints potential performance problems of the guest language implementation.")
+    public static final OptionValue<Boolean> PrintTrufflePerformanceWarnings = new OptionValue<>(false);
     @Option(help = "")
     public static final OptionValue<Boolean> TraceTruffleCompilation = new OptionValue<>(false);
     @Option(help = "")
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java	Fri Oct 03 13:48:58 2014 +0200
@@ -137,15 +137,16 @@
                 className = className.substring(lastIndex + 1, className.length());
             }
 
-            lastIndex = className.lastIndexOf('$');
-            if (lastIndex != -1) {
-                className = className.substring(lastIndex + 1, className.length());
-            }
+            className = extractInnerClassName(className);
 
             String constantType = "";
             if (targetReceiverType != null) {
-                if (!targetReceiverType.getName().equals(className)) {
-                    constantType = "<" + targetReceiverType.getName() + ">";
+                String javaName = targetReceiverType.toJavaName(false);
+
+                javaName = extractInnerClassName(javaName);
+
+                if (!javaName.equals(className)) {
+                    constantType = "<" + javaName + ">";
                 }
             }
 
@@ -164,6 +165,14 @@
             }
         }
 
+        private static String extractInnerClassName(String className) {
+            int lastIndex = className.lastIndexOf('$');
+            if (lastIndex != -1) {
+                return className.substring(lastIndex + 1, className.length());
+            }
+            return className;
+        }
+
         private static String formatSource(StackTraceElement e) {
             if (e == null) {
                 return "";
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java	Fri Oct 03 13:48:58 2014 +0200
@@ -110,7 +110,7 @@
         return policy;
     }
 
-    private static double calculateFrequency(OptimizedCallTarget target, OptimizedDirectCallNode ocn) {
+    public static double calculateFrequency(OptimizedCallTarget target, OptimizedDirectCallNode ocn) {
         return (double) Math.max(1, ocn.getCallCount()) / (double) Math.max(1, target.getCompilationProfile().getCallCount());
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Fri Oct 03 13:48:58 2014 +0200
@@ -33,6 +33,7 @@
     private final boolean recursiveCall;
     private final TruffleInliningDecision recursiveResult;
 
+    private int graalDeepNodeCount = -1;
     private String failedReason;
     private int queryIndex = -1;
     private double score;
@@ -104,11 +105,23 @@
 
     public Map<String, Object> getDebugProperties() {
         Map<String, Object> properties = new LinkedHashMap<>();
-        properties.put("nodeCount", String.format("%5d/%5d", deepNodeCount, nodeCount));
-        properties.put("frequency", frequency);
+        properties.put("ASTSize", String.format("%5d/%5d", nodeCount, deepNodeCount));
+        properties.put("frequency", String.format("%8.4f", getFrequency()));
         properties.put("score", String.format("%8.4f", getScore()));
         properties.put(String.format("index=%3d, force=%s, callSites=%2d", queryIndex, (isForced() ? "Y" : "N"), getCallSites()), "");
+        if (graalDeepNodeCount != -1) {
+            properties.put("graalCount", String.format("%5d", graalDeepNodeCount));
+        }
         properties.put("reason", failedReason);
         return properties;
     }
+
+    public void setGraalDeepNodeCount(int graalDeepNodeCount) {
+        this.graalDeepNodeCount = graalDeepNodeCount;
+    }
+
+    public int getGraalDeepNodeCount() {
+        return graalDeepNodeCount;
+    }
+
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -30,7 +30,7 @@
 @NodeInfo
 public class NeverPartOfCompilationNode extends MacroStateSplitNode implements IterableNodeType {
 
-    private final String message;
+    protected final String message;
 
     public static NeverPartOfCompilationNode create(Invoke invoke) {
         return USE_GENERATED_NODES ? new NeverPartOfCompilationNodeGen(invoke) : new NeverPartOfCompilationNode(invoke);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -106,13 +106,13 @@
     @NodeInfo
     public static class VirtualOnlyInstanceNode extends VirtualInstanceNode {
 
-        private boolean allowMaterialization;
+        protected boolean allowMaterialization;
 
         public static VirtualOnlyInstanceNode create(ResolvedJavaType type, ResolvedJavaField[] fields) {
             return USE_GENERATED_NODES ? new NewFrameNode_VirtualOnlyInstanceNodeGen(type, fields) : new VirtualOnlyInstanceNode(type, fields);
         }
 
-        VirtualOnlyInstanceNode(ResolvedJavaType type, ResolvedJavaField[] fields) {
+        protected VirtualOnlyInstanceNode(ResolvedJavaType type, ResolvedJavaField[] fields) {
             super(type, fields, false);
         }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -46,7 +46,7 @@
     @Input ValueNode offset;
     @Input ValueNode condition;
     @Input ValueNode location;
-    private final Kind accessKind;
+    protected final Kind accessKind;
 
     public static CustomizedUnsafeLoadFinalNode create(ValueNode object, ValueNode offset, ValueNode condition, ValueNode location, Kind accessKind) {
         return USE_GENERATED_NODES ? new CustomizedUnsafeLoadFinalNodeGen(object, offset, condition, location, accessKind) : new CustomizedUnsafeLoadFinalNode(object, offset, condition, location,
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -67,10 +67,10 @@
                 replaceAtUsages(objectArgument);
                 GraphUtil.removeFixedWithUnusedInputs(this);
             } else {
-                Stamp stamp = StampFactory.declared(lookupJavaType, nonNullArgument.asConstant().asInt() != 0, true);
+                Stamp piStamp = StampFactory.declared(lookupJavaType, nonNullArgument.asConstant().asInt() != 0, true);
                 ConditionAnchorNode valueAnchorNode = graph().add(
                                 ConditionAnchorNode.create(CompareNode.createCompareNode(graph(), Condition.EQ, conditionArgument, ConstantNode.forBoolean(true, graph()))));
-                PiNode piCast = graph().unique(PiNode.create(objectArgument, stamp, valueAnchorNode));
+                PiNode piCast = graph().unique(PiNode.create(objectArgument, piStamp, valueAnchorNode));
                 replaceAtUsages(piCast);
                 graph().replaceFixedWithFixed(this, valueAnchorNode);
             }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Fri Oct 03 13:48:58 2014 +0200
@@ -49,7 +49,7 @@
     private final Map<Loop<Block>, GraphEffectList> loopMergeEffects = newIdentityMap();
     private final Map<LoopBeginNode, BlockT> loopEntryStates = newNodeIdentityMap();
 
-    private boolean changed;
+    protected boolean changed;
 
     public EffectsClosure(SchedulePhase schedule, ControlFlowGraph cfg) {
         this.schedule = schedule;
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/SnippetLocationNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/SnippetLocationNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -46,7 +46,7 @@
 @NodeInfo
 public class SnippetLocationNode extends LocationNode implements Canonicalizable {
 
-    private final SnippetReflectionProvider snippetReflection;
+    protected final SnippetReflectionProvider snippetReflection;
 
     @Input ValueNode valueKind;
     @Input(InputType.Association) ValueNode locationIdentity;
@@ -64,7 +64,7 @@
                         displacement);
     }
 
-    SnippetLocationNode(@InjectedNodeParameter SnippetReflectionProvider snippetReflection, ValueNode locationIdentity, ValueNode kind, ValueNode displacement) {
+    protected SnippetLocationNode(@InjectedNodeParameter SnippetReflectionProvider snippetReflection, ValueNode locationIdentity, ValueNode kind, ValueNode displacement) {
         this(snippetReflection, locationIdentity, kind, displacement, null, null);
     }
 
@@ -74,7 +74,7 @@
                         locationIdentity, kind, displacement, index, indexScaling);
     }
 
-    SnippetLocationNode(SnippetReflectionProvider snippetReflection, ValueNode locationIdentity, ValueNode kind, ValueNode displacement, ValueNode index, ValueNode indexScaling) {
+    protected SnippetLocationNode(SnippetReflectionProvider snippetReflection, ValueNode locationIdentity, ValueNode kind, ValueNode displacement, ValueNode index, ValueNode indexScaling) {
         super(StampFactory.object());
         this.snippetReflection = snippetReflection;
         this.valueKind = kind;
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Fri Oct 03 13:48:58 2014 +0200
@@ -54,7 +54,7 @@
         return USE_GENERATED_NODES ? new WordCastNodeGen(stamp, input) : new WordCastNode(stamp, input);
     }
 
-    WordCastNode(Stamp stamp, ValueNode input) {
+    protected WordCastNode(Stamp stamp, ValueNode input) {
         super(stamp);
         this.input = input;
     }
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/GeneratedBy.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/GeneratedBy.java	Fri Oct 03 13:48:58 2014 +0200
@@ -27,7 +27,7 @@
 import java.lang.annotation.*;
 
 /**
- * Marks a type to be generated by another class or a method.
+ * Marks a type as being generated based on another class or method.
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.TYPE})
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/DSLShare.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/DSLShare.java	Fri Oct 03 13:48:58 2014 +0200
@@ -25,6 +25,7 @@
 package com.oracle.truffle.api.dsl.internal;
 
 import java.util.*;
+import java.util.concurrent.*;
 
 import com.oracle.truffle.api.nodes.*;
 
@@ -50,19 +51,23 @@
         return containsClass(newNode.getMetadata0().getIncludes(), oldNode);
     }
 
-    public static <T extends Node & DSLNode> T rewrite(Node thisNode, T newNode, String message) {
-        assert newNode != null;
-        if (getNext(thisNode) != null || getPrevious(thisNode) != null) {
-            // already polymorphic -> append
-            return appendPolymorphic(findUninitialized(thisNode), newNode);
-        } else if (includes(thisNode, newNode)) {
-            // included -> remains monomorphic
-            newNode.adoptChildren0(thisNode, null);
-            return thisNode.replace(newNode, message);
-        } else {
-            // goto polymorphic
-            return null;
-        }
+    public static <T extends Node & DSLNode> T rewrite(final Node thisNode, final T newNode, final String message) {
+        return thisNode.atomic(new Callable<T>() {
+            public T call() {
+                assert newNode != null;
+                if (getNext(thisNode) != null || getPrevious(thisNode) != null) {
+                    // already polymorphic -> append
+                    return appendPolymorphic(findUninitialized(thisNode), newNode);
+                } else if (includes(thisNode, newNode)) {
+                    // included -> remains monomorphic
+                    newNode.adoptChildren0(thisNode, null);
+                    return thisNode.replace(newNode, message);
+                } else {
+                    // goto polymorphic
+                    return null;
+                }
+            }
+        });
     }
 
     @SuppressWarnings("unchecked")
@@ -86,37 +91,47 @@
         return cur;
     }
 
-    public static <T extends Node & DSLNode> T rewriteUninitialized(Node uninitialized, T newNode) {
-        Node prev = getPrevious(uninitialized);
-        if (prev == null) {
-            newNode.adoptChildren0(uninitialized, null);
-            return uninitialized.replace(newNode, "Uninitialized monomorphic");
-        } else {
-            return appendPolymorphic(uninitialized, newNode);
-        }
+    public static <T extends Node & DSLNode> T rewriteUninitialized(final Node uninitialized, final T newNode) {
+        return uninitialized.atomic(new Callable<T>() {
+            public T call() {
+                Node prev = getPrevious(uninitialized);
+                if (prev == null) {
+                    newNode.adoptChildren0(uninitialized, null);
+                    return uninitialized.replace(newNode, "Uninitialized monomorphic");
+                } else {
+                    return appendPolymorphic(uninitialized, newNode);
+                }
+            }
+        });
+
     }
 
-    public static <T extends Node & DSLNode> T rewriteToPolymorphic(Node oldNode, DSLNode uninitializedDSL, T polymorphic, DSLNode currentCopy, DSLNode newNodeDSL, String message) {
-        assert getNext(oldNode) == null;
-        assert getPrevious(oldNode) == null;
-        assert newNodeDSL != null;
+    public static <T extends Node & DSLNode> T rewriteToPolymorphic(final Node oldNode, final DSLNode uninitializedDSL, final T polymorphic, final DSLNode currentCopy, final DSLNode newNodeDSL,
+                    final String message) {
+        return oldNode.atomic(new Callable<T>() {
+            public T call() {
+                assert getNext(oldNode) == null;
+                assert getPrevious(oldNode) == null;
+                assert newNodeDSL != null;
 
-        Node uninitialized = (Node) uninitializedDSL;
-        Node newNode = (Node) newNodeDSL;
-        polymorphic.adoptChildren0(oldNode, (Node) currentCopy);
+                Node uninitialized = (Node) uninitializedDSL;
+                Node newNode = (Node) newNodeDSL;
+                polymorphic.adoptChildren0(oldNode, (Node) currentCopy);
 
-        updateSourceSection(oldNode, uninitialized);
-        // new specialization
-        updateSourceSection(oldNode, newNode);
-        newNodeDSL.adoptChildren0(null, uninitialized);
-        currentCopy.adoptChildren0(null, newNode);
+                updateSourceSection(oldNode, uninitialized);
+                // new specialization
+                updateSourceSection(oldNode, newNode);
+                newNodeDSL.adoptChildren0(null, uninitialized);
+                currentCopy.adoptChildren0(null, newNode);
 
-        oldNode.replace(polymorphic, message);
+                oldNode.replace(polymorphic, message);
 
-        assert polymorphic.getNext0() == currentCopy;
-        assert newNode != null ? currentCopy.getNext0() == newNode : currentCopy.getNext0() == uninitialized;
-        assert uninitializedDSL.getNext0() == null;
-        return polymorphic;
+                assert polymorphic.getNext0() == currentCopy;
+                assert newNode != null ? currentCopy.getNext0() == newNode : currentCopy.getNext0() == uninitialized;
+                assert uninitializedDSL.getNext0() == null;
+                return polymorphic;
+            }
+        });
     }
 
     private static void updateSourceSection(Node oldNode, Node newNode) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InterfaceChildFieldTest.java	Fri Oct 03 13:48:58 2014 +0200
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2014, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.test;
+
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Test child fields declared with interface types instead of {@link Node} subclasses.
+ */
+public class InterfaceChildFieldTest {
+
+    @Test
+    public void testChild() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        TestChildInterface leftChild = new TestLeafNode();
+        TestChildInterface rightChild = new TestLeafNode();
+        TestChildNode parent = new TestChildNode(leftChild, rightChild);
+        TestRootNode rootNode = new TestRootNode(parent);
+        CallTarget target = runtime.createCallTarget(rootNode);
+        Iterator<Node> iterator = parent.getChildren().iterator();
+        Assert.assertEquals(leftChild, iterator.next());
+        Assert.assertEquals(rightChild, iterator.next());
+        Assert.assertFalse(iterator.hasNext());
+        Object result = target.call();
+        Assert.assertEquals(42, result);
+
+        Assert.assertEquals(4, NodeUtil.countNodes(rootNode));
+        Assert.assertEquals(4, NodeUtil.countNodes(NodeUtil.cloneNode(rootNode)));
+    }
+
+    @Test
+    public void testChildren() {
+        TruffleRuntime runtime = Truffle.getRuntime();
+        TestChildInterface[] children = new TestChildInterface[5];
+        for (int i = 0; i < children.length; i++) {
+            children[i] = new TestLeafNode();
+        }
+        TestChildrenNode parent = new TestChildrenNode(children);
+        TestRootNode rootNode = new TestRootNode(parent);
+        CallTarget target = runtime.createCallTarget(rootNode);
+        Iterator<Node> iterator = parent.getChildren().iterator();
+        for (int i = 0; i < children.length; i++) {
+            Assert.assertEquals(children[i], iterator.next());
+        }
+        Assert.assertFalse(iterator.hasNext());
+        Object result = target.call();
+        Assert.assertEquals(105, result);
+
+        Assert.assertEquals(2 + children.length, NodeUtil.countNodes(rootNode));
+        Assert.assertEquals(2 + children.length, NodeUtil.countNodes(NodeUtil.cloneNode(rootNode)));
+    }
+
+    class TestRootNode extends RootNode {
+
+        @Child private TestChildInterface child;
+
+        public TestRootNode(TestChildInterface child) {
+            super(null);
+            this.child = child;
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return child.executeIntf();
+        }
+    }
+
+    interface TestChildInterface {
+        public int executeIntf();
+    }
+
+    class TestLeafNode extends Node implements TestChildInterface {
+        public TestLeafNode() {
+            super(null);
+        }
+
+        public int executeIntf() {
+            return this.replace(new TestLeaf2Node()).executeIntf();
+        }
+    }
+
+    class TestLeaf2Node extends Node implements TestChildInterface {
+        public TestLeaf2Node() {
+            super(null);
+        }
+
+        public int executeIntf() {
+            return 21;
+        }
+    }
+
+    class TestChildNode extends Node implements TestChildInterface {
+
+        @Child private TestChildInterface left;
+        @Child private TestChildInterface right;
+
+        public TestChildNode(TestChildInterface left, TestChildInterface right) {
+            super(null);
+            this.left = left;
+            this.right = right;
+        }
+
+        @Override
+        public int executeIntf() {
+            return left.executeIntf() + right.executeIntf();
+        }
+    }
+
+    class TestChildrenNode extends Node implements TestChildInterface {
+
+        @Children private final TestChildInterface[] children;
+
+        public TestChildrenNode(TestChildInterface[] children) {
+            super(null);
+            this.children = children;
+        }
+
+        @Override
+        public int executeIntf() {
+            int sum = 0;
+            for (int i = 0; i < children.length; ++i) {
+                sum += children[i].executeIntf();
+            }
+            return sum;
+        }
+    }
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Fri Oct 03 13:48:58 2014 +0200
@@ -185,7 +185,7 @@
 
         public NodeClass(Class<? extends Node> clazz, FieldOffsetProvider fieldOffsetProvider) {
             List<NodeField> fieldsList = new ArrayList<>();
-            List<Long> parentOffsetsList = new ArrayList<>();
+            long parentFieldOffset = -1;
             List<Long> childOffsetsList = new ArrayList<>();
             List<Long> childrenOffsetsList = new ArrayList<>();
 
@@ -195,30 +195,53 @@
                 }
 
                 NodeFieldKind kind;
-                if (Node.class.isAssignableFrom(field.getType()) && field.getName().equals("parent") && field.getDeclaringClass() == Node.class) {
+                if (field.getDeclaringClass() == Node.class && field.getName().equals("parent")) {
+                    assert Node.class.isAssignableFrom(field.getType());
                     kind = NodeFieldKind.PARENT;
-                    parentOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field));
-                } else if (Node.class.isAssignableFrom(field.getType()) && field.getAnnotation(Child.class) != null) {
+                    parentFieldOffset = fieldOffsetProvider.objectFieldOffset(field);
+                } else if (field.getAnnotation(Child.class) != null) {
+                    checkChildField(field);
                     kind = NodeFieldKind.CHILD;
                     childOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field));
-                    assert !Modifier.isFinal(field.getModifiers()) : "child field must not be final (\"" + field.getName() + "\", " + clazz + ")";
-                } else if (field.getType().isArray() && Node.class.isAssignableFrom(field.getType().getComponentType()) && field.getAnnotation(Children.class) != null) {
+                } else if (field.getAnnotation(Children.class) != null) {
+                    checkChildrenField(field);
                     kind = NodeFieldKind.CHILDREN;
                     childrenOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field));
-                    assert Modifier.isFinal(field.getModifiers()) : "children array field must be final (\"" + field.getName() + "\", " + clazz + ")";
                 } else {
                     kind = NodeFieldKind.DATA;
                 }
                 fieldsList.add(new NodeField(kind, field.getType(), field.getName(), fieldOffsetProvider.objectFieldOffset(field)));
             }
+
+            if (parentFieldOffset < 0) {
+                throw new AssertionError("parent field not found");
+            }
+
             this.fields = fieldsList.toArray(new NodeField[fieldsList.size()]);
-            assert parentOffsetsList.size() == 1 : "must have exactly one parent field";
-            this.parentOffset = parentOffsetsList.get(0);
+            this.parentOffset = parentFieldOffset;
             this.childOffsets = toLongArray(childOffsetsList);
             this.childrenOffsets = toLongArray(childrenOffsetsList);
             this.clazz = clazz;
         }
 
+        private static void checkChildField(Field field) {
+            if (!(Node.class.isAssignableFrom(field.getType()) || field.getType().isInterface())) {
+                throw new AssertionError("@Child field type must be a subclass of Node or an interface (" + field + ")");
+            }
+            if (Modifier.isFinal(field.getModifiers())) {
+                throw new AssertionError("@Child field must not be final (" + field + ")");
+            }
+        }
+
+        private static void checkChildrenField(Field field) {
+            if (!(field.getType().isArray() && (Node.class.isAssignableFrom(field.getType().getComponentType()) || field.getType().getComponentType().isInterface()))) {
+                throw new AssertionError("@Children field type must be an array of a subclass of Node or an interface (" + field + ")");
+            }
+            if (!Modifier.isFinal(field.getModifiers())) {
+                throw new AssertionError("@Children field must be final (" + field + ")");
+            }
+        }
+
         public NodeField[] getFields() {
             return fields;
         }
@@ -269,7 +292,7 @@
             private int childrenCount() {
                 int nodeCount = childOffsets.length;
                 for (long fieldOffset : childrenOffsets) {
-                    Node[] children = ((Node[]) unsafe.getObject(node, fieldOffset));
+                    Object[] children = ((Object[]) unsafe.getObject(node, fieldOffset));
                     if (children != null) {
                         nodeCount += children.length;
                     }
@@ -283,9 +306,9 @@
                     return (Node) unsafe.getObject(node, childOffsets[idx]);
                 } else {
                     for (long fieldOffset : childrenOffsets) {
-                        Node[] nodeArray = (Node[]) unsafe.getObject(node, fieldOffset);
+                        Object[] nodeArray = (Object[]) unsafe.getObject(node, fieldOffset);
                         if (idx < nodeCount + nodeArray.length) {
-                            return nodeArray[idx - nodeCount];
+                            return (Node) nodeArray[idx - nodeCount];
                         }
                         nodeCount += nodeArray.length;
                     }
@@ -361,12 +384,12 @@
             }
         }
         for (long fieldOffset : nodeClass.childrenOffsets) {
-            Node[] children = (Node[]) unsafe.getObject(orig, fieldOffset);
+            Object[] children = (Object[]) unsafe.getObject(orig, fieldOffset);
             if (children != null) {
-                Node[] clonedChildren = (Node[]) Array.newInstance(children.getClass().getComponentType(), children.length);
+                Object[] clonedChildren = (Object[]) Array.newInstance(children.getClass().getComponentType(), children.length);
                 for (int i = 0; i < children.length; i++) {
                     if (children[i] != null) {
-                        Node clonedChild = cloneNode(children[i]);
+                        Node clonedChild = cloneNode((Node) children[i]);
                         clonedChildren[i] = clonedChild;
                         unsafe.putObject(clonedChild, nodeClass.parentOffset, clone);
                     }
@@ -388,11 +411,11 @@
             }
         }
         for (long fieldOffset : nodeClass.childrenOffsets) {
-            Node[] children = (Node[]) unsafe.getObject(node, fieldOffset);
+            Object[] children = (Object[]) unsafe.getObject(node, fieldOffset);
             if (children != null) {
-                for (Node child : children) {
+                for (Object child : children) {
                     if (child != null) {
-                        nodes.add(child);
+                        nodes.add((Node) child);
                     }
                 }
             }
@@ -415,8 +438,7 @@
         for (long fieldOffset : nodeClass.getChildrenOffsets()) {
             Object arrayObject = unsafe.getObject(parent, fieldOffset);
             if (arrayObject != null) {
-                assert arrayObject instanceof Node[] : "Children array must be instanceof Node[] ";
-                Node[] array = (Node[]) arrayObject;
+                Object[] array = (Object[]) arrayObject;
                 for (int i = 0; i < array.length; i++) {
                     if (array[i] == oldChild) {
                         assert assertAssignable(nodeClass, fieldOffset, newChild);
@@ -655,25 +677,7 @@
         if (parent == null) {
             p.println(nodeName(node));
         } else {
-            String fieldName = "unknownField";
-            NodeField[] fields = NodeClass.get(parent.getClass()).fields;
-            for (NodeField field : fields) {
-                Object value = field.loadValue(parent);
-                if (value == node) {
-                    fieldName = field.getName();
-                    break;
-                } else if (value instanceof Node[]) {
-                    int index = 0;
-                    for (Node arrayNode : (Node[]) value) {
-                        if (arrayNode == node) {
-                            fieldName = field.getName() + "[" + index + "]";
-                            break;
-                        }
-                        index++;
-                    }
-                }
-            }
-            p.print(fieldName);
+            p.print(getNodeFieldName(parent, node, "unknownField"));
             p.print(" = ");
             p.println(nodeName(node));
         }
@@ -713,25 +717,7 @@
         }
 
         if (parent != null) {
-            String childName = "";
-            NodeField[] fields = NodeClass.get(parent.getClass()).fields;
-            for (NodeField field : fields) {
-                Object value = field.loadValue(parent);
-                if (value == node) {
-                    childName = field.getName();
-                    break;
-                } else if (value instanceof Node[]) {
-                    int index = 0;
-                    for (Node arrayNode : (Node[]) value) {
-                        if (arrayNode == node) {
-                            childName = field.getName() + "[" + index + "]";
-                            break;
-                        }
-                        index++;
-                    }
-                }
-            }
-            sb.append(childName);
+            sb.append(getNodeFieldName(parent, node, ""));
         }
 
         sb.append("  (" + node.getClass().getSimpleName() + ")  ");
@@ -744,6 +730,25 @@
         p.flush();
     }
 
+    private static String getNodeFieldName(Node parent, Node node, String defaultName) {
+        NodeField[] fields = NodeClass.get(parent.getClass()).fields;
+        for (NodeField field : fields) {
+            Object value = field.loadValue(parent);
+            if (field.getKind() == NodeFieldKind.CHILD && value == node) {
+                return field.getName();
+            } else if (field.getKind() == NodeFieldKind.CHILDREN) {
+                int index = 0;
+                for (Object arrayNode : (Object[]) value) {
+                    if (arrayNode == node) {
+                        return field.getName() + "[" + index + "]";
+                    }
+                    index++;
+                }
+            }
+        }
+        return defaultName;
+    }
+
     /**
      * Prints a human readable form of a {@link Node} AST to the given {@link PrintStream}. This
      * print method does not check for cycles in the node structure.
@@ -815,13 +820,13 @@
 
     private static void printChildren(PrintWriter p, int level, Object value) {
         String sep;
-        Node[] children = (Node[]) value;
+        Object[] children = (Object[]) value;
         p.print(" = [");
         sep = "";
-        for (Node child : children) {
+        for (Object child : children) {
             p.print(sep);
             sep = ", ";
-            printTree(p, child, level + 1);
+            printTree(p, (Node) child, level + 1);
         }
         p.print("]");
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java	Fri Oct 03 13:48:58 2014 +0200
@@ -129,13 +129,13 @@
         return valueName(parameter) + "Cast";
     }
 
-    private void addInternalValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame, boolean evaluated) {
-        if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) {
+    private void addInternalValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame, boolean disableFrame, boolean evaluated) {
+        if (forceFrame && !disableFrame && specialization.getSpecification().findParameterSpec("frame") != null) {
             method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue"));
         }
         for (Parameter parameter : specialization.getParameters()) {
             ParameterSpec spec = parameter.getSpecification();
-            if (forceFrame && spec.getName().equals("frame")) {
+            if ((disableFrame || forceFrame) && spec.getName().equals("frame")) {
                 continue;
             }
             if (spec.isLocal()) {
@@ -152,13 +152,13 @@
     }
 
     private static void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame,
-                    Map<String, String> customNames) {
-        if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) {
+                    boolean disableFrame, Map<String, String> customNames) {
+        if (forceFrame && !disableFrame && specialization.getSpecification().findParameterSpec("frame") != null) {
             builder.string("frameValue");
         }
         for (Parameter parameter : specialization.getParameters()) {
             ParameterSpec spec = parameter.getSpecification();
-            if (forceFrame && spec.getName().equals("frame")) {
+            if ((disableFrame || forceFrame) && spec.getName().equals("frame")) {
                 continue;
             }
 
@@ -322,12 +322,12 @@
     /**
      * <pre>
      * variant1 $condition != null
-     * 
+     *
      * $type $name = defaultValue($type);
      * if ($condition) {
      *     $name = $value;
      * }
-     * 
+     *
      * variant2 $condition != null
      * $type $name = $value;
      * </pre>
@@ -1034,7 +1034,7 @@
         private Element createInfoMessage(NodeData node) {
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, STATIC), getContext().getType(String.class), CREATE_INFO);
             method.addParameter(new CodeVariableElement(getContext().getType(String.class), "message"));
-            addInternalValueParameters(method, node.getGenericSpecialization(), false, false);
+            addInternalValueParameters(method, node.getGenericSpecialization(), false, false, false);
 
             CodeTreeBuilder builder = method.createBuilder();
 
@@ -1089,7 +1089,7 @@
 
         private CodeExecutableElement createCachedExecute(NodeData node, SpecializationData polymorph) {
             CodeExecutableElement cachedExecute = new CodeExecutableElement(modifiers(PROTECTED, ABSTRACT), polymorph.getReturnType().getType(), EXECUTE_CHAINED);
-            addInternalValueParameters(cachedExecute, polymorph, true, false);
+            addInternalValueParameters(cachedExecute, polymorph, true, false, false);
 
             ExecutableTypeData sourceExecutableType = node.findExecutableType(polymorph.getReturnType().getTypeSystemType(), 0);
             boolean sourceThrowsUnexpected = sourceExecutableType != null && sourceExecutableType.hasUnexpectedValue(getContext());
@@ -1244,12 +1244,13 @@
             NodeData node = getModel().getNode();
             SpecializationData generic = node.getGenericSpecialization();
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), generic.getReturnType().getType(), EXECUTE_UNINITIALIZED);
-            addInternalValueParameters(method, generic, true, false);
+            addInternalValueParameters(method, generic, true, false, false);
             CodeTreeBuilder builder = method.createBuilder();
 
+            boolean needsFrame = node.isFrameUsedByAnyGuard(getContext());
             CodeTreeBuilder createSpecializationCall = builder.create();
             createSpecializationCall.startCall(SPECIALIZE);
-            addInternalValueParameterNames(createSpecializationCall, generic, generic, null, node.needsFrame(getContext()), null);
+            addInternalValueParameterNames(createSpecializationCall, generic, generic, null, needsFrame, !needsFrame, null);
             createSpecializationCall.end();
             builder.declaration(baseClassName(node), "newNode", createSpecializationCall);
 
@@ -1269,7 +1270,7 @@
             builder.startReturn();
             builder.startStaticCall(context.getTruffleTypes().getDslShare(), "rewriteUninitialized").string("this").string("newNode").end();
             builder.string(".").startCall(EXECUTE_CHAINED);
-            addInternalValueParameterNames(builder, generic, generic, null, true, null);
+            addInternalValueParameterNames(builder, generic, generic, null, true, false, null);
             builder.end();
             builder.end();
 
@@ -1283,7 +1284,7 @@
         private CodeTree createInfoCall(CodeTreeBuilder parent, SpecializationData specialization, String reason) {
             CodeTreeBuilder builder = parent.create();
             builder.startCall(CREATE_INFO).string(reason);
-            addInternalValueParameterNames(builder, specialization, specialization, null, false, null);
+            addInternalValueParameterNames(builder, specialization, specialization, null, false, false, null);
             builder.end();
             return builder.getRoot();
         }
@@ -1293,16 +1294,17 @@
 
             SpecializationData generic = node.getGenericSpecialization();
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), generic.getReturnType().getType(), REWRITE);
-            addInternalValueParameters(method, generic, true, false);
+            addInternalValueParameters(method, generic, true, false, false);
             method.addParameter(new CodeVariableElement(getContext().getType(String.class), "reason"));
 
+            boolean needsFrame = node.isFrameUsedByAnyGuard(getContext());
             CodeTreeBuilder builder = method.createBuilder();
 
             builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerAsserts(), "neverPartOfCompilation").end().end();
             String baseClassName = baseClassName(getModel().getNode());
             CodeTreeBuilder createSpecializationCall = builder.create();
             createSpecializationCall.startCall(SPECIALIZE);
-            addInternalValueParameterNames(createSpecializationCall, generic, generic, null, node.needsFrame(getContext()), null);
+            addInternalValueParameterNames(createSpecializationCall, generic, generic, null, needsFrame, !needsFrame, null);
             createSpecializationCall.end();
             builder.declaration(baseClassName, "newNode", createSpecializationCall);
 
@@ -1328,7 +1330,7 @@
 
             builder.startReturn();
             builder.startCall("returnNode", EXECUTE_CHAINED);
-            addInternalValueParameterNames(builder, node.getGenericSpecialization(), node.getGenericSpecialization(), null, true, null);
+            addInternalValueParameterNames(builder, node.getGenericSpecialization(), node.getGenericSpecialization(), null, true, false, null);
             builder.end();
             builder.end();
 
@@ -1356,16 +1358,19 @@
         private CodeExecutableElement createCreateSpecializationMethod(NodeData node, SpecializationGroup group) {
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), new GeneratedTypeMirror(ElementUtils.getPackageName(node.getTemplateType()), baseClassName(node)),
                             SPECIALIZE);
-            if (!node.needsFrame(getContext())) {
+
+            final boolean needsFrame = node.isFrameUsedByAnyGuard(getContext());
+
+            if (!needsFrame) {
                 method.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getSlowPath()));
             }
 
-            addInternalValueParameters(method, node.getGenericSpecialization(), node.needsFrame(getContext()), false);
+            addInternalValueParameters(method, node.getGenericSpecialization(), needsFrame, !needsFrame, false);
             final CodeTreeBuilder builder = method.createBuilder();
             builder.tree(createExecuteTree(builder, node.getGenericSpecialization(), group, new CodeBlock<SpecializationData>() {
 
                 public CodeTree create(CodeTreeBuilder b, SpecializationData current) {
-                    return createCreateSpecializationMethodBody0(builder, current);
+                    return createCreateSpecializationMethodBody0(builder, current, needsFrame);
                 }
             }, null, false, true, false, true));
 
@@ -1374,7 +1379,7 @@
             return method;
         }
 
-        protected CodeTree createCreateSpecializationMethodBody0(CodeTreeBuilder parent, SpecializationData current) {
+        protected CodeTree createCreateSpecializationMethodBody0(CodeTreeBuilder parent, SpecializationData current, boolean useDeoptimize) {
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             if (current.isGeneric()) {
                 builder.startReturn().nullLiteral().end();
@@ -1386,7 +1391,7 @@
                     builder.startBlock();
                 }
 
-                if (current.getNode().getGenericSpecialization().isReachable()) {
+                if (current.getNode().getGenericSpecialization().isReachable() && useDeoptimize) {
                     builder.tree(createDeoptimize(builder));
                 }
                 builder.startReturn();
@@ -2226,7 +2231,7 @@
 
             CodeTreeBuilder execute = new CodeTreeBuilder(builder);
             execute.startCall("next0", EXECUTE_CHAINED);
-            addInternalValueParameterNames(execute, specialization, polymorphic, param.getLocalName(), true, null);
+            addInternalValueParameterNames(execute, specialization, polymorphic, param.getLocalName(), true, false, null);
             execute.end();
 
             TypeData sourceType = polymorphic.getReturnType().getTypeSystemType();
@@ -2342,7 +2347,7 @@
             SpecializationData generic = node.getGenericSpecialization();
             CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent);
             specializeCall.startCall(REWRITE);
-            addInternalValueParameterNames(specializeCall, generic, node.getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, null);
+            addInternalValueParameterNames(specializeCall, generic, node.getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, false, null);
             specializeCall.doubleQuote(reason);
             specializeCall.end().end();
 
@@ -2664,17 +2669,17 @@
 
             if (specialization.isPolymorphic()) {
                 builder.startReturn().startCall("this.next0", EXECUTE_CHAINED);
-                addInternalValueParameterNames(builder, polymorphic, polymorphic, null, true, null);
+                addInternalValueParameterNames(builder, polymorphic, polymorphic, null, true, false, null);
                 builder.end().end();
             } else if (specialization.isUninitialized()) {
                 builder.tree(createDeoptimizeUninitialized(node, builder));
                 builder.startReturn().startCall("this", EXECUTE_UNINITIALIZED);
-                addInternalValueParameterNames(builder, polymorphic, polymorphic, null, true, null);
+                addInternalValueParameterNames(builder, polymorphic, polymorphic, null, true, false, null);
                 builder.end().end();
             } else {
                 CodeTreeBuilder elseBuilder = new CodeTreeBuilder(builder);
                 elseBuilder.startReturn().startCall("this.next0", EXECUTE_CHAINED);
-                addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, null);
+                addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, false, null);
                 elseBuilder.end().end();
 
                 builder.tree(createExecuteTree(builder, polymorphic, SpecializationGroup.create(specialization), new CodeBlock<SpecializationData>() {
@@ -2861,11 +2866,11 @@
             CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent);
             if (specialization.isPolymorphic()) {
                 returnBuilder.startCall("next0", EXECUTE_CHAINED);
-                addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, null);
+                addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, false, null);
                 returnBuilder.end();
             } else if (specialization.isUninitialized()) {
                 returnBuilder.startCall(EXECUTE_UNINITIALIZED);
-                addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, null);
+                addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, false, null);
                 returnBuilder.end();
             } else if (specialization.getMethod() == null && !node.needsRewrites(context)) {
                 emitEncounteredSynthetic(builder, specialization);
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java	Fri Oct 03 13:48:58 2014 +0200
@@ -99,12 +99,12 @@
         return 0;
     }
 
-    public boolean needsFrame(ProcessorContext context) {
+    public boolean isFrameUsedByAnyGuard(ProcessorContext context) {
         for (SpecializationData specialization : specializations) {
             if (!specialization.isReachable()) {
                 continue;
             }
-            if (specialization.hasFrame(context)) {
+            if (specialization.isFrameUsedByGuard(context)) {
                 return true;
             }
         }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java	Fri Oct 03 13:48:58 2014 +0200
@@ -287,12 +287,19 @@
         return String.format("%s [id = %s, method = %s, guards = %s, signature = %s]", getClass().getSimpleName(), getId(), getMethod(), getGuards(), getTypeSignature());
     }
 
-    public boolean hasFrame(ProcessorContext context) {
-        for (Parameter param : getParameters()) {
-            if (ElementUtils.typeEquals(param.getType(), context.getTruffleTypes().getFrame())) {
-                return true;
+    public boolean isFrameUsedByGuard(ProcessorContext context) {
+        for (GuardExpression guard : getGuards()) {
+            if (guard.getResolvedGuard() == null) {
+                continue;
+            }
+
+            for (Parameter param : guard.getResolvedGuard().getParameters()) {
+                if (ElementUtils.typeEquals(param.getType(), context.getTruffleTypes().getFrame())) {
+                    return true;
+                }
             }
         }
+
         return false;
     }
 
--- a/mx/mx_graal.py	Fri Oct 03 11:07:44 2014 +0200
+++ b/mx/mx_graal.py	Fri Oct 03 13:48:58 2014 +0200
@@ -529,7 +529,7 @@
         graalRuntime_inline_hpp = join(genSrcDir, 'graalRuntime.inline.hpp')
         cp = os.pathsep.join([mx.distribution(d).path for d in dist.distDependencies] + [dist.path, p.output_dir()])
         tmp = StringIO.StringIO()
-        mx.run_java(['-cp', mx._tspU2W(cp), mainClass], out=tmp.write)
+        mx.run_java(['-cp', mx._separatedCygpathU2W(cp), mainClass], out=tmp.write)
 
         # Compute SHA1 for currently generated graalRuntime.inline.hpp content
         # and all other generated sources in genSrcDir
@@ -552,7 +552,7 @@
         javaClass = join(_graal_home, 'GeneratedSourcesSha1.class')
         with open(javaSource, 'w') as fp:
             print >> fp, 'class GeneratedSourcesSha1 { private static final String value = "' + sha1 + '"; }'
-        subprocess.check_call([mx.java().javac, '-d', mx._tpU2W(_graal_home), mx._tpU2W(javaSource)], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
+        subprocess.check_call([mx.java().javac, '-d', mx._cygpathU2W(_graal_home), mx._cygpathU2W(javaSource)], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
         zf = zipfile.ZipFile(dist.path, 'a')
         with open(javaClass, 'rb') as fp:
             zf.writestr(os.path.basename(javaClass), fp.read())
@@ -611,14 +611,14 @@
 
     winSDK = mx.get_env('WIN_SDK', 'C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1\\')
 
-    if not exists(mx._tpW2U(winSDK)):
+    if not exists(mx._cygpathW2U(winSDK)):
         mx.abort("Could not find Windows SDK : '" + winSDK + "' does not exist")
 
-    winSDKSetEnv = mx._tpW2U(join(winSDK, 'Bin', 'SetEnv.cmd'))
+    winSDKSetEnv = mx._cygpathW2U(join(winSDK, 'Bin', 'SetEnv.cmd'))
     if not exists(winSDKSetEnv):
         mx.abort("Invalid Windows SDK path (" + winSDK + ") : could not find Bin/SetEnv.cmd (you can use the WIN_SDK environment variable to specify an other path)")
 
-    wincmd = 'cmd.exe /E:ON /V:ON /K "' + mx._tpU2W(winSDKSetEnv) + '"'
+    wincmd = 'cmd.exe /E:ON /V:ON /K "' + mx._cygpathU2W(winSDKSetEnv) + '"'
     p = subprocess.Popen(wincmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
     stdout = p.stdout
     stdin = p.stdin
@@ -796,13 +796,15 @@
         if not mx.ask_yes_no("Warning: building while --installed-jdks is set (" + _installed_jdks + ") is not recommanded - are you sure you want to continue", 'n'):
             mx.abort(1)
 
+    isWindows = platform.system() == 'Windows' or "CYGWIN" in platform.system()
     for build in builds:
         if build == 'ide-build-target':
             build = os.environ.get('IDE_BUILD_TARGET', None)
             if build is None or len(build) == 0:
                 continue
 
-        jdk = _jdk(build, create=True, installJars=vm != 'original' and not opts2.java)
+        installJars = vm != 'original' and (isWindows or not opts2.java)
+        jdk = _jdk(build, create=True, installJars=installJars)
 
         if vm == 'original':
             if build != 'product':
@@ -846,15 +848,15 @@
             mx.logv('[all files in src and make directories are older than ' + timestampFile[len(_graal_home) + 1:] + ' - skipping native build]')
             continue
 
-        if platform.system() == 'Windows' or "CYGWIN" in platform.system():
-            t_compilelogfile = mx._tpU2W(os.path.join(_graal_home, "graalCompile.log"))
+        if isWindows:
+            t_compilelogfile = mx._cygpathU2W(os.path.join(_graal_home, "graalCompile.log"))
             mksHome = mx.get_env('MKS_HOME', 'C:\\cygwin\\bin')
 
             variant = {'client': 'compiler1', 'server': 'compiler2'}.get(vm, vm)
             project_config = variant + '_' + build
-            t_graal_home = mx._tpU2W(_graal_home)
+            t_graal_home = mx._cygpathU2W(_graal_home)
             _runInDebugShell('msbuild ' + t_graal_home + r'\build\vs-amd64\jvm.vcproj /p:Configuration=' + project_config + ' /target:clean', t_graal_home)
-            winCompileCmd = r'set HotSpotMksHome=' + mksHome + r'& set OUT_DIR=' + mx._tpU2W(jdk) + r'& set JAVA_HOME=' + mx._tpU2W(jdk) + r'& set path=%JAVA_HOME%\bin;%path%;%HotSpotMksHome%& cd /D "' + t_graal_home + r'\make\windows"& call create.bat ' + t_graal_home
+            winCompileCmd = r'set HotSpotMksHome=' + mksHome + r'& set OUT_DIR=' + mx._cygpathU2W(jdk) + r'& set JAVA_HOME=' + mx._cygpathU2W(jdk) + r'& set path=%JAVA_HOME%\bin;%path%;%HotSpotMksHome%& cd /D "' + t_graal_home + r'\make\windows"& call create.bat ' + t_graal_home
             print winCompileCmd
             winCompileSuccess = re.compile(r"^Writing \.vcxproj file:")
             if not _runInDebugShell(winCompileCmd, t_graal_home, t_compilelogfile, winCompileSuccess):
@@ -901,6 +903,9 @@
                 setMakeVar('GRAAL_VERSION', version)
                 setMakeVar('INCLUDE_GRAAL', 'true')
             setMakeVar('INSTALL', 'y', env=env)
+            if mx.get_os() == 'darwin' and platform.mac_ver()[0] != '':
+                # Force use of clang on MacOS
+                setMakeVar('USE_CLANG', 'true')
             if mx.get_os() == 'solaris':
                 # If using sparcWorks, setup flags to avoid make complaining about CC version
                 cCompilerVersion = subprocess.Popen('CC -V', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).stderr.readlines()[0]
@@ -1175,7 +1180,7 @@
             # replaying the VM execution in a native debugger (e.g., gdb).
             vm(prefixArgs + vmArgs + ['-cp', cp, 'com.oracle.graal.test.GraalJUnitCore'] + coreArgs + testclasses)
         else:
-            vm(prefixArgs + vmArgs + ['-cp', cp, 'com.oracle.graal.test.GraalJUnitCore'] + coreArgs + ['@' + testfile])
+            vm(prefixArgs + vmArgs + ['-cp', cp, 'com.oracle.graal.test.GraalJUnitCore'] + coreArgs + ['@' + mx._cygpathU2W(testfile)])
 
     try:
         _run_tests(args, harness, annotations, testfile, blacklist, whitelist, regex)
@@ -1308,9 +1313,11 @@
                 log = open(join(_graal_home, logFile), 'wb')
                 start = time.time()
                 mx.log('BEGIN: ' + v + '-' + vmbuild + '\t(see: ' + logFile + ')')
+                verbose = ['-v'] if mx._opts.verbose else []
                 # Run as subprocess so that output can be directed to a file
-                subprocess.check_call([sys.executable, '-u', join('mxtool', 'mx.py'), '--vm', v, '--vmbuild',
-                                       vmbuild, 'build'], cwd=_graal_home, stdout=log, stderr=subprocess.STDOUT)
+                cmd = [sys.executable, '-u', join('mxtool', 'mx.py')] + verbose + ['--vm', v, '--vmbuild', vmbuild, 'build']
+                mx.logv("executing command: " + str(cmd))
+                subprocess.check_call(cmd, cwd=_graal_home, stdout=log, stderr=subprocess.STDOUT)
                 duration = datetime.timedelta(seconds=time.time() - start)
                 mx.log('END:   ' + v + '-' + vmbuild + '\t[' + str(duration) + ']')
             else:
@@ -1451,7 +1458,7 @@
     _jacoco = 'off'
 
     t = Task('CleanAndBuildIdealGraphVisualizer')
-    buildxml = mx._tpU2W(join(_graal_home, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml'))
+    buildxml = mx._cygpathU2W(join(_graal_home, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml'))
     mx.run(['ant', '-f', buildxml, '-q', 'clean', 'build'])
     tasks.append(t.stop())
 
@@ -1850,7 +1857,7 @@
                 buildOutput.append(x)
         env = os.environ.copy()
         env['JAVA_HOME'] = _jdk(vmToCheck='server')
-        env['MAVEN_OPTS'] = '-server'
+        env['MAVEN_OPTS'] = '-server -XX:-UseGraalClassLoader'
         mx.log("Building benchmarks...")
         cmd = ['mvn']
         if args.settings:
@@ -1876,6 +1883,8 @@
         mx.abort(1)
 
     vmArgs, benchmarksAndJsons = _extract_VM_args(args)
+    if '-XX:-UseGraalClassLoader' not in vmArgs:
+        vmArgs = ['-XX:-UseGraalClassLoader'] + vmArgs
 
     benchmarks = [b for b in benchmarksAndJsons if not b.startswith('{')]
     jmhArgJsons = [b for b in benchmarksAndJsons if b.startswith('{')]
@@ -2245,13 +2254,13 @@
         findbugsJar = join(findbugsLib, 'findbugs.jar')
     assert exists(findbugsJar)
     nonTestProjects = [p for p in mx.projects() if not p.name.endswith('.test') and not p.name.endswith('.jtt')]
-    outputDirs = map(mx._tpU2W, [p.output_dir() for p in nonTestProjects])
+    outputDirs = map(mx._cygpathU2W, [p.output_dir() for p in nonTestProjects])
     findbugsResults = join(_graal_home, 'findbugs.results')
 
-    cmd = ['-jar', mx._tpU2W(findbugsJar), '-textui', '-low', '-maxRank', '15']
+    cmd = ['-jar', mx._cygpathU2W(findbugsJar), '-textui', '-low', '-maxRank', '15']
     if sys.stdout.isatty():
         cmd.append('-progress')
-    cmd = cmd + ['-auxclasspath', mx.classpath([d.name for d in _jdkDeployedDists] + [p.name for p in nonTestProjects]), '-output', mx._tpU2W(findbugsResults), '-exitcode'] + args + outputDirs
+    cmd = cmd + ['-auxclasspath', mx.classpath([d.name for d in _jdkDeployedDists] + [p.name for p in nonTestProjects]), '-output', mx._cygpathU2W(findbugsResults), '-exitcode'] + args + outputDirs
     exitcode = mx.run_java(cmd, nonZeroIsFatal=False)
     if exitcode != 0:
         with open(findbugsResults) as fp:
--- a/mxtool/mx.py	Fri Oct 03 11:07:44 2014 +0200
+++ b/mxtool/mx.py	Fri Oct 03 13:48:58 2014 +0200
@@ -284,6 +284,13 @@
         Add the transitive set of dependencies for this project, including
         libraries if 'includeLibs' is true, to the 'deps' list.
         """
+        return self._all_deps_helper(deps, [], includeLibs, includeSelf, includeJreLibs, includeAnnotationProcessors)
+
+    def _all_deps_helper(self, deps, dependants, includeLibs, includeSelf=True, includeJreLibs=False, includeAnnotationProcessors=False):
+        if self in dependants:
+            abort(str(self) + 'Project dependency cycle found:\n    ' +
+                  '\n        |\n        V\n    '.join(map(str, dependants[dependants.index(self):])) +
+                  '\n        |\n        V\n    ' + self.name)
         childDeps = list(self.deps)
         if includeAnnotationProcessors and len(self.annotation_processors()) > 0:
             childDeps = self.annotation_processors() + childDeps
@@ -292,8 +299,11 @@
         for name in childDeps:
             assert name != self.name
             dep = dependency(name)
-            if not dep in deps and (dep.isProject or (dep.isLibrary() and includeLibs) or (dep.isJreLibrary() and includeJreLibs)):
-                dep.all_deps(deps, includeLibs=includeLibs, includeJreLibs=includeJreLibs, includeAnnotationProcessors=includeAnnotationProcessors)
+            if not dep in deps:
+                if dep.isProject():
+                    dep._all_deps_helper(deps, dependants + [self], includeLibs=includeLibs, includeJreLibs=includeJreLibs, includeAnnotationProcessors=includeAnnotationProcessors)
+                elif dep.isProject or (dep.isLibrary() and includeLibs) or (dep.isJreLibrary() and includeJreLibs):
+                    dep.all_deps(deps, includeLibs=includeLibs, includeJreLibs=includeJreLibs, includeAnnotationProcessors=includeAnnotationProcessors)
         if not self in deps and includeSelf:
             deps.append(self)
         return deps
@@ -1335,39 +1345,43 @@
     else:
         abort('Unknown operating system ' + sys.platform)
 
-def _tpU2W(p):
+def _cygpathU2W(p):
     """
-    Translate a path from unix-style to windows-style
+    Translate a path from unix-style to windows-style.
+    This method has no effects on other platforms than cygwin.
     """
     if p is None or get_os() != "cygwin":
         return p
     return subprocess.check_output(['cygpath', '-w', p]).strip()
 
-def _tpW2U(p):
+def _cygpathW2U(p):
     """
-    Translate a path from windows-style to unix-style
+    Translate a path from windows-style to unix-style.
+    This method has no effects on other platforms than cygwin.
     """
     if p is None or get_os() != "cygwin":
         return p
     return subprocess.check_output(['cygpath', '-u', p]).strip()
 
-def _tspU2W(p):
+def _separatedCygpathU2W(p):
     """
-    Translate a group of paths, seperated by a path seperator.
+    Translate a group of paths, separated by a path separator.
     unix-style to windows-style.
+    This method has no effects on other platforms than cygwin.
     """
     if p is None or p == "" or get_os() != "cygwin":
         return p
-    return ';'.join(map(_tpU2W, p.split(os.pathsep)))
-
-def _tspW2U(p):
+    return ';'.join(map(_cygpathU2W, p.split(os.pathsep)))
+
+def _separatedCygpathW2U(p):
     """
-    Translate a group of paths, seperated by a path seperator.
+    Translate a group of paths, separated by a path separator.
     windows-style to unix-style.
+    This method has no effects on other platforms than cygwin.
     """
     if p is None or p == "" or get_os() != "cygwin":
         return p
-    return os.pathsep.join(map(_tpW2U, p.split(';')))
+    return os.pathsep.join(map(_cygpathW2U, p.split(';')))
 
 def get_arch():
     machine = platform.uname()[4]
@@ -1558,7 +1572,7 @@
     if includeBootClasspath:
         result = os.pathsep.join([java().bootclasspath(), result])
 
-    return _tspU2W(result)
+    return _separatedCygpathU2W(result)
 
 def classpath_walk(names=None, resolve=True, includeSelf=True, includeBootClasspath=False):
     """
@@ -2026,7 +2040,7 @@
         return cmp(self.parts, other.parts)
 
 def _filter_non_existant_paths(paths):
-    return os.pathsep.join([path for path in _tspW2U(paths).split(os.pathsep) if exists(path)])
+    return os.pathsep.join([path for path in _separatedCygpathW2U(paths).split(os.pathsep) if exists(path)])
 
 """
 A JavaConfig object encapsulates info on how Java commands are run.
@@ -2091,8 +2105,8 @@
             os.makedirs(outDir)
         javaSource = join(myDir, 'ClasspathDump.java')
         if not exists(join(outDir, 'ClasspathDump.class')):
-            subprocess.check_call([self.javac, '-d', _tpU2W(outDir), _tpU2W(javaSource)], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
-        self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', _tspU2W(outDir), 'ClasspathDump'], stderr=subprocess.PIPE).split('|')]
+            subprocess.check_call([self.javac, '-d', _cygpathU2W(outDir), _cygpathU2W(javaSource)], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
+        self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', _separatedCygpathU2W(outDir), 'ClasspathDump'], stderr=subprocess.PIPE).split('|')]
         if not self._bootclasspath or not self._extdirs or not self._endorseddirs:
             warn("Could not find all classpaths: boot='" + str(self._bootclasspath) + "' extdirs='" + str(self._extdirs) + "' endorseddirs='" + str(self._endorseddirs) + "'")
         self._bootclasspath = _filter_non_existant_paths(self._bootclasspath)
@@ -2119,17 +2133,17 @@
     def bootclasspath(self):
         if self._bootclasspath is None:
             self._init_classpaths()
-        return _tspU2W(self._bootclasspath)
+        return _separatedCygpathU2W(self._bootclasspath)
 
     def extdirs(self):
         if self._extdirs is None:
             self._init_classpaths()
-        return _tspU2W(self._extdirs)
+        return _separatedCygpathU2W(self._extdirs)
 
     def endorseddirs(self):
         if self._endorseddirs is None:
             self._init_classpaths()
-        return _tspU2W(self._endorseddirs)
+        return _separatedCygpathU2W(self._endorseddirs)
 
     def containsJar(self, jar):
         if self._bootclasspath is None:
@@ -2275,11 +2289,11 @@
     javaSource = join(myDir, 'URLConnectionDownload.java')
     javaClass = join(myDir, 'URLConnectionDownload.class')
     if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource):
-        subprocess.check_call([java().javac, '-d', _tpU2W(myDir), _tpU2W(javaSource)])
+        subprocess.check_call([java().javac, '-d', _cygpathU2W(myDir), _cygpathU2W(javaSource)])
     verbose = []
     if sys.stderr.isatty():
         verbose.append("-v")
-    if run([java().java, '-cp', _tpU2W(myDir), 'URLConnectionDownload', _tpU2W(path)] + verbose + urls, nonZeroIsFatal=False) == 0:
+    if run([java().java, '-cp', _cygpathU2W(myDir), 'URLConnectionDownload', _cygpathU2W(path)] + verbose + urls, nonZeroIsFatal=False) == 0:
         return
 
     abort('Could not download to ' + path + ' from any of the following URLs:\n\n    ' +
@@ -2334,7 +2348,7 @@
     def execute(self):
         argfileName = join(self.proj.dir, 'javafilelist.txt')
         argfile = open(argfileName, 'wb')
-        argfile.write('\n'.join(map(_tpU2W, self.javafilelist)))
+        argfile.write('\n'.join(map(_cygpathU2W, self.javafilelist)))
         argfile.close()
 
         processorArgs = []
@@ -2344,13 +2358,13 @@
             if exists(genDir):
                 shutil.rmtree(genDir)
             os.mkdir(genDir)
-            processorArgs += ['-processorpath', _tspU2W(join(processorPath)), '-s', _tpU2W(genDir)]
+            processorArgs += ['-processorpath', _separatedCygpathU2W(join(processorPath)), '-s', _cygpathU2W(genDir)]
         else:
             processorArgs += ['-proc:none']
 
         args = self.args
         jdk = self.jdk
-        outputDir = _tpU2W(self.outputDir)
+        outputDir = _cygpathU2W(self.outputDir)
         compliance = str(jdk.javaCompliance)
         cp = classpath(self.proj.name, includeSelf=True)
         toBeDeleted = [argfileName]
@@ -2365,7 +2379,7 @@
                     if jdk.debug_port is not None:
                         javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)]
                     javacCmd += processorArgs
-                    javacCmd += ['@' + _tpU2W(argfile.name)]
+                    javacCmd += ['@' + _cygpathU2W(argfile.name)]
 
                     if not args.warnAPI:
                         javacCmd.append('-XDignore.symbol.file')
@@ -2382,7 +2396,7 @@
             else:
                 self.logCompilation('JDT')
 
-                jdtVmArgs = ['-Xmx1g', '-jar', _tpU2W(self.jdtJar)]
+                jdtVmArgs = ['-Xmx1g', '-jar', _cygpathU2W(self.jdtJar)]
 
                 jdtArgs = ['-' + compliance,
                          '-cp', cp, '-g', '-enableJavadoc',
@@ -2412,10 +2426,10 @@
                         with open(jdtPropertiesTmp, 'w') as fp:
                             fp.write(content)
                         toBeDeleted.append(jdtPropertiesTmp)
-                        jdtArgs += ['-properties', jdtPropertiesTmp]
+                        jdtArgs += ['-properties', _cygpathU2W(jdtPropertiesTmp)]
                     else:
-                        jdtArgs += ['-properties', jdtProperties]
-                jdtArgs.append('@' + _tpU2W(argfile.name))
+                        jdtArgs += ['-properties', _cygpathU2W(jdtProperties)]
+                jdtArgs.append('@' + _cygpathU2W(argfile.name))
 
                 run_java(jdtVmArgs + jdtArgs)
 
--- a/src/share/tools/ProjectCreator/WinGammaPlatformVC10.java	Fri Oct 03 11:07:44 2014 +0200
+++ b/src/share/tools/ProjectCreator/WinGammaPlatformVC10.java	Fri Oct 03 13:48:58 2014 +0200
@@ -352,8 +352,7 @@
         // Set /On option
         addAttr(rv, "Optimization", opt);
         // Set /FR option.
-        addAttr(rv, "BrowseInformation", "true");
-        addAttr(rv, "BrowseInformationFile", "$(IntDir)");
+        addAttr(rv, "BrowseInformation", "false");
         // Set /MD option.
         addAttr(rv, "RuntimeLibrary", "MultiThreadedDLL");
         // Set /Oy- option
--- a/src/share/vm/graal/graalRuntime.cpp	Fri Oct 03 11:07:44 2014 +0200
+++ b/src/share/vm/graal/graalRuntime.cpp	Fri Oct 03 13:48:58 2014 +0200
@@ -1015,7 +1015,7 @@
 oop GraalRuntime::compute_graal_class_loader(TRAPS) {
   assert(UseGraalClassLoader, "must be");
   TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/loader/Factory", CHECK_NULL);
-  KlassHandle klass = SystemDictionary::resolve_or_null(name, CHECK_NULL);
+  KlassHandle klass = SystemDictionary::resolve_or_fail(name, true, CHECK_NULL);
 
   TempNewSymbol getClassLoader = SymbolTable::new_symbol("newClassLoader", CHECK_NULL);
   JavaValue result(T_OBJECT);