changeset 13299:d64c0112fb94

Merge.
author Doug Simon <doug.simon@oracle.com>
date Wed, 11 Dec 2013 21:57:10 +0100
parents 5a3491b0c2f0 (current diff) d2165b699e0f (diff)
children d5e65a244f7d
files graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java
diffstat 74 files changed, 1584 insertions(+), 974 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Wed Dec 11 21:57:10 2013 +0100
@@ -55,8 +55,7 @@
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatBranchOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatCondMoveOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.ReturnOp;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.SequentialSwitchOp;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.SwitchRangesOp;
+import com.oracle.graal.lir.amd64.AMD64ControlFlow.StrategySwitchOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.TableSwitchOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LeaOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MembarOp;
@@ -220,6 +219,7 @@
 
     @Override
     public void emitJump(LabelRef label) {
+        assert label != null;
         append(new JumpOp(label));
     }
 
@@ -980,20 +980,9 @@
     }
 
     @Override
-    protected void emitSequentialSwitch(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) {
-        // Making a copy of the switch value is necessary because jump table destroys the input
-        // value
-        if (key.getKind() == Kind.Int || key.getKind() == Kind.Long) {
-            append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, Value.ILLEGAL));
-        } else {
-            assert key.getKind() == Kind.Object : key.getKind();
-            append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, newVariable(Kind.Object)));
-        }
-    }
-
-    @Override
-    protected void emitSwitchRanges(int[] lowKeys, int[] highKeys, LabelRef[] targets, LabelRef defaultTarget, Value key) {
-        append(new SwitchRangesOp(lowKeys, highKeys, targets, defaultTarget, key));
+    protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
+        boolean needsTemp = key.getKind() == Kind.Object;
+        append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getKind()) : Value.ILLEGAL));
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Wed Dec 11 21:57:10 2013 +0100
@@ -46,14 +46,13 @@
 import com.oracle.graal.lir.hsail.HSAILControlFlow.CondMoveOp;
 import com.oracle.graal.lir.hsail.HSAILControlFlow.FloatCondMoveOp;
 import com.oracle.graal.lir.hsail.HSAILControlFlow.ReturnOp;
-import com.oracle.graal.lir.hsail.HSAILControlFlow.SwitchOp;
+import com.oracle.graal.lir.hsail.HSAILControlFlow.StrategySwitchOp;
 import com.oracle.graal.lir.hsail.HSAILMove.LeaOp;
 import com.oracle.graal.lir.hsail.HSAILMove.MembarOp;
 import com.oracle.graal.lir.hsail.HSAILMove.MoveFromRegOp;
 import com.oracle.graal.lir.hsail.HSAILMove.MoveToRegOp;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.phases.util.*;
 
 /**
@@ -702,17 +701,10 @@
      * 
      * Note: Only IntegerSwitchNodes are currently supported. The IntegerSwitchNode is the node that
      * Graal generates for any switch construct appearing in Java bytecode.
-     * 
-     * @param x the SwitchNode
      */
     @Override
-    public void emitSwitch(SwitchNode x) {
-        // get the key of the switch.
-        Variable key = load(operand(x.value()));
-        // set the default target.
-        LabelRef defaultTarget = x.defaultSuccessor() == null ? null : getLIRBlock(x.defaultSuccessor());
-        // emit a sequential switch for the specified key and default target.
-        emitSequentialSwitch(x, key, defaultTarget);
+    protected void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) {
+        emitStrategySwitch(new SwitchStrategy.SequentialStrategy(keyProbabilities, keyConstants), value, keyTargets, defaultTarget);
     }
 
     /**
@@ -727,19 +719,19 @@
      * handling operations related to method dispatch. We haven't yet added support for the
      * TypeSwitchNode, so for the time being we have added a check to ensure that the keys are of
      * type int. This also allows us to flag any test cases/execution paths that may trigger the
-     * creation fo a TypeSwitchNode which we don't support yet.
+     * creation of a TypeSwitchNode which we don't support yet.
      * 
      * 
-     * @param keyConstants array of key constants used for the case statements.
+     * @param strategy the strategy used for this switch.
      * @param keyTargets array of branch targets for each of the cases.
      * @param defaultTarget the branch target for the default case.
      * @param key the key that is compared against the key constants in the case statements.
      */
     @Override
-    protected void emitSequentialSwitch(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) {
+    protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
         if (key.getKind() == Kind.Int) {
             // Append the LIR instruction for generating compare and branch instructions.
-            append(new SwitchOp(keyConstants, keyTargets, defaultTarget, key));
+            append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key));
         } else {
             // Throw an exception if the keys aren't ints.
             throw GraalInternalError.unimplemented("Switch statements are only supported for keys of type int");
@@ -747,11 +739,6 @@
     }
 
     @Override
-    protected void emitSwitchRanges(int[] lowKeys, int[] highKeys, LabelRef[] targets, LabelRef defaultTarget, Value key) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    @Override
     protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
         throw GraalInternalError.unimplemented();
     }
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Wed Dec 11 21:57:10 2013 +0100
@@ -51,7 +51,7 @@
 import com.oracle.graal.lir.ptx.PTXControlFlow.FloatCondMoveOp;
 import com.oracle.graal.lir.ptx.PTXControlFlow.ReturnNoValOp;
 import com.oracle.graal.lir.ptx.PTXControlFlow.ReturnOp;
-import com.oracle.graal.lir.ptx.PTXControlFlow.SequentialSwitchOp;
+import com.oracle.graal.lir.ptx.PTXControlFlow.StrategySwitchOp;
 import com.oracle.graal.lir.ptx.PTXControlFlow.TableSwitchOp;
 import com.oracle.graal.lir.ptx.PTXMemOp.LoadOp;
 import com.oracle.graal.lir.ptx.PTXMemOp.LoadParamOp;
@@ -62,6 +62,7 @@
 import com.oracle.graal.lir.ptx.PTXMove.MoveToRegOp;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.util.*;
 
@@ -269,18 +270,26 @@
     }
 
     @Override
-    public Variable emitLoad(Kind kind, Value address, DeoptimizingNode deopting) {
+    public Variable emitLoad(Kind kind, Value address, Access access) {
         PTXAddressValue loadAddress = asAddress(address);
         Variable result = newVariable(kind);
-        append(new LoadOp(kind, result, loadAddress, deopting != null ? state(deopting) : null));
+        LIRFrameState state = null;
+        if (access instanceof DeoptimizingNode) {
+            state = state((DeoptimizingNode) access);
+        }
+        append(new LoadOp(kind, result, loadAddress, state));
         return result;
     }
 
     @Override
-    public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode deopting) {
+    public void emitStore(Kind kind, Value address, Value inputVal, Access access) {
         PTXAddressValue storeAddress = asAddress(address);
         Variable input = load(inputVal);
-        append(new StoreOp(kind, storeAddress, input, deopting != null ? state(deopting) : null));
+        LIRFrameState state = null;
+        if (access instanceof DeoptimizingNode) {
+            state = state((DeoptimizingNode) access);
+        }
+        append(new StoreOp(kind, storeAddress, input, state));
     }
 
     @Override
@@ -779,20 +788,9 @@
     }
 
     @Override
-    protected void emitSequentialSwitch(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) {
-        // Making a copy of the switch value is necessary because jump table destroys the input
-        // value
-        if (key.getKind() == Kind.Int || key.getKind() == Kind.Long) {
-            append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, Value.ILLEGAL, nextPredRegNum++));
-        } else {
-            assert key.getKind() == Kind.Object : key.getKind();
-            append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, newVariable(Kind.Object), nextPredRegNum++));
-        }
-    }
-
-    @Override
-    protected void emitSwitchRanges(int[] lowKeys, int[] highKeys, LabelRef[] targets, LabelRef defaultTarget, Value key) {
-        throw new InternalError("NYI");
+    protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
+        boolean needsTemp = key.getKind() == Kind.Object;
+        append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getKind()) : Value.ILLEGAL, nextPredRegNum++));
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Wed Dec 11 21:57:10 2013 +0100
@@ -50,8 +50,7 @@
 import com.oracle.graal.lir.sparc.SPARCControlFlow.CondMoveOp;
 import com.oracle.graal.lir.sparc.SPARCControlFlow.FloatCondMoveOp;
 import com.oracle.graal.lir.sparc.SPARCControlFlow.ReturnOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.SequentialSwitchOp;
-import com.oracle.graal.lir.sparc.SPARCControlFlow.SwitchRangesOp;
+import com.oracle.graal.lir.sparc.SPARCControlFlow.StrategySwitchOp;
 import com.oracle.graal.lir.sparc.SPARCControlFlow.TableSwitchOp;
 import com.oracle.graal.lir.sparc.SPARCMove.LoadAddressOp;
 import com.oracle.graal.lir.sparc.SPARCMove.MembarOp;
@@ -359,16 +358,9 @@
     }
 
     @Override
-    protected void emitSequentialSwitch(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) {
-        // Making a copy of the switch value is necessary because jump table destroys the input
-        // value
-        assert key.getKind() == Kind.Int || key.getKind() == Kind.Long || key.getKind() == Kind.Object : key.getKind();
-        append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, newVariable(key.getKind())));
-    }
-
-    @Override
-    protected void emitSwitchRanges(int[] lowKeys, int[] highKeys, LabelRef[] targets, LabelRef defaultTarget, Value key) {
-        append(new SwitchRangesOp(lowKeys, highKeys, targets, defaultTarget, key));
+    protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
+        boolean needsTemp = key.getKind() == Kind.Long || key.getKind() == Kind.Object;
+        append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getKind()) : Value.ILLEGAL));
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Wed Dec 11 21:57:10 2013 +0100
@@ -28,7 +28,6 @@
 import static com.oracle.graal.lir.LIR.*;
 import static com.oracle.graal.lir.LIRValueUtil.*;
 import static com.oracle.graal.nodes.ConstantNode.*;
-import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.util.*;
 import java.util.Map.Entry;
@@ -730,118 +729,66 @@
      */
     @Override
     public void emitSwitch(SwitchNode x) {
+        assert x.defaultSuccessor() != null;
+        LabelRef defaultTarget = getLIRBlock(x.defaultSuccessor());
         int keyCount = x.keyCount();
         if (keyCount == 0) {
-            emitJump(getLIRBlock(x.defaultSuccessor()));
+            emitJump(defaultTarget);
         } else {
             Variable value = load(operand(x.value()));
-            LabelRef defaultTarget = x.defaultSuccessor() == null ? null : getLIRBlock(x.defaultSuccessor());
-            if (value.getKind() != Kind.Int) {
-                // hopefully only a few entries
-                emitSequentialSwitch(x, value, defaultTarget);
+            if (keyCount == 1) {
+                assert defaultTarget != null;
+                emitCompareBranch(load(operand(x.value())), x.keyAt(0), Condition.EQ, false, getLIRBlock(x.keySuccessor(0)), defaultTarget);
             } else {
-                assert value.getKind() == Kind.Int;
-                long valueRange = x.keyAt(keyCount - 1).asLong() - x.keyAt(0).asLong() + 1;
-                int switchRangeCount = switchRangeCount(x);
-                if (switchRangeCount == 0) {
-                    emitJump(getLIRBlock(x.defaultSuccessor()));
-                } else if (switchRangeCount >= MinimumJumpTableSize.getValue() && keyCount / (double) valueRange >= MinTableSwitchDensity.getValue()) {
-                    int minValue = x.keyAt(0).asInt();
-                    assert valueRange < Integer.MAX_VALUE;
-                    LabelRef[] targets = new LabelRef[(int) valueRange];
-                    for (int i = 0; i < valueRange; i++) {
-                        targets[i] = defaultTarget;
-                    }
-                    for (int i = 0; i < keyCount; i++) {
-                        targets[x.keyAt(i).asInt() - minValue] = getLIRBlock(x.keySuccessor(i));
-                    }
-                    emitTableSwitch(minValue, defaultTarget, targets, value);
-                } else if (keyCount / switchRangeCount >= RangeTestsSwitchDensity.getValue()) {
-                    emitSwitchRanges(x, switchRangeCount, value, defaultTarget);
+                LabelRef[] keyTargets = new LabelRef[keyCount];
+                Constant[] keyConstants = new Constant[keyCount];
+                double[] keyProbabilities = new double[keyCount];
+                for (int i = 0; i < keyCount; i++) {
+                    keyTargets[i] = getLIRBlock(x.keySuccessor(i));
+                    keyConstants[i] = x.keyAt(i);
+                    keyProbabilities[i] = x.keyProbability(i);
+                }
+                if (value.getKind() != Kind.Int || !x.isSorted()) {
+                    // hopefully only a few entries
+                    emitStrategySwitch(new SwitchStrategy.SequentialStrategy(keyProbabilities, keyConstants), value, keyTargets, defaultTarget);
                 } else {
-                    emitSequentialSwitch(x, value, defaultTarget);
+                    emitStrategySwitch(keyConstants, keyProbabilities, keyTargets, defaultTarget, value);
                 }
             }
         }
     }
 
-    protected void emitSequentialSwitch(final SwitchNode x, Variable key, LabelRef defaultTarget) {
-        int keyCount = x.keyCount();
-        Integer[] indexes = Util.createSortedPermutation(keyCount, new Comparator<Integer>() {
-
-            @Override
-            public int compare(Integer o1, Integer o2) {
-                return x.keyProbability(o1) < x.keyProbability(o2) ? 1 : x.keyProbability(o1) > x.keyProbability(o2) ? -1 : 0;
+    protected void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) {
+        int keyCount = keyConstants.length;
+        SwitchStrategy strategy = SwitchStrategy.getBestStrategy(keyProbabilities, keyConstants, keyTargets);
+        long valueRange = keyConstants[keyCount - 1].asLong() - keyConstants[0].asLong() + 1;
+        double tableSwitchDensity = keyCount / (double) valueRange;
+        /*
+         * This heuristic tries to find a compromise between the effort for the best switch strategy
+         * and the density of a tableswitch. If the effort for the strategy is at least 4, then a
+         * tableswitch is preferred if better than a certain value that starts at 0.5 and lowers
+         * gradually with additional effort.
+         */
+        if (strategy.getAverageEffort() < 4 || tableSwitchDensity < (1 / Math.sqrt(strategy.getAverageEffort()))) {
+            emitStrategySwitch(strategy, value, keyTargets, defaultTarget);
+        } else {
+            int minValue = keyConstants[0].asInt();
+            assert valueRange < Integer.MAX_VALUE;
+            LabelRef[] targets = new LabelRef[(int) valueRange];
+            for (int i = 0; i < valueRange; i++) {
+                targets[i] = defaultTarget;
             }
-        });
-        LabelRef[] keyTargets = new LabelRef[keyCount];
-        Constant[] keyConstants = new Constant[keyCount];
-        for (int i = 0; i < keyCount; i++) {
-            keyTargets[i] = getLIRBlock(x.keySuccessor(indexes[i]));
-            keyConstants[i] = x.keyAt(indexes[i]);
+            for (int i = 0; i < keyCount; i++) {
+                targets[keyConstants[i].asInt() - minValue] = keyTargets[i];
+            }
+            emitTableSwitch(minValue, defaultTarget, targets, value);
         }
-        emitSequentialSwitch(keyConstants, keyTargets, defaultTarget, key);
     }
 
-    protected abstract void emitSequentialSwitch(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key);
-
-    protected abstract void emitSwitchRanges(int[] lowKeys, int[] highKeys, LabelRef[] targets, LabelRef defaultTarget, Value key);
+    protected abstract void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget);
 
     protected abstract void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key);
 
-    private static int switchRangeCount(SwitchNode x) {
-        int keyCount = x.keyCount();
-        int switchRangeCount = 0;
-        int defaultSux = x.defaultSuccessorIndex();
-
-        int key = x.keyAt(0).asInt();
-        int sux = x.keySuccessorIndex(0);
-        for (int i = 0; i < keyCount; i++) {
-            int newKey = x.keyAt(i).asInt();
-            int newSux = x.keySuccessorIndex(i);
-            if (newSux != defaultSux && (newKey != key + 1 || sux != newSux)) {
-                switchRangeCount++;
-            }
-            key = newKey;
-            sux = newSux;
-        }
-        return switchRangeCount;
-    }
-
-    private void emitSwitchRanges(SwitchNode x, int switchRangeCount, Variable keyValue, LabelRef defaultTarget) {
-        assert switchRangeCount >= 1 : "switch ranges should not be used for emitting only the default case";
-
-        int[] lowKeys = new int[switchRangeCount];
-        int[] highKeys = new int[switchRangeCount];
-        LabelRef[] targets = new LabelRef[switchRangeCount];
-
-        int keyCount = x.keyCount();
-        int defaultSuccessor = x.defaultSuccessorIndex();
-
-        int current = -1;
-        int key = -1;
-        int successor = -1;
-        for (int i = 0; i < keyCount; i++) {
-            int newSuccessor = x.keySuccessorIndex(i);
-            int newKey = x.keyAt(i).asInt();
-            if (newSuccessor != defaultSuccessor) {
-                if (key + 1 == newKey && successor == newSuccessor) {
-                    // still in same range
-                    highKeys[current] = newKey;
-                } else {
-                    current++;
-                    lowKeys[current] = newKey;
-                    highKeys[current] = newKey;
-                    targets[current] = getLIRBlock(x.blockSuccessor(newSuccessor));
-                }
-            }
-            key = newKey;
-            successor = newSuccessor;
-        }
-        assert current == switchRangeCount - 1;
-        emitSwitchRanges(lowKeys, highKeys, targets, defaultTarget, keyValue);
-    }
-
     public FrameMap frameMap() {
         return frameMap;
     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed Dec 11 21:57:10 2013 +0100
@@ -59,6 +59,7 @@
 import com.oracle.graal.lir.amd64.AMD64Move.StoreOp;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 
@@ -446,15 +447,18 @@
     /**
      * Returns whether or not the input access is a (de)compression candidate.
      */
-    private static boolean isCompressCandidate(DeoptimizingNode access) {
-        return access != null && ((HeapAccess) access).isCompressible();
+    private static boolean isCompressCandidate(Access access) {
+        return access != null && access.isCompressible();
     }
 
     @Override
-    public Variable emitLoad(Kind kind, Value address, DeoptimizingNode access) {
+    public Variable emitLoad(Kind kind, Value address, Access access) {
         AMD64AddressValue loadAddress = asAddressValue(address);
         Variable result = newVariable(kind);
-        assert access == null || access instanceof HeapAccess;
+        LIRFrameState state = null;
+        if (access instanceof DeoptimizingNode) {
+            state = state((DeoptimizingNode) access);
+        }
         /**
          * Currently, the (de)compression of pointers applies conditionally to some objects (oops,
          * kind==Object) and some addresses (klass pointers, kind==Long). Initially, the input
@@ -467,24 +471,27 @@
          */
         if (isCompressCandidate(access)) {
             if (config.useCompressedOops && kind == Kind.Object) {
-                append(new LoadCompressedPointer(kind, result, getProviders().getRegisters().getHeapBaseRegister().asValue(), loadAddress, access != null ? state(access) : null, getNarrowKlassBase(),
-                                getNarrowOopBase(), getNarrowOopShift(), getLogMinObjectAlignment()));
+                append(new LoadCompressedPointer(kind, result, getProviders().getRegisters().getHeapBaseRegister().asValue(), loadAddress, state, getNarrowKlassBase(), getNarrowOopBase(),
+                                getNarrowOopShift(), getLogMinObjectAlignment()));
             } else if (config.useCompressedClassPointers && kind == Kind.Long) {
-                append(new LoadCompressedPointer(kind, result, getProviders().getRegisters().getHeapBaseRegister().asValue(), loadAddress, access != null ? state(access) : null, getNarrowKlassBase(),
-                                getNarrowOopBase(), getNarrowKlassShift(), getLogKlassAlignment()));
+                append(new LoadCompressedPointer(kind, result, getProviders().getRegisters().getHeapBaseRegister().asValue(), loadAddress, state, getNarrowKlassBase(), getNarrowOopBase(),
+                                getNarrowKlassShift(), getLogKlassAlignment()));
             } else {
-                append(new LoadOp(kind, result, loadAddress, access != null ? state(access) : null));
+                append(new LoadOp(kind, result, loadAddress, state));
             }
         } else {
-            append(new LoadOp(kind, result, loadAddress, access != null ? state(access) : null));
+            append(new LoadOp(kind, result, loadAddress, state));
         }
         return result;
     }
 
     @Override
-    public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode access) {
+    public void emitStore(Kind kind, Value address, Value inputVal, Access access) {
         AMD64AddressValue storeAddress = asAddressValue(address);
-        LIRFrameState state = access != null ? state(access) : null;
+        LIRFrameState state = null;
+        if (access instanceof DeoptimizingNode) {
+            state = state((DeoptimizingNode) access);
+        }
         if (isConstant(inputVal)) {
             Constant c = asConstant(inputVal);
             if (canStoreConstant(c)) {
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Wed Dec 11 21:57:10 2013 +0100
@@ -35,6 +35,7 @@
 import com.oracle.graal.lir.hsail.HSAILMove.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.util.*;
 
@@ -74,8 +75,8 @@
         return config.narrowKlassBase;
     }
 
-    private static boolean isCompressCandidate(DeoptimizingNode access) {
-        return access != null && ((HeapAccess) access).isCompressible();
+    private static boolean isCompressCandidate(Access access) {
+        return access != null && access.isCompressible();
     }
 
     /**
@@ -114,11 +115,13 @@
     }
 
     @Override
-    public Variable emitLoad(Kind kind, Value address, DeoptimizingNode access) {
+    public Variable emitLoad(Kind kind, Value address, Access access) {
         HSAILAddressValue loadAddress = asAddressValue(address);
         Variable result = newVariable(kind);
-        LIRFrameState state = access != null ? state(access) : null;
-        assert access == null || access instanceof HeapAccess;
+        LIRFrameState state = null;
+        if (access instanceof DeoptimizingNode) {
+            state = state((DeoptimizingNode) access);
+        }
         if (isCompressCandidate(access) && config.useCompressedOops && kind == Kind.Object) {
             Variable scratch = newVariable(Kind.Long);
             append(new LoadCompressedPointer(kind, result, scratch, loadAddress, state, getNarrowOopBase(), getNarrowOopShift(), getLogMinObjectAlignment()));
@@ -132,9 +135,12 @@
     }
 
     @Override
-    public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode access) {
+    public void emitStore(Kind kind, Value address, Value inputVal, Access access) {
         HSAILAddressValue storeAddress = asAddressValue(address);
-        LIRFrameState state = access != null ? state(access) : null;
+        LIRFrameState state = null;
+        if (access instanceof DeoptimizingNode) {
+            state = state((DeoptimizingNode) access);
+        }
         Variable input = load(inputVal);
         if (isCompressCandidate(access) && config.useCompressedOops && kind == Kind.Object) {
             Variable scratch = newVariable(Kind.Long);
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Wed Dec 11 21:57:10 2013 +0100
@@ -45,6 +45,7 @@
 import com.oracle.graal.lir.sparc.SPARCMove.StoreConstantOp;
 import com.oracle.graal.lir.sparc.SPARCMove.StoreOp;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 
 public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator {
@@ -231,15 +232,18 @@
         append(op);
     }
 
-    private static boolean isCompressCandidate(DeoptimizingNode access) {
-        return access != null && ((HeapAccess) access).isCompressible();
+    private static boolean isCompressCandidate(Access access) {
+        return access != null && access.isCompressible();
     }
 
     @Override
-    public Variable emitLoad(Kind kind, Value address, DeoptimizingNode access) {
+    public Variable emitLoad(Kind kind, Value address, Access access) {
         SPARCAddressValue loadAddress = asAddressValue(address);
         Variable result = newVariable(kind);
-        assert access == null || access instanceof HeapAccess;
+        LIRFrameState state = null;
+        if (access instanceof DeoptimizingNode) {
+            state = state((DeoptimizingNode) access);
+        }
         if (isCompressCandidate(access)) {
             if (config.useCompressedOops && kind == Kind.Object) {
                 // append(new LoadCompressedPointer(kind, result, loadAddress, access != null ?
@@ -254,18 +258,21 @@
                 // config.logKlassAlignment));
                 throw GraalInternalError.unimplemented();
             } else {
-                append(new LoadOp(kind, result, loadAddress, access != null ? state(access) : null));
+                append(new LoadOp(kind, result, loadAddress, state));
             }
         } else {
-            append(new LoadOp(kind, result, loadAddress, access != null ? state(access) : null));
+            append(new LoadOp(kind, result, loadAddress, state));
         }
         return result;
     }
 
     @Override
-    public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode access) {
+    public void emitStore(Kind kind, Value address, Value inputVal, Access access) {
         SPARCAddressValue storeAddress = asAddressValue(address);
-        LIRFrameState state = access != null ? state(access) : null;
+        LIRFrameState state = null;
+        if (access instanceof DeoptimizingNode) {
+            state = state((DeoptimizingNode) access);
+        }
         if (isConstant(inputVal)) {
             Constant c = asConstant(inputVal);
             if (canStoreConstant(c)) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Wed Dec 11 21:57:10 2013 +0100
@@ -197,7 +197,7 @@
 
     HotSpotResolvedJavaField[] getInstanceFields(HotSpotResolvedObjectType klass);
 
-    HotSpotResolvedJavaMethod[] getMethods(HotSpotResolvedObjectType klass);
+    long getClassInitializer(HotSpotResolvedObjectType klass);
 
     boolean hasFinalizableSubclass(HotSpotResolvedObjectType klass);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Wed Dec 11 21:57:10 2013 +0100
@@ -98,7 +98,7 @@
     public native HotSpotResolvedJavaField[] getInstanceFields(HotSpotResolvedObjectType klass);
 
     @Override
-    public native HotSpotResolvedJavaMethod[] getMethods(HotSpotResolvedObjectType klass);
+    public native long getClassInitializer(HotSpotResolvedObjectType klass);
 
     @Override
     public native int getCompiledCodeSize(long metaspaceMethod);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed Dec 11 21:57:10 2013 +0100
@@ -65,6 +65,9 @@
     @Option(help = "Print compilation queue activity periodically")
     private static final OptionValue<Boolean> PrintQueue = new OptionValue<>(false);
 
+    @Option(help = "Print bootstrap progress and summary")
+    private static final OptionValue<Boolean> PrintBootstrap = new OptionValue<>(true);
+
     @Option(help = "Time limit in milliseconds for bootstrap (-1 for no limit)")
     private static final OptionValue<Integer> TimedBootstrap = new OptionValue<>(-1);
 
@@ -226,8 +229,11 @@
     }
 
     public void bootstrap() throws Throwable {
-        TTY.print("Bootstrapping Graal");
-        TTY.flush();
+        if (PrintBootstrap.getValue()) {
+            TTY.print("Bootstrapping Graal");
+            TTY.flush();
+        }
+
         long startTime = System.currentTimeMillis();
 
         boolean firstRun = true;
@@ -261,8 +267,10 @@
                 Thread.sleep(100);
                 while (z < compileQueue.getCompletedTaskCount() / 100) {
                     ++z;
-                    TTY.print(".");
-                    TTY.flush();
+                    if (PrintBootstrap.getValue()) {
+                        TTY.print(".");
+                        TTY.flush();
+                    }
                 }
 
                 // Are we out of time?
@@ -283,7 +291,10 @@
 
         bootstrapRunning = false;
 
-        TTY.println(" in %d ms (compiled %d methods)", System.currentTimeMillis() - startTime, compileQueue.getCompletedTaskCount());
+        if (PrintBootstrap.getValue()) {
+            TTY.println(" in %d ms (compiled %d methods)", System.currentTimeMillis() - startTime, compileQueue.getCompletedTaskCount());
+        }
+
         if (runtime.getGraphCache() != null) {
             runtime.getGraphCache().clear();
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Wed Dec 11 21:57:10 2013 +0100
@@ -106,7 +106,7 @@
             ValueNode array = arrayLengthNode.array();
             ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt(),
                             BarrierType.NONE, false));
-            tool.createNullCheckGuard(arrayLengthRead, array);
+            tool.createNullCheckGuard(arrayLengthNode, arrayLengthRead, array);
             graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
         } else if (n instanceof Invoke) {
             Invoke invoke = (Invoke) n;
@@ -117,7 +117,7 @@
                 ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
                 GuardingNode receiverNullCheck = null;
                 if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !ObjectStamp.isObjectNonNull(receiver)) {
-                    receiverNullCheck = tool.createNullCheckGuard(invoke, receiver);
+                    receiverNullCheck = tool.createNullCheckGuard(invoke.asNode(), invoke, receiver);
                 }
                 JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
 
@@ -161,7 +161,7 @@
             BarrierType barrierType = getFieldLoadBarrierType(field);
             ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object)));
             graph.replaceFixedWithFixed(loadField, memoryRead);
-            tool.createNullCheckGuard(memoryRead, object);
+            tool.createNullCheckGuard(memoryRead, memoryRead, object);
 
             if (loadField.isVolatile()) {
                 MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
@@ -175,9 +175,9 @@
             ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : storeField.object();
             BarrierType barrierType = getFieldStoreBarrierType(storeField);
             WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field, false), barrierType, storeField.field().getKind() == Kind.Object));
-            tool.createNullCheckGuard(memoryWrite, object);
             memoryWrite.setStateAfter(storeField.stateAfter());
             graph.replaceFixedWithFixed(storeField, memoryWrite);
+            tool.createNullCheckGuard(memoryWrite, memoryWrite, object);
             FixedWithNextNode last = memoryWrite;
             FixedWithNextNode first = memoryWrite;
 
@@ -197,11 +197,10 @@
             graph.replaceFixedWithFixed(cas, atomicNode);
         } else if (n instanceof LoadIndexedNode) {
             LoadIndexedNode loadIndexed = (LoadIndexedNode) n;
-            GuardingNode boundsCheck = createBoundsCheck(loadIndexed, tool);
             Kind elementKind = loadIndexed.elementKind();
             LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false);
             ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp(), BarrierType.NONE, elementKind == Kind.Object));
-            memoryRead.setGuard(boundsCheck);
+            memoryRead.setGuard(createBoundsCheck(loadIndexed, tool));
             graph.replaceFixedWithFixed(loadIndexed, memoryRead);
         } else if (n instanceof StoreIndexedNode) {
             StoreIndexedNode storeIndexed = (StoreIndexedNode) n;
@@ -719,11 +718,11 @@
             Stamp stamp = StampFactory.positiveInt();
             ReadNode readArrayLength = g.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, g), stamp, BarrierType.NONE, false));
             g.addBeforeFixed(n, readArrayLength);
-            tool.createNullCheckGuard(readArrayLength, array);
+            tool.createNullCheckGuard(readArrayLength, readArrayLength, array);
             arrayLength = readArrayLength;
         }
 
-        return tool.createGuard(g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
+        return tool.createGuard(n, g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
     }
 
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Wed Dec 11 21:57:10 2013 +0100
@@ -596,11 +596,9 @@
     }
 
     public ResolvedJavaMethod getClassInitializer() {
-        ResolvedJavaMethod[] methods = runtime().getCompilerToVM().getMethods(this);
-        for (ResolvedJavaMethod m : methods) {
-            if (m.isClassInitializer()) {
-                return m;
-            }
+        long metaspaceMethod = runtime().getCompilerToVM().getClassInitializer(this);
+        if (metaspaceMethod != 0L) {
+            return createMethod(metaspaceMethod);
         }
         return null;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java	Wed Dec 11 21:57:10 2013 +0100
@@ -66,7 +66,7 @@
         }
     }
 
-    protected static void addG1PreWriteBarrier(AccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean doLoad, boolean nullCheck, StructuredGraph graph) {
+    protected static void addG1PreWriteBarrier(FixedAccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean doLoad, boolean nullCheck, StructuredGraph graph) {
         G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(object, value, location, doLoad, nullCheck));
         preBarrier.setDeoptimizationState(node.getDeoptimizationState());
         node.setNullCheck(false);
@@ -74,12 +74,12 @@
         graph.addBeforeFixed(node, preBarrier);
     }
 
-    protected void addG1PostWriteBarrier(AccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean precise, StructuredGraph graph) {
+    protected void addG1PostWriteBarrier(FixedAccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean precise, StructuredGraph graph) {
         final boolean alwaysNull = ObjectStamp.isObjectAlwaysNull(value);
         graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(object, value, location, precise, alwaysNull)));
     }
 
-    protected void addSerialPostWriteBarrier(AccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean precise, StructuredGraph graph) {
+    protected void addSerialPostWriteBarrier(FixedAccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean precise, StructuredGraph graph) {
         final boolean alwaysNull = ObjectStamp.isObjectAlwaysNull(value);
         final LocationNode loc = (precise ? location : null);
         graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(object, loc, precise, alwaysNull)));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java	Wed Dec 11 21:57:10 2013 +0100
@@ -73,12 +73,12 @@
             Node currentNode = iterator.next();
             assert !isSafepoint(currentNode) : "Write barrier must be present " + write;
             if (useG1GC()) {
-                if (!(currentNode instanceof G1PostWriteBarrier) || ((currentNode instanceof G1PostWriteBarrier) && !validateBarrier((AccessNode) write, (WriteBarrier) currentNode))) {
+                if (!(currentNode instanceof G1PostWriteBarrier) || ((currentNode instanceof G1PostWriteBarrier) && !validateBarrier((FixedAccessNode) write, (WriteBarrier) currentNode))) {
                     expandFrontier(frontier, currentNode);
                 }
             } else {
-                if (!(currentNode instanceof SerialWriteBarrier) || ((currentNode instanceof SerialWriteBarrier) && !validateBarrier((AccessNode) write, (WriteBarrier) currentNode)) ||
-                                ((currentNode instanceof SerialWriteBarrier) && !validateBarrier((AccessNode) write, (WriteBarrier) currentNode))) {
+                if (!(currentNode instanceof SerialWriteBarrier) || ((currentNode instanceof SerialWriteBarrier) && !validateBarrier((FixedAccessNode) write, (WriteBarrier) currentNode)) ||
+                                ((currentNode instanceof SerialWriteBarrier) && !validateBarrier((FixedAccessNode) write, (WriteBarrier) currentNode))) {
                     expandFrontier(frontier, currentNode);
                 }
             }
@@ -90,8 +90,8 @@
         final Node previous = node.predecessor();
         final boolean validatePreBarrier = HotSpotReplacementsUtil.useG1GC() && (isObjectWrite(node) || !((ArrayRangeWriteNode) node).isInitialization());
         if (isObjectWrite(node)) {
-            return next instanceof WriteBarrier && validateBarrier((AccessNode) node, (WriteBarrier) next) &&
-                            (!validatePreBarrier || (previous instanceof WriteBarrier && validateBarrier((AccessNode) node, (WriteBarrier) previous)));
+            return next instanceof WriteBarrier && validateBarrier((FixedAccessNode) node, (WriteBarrier) next) &&
+                            (!validatePreBarrier || (previous instanceof WriteBarrier && validateBarrier((FixedAccessNode) node, (WriteBarrier) previous)));
 
         } else if (isObjectArrayRangeWrite(node)) {
             return ((next instanceof ArrayRangeWriteBarrier) && ((ArrayRangeWriteNode) node).getArray() == ((ArrayRangeWriteBarrier) next).getObject()) &&
@@ -103,7 +103,7 @@
 
     private static boolean isObjectWrite(Node node) {
         // Read nodes with barrier attached (G1 Ref field) are not validated yet.
-        return node instanceof AccessNode && ((HeapAccess) node).getBarrierType() != BarrierType.NONE && !(node instanceof ReadNode);
+        return node instanceof FixedAccessNode && ((HeapAccess) node).getBarrierType() != BarrierType.NONE && !(node instanceof ReadNode);
     }
 
     private static boolean isObjectArrayRangeWrite(Node node) {
@@ -127,7 +127,7 @@
         return ((node instanceof DeoptimizingNode) && ((DeoptimizingNode) node).canDeoptimize()) || (node instanceof LoopBeginNode);
     }
 
-    private static boolean validateBarrier(AccessNode write, WriteBarrier barrier) {
+    private static boolean validateBarrier(FixedAccessNode write, WriteBarrier barrier) {
         assert write instanceof WriteNode || write instanceof LoweredCompareAndSwapNode : "Node must be of type requiring a write barrier";
         if ((barrier.getObject() == write.object()) && (!barrier.usePrecise() || (barrier.usePrecise() && barrier.getLocation() == write.location()))) {
             return true;
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/VerifyOptionsPhase.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/VerifyOptionsPhase.java	Wed Dec 11 21:57:10 2013 +0100
@@ -64,12 +64,11 @@
             if (superType != null && !MetaUtil.isJavaLangObject(superType)) {
                 checkType(superType, option, metaAccess, foreignCalls, checked);
             }
-            for (ResolvedJavaMethod method : type.getDeclaredMethods()) {
-                if (method.isClassInitializer()) {
-                    StructuredGraph graph = new StructuredGraph(method);
-                    new GraphBuilderPhase(metaAccess, foreignCalls, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
-                    new VerifyOptionsPhase(type, metaAccess, option).apply(graph);
-                }
+            ResolvedJavaMethod clinit = type.getClassInitializer();
+            if (clinit != null) {
+                StructuredGraph graph = new StructuredGraph(clinit);
+                new GraphBuilderPhase(metaAccess, foreignCalls, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
+                new VerifyOptionsPhase(type, metaAccess, option).apply(graph);
             }
         }
     }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Wed Dec 11 21:57:10 2013 +0100
@@ -36,6 +36,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.SwitchStrategy.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.calc.*;
 
@@ -102,6 +103,61 @@
         }
     }
 
+    public static class StrategySwitchOp extends AMD64LIRInstruction implements BlockEndOp {
+        @Use({CONST}) protected Constant[] keyConstants;
+        private final LabelRef[] keyTargets;
+        private LabelRef defaultTarget;
+        @Alive({REG}) protected Value key;
+        @Temp({REG, ILLEGAL}) protected Value scratch;
+        private final SwitchStrategy strategy;
+
+        public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) {
+            this.strategy = strategy;
+            this.keyConstants = strategy.keyConstants;
+            this.keyTargets = keyTargets;
+            this.defaultTarget = defaultTarget;
+            this.key = key;
+            this.scratch = scratch;
+            assert keyConstants.length == keyTargets.length;
+            assert keyConstants.length == strategy.keyProbabilities.length;
+            assert (scratch.getKind() == Kind.Illegal) == (key.getKind() == Kind.Int || key.getKind() == Kind.Long);
+        }
+
+        @Override
+        public void emitCode(final CompilationResultBuilder crb, final AMD64MacroAssembler masm) {
+            final Register keyRegister = asRegister(key);
+
+            BaseSwitchClosure closure = new BaseSwitchClosure(crb, masm, keyTargets, defaultTarget) {
+                @Override
+                protected void conditionalJump(int index, Condition condition, Label target) {
+                    switch (key.getKind()) {
+                        case Int:
+                            if (crb.codeCache.needsDataPatch(keyConstants[index])) {
+                                crb.recordDataReferenceInCode(keyConstants[index], 0, true);
+                            }
+                            long lc = keyConstants[index].asLong();
+                            assert NumUtil.isInt(lc);
+                            masm.cmpl(keyRegister, (int) lc);
+                            break;
+                        case Long:
+                            masm.cmpq(keyRegister, (AMD64Address) crb.asLongConstRef(keyConstants[index]));
+                            break;
+                        case Object:
+                            assert condition == Condition.EQ || condition == Condition.NE;
+                            Register temp = asObjectReg(scratch);
+                            AMD64Move.move(crb, masm, temp.asValue(Kind.Object), keyConstants[index]);
+                            masm.cmpptr(keyRegister, temp);
+                            break;
+                        default:
+                            throw new GraalInternalError("switch only supported for int, long and object");
+                    }
+                    masm.jcc(intCond(condition), target);
+                }
+            };
+            strategy.run(closure);
+        }
+    }
+
     public static class TableSwitchOp extends AMD64LIRInstruction implements BlockEndOp {
         private final int lowKey;
         private final LabelRef defaultTarget;
@@ -119,128 +175,64 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            tableswitch(crb, masm, lowKey, defaultTarget, targets, asIntReg(index), asLongReg(scratch));
-        }
-    }
-
-    public static class SequentialSwitchOp extends AMD64LIRInstruction implements BlockEndOp {
-        @Use({CONST}) protected Constant[] keyConstants;
-        private final LabelRef[] keyTargets;
-        private LabelRef defaultTarget;
-        @Alive({REG}) protected Value key;
-        @Temp({REG, ILLEGAL}) protected Value scratch;
-
-        public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) {
-            assert keyConstants.length == keyTargets.length;
-            this.keyConstants = keyConstants;
-            this.keyTargets = keyTargets;
-            this.defaultTarget = defaultTarget;
-            this.key = key;
-            this.scratch = scratch;
-        }
+            Register value = asIntReg(index);
+            Register scratchReg = asLongReg(scratch);
 
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            if (key.getKind() == Kind.Int) {
-                Register intKey = asIntReg(key);
-                for (int i = 0; i < keyConstants.length; i++) {
-                    if (crb.codeCache.needsDataPatch(keyConstants[i])) {
-                        crb.recordDataReferenceInCode(keyConstants[i], 0, true);
-                    }
-                    long lc = keyConstants[i].asLong();
-                    assert NumUtil.isInt(lc);
-                    masm.cmpl(intKey, (int) lc);
-                    masm.jcc(ConditionFlag.Equal, keyTargets[i].label());
-                }
-            } else if (key.getKind() == Kind.Long) {
-                Register longKey = asLongReg(key);
-                for (int i = 0; i < keyConstants.length; i++) {
-                    masm.cmpq(longKey, (AMD64Address) crb.asLongConstRef(keyConstants[i]));
-                    masm.jcc(ConditionFlag.Equal, keyTargets[i].label());
-                }
-            } else if (key.getKind() == Kind.Object) {
-                Register objectKey = asObjectReg(key);
-                Register temp = asObjectReg(scratch);
-                for (int i = 0; i < keyConstants.length; i++) {
-                    AMD64Move.move(crb, masm, temp.asValue(Kind.Object), keyConstants[i]);
-                    masm.cmpptr(objectKey, temp);
-                    masm.jcc(ConditionFlag.Equal, keyTargets[i].label());
-                }
+            Buffer buf = masm.codeBuffer;
+            // Compare index against jump table bounds
+            int highKey = lowKey + targets.length - 1;
+            if (lowKey != 0) {
+                // subtract the low value from the switch value
+                masm.subl(value, lowKey);
+                masm.cmpl(value, highKey - lowKey);
             } else {
-                throw new GraalInternalError("sequential switch only supported for int, long and object");
-            }
-            if (!defaultTarget.isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) {
-                masm.jmp(defaultTarget.label());
+                masm.cmpl(value, highKey);
             }
-        }
-    }
-
-    public static class SwitchRangesOp extends AMD64LIRInstruction implements BlockEndOp {
-        private final LabelRef[] keyTargets;
-        private LabelRef defaultTarget;
-        private final int[] lowKeys;
-        private final int[] highKeys;
-        @Alive protected Value key;
-
-        public SwitchRangesOp(int[] lowKeys, int[] highKeys, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) {
-            this.lowKeys = lowKeys;
-            this.highKeys = highKeys;
-            this.keyTargets = keyTargets;
-            this.defaultTarget = defaultTarget;
-            this.key = key;
-        }
 
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            assert isSorted(lowKeys) && isSorted(highKeys);
-
-            Label actualDefaultTarget = defaultTarget == null ? new Label() : defaultTarget.label();
-            int prevHighKey = 0;
-            boolean skipLowCheck = false;
-            for (int i = 0; i < lowKeys.length; i++) {
-                int lowKey = lowKeys[i];
-                int highKey = highKeys[i];
-                if (lowKey == highKey) {
-                    masm.cmpl(asIntReg(key), lowKey);
-                    masm.jcc(ConditionFlag.Equal, keyTargets[i].label());
-                    skipLowCheck = false;
-                } else {
-                    if (!skipLowCheck || (prevHighKey + 1) != lowKey) {
-                        masm.cmpl(asIntReg(key), lowKey);
-                        masm.jcc(ConditionFlag.Less, actualDefaultTarget);
-                    }
-                    masm.cmpl(asIntReg(key), highKey);
-                    masm.jcc(ConditionFlag.LessEqual, keyTargets[i].label());
-                    skipLowCheck = true;
-                }
-                prevHighKey = highKey;
+            // Jump to default target if index is not within the jump table
+            if (defaultTarget != null) {
+                masm.jcc(ConditionFlag.Above, defaultTarget.label());
             }
 
-            if (defaultTarget != null) {
-                if (!defaultTarget.isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) {
-                    masm.jmp(defaultTarget.label());
-                }
-            } else {
-                masm.bind(actualDefaultTarget);
-                masm.hlt();
+            // Set scratch to address of jump table
+            int leaPos = buf.position();
+            masm.leaq(scratchReg, new AMD64Address(AMD64.rip, 0));
+            int afterLea = buf.position();
+
+            // Load jump table entry into scratch and jump to it
+            masm.movslq(value, new AMD64Address(scratchReg, value, Scale.Times4, 0));
+            masm.addq(scratchReg, value);
+            masm.jmp(scratchReg);
+
+            // Inserting padding so that jump table address is 4-byte aligned
+            if ((buf.position() & 0x3) != 0) {
+                masm.nop(4 - (buf.position() & 0x3));
             }
-        }
 
-        @Override
-        protected void verify() {
-            super.verify();
-            assert lowKeys.length == keyTargets.length;
-            assert highKeys.length == keyTargets.length;
-            assert key.getKind() == Kind.Int;
-        }
+            // Patch LEA instruction above now that we know the position of the jump table
+            int jumpTablePos = buf.position();
+            buf.setPosition(leaPos);
+            masm.leaq(scratchReg, new AMD64Address(AMD64.rip, jumpTablePos - afterLea));
+            buf.setPosition(jumpTablePos);
 
-        private static boolean isSorted(int[] values) {
-            for (int i = 1; i < values.length; i++) {
-                if (values[i - 1] >= values[i]) {
-                    return false;
+            // Emit jump table entries
+            for (LabelRef target : targets) {
+                Label label = target.label();
+                int offsetToJumpTableBase = buf.position() - jumpTablePos;
+                if (label.isBound()) {
+                    int imm32 = label.position() - jumpTablePos;
+                    buf.emitInt(imm32);
+                } else {
+                    label.addPatchAt(buf.position());
+
+                    buf.emitByte(0); // pseudo-opcode for jump table entry
+                    buf.emitShort(offsetToJumpTableBase);
+                    buf.emitByte(0); // padding to make jump table entry 4 bytes wide
                 }
             }
-            return true;
+
+            JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, 4);
+            crb.compilationResult.addAnnotation(jt);
         }
     }
 
@@ -286,64 +278,6 @@
         }
     }
 
-    private static void tableswitch(CompilationResultBuilder crb, AMD64MacroAssembler masm, int lowKey, LabelRef defaultTarget, LabelRef[] targets, Register value, Register scratch) {
-        Buffer buf = masm.codeBuffer;
-        // Compare index against jump table bounds
-        int highKey = lowKey + targets.length - 1;
-        if (lowKey != 0) {
-            // subtract the low value from the switch value
-            masm.subl(value, lowKey);
-            masm.cmpl(value, highKey - lowKey);
-        } else {
-            masm.cmpl(value, highKey);
-        }
-
-        // Jump to default target if index is not within the jump table
-        if (defaultTarget != null) {
-            masm.jcc(ConditionFlag.Above, defaultTarget.label());
-        }
-
-        // Set scratch to address of jump table
-        int leaPos = buf.position();
-        masm.leaq(scratch, new AMD64Address(AMD64.rip, 0));
-        int afterLea = buf.position();
-
-        // Load jump table entry into scratch and jump to it
-        masm.movslq(value, new AMD64Address(scratch, value, Scale.Times4, 0));
-        masm.addq(scratch, value);
-        masm.jmp(scratch);
-
-        // Inserting padding so that jump table address is 4-byte aligned
-        if ((buf.position() & 0x3) != 0) {
-            masm.nop(4 - (buf.position() & 0x3));
-        }
-
-        // Patch LEA instruction above now that we know the position of the jump table
-        int jumpTablePos = buf.position();
-        buf.setPosition(leaPos);
-        masm.leaq(scratch, new AMD64Address(AMD64.rip, jumpTablePos - afterLea));
-        buf.setPosition(jumpTablePos);
-
-        // Emit jump table entries
-        for (LabelRef target : targets) {
-            Label label = target.label();
-            int offsetToJumpTableBase = buf.position() - jumpTablePos;
-            if (label.isBound()) {
-                int imm32 = label.position() - jumpTablePos;
-                buf.emitInt(imm32);
-            } else {
-                label.addPatchAt(buf.position());
-
-                buf.emitByte(0); // pseudo-opcode for jump table entry
-                buf.emitShort(offsetToJumpTableBase);
-                buf.emitByte(0); // padding to make jump table entry 4 bytes wide
-            }
-        }
-
-        JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, 4);
-        crb.compilationResult.addAnnotation(jt);
-    }
-
     private static void floatJcc(AMD64MacroAssembler masm, ConditionFlag condition, boolean unorderedIsTrue, Label label) {
         Label endLabel = new Label();
         if (unorderedIsTrue && !trueOnUnordered(condition)) {
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILCompare.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILCompare.java	Wed Dec 11 21:57:10 2013 +0100
@@ -71,7 +71,7 @@
         emitCompare(masm, condition, x, y, unorderedIsTrue);
     }
 
-    private static String conditionToString(Condition condition) {
+    public static String conditionToString(Condition condition) {
         switch (condition) {
             case EQ:
                 return "eq";
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java	Wed Dec 11 21:57:10 2013 +0100
@@ -25,10 +25,12 @@
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.hsail.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.*;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.SwitchStrategy.BaseSwitchClosure;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.calc.*;
 
@@ -46,7 +48,7 @@
      * performing HSAIL code. Thus the execution path for both the TABLESWITCH and LOOKUPSWITCH
      * bytecodes go through this op.
      */
-    public static class SwitchOp extends HSAILLIRInstruction implements BlockEndOp {
+    public static class StrategySwitchOp extends HSAILLIRInstruction implements BlockEndOp {
         /**
          * The array of key constants used for the cases of this switch statement.
          */
@@ -61,20 +63,19 @@
          */
         @Alive({REG}) protected Value key;
 
+        private final SwitchStrategy strategy;
+
         /**
-         * Constructor. Called from the HSAILLIRGenerator.emitSequentialSwitch routine.
-         * 
-         * @param keyConstants
-         * @param keyTargets
-         * @param defaultTarget
-         * @param key
+         * Constructor. Called from the HSAILLIRGenerator.emitStrategySwitch routine.
          */
-        public SwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) {
-            assert keyConstants.length == keyTargets.length;
-            this.keyConstants = keyConstants;
+        public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) {
+            this.strategy = strategy;
+            this.keyConstants = strategy.keyConstants;
             this.keyTargets = keyTargets;
             this.defaultTarget = defaultTarget;
             this.key = key;
+            assert keyConstants.length == keyTargets.length;
+            assert keyConstants.length == strategy.keyProbabilities.length;
         }
 
         /**
@@ -89,22 +90,24 @@
          * @param masm the HSAIL assembler
          */
         @Override
-        public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
-            if (key.getKind() == Kind.Int) {
-                for (int i = 0; i < keyConstants.length; i++) {
-                    // Generate cascading compare and branches for each case.
-                    masm.emitCompare(key, keyConstants[i], "eq", false, false);
-                    masm.cbr(masm.nameOf(keyTargets[i].label()));
+        public void emitCode(CompilationResultBuilder crb, final HSAILAssembler masm) {
+            BaseSwitchClosure closure = new BaseSwitchClosure(crb, masm, keyTargets, defaultTarget) {
+                @Override
+                protected void conditionalJump(int index, Condition condition, Label target) {
+                    switch (key.getKind()) {
+                        case Int:
+                            // Generate cascading compare and branches for each case.
+                            masm.emitCompare(key, keyConstants[index], HSAILCompare.conditionToString(condition), false, false);
+                            masm.cbr(masm.nameOf(target));
+                            break;
+                        case Long:
+                        case Object:
+                        default:
+                            throw new GraalInternalError("switch only supported for int");
+                    }
                 }
-                // Generate a jump for the default target if there is one.
-                if (defaultTarget != null && !defaultTarget.isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) {
-                    masm.jmp(defaultTarget.label());
-                }
-
-            } else {
-                // Throw an exception if the key isn't of type int.
-                throw new GraalInternalError("Switch statments are only supported for int keys");
-            }
+            };
+            strategy.run(closure);
         }
     }
 
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java	Wed Dec 11 21:57:10 2013 +0100
@@ -29,13 +29,14 @@
 import com.oracle.graal.api.code.CompilationResult.JumpTable;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
-import com.oracle.graal.asm.ptx.*;
 import com.oracle.graal.asm.ptx.PTXAssembler.Global;
 import com.oracle.graal.asm.ptx.PTXAssembler.Setp;
+import com.oracle.graal.asm.ptx.*;
 import com.oracle.graal.asm.ptx.PTXMacroAssembler.Mov;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.SwitchStrategy.BaseSwitchClosure;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.calc.*;
 
@@ -193,54 +194,55 @@
         }
     }
 
-    public static class SequentialSwitchOp extends PTXLIRInstruction implements BlockEndOp {
+    public static class StrategySwitchOp extends PTXLIRInstruction implements BlockEndOp {
 
         @Use({CONST}) protected Constant[] keyConstants;
         private final LabelRef[] keyTargets;
         private LabelRef defaultTarget;
         @Alive({REG}) protected Value key;
         @Temp({REG, ILLEGAL}) protected Value scratch;
+        private final SwitchStrategy strategy;
         // Number of predicate register that would be set by this instruction.
         protected int predRegNum;
 
-        public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch, int predReg) {
-            assert keyConstants.length == keyTargets.length;
-            this.keyConstants = keyConstants;
+        public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch, int predReg) {
+            this.strategy = strategy;
+            this.keyConstants = strategy.keyConstants;
             this.keyTargets = keyTargets;
             this.defaultTarget = defaultTarget;
             this.key = key;
             this.scratch = scratch;
+            assert keyConstants.length == keyTargets.length;
+            assert keyConstants.length == strategy.keyProbabilities.length;
+            assert (scratch.getKind() == Kind.Illegal) == (key.getKind() == Kind.Int || key.getKind() == Kind.Long);
             predRegNum = predReg;
         }
 
         @Override
-        public void emitCode(CompilationResultBuilder crb, PTXMacroAssembler masm) {
-            Kind keyKind = key.getKind();
-
-            if (keyKind == Kind.Int || keyKind == Kind.Long) {
-                for (int i = 0; i < keyConstants.length; i++) {
-                    if (crb.codeCache.needsDataPatch(keyConstants[i])) {
-                        crb.recordDataReferenceInCode(keyConstants[i], 0, true);
+        public void emitCode(final CompilationResultBuilder crb, final PTXMacroAssembler masm) {
+            BaseSwitchClosure closure = new BaseSwitchClosure(crb, masm, keyTargets, defaultTarget) {
+                @Override
+                protected void conditionalJump(int index, Condition condition, Label target) {
+                    switch (key.getKind()) {
+                        case Int:
+                        case Long:
+                            if (crb.codeCache.needsDataPatch(keyConstants[index])) {
+                                crb.recordDataReferenceInCode(keyConstants[index], 0, true);
+                            }
+                            new Setp(EQ, keyConstants[index], key, predRegNum).emit(masm);
+                            break;
+                        case Object:
+                            assert condition == Condition.EQ || condition == Condition.NE;
+                            PTXMove.move(crb, masm, scratch, keyConstants[index]);
+                            new Setp(condition, scratch, key, predRegNum).emit(masm);
+                            break;
+                        default:
+                            throw new GraalInternalError("switch only supported for int, long and object");
                     }
-                    new Setp(EQ, keyConstants[i], key, predRegNum).emit(masm);
-                    masm.bra(masm.nameOf(keyTargets[i].label()), predRegNum);
+                    masm.bra(masm.nameOf(target), predRegNum);
                 }
-            } else if (keyKind == Kind.Object) {
-                for (int i = 0; i < keyConstants.length; i++) {
-                    PTXMove.move(crb, masm, scratch, keyConstants[i]);
-                    new Setp(EQ, keyConstants[i], scratch, predRegNum).emit(masm);
-                    masm.bra(keyTargets[i].label().toString(), predRegNum);
-                }
-            } else {
-                throw new GraalInternalError("sequential switch only supported for int, long and object");
-            }
-            if (defaultTarget != null) {
-                if (!defaultTarget.isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) {
-                    masm.jmp(defaultTarget.label());
-                }
-            } else {
-                // masm.hlt();
-            }
+            };
+            strategy.run(closure);
         }
     }
 
@@ -265,41 +267,35 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, PTXMacroAssembler masm) {
-            tableswitch(crb, masm, lowKey, defaultTarget, targets, index, scratch, predRegNum);
+            Buffer buf = masm.codeBuffer;
+
+            // Compare index against jump table bounds
+
+            int highKey = lowKey + targets.length - 1;
+            if (lowKey != 0) {
+                // subtract the low value from the switch value
+                // new Sub(value, value, lowKey).emit(masm);
+                new Setp(GT, index, Constant.forInt(highKey - lowKey), predRegNum).emit(masm);
+            } else {
+                new Setp(GT, index, Constant.forInt(highKey), predRegNum).emit(masm);
+            }
+
+            // Jump to default target if index is not within the jump table
+            if (defaultTarget != null) {
+                masm.bra(masm.nameOf(defaultTarget.label()), predRegNum);
+            }
+
+            // address of jump table
+            int tablePos = buf.position();
+
+            JumpTable jt = new JumpTable(tablePos, lowKey, highKey, 4);
+            String name = "jumptable" + jt.position;
+
+            new Global(index, name, targets).emit(masm);
+
+            // bra(Value, name);
+
+            crb.compilationResult.addAnnotation(jt);
         }
     }
-
-    @SuppressWarnings("unused")
-    private static void tableswitch(CompilationResultBuilder crb, PTXAssembler masm, int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value value, Value scratch, int predNum) {
-        Buffer buf = masm.codeBuffer;
-
-        // Compare index against jump table bounds
-
-        int highKey = lowKey + targets.length - 1;
-        if (lowKey != 0) {
-            // subtract the low value from the switch value
-            // new Sub(value, value, lowKey).emit(masm);
-            new Setp(GT, value, Constant.forInt(highKey - lowKey), predNum).emit(masm);
-        } else {
-            new Setp(GT, value, Constant.forInt(highKey), predNum).emit(masm);
-        }
-
-        // Jump to default target if index is not within the jump table
-        if (defaultTarget != null) {
-            masm.bra(masm.nameOf(defaultTarget.label()), predNum);
-        }
-
-        // address of jump table
-        int tablePos = buf.position();
-
-        JumpTable jt = new JumpTable(tablePos, lowKey, highKey, 4);
-        String name = "jumptable" + jt.position;
-
-        new Global(value, name, targets).emit(masm);
-
-        // bra(Value, name);
-
-        crb.compilationResult.addAnnotation(jt);
-
-    }
 }
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Wed Dec 11 21:57:10 2013 +0100
@@ -30,15 +30,31 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCAssembler.*;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Bpe;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Bpg;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Bpge;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Bpgu;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Bpl;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Bple;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Bpleu;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Bpne;
+import com.oracle.graal.asm.sparc.SPARCAssembler.CC;
+import com.oracle.graal.asm.sparc.SPARCAssembler.ConditionFlag;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Movcc;
+import com.oracle.graal.asm.sparc.SPARCAssembler.Sub;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Bpgeu;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Bplu;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Cmp;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Jmp;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Nop;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Ret;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.*;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.SwitchStrategy.BaseSwitchClosure;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.calc.*;
 
-import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
-
 public class SPARCControlFlow {
 
     public static class BranchOp extends SPARCLIRInstruction implements StandardOp.BranchOp {
@@ -72,40 +88,7 @@
             }
             assert kind == Kind.Int || kind == Kind.Long || kind == Kind.Object;
             CC cc = kind == Kind.Int ? CC.Icc : CC.Xcc;
-            switch (actualCondition) {
-                case EQ:
-                    new Bpe(cc, actualTarget).emit(masm);
-                    break;
-                case NE:
-                    new Bpne(cc, actualTarget).emit(masm);
-                    break;
-                case BT:
-                    new Bplu(cc, actualTarget).emit(masm);
-                    break;
-                case LT:
-                    new Bpl(cc, actualTarget).emit(masm);
-                    break;
-                case BE:
-                    new Bpleu(cc, actualTarget).emit(masm);
-                    break;
-                case LE:
-                    new Bple(cc, actualTarget).emit(masm);
-                    break;
-                case GE:
-                    new Bpge(cc, actualTarget).emit(masm);
-                    break;
-                case AE:
-                    new Bpgeu(cc, actualTarget).emit(masm);
-                    break;
-                case GT:
-                    new Bpg(cc, actualTarget).emit(masm);
-                    break;
-                case AT:
-                    new Bpgu(cc, actualTarget).emit(masm);
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
+            emitCompare(masm, actualTarget, actualCondition, cc);
             new Nop().emit(masm);  // delay slot
             if (needJump) {
                 masm.jmp(falseDestination.label());
@@ -113,6 +96,43 @@
         }
     }
 
+    private static void emitCompare(SPARCMacroAssembler masm, Label target, Condition actualCondition, CC cc) {
+        switch (actualCondition) {
+            case EQ:
+                new Bpe(cc, target).emit(masm);
+                break;
+            case NE:
+                new Bpne(cc, target).emit(masm);
+                break;
+            case BT:
+                new Bplu(cc, target).emit(masm);
+                break;
+            case LT:
+                new Bpl(cc, target).emit(masm);
+                break;
+            case BE:
+                new Bpleu(cc, target).emit(masm);
+                break;
+            case LE:
+                new Bple(cc, target).emit(masm);
+                break;
+            case GE:
+                new Bpge(cc, target).emit(masm);
+                break;
+            case AE:
+                new Bpgeu(cc, target).emit(masm);
+                break;
+            case GT:
+                new Bpg(cc, target).emit(masm);
+                break;
+            case AT:
+                new Bpgu(cc, target).emit(masm);
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
     @Opcode("CMOVE")
     public static class CondMoveOp extends SPARCLIRInstruction {
 
@@ -264,136 +284,64 @@
         }
     }
 
-    public static class SequentialSwitchOp extends SPARCLIRInstruction implements BlockEndOp {
-
+    public static class StrategySwitchOp extends SPARCLIRInstruction implements BlockEndOp {
         @Use({CONST}) protected Constant[] keyConstants;
         private final LabelRef[] keyTargets;
         private LabelRef defaultTarget;
         @Alive({REG}) protected Value key;
         @Temp({REG, ILLEGAL}) protected Value scratch;
+        private final SwitchStrategy strategy;
 
-        public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) {
-            assert keyConstants.length == keyTargets.length;
-            this.keyConstants = keyConstants;
+        public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) {
+            this.strategy = strategy;
+            this.keyConstants = strategy.keyConstants;
             this.keyTargets = keyTargets;
             this.defaultTarget = defaultTarget;
             this.key = key;
             this.scratch = scratch;
+            assert keyConstants.length == keyTargets.length;
+            assert keyConstants.length == strategy.keyProbabilities.length;
+            assert (scratch.getKind() == Kind.Illegal) == (key.getKind() == Kind.Int);
         }
 
         @Override
-        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            if (key.getKind() == Kind.Int) {
-                Register intKey = asIntReg(key);
-                for (int i = 0; i < keyConstants.length; i++) {
-                    if (crb.codeCache.needsDataPatch(keyConstants[i])) {
-                        crb.recordDataReferenceInCode(keyConstants[i], 0, true);
+        public void emitCode(final CompilationResultBuilder crb, final SPARCMacroAssembler masm) {
+            final Register keyRegister = asRegister(key);
+
+            BaseSwitchClosure closure = new BaseSwitchClosure(crb, masm, keyTargets, defaultTarget) {
+                @Override
+                protected void conditionalJump(int index, Condition condition, Label target) {
+                    switch (key.getKind()) {
+                        case Int:
+                            if (crb.codeCache.needsDataPatch(keyConstants[index])) {
+                                crb.recordDataReferenceInCode(keyConstants[index], 0, true);
+                            }
+                            long lc = keyConstants[index].asLong();
+                            assert NumUtil.isInt(lc);
+                            new Cmp(keyRegister, (int) lc).emit(masm);
+                            emitCompare(masm, target, condition, CC.Icc);
+                            break;
+                        case Long: {
+                            Register temp = asLongReg(scratch);
+                            SPARCMove.move(crb, masm, temp.asValue(Kind.Long), keyConstants[index]);
+                            new Cmp(keyRegister, temp).emit(masm);
+                            emitCompare(masm, target, condition, CC.Xcc);
+                            break;
+                        }
+                        case Object: {
+                            Register temp = asObjectReg(scratch);
+                            SPARCMove.move(crb, masm, temp.asValue(Kind.Object), keyConstants[index]);
+                            new Cmp(keyRegister, temp).emit(masm);
+                            emitCompare(masm, target, condition, CC.Ptrcc);
+                            break;
+                        }
+                        default:
+                            throw new GraalInternalError("switch only supported for int, long and object");
                     }
-                    long lc = keyConstants[i].asLong();
-                    assert NumUtil.isInt(lc);
-                    new Cmp(intKey, (int) lc).emit(masm);
-                    new Bpe(CC.Icc, keyTargets[i].label()).emit(masm);
-                    new Nop().emit(masm);  // delay slot
-                }
-            } else if (key.getKind() == Kind.Long) {
-                Register longKey = asLongReg(key);
-                Register temp = asLongReg(scratch);
-                for (int i = 0; i < keyConstants.length; i++) {
-                    SPARCMove.move(crb, masm, temp.asValue(Kind.Long), keyConstants[i]);
-                    new Cmp(longKey, temp).emit(masm);
-                    new Bpe(CC.Xcc, keyTargets[i].label()).emit(masm);
-                    new Nop().emit(masm);  // delay slot
-                }
-            } else if (key.getKind() == Kind.Object) {
-                Register objectKey = asObjectReg(key);
-                Register temp = asObjectReg(scratch);
-                for (int i = 0; i < keyConstants.length; i++) {
-                    SPARCMove.move(crb, masm, temp.asValue(Kind.Object), keyConstants[i]);
-                    new Cmp(objectKey, temp).emit(masm);
-                    new Bpe(CC.Ptrcc, keyTargets[i].label()).emit(masm);
                     new Nop().emit(masm);  // delay slot
                 }
-            } else {
-                throw new GraalInternalError("sequential switch only supported for int, long and object");
-            }
-            if (defaultTarget != null) {
-                if (!defaultTarget.isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) {
-                    masm.jmp(defaultTarget.label());
-                }
-            } else {
-                new Illtrap(0).emit(masm);
-            }
-        }
-    }
-
-    public static class SwitchRangesOp extends SPARCLIRInstruction implements BlockEndOp {
-
-        private final LabelRef[] keyTargets;
-        private LabelRef defaultTarget;
-        private final int[] lowKeys;
-        private final int[] highKeys;
-        @Alive protected Value key;
-
-        public SwitchRangesOp(int[] lowKeys, int[] highKeys, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) {
-            this.lowKeys = lowKeys;
-            this.highKeys = highKeys;
-            this.keyTargets = keyTargets;
-            this.defaultTarget = defaultTarget;
-            this.key = key;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            assert isSorted(lowKeys) && isSorted(highKeys);
-
-            Label actualDefaultTarget = defaultTarget == null ? new Label() : defaultTarget.label();
-            int prevHighKey = 0;
-            boolean skipLowCheck = false;
-            for (int i = 0; i < lowKeys.length; i++) {
-                int lowKey = lowKeys[i];
-                int highKey = highKeys[i];
-                if (lowKey == highKey) {
-                    // masm.cmpl(asIntReg(key), lowKey);
-                    // masm.jcc(ConditionFlag.Equal, keyTargets[i].label());
-                    skipLowCheck = false;
-                } else {
-                    if (!skipLowCheck || (prevHighKey + 1) != lowKey) {
-                        // masm.cmpl(asIntReg(key), lowKey);
-                        // masm.jcc(ConditionFlag.Less, actualDefaultTarget);
-                    }
-                    // masm.cmpl(asIntReg(key), highKey);
-                    // masm.jcc(ConditionFlag.LessEqual, keyTargets[i].label());
-                    skipLowCheck = true;
-                }
-                prevHighKey = highKey;
-            }
-
-            if (defaultTarget != null) {
-                if (!defaultTarget.isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) {
-                    new Bpa(defaultTarget.label()).emit(masm);
-                }
-            } else {
-                masm.bind(actualDefaultTarget);
-                new Illtrap(0).emit(masm);
-            }
-            throw GraalInternalError.unimplemented();
-        }
-
-        @Override
-        protected void verify() {
-            super.verify();
-            assert lowKeys.length == keyTargets.length;
-            assert highKeys.length == keyTargets.length;
-            assert key.getKind() == Kind.Int;
-        }
-
-        private static boolean isSorted(int[] values) {
-            for (int i = 1; i < values.length; i++) {
-                if (values[i - 1] >= values[i]) {
-                    return false;
-                }
-            }
-            return true;
+            };
+            strategy.run(closure);
         }
     }
 
@@ -415,41 +363,40 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            tableswitch(crb, masm, lowKey, defaultTarget, targets, asIntReg(index), asLongReg(scratch));
+            Register value = asIntReg(index);
+            Register scratchReg = asLongReg(scratch);
+
+            Buffer buf = masm.codeBuffer;
+            // Compare index against jump table bounds
+            int highKey = lowKey + targets.length - 1;
+            if (lowKey != 0) {
+                // subtract the low value from the switch value
+                new Sub(value, lowKey, value).emit(masm);
+                // masm.setp_gt_s32(value, highKey - lowKey);
+            } else {
+                // masm.setp_gt_s32(value, highKey);
+            }
+
+            // Jump to default target if index is not within the jump table
+            if (defaultTarget != null) {
+                new Bpgu(CC.Icc, defaultTarget.label()).emit(masm);
+                new Nop().emit(masm);  // delay slot
+            }
+
+            // Load jump table entry into scratch and jump to it
+            // masm.movslq(value, new AMD64Address(scratch, value, Scale.Times4, 0));
+            // masm.addq(scratch, value);
+            new Jmp(new SPARCAddress(scratchReg, 0)).emit(masm);
+            new Nop().emit(masm);  // delay slot
+
+            // address of jump table
+            int tablePos = buf.position();
+
+            JumpTable jt = new JumpTable(tablePos, lowKey, highKey, 4);
+            crb.compilationResult.addAnnotation(jt);
+
+            // SPARC: unimp: tableswitch extract
+            throw GraalInternalError.unimplemented();
         }
     }
-
-    private static void tableswitch(CompilationResultBuilder crb, SPARCAssembler masm, int lowKey, LabelRef defaultTarget, LabelRef[] targets, Register value, Register scratch) {
-        Buffer buf = masm.codeBuffer;
-        // Compare index against jump table bounds
-        int highKey = lowKey + targets.length - 1;
-        if (lowKey != 0) {
-            // subtract the low value from the switch value
-            new Sub(value, lowKey, value).emit(masm);
-            // masm.setp_gt_s32(value, highKey - lowKey);
-        } else {
-            // masm.setp_gt_s32(value, highKey);
-        }
-
-        // Jump to default target if index is not within the jump table
-        if (defaultTarget != null) {
-            new Bpgu(CC.Icc, defaultTarget.label()).emit(masm);
-            new Nop().emit(masm);  // delay slot
-        }
-
-        // Load jump table entry into scratch and jump to it
-        // masm.movslq(value, new AMD64Address(scratch, value, Scale.Times4, 0));
-        // masm.addq(scratch, value);
-        new Jmp(new SPARCAddress(scratch, 0)).emit(masm);
-        new Nop().emit(masm);  // delay slot
-
-        // address of jump table
-        int tablePos = buf.position();
-
-        JumpTable jt = new JumpTable(tablePos, lowKey, highKey, 4);
-        crb.compilationResult.addAnnotation(jt);
-
-        // SPARC: unimp: tableswitch extract
-        throw GraalInternalError.unimplemented();
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SwitchStrategy.java	Wed Dec 11 21:57:10 2013 +0100
@@ -0,0 +1,448 @@
+/*
+ * 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.lir;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.nodes.calc.*;
+
+public abstract class SwitchStrategy {
+
+    private interface SwitchClosure {
+        /**
+         * Generates a conditional or unconditional jump. The jump will be unconditional if
+         * condition is null. If defaultTarget is true, then the jump will go the the default.
+         * 
+         * @param index Index of the value and the jump target (only used if defaultTarget == false)
+         * @param condition The condition on which to jump (can be null)
+         * @param defaultTarget true if the jump should go to the default target, false if index
+         *            should be used.
+         */
+        void conditionalJump(int index, Condition condition, boolean defaultTarget);
+
+        /**
+         * Generates a conditional jump to the target with the specified index. The fall through
+         * should go to the default target.
+         * 
+         * @param index Index of the value and the jump target
+         * @param condition The condition on which to jump
+         * @param canFallThrough true if this is the last instruction in the switch statement, to
+         *            allow for fall-through optimizations.
+         */
+        void conditionalJumpOrDefault(int index, Condition condition, boolean canFallThrough);
+
+        /**
+         * Create a new label and generate a conditional jump to it.
+         * 
+         * @param index Index of the value and the jump target
+         * @param condition The condition on which to jump
+         * @return a new Label
+         */
+        Label conditionalJump(int index, Condition condition);
+
+        /**
+         * Binds a label returned by {@link #conditionalJump(int, Condition)}.
+         */
+        void bind(Label label);
+
+        /**
+         * Return true iff the target of both indexes is the same.
+         */
+        boolean isSameTarget(int index1, int index2);
+    }
+
+    /**
+     * Backends can subclass this abstract class to generate code for switch strategies.
+     */
+    public abstract static class BaseSwitchClosure implements SwitchClosure {
+
+        private final CompilationResultBuilder crb;
+        private final AbstractAssembler masm;
+        private final LabelRef[] keyTargets;
+        private final LabelRef defaultTarget;
+
+        public BaseSwitchClosure(CompilationResultBuilder crb, AbstractAssembler masm, LabelRef[] keyTargets, LabelRef defaultTarget) {
+            this.crb = crb;
+            this.masm = masm;
+            this.keyTargets = keyTargets;
+            this.defaultTarget = defaultTarget;
+        }
+
+        /**
+         * This method generates code for a comparison between the actual value and the constant at
+         * the given index and a condition jump to target.
+         */
+        protected abstract void conditionalJump(int index, Condition condition, Label target);
+
+        public void conditionalJump(int index, Condition condition, boolean targetDefault) {
+            Label target = targetDefault ? defaultTarget.label() : keyTargets[index].label();
+            if (condition == null) {
+                masm.jmp(target);
+            } else {
+                conditionalJump(index, condition, target);
+            }
+        }
+
+        public void conditionalJumpOrDefault(int index, Condition condition, boolean canFallThrough) {
+            if (canFallThrough && defaultTarget.isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) {
+                conditionalJump(index, condition, keyTargets[index].label());
+            } else if (canFallThrough && keyTargets[index].isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) {
+                conditionalJump(index, condition.negate(), defaultTarget.label());
+            } else {
+                conditionalJump(index, condition, keyTargets[index].label());
+                masm.jmp(defaultTarget.label());
+            }
+        }
+
+        public Label conditionalJump(int index, Condition condition) {
+            Label label = new Label();
+            conditionalJump(index, condition, label);
+            return label;
+        }
+
+        public void bind(Label label) {
+            masm.bind(label);
+        }
+
+        public boolean isSameTarget(int index1, int index2) {
+            return keyTargets[index1] == keyTargets[index2];
+        }
+
+    }
+
+    private class EffortClosure implements SwitchClosure {
+
+        private int defaultEffort;
+        private int defaultCount;
+        private final int[] keyEfforts = new int[keyConstants.length];
+        private final int[] keyCounts = new int[keyConstants.length];
+        private final LabelRef[] keyTargets;
+
+        public EffortClosure(LabelRef[] keyTargets) {
+            this.keyTargets = keyTargets;
+        }
+
+        public void conditionalJump(int index, Condition condition, boolean defaultTarget) {
+            // nothing to do
+        }
+
+        public void conditionalJumpOrDefault(int index, Condition condition, boolean canFallThrough) {
+            // nothing to do
+        }
+
+        public Label conditionalJump(int index, Condition condition) {
+            // nothing to do
+            return null;
+        }
+
+        public void bind(Label label) {
+            // nothing to do
+        }
+
+        public boolean isSameTarget(int index1, int index2) {
+            return keyTargets[index1] == keyTargets[index2];
+        }
+
+        public double getAverageEffort() {
+            double defaultProbability = 1;
+            double effort = 0;
+            for (int i = 0; i < keyConstants.length; i++) {
+                effort += keyEfforts[i] * keyProbabilities[i] / keyCounts[i];
+                defaultProbability -= keyProbabilities[i];
+            }
+            return effort + defaultEffort * defaultProbability / defaultCount;
+        }
+    }
+
+    public final double[] keyProbabilities;
+    public final Constant[] keyConstants;
+    private double averageEffort = -1;
+    private EffortClosure effortClosure;
+
+    public SwitchStrategy(double[] keyProbabilities, Constant[] keyConstants) {
+        assert keyConstants.length == keyProbabilities.length && keyConstants.length >= 2;
+        this.keyProbabilities = keyProbabilities;
+        this.keyConstants = keyConstants;
+    }
+
+    public double getAverageEffort() {
+        assert averageEffort >= 0;
+        return averageEffort;
+    }
+
+    /*
+     * Looks for the end of a stretch of key constants that are successive numbers and have the same
+     * target.
+     */
+    protected int getSliceEnd(SwitchClosure closure, int pos) {
+        int slice = pos;
+        while (slice < (keyConstants.length - 1) && keyConstants[slice + 1].asLong() == keyConstants[slice].asLong() + 1 && closure.isSameTarget(slice, slice + 1)) {
+            slice++;
+        }
+        return slice;
+    }
+
+    protected void registerEffort(int rangeStart, int rangeEnd, int depth) {
+        if (effortClosure != null) {
+            for (int i = rangeStart; i <= rangeEnd; i++) {
+                effortClosure.keyEfforts[i] += depth;
+                effortClosure.keyCounts[i]++;
+            }
+        }
+    }
+
+    protected void registerDefaultEffort(int depth) {
+        if (effortClosure != null) {
+            effortClosure.defaultEffort += depth;
+            effortClosure.defaultCount++;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "[avgEffort=" + averageEffort + "]";
+    }
+
+    public static class SequentialStrategy extends SwitchStrategy {
+        private final Integer[] indexes;
+
+        public SequentialStrategy(final double[] keyProbabilities, Constant[] keyConstants) {
+            super(keyProbabilities, keyConstants);
+
+            int keyCount = keyConstants.length;
+            indexes = new Integer[keyCount];
+            for (int i = 0; i < keyCount; i++) {
+                indexes[i] = i;
+            }
+            Arrays.sort(indexes, new Comparator<Integer>() {
+                @Override
+                public int compare(Integer o1, Integer o2) {
+                    return keyProbabilities[o1] < keyProbabilities[o2] ? 1 : keyProbabilities[o1] > keyProbabilities[o2] ? -1 : 0;
+                }
+            });
+        }
+
+        @Override
+        public void run(SwitchClosure closure) {
+            for (int i = 0; i < keyConstants.length - 1; i++) {
+                closure.conditionalJump(indexes[i], Condition.EQ, false);
+                registerEffort(indexes[i], indexes[i], i + 1);
+            }
+            closure.conditionalJumpOrDefault(indexes[keyConstants.length - 1], Condition.EQ, true);
+            registerEffort(indexes[keyConstants.length - 1], indexes[keyConstants.length - 1], keyConstants.length);
+            registerDefaultEffort(keyConstants.length);
+        }
+    }
+
+    public static class RangesStrategy extends SwitchStrategy {
+        private final Integer[] indexes;
+
+        public RangesStrategy(final double[] keyProbabilities, Constant[] keyConstants) {
+            super(keyProbabilities, keyConstants);
+
+            int keyCount = keyConstants.length;
+            indexes = new Integer[keyCount];
+            for (int i = 0; i < keyCount; i++) {
+                indexes[i] = i;
+            }
+            Arrays.sort(indexes, new Comparator<Integer>() {
+                @Override
+                public int compare(Integer o1, Integer o2) {
+                    return keyProbabilities[o1] < keyProbabilities[o2] ? 1 : keyProbabilities[o1] > keyProbabilities[o2] ? -1 : 0;
+                }
+            });
+        }
+
+        @Override
+        public void run(SwitchClosure closure) {
+            int depth = 0;
+            closure.conditionalJump(0, Condition.LT, true);
+            registerDefaultEffort(++depth);
+            int rangeStart = 0;
+            int rangeEnd = getSliceEnd(closure, rangeStart);
+            while (rangeEnd != keyConstants.length - 1) {
+                if (rangeStart == rangeEnd) {
+                    closure.conditionalJump(rangeStart, Condition.EQ, false);
+                    registerEffort(rangeStart, rangeEnd, ++depth);
+                } else {
+                    if (rangeStart == 0 || keyConstants[rangeStart - 1].asLong() + 1 != keyConstants[rangeStart].asLong()) {
+                        closure.conditionalJump(rangeStart, Condition.LT, true);
+                        registerDefaultEffort(++depth);
+                    }
+                    closure.conditionalJump(rangeEnd, Condition.LE, false);
+                    registerEffort(rangeStart, rangeEnd, ++depth);
+                }
+                rangeStart = rangeEnd + 1;
+                rangeEnd = getSliceEnd(closure, rangeStart);
+            }
+            if (rangeStart == rangeEnd) {
+                closure.conditionalJumpOrDefault(rangeStart, Condition.EQ, true);
+                registerEffort(rangeStart, rangeEnd, ++depth);
+                registerDefaultEffort(depth);
+            } else {
+                if (rangeStart == 0 || keyConstants[rangeStart - 1].asLong() + 1 != keyConstants[rangeStart].asLong()) {
+                    closure.conditionalJump(rangeStart, Condition.LT, true);
+                    registerDefaultEffort(++depth);
+                }
+                closure.conditionalJumpOrDefault(rangeEnd, Condition.LE, true);
+                registerEffort(rangeStart, rangeEnd, ++depth);
+                registerDefaultEffort(depth);
+            }
+        }
+    }
+
+    public static class BooleanStrategy extends SwitchStrategy {
+
+        private static final double MIN_PROBABILITY = 0.00001;
+
+        private final double[] probabilitySums;
+
+        public BooleanStrategy(double[] keyProbabilities, Constant[] keyConstants) {
+            super(keyProbabilities, keyConstants);
+            probabilitySums = new double[keyProbabilities.length + 1];
+            double sum = 0;
+            for (int i = 0; i < keyConstants.length; i++) {
+                sum += Math.max(keyProbabilities[i], MIN_PROBABILITY);
+                probabilitySums[i + 1] = sum;
+            }
+        }
+
+        @Override
+        public void run(SwitchClosure closure) {
+            recurseBooleanSwitch(closure, 0, keyConstants.length - 1, 0);
+        }
+
+        /**
+         * Recursively generate a list of comparisons that always subdivides the key list in the
+         * middle (in terms of probability, not index).
+         */
+        private void recurseBooleanSwitch(SwitchClosure closure, int left, int right, int startDepth) {
+            assert startDepth < keyConstants.length * 3 : "runaway recursion in boolean switch";
+            int depth = startDepth;
+            boolean leftBorder = left == 0;
+            boolean rightBorder = right == keyConstants.length - 1;
+
+            if (left + 1 == right) {
+                // only two possible values
+                if (leftBorder || rightBorder || keyConstants[right].asLong() + 1 != keyConstants[right + 1].asLong() || keyConstants[left].asLong() + 1 != keyConstants[right].asLong()) {
+                    closure.conditionalJump(left, Condition.EQ, false);
+                    registerEffort(left, left, ++depth);
+                    closure.conditionalJumpOrDefault(right, Condition.EQ, rightBorder);
+                    registerEffort(right, right, ++depth);
+                    registerDefaultEffort(depth);
+                } else {
+                    closure.conditionalJump(left, Condition.EQ, false);
+                    registerEffort(left, left, ++depth);
+                    closure.conditionalJump(right, null, false);
+                    registerEffort(right, right, depth);
+                }
+                return;
+            }
+            double probabilityStart = probabilitySums[left];
+            double probabilityMiddle = (probabilityStart + probabilitySums[right + 1]) / 2;
+            assert probabilityStart >= probabilityStart;
+            int middle = left;
+            while (getSliceEnd(closure, middle + 1) < right && probabilitySums[getSliceEnd(closure, middle + 1)] < probabilityMiddle) {
+                middle = getSliceEnd(closure, middle + 1);
+            }
+            middle = getSliceEnd(closure, middle);
+            assert middle < keyConstants.length - 1;
+
+            if (getSliceEnd(closure, left) == middle) {
+                if (left == 0) {
+                    closure.conditionalJump(0, Condition.LT, true);
+                    registerDefaultEffort(++depth);
+                }
+                closure.conditionalJump(middle, Condition.LE, false);
+                registerEffort(left, middle, ++depth);
+
+                if (middle + 1 == right) {
+                    closure.conditionalJumpOrDefault(right, Condition.EQ, rightBorder);
+                    registerEffort(right, right, ++depth);
+                    registerDefaultEffort(depth);
+                } else {
+                    if (keyConstants[middle].asLong() + 1 != keyConstants[middle + 1].asLong()) {
+                        closure.conditionalJump(middle + 1, Condition.LT, true);
+                        registerDefaultEffort(++depth);
+                    }
+                    if (getSliceEnd(closure, middle + 1) == right) {
+                        if (right == keyConstants.length - 1 || keyConstants[right].asLong() + 1 != keyConstants[right + 1].asLong()) {
+                            closure.conditionalJumpOrDefault(right, Condition.LE, rightBorder);
+                            registerEffort(middle + 1, right, ++depth);
+                            registerDefaultEffort(depth);
+                        } else {
+                            closure.conditionalJump(middle + 1, null, false);
+                            registerEffort(middle + 1, right, depth);
+                        }
+                    } else {
+                        recurseBooleanSwitch(closure, middle + 1, right, depth);
+                    }
+                }
+            } else if (getSliceEnd(closure, middle + 1) == right) {
+                if (rightBorder || keyConstants[right].asLong() + 1 != keyConstants[right + 1].asLong()) {
+                    closure.conditionalJump(right, Condition.GT, true);
+                    registerDefaultEffort(++depth);
+                }
+                closure.conditionalJump(middle + 1, Condition.GE, false);
+                registerEffort(middle + 1, right, ++depth);
+                recurseBooleanSwitch(closure, left, middle, depth);
+            } else {
+                Label label = closure.conditionalJump(middle + 1, Condition.GE);
+                depth++;
+                recurseBooleanSwitch(closure, left, middle, depth);
+                closure.bind(label);
+                recurseBooleanSwitch(closure, middle + 1, right, depth);
+            }
+        }
+    }
+
+    public abstract void run(SwitchClosure closure);
+
+    private static SwitchStrategy[] getStrategies(double[] keyProbabilities, Constant[] keyConstants, LabelRef[] keyTargets) {
+        SwitchStrategy[] strategies = new SwitchStrategy[]{new SequentialStrategy(keyProbabilities, keyConstants), new RangesStrategy(keyProbabilities, keyConstants),
+                        new BooleanStrategy(keyProbabilities, keyConstants)};
+        for (SwitchStrategy strategy : strategies) {
+            strategy.effortClosure = strategy.new EffortClosure(keyTargets);
+            strategy.run(strategy.effortClosure);
+            strategy.averageEffort = strategy.effortClosure.getAverageEffort();
+            strategy.effortClosure = null;
+        }
+        return strategies;
+    }
+
+    public static SwitchStrategy getBestStrategy(double[] keyProbabilities, Constant[] keyConstants, LabelRef[] keyTargets) {
+        SwitchStrategy[] strategies = getStrategies(keyProbabilities, keyConstants, keyTargets);
+        double bestEffort = Integer.MAX_VALUE;
+        SwitchStrategy bestStrategy = null;
+        for (SwitchStrategy strategy : strategies) {
+            if (strategy.getAverageEffort() < bestEffort) {
+                bestEffort = strategy.getAverageEffort();
+                bestStrategy = strategy;
+            }
+        }
+        return bestStrategy;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java	Wed Dec 11 21:57:10 2013 +0100
@@ -26,7 +26,7 @@
 
 public abstract class DeoptimizingFixedWithNextNode extends FixedWithNextNode implements DeoptimizingNode {
 
-    @Input private FrameState deoptState;
+    @Input(notDataflow = true) private FrameState deoptState;
 
     public DeoptimizingFixedWithNextNode(Stamp stamp) {
         super(stamp);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingNode.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingNode.java	Wed Dec 11 21:57:10 2013 +0100
@@ -25,7 +25,7 @@
 import com.oracle.graal.nodes.spi.*;
 
 /**
- * Interface implemented by nodes which need deoptimization information.
+ * Interface implemented by nodes which may need {@linkplain FrameState deoptimization information}.
  */
 public interface DeoptimizingNode extends NodeWithState {
 
@@ -42,7 +42,7 @@
     /**
      * Sets the deoptimization information associated with this node.
      * 
-     * @param state the FrameState which represents the deoptimization information
+     * @param state the {@link FrameState} which represents the deoptimization information
      */
     void setDeoptimizationState(FrameState state);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Wed Dec 11 21:57:10 2013 +0100
@@ -63,7 +63,7 @@
     @Override
     public void lower(LoweringTool tool) {
         if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FLOATING_GUARDS) {
-            ValueNode guard = tool.createGuard(condition(), getReason(), getAction(), isNegated()).asNode();
+            ValueNode guard = tool.createGuard(this, condition(), getReason(), getAction(), isNegated()).asNode();
             this.replaceAtUsages(guard);
             ValueAnchorNode newAnchor = graph().add(new ValueAnchorNode(guard.asNode()));
             graph().replaceFixedWithFixed(this, newAnchor);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Wed Dec 11 21:57:10 2013 +0100
@@ -33,6 +33,8 @@
 /**
  * The {@code FrameState} class encapsulates the frame state (i.e. local variables and operand
  * stack) at a particular point in the abstract interpretation.
+ * 
+ * This can be used as debug or deoptimization information.
  */
 @NodeInfo(nameTemplate = "FrameState@{p#method/s}:{p#bci}")
 public final class FrameState extends VirtualState implements IterableNodeType {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Wed Dec 11 21:57:10 2013 +0100
@@ -77,7 +77,7 @@
 
     @Override
     public void lower(LoweringTool tool) {
-        GuardingNode guard = tool.createGuard(condition, reason, action, negated);
+        GuardingNode guard = tool.createGuard(next(), condition, reason, action, negated);
         ValueAnchorNode anchor = graph().add(new ValueAnchorNode((ValueNode) guard));
         PiNode pi = graph().unique(new PiNode(object, stamp(), (ValueNode) guard));
         replaceAtUsages(pi);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StateSplit.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StateSplit.java	Wed Dec 11 21:57:10 2013 +0100
@@ -30,19 +30,21 @@
 public interface StateSplit extends NodeWithState {
 
     /**
-     * Gets the state of the JVM frame after execution of this node.
+     * Gets the {@link FrameState} corresponding to the state of the JVM after execution of this
+     * node.
      */
     FrameState stateAfter();
 
     /**
-     * Sets the state of the JVM frame after execution of this node.
+     * Sets the {@link FrameState} corresponding to the state of the JVM after execution of this
+     * node.
      */
     void setStateAfter(FrameState x);
 
     /**
-     * Determines if this node has a side-effect. Execution of such a node changes state visible to
-     * other threads. These nodes denote boundaries across which deoptimization points cannot be
-     * moved.
+     * Determines if this node has a side-effect. Such nodes can not be safely re-executed because
+     * they modified state which is visible to other thread or modified state beyond what is
+     * captured in {@link FrameState} nodes.
      */
     boolean hasSideEffect();
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/Access.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/Access.java	Wed Dec 11 21:57:10 2013 +0100
@@ -24,12 +24,10 @@
 
 import com.oracle.graal.nodes.*;
 
-public interface Access extends DeoptimizingNode, GuardedNode, HeapAccess {
+public interface Access extends GuardedNode, HeapAccess {
 
     ValueNode object();
 
     LocationNode nullCheckLocation();
 
-    void setNullCheck(boolean check);
-
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java	Mon Dec 09 21:40:45 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2011, 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.nodes.extended;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
-
-/**
- * Accesses a value at an memory address specified by an {@linkplain #object object} and a
- * {@linkplain #nullCheckLocation() location}. The access does not include a null check on the
- * object.
- */
-public abstract class AccessNode extends DeoptimizingFixedWithNextNode implements Access, GuardingNode {
-
-    @Input private GuardingNode guard;
-    @Input private ValueNode object;
-    @Input private ValueNode location;
-    private boolean nullCheck;
-    private BarrierType barrierType;
-    private boolean compressible;
-
-    public ValueNode object() {
-        return object;
-    }
-
-    public LocationNode location() {
-        return (LocationNode) location;
-    }
-
-    public LocationNode nullCheckLocation() {
-        return (LocationNode) location;
-    }
-
-    public boolean getNullCheck() {
-        return nullCheck;
-    }
-
-    public void setNullCheck(boolean check) {
-        this.nullCheck = check;
-    }
-
-    public AccessNode(ValueNode object, ValueNode location, Stamp stamp) {
-        this(object, location, stamp, null, BarrierType.NONE, false);
-    }
-
-    public AccessNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType, boolean compressible) {
-        this(object, location, stamp, null, barrierType, compressible);
-    }
-
-    public AccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean compressible) {
-        super(stamp);
-        this.object = object;
-        this.location = location;
-        this.guard = guard;
-        this.barrierType = barrierType;
-        this.compressible = compressible;
-    }
-
-    @Override
-    public boolean canDeoptimize() {
-        return nullCheck;
-    }
-
-    @Override
-    public GuardingNode getGuard() {
-        return guard;
-    }
-
-    @Override
-    public void setGuard(GuardingNode guard) {
-        updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode());
-        this.guard = guard;
-    }
-
-    @Override
-    public BarrierType getBarrierType() {
-        return barrierType;
-    }
-
-    @Override
-    public boolean isCompressible() {
-        return compressible;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java	Wed Dec 11 21:57:10 2013 +0100
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2011, 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.nodes.extended;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Accesses a value at an memory address specified by an {@linkplain #object object} and a
+ * {@linkplain #nullCheckLocation() location}. The access does not include a null check on the
+ * object.
+ */
+public abstract class FixedAccessNode extends DeoptimizingFixedWithNextNode implements Access, GuardingNode {
+
+    @Input private GuardingNode guard;
+    @Input private ValueNode object;
+    @Input private ValueNode location;
+    private boolean nullCheck;
+    private BarrierType barrierType;
+    private boolean compressible;
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public LocationNode location() {
+        return (LocationNode) location;
+    }
+
+    public LocationNode nullCheckLocation() {
+        return (LocationNode) location;
+    }
+
+    public boolean getNullCheck() {
+        return nullCheck;
+    }
+
+    public void setNullCheck(boolean check) {
+        this.nullCheck = check;
+    }
+
+    public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp) {
+        this(object, location, stamp, null, BarrierType.NONE, false);
+    }
+
+    public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType, boolean compressible) {
+        this(object, location, stamp, null, barrierType, compressible);
+    }
+
+    public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean compressible) {
+        super(stamp);
+        this.object = object;
+        this.location = location;
+        this.guard = guard;
+        this.barrierType = barrierType;
+        this.compressible = compressible;
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return nullCheck;
+    }
+
+    @Override
+    public GuardingNode getGuard() {
+        return guard;
+    }
+
+    @Override
+    public void setGuard(GuardingNode guard) {
+        updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode());
+        this.guard = guard;
+    }
+
+    @Override
+    public BarrierType getBarrierType() {
+        return barrierType;
+    }
+
+    @Override
+    public boolean isCompressible() {
+        return compressible;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Wed Dec 11 21:57:10 2013 +0100
@@ -27,9 +27,9 @@
 import com.oracle.graal.nodes.type.*;
 
 /**
- * An {@link AccessNode} that can be converted to a {@link FloatingAccessNode}.
+ * An {@link FixedAccessNode} that can be converted to a {@link FloatingAccessNode}.
  */
-public abstract class FloatableAccessNode extends AccessNode {
+public abstract class FloatableAccessNode extends FixedAccessNode {
 
     public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp) {
         super(object, location, stamp);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Wed Dec 11 21:57:10 2013 +0100
@@ -30,8 +30,6 @@
 
     @Input private ValueNode object;
     @Input private LocationNode location;
-    @Input private FrameState deoptState;
-    private boolean nullCheck;
     private BarrierType barrierType;
     private boolean compressible;
 
@@ -51,14 +49,6 @@
         return location.getLocationIdentity();
     }
 
-    public boolean getNullCheck() {
-        return nullCheck;
-    }
-
-    public void setNullCheck(boolean check) {
-        this.nullCheck = check;
-    }
-
     public FloatingAccessNode(ValueNode object, LocationNode location, Stamp stamp) {
         super(stamp);
         this.object = object;
@@ -74,34 +64,14 @@
     }
 
     @Override
-    public boolean canDeoptimize() {
-        return nullCheck;
-    }
-
-    @Override
-    public FrameState getDeoptimizationState() {
-        return deoptState;
-    }
-
-    @Override
-    public void setDeoptimizationState(FrameState f) {
-        updateUsages(deoptState, f);
-        deoptState = f;
-    }
-
-    @Override
     public BarrierType getBarrierType() {
         return barrierType;
     }
 
-    public FrameState getState() {
-        return deoptState;
-    }
-
     @Override
     public boolean isCompressible() {
         return compressible;
     }
 
-    public abstract Access asFixedNode();
+    public abstract FixedAccessNode asFixedNode();
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Wed Dec 11 21:57:10 2013 +0100
@@ -71,7 +71,7 @@
     }
 
     @Override
-    public Access asFixedNode() {
+    public FixedAccessNode asFixedNode() {
         return graph().add(new ReadNode(object(), nullCheckLocation(), stamp(), getGuard(), getBarrierType(), isCompressible()));
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Wed Dec 11 21:57:10 2013 +0100
@@ -54,6 +54,15 @@
         assert keySuccessors.length == keys.length + 1;
         assert keySuccessors.length == keyProbabilities.length;
         this.keys = keys;
+        assert assertValues();
+        assert assertSorted();
+    }
+
+    private boolean assertSorted() {
+        for (int i = 1; i < keys.length; i++) {
+            assert keys[i - 1] < keys[i];
+        }
+        return true;
     }
 
     /**
@@ -70,6 +79,11 @@
         this(value, new AbstractBeginNode[successorCount], keys, keyProbabilities, keySuccessors);
     }
 
+    @Override
+    public boolean isSorted() {
+        return true;
+    }
+
     /**
      * Gets the key at the specified index.
      * 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Wed Dec 11 21:57:10 2013 +0100
@@ -31,7 +31,7 @@
 import com.oracle.graal.nodes.virtual.*;
 
 /**
- * Reads an {@linkplain AccessNode accessed} value.
+ * Reads an {@linkplain FixedAccessNode accessed} value.
  */
 public final class ReadNode extends FloatableAccessNode implements LIRLowerable, Canonicalizable, PiPushable, Virtualizable {
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Wed Dec 11 21:57:10 2013 +0100
@@ -47,6 +47,7 @@
      */
     public SwitchNode(ValueNode value, AbstractBeginNode[] successors, int[] keySuccessors, double[] keyProbabilities) {
         super(StampFactory.forVoid());
+        assert value.kind() == Kind.Int || value.kind() == Kind.Long || value.kind() == Kind.Object;
         assert keySuccessors.length == keyProbabilities.length;
         this.successors = new NodeSuccessorList<>(this, successors);
         this.value = value;
@@ -65,6 +66,15 @@
         return true;
     }
 
+    protected boolean assertValues() {
+        Kind kind = value.kind();
+        for (int i = 0; i < keyCount(); i++) {
+            Constant key = keyAt(i);
+            assert key.getKind() == kind;
+        }
+        return true;
+    }
+
     @Override
     public double probability(AbstractBeginNode successor) {
         double sum = 0;
@@ -107,6 +117,8 @@
         return value;
     }
 
+    public abstract boolean isSorted();
+
     /**
      * The number of distinct keys in this switch.
      */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Wed Dec 11 21:57:10 2013 +0100
@@ -31,9 +31,9 @@
 import com.oracle.graal.nodes.virtual.*;
 
 /**
- * Writes a given {@linkplain #value() value} a {@linkplain AccessNode memory location}.
+ * Writes a given {@linkplain #value() value} a {@linkplain FixedAccessNode memory location}.
  */
-public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single, MemoryAccess, Virtualizable {
+public final class WriteNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single, MemoryAccess, Virtualizable {
 
     @Input private ValueNode value;
     @Input(notDataflow = true) private FrameState stateAfter;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Wed Dec 11 21:57:10 2013 +0100
@@ -31,7 +31,7 @@
 /**
  * Represents the lowered version of an atomic compare-and-swap operation{@code CompareAndSwapNode}.
  */
-public class LoweredCompareAndSwapNode extends AccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single {
+public class LoweredCompareAndSwapNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single {
 
     @Input private ValueNode expectedValue;
     @Input private ValueNode newValue;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Wed Dec 11 21:57:10 2013 +0100
@@ -56,6 +56,25 @@
         assert successors.length <= keys.length + 1;
         assert keySuccessors.length == keyProbabilities.length;
         this.keys = keys;
+        assert assertValues();
+    }
+
+    @Override
+    public boolean isSorted() {
+        Kind kind = value().kind();
+        if (kind.isNumericInteger()) {
+            Constant lastKey = null;
+            for (int i = 0; i < keyCount(); i++) {
+                Constant key = keyAt(i);
+                if (lastKey != null && key.asLong() <= lastKey.asLong()) {
+                    return false;
+                }
+                lastKey = key;
+            }
+            return true;
+        } else {
+            return false;
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Wed Dec 11 21:57:10 2013 +0100
@@ -61,9 +61,9 @@
 
     Value emitAddress(StackSlot slot);
 
-    Value emitLoad(Kind kind, Value address, DeoptimizingNode deopting);
+    Value emitLoad(Kind kind, Value address, Access access);
 
-    void emitStore(Kind kind, Value address, Value input, DeoptimizingNode deopting);
+    void emitStore(Kind kind, Value address, Value input, Access access);
 
     void emitMembar(int barriers);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java	Wed Dec 11 21:57:10 2013 +0100
@@ -39,11 +39,11 @@
 
     Replacements getReplacements();
 
-    GuardingNode createNullCheckGuard(GuardedNode guardedNode, ValueNode object);
+    GuardingNode createNullCheckGuard(FixedNode before, GuardedNode guardedNode, ValueNode object);
 
-    GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action);
+    GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action);
 
-    GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated);
+    GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated);
 
     Assumptions assumptions();
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java	Wed Dec 11 21:57:10 2013 +0100
@@ -22,8 +22,29 @@
  */
 package com.oracle.graal.nodes.spi;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import static com.oracle.graal.nodes.StructuredGraph.GuardsStage.*;
 
+/**
+ * Interface for nodes which have {@link FrameState} nodes as input.
+ * <p>
+ * Some node can declare more than one interface which requires a {@link FrameState} input (e.g.
+ * {@link DeoptimizingNode} and {@link StateSplit}). Since this interface can only report one
+ * {@link FrameState}, such nodes must ensure they only maintain a link to at most one
+ * {@link FrameState} at all times. Usually this is not a problem because {@link FrameState} are
+ * associated only with {@link StateSplit} nodes before the {@link #AFTER_FSA} stage and only with
+ * {@link DeoptimizingNode} after.
+ * 
+ * 
+ */
 public interface NodeWithState {
+    /**
+     * Gets the {@link FrameState} associated with this node.
+     * 
+     * @return the {@link FrameState} associated with this node
+     */
     FrameState getState();
+
+    Node asNode();
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Wed Dec 11 21:57:10 2013 +0100
@@ -226,7 +226,6 @@
             if (accessNode.canFloat()) {
                 MemoryNode lastLocationAccess = state.getLastLocationAccess(locationIdentity);
                 FloatingAccessNode floatingNode = accessNode.asFloatingNode(lastLocationAccess);
-                floatingNode.setNullCheck(accessNode.getNullCheck());
                 ValueAnchorNode anchor = null;
                 GuardingNode guard = accessNode.getGuard();
                 if (guard != null) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Wed Dec 11 21:57:10 2013 +0100
@@ -86,10 +86,11 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        assert checkFixedDeopts(graph);
-        ReentrantNodeIterator.apply(new FrameStateAssignmentClosure(), graph.start(), null, null);
-
-        graph.setGuardsStage(GuardsStage.AFTER_FSA);
+        assert graph.getGuardsStage().ordinal() >= GuardsStage.FIXED_DEOPTS.ordinal() && checkFixedDeopts(graph);
+        if (graph.getGuardsStage().ordinal() < GuardsStage.AFTER_FSA.ordinal()) {
+            ReentrantNodeIterator.apply(new FrameStateAssignmentClosure(), graph.start(), null, null);
+            graph.setGuardsStage(GuardsStage.AFTER_FSA);
+        }
     }
 
     private static boolean checkFixedDeopts(StructuredGraph graph) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Wed Dec 11 21:57:10 2013 +0100
@@ -95,12 +95,13 @@
             GuardNode guard = nullGuarded.get(access.object());
             if (guard != null && isImplicitNullCheck(access.nullCheckLocation())) {
                 access.setGuard(guard.getGuard());
-                Access fixedAccess = access;
+                FixedAccessNode fixedAccess;
                 if (access instanceof FloatingAccessNode) {
                     fixedAccess = ((FloatingAccessNode) access).asFixedNode();
-                    replaceCurrent((FixedWithNextNode) fixedAccess.asNode());
+                    replaceCurrent(fixedAccess.asNode());
+                } else {
+                    fixedAccess = (FixedAccessNode) access;
                 }
-                assert fixedAccess instanceof FixedNode;
                 fixedAccess.setNullCheck(true);
                 LogicNode condition = guard.condition();
                 guard.replaceAndDelete(fixedAccess.asNode());
@@ -185,14 +186,17 @@
 
     @Override
     protected void run(StructuredGraph graph, MidTierContext context) {
-        SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
-        schedule.apply(graph);
+        if (graph.getGuardsStage().ordinal() < GuardsStage.FIXED_DEOPTS.ordinal()) {
+            SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
+            schedule.apply(graph);
 
-        for (Block block : schedule.getCFG().getBlocks()) {
-            processBlock(block, schedule, context.getTarget().implicitNullCheckLimit);
+            for (Block block : schedule.getCFG().getBlocks()) {
+                processBlock(block, schedule, context != null ? context.getTarget().implicitNullCheckLimit : 0);
+            }
+            graph.setGuardsStage(GuardsStage.FIXED_DEOPTS);
         }
 
-        graph.setGuardsStage(GuardsStage.FIXED_DEOPTS);
+        assert graph.getNodes(GuardNode.class).isEmpty();
     }
 
     private static void processBlock(Block block, SchedulePhase schedule, int implicitNullCheckLimit) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Wed Dec 11 21:57:10 2013 +0100
@@ -1297,6 +1297,7 @@
     public static Map<Node, Node> inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
         final NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
         StructuredGraph graph = invoke.asNode().graph();
+        assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal();
 
         FrameState stateAfter = invoke.stateAfter();
         assert stateAfter == null || stateAfter.isAlive();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Wed Dec 11 21:57:10 2013 +0100
@@ -89,7 +89,7 @@
         }
 
         @Override
-        public GuardingNode createNullCheckGuard(GuardedNode guardedNode, ValueNode object) {
+        public GuardingNode createNullCheckGuard(FixedNode before, GuardedNode guardedNode, ValueNode object) {
             if (ObjectStamp.isObjectNonNull(object)) {
                 // Short cut creation of null check guard if the object is known to be non-null.
                 return null;
@@ -97,10 +97,10 @@
             StructuredGraph graph = guardedNode.asNode().graph();
             if (graph.getGuardsStage().ordinal() > GuardsStage.FLOATING_GUARDS.ordinal()) {
                 NullCheckNode nullCheck = graph.add(new NullCheckNode(object));
-                graph.addBeforeFixed((FixedNode) guardedNode, nullCheck);
+                graph.addBeforeFixed(before, nullCheck);
                 return nullCheck;
             } else {
-                GuardingNode guard = createGuard(graph.unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true);
+                GuardingNode guard = createGuard(before, graph.unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true);
                 assert guardedNode.getGuard() == null;
                 guardedNode.setGuard(guard);
                 return guard;
@@ -108,8 +108,8 @@
         }
 
         @Override
-        public GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action) {
-            return createGuard(condition, deoptReason, action, false);
+        public GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action) {
+            return createGuard(before, condition, deoptReason, action, false);
         }
 
         @Override
@@ -117,11 +117,32 @@
             return context.getAssumptions();
         }
 
+        private class DummyGuardHandle extends ValueNode implements GuardedNode {
+            @Input private GuardingNode guard;
+
+            public DummyGuardHandle(GuardingNode guard) {
+                super(StampFactory.forVoid());
+                this.guard = guard;
+            }
+
+            public GuardingNode getGuard() {
+                return guard;
+            }
+
+            public void setGuard(GuardingNode guard) {
+                updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode());
+                this.guard = guard;
+            }
+
+            @Override
+            public ValueNode asNode() {
+                return this;
+            }
+
+        }
+
         @Override
-        public GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) {
-            if (condition.graph().getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) {
-                throw new GraalInternalError("Cannot create guards after guard lowering");
-            }
+        public GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) {
             if (OptEliminateGuards.getValue()) {
                 for (Node usage : condition.usages()) {
                     if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage) && ((GuardNode) usage).negated() == negated) {
@@ -129,12 +150,21 @@
                     }
                 }
             }
-            GuardNode newGuard = guardAnchor.asNode().graph().unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated));
-            if (OptEliminateGuards.getValue()) {
-                activeGuards.grow();
-                activeGuards.mark(newGuard);
+            StructuredGraph graph = before.graph();
+            if (condition.graph().getGuardsStage().ordinal() >= StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) {
+                FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(condition, deoptReason, action, negated));
+                graph.addBeforeFixed(before, fixedGuard);
+                DummyGuardHandle handle = graph.add(new DummyGuardHandle(fixedGuard));
+                fixedGuard.lower(this);
+                return handle.getGuard();
+            } else {
+                GuardNode newGuard = graph.unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated));
+                if (OptEliminateGuards.getValue()) {
+                    activeGuards.grow();
+                    activeGuards.mark(newGuard);
+                }
+                return newGuard;
             }
-            return newGuard;
         }
 
         @Override
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Wed Dec 11 21:57:10 2013 +0100
@@ -891,7 +891,7 @@
                         closure.apply(cfg.getNodeToBlock().get(pred));
                     }
                 } else {
-                    // For the time being, only FrameStates can be connected to StateSplits.
+                    // For the time being, FrameStates can only be connected to NodeWithState.
                     if (!(usage instanceof FrameState)) {
                         throw new SchedulingError(usage.toString());
                     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Wed Dec 11 21:57:10 2013 +0100
@@ -325,7 +325,7 @@
             this.method = info.method;
             this.guardsStage = guardsStage;
             this.values = new Object[info.getParameterCount()];
-            this.hash = info.method.hashCode();
+            this.hash = info.method.hashCode() + 31 * guardsStage.hashCode();
         }
 
         protected void setParam(int paramIdx, Object value) {
@@ -475,8 +475,7 @@
         ResolvedJavaMethod method = snippetGraph.method();
         Signature signature = method.getSignature();
 
-        Assumptions assumptions = providers.getReplacements().getAssumptions();
-        PhaseContext phaseContext = new PhaseContext(providers, assumptions);
+        PhaseContext phaseContext = new PhaseContext(providers, new Assumptions(false));
 
         // Copy snippet graph, replacing constant parameters with given arguments
         final StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method());
@@ -578,11 +577,14 @@
             }
         } while (exploded);
 
+        GuardsStage guardsStage = args.cacheKey.guardsStage;
         // Perform lowering on the snippet
-        snippetCopy.setGuardsStage(args.cacheKey.guardsStage);
+        if (guardsStage.ordinal() >= GuardsStage.FIXED_DEOPTS.ordinal()) {
+            new GuardLoweringPhase().apply(snippetCopy, null);
+        }
+        snippetCopy.setGuardsStage(guardsStage);
         try (Scope s = Debug.scope("LoweringSnippetTemplate", snippetCopy)) {
-            PhaseContext c = new PhaseContext(providers, new Assumptions(false));
-            new LoweringPhase(new CanonicalizerPhase(true)).apply(snippetCopy, c);
+            new LoweringPhase(new CanonicalizerPhase(true)).apply(snippetCopy, phaseContext);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Wed Dec 11 21:57:10 2013 +0100
@@ -31,6 +31,7 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
@@ -96,9 +97,15 @@
      * @param replacementGraph a replacement (i.e., snippet or method substitution) graph
      */
     protected StructuredGraph lowerReplacement(final StructuredGraph replacementGraph, LoweringTool tool) {
-        replacementGraph.setGuardsStage(graph().getGuardsStage());
         final PhaseContext c = new PhaseContext(tool.getMetaAccess(), tool.getConstantReflection(), tool.getLowerer(), tool.getReplacements(), tool.assumptions());
-        try (Scope s = Debug.scope("LoweringReplacement", replacementGraph)) {
+        GuardsStage guardsStage = graph().getGuardsStage();
+        if (guardsStage.ordinal() >= GuardsStage.FIXED_DEOPTS.ordinal()) {
+            new GuardLoweringPhase().apply(replacementGraph, null);
+            if (guardsStage.ordinal() >= GuardsStage.AFTER_FSA.ordinal()) {
+                new FrameStateAssignmentPhase().apply(replacementGraph);
+            }
+        }
+        try (Scope s = Debug.scope("LoweringSnippetTemplate", replacementGraph)) {
             new LoweringPhase(new CanonicalizerPhase(true)).apply(replacementGraph, c);
         } catch (Throwable e) {
             throw Debug.handle(e);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Wed Dec 11 21:57:10 2013 +0100
@@ -130,19 +130,14 @@
     }
 
     private void processNodeWithState(NodeWithState nodeWithState, final BlockT state, final GraphEffectList effects) {
-        FrameState stateAfter = nodeWithState.getState();
-        if (stateAfter != null) {
-            if (stateAfter.usages().count() > 1) {
-                if (nodeWithState instanceof StateSplit) {
-                    StateSplit split = (StateSplit) nodeWithState;
-                    stateAfter = (FrameState) stateAfter.copyWithInputs();
-                    split.setStateAfter(stateAfter);
-                } else {
-                    throw GraalInternalError.shouldNotReachHere();
-                }
+        FrameState frameState = nodeWithState.getState();
+        if (frameState != null) {
+            if (frameState.usages().count() > 1) {
+                nodeWithState.asNode().replaceFirstInput(frameState, frameState.copyWithInputs());
+                frameState = nodeWithState.getState();
             }
             final HashSet<ObjectState> virtual = new HashSet<>();
-            stateAfter.applyToNonVirtual(new NodeClosure<ValueNode>() {
+            frameState.applyToNonVirtual(new NodeClosure<ValueNode>() {
 
                 @Override
                 public void apply(Node usage, ValueNode value) {
@@ -203,7 +198,7 @@
                 } else {
                     v = new MaterializedObjectState(obj.virtual, obj.getMaterializedValue());
                 }
-                effects.addVirtualMapping(stateAfter, v);
+                effects.addVirtualMapping(frameState, v);
             }
         }
     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Wed Dec 11 21:57:10 2013 +0100
@@ -91,18 +91,24 @@
         boolean success = true;
         for (Node node : obsoleteNodes) {
             if (flood.isMarked(node)) {
-                TTY.print("offending node path:");
+                TTY.println("offending node path:");
                 Node current = node;
-                while (current != null) {
-                    TTY.println(current.toString());
+                TTY.print(current.toString());
+                while (true) {
                     current = path.get(current);
-                    if (current != null && current instanceof FixedNode && !obsoleteNodes.contains(current)) {
-                        break;
+                    if (current != null) {
+                        TTY.print(" -> " + current.toString());
+                        if (current instanceof FixedNode && !obsoleteNodes.contains(current)) {
+                            break;
+                        }
                     }
                 }
                 success = false;
             }
         }
+        if (!success) {
+            TTY.println();
+        }
         return success;
     }
 
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java	Wed Dec 11 21:57:10 2013 +0100
@@ -26,8 +26,22 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
-import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.*;
-import com.oracle.truffle.api.dsl.test.TypeSystemTest.*;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.DoubleEvaluatedNodeFactory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.EvaluatedNodeFactory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedGenerationFactory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs0Factory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs1Factory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs2Factory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs3Factory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs4Factory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs5Factory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.UseDoubleEvaluatedNodeFactory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.UseEvaluatedNodeFactory;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.ArgumentNode;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.ChildrenNode;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestArguments;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 
@@ -126,4 +140,120 @@
         }
     }
 
+    @Test
+    public void test0VarArgs1() {
+        TestRootNode<TestEvaluatedVarArgs0> root = TestHelper.createRoot(TestEvaluatedVarArgs0Factory.getInstance());
+        Assert.assertEquals(42, root.getNode().execute1(null));
+    }
+
+    abstract static class TestEvaluatedVarArgs0 extends ChildrenNode {
+
+        public abstract Object execute1(VirtualFrame frame, Object... value);
+
+        @Specialization
+        int call() {
+            return 42;
+        }
+    }
+
+    @Test
+    public void test1VarArgs1() {
+        TestRootNode<TestEvaluatedVarArgs1> root = TestHelper.createRoot(TestEvaluatedVarArgs1Factory.getInstance());
+        Assert.assertEquals(42, root.getNode().execute1(null, 42));
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test1VarArgs2() {
+        TestRootNode<TestEvaluatedVarArgs2> root = TestHelper.createRoot(TestEvaluatedVarArgs2Factory.getInstance());
+        Assert.assertEquals(-1, root.getNode().execute1(null));
+    }
+
+    abstract static class TestEvaluatedVarArgs1 extends ChildrenNode {
+
+        public abstract Object execute1(VirtualFrame frame, Object... value);
+
+        @Specialization
+        int call(int exp0) {
+            return exp0;
+        }
+    }
+
+    @Test
+    public void test2VarArgs1() {
+        TestRootNode<TestEvaluatedVarArgs2> root = TestHelper.createRoot(TestEvaluatedVarArgs2Factory.getInstance());
+        Assert.assertEquals(42, root.getNode().execute1(null, 21, 21));
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test2VarArgs2() {
+        TestRootNode<TestEvaluatedVarArgs2> root = TestHelper.createRoot(TestEvaluatedVarArgs2Factory.getInstance());
+        Assert.assertEquals(-1, root.getNode().execute1(null, 42));
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test2VarArgs3() {
+        TestRootNode<TestEvaluatedVarArgs2> root = TestHelper.createRoot(TestEvaluatedVarArgs2Factory.getInstance());
+        Assert.assertEquals(-1, root.getNode().execute1(null));
+    }
+
+    abstract static class TestEvaluatedVarArgs2 extends ChildrenNode {
+
+        public abstract Object execute1(VirtualFrame frame, Object... value);
+
+        @Specialization
+        int call(int exp0, int exp1) {
+            return exp0 + exp1;
+        }
+    }
+
+    @Test
+    public void test3VarArgs1() {
+        TestRootNode<TestEvaluatedVarArgs3> root = TestHelper.createRoot(TestEvaluatedVarArgs3Factory.getInstance());
+        Assert.assertEquals(42, root.getNode().execute1(null, 42));
+    }
+
+    @NodeChild
+    abstract static class TestEvaluatedVarArgs3 extends ValueNode {
+
+        public abstract Object execute1(VirtualFrame frame, Object... value);
+
+        @Specialization
+        int call(int exp0) {
+            return exp0;
+        }
+    }
+
+    @Test
+    public void test4VarArgs1() {
+        TestRootNode<TestEvaluatedVarArgs4> root = TestHelper.createRoot(TestEvaluatedVarArgs4Factory.getInstance());
+        Assert.assertEquals(42, root.getNode().execute1(null, 21, 21));
+    }
+
+    @NodeChildren({@NodeChild, @NodeChild})
+    abstract static class TestEvaluatedVarArgs4 extends ValueNode {
+
+        public abstract Object execute1(VirtualFrame frame, Object... value);
+
+        @Specialization
+        int call(int exp0, int exp1) {
+            return exp0 + exp1;
+        }
+    }
+
+    @Test
+    public void test5VarArgs1() {
+        TestRootNode<TestEvaluatedVarArgs5> root = TestHelper.createRoot(TestEvaluatedVarArgs5Factory.getInstance());
+        Assert.assertEquals(42, root.getNode().execute1(null));
+    }
+
+    abstract static class TestEvaluatedVarArgs5 extends ValueNode {
+
+        public abstract Object execute1(VirtualFrame frame, Object... value);
+
+        @Specialization
+        int call() {
+            return 42;
+        }
+    }
+
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeExecutableElement.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeExecutableElement.java	Wed Dec 11 21:57:10 2013 +0100
@@ -113,6 +113,11 @@
         return name;
     }
 
+    public CodeTreeBuilder getBuilder() {
+        CodeTree tree = this.bodyTree;
+        return createBuilder().tree(tree);
+    }
+
     public CodeTreeBuilder createBuilder() {
         CodeTreeBuilder builder = new CodeTreeBuilder(null);
         this.bodyTree = builder.getTree();
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/AbstractCodeWriter.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/AbstractCodeWriter.java	Wed Dec 11 21:57:10 2013 +0100
@@ -274,16 +274,28 @@
                 }
             }
         } else {
+            Element enclosing = f.getEnclosingElement();
             writeModifiers(f.getModifiers());
-            write(useImport(f, f.asType()));
 
-            if (f.getEnclosingElement().getKind() == ElementKind.METHOD) {
-                ExecutableElement method = (ExecutableElement) f.getEnclosingElement();
+            boolean varArgs = false;
+            if (enclosing.getKind() == ElementKind.METHOD) {
+                ExecutableElement method = (ExecutableElement) enclosing;
                 if (method.isVarArgs() && method.getParameters().indexOf(f) == method.getParameters().size() - 1) {
-                    write("...");
+                    varArgs = true;
                 }
             }
 
+            TypeMirror varType = f.asType();
+            if (varArgs) {
+                if (varType.getKind() == TypeKind.ARRAY) {
+                    varType = ((ArrayType) varType).getComponentType();
+                }
+                write(useImport(f, varType));
+                write("...");
+            } else {
+                write(useImport(f, varType));
+            }
+
             write(" ");
             write(f.getSimpleName());
             if (init != null) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ExecutableTypeMethodParser.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ExecutableTypeMethodParser.java	Wed Dec 11 21:57:10 2013 +0100
@@ -39,6 +39,7 @@
         super(context, node);
         setEmitErrors(false);
         setParseNullOnError(false);
+        setUseVarArgs(true);
     }
 
     @Override
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Wed Dec 11 21:57:10 2013 +0100
@@ -478,6 +478,14 @@
         return createCastType(typeSystem, sourceType, targetType, true, expression);
     }
 
+    public CodeTree createDeoptimize(CodeTreeBuilder parent) {
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+        builder.startStatement();
+        builder.startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end();
+        builder.end();
+        return builder.getRoot();
+    }
+
     private class NodeFactoryFactory extends ClassElementFactory<NodeData> {
 
         private final Map<NodeData, List<TypeElement>> childTypes;
@@ -1015,7 +1023,7 @@
                 CodeTreeBuilder access = builder.create();
                 access.string("this.").string(child.getName());
                 if (child.getCardinality().isMany()) {
-                    access.string("[").string(String.valueOf(param.getIndex())).string("]");
+                    access.string("[").string(String.valueOf(param.getSpecificationIndex())).string("]");
                 }
 
                 String oldName = "old" + Utils.firstLetterUpperCase(param.getLocalName());
@@ -2102,7 +2110,7 @@
                 return null;
             }
             String prefix = expect ? "expect" : "execute";
-            return prefix + Utils.firstLetterUpperCase(child.getName()) + Utils.firstLetterUpperCase(Utils.getSimpleName(param.getType())) + param.getIndex();
+            return prefix + Utils.firstLetterUpperCase(child.getName()) + Utils.firstLetterUpperCase(Utils.getSimpleName(param.getType())) + param.getSpecificationIndex();
         }
 
         private List<CodeExecutableElement> createExecuteChilds(ActualParameter param, Set<TypeData> expectTypes) {
@@ -2418,7 +2426,7 @@
                 throw new AssertionError();
             }
             if (targetParameter.getSpecification().isIndexed()) {
-                builder.string("[" + targetParameter.getIndex() + "]");
+                builder.string("[" + targetParameter.getSpecificationIndex() + "]");
             }
             return builder.getRoot();
         }
@@ -2470,14 +2478,6 @@
             return builder.getRoot();
         }
 
-        protected CodeTree createDeoptimize(CodeTreeBuilder parent) {
-            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-            builder.startStatement();
-            builder.startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end();
-            builder.end();
-            return builder.getRoot();
-        }
-
         protected CodeTree createReturnExecuteAndSpecialize(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData current, ActualParameter exceptionParam, String reason) {
             NodeData node = current.getNode();
             SpecializationData generic = node.getGenericSpecialization();
@@ -2729,7 +2729,7 @@
                 }
                 CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, true);
                 clazz.add(executeMethod);
-                CodeTreeBuilder builder = executeMethod.createBuilder();
+                CodeTreeBuilder builder = executeMethod.getBuilder();
                 CodeTree result = createExecuteBody(builder, specialization, execType);
                 if (result != null) {
                     builder.tree(result);
@@ -2757,7 +2757,7 @@
             ExecutableTypeData execType = parser.parse(Arrays.asList(executeCached)).get(0);
 
             CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, false);
-            CodeTreeBuilder builder = executeMethod.createBuilder();
+            CodeTreeBuilder builder = executeMethod.getBuilder();
 
             if (specialization.isGeneric() || specialization.isPolymorphic()) {
                 builder.startThrow().startNew(getContext().getType(AssertionError.class));
@@ -2786,7 +2786,7 @@
             NodeData node = specialization.getNode();
 
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-            builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end();
+            builder.tree(createDeoptimize(builder));
 
             builder.declaration(getContext().getTruffleTypes().getNode(), "root", "this");
             builder.declaration(getContext().getType(int.class), "depth", "0");
@@ -2851,15 +2851,46 @@
         private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType, boolean evaluated) {
             CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod());
 
+            CodeTreeBuilder builder = method.createBuilder();
             int i = 0;
+            int signatureIndex = -1;
             for (VariableElement param : method.getParameters()) {
                 CodeVariableElement var = CodeVariableElement.clone(param);
                 ActualParameter actualParameter = execType.getParameters().get(i);
+                if (actualParameter.getSpecification().isSignature()) {
+                    signatureIndex++;
+                }
+
+                String name;
                 if (evaluated && actualParameter.getSpecification().isSignature()) {
-                    var.setName(valueNameEvaluated(actualParameter));
+                    name = valueNameEvaluated(actualParameter);
                 } else {
-                    var.setName(valueName(actualParameter));
+                    name = valueName(actualParameter);
                 }
+
+                int varArgCount = getModel().getSignatureSize() - signatureIndex;
+                if (evaluated && actualParameter.isVarArgs()) {
+                    ActualParameter baseVarArgs = actualParameter;
+                    name = valueName(baseVarArgs) + "Args";
+
+                    builder.startAssert().string(name).string(" != null").end();
+                    builder.startAssert().string(name).string(".length == ").string(String.valueOf(varArgCount)).end();
+                    if (varArgCount > 0) {
+                        List<ActualParameter> varArgsParameter = execType.getParameters().subList(i, execType.getParameters().size());
+                        for (ActualParameter varArg : varArgsParameter) {
+                            if (varArgCount <= 0) {
+                                break;
+                            }
+                            TypeMirror type = baseVarArgs.getType();
+                            if (type.getKind() == TypeKind.ARRAY) {
+                                type = ((ArrayType) type).getComponentType();
+                            }
+                            builder.declaration(type, valueNameEvaluated(varArg), name + "[" + varArg.getVarArgsIndex() + "]");
+                            varArgCount--;
+                        }
+                    }
+                }
+                var.setName(name);
                 method.getParameters().set(i, var);
                 i++;
             }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java	Wed Dec 11 21:57:10 2013 +0100
@@ -78,6 +78,13 @@
         this.assumptions = splitSource.assumptions;
     }
 
+    public int getSignatureSize() {
+        if (getSpecializations() != null && !getSpecializations().isEmpty()) {
+            return getSpecializations().get(0).getSignatureSize();
+        }
+        return 0;
+    }
+
     public boolean needsFrame(ProcessorContext context) {
         for (SpecializationData specialization : specializations) {
             if (!specialization.isReachable()) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java	Wed Dec 11 21:57:10 2013 +0100
@@ -205,6 +205,7 @@
 
             finalizeSpecializations(elements, splittedNode);
             verifyNode(splittedNode, elements);
+            expandExecutableTypeVarArgs(splittedNode);
             createPolymorphicSpecializations(splittedNode);
             assignShortCircuitsToSpecializations(splittedNode);
         }
@@ -217,6 +218,26 @@
         return node;
     }
 
+    private static void expandExecutableTypeVarArgs(NodeData node) {
+        for (ExecutableTypeData executableMethod : node.getExecutableTypes()) {
+            if (!(executableMethod.getMethod().isVarArgs() && executableMethod.getSpecification().isVariableRequiredArguments())) {
+                continue;
+            }
+            int expandArguments = node.getSignatureSize() - executableMethod.getSignatureSize();
+            if (expandArguments > 0) {
+                int signatureSize = executableMethod.getSignatureSize();
+                ActualParameter parameter = executableMethod.getSignatureParameter(signatureSize - 1);
+                for (int i = 0; i < expandArguments; i++) {
+                    int newVarArgsIndex = parameter.getVarArgsIndex() + i + 1;
+                    int newSpecificationIndex = parameter.getSpecificationIndex() + i + 1;
+                    executableMethod.getParameters().add(
+                                    new ActualParameter(parameter.getSpecification(), parameter.getTypeSystemType(), newSpecificationIndex, newVarArgsIndex, parameter.isImplicit()));
+                }
+
+            }
+        }
+    }
+
     private void createPolymorphicSpecializations(NodeData node) {
         if (!node.needsRewrites(context) || !node.isPolymorphic()) {
             node.setPolymorphicSpecializations(Collections.<SpecializationData> emptyList());
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationData.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationData.java	Wed Dec 11 21:57:10 2013 +0100
@@ -261,7 +261,7 @@
         if (getParameters().isEmpty() || !Utils.typeEquals(getParameters().get(0).getType(), frameType)) {
             ParameterSpec frameSpec = getSpecification().findParameterSpec("frame");
             if (frameSpec != null) {
-                getParameters().add(0, new ActualParameter(frameSpec, frameType, -1, false));
+                getParameters().add(0, new ActualParameter(frameSpec, frameType, -1, -1, false));
             }
         }
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/ActualParameter.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/ActualParameter.java	Wed Dec 11 21:57:10 2013 +0100
@@ -33,49 +33,56 @@
     private TypeData typeSystemType;
     private TemplateMethod method;
     private final String localName;
-    private final int index;
+    private final int specificationIndex;
+    private final int varArgsIndex;
     private final boolean implicit;
     private final TypeMirror type;
 
-    public ActualParameter(ParameterSpec specification, TypeMirror actualType, int index, boolean implicit) {
+    public ActualParameter(ParameterSpec specification, TypeMirror actualType, int specificationIndex, int varArgsIndex, boolean implicit) {
         this.specification = specification;
         this.type = actualType;
         this.typeSystemType = null;
 
-        this.index = index;
+        this.specificationIndex = specificationIndex;
         this.implicit = implicit;
         String valueName = specification.getName() + "Value";
 
         if (specification.isIndexed()) {
-            valueName += index;
+            valueName += specificationIndex;
         }
+        this.varArgsIndex = varArgsIndex;
         this.localName = valueName;
     }
 
-    public ActualParameter(ParameterSpec specification, TypeData actualType, int index, boolean implicit) {
-        this(specification, actualType.getPrimitiveType(), index, implicit);
+    public ActualParameter(ParameterSpec specification, TypeData actualType, int specificationIndex, int varArgsIndex, boolean implicit) {
+        this(specification, actualType.getPrimitiveType(), specificationIndex, varArgsIndex, implicit);
         this.typeSystemType = actualType;
     }
 
     public ActualParameter(ActualParameter parameter, TypeData otherType) {
-        this(parameter.specification, otherType, parameter.index, parameter.implicit);
+        this(parameter.specification, otherType, parameter.specificationIndex, parameter.varArgsIndex, parameter.implicit);
     }
 
     public ActualParameter(ActualParameter parameter) {
         this.specification = parameter.specification;
         this.type = parameter.type;
         this.typeSystemType = parameter.typeSystemType;
-        this.index = parameter.index;
+        this.specificationIndex = parameter.specificationIndex;
         this.implicit = parameter.implicit;
         this.localName = parameter.localName;
+        this.varArgsIndex = parameter.varArgsIndex;
+    }
+
+    public int getVarArgsIndex() {
+        return varArgsIndex;
     }
 
     public boolean isImplicit() {
         return implicit;
     }
 
-    public int getIndex() {
-        return index;
+    public int getSpecificationIndex() {
+        return specificationIndex;
     }
 
     public String getLocalName() {
@@ -102,6 +109,10 @@
         return typeSystemType;
     }
 
+    public boolean isVarArgs() {
+        return varArgsIndex >= 0;
+    }
+
     public ActualParameter getPreviousParameter() {
         return method.getPreviousParam(this);
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/MethodSpec.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/MethodSpec.java	Wed Dec 11 21:57:10 2013 +0100
@@ -37,6 +37,7 @@
     private final List<ParameterSpec> optional = new ArrayList<>();
     private final List<ParameterSpec> required = new ArrayList<>();
 
+    private int minimumRequiredArguments;
     private boolean variableRequiredArguments;
     private List<TypeDef> typeDefinitions;
 
@@ -44,6 +45,14 @@
         this.returnType = returnType;
     }
 
+    public void setMinimumRequiredArguments(int minimumRequiredArguments) {
+        this.minimumRequiredArguments = minimumRequiredArguments;
+    }
+
+    public int getMinimumRequiredArguments() {
+        return minimumRequiredArguments;
+    }
+
     public void setVariableRequiredArguments(boolean variableArguments) {
         this.variableRequiredArguments = variableArguments;
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java	Wed Dec 11 21:57:10 2013 +0100
@@ -202,6 +202,17 @@
         return prev;
     }
 
+    public int getSignatureSize() {
+        int signatureSize = 0;
+        for (ActualParameter parameter : getParameters()) {
+            if (!parameter.getSpecification().isSignature()) {
+                continue;
+            }
+            signatureSize++;
+        }
+        return signatureSize;
+    }
+
     public Signature getSignature() {
         Signature signature = new Signature();
         for (ActualParameter parameter : getReturnTypeAndParameters()) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethodParser.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethodParser.java	Wed Dec 11 21:57:10 2013 +0100
@@ -44,12 +44,21 @@
 
     private boolean emitErrors = true;
     private boolean parseNullOnError = false;
+    private boolean useVarArgs = false;
 
     public TemplateMethodParser(ProcessorContext context, T template) {
         this.template = template;
         this.context = context;
     }
 
+    protected void setUseVarArgs(boolean useVarArgs) {
+        this.useVarArgs = useVarArgs;
+    }
+
+    public boolean isUseVarArgs() {
+        return useVarArgs;
+    }
+
     public boolean isEmitErrors() {
         return emitErrors;
     }
@@ -140,7 +149,7 @@
 
         ParameterSpec returnTypeSpec = methodSpecification.getReturnType();
 
-        ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, method.getReturnType(), template, 0, false);
+        ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, method.getReturnType(), template, 0, -1, false);
         if (returnTypeMirror == null) {
             if (emitErrors) {
                 E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections.<ActualParameter> emptyList()), true);
@@ -161,7 +170,7 @@
             parameterTypes.add(var.asType());
         }
 
-        List<ActualParameter> parameters = parseParameters(methodSpecification, parameterTypes);
+        List<ActualParameter> parameters = parseParameters(methodSpecification, parameterTypes, isUseVarArgs() && method.isVarArgs());
         if (parameters == null) {
             if (isEmitErrors()) {
                 E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections.<ActualParameter> emptyList()), true);
@@ -201,7 +210,7 @@
      * ones are cut and used to parse the optional parameters. All those remaining parameters must
      * be consumed otherwise its an error.
      */
-    private List<ActualParameter> parseParameters(MethodSpec spec, List<TypeMirror> parameterTypes) {
+    private List<ActualParameter> parseParameters(MethodSpec spec, List<TypeMirror> parameterTypes, boolean varArgs) {
         List<TypeMirror> implicitTypes = spec.getImplicitRequiredTypes();
 
         int offset = -1;
@@ -211,7 +220,7 @@
             offset++;
             types = new ConsumableListIterator<>(new ArrayList<>(implicitTypes));
             types.data.addAll(parameterTypes.subList(offset, parameterTypes.size()));
-            parsedRequired = parseParametersRequired(spec, types);
+            parsedRequired = parseParametersRequired(spec, types, varArgs);
         }
 
         if (parsedRequired == null && offset >= 0) {
@@ -244,7 +253,7 @@
             int oldIndex = types.getIndex();
             int optionalCount = 1;
             for (ParameterSpec paramspec : optionals) {
-                ActualParameter optionalParam = matchParameter(paramspec, type, template, 0, false);
+                ActualParameter optionalParam = matchParameter(paramspec, type, template, 0, -1, false);
                 if (optionalParam != null) {
                     optionals.consume(optionalCount);
                     types.consume();
@@ -264,9 +273,10 @@
         return parsedParams;
     }
 
-    private List<ActualParameter> parseParametersRequired(MethodSpec spec, ConsumableListIterator<TypeMirror> types) {
+    private List<ActualParameter> parseParametersRequired(MethodSpec spec, ConsumableListIterator<TypeMirror> types, boolean varArgs) {
         List<ActualParameter> parsedParams = new ArrayList<>();
 
+        int varArgsParameterIndex = -1;
         int specificationParameterIndex = 0;
         ConsumableListIterator<ParameterSpec> required = new ConsumableListIterator<>(spec.getRequired());
         while (required.get() != null || types.get() != null) {
@@ -278,8 +288,15 @@
                 }
                 break;
             }
+            TypeMirror actualType = types.get();
+            if (varArgs && types.isLast()) {
+                if (actualType.getKind() == TypeKind.ARRAY) {
+                    actualType = ((ArrayType) actualType).getComponentType();
+                }
+                varArgsParameterIndex++;
+            }
             boolean implicit = types.getIndex() < spec.getImplicitRequiredTypes().size();
-            ActualParameter resolvedParameter = matchParameter(required.get(), types.get(), template, specificationParameterIndex, implicit);
+            ActualParameter resolvedParameter = matchParameter(required.get(), actualType, template, specificationParameterIndex, varArgsParameterIndex, implicit);
             if (resolvedParameter == null) {
                 if (required.get().getCardinality() == Cardinality.MANY) {
                     required.consume();
@@ -289,7 +306,16 @@
                 return null;
             } else {
                 parsedParams.add(resolvedParameter);
-                types.consume();
+
+                if (varArgs && types.isLast()) {
+                    /* Both varargs spec and varargs definition. Need to consume to terminate. */
+                    if (required.get().getCardinality() == Cardinality.MANY) {
+                        types.consume();
+                    }
+                } else {
+                    types.consume();
+                }
+
                 if (required.get().getCardinality() == Cardinality.ONE) {
                     required.consume();
                     specificationParameterIndex = 0;
@@ -299,7 +325,7 @@
             }
         }
 
-        if (!types.toList().isEmpty()) {
+        if (!types.toList().isEmpty() && !(varArgs && types.isLast())) {
             // additional types -> error
             return null;
         }
@@ -311,7 +337,7 @@
         return parsedParams;
     }
 
-    private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template originalTemplate, int index, boolean implicit) {
+    private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template originalTemplate, int specificationIndex, int varArgsIndex, boolean implicit) {
         TypeMirror resolvedType = mirror;
         if (hasError(resolvedType)) {
             resolvedType = context.resolveNotYetCompiledType(mirror, originalTemplate);
@@ -323,9 +349,9 @@
 
         TypeData resolvedTypeData = getTypeSystem().findTypeData(resolvedType);
         if (resolvedTypeData != null) {
-            return new ActualParameter(specification, resolvedTypeData, index, implicit);
+            return new ActualParameter(specification, resolvedTypeData, specificationIndex, varArgsIndex, implicit);
         } else {
-            return new ActualParameter(specification, resolvedType, index, implicit);
+            return new ActualParameter(specification, resolvedType, specificationIndex, varArgsIndex, implicit);
         }
     }
 
@@ -346,6 +372,10 @@
             return data.get(index);
         }
 
+        public boolean isLast() {
+            return index == data.size() - 1;
+        }
+
         public E consume() {
             return consume(1);
         }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardParser.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardParser.java	Wed Dec 11 21:57:10 2013 +0100
@@ -93,9 +93,11 @@
             } else {
                 ActualParameter p;
                 if (parameter.getTypeSystemType() != null) {
-                    p = new ActualParameter(specializationParameter.getSpecification(), parameter.getTypeSystemType(), specializationParameter.getIndex(), parameter.isImplicit());
+                    p = new ActualParameter(specializationParameter.getSpecification(), parameter.getTypeSystemType(), specializationParameter.getSpecificationIndex(),
+                                    specializationParameter.getVarArgsIndex(), parameter.isImplicit());
                 } else {
-                    p = new ActualParameter(specializationParameter.getSpecification(), parameter.getType(), specializationParameter.getIndex(), parameter.isImplicit());
+                    p = new ActualParameter(specializationParameter.getSpecification(), parameter.getType(), specializationParameter.getSpecificationIndex(),
+                                    specializationParameter.getVarArgsIndex(), parameter.isImplicit());
                 }
                 newParameters.add(p);
             }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemCodeGenerator.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemCodeGenerator.java	Wed Dec 11 21:57:10 2013 +0100
@@ -221,7 +221,7 @@
             }
 
             builder.startElseBlock();
-            builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end();
+            builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end();
             builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).doubleQuote("Illegal type ").end().end();
             builder.end();
             return method;
@@ -248,7 +248,7 @@
             }
 
             builder.startElseBlock();
-            builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end();
+            builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end();
             builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).doubleQuote("Illegal type ").end().end();
             builder.end();
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLNodeFactory.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLNodeFactory.java	Wed Dec 11 21:57:10 2013 +0100
@@ -59,10 +59,6 @@
         this.parser = parser;
     }
 
-    public CallTarget findFunction(String name) {
-        return context.getFunctionRegistry().lookup(name);
-    }
-
     public void startFunction() {
         frameDescriptor = new FrameDescriptor();
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/CallNode.java	Mon Dec 09 21:40:45 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/CallNode.java	Wed Dec 11 21:57:10 2013 +0100
@@ -140,22 +140,21 @@
                     }
                     return new InlinableCallNode((DefaultCallTarget) function, clonedArgs);
                 }
+                // got a call target that is not inlinable (should not occur for SL)
+                return new DispatchedCallNode(defaultFunction, clonedArgs);
+            } else {
+                throw new AssertionError();
             }
 
-            // got a call target that is not inlinable (should not occur for SL)
-            return new DispatchedCallNode(function, clonedArgs);
         }
     }
 
     private static final class InlinableCallNode extends DispatchedCallNode implements InlinableCallSite {
 
-        private final DefaultCallTarget inlinableTarget;
-
         @CompilationFinal private int callCount;
 
         InlinableCallNode(DefaultCallTarget function, ArgumentsNode arguments) {
             super(function, arguments);
-            this.inlinableTarget = function;
         }
 
         @Override
@@ -170,7 +169,7 @@
 
         @Override
         public Node getInlineTree() {
-            RootNode root = inlinableTarget.getRootNode();
+            RootNode root = function.getRootNode();
             if (root instanceof FunctionRootNode) {
                 return ((FunctionRootNode) root).getUninitializedBody();
             }
@@ -182,7 +181,7 @@
             CompilerAsserts.neverPartOfCompilation();
             TypedNode functionCall = null;
 
-            RootNode root = inlinableTarget.getRootNode();
+            RootNode root = function.getRootNode();
             if (root instanceof FunctionRootNode) {
                 functionCall = ((FunctionRootNode) root).inline(NodeUtil.cloneNode(args));
             }
@@ -204,7 +203,7 @@
 
         @Override
         public CallTarget getCallTarget() {
-            return inlinableTarget;
+            return function;
         }
 
     }
@@ -212,9 +211,9 @@
     private static class DispatchedCallNode extends TypedNode {
 
         @Child protected ArgumentsNode args;
-        protected final CallTarget function;
+        protected final DefaultCallTarget function;
 
-        DispatchedCallNode(CallTarget function, ArgumentsNode arguments) {
+        DispatchedCallNode(DefaultCallTarget function, ArgumentsNode arguments) {
             this.args = adoptChild(arguments);
             this.function = function;
         }
--- a/mxtool/mx.py	Mon Dec 09 21:40:45 2013 +0100
+++ b/mxtool/mx.py	Wed Dec 11 21:57:10 2013 +0100
@@ -2155,13 +2155,17 @@
 
     log('{0} files were modified'.format(len(modified)))
     if len(modified) != 0:
+        arcbase = _primary_suite.dir
         if args.backup:
             backup = os.path.abspath('eclipseformat.backup.zip')
-            arcbase = _primary_suite.dir
             zf = zipfile.ZipFile(backup, 'w', zipfile.ZIP_DEFLATED)
-            for fi in modified:
-                arcname = os.path.relpath(fi.path, arcbase).replace(os.sep, '/')
+        for fi in modified:
+            name = os.path.relpath(fi.path, arcbase)
+            log(' - {0}'.format(name))
+            if args.backup:
+                arcname = name.replace(os.sep, '/')
                 zf.writestr(arcname, fi.content)
+        if args.backup:
             zf.close()
             log('Wrote backup of {0} modified files to {1}'.format(len(modified), backup))
         return 1
--- a/src/cpu/x86/vm/globals_x86.hpp	Mon Dec 09 21:40:45 2013 +0100
+++ b/src/cpu/x86/vm/globals_x86.hpp	Wed Dec 11 21:57:10 2013 +0100
@@ -79,7 +79,8 @@
 // GC Ergo Flags
 define_pd_global(uintx, CMSYoungGenPerWorker, 64*M);  // default max size of CMS young gen, per GC worker thread
 
-define_pd_global(uintx, TypeProfileLevel, 111);
+// Disabled in GRAAL until HotSpotMethodData is updated to be aware of the new profiling tags
+define_pd_global(uintx, TypeProfileLevel, GRAAL_ONLY(0) NOT_GRAAL(111));
 
 #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
                                                                             \
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Mon Dec 09 21:40:45 2013 +0100
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Wed Dec 11 21:57:10 2013 +0100
@@ -469,25 +469,10 @@
   return JNIHandles::make_local(THREAD, field_array());
 C2V_END
 
-C2V_VMENTRY(jobject, getMethods, (JNIEnv *, jobject, jobject klass))
-  ResourceMark rm;
-
+C2V_VMENTRY(jlong, getClassInitializer, (JNIEnv *, jobject, jobject klass))
   instanceKlassHandle k(THREAD, java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaClass(klass)));
-  Array<Method*>* methods = k->methods();
-  int methods_length = methods->length();
-
-  // Allocate result
-  objArrayOop r = oopFactory::new_objArray(SystemDictionary::HotSpotResolvedJavaMethod_klass(), methods_length, CHECK_NULL);
-  objArrayHandle result (THREAD, r);
-
-  for (int i = 0; i < methods_length; i++) {
-    methodHandle method(THREAD, methods->at(i));
-    Handle holder = JNIHandles::resolve(klass);
-    oop m = VMToCompiler::createResolvedJavaMethod(holder, method(), THREAD);
-    result->obj_at_put(i, m);
-  }
-
-  return JNIHandles::make_local(THREAD, result());
+  Method* clinit = k->class_initializer();
+  return (jlong) (address) clinit;
 C2V_END
 
 C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv *env, jobject, jlong addr))
@@ -966,7 +951,7 @@
   {CC"lookupFieldInPool",             CC"("METASPACE_CONSTANT_POOL"IB)"FIELD,                           FN_PTR(lookupFieldInPool)},
   {CC"resolveMethod",                 CC"("HS_RESOLVED_TYPE STRING STRING")"METHOD,                     FN_PTR(resolveMethod)},
   {CC"getInstanceFields",             CC"("HS_RESOLVED_TYPE")["HS_RESOLVED_FIELD,                       FN_PTR(getInstanceFields)},
-  {CC"getMethods",                    CC"("HS_RESOLVED_TYPE")["HS_RESOLVED_METHOD,                      FN_PTR(getMethods)},
+  {CC"getClassInitializer",           CC"("HS_RESOLVED_TYPE")"METASPACE_METHOD,                         FN_PTR(getClassInitializer)},
   {CC"hasFinalizableSubclass",        CC"("HS_RESOLVED_TYPE")Z",                                        FN_PTR(hasFinalizableSubclass)},
   {CC"getMaxCallTargetOffset",        CC"(J)J",                                                         FN_PTR(getMaxCallTargetOffset)},
   {CC"getMetaspaceMethod",            CC"("CLASS"I)"METASPACE_METHOD,                                   FN_PTR(getMetaspaceMethod)},
--- a/src/share/vm/oops/methodData.hpp	Mon Dec 09 21:40:45 2013 +0100
+++ b/src/share/vm/oops/methodData.hpp	Wed Dec 11 21:57:10 2013 +0100
@@ -2193,7 +2193,7 @@
 
   // Return (uint)-1 for overflow.
   uint trap_count(int reason) const {
-    assert((uint)reason < _trap_hist_limit, "oob");
+    assert((uint)reason < GRAAL_ONLY(2*) _trap_hist_limit, "oob");
     return (int)((_trap_hist._array[reason]+1) & _trap_hist_mask) - 1;
   }
   // For loops:
@@ -2202,7 +2202,7 @@
   uint inc_trap_count(int reason) {
     // Count another trap, anywhere in this method.
     assert(reason >= 0, "must be single trap");
-    assert((uint)reason < _trap_hist_limit, "oob");
+    assert((uint)reason < GRAAL_ONLY(2*) _trap_hist_limit, "oob");
     uint cnt1 = 1 + _trap_hist._array[reason];
     if ((cnt1 & _trap_hist_mask) != 0) {  // if no counter overflow...
       _trap_hist._array[reason] = cnt1;
--- a/src/share/vm/runtime/arguments.cpp	Mon Dec 09 21:40:45 2013 +0100
+++ b/src/share/vm/runtime/arguments.cpp	Wed Dec 11 21:57:10 2013 +0100
@@ -2336,6 +2336,10 @@
       warning("forcing ScavengeRootsInCode non-zero because Graal is enabled");
       ScavengeRootsInCode = 1;
   }
+  if (TypeProfileLevel != 0) {
+      warning("forcing TypeProfileLevel to 0 as HotSpotMethodData can not yet handle the new type profile info");
+      TypeProfileLevel = 0;
+  }
 #endif
 
   // Need to limit the extent of the padding to reasonable size.