changeset 23146:5eb7281c661c

merge
author Christian Wimmer <christian.wimmer@oracle.com>
date Tue, 08 Dec 2015 12:30:15 -0800
parents 49619bdbd262 (current diff) 043cb31c85cd (diff)
children 2d578cb15516
files graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ForeignCallPlugin.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderPlugin.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/IntrinsicContext.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoopExplosionPlugin.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodSubstitutionPlugin.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/NodePlugin.java graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ParameterPlugin.java graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/JVMCIErrorTest.java graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeParser.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/FixedInterval.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/FixedRange.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/IntervalHint.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/RegisterVerifier.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceInterval.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceIntervalDumper.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceIntervalWalker.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScan.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanAllocationPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanAssignLocationsPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanEliminateSpillMovePhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanLifetimeAnalysisPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanRegisterAllocationPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanResolveDataFlowPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanWalker.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLocalMoveResolver.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/UsePosList.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java
diffstat 233 files changed, 11472 insertions(+), 10622 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/ControlFlowAnchorDirectiveTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/ControlFlowAnchorDirectiveTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -167,6 +167,7 @@
         while (ret > 1) {
             GraalDirectives.controlFlowAnchor();
             if (ret % 2 == 0) {
+                GraalDirectives.controlFlowAnchor();
                 ret /= 2;
             } else {
                 ret = 3 * ret + 1;
--- a/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/SnippetReflectionProvider.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/SnippetReflectionProvider.java	Tue Dec 08 12:30:15 2015 -0800
@@ -182,5 +182,5 @@
      * @return the value that should be bound to the parameter when invoking the constructor or null
      *         if this provider cannot provide a value of the requested type
      */
-    Object getInjectedNodeIntrinsicParameter(ResolvedJavaType type);
+    <T> T getInjectedNodeIntrinsicParameter(Class<T> type);
 }
--- a/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -75,6 +75,7 @@
             byte[] targetCode = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc);
             compResult.setTargetCode(targetCode, targetCode.length);
             compResult.setTotalFrameSize(0);
+            compResult.close();
 
             InstalledCode code = codeCache.addCode(method, compResult, null, null);
 
--- a/graal/com.oracle.graal.code/src/com/oracle/graal/code/HexCodeFile.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.code/src/com/oracle/graal/code/HexCodeFile.java	Tue Dec 08 12:30:15 2015 -0800
@@ -122,7 +122,7 @@
      * Map from a machine code position to a comment for the operands of the instruction at the
      * position.
      */
-    public final Map<Integer, String> operandComments = new TreeMap<>();
+    public final Map<Integer, List<String>> operandComments = new TreeMap<>();
 
     public final byte[] code;
 
@@ -180,8 +180,10 @@
             }
         }
 
-        for (Map.Entry<Integer, String> e : operandComments.entrySet()) {
-            ps.printf("OperandComment %d %s %s%n", e.getKey(), e.getValue(), SECTION_DELIM);
+        for (Map.Entry<Integer, List<String>> e : operandComments.entrySet()) {
+            for (String c : e.getValue()) {
+                ps.printf("OperandComment %d %s %s%n", e.getKey(), c, SECTION_DELIM);
+            }
         }
         ps.flush();
     }
@@ -218,12 +220,15 @@
     }
 
     /**
-     * Sets an operand comment for a given position.
-     *
-     * @return the previous operand comment for {@code pos}
+     * Adds an operand comment for a given position.
      */
-    public String addOperandComment(int pos, String comment) {
-        return operandComments.put(pos, encodeString(comment));
+    public void addOperandComment(int pos, String comment) {
+        List<String> list = comments.get(pos);
+        if (list == null) {
+            list = new ArrayList<>(1);
+            comments.put(pos, list);
+        }
+        list.add(encodeString(comment));
     }
 
     /**
--- a/graal/com.oracle.graal.code/src/com/oracle/graal/code/HexCodeFileDisassemblerProvider.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.code/src/com/oracle/graal/code/HexCodeFileDisassemblerProvider.java	Tue Dec 08 12:30:15 2015 -0800
@@ -117,8 +117,7 @@
     }
 
     private static void addOperandComment(HexCodeFile hcf, int pos, String comment) {
-        String oldValue = hcf.addOperandComment(pos, comment);
-        assert oldValue == null : "multiple comments for operand of instruction at " + pos + ": " + comment + ", " + oldValue;
+        hcf.addOperandComment(pos, comment);
     }
 
     /**
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeMatchRules.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeMatchRules.java	Tue Dec 08 12:30:15 2015 -0800
@@ -126,7 +126,7 @@
 
         if (value.isConstant()) {
             JavaConstant constant = value.asJavaConstant();
-            if (constant != null && kind == AMD64Kind.QWORD && !NumUtil.isInt(constant.asLong())) {
+            if (constant != null && kind == AMD64Kind.QWORD && !constant.getJavaKind().isObject() && !NumUtil.isInt(constant.asLong())) {
                 // Only imm32 as long
                 return null;
             }
@@ -146,14 +146,7 @@
                 LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
                 boolean unorderedIsTrue = compare.unorderedIsTrue();
                 double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
-                Value other;
-                JavaConstant constant = value.asJavaConstant();
-                if (constant != null) {
-                    other = gen.emitJavaConstant(constant);
-                } else {
-                    other = operand(value);
-                }
-
+                Value other = operand(value);
                 AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
                 getLIRGeneratorTool().emitCompareBranchMemory(kind, other, address, getState(access), finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability);
                 return null;
@@ -268,6 +261,8 @@
     @MatchRule("(If (FloatLessThan=compare value FloatingRead=access))")
     @MatchRule("(If (PointerEquals=compare value Read=access))")
     @MatchRule("(If (PointerEquals=compare value FloatingRead=access))")
+    @MatchRule("(If (ObjectEquals=compare value Read=access))")
+    @MatchRule("(If (ObjectEquals=compare value FloatingRead=access))")
     public ComplexMatchResult ifCompareMemory(IfNode root, CompareNode compare, ValueNode value, Access access) {
         return emitCompareBranchMemory(root, compare, value, access);
     }
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64SuitesProvider.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64SuitesProvider.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -24,10 +24,10 @@
 
 import static com.oracle.graal.compiler.common.BackendOptions.ShouldOptimizeStackToStackMoves;
 
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.java.DefaultSuitesProvider;
 import com.oracle.graal.lir.amd64.phases.StackMoveOptimizationPhase;
 import com.oracle.graal.lir.phases.LIRSuites;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.phases.tiers.CompilerConfiguration;
 
 public class AMD64SuitesProvider extends DefaultSuitesProvider {
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/spi/ForeignCallsProvider.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/spi/ForeignCallsProvider.java	Tue Dec 08 12:30:15 2015 -0800
@@ -48,6 +48,11 @@
     boolean canDeoptimize(ForeignCallDescriptor descriptor);
 
     /**
+     * Identifies foreign calls which are guaranteed to include a safepoint check.
+     */
+    boolean isGuaranteedSafepoint(ForeignCallDescriptor descriptor);
+
+    /**
      * Gets the linkage for a foreign call.
      */
     ForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor);
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCSuitesProvider.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCSuitesProvider.java	Tue Dec 08 12:30:15 2015 -0800
@@ -22,8 +22,8 @@
  */
 package com.oracle.graal.compiler.sparc;
 
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.java.DefaultSuitesProvider;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.phases.tiers.CompilerConfiguration;
 import com.oracle.graal.phases.tiers.Suites;
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Tue Dec 08 12:30:15 2015 -0800
@@ -68,14 +68,14 @@
 import com.oracle.graal.debug.GraalDebugConfig;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.NodeClass;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.nodeinfo.NodeInfo;
 import com.oracle.graal.nodes.PhiNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.VerifyPhase;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CountedLoopTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CountedLoopTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -22,22 +22,23 @@
  */
 package com.oracle.graal.compiler.test;
 
+import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 import org.junit.Test;
 
 import com.oracle.graal.api.directives.GraalDirectives;
 import com.oracle.graal.graph.NodeClass;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.loop.InductionVariable;
 import com.oracle.graal.loop.LoopsData;
 import com.oracle.graal.nodeinfo.NodeInfo;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.calc.FloatingNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.spi.LIRLowerable;
 import com.oracle.graal.nodes.spi.NodeLIRBuilderTool;
 
@@ -232,13 +233,6 @@
         public void generate(NodeLIRBuilderTool gen) {
             gen.setResult(this, gen.operand(iv));
         }
-
-        @NodeIntrinsic
-        public static native int get(@ConstantNodeParameter IVProperty property, int iv);
-    }
-
-    protected static int getIntrinsic(IVProperty property, int iv) {
-        return IVPropertyNode.get(property, iv);
     }
 
     @Override
@@ -246,11 +240,18 @@
         Plugins plugins = super.getDefaultGraphBuilderPlugins();
         Registration r = new Registration(plugins.getInvocationPlugins(), CountedLoopTest.class);
 
-        ResolvedJavaMethod intrinsic = getResolvedJavaMethod("getIntrinsic");
         r.register2("get", IVProperty.class, int.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) {
-                b.intrinsify(targetMethod, intrinsic, new ValueNode[]{arg1, arg2});
-                return true;
+                IVProperty property = null;
+                if (arg1.isConstant()) {
+                    property = getSnippetReflection().asObject(IVProperty.class, arg1.asJavaConstant());
+                }
+                if (property != null) {
+                    b.addPush(JavaKind.Int, new IVPropertyNode(property, arg2));
+                    return true;
+                } else {
+                    return false;
+                }
             }
         });
 
@@ -268,4 +269,37 @@
         return true;
     }
 
+    public static Result incrementNeqSnippet(int limit) {
+        int i;
+        int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive
+        Result ret = new Result();
+        for (i = 0; i != posLimit; i++) {
+            GraalDirectives.controlFlowAnchor();
+            ret.extremum = get(InductionVariable::extremumNode, i);
+        }
+        ret.exitValue = get(InductionVariable::exitValueNode, i);
+        return ret;
+    }
+
+    @Test
+    public void decrementNeq() {
+        test("decrementNeqSnippet", 256);
+    }
+
+    public static Result decrementNeqSnippet(int limit) {
+        int i;
+        int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive
+        Result ret = new Result();
+        for (i = posLimit; i != 0; i--) {
+            GraalDirectives.controlFlowAnchor();
+            ret.extremum = get(InductionVariable::extremumNode, i);
+        }
+        ret.exitValue = get(InductionVariable::exitValueNode, i);
+        return ret;
+    }
+
+    @Test
+    public void incrementNeq() {
+        test("incrementNeqSnippet", 256);
+    }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -37,10 +37,10 @@
 import org.junit.Test;
 
 import com.oracle.graal.debug.Debug;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import com.oracle.graal.nodes.java.RegisterFinalizerNode;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -80,11 +80,6 @@
 import com.oracle.graal.debug.TTY;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.NodeMap;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
 import com.oracle.graal.java.ComputeLoopFrequenciesClosure;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.lir.asm.CompilationResultBuilderFactory;
@@ -99,6 +94,11 @@
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.cfg.Block;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.spi.LoweringProvider;
 import com.oracle.graal.nodes.spi.Replacements;
 import com.oracle.graal.nodes.virtual.VirtualObjectNode;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -37,11 +37,11 @@
 
 import org.junit.Test;
 
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
 import com.oracle.graal.lir.asm.CompilationResultBuilderFactory;
 import com.oracle.graal.nodes.FullInfopointNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.tiers.HighTierContext;
@@ -83,7 +83,7 @@
         final StructuredGraph graph = parseDebug(method, AllowAssumptions.from(OptAssumptions.getValue()));
         int graphLineSPs = 0;
         for (FullInfopointNode ipn : graph.getNodes().filter(FullInfopointNode.class)) {
-            if (ipn.getReason() == InfopointReason.LINE_NUMBER) {
+            if (ipn.getReason() == InfopointReason.BYTECODE_POSITION) {
                 ++graphLineSPs;
             }
         }
@@ -95,7 +95,7 @@
         int lineSPs = 0;
         for (Infopoint sp : cr.getInfopoints()) {
             assertNotNull(sp.reason);
-            if (sp.reason == InfopointReason.LINE_NUMBER) {
+            if (sp.reason == InfopointReason.BYTECODE_POSITION) {
                 ++lineSPs;
             }
         }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StaticInterfaceFieldTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StaticInterfaceFieldTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -36,12 +36,12 @@
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.DebugConfigScope;
 import com.oracle.graal.debug.DelegatingDebugConfig;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.VerifyPhase;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/UnbalancedMonitorsTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/UnbalancedMonitorsTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -31,12 +31,12 @@
 
 import org.junit.Test;
 
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.phases.OptimisticOptimizations;
 
 /**
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, 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
@@ -33,11 +33,11 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.DebugDumpScope;
 import com.oracle.graal.graph.Node;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
 import com.oracle.graal.nodes.FullInfopointNode;
 import com.oracle.graal.nodes.Invoke;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -42,9 +42,6 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.NodeMap;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.ConstantNode;
@@ -56,6 +53,9 @@
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.ValuePhiNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.java.LoadFieldNode;
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
 import com.oracle.graal.nodes.java.NewArrayNode;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Dec 08 12:30:15 2015 -0800
@@ -345,7 +345,6 @@
             FrameMap frameMap = lirGenRes.getFrameMap();
             CompilationResultBuilder crb = backend.newCompilationResultBuilder(lirGenRes, frameMap, compilationResult, factory);
             backend.emitCode(crb, lirGenRes.getLIR(), installedCodeOwner);
-            crb.finish();
             if (assumptions != null && !assumptions.isEmpty()) {
                 compilationResult.setAssumptions(assumptions.toArray());
             }
@@ -353,7 +352,7 @@
                 compilationResult.setMethods(rootMethod, inlinedMethods);
                 compilationResult.setBytecodeSize(bytecodeSize);
             }
-
+            crb.finish();
             if (Debug.isMeterEnabled()) {
                 List<DataPatch> ldp = compilationResult.getDataPatches();
                 JavaKind[] kindValues = JavaKind.values();
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Tue Dec 08 12:30:15 2015 -0800
@@ -451,7 +451,7 @@
             BytecodePosition position = node.getNodeContext(BytecodePosition.class);
             if (position != null && (lastPosition == null || !lastPosition.equals(position))) {
                 lastPosition = position;
-                recordSimpleInfopoint(InfopointReason.LINE_NUMBER, position);
+                recordSimpleInfopoint(InfopointReason.BYTECODE_POSITION, position);
             }
         }
         if (node instanceof LIRLowerable) {
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Tue Dec 08 12:30:15 2015 -0800
@@ -576,6 +576,26 @@
         }
     }
 
+    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9) {
+        log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
+    }
+
+    public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
+        }
+    }
+
+    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10) {
+        log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
+    }
+
+    public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
+        }
+    }
+
     public static void logv(String format, Object... args) {
         logv(DEFAULT_LOG_LEVEL, format, args);
     }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, 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
@@ -163,7 +163,11 @@
      * annotated method can be replaced with an instance of the node class denoted by
      * {@link #value()}. For this reason, the signature of the annotated method must match the
      * signature (excluding a prefix of {@linkplain InjectedNodeParameter injected} parameters) of a
-     * factory method named {@code "create"} in the node class.
+     * constructor in the node class.
+     * <p>
+     * If the node class has a static method {@code intrinsify} with a matching signature plus a
+     * {@code GraphBuilderContext} as first argument, this method is called instead of creating the
+     * node.
      */
     @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
     @java.lang.annotation.Target(ElementType.METHOD)
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeStack.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeStack.java	Tue Dec 08 12:30:15 2015 -0800
@@ -57,4 +57,17 @@
     public boolean isEmpty() {
         return tos == 0;
     }
+
+    @Override
+    public String toString() {
+        if (tos == 0) {
+            return "NodeStack: []";
+        }
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < tos; i++) {
+            sb.append(", ");
+            sb.append(values[i]);
+        }
+        return "NodeStack: [" + sb.substring(2) + "]";
+    }
 }
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ForeignCallPlugin.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graphbuilderconf;
-
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-
-import com.oracle.graal.compiler.common.spi.ForeignCallDescriptor;
-import com.oracle.graal.compiler.common.spi.ForeignCallsProvider;
-import com.oracle.graal.nodes.ValueNode;
-import com.oracle.graal.nodes.extended.ForeignCallNode;
-
-/**
- * {@link InvocationPlugin} for converting a method call directly to a foreign call.
- */
-public final class ForeignCallPlugin implements InvocationPlugin {
-    private final ForeignCallsProvider foreignCalls;
-    private final ForeignCallDescriptor descriptor;
-
-    public ForeignCallPlugin(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor) {
-        this.foreignCalls = foreignCalls;
-        this.descriptor = descriptor;
-    }
-
-    public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] args) {
-        ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, descriptor, args);
-        foreignCall.setBci(b.bci());
-        b.addPush(targetMethod.getSignature().getReturnKind(), foreignCall);
-        return true;
-    }
-}
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,301 +0,0 @@
-/*
- * Copyright (c) 2011, 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.graphbuilderconf;
-
-import java.util.Arrays;
-
-import jdk.vm.ci.meta.ResolvedJavaType;
-
-import com.oracle.graal.compiler.common.GraalOptions;
-import com.oracle.graal.nodes.FullInfopointNode;
-import com.oracle.graal.nodes.SimpleInfopointNode;
-
-public class GraphBuilderConfiguration {
-
-    public static class Plugins {
-        private final InvocationPlugins invocationPlugins;
-        private NodePlugin[] nodePlugins;
-        private ParameterPlugin[] parameterPlugins;
-        private InlineInvokePlugin[] inlineInvokePlugins;
-        private LoopExplosionPlugin loopExplosionPlugin;
-
-        /**
-         * Creates a copy of a given set of plugins. The {@link InvocationPlugins} in
-         * {@code copyFrom} become the {@linkplain InvocationPlugins#getParent() default}
-         * {@linkplain #getInvocationPlugins() invocation plugins} in this object.
-         */
-        public Plugins(Plugins copyFrom) {
-            this.invocationPlugins = new InvocationPlugins(copyFrom.invocationPlugins);
-            this.nodePlugins = copyFrom.nodePlugins;
-            this.parameterPlugins = copyFrom.parameterPlugins;
-            this.inlineInvokePlugins = copyFrom.inlineInvokePlugins;
-            this.loopExplosionPlugin = copyFrom.loopExplosionPlugin;
-        }
-
-        /**
-         * Creates a new set of plugins.
-         *
-         * @param invocationPlugins the {@linkplain #getInvocationPlugins() invocation plugins} in
-         *            this object
-         */
-        public Plugins(InvocationPlugins invocationPlugins) {
-            this.invocationPlugins = invocationPlugins;
-            this.nodePlugins = new NodePlugin[0];
-            this.parameterPlugins = new ParameterPlugin[0];
-            this.inlineInvokePlugins = new InlineInvokePlugin[0];
-        }
-
-        public InvocationPlugins getInvocationPlugins() {
-            return invocationPlugins;
-        }
-
-        public NodePlugin[] getNodePlugins() {
-            return nodePlugins;
-        }
-
-        public void appendNodePlugin(NodePlugin plugin) {
-            nodePlugins = Arrays.copyOf(nodePlugins, nodePlugins.length + 1);
-            nodePlugins[nodePlugins.length - 1] = plugin;
-        }
-
-        public void prependNodePlugin(NodePlugin plugin) {
-            NodePlugin[] newPlugins = new NodePlugin[nodePlugins.length + 1];
-            System.arraycopy(nodePlugins, 0, newPlugins, 1, nodePlugins.length);
-            newPlugins[0] = plugin;
-            nodePlugins = newPlugins;
-        }
-
-        public void clearNodePlugin() {
-            nodePlugins = new NodePlugin[0];
-        }
-
-        public ParameterPlugin[] getParameterPlugins() {
-            return parameterPlugins;
-        }
-
-        public void appendParameterPlugin(ParameterPlugin plugin) {
-            parameterPlugins = Arrays.copyOf(parameterPlugins, parameterPlugins.length + 1);
-            parameterPlugins[parameterPlugins.length - 1] = plugin;
-        }
-
-        public void prependParameterPlugin(ParameterPlugin plugin) {
-            ParameterPlugin[] newPlugins = new ParameterPlugin[parameterPlugins.length + 1];
-            System.arraycopy(parameterPlugins, 0, newPlugins, 1, parameterPlugins.length);
-            newPlugins[0] = plugin;
-            parameterPlugins = newPlugins;
-        }
-
-        public void clearParameterPlugin() {
-            parameterPlugins = new ParameterPlugin[0];
-        }
-
-        public InlineInvokePlugin[] getInlineInvokePlugins() {
-            return inlineInvokePlugins;
-        }
-
-        public void appendInlineInvokePlugin(InlineInvokePlugin plugin) {
-            inlineInvokePlugins = Arrays.copyOf(inlineInvokePlugins, inlineInvokePlugins.length + 1);
-            inlineInvokePlugins[inlineInvokePlugins.length - 1] = plugin;
-        }
-
-        public void prependInlineInvokePlugin(InlineInvokePlugin plugin) {
-            InlineInvokePlugin[] newPlugins = new InlineInvokePlugin[inlineInvokePlugins.length + 1];
-            System.arraycopy(inlineInvokePlugins, 0, newPlugins, 1, inlineInvokePlugins.length);
-            newPlugins[0] = plugin;
-            inlineInvokePlugins = newPlugins;
-        }
-
-        public void clearInlineInvokePlugins() {
-            inlineInvokePlugins = new InlineInvokePlugin[0];
-        }
-
-        public LoopExplosionPlugin getLoopExplosionPlugin() {
-            return loopExplosionPlugin;
-        }
-
-        public void setLoopExplosionPlugin(LoopExplosionPlugin plugin) {
-            this.loopExplosionPlugin = plugin;
-        }
-    }
-
-    private static final ResolvedJavaType[] EMPTY = new ResolvedJavaType[]{};
-
-    private final boolean eagerResolving;
-    private final boolean omitAllExceptionEdges;
-    private final boolean omitAssertions;
-    private final ResolvedJavaType[] skippedExceptionTypes;
-    private final DebugInfoMode debugInfoMode;
-    private final boolean clearNonLiveLocals;
-    private boolean useProfiling;
-    private final Plugins plugins;
-
-    public static enum DebugInfoMode {
-        SafePointsOnly,
-        /**
-         * This mode inserts {@link SimpleInfopointNode}s in places where no safepoints would be
-         * inserted: inlining boundaries, and line number switches.
-         * <p>
-         * In this mode the infopoint only have a location (method and bytecode index) and no
-         * values.
-         * <p>
-         * This is useful to have better program counter to bci mapping and has no influence on the
-         * generated code. However it can increase the amount of metadata and does not allow access
-         * to accessing values at runtime.
-         */
-        Simple,
-        /**
-         * In this mode, {@link FullInfopointNode}s are generated in the same locations as in
-         * {@link #Simple} mode but the infopoints have access to the runtime values.
-         * <p>
-         * This is relevant when code is to be generated for native, machine-code level debugging
-         * but can have a limit the amount of optimization applied to the code.
-         */
-        Full,
-    }
-
-    protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, boolean omitAssertions, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes,
-                    boolean clearNonLiveLocals, Plugins plugins) {
-        this.eagerResolving = eagerResolving;
-        this.omitAllExceptionEdges = omitAllExceptionEdges;
-        this.omitAssertions = omitAssertions;
-        this.debugInfoMode = debugInfoMode;
-        this.skippedExceptionTypes = skippedExceptionTypes;
-        this.clearNonLiveLocals = clearNonLiveLocals;
-        this.useProfiling = true;
-        this.plugins = plugins;
-    }
-
-    /**
-     * Creates a copy of this configuration with all its plugins. The {@link InvocationPlugins} in
-     * this configuration become the {@linkplain InvocationPlugins#getParent() parent} of the
-     * {@link InvocationPlugins} in the copy.
-     */
-    public GraphBuilderConfiguration copy() {
-        Plugins newPlugins = new Plugins(plugins);
-        GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, newPlugins);
-        result.useProfiling = useProfiling;
-        return result;
-    }
-
-    public boolean getUseProfiling() {
-        return useProfiling;
-    }
-
-    public void setUseProfiling(boolean b) {
-        this.useProfiling = b;
-    }
-
-    public GraphBuilderConfiguration withEagerResolving(boolean newEagerResolving) {
-        return new GraphBuilderConfiguration(newEagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, plugins);
-    }
-
-    public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
-        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, newSkippedExceptionTypes, clearNonLiveLocals, plugins);
-    }
-
-    public GraphBuilderConfiguration withOmitAllExceptionEdges(boolean newOmitAllExceptionEdges) {
-        return new GraphBuilderConfiguration(eagerResolving, newOmitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, plugins);
-    }
-
-    public GraphBuilderConfiguration withOmitAssertions(boolean newOmitAssertions) {
-        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newOmitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, plugins);
-    }
-
-    public GraphBuilderConfiguration withDebugInfoMode(DebugInfoMode newDebugInfoMode) {
-        ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length);
-        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, newDebugInfoMode, newSkippedExceptionTypes, clearNonLiveLocals, plugins);
-    }
-
-    public GraphBuilderConfiguration withClearNonLiveLocals(boolean newClearNonLiveLocals) {
-        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, newClearNonLiveLocals, plugins);
-    }
-
-    public ResolvedJavaType[] getSkippedExceptionTypes() {
-        return skippedExceptionTypes;
-    }
-
-    public boolean eagerResolving() {
-        return eagerResolving;
-    }
-
-    public boolean omitAllExceptionEdges() {
-        return omitAllExceptionEdges;
-    }
-
-    public boolean omitAssertions() {
-        return omitAssertions;
-    }
-
-    public boolean insertNonSafepointDebugInfo() {
-        return debugInfoMode.ordinal() >= DebugInfoMode.Simple.ordinal();
-    }
-
-    public boolean insertFullDebugInfo() {
-        return debugInfoMode.ordinal() >= DebugInfoMode.Full.ordinal();
-    }
-
-    public boolean insertSimpleDebugInfo() {
-        return debugInfoMode == DebugInfoMode.Simple;
-    }
-
-    public boolean clearNonLiveLocals() {
-        return clearNonLiveLocals;
-    }
-
-    public static GraphBuilderConfiguration getDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(false, false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
-    }
-
-    public static GraphBuilderConfiguration getInfopointDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
-    }
-
-    public static GraphBuilderConfiguration getEagerDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
-    }
-
-    public static GraphBuilderConfiguration getInfopointEagerDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
-    }
-
-    public static GraphBuilderConfiguration getSnippetDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
-    }
-
-    public static GraphBuilderConfiguration getFullDebugDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Full, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
-    }
-
-    /**
-     * Returns {@code true} if it is an error for a class/field/method resolution to fail. The
-     * default is the same result as returned by {@link #eagerResolving()}. However, it may be
-     * overridden to allow failure even when {@link #eagerResolving} is {@code true}.
-     */
-    public boolean unresolvedIsError() {
-        return eagerResolving;
-    }
-
-    public Plugins getPlugins() {
-        return plugins;
-    }
-}
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,266 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graphbuilderconf;
-
-import static com.oracle.graal.compiler.common.type.StampFactory.objectNonNull;
-import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
-import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
-import jdk.vm.ci.code.BailoutException;
-import jdk.vm.ci.meta.Assumptions;
-import jdk.vm.ci.meta.ConstantReflectionProvider;
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.JavaType;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaType;
-
-import com.oracle.graal.compiler.common.type.ObjectStamp;
-import com.oracle.graal.compiler.common.type.Stamp;
-import com.oracle.graal.compiler.common.type.StampFactory;
-import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.FixedGuardNode;
-import com.oracle.graal.nodes.PiNode;
-import com.oracle.graal.nodes.StateSplit;
-import com.oracle.graal.nodes.StructuredGraph;
-import com.oracle.graal.nodes.ValueNode;
-import com.oracle.graal.nodes.calc.IsNullNode;
-import com.oracle.graal.nodes.spi.StampProvider;
-import com.oracle.graal.nodes.type.StampTool;
-
-/**
- * Used by a {@link GraphBuilderPlugin} to interface with an object that parses the bytecode of a
- * single {@linkplain #getMethod() method} as part of building a {@linkplain #getGraph() graph} .
- */
-public interface GraphBuilderContext {
-
-    /**
-     * Raw operation for adding a node to the graph when neither {@link #add} nor
-     * {@link #addPush(JavaKind, ValueNode)} can be used.
-     *
-     * @return either the node added or an equivalent node
-     */
-    <T extends ValueNode> T append(T value);
-
-    /**
-     * Adds the given node to the graph and also adds recursively all referenced inputs.
-     *
-     * @param value the node to be added to the graph
-     * @return either the node added or an equivalent node
-     */
-    <T extends ValueNode> T recursiveAppend(T value);
-
-    /**
-     * Pushes a given value to the frame state stack using an explicit kind. This should be used
-     * when {@code value.getJavaKind()} is different from the kind that the bytecode instruction
-     * currently being parsed pushes to the stack.
-     *
-     * @param kind the kind to use when type checking this operation
-     * @param value the value to push to the stack. The value must already have been
-     *            {@linkplain #append(ValueNode) appended}.
-     */
-    void push(JavaKind kind, ValueNode value);
-
-    /**
-     * Adds a node to the graph. If the returned node is a {@link StateSplit} with a null
-     * {@linkplain StateSplit#stateAfter() frame state}, the frame state is initialized.
-     *
-     * @param value the value to add to the graph and push to the stack. The
-     *            {@code value.getJavaKind()} kind is used when type checking this operation.
-     * @return a node equivalent to {@code value} in the graph
-     */
-    default <T extends ValueNode> T add(T value) {
-        if (value.graph() != null) {
-            assert !(value instanceof StateSplit) || ((StateSplit) value).stateAfter() != null;
-            return value;
-        }
-        T equivalentValue = append(value);
-        if (equivalentValue instanceof StateSplit) {
-            StateSplit stateSplit = (StateSplit) equivalentValue;
-            if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
-                setStateAfter(stateSplit);
-            }
-        }
-        return equivalentValue;
-    }
-
-    /**
-     * Adds a node with a non-void kind to the graph, pushes it to the stack. If the returned node
-     * is a {@link StateSplit} with a null {@linkplain StateSplit#stateAfter() frame state}, the
-     * frame state is initialized.
-     *
-     * @param kind the kind to use when type checking this operation
-     * @param value the value to add to the graph and push to the stack
-     * @return a node equivalent to {@code value} in the graph
-     */
-    default <T extends ValueNode> T addPush(JavaKind kind, T value) {
-        T equivalentValue = value.graph() != null ? value : append(value);
-        push(kind, equivalentValue);
-        if (equivalentValue instanceof StateSplit) {
-            StateSplit stateSplit = (StateSplit) equivalentValue;
-            if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
-                setStateAfter(stateSplit);
-            }
-        }
-        return equivalentValue;
-    }
-
-    /**
-     * Handles an invocation that a plugin determines can replace the original invocation (i.e., the
-     * one for which the plugin was applied). This applies all standard graph builder processing to
-     * the replaced invocation including applying any relevant plugins.
-     *
-     * @param invokeKind the kind of the replacement invocation
-     * @param targetMethod the target of the replacement invocation
-     * @param args the arguments to the replacement invocation
-     * @param forceInlineEverything specifies if all invocations encountered in the scope of
-     *            handling the replaced invoke are to be force inlined
-     */
-    void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean forceInlineEverything);
-
-    /**
-     * Intrinsifies an invocation of a given method by inlining the bytecodes of a given
-     * substitution method.
-     *
-     * @param targetMethod the method being intrinsified
-     * @param substitute the intrinsic implementation
-     * @param args the arguments with which to inline the invocation
-     */
-    void intrinsify(ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, ValueNode[] args);
-
-    StampProvider getStampProvider();
-
-    MetaAccessProvider getMetaAccess();
-
-    default Assumptions getAssumptions() {
-        return getGraph().getAssumptions();
-    }
-
-    ConstantReflectionProvider getConstantReflection();
-
-    /**
-     * Gets the graph being constructed.
-     */
-    StructuredGraph getGraph();
-
-    /**
-     * Creates a snap shot of the current frame state with the BCI of the instruction after the one
-     * currently being parsed and assigns it to a given {@linkplain StateSplit#hasSideEffect() side
-     * effect} node.
-     *
-     * @param sideEffect a side effect node just appended to the graph
-     */
-    void setStateAfter(StateSplit sideEffect);
-
-    /**
-     * Gets the parsing context for the method that inlines the method being parsed by this context.
-     */
-    GraphBuilderContext getParent();
-
-    /**
-     * Gets the first ancestor parsing context that is not parsing a
-     * {@linkplain #parsingIntrinsic() intrinsic}.
-     */
-    default GraphBuilderContext getNonIntrinsicAncestor() {
-        GraphBuilderContext ancestor = getParent();
-        while (ancestor != null && ancestor.parsingIntrinsic()) {
-            ancestor = ancestor.getParent();
-        }
-        return ancestor;
-    }
-
-    /**
-     * Gets the method being parsed by this context.
-     */
-    ResolvedJavaMethod getMethod();
-
-    /**
-     * Gets the index of the bytecode instruction currently being parsed.
-     */
-    int bci();
-
-    /**
-     * Gets the kind of invocation currently being parsed.
-     */
-    InvokeKind getInvokeKind();
-
-    /**
-     * Gets the return type of the invocation currently being parsed.
-     */
-    JavaType getInvokeReturnType();
-
-    default Stamp getInvokeReturnStamp() {
-        JavaType returnType = getInvokeReturnType();
-        if (returnType.getJavaKind() == JavaKind.Object && returnType instanceof ResolvedJavaType) {
-            return StampFactory.declared((ResolvedJavaType) returnType);
-        } else {
-            return StampFactory.forKind(returnType.getJavaKind());
-        }
-    }
-
-    /**
-     * Gets the inline depth of this context. A return value of 0 implies that this is the context
-     * for the parse root.
-     */
-    default int getDepth() {
-        GraphBuilderContext parent = getParent();
-        return parent == null ? 0 : 1 + parent.getDepth();
-    }
-
-    /**
-     * Determines if this parsing context is within the bytecode of an intrinsic or a method inlined
-     * by an intrinsic.
-     */
-    default boolean parsingIntrinsic() {
-        return getIntrinsic() != null;
-    }
-
-    /**
-     * Gets the intrinsic of the current parsing context or {@code null} if not
-     * {@link #parsingIntrinsic() parsing an intrinsic}.
-     */
-    IntrinsicContext getIntrinsic();
-
-    BailoutException bailout(String string);
-
-    /**
-     * Gets a version of a given value that has a {@linkplain StampTool#isPointerNonNull(ValueNode)
-     * non-null} stamp.
-     */
-    default ValueNode nullCheckedValue(ValueNode value) {
-        if (!StampTool.isPointerNonNull(value.stamp())) {
-            IsNullNode condition = getGraph().unique(new IsNullNode(value));
-            ObjectStamp receiverStamp = (ObjectStamp) value.stamp();
-            Stamp stamp = receiverStamp.join(objectNonNull());
-            FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, NullCheckException, InvalidateReprofile, true));
-            PiNode nonNullReceiver = getGraph().unique(new PiNode(value, stamp));
-            nonNullReceiver.setGuard(fixedGuard);
-            // TODO: Propogating the non-null into the frame state would
-            // remove subsequent null-checks on the same value. However,
-            // it currently causes an assertion failure when merging states.
-            //
-            // frameState.replace(value, nonNullReceiver);
-            return nonNullReceiver;
-        }
-        return value;
-    }
-}
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderPlugin.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graphbuilderconf;
-
-/**
- * Marker interface for graph builder plugins.
- */
-public interface GraphBuilderPlugin {
-}
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graphbuilderconf;
-
-import jdk.vm.ci.meta.JavaType;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-
-import com.oracle.graal.nodes.Invoke;
-import com.oracle.graal.nodes.ValueNode;
-
-/**
- * Plugin for specifying what is inlined during graph parsing. This plugin is also notified
- * {@link #notifyBeforeInline before} and {@link #notifyAfterInline} the inlining, as well as of
- * {@link #notifyNotInlined non-inlined} invocations (i.e., those for which an {@link Invoke} node
- * is created).
- */
-public interface InlineInvokePlugin extends GraphBuilderPlugin {
-
-    /**
-     * Result of a {@link #shouldInlineInvoke inlining decision}.
-     */
-    public static class InlineInfo {
-
-        /**
-         * Denotes a call site that must not be inlined and should be implemented by a node that
-         * does not speculate on the call not raising an exception.
-         */
-        public static final InlineInfo DO_NOT_INLINE_WITH_EXCEPTION = new InlineInfo(null, false);
-
-        /**
-         * Denotes a call site must not be inlined and can be implemented by a node that speculates
-         * the call will not throw an exception.
-         */
-        public static final InlineInfo DO_NOT_INLINE_NO_EXCEPTION = new InlineInfo(null, false);
-
-        private final ResolvedJavaMethod methodToInline;
-        private final boolean isIntrinsic;
-
-        public InlineInfo(ResolvedJavaMethod methodToInline, boolean isIntrinsic) {
-            this.methodToInline = methodToInline;
-            this.isIntrinsic = isIntrinsic;
-        }
-
-        /**
-         * Returns the method to be inlined, or {@code null} if the call site must not be inlined.
-         */
-        public ResolvedJavaMethod getMethodToInline() {
-            return methodToInline;
-        }
-
-        /**
-         * Specifies if {@link #methodToInline} is an intrinsic for the original method (i.e., the
-         * {@code method} passed to {@link InlineInvokePlugin#shouldInlineInvoke}).
-         */
-        public boolean isIntrinsic() {
-            return isIntrinsic;
-        }
-    }
-
-    /**
-     * Determines whether a call to a given method is to be inlined. The return value is a
-     * tri-state:
-     * <p>
-     * Non-null return value with a non-null {@link InlineInfo#getMethodToInline method}: That
-     * {@link InlineInfo#getMethodToInline method} is inlined. Note that it can be a different
-     * method than the one specified here as the parameter, which allows method substitutions.
-     * <p>
-     * Non-null return value with a null {@link InlineInfo#getMethodToInline method}, e.g.,
-     * {@link InlineInfo#DO_NOT_INLINE_WITH_EXCEPTION}: The method is not inlined, and other plugins
-     * with a lower priority cannot overwrite this decision.
-     * <p>
-     * Null return value: This plugin made no decision, other plugins with a lower priority are
-     * asked.
-     *
-     * @param b the context
-     * @param method the target method of an invoke
-     * @param args the arguments to the invoke
-     * @param returnType the return type derived from {@code method}'s signature
-     */
-    default InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
-        return null;
-    }
-
-    /**
-     * Notification that a method is about to be inlined.
-     *
-     * @param methodToInline the inlined method
-     */
-    default void notifyBeforeInline(ResolvedJavaMethod methodToInline) {
-    }
-
-    /**
-     * Notification that a method was inlined.
-     *
-     * @param methodToInline the inlined method
-     */
-    default void notifyAfterInline(ResolvedJavaMethod methodToInline) {
-    }
-
-    /**
-     * Notifies this plugin of the {@link Invoke} node created for a method that was not inlined per
-     * {@link #shouldInlineInvoke}.
-     *
-     * @param b the context
-     * @param method the method that was not inlined
-     * @param invoke the invoke node created for the call to {@code method}
-     */
-    default void notifyNotInlined(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
-    }
-}
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/IntrinsicContext.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,170 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graphbuilderconf;
-
-import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
-import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
-import static jdk.vm.ci.code.BytecodeFrame.AFTER_BCI;
-import static jdk.vm.ci.code.BytecodeFrame.BEFORE_BCI;
-import static jdk.vm.ci.code.BytecodeFrame.INVALID_FRAMESTATE_BCI;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-
-import com.oracle.graal.nodes.AbstractMergeNode;
-import com.oracle.graal.nodes.FrameState;
-import com.oracle.graal.nodes.Invoke;
-import com.oracle.graal.nodes.StateSplit;
-import com.oracle.graal.nodes.StructuredGraph;
-
-/**
- * An intrinsic is a substitute implementation of a Java method (or a bytecode in the case of
- * snippets) that is itself implemented in Java. This interface provides information about the
- * intrinsic currently being processed by the graph builder.
- *
- * When in the scope of an intrinsic, the graph builder does not check the value kinds flowing
- * through the JVM state since intrinsics can employ non-Java kinds to represent values such as raw
- * machine words and pointers.
- */
-public class IntrinsicContext {
-
-    /**
-     * Gets the method being intrinsified.
-     */
-    final ResolvedJavaMethod method;
-
-    /**
-     * Gets the method providing the intrinsic implementation.
-     */
-    final ResolvedJavaMethod intrinsic;
-
-    public ResolvedJavaMethod getOriginalMethod() {
-        return method;
-    }
-
-    public ResolvedJavaMethod getIntrinsicMethod() {
-        return intrinsic;
-    }
-
-    /**
-     * Determines if a call within the compilation scope of this intrinsic represents a call to the
-     * {@linkplain #getOriginalMethod() original} method. This denotes the path where a partial
-     * intrinsification falls back to the original method.
-     */
-    public boolean isCallToOriginal(ResolvedJavaMethod targetMethod) {
-        return method.equals(targetMethod) || intrinsic.equals(targetMethod);
-    }
-
-    final CompilationContext compilationContext;
-
-    public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, CompilationContext compilationContext) {
-        this.method = method;
-        this.intrinsic = intrinsic;
-        this.compilationContext = compilationContext;
-        assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)");
-    }
-
-    public boolean isPostParseInlined() {
-        return compilationContext.equals(INLINE_AFTER_PARSING);
-    }
-
-    public boolean isCompilationRoot() {
-        return compilationContext.equals(ROOT_COMPILATION);
-    }
-
-    /**
-     * Denotes the compilation context in which an intrinsic is being parsed.
-     */
-    public enum CompilationContext {
-        /**
-         * An intrinsic is being processed when parsing an invoke bytecode that calls the
-         * intrinsified method.
-         */
-        INLINE_DURING_PARSING,
-
-        /**
-         * An intrinsic is being processed when inlining an {@link Invoke} in an existing graph.
-         */
-        INLINE_AFTER_PARSING,
-
-        /**
-         * An intrinsic is the root of compilation.
-         */
-        ROOT_COMPILATION
-    }
-
-    /**
-     * Models the state of a graph in terms of {@link StateSplit#hasSideEffect() side effects} that
-     * are control flow predecessors of the current point in a graph.
-     */
-    public interface SideEffectsState {
-
-        /**
-         * Determines if the current program point is preceded by one or more side effects.
-         */
-        boolean isAfterSideEffect();
-
-        /**
-         * Gets the side effects preceding the current program point.
-         */
-        Iterable<StateSplit> sideEffects();
-
-        /**
-         * Records a side effect for the current program point.
-         */
-        void addSideEffect(StateSplit sideEffect);
-    }
-
-    public FrameState createFrameState(StructuredGraph graph, SideEffectsState sideEffects, StateSplit forStateSplit) {
-        assert forStateSplit != graph.start();
-        if (forStateSplit.hasSideEffect()) {
-            if (sideEffects.isAfterSideEffect()) {
-                // Only the last side effect on any execution path in a replacement
-                // can inherit the stateAfter of the replaced node
-                FrameState invalid = graph.add(new FrameState(INVALID_FRAMESTATE_BCI));
-                for (StateSplit lastSideEffect : sideEffects.sideEffects()) {
-                    lastSideEffect.setStateAfter(invalid);
-                }
-            }
-            sideEffects.addSideEffect(forStateSplit);
-            return graph.add(new FrameState(AFTER_BCI));
-        } else {
-            if (forStateSplit instanceof AbstractMergeNode) {
-                // Merge nodes always need a frame state
-                if (sideEffects.isAfterSideEffect()) {
-                    // A merge after one or more side effects
-                    return graph.add(new FrameState(AFTER_BCI));
-                } else {
-                    // A merge before any side effects
-                    return graph.add(new FrameState(BEFORE_BCI));
-                }
-            } else {
-                // Other non-side-effects do not need a state
-                return null;
-            }
-        }
-    }
-
-    @Override
-    public String toString() {
-        return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", intrinsic: " + intrinsic.format("%H.%n(%p)") + ", context: " + compilationContext + "}";
-    }
-}
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,208 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graphbuilderconf;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.reflect.Method;
-
-import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-
-import com.oracle.graal.nodes.Invoke;
-import com.oracle.graal.nodes.ValueNode;
-import com.oracle.graal.nodes.type.StampTool;
-
-/**
- * Plugin for handling a specific method invocation.
- */
-public interface InvocationPlugin extends GraphBuilderPlugin {
-
-    /**
-     * The receiver in a non-static method. The class literal for this interface must be used with
-     * {@link InvocationPlugins#put(InvocationPlugin, boolean, boolean, boolean, Class, String, Class...)}
-     * to denote the receiver argument for such a non-static method.
-     */
-    public interface Receiver {
-        /**
-         * Gets the receiver value, null checking it first if necessary.
-         *
-         * @return the receiver value with a {@linkplain StampTool#isPointerNonNull(ValueNode)
-         *         non-null} stamp
-         */
-        ValueNode get();
-
-        /**
-         * Determines if the receiver is constant.
-         */
-        default boolean isConstant() {
-            return false;
-        }
-    }
-
-    /**
-     * Determines if this plugin is for a method with a polymorphic signature (e.g.
-     * {@link MethodHandle#invokeExact(Object...)}).
-     */
-    default boolean isSignaturePolymorphic() {
-        return false;
-    }
-
-    /**
-     * Determines if this plugin can only be used when inlining the method is it associated with.
-     * That is, this plugin cannot be used when the associated method is the compilation root.
-     */
-    default boolean inlineOnly() {
-        return isSignaturePolymorphic();
-    }
-
-    /**
-     * Handles invocation of a signature polymorphic method.
-     *
-     * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static
-     * @param argsIncludingReceiver all arguments to the invocation include the raw receiver in
-     *            position 0 if {@code targetMethod} is not static
-     * @see #execute
-     */
-    default boolean applyPolymorphic(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode... argsIncludingReceiver) {
-        return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
-    }
-
-    /**
-     * @see #execute
-     */
-    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver) {
-        return defaultHandler(b, targetMethod, receiver);
-    }
-
-    /**
-     * @see #execute
-     */
-    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg) {
-        return defaultHandler(b, targetMethod, receiver, arg);
-    }
-
-    /**
-     * @see #execute
-     */
-    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2) {
-        return defaultHandler(b, targetMethod, receiver, arg1, arg2);
-    }
-
-    /**
-     * @see #execute
-     */
-    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
-        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3);
-    }
-
-    /**
-     * @see #execute
-     */
-    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) {
-        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4);
-    }
-
-    /**
-     * @see #execute
-     */
-    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) {
-        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4, arg5);
-    }
-
-    /**
-     * Executes this plugin against a set of invocation arguments.
-     *
-     * The default implementation in {@link InvocationPlugin} dispatches to the {@code apply(...)}
-     * method that matches the number of arguments or to {@link #applyPolymorphic} if {@code plugin}
-     * is {@linkplain #isSignaturePolymorphic() signature polymorphic}.
-     *
-     * @param targetMethod the method for which this plugin is being applied
-     * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static
-     * @param argsIncludingReceiver all arguments to the invocation include the receiver in position
-     *            0 if {@code targetMethod} is not static
-     * @return {@code true} if this plugin handled the invocation of {@code targetMethod}
-     *         {@code false} if the graph builder should process the invoke further (e.g., by
-     *         inlining it or creating an {@link Invoke} node). A plugin that does not handle an
-     *         invocation must not modify the graph being constructed.
-     */
-    default boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver) {
-        if (isSignaturePolymorphic()) {
-            return applyPolymorphic(b, targetMethod, receiver, argsIncludingReceiver);
-        } else if (receiver != null) {
-            assert !targetMethod.isStatic();
-            assert argsIncludingReceiver.length > 0;
-            if (argsIncludingReceiver.length == 1) {
-                return apply(b, targetMethod, receiver);
-            } else if (argsIncludingReceiver.length == 2) {
-                return apply(b, targetMethod, receiver, argsIncludingReceiver[1]);
-            } else if (argsIncludingReceiver.length == 3) {
-                return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2]);
-            } else if (argsIncludingReceiver.length == 4) {
-                return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3]);
-            } else if (argsIncludingReceiver.length == 5) {
-                return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4]);
-            } else {
-                return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
-            }
-        } else {
-            assert targetMethod.isStatic();
-            if (argsIncludingReceiver.length == 0) {
-                return apply(b, targetMethod, null);
-            } else if (argsIncludingReceiver.length == 1) {
-                return apply(b, targetMethod, null, argsIncludingReceiver[0]);
-            } else if (argsIncludingReceiver.length == 2) {
-                return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1]);
-            } else if (argsIncludingReceiver.length == 3) {
-                return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2]);
-            } else if (argsIncludingReceiver.length == 4) {
-                return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3]);
-            } else if (argsIncludingReceiver.length == 5) {
-                return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4]);
-            } else {
-                return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
-            }
-
-        }
-    }
-
-    /**
-     * Handles an invocation when a specific {@code apply} method is not available.
-     */
-    default boolean defaultHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, @SuppressWarnings("unused") InvocationPlugin.Receiver receiver,
-                    ValueNode... args) {
-        throw new JVMCIError("Invocation plugin for %s does not handle invocations with %d arguments", targetMethod.format("%H.%n(%p)"), args.length);
-    }
-
-    default StackTraceElement getApplySourceLocation(MetaAccessProvider metaAccess) {
-        Class<?> c = getClass();
-        for (Method m : c.getDeclaredMethods()) {
-            if (m.getName().equals("apply")) {
-                return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
-            } else if (m.getName().equals("defaultHandler")) {
-                return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
-            }
-        }
-        throw new JVMCIError("could not find method named \"apply\" or \"defaultHandler\" in " + c.getName());
-    }
-}
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,604 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graphbuilderconf;
-
-import static java.lang.String.format;
-
-import java.lang.reflect.Executable;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-
-import com.oracle.graal.graph.Node;
-import com.oracle.graal.graph.iterators.NodeIterable;
-import com.oracle.graal.nodes.ValueNode;
-
-/**
- * Manages a set of {@link InvocationPlugin}s.
- */
-public class InvocationPlugins {
-
-    public static class InvocationPluginReceiver implements InvocationPlugin.Receiver {
-        private final GraphBuilderContext parser;
-        private ValueNode[] args;
-        private ValueNode value;
-
-        public InvocationPluginReceiver(GraphBuilderContext parser) {
-            this.parser = parser;
-        }
-
-        @Override
-        public ValueNode get() {
-            assert args != null : "Cannot get the receiver of a static method";
-            if (value == null) {
-                value = parser.nullCheckedValue(args[0]);
-                if (value != args[0]) {
-                    args[0] = value;
-                }
-            }
-            return value;
-        }
-
-        @Override
-        public boolean isConstant() {
-            return args[0].isConstant();
-        }
-
-        public InvocationPluginReceiver init(ResolvedJavaMethod targetMethod, ValueNode[] newArgs) {
-            if (!targetMethod.isStatic()) {
-                this.args = newArgs;
-                this.value = null;
-                return this;
-            }
-            return null;
-        }
-    }
-
-    /**
-     * Utility for
-     * {@linkplain InvocationPlugins#register(InvocationPlugin, Class, String, Class...)
-     * registration} of invocation plugins.
-     */
-    public static class Registration {
-
-        private final InvocationPlugins plugins;
-        private final Class<?> declaringClass;
-        private boolean allowOverwrite;
-
-        /**
-         * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
-         * given class.
-         *
-         * @param plugins where to register the plugins
-         * @param declaringClass the class declaring the methods for which plugins will be
-         *            registered via this object
-         */
-        public Registration(InvocationPlugins plugins, Class<?> declaringClass) {
-            this.plugins = plugins;
-            this.declaringClass = declaringClass;
-        }
-
-        /**
-         * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
-         * given class.
-         *
-         * @param plugins where to register the plugins
-         * @param declaringClassName the name of the class class declaring the methods for which
-         *            plugins will be registered via this object
-         */
-        public Registration(InvocationPlugins plugins, String declaringClassName) {
-            this.plugins = plugins;
-            try {
-                this.declaringClass = Class.forName(declaringClassName);
-            } catch (ClassNotFoundException ex) {
-                throw JVMCIError.shouldNotReachHere(ex);
-            }
-        }
-
-        /**
-         * Configures this registration to allow or disallow overwriting of invocation plugins.
-         */
-        public Registration setAllowOverwrite(boolean allowOverwrite) {
-            this.allowOverwrite = allowOverwrite;
-            return this;
-        }
-
-        /**
-         * Registers a plugin for a method with no arguments.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void register0(String name, InvocationPlugin plugin) {
-            plugins.register(plugin, false, allowOverwrite, declaringClass, name);
-        }
-
-        /**
-         * Registers a plugin for a method with 1 argument.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void register1(String name, Class<?> arg, InvocationPlugin plugin) {
-            plugins.register(plugin, false, allowOverwrite, declaringClass, name, arg);
-        }
-
-        /**
-         * Registers a plugin for a method with 2 arguments.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void register2(String name, Class<?> arg1, Class<?> arg2, InvocationPlugin plugin) {
-            plugins.register(plugin, false, allowOverwrite, declaringClass, name, arg1, arg2);
-        }
-
-        /**
-         * Registers a plugin for a method with 3 arguments.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void register3(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, InvocationPlugin plugin) {
-            plugins.register(plugin, false, allowOverwrite, declaringClass, name, arg1, arg2, arg3);
-        }
-
-        /**
-         * Registers a plugin for a method with 4 arguments.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void register4(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, InvocationPlugin plugin) {
-            plugins.register(plugin, false, allowOverwrite, declaringClass, name, arg1, arg2, arg3, arg4);
-        }
-
-        /**
-         * Registers a plugin for a method with 5 arguments.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void register5(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, Class<?> arg5, InvocationPlugin plugin) {
-            plugins.register(plugin, false, allowOverwrite, declaringClass, name, arg1, arg2, arg3, arg4, arg5);
-        }
-
-        /**
-         * Registers a plugin for an optional method with no arguments.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void registerOptional0(String name, InvocationPlugin plugin) {
-            plugins.register(plugin, true, allowOverwrite, declaringClass, name);
-        }
-
-        /**
-         * Registers a plugin for an optional method with 1 argument.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void registerOptional1(String name, Class<?> arg, InvocationPlugin plugin) {
-            plugins.register(plugin, true, allowOverwrite, declaringClass, name, arg);
-        }
-
-        /**
-         * Registers a plugin for an optional method with 2 arguments.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void registerOptional2(String name, Class<?> arg1, Class<?> arg2, InvocationPlugin plugin) {
-            plugins.register(plugin, true, allowOverwrite, declaringClass, name, arg1, arg2);
-        }
-
-        /**
-         * Registers a plugin for an optional method with 3 arguments.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void registerOptional3(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, InvocationPlugin plugin) {
-            plugins.register(plugin, true, allowOverwrite, declaringClass, name, arg1, arg2, arg3);
-        }
-
-        /**
-         * Registers a plugin for an optional method with 4 arguments.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void registerOptional4(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, InvocationPlugin plugin) {
-            plugins.register(plugin, true, allowOverwrite, declaringClass, name, arg1, arg2, arg3, arg4);
-        }
-
-        /**
-         * Registers a plugin that implements a method based on the bytecode of a substitute method.
-         *
-         * @param substituteDeclaringClass the class declaring the substitute method
-         * @param name the name of both the original and substitute method
-         * @param argumentTypes the argument types of the method. Element 0 of this array must be
-         *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
-         *            is non-static. Upon returning, element 0 will have been rewritten to
-         *            {@code declaringClass}
-         */
-        public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, Class<?>... argumentTypes) {
-            registerMethodSubstitution(substituteDeclaringClass, name, name, argumentTypes);
-        }
-
-        /**
-         * Registers a plugin that implements a method based on the bytecode of a substitute method.
-         *
-         * @param substituteDeclaringClass the class declaring the substitute method
-         * @param name the name of both the original method
-         * @param substituteName the name of the substitute method
-         * @param argumentTypes the argument types of the method. Element 0 of this array must be
-         *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
-         *            is non-static. Upon returning, element 0 will have been rewritten to
-         *            {@code declaringClass}
-         */
-        public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, String substituteName, Class<?>... argumentTypes) {
-            MethodSubstitutionPlugin plugin = new MethodSubstitutionPlugin(substituteDeclaringClass, substituteName, argumentTypes);
-            plugins.register(plugin, false, allowOverwrite, declaringClass, name, argumentTypes);
-        }
-    }
-
-    /**
-     * Key for a method.
-     */
-    static class MethodKey {
-        final boolean isStatic;
-
-        /**
-         * This method is optional. This is used for new API methods not present in previous JDK
-         * versions.
-         */
-        final boolean isOptional;
-
-        final Class<?> declaringClass;
-        final String name;
-        final Class<?>[] argumentTypes;
-        final InvocationPlugin value;
-
-        MethodKey(InvocationPlugin data, boolean isStatic, boolean isOptional, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
-            assert isStatic || argumentTypes[0] == declaringClass;
-            this.value = data;
-            this.isStatic = isStatic;
-            this.isOptional = isOptional;
-            this.declaringClass = declaringClass;
-            this.name = name;
-            this.argumentTypes = argumentTypes;
-            assert isOptional || resolveJava() != null;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof MethodKey) {
-                MethodKey that = (MethodKey) obj;
-                boolean res = this.name.equals(that.name) && this.declaringClass.equals(that.declaringClass) && Arrays.equals(this.argumentTypes, that.argumentTypes);
-                assert !res || this.isStatic == that.isStatic;
-                return res;
-            }
-            return false;
-        }
-
-        public int getDeclaredParameterCount() {
-            return isStatic ? argumentTypes.length : argumentTypes.length - 1;
-        }
-
-        @Override
-        public int hashCode() {
-            // Replay compilation mandates use of stable hash codes
-            return declaringClass.getName().hashCode() ^ name.hashCode();
-        }
-
-        private ResolvedJavaMethod resolve(MetaAccessProvider metaAccess) {
-            Executable method = resolveJava();
-            if (method == null) {
-                return null;
-            }
-            return metaAccess.lookupJavaMethod(method);
-        }
-
-        private Executable resolveJava() {
-            try {
-                Executable res;
-                Class<?>[] parameterTypes = isStatic ? argumentTypes : Arrays.copyOfRange(argumentTypes, 1, argumentTypes.length);
-                if (name.equals("<init>")) {
-                    res = declaringClass.getDeclaredConstructor(parameterTypes);
-                } else {
-                    res = declaringClass.getDeclaredMethod(name, parameterTypes);
-                }
-                assert Modifier.isStatic(res.getModifiers()) == isStatic;
-                return res;
-            } catch (NoSuchMethodException | SecurityException e) {
-                if (isOptional) {
-                    return null;
-                }
-                throw new InternalError(e);
-            }
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder(declaringClass.getName()).append('.').append(name).append('(');
-            for (Class<?> p : argumentTypes) {
-                if (sb.charAt(sb.length() - 1) != '(') {
-                    sb.append(", ");
-                }
-                sb.append(p.getSimpleName());
-            }
-            return sb.append(')').toString();
-        }
-    }
-
-    private final MetaAccessProvider metaAccess;
-
-    /**
-     * Initial list of entries.
-     */
-    private final List<MethodKey> registrations = new ArrayList<>(INITIAL_CAPACITY);
-
-    /**
-     * Entry map that is initialized upon first call to {@link #get(ResolvedJavaMethod)}.
-     *
-     * Note: this must be volatile since double-checked locking is used to initialize it
-     */
-    private volatile Map<ResolvedJavaMethod, InvocationPlugin> entries;
-
-    private static final int INITIAL_CAPACITY = 64;
-
-    /**
-     * Adds an entry to this map for a specified method.
-     *
-     * @param value value to be associated with the specified method
-     * @param isStatic specifies if the method is static
-     * @param isOptional specifies if the method is optional
-     * @param declaringClass the class declaring the method
-     * @param name the name of the method
-     * @param argumentTypes the argument types of the method. Element 0 of this array must be
-     *            {@code declaringClass} iff the method is non-static.
-     * @return an object representing the method
-     */
-    MethodKey put(InvocationPlugin value, boolean isStatic, boolean isOptional, boolean allowOverwrite, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
-        assert isStatic || argumentTypes[0] == declaringClass;
-        MethodKey methodKey = new MethodKey(value, isStatic, isOptional, declaringClass, name, argumentTypes);
-        assert entries == null : "registration is closed";
-        assert allowOverwrite || !registrations.contains(methodKey) : "a value is already registered for " + methodKey;
-        registrations.add(methodKey);
-        return methodKey;
-    }
-
-    /**
-     * Determines if a method denoted by a given {@link MethodKey} is in this map.
-     */
-    boolean containsKey(MethodKey key) {
-        return registrations.contains(key);
-    }
-
-    InvocationPlugin get(ResolvedJavaMethod method) {
-        if (entries == null) {
-            initializeMap();
-        }
-
-        return entries.get(method);
-    }
-
-    /**
-     * Disallows new registrations of new plugins, and creates the internal tables for method
-     * lookup.
-     */
-    public void closeRegistration() {
-        if (entries == null) {
-            initializeMap();
-        }
-    }
-
-    void initializeMap() {
-        if (registrations.isEmpty()) {
-            entries = Collections.emptyMap();
-        } else {
-            Map<ResolvedJavaMethod, InvocationPlugin> newEntries = new HashMap<>();
-            for (MethodKey methodKey : registrations) {
-                ResolvedJavaMethod m = methodKey.resolve(metaAccess);
-                newEntries.put(m, methodKey.value);
-            }
-            entries = newEntries;
-        }
-    }
-
-    public int size() {
-        return registrations.size();
-    }
-
-    /**
-     * The plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched} before searching in
-     * this object.
-     */
-    protected final InvocationPlugins parent;
-
-    private InvocationPlugins(InvocationPlugins parent, MetaAccessProvider metaAccess) {
-        this.metaAccess = metaAccess;
-        InvocationPlugins p = parent;
-        this.parent = p;
-    }
-
-    /**
-     * Creates a set of invocation plugins with a non-null {@linkplain #getParent() parent}.
-     */
-    public InvocationPlugins(InvocationPlugins parent) {
-        this(parent, parent.getMetaAccess());
-    }
-
-    public MetaAccessProvider getMetaAccess() {
-        return metaAccess;
-    }
-
-    public InvocationPlugins(MetaAccessProvider metaAccess) {
-        this(null, metaAccess);
-    }
-
-    private void register(InvocationPlugin plugin, boolean isOptional, boolean allowOverwrite, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
-        boolean isStatic = argumentTypes.length == 0 || argumentTypes[0] != InvocationPlugin.Receiver.class;
-        if (!isStatic) {
-            argumentTypes[0] = declaringClass;
-        }
-        MethodKey methodInfo = put(plugin, isStatic, isOptional, allowOverwrite, declaringClass, name, argumentTypes);
-        assert Checker.check(this, methodInfo, plugin);
-    }
-
-    /**
-     * Registers an invocation plugin for a given method. There must be no plugin currently
-     * registered for {@code method}.
-     *
-     * @param argumentTypes the argument types of the method. Element 0 of this array must be the
-     *            {@link Class} value for {@link InvocationPlugin.Receiver} iff the method is
-     *            non-static. Upon returning, element 0 will have been rewritten to
-     *            {@code declaringClass}
-     */
-    public void register(InvocationPlugin plugin, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
-        register(plugin, false, false, declaringClass, name, argumentTypes);
-    }
-
-    /**
-     * Registers an invocation plugin for a given, optional method. There must be no plugin
-     * currently registered for {@code method}.
-     *
-     * @param argumentTypes the argument types of the method. Element 0 of this array must be the
-     *            {@link Class} value for {@link InvocationPlugin.Receiver} iff the method is
-     *            non-static. Upon returning, element 0 will have been rewritten to
-     *            {@code declaringClass}
-     */
-    public void registerOptional(InvocationPlugin plugin, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
-        register(plugin, true, false, declaringClass, name, argumentTypes);
-    }
-
-    /**
-     * Gets the plugin for a given method.
-     *
-     * @param method the method to lookup
-     * @return the plugin associated with {@code method} or {@code null} if none exists
-     */
-    public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
-        if (parent != null) {
-            InvocationPlugin plugin = parent.lookupInvocation(method);
-            if (plugin != null) {
-                return plugin;
-            }
-        }
-        return get(method);
-    }
-
-    /**
-     * Gets the invocation plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched}
-     * before searching in this object.
-     */
-    public InvocationPlugins getParent() {
-        return parent;
-    }
-
-    @Override
-    public String toString() {
-        return registrations.stream().map(MethodKey::toString).collect(Collectors.joining(", ")) + " / parent: " + this.parent;
-    }
-
-    private static class Checker {
-        private static final int MAX_ARITY = 5;
-        /**
-         * The set of all {@link InvocationPlugin#apply} method signatures.
-         */
-        static final Class<?>[][] SIGS;
-
-        static {
-            ArrayList<Class<?>[]> sigs = new ArrayList<>(MAX_ARITY);
-            for (Method method : InvocationPlugin.class.getDeclaredMethods()) {
-                if (!Modifier.isStatic(method.getModifiers()) && method.getName().equals("apply")) {
-                    Class<?>[] sig = method.getParameterTypes();
-                    assert sig[0] == GraphBuilderContext.class;
-                    assert sig[1] == ResolvedJavaMethod.class;
-                    assert sig[2] == InvocationPlugin.Receiver.class;
-                    assert Arrays.asList(sig).subList(3, sig.length).stream().allMatch(c -> c == ValueNode.class);
-                    while (sigs.size() < sig.length - 2) {
-                        sigs.add(null);
-                    }
-                    sigs.set(sig.length - 3, sig);
-                }
-            }
-            assert sigs.indexOf(null) == -1 : format("need to add an apply() method to %s that takes %d %s arguments ", InvocationPlugin.class.getName(), sigs.indexOf(null),
-                            ValueNode.class.getSimpleName());
-            SIGS = sigs.toArray(new Class<?>[sigs.size()][]);
-        }
-
-        public static boolean check(InvocationPlugins plugins, MethodKey method, InvocationPlugin plugin) {
-            InvocationPlugins p = plugins.parent;
-            while (p != null) {
-                assert !p.containsKey(method) : "a plugin is already registered for " + method;
-                p = p.parent;
-            }
-            if (plugin instanceof ForeignCallPlugin) {
-                return true;
-            }
-            if (plugin instanceof MethodSubstitutionPlugin) {
-                MethodSubstitutionPlugin msplugin = (MethodSubstitutionPlugin) plugin;
-                msplugin.getJavaSubstitute();
-                return true;
-            }
-            int arguments = method.getDeclaredParameterCount();
-            assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method);
-            for (Method m : plugin.getClass().getDeclaredMethods()) {
-                if (m.getName().equals("apply")) {
-                    Class<?>[] parameterTypes = m.getParameterTypes();
-                    if (Arrays.equals(SIGS[arguments], parameterTypes)) {
-                        return true;
-                    }
-                }
-            }
-            throw new AssertionError(format("graph builder plugin for %s not found", method));
-        }
-    }
-
-    /**
-     * Checks a set of nodes added to the graph by an {@link InvocationPlugin}.
-     *
-     * @param b the graph builder that applied the plugin
-     * @param plugin a plugin that was just applied
-     * @param newNodes the nodes added to the graph by {@code plugin}
-     * @throws AssertionError if any check fail
-     */
-    public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable<Node> newNodes) {
-        if (parent != null) {
-            parent.checkNewNodes(b, plugin, newNodes);
-        }
-    }
-}
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoopExplosionPlugin.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graphbuilderconf;
-
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-
-public interface LoopExplosionPlugin extends GraphBuilderPlugin {
-    boolean shouldExplodeLoops(ResolvedJavaMethod method);
-
-    boolean shouldMergeExplosions(ResolvedJavaMethod method);
-}
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodSubstitutionPlugin.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graphbuilderconf;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.stream.Collectors;
-
-import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import sun.misc.Launcher;
-
-import com.oracle.graal.nodes.ValueNode;
-
-/**
- * An {@link InvocationPlugin} for a method where the implementation of the method is provided by a
- * {@linkplain #getSubstitute(MetaAccessProvider) substitute} method. A substitute method must be
- * static even if the substituted method is not.
- */
-public final class MethodSubstitutionPlugin implements InvocationPlugin {
-
-    private ResolvedJavaMethod cachedSubstitute;
-
-    /**
-     * The class in which the substitute method is declared.
-     */
-    private final Class<?> declaringClass;
-
-    /**
-     * The name of the original and substitute method.
-     */
-    private final String name;
-
-    /**
-     * The parameter types of the substitute method.
-     */
-    private final Class<?>[] parameters;
-
-    private final boolean originalIsStatic;
-
-    /**
-     * Creates a method substitution plugin.
-     *
-     * @param declaringClass the class in which the substitute method is declared
-     * @param name the name of the substitute method
-     * @param parameters the parameter types of the substitute method. If the original method is not
-     *            static, then {@code parameters[0]} must be the {@link Class} value denoting
-     *            {@link InvocationPlugin.Receiver}
-     */
-    public MethodSubstitutionPlugin(Class<?> declaringClass, String name, Class<?>... parameters) {
-        this.declaringClass = declaringClass;
-        this.name = name;
-        this.parameters = parameters;
-        this.originalIsStatic = parameters.length == 0 || parameters[0] != InvocationPlugin.Receiver.class;
-    }
-
-    /**
-     * Creates a method substitution plugin.
-     *
-     * @param declaringClass the class in which the substitute method is declared
-     * @param name the name of the substitute method
-     * @param parameters the parameter types of the substitute method
-     */
-    public MethodSubstitutionPlugin(boolean originalIsStatic, Class<?> declaringClass, String name, Class<?>... parameters) {
-        this.declaringClass = declaringClass;
-        this.name = name;
-        this.parameters = parameters;
-        this.originalIsStatic = originalIsStatic;
-    }
-
-    public boolean inlineOnly() {
-        // Conservatively assume MacroNodes may be used in a substitution
-        return true;
-    }
-
-    /**
-     * Gets the substitute method, resolving it first if necessary.
-     */
-    public ResolvedJavaMethod getSubstitute(MetaAccessProvider metaAccess) {
-        if (cachedSubstitute == null) {
-            cachedSubstitute = metaAccess.lookupJavaMethod(getJavaSubstitute());
-        }
-        return cachedSubstitute;
-    }
-
-    /**
-     * Gets the reflection API version of the substitution method.
-     */
-    Method getJavaSubstitute() throws JVMCIError {
-        Method substituteMethod = lookupSubstitute();
-        int modifiers = substituteMethod.getModifiers();
-        if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
-            throw new JVMCIError("Substitution method must not be abstract or native: " + substituteMethod);
-        }
-        if (!Modifier.isStatic(modifiers)) {
-            throw new JVMCIError("Substitution method must be static: " + substituteMethod);
-        }
-        return substituteMethod;
-    }
-
-    /**
-     * Determines if a given method is the substitute method of this plugin.
-     */
-    private boolean isSubstitute(Method m) {
-        if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(name)) {
-            if (parameters.length == m.getParameterCount()) {
-                Class<?>[] mparams = m.getParameterTypes();
-                int start = 0;
-                if (!originalIsStatic) {
-                    start = 1;
-                    if (!mparams[0].isAssignableFrom(parameters[0])) {
-                        return false;
-                    }
-                }
-                for (int i = start; i < mparams.length; i++) {
-                    if (mparams[i] != parameters[i]) {
-                        return false;
-                    }
-                }
-            }
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Gets the substitute method of this plugin.
-     */
-    private Method lookupSubstitute() {
-        for (Method m : declaringClass.getDeclaredMethods()) {
-            if (isSubstitute(m)) {
-                return m;
-            }
-        }
-        throw new JVMCIError("No method found specified by %s", this);
-    }
-
-    /**
-     * Resolves a name to a class.
-     *
-     * @param className the name of the class to resolve
-     * @param optional if true, resolution failure returns null
-     * @return the resolved class or null if resolution fails and {@code optional} is true
-     */
-    public static Class<?> resolveClass(String className, boolean optional) {
-        try {
-            // Need to use launcher class path to handle classes
-            // that are not on the boot class path
-            ClassLoader cl = Launcher.getLauncher().getClassLoader();
-            return Class.forName(className, false, cl);
-        } catch (ClassNotFoundException e) {
-            if (optional) {
-                return null;
-            }
-            throw new JVMCIError("Could not resolve type " + className);
-        }
-    }
-
-    @Override
-    public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver) {
-        ResolvedJavaMethod subst = getSubstitute(b.getMetaAccess());
-        if (receiver != null) {
-            receiver.get();
-        }
-        b.intrinsify(targetMethod, subst, argsIncludingReceiver);
-        return true;
-    }
-
-    public StackTraceElement getApplySourceLocation(MetaAccessProvider metaAccess) {
-        Class<?> c = getClass();
-        for (Method m : c.getDeclaredMethods()) {
-            if (m.getName().equals("execute")) {
-                return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
-            }
-        }
-        throw new JVMCIError("could not find method named \"execute\" in " + c.getName());
-    }
-
-    @Override
-    public String toString() {
-        return String.format("%s[%s.%s(%s)]", getClass().getSimpleName(), declaringClass.getName(), name,
-                        Arrays.asList(parameters).stream().map(c -> c.getSimpleName()).collect(Collectors.joining(", ")));
-    }
-}
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/NodePlugin.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,213 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graphbuilderconf;
-
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.JavaTypeProfile;
-import jdk.vm.ci.meta.ResolvedJavaField;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.meta.Signature;
-
-import com.oracle.graal.nodes.ValueNode;
-
-public interface NodePlugin extends GraphBuilderPlugin {
-    /**
-     * Handle the parsing of a method invocation bytecode to a method that can be bound statically.
-     * If the method returns true, it must {@link GraphBuilderContext#push push} a value as the
-     * result of the method invocation using the {@link Signature#getReturnKind return kind} of the
-     * method.
-     *
-     * @param b the context
-     * @param method the statically bound, invoked method
-     * @param args the arguments of the method invocation
-     * @return true if the plugin handles the invocation, false otherwise
-     */
-    default boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
-        return false;
-    }
-
-    /**
-     * Handle the parsing of a GETFIELD bytecode. If the method returns true, it must
-     * {@link GraphBuilderContext#push push} a value using the
-     * {@link ResolvedJavaField#getJavaKind() kind} of the field.
-     *
-     * @param b the context
-     * @param object the receiver object for the field access
-     * @param field the accessed field
-     * @return true if the plugin handles the field access, false otherwise
-     */
-    default boolean handleLoadField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field) {
-        return false;
-    }
-
-    /**
-     * Handle the parsing of a GETSTATIC bytecode. If the method returns true, it must
-     * {@link GraphBuilderContext#push push} a value using the
-     * {@link ResolvedJavaField#getJavaKind() kind} of the field.
-     *
-     * @param b the context
-     * @param field the accessed field
-     * @return true if the plugin handles the field access, false otherwise
-     */
-    default boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField field) {
-        return false;
-    }
-
-    /**
-     * Handle the parsing of a PUTFIELD bytecode.
-     *
-     * @param b the context
-     * @param object the receiver object for the field access
-     * @param field the accessed field
-     * @param value the value to be stored into the field
-     * @return true if the plugin handles the field access, false otherwise
-     */
-    default boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) {
-        return false;
-    }
-
-    /**
-     * Handle the parsing of a PUTSTATIC bytecode.
-     *
-     * @param b the context
-     * @param field the accessed field
-     * @param value the value to be stored into the field
-     * @return true if the plugin handles the field access, false otherwise.
-     */
-    default boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value) {
-        return false;
-    }
-
-    /**
-     * Handle the parsing of an array load bytecode. If the method returns true, it must
-     * {@link GraphBuilderContext#push push} a value using the provided elementKind.
-     *
-     * @param b the context
-     * @param array the accessed array
-     * @param index the index for the array access
-     * @param elementKind the element kind of the accessed array
-     * @return true if the plugin handles the array access, false otherwise.
-     */
-    default boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind) {
-        return false;
-    }
-
-    /**
-     * Handle the parsing of an array store bytecode.
-     *
-     * @param b the context
-     * @param array the accessed array
-     * @param index the index for the array access
-     * @param elementKind the element kind of the accessed array
-     * @param value the value to be stored into the array
-     * @return true if the plugin handles the array access, false otherwise.
-     */
-    default boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind, ValueNode value) {
-        return false;
-    }
-
-    /**
-     * Handle the parsing of a CHECKCAST bytecode. If the method returns true, it must
-     * {@link GraphBuilderContext#push push} a value with the result of the cast using
-     * {@link JavaKind#Object}.
-     *
-     * @param b the context
-     * @param object the object to be type checked
-     * @param type the type that the object is checked against
-     * @param profile the profiling information for the type check, or null if no profiling
-     *            information is available
-     * @return true if the plugin handles the cast, false otherwise
-     */
-    default boolean handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
-        return false;
-    }
-
-    /**
-     * Handle the parsing of a INSTANCEOF bytecode. If the method returns true, it must
-     * {@link GraphBuilderContext#push push} a value with the result of the instanceof using
-     * {@link JavaKind#Int}.
-     *
-     * @param b the context
-     * @param object the object to be type checked
-     * @param type the type that the object is checked against
-     * @param profile the profiling information for the type check, or null if no profiling
-     *            information is available
-     * @return true if the plugin handles the instanceof, false otherwise
-     */
-    default boolean handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
-        return false;
-    }
-
-    /**
-     * Handle the parsing of a NEW bytecode. If the method returns true, it must
-     * {@link GraphBuilderContext#push push} a value with the result of the allocation using
-     * {@link JavaKind#Object}.
-     *
-     * @param b the context
-     * @param type the type to be instantiated
-     * @return true if the plugin handles the bytecode, false otherwise
-     */
-    default boolean handleNewInstance(GraphBuilderContext b, ResolvedJavaType type) {
-        return false;
-    }
-
-    /**
-     * Handle the parsing of a NEWARRAY and ANEWARRAY bytecode. If the method returns true, it must
-     * {@link GraphBuilderContext#push push} a value with the result of the allocation using
-     * {@link JavaKind#Object}.
-     *
-     * @param b the context
-     * @param elementType the element type of the array to be instantiated
-     * @param length the length of the new array
-     * @return true if the plugin handles the bytecode, false otherwise
-     */
-    default boolean handleNewArray(GraphBuilderContext b, ResolvedJavaType elementType, ValueNode length) {
-        return false;
-    }
-
-    /**
-     * Handle the parsing of a MULTIANEWARRAY bytecode. If the method returns true, it must
-     * {@link GraphBuilderContext#push push} a value with the result of the allocation using
-     * {@link JavaKind#Object}.
-     *
-     * @param b the context
-     * @param type the type of the outermost array to be instantiated
-     * @param dimensions the array of lengths for all the dimensions to be instantiated
-     * @return true if the plugin handles the bytecode, false otherwise
-     */
-    default boolean handleNewMultiArray(GraphBuilderContext b, ResolvedJavaType type, ValueNode[] dimensions) {
-        return false;
-    }
-
-    /**
-     * If the plugin {@link GraphBuilderContext#push pushes} a value with a different
-     * {@link JavaKind} than specified by the bytecode, it must override this method and return
-     * {@code true}. This disables assertion checking for value kinds.
-     *
-     * @param b the context
-     */
-    default boolean canChangeStackKind(GraphBuilderContext b) {
-        return false;
-    }
-}
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ParameterPlugin.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graphbuilderconf;
-
-import com.oracle.graal.compiler.common.type.Stamp;
-import com.oracle.graal.nodes.calc.FloatingNode;
-
-public interface ParameterPlugin extends GraphBuilderPlugin {
-    FloatingNode interceptParameter(GraphBuilderContext b, int index, Stamp stamp);
-}
--- a/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/DataPatchInConstantsTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/DataPatchInConstantsTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, 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
@@ -29,18 +29,17 @@
 import jdk.vm.ci.amd64.AMD64;
 import jdk.vm.ci.meta.AllocatableValue;
 import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 
-import com.oracle.graal.api.replacements.ClassSubstitution;
-import com.oracle.graal.api.replacements.MethodSubstitution;
 import com.oracle.graal.asm.amd64.AMD64Address;
 import com.oracle.graal.asm.amd64.AMD64MacroAssembler;
 import com.oracle.graal.graph.NodeClass;
 import com.oracle.graal.hotspot.nodes.CompressionNode;
-import com.oracle.graal.hotspot.nodes.CompressionNode.CompressionOp;
 import com.oracle.graal.hotspot.nodes.type.NarrowOopStamp;
 import com.oracle.graal.hotspot.test.HotSpotGraalCompilerTest;
 import com.oracle.graal.lir.LIRInstruction;
@@ -51,6 +50,10 @@
 import com.oracle.graal.nodeinfo.NodeInfo;
 import com.oracle.graal.nodes.FixedWithNextNode;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.spi.LIRLowerable;
 import com.oracle.graal.nodes.spi.NodeLIRBuilderTool;
 
@@ -135,30 +138,28 @@
         test("compareSnippet");
     }
 
-    private static boolean initReplacements = false;
-
-    @Before
-    public void initReplacements() {
-        if (!initReplacements) {
-            getReplacements().registerSubstitutions(DataPatchInConstantsTest.class, DataPatchInConstantsTestSubstitutions.class);
-            initReplacements = true;
-        }
-    }
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins plugins = super.getDefaultGraphBuilderPlugins();
+        Registration r = new Registration(plugins.getInvocationPlugins(), DataPatchInConstantsTest.class);
 
-    @ClassSubstitution(DataPatchInConstantsTest.class)
-    private static class DataPatchInConstantsTestSubstitutions {
+        r.register1("loadThroughPatch", Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+                b.addPush(JavaKind.Object, new LoadThroughPatchNode(arg));
+                return true;
+            }
+        });
 
-        @MethodSubstitution
-        public static Object loadThroughPatch(Object obj) {
-            return LoadThroughPatchNode.load(obj);
-        }
+        r.register1("loadThroughCompressedPatch", Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+                ValueNode compressed = b.add(CompressionNode.compress(arg, config().getOopEncoding()));
+                ValueNode patch = b.add(new LoadThroughPatchNode(compressed));
+                b.addPush(JavaKind.Object, CompressionNode.uncompress(patch, config().getOopEncoding()));
+                return true;
+            }
+        });
 
-        @MethodSubstitution
-        public static Object loadThroughCompressedPatch(Object obj) {
-            Object compressed = CompressionNode.compression(CompressionOp.Compress, obj, config().getOopEncoding());
-            Object patch = LoadThroughPatchNode.load(compressed);
-            return CompressionNode.compression(CompressionOp.Uncompress, patch, config().getOopEncoding());
-        }
+        return plugins;
     }
 
     @NodeInfo
@@ -181,9 +182,6 @@
             gen.append(new LoadThroughPatchOp(input.asConstant(), stamp() instanceof NarrowOopStamp, ret));
             generator.setResult(this, ret);
         }
-
-        @NodeIntrinsic
-        public static native Object load(Object obj);
     }
 
     private static final class LoadThroughPatchOp extends LIRInstruction {
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue Dec 08 12:30:15 2015 -0800
@@ -45,7 +45,6 @@
 
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
 import com.oracle.graal.compiler.amd64.AMD64SuitesProvider;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.hotspot.DefaultHotSpotGraalCompilerFactory;
 import com.oracle.graal.hotspot.HotSpotBackend;
 import com.oracle.graal.hotspot.HotSpotBackendFactory;
@@ -63,9 +62,11 @@
 import com.oracle.graal.hotspot.meta.HotSpotStampProvider;
 import com.oracle.graal.hotspot.meta.HotSpotSuitesProvider;
 import com.oracle.graal.hotspot.word.HotSpotWordTypes;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.phases.tiers.CompilerConfiguration;
 import com.oracle.graal.phases.util.Providers;
 import com.oracle.graal.replacements.amd64.AMD64GraphBuilderPlugins;
+import com.oracle.graal.word.WordTypes;
 
 @ServiceProvider(HotSpotBackendFactory.class)
 public class AMD64HotSpotBackendFactory implements HotSpotBackendFactory {
@@ -112,15 +113,15 @@
             HotSpotStampProvider stampProvider = new HotSpotStampProvider();
             Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null, stampProvider);
 
+            try (InitTimer rt = timer("create WordTypes")) {
+                wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind);
+            }
             try (InitTimer rt = timer("create SnippetReflection provider")) {
-                snippetReflection = createSnippetReflection(graalRuntime, constantReflection);
+                snippetReflection = createSnippetReflection(graalRuntime, constantReflection, wordTypes);
             }
             try (InitTimer rt = timer("create Replacements provider")) {
                 replacements = createReplacements(config, p, snippetReflection);
             }
-            try (InitTimer rt = timer("create WordTypes")) {
-                wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind);
-            }
             try (InitTimer rt = timer("create GraphBuilderPhase plugins")) {
                 plugins = createGraphBuilderPlugins(config, target, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes, stampProvider);
                 replacements.setGraphBuilderPlugins(plugins);
@@ -166,8 +167,8 @@
                         registers.getHeapBaseRegister()));
     }
 
-    protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection) {
-        return new HotSpotSnippetReflectionProvider(runtime, constantReflection);
+    protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) {
+        return new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes);
     }
 
     protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls,
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Tue Dec 08 12:30:15 2015 -0800
@@ -324,11 +324,9 @@
         RegisterConfig regConfig = frameMap.getRegisterConfig();
         HotSpotVMConfig config = config();
         Label unverifiedStub = installedCodeOwner == null || installedCodeOwner.isStatic() ? null : new Label();
-        boolean hasUnsafeAccess = crb.compilationResult.hasUnsafeAccess();
-        int i = 0;
-        do {
+        for (int i = 0; i < 2; i++) {
             if (i > 0) {
-                crb.reset();
+                crb.resetForEmittingCode();
                 lir.resetLabels();
                 resetDelayedControlTransfers(lir);
             }
@@ -358,9 +356,7 @@
 
             // Emit code for the LIR
             crb.emit(lir);
-        } while (i++ < 1);
-        // Restore the unsafeAccess flag
-        crb.compilationResult.setHasUnsafeAccess(hasUnsafeAccess);
+        }
         profileInstructions(lir, crb);
 
         HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Tue Dec 08 12:30:15 2015 -0800
@@ -42,7 +42,6 @@
 
 import com.oracle.graal.compiler.sparc.SPARCAddressLowering;
 import com.oracle.graal.compiler.sparc.SPARCSuitesProvider;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.hotspot.DefaultHotSpotGraalCompilerFactory;
 import com.oracle.graal.hotspot.HotSpotBackend;
 import com.oracle.graal.hotspot.HotSpotBackendFactory;
@@ -59,6 +58,7 @@
 import com.oracle.graal.hotspot.meta.HotSpotStampProvider;
 import com.oracle.graal.hotspot.meta.HotSpotSuitesProvider;
 import com.oracle.graal.hotspot.word.HotSpotWordTypes;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.spi.LoweringProvider;
 import com.oracle.graal.phases.tiers.CompilerConfiguration;
 import com.oracle.graal.phases.util.Providers;
@@ -88,9 +88,9 @@
         LoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
         HotSpotStampProvider stampProvider = new HotSpotStampProvider();
         Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null, stampProvider);
-        HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime, constantReflection);
+        HotSpotWordTypes wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind);
+        HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes);
         HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, snippetReflection, config, target);
-        HotSpotWordTypes wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind);
         Plugins plugins = createGraphBuilderPlugins(config, metaAccess, constantReflection, foreignCalls, stampProvider, snippetReflection, replacements, wordTypes);
         replacements.setGraphBuilderPlugins(plugins);
         HotSpotSuitesProvider suites = createSuites(config, runtime, compilerConfiguration, plugins, codeCache);
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Tue Dec 08 12:30:15 2015 -0800
@@ -31,6 +31,8 @@
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.LEAF_NOFP;
 import static com.oracle.graal.hotspot.HotSpotHostBackend.DEOPTIMIZATION_HANDLER;
 import static com.oracle.graal.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
+import static com.oracle.graal.hotspot.replacements.CRC32Substitutions.UPDATE_BYTES_CRC32;
+import static jdk.vm.ci.code.CallingConvention.Type.NativeCall;
 import static jdk.vm.ci.meta.LocationIdentity.any;
 import static jdk.vm.ci.meta.Value.ILLEGAL;
 import static jdk.vm.ci.sparc.SPARC.i0;
@@ -87,6 +89,11 @@
             link(new SPARCUncommonTrapStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS), config));
         }
 
+        if (config.useCRC32Intrinsics) {
+            // This stub does callee saving
+            registerForeignCall(UPDATE_BYTES_CRC32, config.updateBytesCRC32Stub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, any());
+        }
+
         super.initialize(providers);
     }
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/DataPatchTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/DataPatchTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -30,17 +30,12 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import com.oracle.graal.api.directives.GraalDirectives;
 import com.oracle.graal.api.replacements.ClassSubstitution;
 import com.oracle.graal.api.replacements.MethodSubstitution;
 import com.oracle.graal.compiler.test.GraalCompilerTest;
-import com.oracle.graal.graph.NodeClass;
 import com.oracle.graal.hotspot.nodes.CompressionNode;
 import com.oracle.graal.hotspot.nodes.CompressionNode.CompressionOp;
-import com.oracle.graal.nodeinfo.NodeInfo;
-import com.oracle.graal.nodes.ValueNode;
-import com.oracle.graal.nodes.calc.FloatingNode;
-import com.oracle.graal.nodes.spi.LIRLowerable;
-import com.oracle.graal.nodes.spi.NodeLIRBuilderTool;
 
 public class DataPatchTest extends GraalCompilerTest {
 
@@ -93,27 +88,8 @@
         @MethodSubstitution
         public static Object compressUncompress(Object obj) {
             Object compressed = CompressionNode.compression(CompressionOp.Compress, obj, config.getOopEncoding());
-            Object proxy = ConstantFoldBarrier.wrap(compressed);
+            Object proxy = GraalDirectives.opaque(compressed);
             return CompressionNode.compression(CompressionOp.Uncompress, proxy, config.getOopEncoding());
         }
     }
-
-    @NodeInfo
-    private static final class ConstantFoldBarrier extends FloatingNode implements LIRLowerable {
-
-        public static final NodeClass<ConstantFoldBarrier> TYPE = NodeClass.create(ConstantFoldBarrier.class);
-        @Input protected ValueNode input;
-
-        public ConstantFoldBarrier(ValueNode input) {
-            super(TYPE, input.stamp());
-            this.input = input;
-        }
-
-        public void generate(NodeLIRBuilderTool generator) {
-            generator.setResult(this, generator.operand(input));
-        }
-
-        @NodeIntrinsic
-        public static native Object wrap(Object object);
-    }
 }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ForeignCallDeoptimizeTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ForeignCallDeoptimizeTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -22,50 +22,42 @@
  */
 package com.oracle.graal.hotspot.test;
 
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
 import org.junit.Test;
 
-import com.oracle.graal.api.replacements.ClassSubstitution;
-import com.oracle.graal.api.replacements.MethodSubstitution;
-import com.oracle.graal.api.test.Graal;
-import com.oracle.graal.compiler.common.spi.ForeignCallDescriptor;
+import com.oracle.graal.compiler.common.spi.ForeignCallsProvider;
 import com.oracle.graal.compiler.test.GraalCompilerTest;
-import com.oracle.graal.graph.Node.ConstantNodeParameter;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.meta.HotSpotForeignCallsProviderImpl;
+import com.oracle.graal.hotspot.meta.HotSpotProviders;
+import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.extended.ForeignCallNode;
-import com.oracle.graal.nodes.spi.Replacements;
-import com.oracle.graal.runtime.RuntimeProvider;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
 
 /**
  * Tests that deoptimization upon exception handling works.
  */
 public class ForeignCallDeoptimizeTest extends GraalCompilerTest {
 
-    private static boolean substitutionsInstalled;
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        ForeignCallsProvider foreignCalls = ((HotSpotProviders) getProviders()).getForeignCalls();
 
-    public ForeignCallDeoptimizeTest() {
-        if (!substitutionsInstalled) {
-            Replacements replacements = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getProviders().getReplacements();
-            replacements.registerSubstitutions(ForeignCallDeoptimizeTest.class, Substitutions.class);
-            substitutionsInstalled = true;
-        }
-    }
+        Plugins ret = super.getDefaultGraphBuilderPlugins();
+        ret.getInvocationPlugins().register(new InvocationPlugin() {
 
-    @ClassSubstitution(ForeignCallDeoptimizeTest.class)
-    static class Substitutions {
-
-        @MethodSubstitution(isStatic = true)
-        static int testCallInt(int value) {
-            return testDeoptimizeCallInt(HotSpotForeignCallsProviderImpl.TEST_DEOPTIMIZE_CALL_INT, value);
-        }
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+                ForeignCallNode node = new ForeignCallNode(foreignCalls, HotSpotForeignCallsProviderImpl.TEST_DEOPTIMIZE_CALL_INT, arg);
+                b.addPush(JavaKind.Int, node);
+                return true;
+            }
+        }, ForeignCallDeoptimizeTest.class, "testCallInt", int.class);
+        return ret;
     }
 
-    /**
-     * Exercise deoptimization inside of a non leaf runtime call.
-     */
-    @NodeIntrinsic(ForeignCallNode.class)
-    static native int testDeoptimizeCallInt(@ConstantNodeParameter ForeignCallDescriptor descriptor, int value);
-
     public static int testCallInt(int value) {
         return value;
     }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.test;
 
-import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
+import static com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
 import static jdk.vm.ci.hotspot.HotSpotVMConfig.config;
 
 import java.io.ByteArrayOutputStream;
@@ -44,14 +44,14 @@
 import org.junit.Assert;
 import org.junit.Test;
 
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.IntrinsicContext;
 import com.oracle.graal.hotspot.meta.HotSpotGraphBuilderPlugins;
 import com.oracle.graal.hotspot.meta.HotSpotProviders;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.phases.OptimisticOptimizations;
 
 /**
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/JVMCIErrorTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,175 +0,0 @@
-/*
- * Copyright (c) 2015, 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.hotspot.test;
-
-import java.util.function.Consumer;
-
-import jdk.vm.ci.code.CompilationResult;
-import jdk.vm.ci.code.CompilationResult.ConstantReference;
-import jdk.vm.ci.code.CompilationResult.DataPatch;
-import jdk.vm.ci.code.CompilationResult.DataSectionReference;
-import jdk.vm.ci.code.CompilationResult.Infopoint;
-import jdk.vm.ci.code.CompilationResult.Reference;
-import jdk.vm.ci.code.DataSection.Data;
-import jdk.vm.ci.code.DataSection.DataBuilder;
-import jdk.vm.ci.code.InfopointReason;
-import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.hotspot.HotSpotConstant;
-import jdk.vm.ci.meta.Assumptions.Assumption;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.VMConstant;
-
-import org.junit.Test;
-
-import com.oracle.graal.compiler.test.GraalCompilerTest;
-
-public class JVMCIErrorTest extends GraalCompilerTest {
-
-    public static void testMethod() {
-    }
-
-    private void test(Consumer<CompilationResult> modify) {
-        ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
-        CompilationResult compResult = compile(method, null);
-
-        modify.accept(compResult);
-
-        getCodeCache().addCode(method, compResult, null, null);
-    }
-
-    @Test(expected = JVMCIError.class)
-    public void testInvalidAssumption() {
-        test(r -> r.setAssumptions(new Assumption[]{new InvalidAssumption()}));
-    }
-
-    private static class InvalidAssumption extends Assumption {
-    }
-
-    @Test(expected = JVMCIError.class)
-    public void testInvalidAlignment() {
-        test(r -> r.getDataSection().insertData(new Data(7, 1, DataBuilder.zero(1))));
-    }
-
-    @Test(expected = JVMCIError.class)
-    public void testInvalidDataSectionReference() {
-        test(r -> {
-            DataSectionReference ref = r.getDataSection().insertData(new Data(1, 1, DataBuilder.zero(1)));
-            Data data = new Data(1, 1, (buffer, patch) -> {
-                patch.accept(new DataPatch(buffer.position(), ref));
-                buffer.put((byte) 0);
-            });
-            r.getDataSection().insertData(data);
-        });
-    }
-
-    @Test(expected = JVMCIError.class)
-    public void testInvalidNarrowMethodInDataSection() {
-        test(r -> {
-            ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
-            HotSpotConstant c = (HotSpotConstant) method.getEncoding();
-            Data data = new Data(4, 4, (buffer, patch) -> {
-                patch.accept(new DataPatch(buffer.position(), new ConstantReference((VMConstant) c.compress())));
-                buffer.putInt(0);
-            });
-            r.getDataSection().insertData(data);
-        });
-    }
-
-    @Test(expected = JVMCIError.class)
-    public void testInvalidConstantInDataSection() {
-        test(r -> {
-            Data data = new Data(1, 1, (buffer, patch) -> {
-                patch.accept(new DataPatch(buffer.position(), new ConstantReference(new InvalidVMConstant())));
-            });
-            r.getDataSection().insertData(data);
-        });
-    }
-
-    @Test(expected = JVMCIError.class)
-    public void testInvalidConstantInCode() {
-        test(r -> r.recordDataPatch(0, new ConstantReference(new InvalidVMConstant())));
-    }
-
-    private static class InvalidVMConstant implements VMConstant {
-
-        public boolean isDefaultForKind() {
-            return false;
-        }
-
-        public String toValueString() {
-            return null;
-        }
-    }
-
-    @Test(expected = JVMCIError.class)
-    public void testInvalidReference() {
-        test(r -> r.recordDataPatch(0, new InvalidReference()));
-    }
-
-    private static class InvalidReference extends Reference {
-
-        @Override
-        public int hashCode() {
-            return 0;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            return false;
-        }
-    }
-
-    @Test(expected = JVMCIError.class)
-    public void testOutOfBoundsDataSectionReference() {
-        test(r -> {
-            DataSectionReference ref = new DataSectionReference();
-            ref.setOffset(0x1000);
-            r.recordDataPatch(0, ref);
-        });
-    }
-
-    @Test(expected = JVMCIError.class)
-    public void testInvalidMark() {
-        test(r -> r.recordMark(0, new Object()));
-    }
-
-    @Test(expected = JVMCIError.class)
-    public void testInvalidMarkInt() {
-        test(r -> r.recordMark(0, -1));
-    }
-
-    @Test(expected = JVMCIError.class)
-    public void testUnknownInfopointReason() {
-        test(r -> r.addInfopoint(new Infopoint(0, null, InfopointReason.UNKNOWN)));
-    }
-
-    @Test(expected = JVMCIError.class)
-    public void testInfopointMissingDebugInfo() {
-        test(r -> r.addInfopoint(new Infopoint(0, null, InfopointReason.METHOD_START)));
-    }
-
-    @Test(expected = JVMCIError.class)
-    public void testSafepointMissingDebugInfo() {
-        test(r -> r.addInfopoint(new Infopoint(0, null, InfopointReason.SAFEPOINT)));
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotForeignCallLinkage.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotForeignCallLinkage.java	Tue Dec 08 12:30:15 2015 -0800
@@ -77,7 +77,7 @@
          * in the called function. That is, {@code JavaFrameAnchor} management code around the call
          * is required.
          */
-        NOT_LEAF;
+        SAFEPOINT,
     }
 
     /**
@@ -115,4 +115,9 @@
      * Gets the VM symbol associated with the target {@linkplain #getAddress() address} of the call.
      */
     String getSymbol();
+
+    /**
+     * Identifies foreign calls which are guaranteed to include a safepoint check.
+     */
+    boolean isGuaranteedSafepoint();
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotForeignCallLinkageImpl.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotForeignCallLinkageImpl.java	Tue Dec 08 12:30:15 2015 -0800
@@ -172,6 +172,10 @@
         return reexecutable;
     }
 
+    public boolean isGuaranteedSafepoint() {
+        return transition == Transition.SAFEPOINT;
+    }
+
     public LocationIdentity[] getKilledLocations() {
         return killedLocations;
     }
@@ -241,7 +245,7 @@
 
     @Override
     public boolean needsDebugInfo() {
-        return transition == Transition.NOT_LEAF;
+        return transition == Transition.SAFEPOINT;
     }
 
     public boolean mayContainFP() {
@@ -249,7 +253,7 @@
     }
 
     public boolean needsJavaFrameAnchor() {
-        if (transition == Transition.NOT_LEAF || transition == Transition.STACK_INSPECTABLE_LEAF) {
+        if (transition == Transition.SAFEPOINT || transition == Transition.STACK_INSPECTABLE_LEAF) {
             if (stub != null) {
                 // The stub will do the JavaFrameAnchor management
                 // around the runtime call(s) it makes
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalCompiler.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalCompiler.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot;
 
 import static com.oracle.graal.compiler.common.GraalOptions.OptAssumptions;
-import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
+import static com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
 import static jdk.vm.ci.code.CallingConvention.Type.JavaCallee;
 import static jdk.vm.ci.code.CodeUtil.getCallingConvention;
 import jdk.vm.ci.code.CallingConvention;
@@ -47,9 +47,6 @@
 import com.oracle.graal.debug.TTY;
 import com.oracle.graal.debug.TopLevelDebugConfig;
 import com.oracle.graal.debug.internal.DebugScope;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.IntrinsicContext;
 import com.oracle.graal.hotspot.meta.HotSpotProviders;
 import com.oracle.graal.hotspot.meta.HotSpotSuitesProvider;
 import com.oracle.graal.hotspot.phases.OnStackReplacementPhase;
@@ -58,6 +55,9 @@
 import com.oracle.graal.lir.phases.LIRSuites;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.spi.Replacements;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.OptimisticOptimizations.Optimization;
@@ -137,10 +137,10 @@
             // all code after the OSR loop is never executed.
             optimisticOpts.remove(Optimization.RemoveNeverExecutedCode);
         }
-        CompilationResult result = GraalCompiler.compileGraph(graph, cc, method, providers, backend, getGraphBuilderSuite(providers, isOSR), optimisticOpts, profilingInfo, suites, lirSuites,
-                        new CompilationResult(), CompilationResultBuilderFactory.Default);
-
+        CompilationResult result = new CompilationResult();
         result.setEntryBCI(entryBCI);
+        GraalCompiler.compileGraph(graph, cc, method, providers, backend, getGraphBuilderSuite(providers, isOSR), optimisticOpts, profilingInfo, suites, lirSuites, result,
+                        CompilationResultBuilderFactory.Default);
 
         if (!isOSR) {
             ProfilingInfo profile = method.getProfilingInfo();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotInstructionProfiling.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotInstructionProfiling.java	Tue Dec 08 12:30:15 2015 -0800
@@ -54,7 +54,8 @@
 
     @Override
     protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
-                    BenchmarkCounterFactory counterFactory) {
+                    PostAllocationOptimizationContext context) {
+        BenchmarkCounterFactory counterFactory = context.counterFactory;
         new Analyzer(target, lirGenRes.getCompilationUnitName(), lirGenRes.getLIR(), counterFactory).run();
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Tue Dec 08 12:30:15 2015 -0800
@@ -63,6 +63,7 @@
 import com.oracle.graal.graph.NodeInputList;
 import com.oracle.graal.hotspot.HotSpotGraalRuntimeProvider;
 import com.oracle.graal.hotspot.nodes.CompressionNode;
+import com.oracle.graal.hotspot.nodes.CompressionNode.CompressionOp;
 import com.oracle.graal.hotspot.nodes.ComputeObjectAddressNode;
 import com.oracle.graal.hotspot.nodes.G1ArrayRangePostWriteBarrier;
 import com.oracle.graal.hotspot.nodes.G1ArrayRangePreWriteBarrier;
@@ -101,6 +102,7 @@
 import com.oracle.graal.nodes.Invoke;
 import com.oracle.graal.nodes.LoweredCallTargetNode;
 import com.oracle.graal.nodes.ParameterNode;
+import com.oracle.graal.nodes.PiNode;
 import com.oracle.graal.nodes.SafepointNode;
 import com.oracle.graal.nodes.StartNode;
 import com.oracle.graal.nodes.StructuredGraph;
@@ -362,10 +364,11 @@
             MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
             NodeInputList<ValueNode> parameters = callTarget.arguments();
             ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
-            GuardingNode receiverNullCheck = null;
             if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !StampTool.isPointerNonNull(receiver)) {
-                receiverNullCheck = createNullCheck(receiver, invoke.asNode(), tool);
-                invoke.setGuard(receiverNullCheck);
+                GuardingNode receiverNullCheck = createNullCheck(receiver, invoke.asNode(), tool);
+                PiNode nonNullReceiver = graph.unique(new PiNode(receiver, ((ObjectStamp) receiver.stamp()).join(StampFactory.objectNonNull()), (ValueNode) receiverNullCheck));
+                parameters.set(0, nonNullReceiver);
+                receiver = nonNullReceiver;
             }
             JavaType[] signature = callTarget.targetMethod().getSignature().toParameterTypes(callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
 
@@ -375,7 +378,7 @@
                 ResolvedJavaType receiverType = invoke.getReceiverType();
                 if (hsMethod.isInVirtualMethodTable(receiverType)) {
                     JavaKind wordKind = runtime.getTarget().wordJavaKind;
-                    ValueNode hub = createReadHub(graph, receiver, receiverNullCheck, tool);
+                    ValueNode hub = createReadHub(graph, receiver, tool);
 
                     ReadNode metaspaceMethod = createReadVirtualMethod(graph, hub, hsMethod, receiverType);
                     // We use LocationNode.ANY_LOCATION for the reads that access the
@@ -410,11 +413,11 @@
     }
 
     @Override
-    protected ValueNode implicitLoadConvert(StructuredGraph graph, JavaKind kind, ValueNode value, boolean compressible) {
+    protected ValueNode implicitLoadConvert(JavaKind kind, ValueNode value, boolean compressible) {
         if (kind == JavaKind.Object && compressible && config().useCompressedOops) {
-            return CompressionNode.uncompress(value, config().getOopEncoding());
+            return new CompressionNode(CompressionOp.Uncompress, value, config().getOopEncoding());
         }
-        return super.implicitLoadConvert(graph, kind, value, compressible);
+        return super.implicitLoadConvert(kind, value, compressible);
     }
 
     @Override
@@ -425,11 +428,11 @@
     }
 
     @Override
-    protected ValueNode implicitStoreConvert(StructuredGraph graph, JavaKind kind, ValueNode value, boolean compressible) {
+    protected ValueNode implicitStoreConvert(JavaKind kind, ValueNode value, boolean compressible) {
         if (kind == JavaKind.Object && compressible && config().useCompressedOops) {
-            return CompressionNode.compress(value, config().getOopEncoding());
+            return new CompressionNode(CompressionOp.Compress, value, config().getOopEncoding());
         }
-        return super.implicitStoreConvert(graph, kind, value, compressible);
+        return super.implicitStoreConvert(kind, value, compressible);
     }
 
     @Override
@@ -584,9 +587,9 @@
     }
 
     @Override
-    protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, GuardingNode guard, LoweringTool tool) {
+    protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, LoweringTool tool) {
         if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
-            return graph.unique(new LoadHubNode(tool.getStampProvider(), object, guard != null ? guard.asNode() : null));
+            return graph.unique(new LoadHubNode(tool.getStampProvider(), object));
         }
         assert !object.isConstant() || object.isNullConstant();
 
@@ -596,7 +599,7 @@
         }
 
         AddressNode address = createOffsetAddress(graph, object, config().hubOffset);
-        FloatingReadNode memoryRead = graph.unique(new FloatingReadNode(address, HUB_LOCATION, null, hubStamp, guard, BarrierType.NONE));
+        FloatingReadNode memoryRead = graph.unique(new FloatingReadNode(address, HUB_LOCATION, null, hubStamp, null, BarrierType.NONE));
         if (config().useCompressedClassPointers) {
             return CompressionNode.uncompress(memoryRead, config().getKlassEncoding());
         } else {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotForeignCallsProviderImpl.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotForeignCallsProviderImpl.java	Tue Dec 08 12:30:15 2015 -0800
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.meta;
 
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS;
-import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.NOT_LEAF;
+import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.SAFEPOINT;
 import static jdk.vm.ci.code.CallingConvention.Type.JavaCall;
 import static jdk.vm.ci.code.CallingConvention.Type.JavaCallee;
 
@@ -113,7 +113,7 @@
                     boolean reexecutable, LocationIdentity... killedLocations) {
         Class<?> resultType = descriptor.getResultType();
         assert address != 0;
-        assert transition != NOT_LEAF || resultType.isPrimitive() || Word.class.isAssignableFrom(resultType) : "non-leaf foreign calls must return objects in thread local storage: " + descriptor;
+        assert transition != SAFEPOINT || resultType.isPrimitive() || Word.class.isAssignableFrom(resultType) : "non-leaf foreign calls must return objects in thread local storage: " + descriptor;
         return register(HotSpotForeignCallLinkageImpl.create(metaAccess, codeCache, this, descriptor, address, effect, outgoingCcType, null, transition, reexecutable, killedLocations));
     }
 
@@ -166,6 +166,11 @@
         return foreignCalls.get(descriptor).needsDebugInfo();
     }
 
+    public boolean isGuaranteedSafepoint(ForeignCallDescriptor descriptor) {
+        assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor;
+        return foreignCalls.get(descriptor).isGuaranteedSafepoint();
+    }
+
     public LocationIdentity[] getKilledLocations(ForeignCallDescriptor descriptor) {
         assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor;
         return foreignCalls.get(descriptor).getKilledLocations();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -39,18 +39,11 @@
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.options.StableOptionValue;
+import jdk.vm.ci.service.Services;
 import sun.reflect.Reflection;
 
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
 import com.oracle.graal.compiler.common.spi.ForeignCallsProvider;
-import com.oracle.graal.graphbuilderconf.ForeignCallPlugin;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin.Receiver;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
-import com.oracle.graal.graphbuilderconf.MethodSubstitutionPlugin;
 import com.oracle.graal.hotspot.nodes.ClassCastNode;
 import com.oracle.graal.hotspot.nodes.CurrentJavaThreadNode;
 import com.oracle.graal.hotspot.replacements.AESCryptSubstitutions;
@@ -68,6 +61,15 @@
 import com.oracle.graal.nodes.ConstantNode;
 import com.oracle.graal.nodes.PiNode;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.graphbuilderconf.ForeignCallPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin.Receiver;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import com.oracle.graal.nodes.graphbuilderconf.MethodSubstitutionPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
 import com.oracle.graal.nodes.memory.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.memory.address.AddressNode;
 import com.oracle.graal.nodes.memory.address.OffsetAddressNode;
@@ -75,7 +77,7 @@
 import com.oracle.graal.nodes.util.GraphUtil;
 import com.oracle.graal.replacements.InlineDuringParsingPlugin;
 import com.oracle.graal.replacements.MethodHandlePlugin;
-import com.oracle.graal.replacements.NodeIntrinsificationPhase;
+import com.oracle.graal.replacements.NodeIntrinsificationProvider;
 import com.oracle.graal.replacements.NodeIntrinsificationPlugin;
 import com.oracle.graal.replacements.ReplacementsImpl;
 import com.oracle.graal.replacements.StandardGraphBuilderPlugins;
@@ -100,8 +102,8 @@
         InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess);
 
         Plugins plugins = new Plugins(invocationPlugins);
-        NodeIntrinsificationPhase nodeIntrinsificationPhase = new NodeIntrinsificationPhase(metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider);
-        NodeIntrinsificationPlugin nodeIntrinsificationPlugin = new NodeIntrinsificationPlugin(metaAccess, nodeIntrinsificationPhase, wordTypes, false);
+        NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, wordTypes);
+        NodeIntrinsificationPlugin nodeIntrinsificationPlugin = new NodeIntrinsificationPlugin();
         HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes);
         HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(wordOperationPlugin, nodeIntrinsificationPlugin);
 
@@ -114,17 +116,26 @@
             plugins.appendInlineInvokePlugin(new InlineDuringParsingPlugin());
         }
 
-        registerObjectPlugins(invocationPlugins);
-        registerClassPlugins(plugins);
-        registerSystemPlugins(invocationPlugins, foreignCalls);
-        registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config);
-        registerCallSitePlugins(invocationPlugins);
-        registerReflectionPlugins(invocationPlugins);
-        registerStableOptionPlugins(invocationPlugins, snippetReflection);
-        registerAESPlugins(invocationPlugins, config);
-        registerCRC32Plugins(invocationPlugins, config);
-        StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, invocationPlugins, true);
+        invocationPlugins.defer(new Runnable() {
 
+            public void run() {
+                registerObjectPlugins(invocationPlugins);
+                registerClassPlugins(plugins);
+                registerSystemPlugins(invocationPlugins, foreignCalls);
+                registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config);
+                registerCallSitePlugins(invocationPlugins);
+                registerReflectionPlugins(invocationPlugins);
+                registerStableOptionPlugins(invocationPlugins, snippetReflection);
+                registerAESPlugins(invocationPlugins, config);
+                registerCRC32Plugins(invocationPlugins, config);
+                StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, invocationPlugins, true);
+
+                for (NodeIntrinsicPluginFactory factory : Services.load(NodeIntrinsicPluginFactory.class)) {
+                    factory.registerPlugin(invocationPlugins, nodeIntrinsificationProvider);
+                }
+
+            }
+        });
         return plugins;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Tue Dec 08 12:30:15 2015 -0800
@@ -50,7 +50,7 @@
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.LEAF;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.LEAF_NOFP;
-import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.NOT_LEAF;
+import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.SAFEPOINT;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.STACK_INSPECTABLE_LEAF;
 import static com.oracle.graal.hotspot.HotSpotHostBackend.DEOPTIMIZATION_HANDLER;
 import static com.oracle.graal.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
@@ -234,12 +234,12 @@
         registerForeignCall(ARITHMETIC_POW, c.arithmeticPowAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(LOAD_AND_CLEAR_EXCEPTION, c.loadAndClearExceptionAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, any());
 
-        registerForeignCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any());
-        registerForeignCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, c.exceptionHandlerForReturnAddressAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any());
-        registerForeignCall(FETCH_UNROLL_INFO, c.deoptimizationFetchUnrollInfo, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any());
-        registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any());
-        registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any());
-        registerForeignCall(UNCOMMON_TRAP, c.deoptimizationUncommonTrap, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, NOT_REEXECUTABLE, any());
+        registerForeignCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any());
+        registerForeignCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, c.exceptionHandlerForReturnAddressAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any());
+        registerForeignCall(FETCH_UNROLL_INFO, c.deoptimizationFetchUnrollInfo, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any());
+        registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any());
+        registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, any());
+        registerForeignCall(UNCOMMON_TRAP, c.deoptimizationUncommonTrap, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, NOT_REEXECUTABLE, any());
 
         /*
          * We cannot use LEAF_SP here because on some architectures we have to align the stack
@@ -252,24 +252,24 @@
          * This message call is registered twice, where the second one must only be used for calls
          * that do not return, i.e., that exit the VM.
          */
-        registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS);
+        registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, SAFEPOINT, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(ASSERTION_VM_MESSAGE_C, c.vmMessageAddress, NativeCall, PRESERVES_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
 
-        link(new NewInstanceStub(providers, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION)));
-        link(new NewArrayStub(providers, registerStubCall(NEW_ARRAY, REEXECUTABLE, NOT_LEAF, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION)));
+        link(new NewInstanceStub(providers, registerStubCall(NEW_INSTANCE, REEXECUTABLE, SAFEPOINT, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION)));
+        link(new NewArrayStub(providers, registerStubCall(NEW_ARRAY, REEXECUTABLE, SAFEPOINT, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION)));
         link(new ExceptionHandlerStub(providers, foreignCalls.get(EXCEPTION_HANDLER)));
-        link(new UnwindExceptionToCallerStub(providers, registerStubCall(UNWIND_EXCEPTION_TO_CALLER, NOT_REEXECUTABLE, NOT_LEAF, any())));
+        link(new UnwindExceptionToCallerStub(providers, registerStubCall(UNWIND_EXCEPTION_TO_CALLER, NOT_REEXECUTABLE, SAFEPOINT, any())));
         link(new VerifyOopStub(providers, registerStubCall(VERIFY_OOP, REEXECUTABLE, LEAF_NOFP, NO_LOCATIONS)));
 
-        linkForeignCall(providers, IDENTITY_HASHCODE, c.identityHashCodeAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, MARK_WORD_LOCATION);
-        linkForeignCall(providers, REGISTER_FINALIZER, c.registerFinalizerAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, any());
-        linkForeignCall(providers, CREATE_NULL_POINTER_EXCEPTION, c.createNullPointerExceptionAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, any());
-        linkForeignCall(providers, CREATE_OUT_OF_BOUNDS_EXCEPTION, c.createOutOfBoundsExceptionAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, any());
-        linkForeignCall(providers, MONITORENTER, c.monitorenterAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, any());
+        linkForeignCall(providers, IDENTITY_HASHCODE, c.identityHashCodeAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, MARK_WORD_LOCATION);
+        linkForeignCall(providers, REGISTER_FINALIZER, c.registerFinalizerAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any());
+        linkForeignCall(providers, CREATE_NULL_POINTER_EXCEPTION, c.createNullPointerExceptionAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any());
+        linkForeignCall(providers, CREATE_OUT_OF_BOUNDS_EXCEPTION, c.createOutOfBoundsExceptionAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any());
+        linkForeignCall(providers, MONITORENTER, c.monitorenterAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any());
         linkForeignCall(providers, MONITOREXIT, c.monitorexitAddress, PREPEND_THREAD, STACK_INSPECTABLE_LEAF, NOT_REEXECUTABLE, any());
-        linkForeignCall(providers, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
-        linkForeignCall(providers, DYNAMIC_NEW_ARRAY, c.dynamicNewArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION);
-        linkForeignCall(providers, DYNAMIC_NEW_INSTANCE, c.dynamicNewInstanceAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION);
+        linkForeignCall(providers, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
+        linkForeignCall(providers, DYNAMIC_NEW_ARRAY, c.dynamicNewArrayAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, INIT_LOCATION);
+        linkForeignCall(providers, DYNAMIC_NEW_INSTANCE, c.dynamicNewInstanceAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, INIT_LOCATION);
         linkForeignCall(providers, LOG_PRINTF, c.logPrintfAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(providers, LOG_OBJECT, c.logObjectAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(providers, LOG_PRIMITIVE, c.logPrimitiveAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
@@ -280,9 +280,9 @@
         linkForeignCall(providers, VALIDATE_OBJECT, c.validateObject, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
 
         // Cannot be a leaf as VM acquires Thread_lock which requires thread_in_vm state
-        linkForeignCall(providers, THREAD_IS_INTERRUPTED, c.threadIsInterruptedAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, any());
+        linkForeignCall(providers, THREAD_IS_INTERRUPTED, c.threadIsInterruptedAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any());
 
-        linkForeignCall(providers, TEST_DEOPTIMIZE_CALL_INT, c.testDeoptimizeCallInt, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, any());
+        linkForeignCall(providers, TEST_DEOPTIMIZE_CALL_INT, c.testDeoptimizeCallInt, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any());
 
         registerArrayCopy(JavaKind.Byte, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy);
         registerArrayCopy(JavaKind.Boolean, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Tue Dec 08 12:30:15 2015 -0800
@@ -30,12 +30,12 @@
 import com.oracle.graal.compiler.common.GraalOptions;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.iterators.NodeIterable;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
 import com.oracle.graal.hotspot.phases.AheadOfTimeVerificationPhase;
 import com.oracle.graal.nodes.ConstantNode;
 import com.oracle.graal.nodes.FrameState;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
 import com.oracle.graal.nodes.type.StampTool;
 import com.oracle.graal.replacements.nodes.MacroNode;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNodePlugin.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNodePlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -34,13 +34,13 @@
 import com.oracle.graal.api.replacements.Fold;
 import com.oracle.graal.compiler.common.type.Stamp;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InlineInvokePlugin;
-import com.oracle.graal.graphbuilderconf.NodePlugin;
-import com.oracle.graal.graphbuilderconf.ParameterPlugin;
 import com.oracle.graal.nodes.ConstantNode;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.calc.FloatingNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InlineInvokePlugin;
+import com.oracle.graal.nodes.graphbuilderconf.NodePlugin;
+import com.oracle.graal.nodes.graphbuilderconf.ParameterPlugin;
 import com.oracle.graal.replacements.NodeIntrinsificationPlugin;
 import com.oracle.graal.replacements.WordOperationPlugin;
 import com.oracle.graal.word.Word;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProviders.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProviders.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -27,8 +27,8 @@
 import jdk.vm.ci.meta.MetaAccessProvider;
 
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.hotspot.word.HotSpotWordTypes;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.spi.LoweringProvider;
 import com.oracle.graal.nodes.spi.Replacements;
 import com.oracle.graal.phases.tiers.SuitesProvider;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSnippetReflectionProvider.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSnippetReflectionProvider.java	Tue Dec 08 12:30:15 2015 -0800
@@ -28,20 +28,22 @@
 import jdk.vm.ci.hotspot.HotSpotVMConfig;
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
 import com.oracle.graal.hotspot.HotSpotGraalRuntimeProvider;
+import com.oracle.graal.word.WordTypes;
 
 public class HotSpotSnippetReflectionProvider implements SnippetReflectionProvider {
 
     private final HotSpotGraalRuntimeProvider runtime;
     private final HotSpotConstantReflectionProvider constantReflection;
+    private final WordTypes wordTypes;
 
-    public HotSpotSnippetReflectionProvider(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection) {
+    public HotSpotSnippetReflectionProvider(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) {
         this.runtime = runtime;
         this.constantReflection = constantReflection;
+        this.wordTypes = wordTypes;
     }
 
     @Override
@@ -88,29 +90,28 @@
     }
 
     // Lazily initialized
-    private ResolvedJavaType wordTypesType;
-    private ResolvedJavaType runtimeType;
-    private ResolvedJavaType configType;
+    private Class<?> wordTypesType;
+    private Class<?> runtimeType;
+    private Class<?> configType;
 
-    public Object getInjectedNodeIntrinsicParameter(ResolvedJavaType type) {
+    public <T> T getInjectedNodeIntrinsicParameter(Class<T> type) {
         // Need to test all fields since there no guarantee under the JMM
         // about the order in which these fields are written.
         HotSpotVMConfig config = config();
         if (configType == null || wordTypesType == null || configType == null) {
-            MetaAccessProvider metaAccess = runtime.getHostProviders().getMetaAccess();
-            wordTypesType = metaAccess.lookupJavaType(runtime.getHostProviders().getWordTypes().getClass());
-            runtimeType = metaAccess.lookupJavaType(runtime.getClass());
-            configType = metaAccess.lookupJavaType(config.getClass());
+            wordTypesType = wordTypes.getClass();
+            runtimeType = runtime.getClass();
+            configType = config.getClass();
         }
 
         if (type.isAssignableFrom(wordTypesType)) {
-            return runtime.getHostProviders().getWordTypes();
+            return type.cast(wordTypes);
         }
         if (type.isAssignableFrom(runtimeType)) {
-            return runtime;
+            return type.cast(runtime);
         }
         if (type.isAssignableFrom(configType)) {
-            return config;
+            return type.cast(config);
         }
         return null;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Tue Dec 08 12:30:15 2015 -0800
@@ -28,8 +28,6 @@
 import jdk.vm.ci.options.DerivedOptionValue;
 import jdk.vm.ci.options.DerivedOptionValue.OptionSupplier;
 
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.DebugInfoMode;
 import com.oracle.graal.hotspot.HotSpotBackend;
 import com.oracle.graal.hotspot.HotSpotGraalRuntimeProvider;
 import com.oracle.graal.hotspot.HotSpotInstructionProfiling;
@@ -44,6 +42,8 @@
 import com.oracle.graal.nodes.SimplifyingGraphDecoder;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.DebugInfoMode;
 import com.oracle.graal.phases.BasePhase;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.common.AddressLoweringPhase;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -35,7 +35,6 @@
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
 import com.oracle.graal.compiler.common.type.Stamp;
 import com.oracle.graal.compiler.common.type.StampFactory;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
 import com.oracle.graal.hotspot.nodes.LoadIndexedPointerNode;
 import com.oracle.graal.hotspot.nodes.type.KlassPointerStamp;
 import com.oracle.graal.hotspot.nodes.type.MetaspacePointerStamp;
@@ -48,6 +47,7 @@
 import com.oracle.graal.nodes.calc.ConditionalNode;
 import com.oracle.graal.nodes.calc.IsNullNode;
 import com.oracle.graal.nodes.calc.PointerEqualsNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
 import com.oracle.graal.nodes.java.LoadIndexedNode;
 import com.oracle.graal.nodes.memory.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.memory.ReadNode;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AcquiredCASLockNode.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, 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.hotspot.nodes;
+
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.nodeinfo.NodeInfo;
+import com.oracle.graal.nodes.FixedWithNextNode;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.spi.LIRLowerable;
+import com.oracle.graal.nodes.spi.NodeLIRBuilderTool;
+
+/**
+ * Marks the control flow path where an object acquired a lightweight lock based on an atomic
+ * compare-and-swap (CAS) of the mark word in the object's header.
+ */
+@NodeInfo
+public final class AcquiredCASLockNode extends FixedWithNextNode implements LIRLowerable {
+    public static final NodeClass<AcquiredCASLockNode> TYPE = NodeClass.create(AcquiredCASLockNode.class);
+
+    @Input ValueNode object;
+
+    public AcquiredCASLockNode(ValueNode object) {
+        super(TYPE, StampFactory.forVoid());
+        this.object = object;
+    }
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public void generate(NodeLIRBuilderTool generator) {
+        // This is just a marker node so it generates nothing
+    }
+
+    @NodeIntrinsic
+    public static native void mark(Object object);
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java	Tue Dec 08 12:30:15 2015 -0800
@@ -48,7 +48,7 @@
      * Gets the address of {@code StubRoutines::x86::_crc_table} in {@code stubRoutines_x86.hpp}.
      */
     @Fold
-    private static long crcTableAddress() {
+    static long crcTableAddress() {
         return config().crcTableAddress;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastDynamicSnippets.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastDynamicSnippets.java	Tue Dec 08 12:30:15 2015 -0800
@@ -41,6 +41,7 @@
 import com.oracle.graal.hotspot.nodes.SnippetAnchorNode;
 import com.oracle.graal.hotspot.word.KlassPointer;
 import com.oracle.graal.nodes.DeoptimizeNode;
+import com.oracle.graal.nodes.PiNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.extended.GuardingNode;
@@ -64,7 +65,7 @@
             isNull.inc();
         } else {
             GuardingNode anchorNode = SnippetAnchorNode.anchor();
-            KlassPointer objectHub = loadHubIntrinsic(object, anchorNode);
+            KlassPointer objectHub = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode));
             if (!checkUnknownSubType(hub, objectHub)) {
                 DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException);
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Tue Dec 08 12:30:15 2015 -0800
@@ -71,7 +71,7 @@
     }
 
     @Fold
-    private static Class<?> getAESCryptClass() {
+    static Class<?> getAESCryptClass() {
         return AESCryptSubstitutions.AESCryptClass;
     }
 
@@ -79,7 +79,7 @@
         Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
         Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
         if (getAESCryptClass().isInstance(embeddedCipher)) {
-            Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
+            Object aesCipher = getAESCryptClass().cast(embeddedCipher);
             crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true, false);
             return inLength;
         } else {
@@ -91,7 +91,7 @@
         Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
         Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
         if (getAESCryptClass().isInstance(embeddedCipher)) {
-            Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
+            Object aesCipher = getAESCryptClass().cast(embeddedCipher);
             crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true, false);
             return inLength;
         } else {
@@ -103,7 +103,7 @@
         Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
         Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
         if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
-            Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
+            Object aesCipher = getAESCryptClass().cast(embeddedCipher);
             crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, false);
             return inLength;
         } else {
@@ -115,7 +115,7 @@
         Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
         Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
         if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
-            Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
+            Object aesCipher = getAESCryptClass().cast(embeddedCipher);
             crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, false);
             return inLength;
         } else {
@@ -131,7 +131,7 @@
         Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
         Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
         if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
-            Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
+            Object aesCipher = getAESCryptClass().cast(embeddedCipher);
             crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, true);
             return inLength;
         } else {
@@ -146,7 +146,7 @@
         Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
         Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
         if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
-            Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
+            Object aesCipher = getAESCryptClass().cast(embeddedCipher);
             crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, true);
             return inLength;
         } else {
@@ -157,7 +157,7 @@
     private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt, boolean withOriginalKey) {
         AESCryptSubstitutions.checkArgs(in, inOffset, out, outOffset);
         Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
-        Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
+        Object aesCipher = getAESCryptClass().cast(embeddedCipher);
         Object kObject = UnsafeLoadNode.load(aesCipher, AESCryptSubstitutions.kOffset, JavaKind.Object, LocationIdentity.any());
         Object rObject = UnsafeLoadNode.load(realReceiver, rOffset, JavaKind.Object, LocationIdentity.any());
         Pointer kAddr = Word.objectToTrackedPointer(kObject).add(getArrayBaseOffset(JavaKind.Int));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassGetHubNode.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassGetHubNode.java	Tue Dec 08 12:30:15 2015 -0800
@@ -91,7 +91,7 @@
             }
             if (clazz instanceof GetClassNode) {
                 GetClassNode getClass = (GetClassNode) clazz;
-                return new LoadHubNode(KlassPointerStamp.klassNonNull(), getClass.getObject(), null);
+                return new LoadHubNode(KlassPointerStamp.klassNonNull(), getClass.getObject());
             }
             if (clazz instanceof HubGetClassNode) {
                 // replace _klass._java_mirror._klass -> _klass
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Tue Dec 08 12:30:15 2015 -0800
@@ -195,14 +195,14 @@
     public static final LocationIdentity TLAB_END_LOCATION = NamedLocationIdentity.mutable("TlabEnd");
 
     @Fold
-    private static int threadTlabEndOffset() {
+    static int threadTlabEndOffset() {
         return config().threadTlabEndOffset();
     }
 
     public static final LocationIdentity TLAB_START_LOCATION = NamedLocationIdentity.mutable("TlabStart");
 
     @Fold
-    private static int threadTlabStartOffset() {
+    static int threadTlabStartOffset() {
         return config().threadTlabStartOffset();
     }
 
@@ -212,7 +212,7 @@
      * @see HotSpotVMConfig#pendingExceptionOffset
      */
     @Fold
-    private static int threadPendingExceptionOffset() {
+    static int threadPendingExceptionOffset() {
         return config().pendingExceptionOffset;
     }
 
@@ -222,14 +222,14 @@
      * @see HotSpotVMConfig#pendingDeoptimizationOffset
      */
     @Fold
-    private static int threadPendingDeoptimizationOffset() {
+    static int threadPendingDeoptimizationOffset() {
         return config().pendingDeoptimizationOffset;
     }
 
     public static final LocationIdentity OBJECT_RESULT_LOCATION = NamedLocationIdentity.mutable("ObjectResult");
 
     @Fold
-    private static int objectResultOffset() {
+    static int objectResultOffset() {
         return config().threadObjectResultOffset;
     }
 
@@ -503,7 +503,7 @@
     };
 
     @Fold
-    private static int hubOffset() {
+    static int hubOffset() {
         return config().hubOffset;
     }
 
@@ -750,9 +750,6 @@
     private static native KlassPointer loadKlassFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter JavaKind wordKind, @ConstantNodeParameter LocationIdentity locationIdentity);
 
     @NodeIntrinsic(value = LoadHubNode.class)
-    public static native KlassPointer loadHubIntrinsic(Object object, GuardingNode anchor);
-
-    @NodeIntrinsic(value = LoadHubNode.class)
     public static native KlassPointer loadHubIntrinsic(Object object);
 
     @Fold
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Tue Dec 08 12:30:15 2015 -0800
@@ -60,6 +60,7 @@
 import com.oracle.graal.hotspot.word.KlassPointer;
 import com.oracle.graal.nodes.ConstantNode;
 import com.oracle.graal.nodes.DeoptimizeNode;
+import com.oracle.graal.nodes.PiNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.TypeCheckHints;
 import com.oracle.graal.nodes.ValueNode;
@@ -106,7 +107,7 @@
             return falseValue;
         }
         GuardingNode anchorNode = SnippetAnchorNode.anchor();
-        KlassPointer objectHub = loadHubIntrinsic(object, anchorNode);
+        KlassPointer objectHub = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode));
         // if we get an exact match: succeed immediately
         ExplodeLoopNode.explodeLoop();
         for (int i = 0; i < hints.length; i++) {
@@ -136,7 +137,7 @@
             return falseValue;
         }
         GuardingNode anchorNode = SnippetAnchorNode.anchor();
-        KlassPointer objectHub = loadHubIntrinsic(object, anchorNode);
+        KlassPointer objectHub = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode));
         if (probability(LIKELY_PROBABILITY, objectHub.notEqual(exactHub))) {
             exactMiss.inc();
             return falseValue;
@@ -155,7 +156,7 @@
             return falseValue;
         }
         GuardingNode anchorNode = SnippetAnchorNode.anchor();
-        KlassPointer objectHub = loadHubIntrinsic(object, anchorNode);
+        KlassPointer objectHub = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode));
         if (probability(NOT_LIKELY_PROBABILITY, objectHub.readKlassPointer(superCheckOffset, PRIMARY_SUPERS_LOCATION).notEqual(hub))) {
             displayMiss.inc();
             return falseValue;
@@ -174,7 +175,7 @@
             return falseValue;
         }
         GuardingNode anchorNode = SnippetAnchorNode.anchor();
-        KlassPointer objectHub = loadHubIntrinsic(object, anchorNode);
+        KlassPointer objectHub = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode));
         // if we get an exact match: succeed immediately
         ExplodeLoopNode.explodeLoop();
         for (int i = 0; i < hints.length; i++) {
@@ -203,7 +204,7 @@
         }
         GuardingNode anchorNode = SnippetAnchorNode.anchor();
         KlassPointer hub = ClassGetHubNode.readClass(mirror, anchorNode);
-        KlassPointer objectHub = loadHubIntrinsic(object, anchorNode);
+        KlassPointer objectHub = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode));
         if (hub.isNull() || !checkUnknownSubType(hub, objectHub)) {
             return falseValue;
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Tue Dec 08 12:30:15 2015 -0800
@@ -46,7 +46,6 @@
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.verifyOop;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY;
-import static com.oracle.graal.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.VERY_FAST_PATH_PROBABILITY;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.VERY_SLOW_PATH_PROBABILITY;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.probability;
@@ -75,6 +74,7 @@
 import com.oracle.graal.graph.iterators.NodeIterable;
 import com.oracle.graal.hotspot.meta.HotSpotProviders;
 import com.oracle.graal.hotspot.meta.HotSpotRegistersProvider;
+import com.oracle.graal.hotspot.nodes.AcquiredCASLockNode;
 import com.oracle.graal.hotspot.nodes.CurrentLockNode;
 import com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode;
 import com.oracle.graal.hotspot.nodes.FastAcquireBiasedLockNode;
@@ -91,6 +91,7 @@
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.debug.DynamicCounterNode;
+import com.oracle.graal.nodes.extended.BranchProbabilityNode;
 import com.oracle.graal.nodes.extended.ForeignCallNode;
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
 import com.oracle.graal.nodes.java.MonitorExitNode;
@@ -128,25 +129,25 @@
  *             JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)
  *             size:32 ------------------------------------------>| (CMS free block)
  *             PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
- *
+ * 
  *  64 bits:
  *  --------
  *  unused:25 hash:31 -->| unused:1   age:4    biased_lock:1 lock:2 (normal object)
  *  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)
  *  PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
  *  size:64 ----------------------------------------------------->| (CMS free block)
- *
+ * 
  *  unused:25 hash:31 -->| cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && normal object)
  *  JavaThread*:54 epoch:2 cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && biased object)
  *  narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
  *  unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)
- *
+ * 
  *  - hash contains the identity hash value: largest value is
  *    31 bits, see os::random().  Also, 64-bit vm's require
  *    a hash value no bigger than 32 bits because they will not
  *    properly generate a mask larger than that: see library_call.cpp
  *    and c1_CodePatterns_sparc.cpp.
- *
+ * 
  *  - the biased lock pattern is used to bias a lock toward a given
  *    thread. When this pattern is set in the low three bits, the lock
  *    is either biased toward a given thread or "anonymously" biased,
@@ -155,12 +156,12 @@
  *    be performed by that thread without using atomic operations.
  *    When a lock's bias is revoked, it reverts back to the normal
  *    locking scheme described below.
- *
+ * 
  *    Note that we are overloading the meaning of the "unlocked" state
  *    of the header. Because we steal a bit from the age we can
  *    guarantee that the bias pattern will never be seen for a truly
  *    unlocked object.
- *
+ * 
  *    Note also that the biased state contains the age bits normally
  *    contained in the object header. Large increases in scavenge
  *    times were seen when these bits were absent and an arbitrary age
@@ -171,18 +172,18 @@
  *    a very large value (currently 128 bytes (32bVM) or 256 bytes (64bVM))
  *    to make room for the age bits & the epoch bits (used in support of
  *    biased locking), and for the CMS "freeness" bit in the 64bVM (+COOPs).
- *
+ * 
  *    [JavaThread* | epoch | age | 1 | 01]       lock is biased toward given thread
  *    [0           | epoch | age | 1 | 01]       lock is anonymously biased
- *
+ * 
  *  - the two lock bits are used to describe three states: locked/unlocked and monitor.
- *
+ * 
  *    [ptr             | 00]  locked             ptr points to real header on stack
  *    [header      | 0 | 01]  unlocked           regular object header
  *    [ptr             | 10]  monitor            inflated lock (header is wapped out)
  *    [ptr             | 11]  marked             used by markSweep to mark an object
  *                                               not valid at any other time
- *
+ * 
  *    We assume that stack/thread pointers have the lowest two bits cleared.
  * </pre>
  *
@@ -202,7 +203,7 @@
     private static final boolean PROFILE_CONTEXT = false;
 
     @Fold
-    private static boolean doProfile() {
+    static boolean doProfile() {
         return Options.ProfileMonitors.getValue();
     }
 
@@ -250,7 +251,7 @@
             trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord);
             trace(trace, "           thread: 0x%016lx\n", thread);
             trace(trace, "              tmp: 0x%016lx\n", tmp);
-            if (probability(FREQUENT_PROBABILITY, tmp.equal(0))) {
+            if (probability(BranchProbabilityNode.NOT_LIKELY_PROBABILITY, tmp.equal(0))) {
                 // Object is already biased to current thread -> done
                 traceObject(trace, "+lock{bias:existing}", object, true);
                 lockBiasExisting.inc();
@@ -259,7 +260,7 @@
             }
 
             // Now check to see whether biasing is enabled for this object
-            if (probability(NOT_FREQUENT_PROBABILITY, biasableLockBits.notEqual(Word.unsigned(biasedLockPattern())))) {
+            if (probability(BranchProbabilityNode.FAST_PATH_PROBABILITY, biasableLockBits.notEqual(Word.unsigned(biasedLockPattern())))) {
                 // Biasing not enabled -> fall through to lightweight locking
                 unbiasable.inc();
             } else {
@@ -360,7 +361,7 @@
         // Test if the object's mark word is unlocked, and if so, store the
         // (address of) the lock slot into the object's mark word.
         Word currentMark = compareAndSwap(OffsetAddressNode.address(object, markOffset()), unlockedMark, lock, MARK_WORD_LOCATION);
-        if (currentMark.notEqual(unlockedMark)) {
+        if (probability(BranchProbabilityNode.SLOW_PATH_PROBABILITY, currentMark.notEqual(unlockedMark))) {
             trace(trace, "      currentMark: 0x%016lx\n", currentMark);
             // The mark word in the object header was not the same.
             // Either the object is locked by another thread or is already locked
@@ -394,6 +395,7 @@
         } else {
             traceObject(trace, "+lock{cas}", object, true);
             lockCas.inc();
+            AcquiredCASLockNode.mark(object);
         }
     }
 
@@ -426,7 +428,7 @@
             // the bias bit would be clear.
             final Word mark = loadWordFromObject(object, markOffset());
             trace(trace, "             mark: 0x%016lx\n", mark);
-            if (probability(FREQUENT_PROBABILITY, mark.and(biasedLockMaskInPlace()).equal(Word.unsigned(biasedLockPattern())))) {
+            if (probability(BranchProbabilityNode.NOT_LIKELY_PROBABILITY, mark.and(biasedLockMaskInPlace()).equal(Word.unsigned(biasedLockPattern())))) {
                 endLockScope();
                 decCounter();
                 traceObject(trace, "-lock{bias}", object, false);
@@ -441,7 +443,7 @@
         final Word displacedMark = lock.readWord(lockDisplacedMarkOffset(), DISPLACED_MARK_WORD_LOCATION);
         trace(trace, "    displacedMark: 0x%016lx\n", displacedMark);
 
-        if (displacedMark.equal(0)) {
+        if (probability(BranchProbabilityNode.NOT_LIKELY_PROBABILITY, displacedMark.equal(0))) {
             // Recursive locking => done
             traceObject(trace, "-lock{recursive}", object, false);
             unlockCasRecursive.inc();
@@ -669,7 +671,7 @@
     private static native void monitorenterStubC(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object, Word lock);
 
     @NodeIntrinsic(ForeignCallNode.class)
-    private static native void monitorexitStubC(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object, Word lock);
+    public static native void monitorexitStubC(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object, Word lock);
 
     /**
      * Counters for the various paths for acquiring a lock. The counters whose names start with
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue Dec 08 12:30:15 2015 -0800
@@ -138,7 +138,7 @@
     public static final ProfileMode PROFILE_MODE = ProfileMode.AllocatedTypes;
 
     @Fold
-    private static String createName(String path, String typeContext) {
+    static String createName(String path, String typeContext) {
         switch (PROFILE_MODE) {
             case AllocatingMethods:
                 return "";
@@ -155,7 +155,7 @@
     }
 
     @Fold
-    private static boolean doProfile() {
+    static boolean doProfile() {
         return ProfileAllocations.getValue();
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/RuntimeStringSnippets.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/RuntimeStringSnippets.java	Tue Dec 08 12:30:15 2015 -0800
@@ -49,7 +49,7 @@
 public class RuntimeStringSnippets implements Snippets {
 
     @Fold
-    private static long valueOffset() {
+    static long valueOffset() {
         try {
             return UNSAFE.objectFieldOffset(String.class.getDeclaredField("value"));
         } catch (Exception e) {
@@ -58,7 +58,7 @@
     }
 
     @Fold
-    private static long hashOffset() {
+    static long hashOffset() {
         try {
             return UNSAFE.objectFieldOffset(String.class.getDeclaredField("hash"));
         } catch (Exception e) {
@@ -67,7 +67,7 @@
     }
 
     @Fold
-    private static long arrayBaseOffset() {
+    static long arrayBaseOffset() {
         return UNSAFE.arrayBaseOffset(char[].class);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Tue Dec 08 12:30:15 2015 -0800
@@ -62,6 +62,7 @@
 import com.oracle.graal.nodes.Invoke;
 import com.oracle.graal.nodes.InvokeNode;
 import com.oracle.graal.nodes.NamedLocationIdentity;
+import com.oracle.graal.nodes.PiNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.extended.UnsafeLoadNode;
@@ -173,8 +174,8 @@
     public static void arraycopyPredictedObjectWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, KlassPointer objectArrayKlass,
                     @ConstantParameter SnippetCounter counter, @ConstantParameter SnippetCounter copiedCounter) {
         if (length > 0) {
-            KlassPointer srcHub = loadHub(nonNullSrc);
-            KlassPointer destHub = loadHub(nonNullDest);
+            KlassPointer srcHub = loadHub(PiNode.asNonNullObject(nonNullSrc));
+            KlassPointer destHub = loadHub(PiNode.asNonNullObject(nonNullDest));
             if (probability(FAST_PATH_PROBABILITY, srcHub == destHub || destHub == objectArrayKlass)) {
                 counter.inc();
                 copiedCounter.add(length);
@@ -284,7 +285,7 @@
     }
 
     @Fold
-    private static LocationIdentity getArrayLocation(JavaKind kind) {
+    static LocationIdentity getArrayLocation(JavaKind kind) {
         return NamedLocationIdentity.getArrayLocation(kind);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java	Tue Dec 08 12:30:15 2015 -0800
@@ -144,7 +144,7 @@
     }
 
     @Fold
-    private static LocationIdentity getArrayLocation(JavaKind kind) {
+    static LocationIdentity getArrayLocation(JavaKind kind) {
         return NamedLocationIdentity.getArrayLocation(kind);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -154,7 +154,7 @@
          * Stack bang to make sure there's enough room for the interpreter frames. Bang stack for
          * total size of the interpreter frames plus shadow page size. Bang one page at a time
          * because large sizes can bang beyond yellow and red zones.
-         *
+         * 
          * @deprecated This code should go away as soon as JDK-8032410 hits the Graal repository.
          */
         final int totalFrameSizes = unrollBlock.readInt(deoptimizationUnrollBlockTotalFrameSizesOffset());
@@ -228,7 +228,7 @@
     }
 
     @Fold
-    private static int stackShadowPages() {
+    static int stackShadowPages() {
         return config().useStackBanging ? config().stackShadowPages : 0;
     }
 
@@ -241,57 +241,57 @@
      */
     @Deprecated
     @Fold
-    private static int stackBias() {
+    static int stackBias() {
         return config().stackBias;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() {
+    static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() {
         return config().deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockCallerAdjustmentOffset() {
+    static int deoptimizationUnrollBlockCallerAdjustmentOffset() {
         return config().deoptimizationUnrollBlockCallerAdjustmentOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockNumberOfFramesOffset() {
+    static int deoptimizationUnrollBlockNumberOfFramesOffset() {
         return config().deoptimizationUnrollBlockNumberOfFramesOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockTotalFrameSizesOffset() {
+    static int deoptimizationUnrollBlockTotalFrameSizesOffset() {
         return config().deoptimizationUnrollBlockTotalFrameSizesOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockUnpackKindOffset() {
+    static int deoptimizationUnrollBlockUnpackKindOffset() {
         return config().deoptimizationUnrollBlockUnpackKindOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockFrameSizesOffset() {
+    static int deoptimizationUnrollBlockFrameSizesOffset() {
         return config().deoptimizationUnrollBlockFrameSizesOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockFramePcsOffset() {
+    static int deoptimizationUnrollBlockFramePcsOffset() {
         return config().deoptimizationUnrollBlockFramePcsOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockInitialInfoOffset() {
+    static int deoptimizationUnrollBlockInitialInfoOffset() {
         return config().deoptimizationUnrollBlockInitialInfoOffset;
     }
 
     @Fold
-    private static int deoptimizationUnpackDeopt() {
+    static int deoptimizationUnpackDeopt() {
         return config().deoptimizationUnpackDeopt;
     }
 
     @Fold
-    private static int deoptimizationUnpackUncommonTrap() {
+    static int deoptimizationUnpackUncommonTrap() {
         return config().deoptimizationUnpackUncommonTrap;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Tue Dec 08 12:30:15 2015 -0800
@@ -133,7 +133,7 @@
     }
 
     @Fold
-    private static boolean logging() {
+    static boolean logging() {
         return Boolean.getBoolean("graal.logExceptionHandlerStub");
     }
 
@@ -146,7 +146,7 @@
      */
     @Fold
     @SuppressWarnings("all")
-    private static boolean assertionsEnabled() {
+    static boolean assertionsEnabled() {
         boolean enabled = false;
         assert enabled = true;
         return enabled || cAssertionsEnabled();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, 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
@@ -84,7 +84,7 @@
     }
 
     @Fold
-    private static boolean logging() {
+    static boolean logging() {
         return Boolean.getBoolean("graal.logNewArrayStub");
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Tue Dec 08 12:30:15 2015 -0800
@@ -126,7 +126,7 @@
     }
 
     @Fold
-    private static boolean logging() {
+    static boolean logging() {
         return Boolean.getBoolean("graal.logNewInstanceStub");
     }
 
@@ -294,7 +294,7 @@
     }
 
     @Fold
-    private static boolean forceSlowPath() {
+    static boolean forceSlowPath() {
         return Boolean.getBoolean("graal.newInstanceStub.forceSlowPath");
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, 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
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
-import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
+import static com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
 
 import java.lang.reflect.Method;
 
@@ -34,15 +34,15 @@
 
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.IntrinsicContext;
 import com.oracle.graal.hotspot.HotSpotForeignCallLinkage;
 import com.oracle.graal.hotspot.meta.HotSpotProviders;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.spi.LoweringTool;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -47,6 +47,7 @@
 import com.oracle.graal.hotspot.nodes.StubForeignCallNode;
 import com.oracle.graal.hotspot.nodes.VMErrorNode;
 import com.oracle.graal.hotspot.word.KlassPointer;
+import com.oracle.graal.nodes.PiNode;
 import com.oracle.graal.nodes.extended.GuardingNode;
 import com.oracle.graal.replacements.Log;
 import com.oracle.graal.word.Pointer;
@@ -241,7 +242,7 @@
                     fatal("oop not in heap: %p", oop.rawValue());
                 }
 
-                KlassPointer klass = loadHubIntrinsic(object, anchorNode);
+                KlassPointer klass = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode));
                 if (klass.isNull()) {
                     fatal("klass for oop %p is null", oop.rawValue());
                 }
@@ -251,22 +252,22 @@
     }
 
     @Fold
-    private static long verifyOopCounterAddress() {
+    static long verifyOopCounterAddress() {
         return config().verifyOopCounterAddress;
     }
 
     @Fold
-    private static long verifyOopMask() {
+    static long verifyOopMask() {
         return config().verifyOopMask;
     }
 
     @Fold
-    private static long verifyOopBits() {
+    static long verifyOopBits() {
         return config().verifyOopBits;
     }
 
     @Fold
-    private static int hubOffset() {
+    static int hubOffset() {
         return config().hubOffset;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -156,7 +156,7 @@
     }
 
     @Fold
-    private static int stackShadowPages() {
+    static int stackShadowPages() {
         return config().useStackBanging ? config().stackShadowPages : 0;
     }
 
@@ -169,52 +169,52 @@
      */
     @Deprecated
     @Fold
-    private static int stackBias() {
+    static int stackBias() {
         return config().stackBias;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() {
+    static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() {
         return config().deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockCallerAdjustmentOffset() {
+    static int deoptimizationUnrollBlockCallerAdjustmentOffset() {
         return config().deoptimizationUnrollBlockCallerAdjustmentOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockNumberOfFramesOffset() {
+    static int deoptimizationUnrollBlockNumberOfFramesOffset() {
         return config().deoptimizationUnrollBlockNumberOfFramesOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockTotalFrameSizesOffset() {
+    static int deoptimizationUnrollBlockTotalFrameSizesOffset() {
         return config().deoptimizationUnrollBlockTotalFrameSizesOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockFrameSizesOffset() {
+    static int deoptimizationUnrollBlockFrameSizesOffset() {
         return config().deoptimizationUnrollBlockFrameSizesOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockFramePcsOffset() {
+    static int deoptimizationUnrollBlockFramePcsOffset() {
         return config().deoptimizationUnrollBlockFramePcsOffset;
     }
 
     @Fold
-    private static int deoptimizationUnrollBlockInitialInfoOffset() {
+    static int deoptimizationUnrollBlockInitialInfoOffset() {
         return config().deoptimizationUnrollBlockInitialInfoOffset;
     }
 
     @Fold
-    private static int deoptimizationUnpackDeopt() {
+    static int deoptimizationUnpackDeopt() {
         return config().deoptimizationUnpackDeopt;
     }
 
     @Fold
-    private static int deoptimizationUnpackUncommonTrap() {
+    static int deoptimizationUnpackUncommonTrap() {
         return config().deoptimizationUnpackUncommonTrap;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, 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
@@ -96,7 +96,7 @@
     }
 
     @Fold
-    private static boolean logging() {
+    static boolean logging() {
         return Boolean.getBoolean("graal.logUnwindExceptionToCallerStub");
     }
 
@@ -109,7 +109,7 @@
      */
     @Fold
     @SuppressWarnings("all")
-    private static boolean assertionsEnabled() {
+    static boolean assertionsEnabled() {
         boolean enabled = false;
         assert enabled = true;
         return enabled || cAssertionsEnabled();
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeParser.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeParser.java	Tue Dec 08 12:30:15 2015 -0800
@@ -231,12 +231,12 @@
 import static com.oracle.graal.compiler.common.GraalOptions.ResolveClassBeforeStaticInvoke;
 import static com.oracle.graal.compiler.common.GraalOptions.StressInvokeWithExceptionNode;
 import static com.oracle.graal.compiler.common.type.StampFactory.objectNonNull;
-import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_DURING_PARSING;
 import static com.oracle.graal.java.BytecodeParserOptions.DumpDuringGraphBuilding;
 import static com.oracle.graal.java.BytecodeParserOptions.FailedLoopExplosionIsFatal;
 import static com.oracle.graal.java.BytecodeParserOptions.MaximumLoopExplosionCount;
 import static com.oracle.graal.java.BytecodeParserOptions.TraceInlineDuringParsing;
 import static com.oracle.graal.java.BytecodeParserOptions.TraceParserPlugins;
+import static com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_DURING_PARSING;
 import static com.oracle.graal.nodes.type.StampTool.isPointerNonNull;
 import static java.lang.String.format;
 import static jdk.vm.ci.common.JVMCIError.guarantee;
@@ -312,15 +312,6 @@
 import com.oracle.graal.graph.Node.ValueNumberable;
 import com.oracle.graal.graph.NodeBitMap;
 import com.oracle.graal.graph.iterators.NodeIterable;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InlineInvokePlugin;
-import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo;
-import com.oracle.graal.graphbuilderconf.IntrinsicContext;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver;
-import com.oracle.graal.graphbuilderconf.LoopExplosionPlugin;
-import com.oracle.graal.graphbuilderconf.NodePlugin;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock;
 import com.oracle.graal.nodeinfo.InputType;
@@ -393,6 +384,15 @@
 import com.oracle.graal.nodes.extended.GuardedNode;
 import com.oracle.graal.nodes.extended.GuardingNode;
 import com.oracle.graal.nodes.extended.IntegerSwitchNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InlineInvokePlugin;
+import com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.LoopExplosionPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.NodePlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver;
 import com.oracle.graal.nodes.java.ArrayLengthNode;
 import com.oracle.graal.nodes.java.CheckCastNode;
 import com.oracle.graal.nodes.java.ExceptionObjectNode;
@@ -1387,7 +1387,7 @@
 
     protected void genThrow() {
         if (GraalOptions.OldInfopoints.getValue() && graphBuilderConfig.insertNonSafepointDebugInfo() && !parsingIntrinsic()) {
-            genInfoPointNode(InfopointReason.LINE_NUMBER, null);
+            genInfoPointNode(InfopointReason.BYTECODE_POSITION, null);
         }
 
         ValueNode exception = frameState.pop(JavaKind.Object);
@@ -2642,7 +2642,7 @@
             if (GraalOptions.OldInfopoints.getValue() && graphBuilderConfig.insertNonSafepointDebugInfo() && !parsingIntrinsic()) {
                 currentLineNumber = lnt != null ? lnt.getLineNumber(bci) : (graphBuilderConfig.insertFullDebugInfo() ? -1 : bci);
                 if (currentLineNumber != previousLineNumber) {
-                    genInfoPointNode(InfopointReason.LINE_NUMBER, null);
+                    genInfoPointNode(InfopointReason.BYTECODE_POSITION, null);
                     previousLineNumber = currentLineNumber;
                 }
             }
@@ -3434,7 +3434,7 @@
         if (skippedExceptionTypes != null) {
             for (ResolvedJavaType exceptionType : skippedExceptionTypes) {
                 if (exceptionType.isAssignableFrom(resolvedType)) {
-                    append(new DeoptimizeNode(DeoptimizationAction.None, TransferToInterpreter));
+                    append(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, TransferToInterpreter));
                     return;
                 }
             }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultSuitesProvider.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultSuitesProvider.java	Tue Dec 08 12:30:15 2015 -0800
@@ -25,9 +25,9 @@
 import jdk.vm.ci.options.DerivedOptionValue;
 import jdk.vm.ci.options.DerivedOptionValue.OptionSupplier;
 
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.lir.phases.LIRSuites;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.tiers.CompilerConfiguration;
 import com.oracle.graal.phases.tiers.HighTierContext;
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Tue Dec 08 12:30:15 2015 -0800
@@ -54,8 +54,6 @@
 import com.oracle.graal.compiler.common.type.Stamp;
 import com.oracle.graal.compiler.common.type.StampFactory;
 import com.oracle.graal.debug.Debug;
-import com.oracle.graal.graphbuilderconf.IntrinsicContext.SideEffectsState;
-import com.oracle.graal.graphbuilderconf.ParameterPlugin;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.nodeinfo.Verbosity;
 import com.oracle.graal.nodes.AbstractMergeNode;
@@ -71,6 +69,8 @@
 import com.oracle.graal.nodes.ValuePhiNode;
 import com.oracle.graal.nodes.ValueProxyNode;
 import com.oracle.graal.nodes.calc.FloatingNode;
+import com.oracle.graal.nodes.graphbuilderconf.ParameterPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext.SideEffectsState;
 import com.oracle.graal.nodes.java.MonitorIdNode;
 import com.oracle.graal.nodes.util.GraphUtil;
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, 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
@@ -26,9 +26,9 @@
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.IntrinsicContext;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext;
 import com.oracle.graal.nodes.spi.StampProvider;
 import com.oracle.graal.phases.BasePhase;
 import com.oracle.graal.phases.OptimisticOptimizations;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/phases/StackMoveOptimizationPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/phases/StackMoveOptimizationPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -44,7 +44,6 @@
 import com.oracle.graal.lir.RedundantMoveElimination;
 import com.oracle.graal.lir.amd64.AMD64Move.AMD64MultiStackMove;
 import com.oracle.graal.lir.amd64.AMD64Move.AMD64StackMove;
-import com.oracle.graal.lir.gen.BenchmarkCounterFactory;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase;
 
@@ -67,7 +66,7 @@
 
     @Override
     protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
-                    BenchmarkCounterFactory counterFactory) {
+                    PostAllocationOptimizationContext context) {
         LIR lir = lirGenRes.getLIR();
         for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
             List<LIRInstruction> instructions = lir.getLIRforBlock(block);
--- a/graal/com.oracle.graal.lir.jtt/src/com/oracle/graal/lir/jtt/LIRTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir.jtt/src/com/oracle/graal/lir/jtt/LIRTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -38,14 +38,14 @@
 import com.oracle.graal.compiler.common.type.StampFactory;
 import com.oracle.graal.graph.NodeClass;
 import com.oracle.graal.graph.NodeInputList;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
 import com.oracle.graal.jtt.JTTTest;
 import com.oracle.graal.nodeinfo.NodeInfo;
 import com.oracle.graal.nodes.FixedWithNextNode;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
 import com.oracle.graal.nodes.spi.LIRLowerable;
 import com.oracle.graal.nodes.spi.NodeLIRBuilderTool;
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java	Tue Dec 08 12:30:15 2015 -0800
@@ -33,7 +33,6 @@
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.DebugMetric;
-import com.oracle.graal.lir.gen.BenchmarkCounterFactory;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase;
 
@@ -47,7 +46,7 @@
      */
     @Override
     protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
-                    BenchmarkCounterFactory counterFactory) {
+                    PostAllocationOptimizationContext context) {
         LIR lir = lirGenRes.getLIR();
         new Optimizer<B>(lir).deleteEmptyBlocks(codeEmittingOrder);
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java	Tue Dec 08 12:30:15 2015 -0800
@@ -31,7 +31,6 @@
 import com.oracle.graal.lir.StandardOp.LoadConstantOp;
 import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.StandardOp.ValueMoveOp;
-import com.oracle.graal.lir.gen.BenchmarkCounterFactory;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase;
 
@@ -57,7 +56,7 @@
 
     @Override
     protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
-                    BenchmarkCounterFactory counterFactory) {
+                    PostAllocationOptimizationContext context) {
         LIR ir = lirGenRes.getLIR();
         Optimizer optimizer = new Optimizer(ir);
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java	Tue Dec 08 12:30:15 2015 -0800
@@ -29,7 +29,6 @@
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
 import com.oracle.graal.lir.StandardOp.NullCheck;
-import com.oracle.graal.lir.gen.BenchmarkCounterFactory;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase;
 
@@ -37,7 +36,7 @@
 
     @Override
     protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
-                    BenchmarkCounterFactory counterFactory) {
+                    PostAllocationOptimizationContext context) {
         LIR ir = lirGenRes.getLIR();
         List<? extends AbstractBlockBase<?>> blocks = ir.codeEmittingOrder();
         NullCheckOptimizer.foldNullChecks(ir, blocks, target.implicitNullCheckLimit);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Tue Dec 08 12:30:15 2015 -0800
@@ -46,7 +46,6 @@
 import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.StandardOp.ValueMoveOp;
 import com.oracle.graal.lir.framemap.FrameMap;
-import com.oracle.graal.lir.gen.BenchmarkCounterFactory;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase;
 
@@ -57,7 +56,7 @@
 
     @Override
     protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
-                    BenchmarkCounterFactory counterFactory) {
+                    PostAllocationOptimizationContext context) {
         Optimization redundantMoveElimination = new Optimization(lirGenRes.getFrameMap());
         redundantMoveElimination.doOptimize(lirGenRes.getLIR());
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/AllocationStageVerifier.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/AllocationStageVerifier.java	Tue Dec 08 12:30:15 2015 -0800
@@ -31,14 +31,12 @@
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.Value;
 
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.lir.LIR;
 import com.oracle.graal.lir.LIRInstruction;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 import com.oracle.graal.lir.phases.AllocationPhase;
 
 /**
@@ -47,8 +45,7 @@
 public class AllocationStageVerifier extends AllocationPhase {
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext context) {
         verifyLIR(lirGenRes.getLIR());
 
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanAssignLocationsPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanAssignLocationsPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -37,7 +37,6 @@
 import jdk.vm.ci.meta.AllocatableValue;
 import jdk.vm.ci.meta.Value;
 
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.Indent;
@@ -52,7 +51,6 @@
 import com.oracle.graal.lir.StandardOp.ValueMoveOp;
 import com.oracle.graal.lir.Variable;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 import com.oracle.graal.lir.phases.AllocationPhase;
 
 /**
@@ -67,8 +65,7 @@
     }
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext context) {
         assignLocations();
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -37,7 +37,6 @@
 import jdk.vm.ci.options.OptionType;
 import jdk.vm.ci.options.OptionValue;
 
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.Indent;
@@ -49,7 +48,6 @@
 import com.oracle.graal.lir.alloc.lsra.Interval.SpillState;
 import com.oracle.graal.lir.alloc.lsra.LinearScan.IntervalPredicate;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 import com.oracle.graal.lir.phases.AllocationPhase;
 
 public class LinearScanEliminateSpillMovePhase extends AllocationPhase {
@@ -76,8 +74,7 @@
     }
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext context) {
         eliminateSpillMoves();
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -49,7 +49,6 @@
 import jdk.vm.ci.meta.Value;
 
 import com.oracle.graal.compiler.common.alloc.ComputeBlockOrder;
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.compiler.common.util.BitMap2D;
 import com.oracle.graal.debug.Debug;
@@ -66,7 +65,6 @@
 import com.oracle.graal.lir.alloc.lsra.Interval.SpillState;
 import com.oracle.graal.lir.alloc.lsra.LinearScan.BlockData;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 import com.oracle.graal.lir.phases.AllocationPhase;
 
 public class LinearScanLifetimeAnalysisPhase extends AllocationPhase {
@@ -81,8 +79,7 @@
     }
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext context) {
         numberInstructions();
         allocator.printLir("Before register allocation", true);
         computeLocalLiveSets();
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -32,7 +32,6 @@
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.AllocatableValue;
 
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.DebugMetric;
@@ -42,7 +41,6 @@
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.alloc.lsra.Interval.SpillState;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 import com.oracle.graal.lir.phases.AllocationPhase;
 
 public final class LinearScanOptimizeSpillPositionPhase extends AllocationPhase {
@@ -57,8 +55,7 @@
     }
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext context) {
         optimizeSpillPosition();
         allocator.printIntervals("After optimize spill position");
     }
@@ -125,7 +122,7 @@
             /*
              * The spill block is the begin of the first split child (aka the value is on the
              * stack).
-             *
+             * 
              * The problem is that if spill block has more than one predecessor, the values at the
              * end of the predecessors might differ. Therefore, we would need a spill move in all
              * predecessors. To avoid this we spill in the dominator.
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -46,8 +46,9 @@
     }
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext context) {
+        MoveFactory spillMoveFactory = context.spillMoveFactory;
+        RegisterAllocationConfig registerAllocationConfig = context.registerAllocationConfig;
         final LinearScan allocator;
         switch (LinearScanVariant.getValue()) {
             case SSI_LSRA:
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -26,12 +26,10 @@
 
 import jdk.vm.ci.code.TargetDescription;
 
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.Indent;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 import com.oracle.graal.lir.phases.AllocationPhase;
 
 public final class LinearScanRegisterAllocationPhase extends AllocationPhase {
@@ -43,8 +41,7 @@
     }
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext context) {
         allocator.printIntervals("Before register allocation");
         allocateRegisters();
         allocator.printIntervals("After register allocation");
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanResolveDataFlowPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanResolveDataFlowPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -29,14 +29,12 @@
 
 import jdk.vm.ci.code.TargetDescription;
 
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.Indent;
 import com.oracle.graal.lir.LIRInstruction;
 import com.oracle.graal.lir.StandardOp;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 import com.oracle.graal.lir.phases.AllocationPhase;
 
 /**
@@ -53,8 +51,7 @@
     }
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext context) {
         resolveDataFlow();
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/FixedInterval.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,310 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, 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.alloc.trace;
-
-import static jdk.vm.ci.code.ValueUtil.asRegister;
-import static jdk.vm.ci.code.ValueUtil.isRegister;
-import jdk.vm.ci.meta.AllocatableValue;
-import jdk.vm.ci.meta.Value;
-
-import com.oracle.graal.lir.LIRInstruction;
-
-/**
- * Represents a fixed interval.
- */
-public final class FixedInterval extends IntervalHint {
-
-    static final class FixedList {
-
-        public FixedInterval fixed;
-
-        public FixedList(FixedInterval fixed) {
-            this.fixed = fixed;
-        }
-
-        /**
-         * Gets the fixed list.
-         */
-        public FixedInterval getFixed() {
-            return fixed;
-        }
-
-        /**
-         * Sets the fixed list.
-         */
-        public void setFixed(FixedInterval list) {
-            fixed = list;
-        }
-
-        /**
-         * Adds an interval to a list sorted by {@linkplain FixedInterval#currentFrom() current
-         * from} positions.
-         *
-         * @param interval the interval to add
-         */
-        public void addToListSortedByCurrentFromPositions(FixedInterval interval) {
-            FixedInterval list = getFixed();
-            FixedInterval prev = null;
-            FixedInterval cur = list;
-            while (cur.currentFrom() < interval.currentFrom()) {
-                prev = cur;
-                cur = cur.next;
-            }
-            FixedInterval result = list;
-            if (prev == null) {
-                // add to head of list
-                result = interval;
-            } else {
-                // add before 'cur'
-                prev.next = interval;
-            }
-            interval.next = cur;
-            setFixed(result);
-        }
-
-    }
-
-    /**
-     * The fixed operand of this interval.
-     */
-    public final AllocatableValue operand;
-
-    /**
-     * The head of the list of ranges describing this interval. This list is sorted by
-     * {@linkplain LIRInstruction#id instruction ids}.
-     */
-    private FixedRange first;
-
-    /**
-     * Iterator used to traverse the ranges of an interval.
-     */
-    private FixedRange current;
-
-    /**
-     * Link to next interval in a sorted list of intervals that ends with {@link #EndMarker}.
-     */
-    FixedInterval next;
-
-    private int cachedTo; // cached value: to of last range (-1: not cached)
-
-    public FixedRange first() {
-        return first;
-    }
-
-    @Override
-    public int from() {
-        return first.from;
-    }
-
-    public int to() {
-        if (cachedTo == -1) {
-            cachedTo = calcTo();
-        }
-        assert cachedTo == calcTo() : "invalid cached value";
-        return cachedTo;
-    }
-
-    // test intersection
-    boolean intersects(TraceInterval i) {
-        return first.intersects(i);
-    }
-
-    int intersectsAt(TraceInterval i) {
-        return first.intersectsAt(i);
-    }
-
-    // range iteration
-    void rewindRange() {
-        current = first;
-    }
-
-    void nextRange() {
-        assert this != EndMarker : "not allowed on sentinel";
-        current = current.next;
-    }
-
-    int currentFrom() {
-        return current.from;
-    }
-
-    int currentTo() {
-        return current.to;
-    }
-
-    boolean currentAtEnd() {
-        return current == FixedRange.EndMarker;
-    }
-
-    boolean currentIntersects(TraceInterval it) {
-        return current.intersects(it);
-    }
-
-    int currentIntersectsAt(TraceInterval it) {
-        return current.intersectsAt(it);
-    }
-
-    // range creation
-    public void setFrom(int from) {
-        assert !isEmpty();
-        first().from = from;
-    }
-
-    private boolean isEmpty() {
-        return first() == FixedRange.EndMarker;
-    }
-
-    public void addRange(int from, int to) {
-        if (isEmpty()) {
-            first = new FixedRange(from, to, first());
-            return;
-        }
-        if (to <= to() && from >= from()) {
-            return;
-        }
-        if (from() == to) {
-            first().from = from;
-        } else {
-            first = new FixedRange(from, to, first());
-        }
-    }
-
-    @Override
-    public AllocatableValue location() {
-        return operand;
-    }
-
-    /**
-     * Sentinel interval to denote the end of an interval list.
-     */
-    static final FixedInterval EndMarker = new FixedInterval(Value.ILLEGAL);
-
-    FixedInterval(AllocatableValue operand) {
-        assert operand != null;
-        this.operand = operand;
-        this.first = FixedRange.EndMarker;
-        this.current = FixedRange.EndMarker;
-        this.next = FixedInterval.EndMarker;
-        this.cachedTo = -1;
-    }
-
-    int calcTo() {
-        assert first != FixedRange.EndMarker : "interval has no range";
-
-        FixedRange r = first;
-        while (r.next != FixedRange.EndMarker) {
-            r = r.next;
-        }
-        return r.to;
-    }
-
-    // returns true if the opId is inside the interval
-    boolean covers(int opId, LIRInstruction.OperandMode mode) {
-        FixedRange cur = first;
-
-        while (cur != FixedRange.EndMarker && cur.to < opId) {
-            cur = cur.next;
-        }
-        if (cur != FixedRange.EndMarker) {
-            assert cur.to != cur.next.from : "ranges not separated";
-
-            if (mode == LIRInstruction.OperandMode.DEF) {
-                return cur.from <= opId && opId < cur.to;
-            } else {
-                return cur.from <= opId && opId <= cur.to;
-            }
-        }
-        return false;
-    }
-
-    // returns true if the interval has any hole between holeFrom and holeTo
-    // (even if the hole has only the length 1)
-    boolean hasHoleBetween(int holeFrom, int holeTo) {
-        assert holeFrom < holeTo : "check";
-        assert from() <= holeFrom && holeTo <= to() : "index out of interval";
-
-        FixedRange cur = first;
-        while (cur != FixedRange.EndMarker) {
-            assert cur.to < cur.next.from : "no space between ranges";
-
-            // hole-range starts before this range . hole
-            if (holeFrom < cur.from) {
-                return true;
-
-                // hole-range completely inside this range . no hole
-            } else {
-                if (holeTo <= cur.to) {
-                    return false;
-
-                    // overlapping of hole-range with this range . hole
-                } else {
-                    if (holeFrom <= cur.to) {
-                        return true;
-                    }
-                }
-            }
-
-            cur = cur.next;
-        }
-
-        return false;
-    }
-
-    @Override
-    public String toString() {
-        String from = "?";
-        String to = "?";
-        if (first != null && first != FixedRange.EndMarker) {
-            from = String.valueOf(from());
-            // to() may cache a computed value, modifying the current object, which is a bad idea
-            // for a printing function. Compute it directly instead.
-            to = String.valueOf(calcTo());
-        }
-        String locationString = "@" + this.operand;
-        return asRegister(operand).number + ":" + operand + (isRegister(operand) ? "" : locationString) + "[" + from + "," + to + "]";
-    }
-
-    /**
-     * Gets a single line string for logging the details of this interval to a log stream.
-     */
-    @Override
-    public String logString(TraceLinearScan allocator) {
-        StringBuilder buf = new StringBuilder(100);
-        buf.append("fix ").append(asRegister(operand).number).append(':').append(operand).append(' ');
-
-        buf.append(" ranges{");
-
-        // print ranges
-        FixedRange cur = first;
-        while (cur != FixedRange.EndMarker) {
-            if (cur != first) {
-                buf.append(", ");
-            }
-            buf.append(cur);
-            cur = cur.next;
-            assert cur != null : "range list not closed with range sentinel";
-        }
-        buf.append("}");
-        return buf.toString();
-    }
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/FixedRange.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, 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.alloc.trace;
-
-/**
- * Represents a range of integers from a start (inclusive) to an end (exclusive).
- */
-public final class FixedRange {
-
-    public static final FixedRange EndMarker = new FixedRange(Integer.MAX_VALUE, Integer.MAX_VALUE, null);
-
-    /**
-     * The start of the range, inclusive.
-     */
-    public int from;
-
-    /**
-     * The end of the range, exclusive.
-     */
-    public int to;
-
-    /**
-     * A link to allow the range to be put into a singly linked list.
-     */
-    public FixedRange next;
-
-    boolean intersects(TraceInterval i) {
-        return intersectsAt(i) != -1;
-    }
-
-    /**
-     * Creates a new range.
-     *
-     * @param from the start of the range, inclusive
-     * @param to the end of the range, exclusive
-     * @param next link to the next range in a linked list
-     */
-    FixedRange(int from, int to, FixedRange next) {
-        this.from = from;
-        this.to = to;
-        this.next = next;
-    }
-
-    int intersectsAt(TraceInterval other) {
-        FixedRange range = this;
-        assert other != null : "null ranges not allowed";
-        assert range != EndMarker && other != TraceInterval.EndMarker : "empty ranges not allowed";
-        int intervalFrom = other.from();
-        int intervalTo = other.to();
-
-        do {
-            if (range.from < intervalFrom) {
-                if (range.to <= intervalFrom) {
-                    range = range.next;
-                    if (range == EndMarker) {
-                        return -1;
-                    }
-                } else {
-                    return intervalFrom;
-                }
-            } else {
-                if (intervalFrom < range.from) {
-                    if (intervalTo <= range.from) {
-                        return -1;
-                    }
-                    return range.from;
-                } else {
-                    assert range.from == intervalFrom;
-                    if (range.from == range.to) {
-                        range = range.next;
-                        if (range == EndMarker) {
-                            return -1;
-                        }
-                    } else {
-                        if (intervalFrom == intervalTo) {
-                            return -1;
-                        }
-                        return range.from;
-                    }
-                }
-            }
-        } while (true);
-    }
-
-    @Override
-    public String toString() {
-        return "[" + from + ", " + to + "]";
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/IntervalHint.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, 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.alloc.trace;
-
-import jdk.vm.ci.meta.AllocatableValue;
-
-/**
- * An interval that is a hint for an {@code TraceInterval interval}.
- */
-abstract class IntervalHint {
-
-    public abstract AllocatableValue location();
-
-    public abstract int from();
-
-    public abstract String logString(TraceLinearScan allocator);
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/RegisterVerifier.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,264 +0,0 @@
-/*
- * Copyright (c) 2009, 2012, 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.alloc.trace;
-
-import static jdk.vm.ci.code.ValueUtil.asRegister;
-import static jdk.vm.ci.code.ValueUtil.isRegister;
-
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.List;
-
-import jdk.vm.ci.code.Register;
-import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.meta.Value;
-
-import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
-import com.oracle.graal.compiler.common.util.ArrayMap;
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.debug.Indent;
-import com.oracle.graal.lir.InstructionValueConsumer;
-import com.oracle.graal.lir.LIRInstruction;
-import com.oracle.graal.lir.LIRInstruction.OperandFlag;
-import com.oracle.graal.lir.LIRInstruction.OperandMode;
-
-/**
- */
-final class RegisterVerifier {
-
-    TraceLinearScan allocator;
-    List<AbstractBlockBase<?>> workList; // all blocks that must be processed
-    ArrayMap<TraceInterval[]> savedStates; // saved information of previous check
-
-    // simplified access to methods of LinearScan
-    TraceInterval intervalAt(Value operand) {
-        return allocator.intervalFor(operand);
-    }
-
-    // currently, only registers are processed
-    int stateSize() {
-        return allocator.numRegisters();
-    }
-
-    // accessors
-    TraceInterval[] stateForBlock(AbstractBlockBase<?> block) {
-        return savedStates.get(block.getId());
-    }
-
-    void setStateForBlock(AbstractBlockBase<?> block, TraceInterval[] savedState) {
-        savedStates.put(block.getId(), savedState);
-    }
-
-    void addToWorkList(AbstractBlockBase<?> block) {
-        if (!workList.contains(block)) {
-            workList.add(block);
-        }
-    }
-
-    RegisterVerifier(TraceLinearScan allocator) {
-        this.allocator = allocator;
-        workList = new ArrayList<>(16);
-        this.savedStates = new ArrayMap<>();
-
-    }
-
-    @SuppressWarnings("try")
-    void verify(AbstractBlockBase<?> start) {
-        try (Scope s = Debug.scope("RegisterVerifier")) {
-            // setup input registers (method arguments) for first block
-            TraceInterval[] inputState = new TraceInterval[stateSize()];
-            setStateForBlock(start, inputState);
-            addToWorkList(start);
-
-            // main loop for verification
-            do {
-                AbstractBlockBase<?> block = workList.get(0);
-                workList.remove(0);
-
-                processBlock(block);
-            } while (!workList.isEmpty());
-        }
-    }
-
-    @SuppressWarnings("try")
-    private void processBlock(AbstractBlockBase<?> block) {
-        try (Indent indent = Debug.logAndIndent("processBlock B%d", block.getId())) {
-            // must copy state because it is modified
-            TraceInterval[] inputState = copy(stateForBlock(block));
-
-            try (Indent indent2 = Debug.logAndIndent("Input-State of intervals:")) {
-                printState(inputState);
-            }
-
-            // process all operations of the block
-            processOperations(block, inputState);
-
-            try (Indent indent2 = Debug.logAndIndent("Output-State of intervals:")) {
-                printState(inputState);
-            }
-
-            // iterate all successors
-            for (AbstractBlockBase<?> succ : block.getSuccessors()) {
-                processSuccessor(succ, inputState);
-            }
-        }
-    }
-
-    protected void printState(TraceInterval[] inputState) {
-        for (int i = 0; i < stateSize(); i++) {
-            Register reg = allocator.getRegisters()[i];
-            assert reg.number == i;
-            if (inputState[i] != null) {
-                Debug.log(" %6s %4d  --  %s", reg, inputState[i].operandNumber, inputState[i]);
-            } else {
-                Debug.log(" %6s   __", reg);
-            }
-        }
-    }
-
-    private void processSuccessor(AbstractBlockBase<?> block, TraceInterval[] inputState) {
-        TraceInterval[] savedState = stateForBlock(block);
-
-        if (savedState != null) {
-            // this block was already processed before.
-            // check if new inputState is consistent with savedState
-
-            boolean savedStateCorrect = true;
-            for (int i = 0; i < stateSize(); i++) {
-                if (inputState[i] != savedState[i]) {
-                    // current inputState and previous savedState assume a different
-                    // interval in this register . assume that this register is invalid
-                    if (savedState[i] != null) {
-                        // invalidate old calculation only if it assumed that
-                        // register was valid. when the register was already invalid,
-                        // then the old calculation was correct.
-                        savedStateCorrect = false;
-                        savedState[i] = null;
-
-                        Debug.log("processSuccessor B%d: invalidating slot %d", block.getId(), i);
-                    }
-                }
-            }
-
-            if (savedStateCorrect) {
-                // already processed block with correct inputState
-                Debug.log("processSuccessor B%d: previous visit already correct", block.getId());
-            } else {
-                // must re-visit this block
-                Debug.log("processSuccessor B%d: must re-visit because input state changed", block.getId());
-                addToWorkList(block);
-            }
-
-        } else {
-            // block was not processed before, so set initial inputState
-            Debug.log("processSuccessor B%d: initial visit", block.getId());
-
-            setStateForBlock(block, copy(inputState));
-            addToWorkList(block);
-        }
-    }
-
-    static TraceInterval[] copy(TraceInterval[] inputState) {
-        return inputState.clone();
-    }
-
-    static void statePut(TraceInterval[] inputState, Value location, TraceInterval interval) {
-        if (location != null && isRegister(location)) {
-            Register reg = asRegister(location);
-            int regNum = reg.number;
-            if (interval != null) {
-                Debug.log("%s = %s", reg, interval.operand);
-            } else if (inputState[regNum] != null) {
-                Debug.log("%s = null", reg);
-            }
-
-            inputState[regNum] = interval;
-        }
-    }
-
-    static boolean checkState(AbstractBlockBase<?> block, LIRInstruction op, TraceInterval[] inputState, Value operand, Value reg, TraceInterval interval) {
-        if (reg != null && isRegister(reg)) {
-            if (inputState[asRegister(reg).number] != interval) {
-                throw new JVMCIError(
-                                "Error in register allocation: operation (%s) in block %s expected register %s (operand %s) to contain the value of interval %s but data-flow says it contains interval %s",
-                                op, block, reg, operand, interval, inputState[asRegister(reg).number]);
-            }
-        }
-        return true;
-    }
-
-    void processOperations(AbstractBlockBase<?> block, final TraceInterval[] inputState) {
-        List<LIRInstruction> ops = allocator.getLIR().getLIRforBlock(block);
-        InstructionValueConsumer useConsumer = new InstructionValueConsumer() {
-
-            @Override
-            public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                // we skip spill moves inserted by the spill position optimization
-                if (TraceLinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand) && op.id() != TraceLinearScan.DOMINATOR_SPILL_MOVE_ID) {
-                    TraceInterval interval = intervalAt(operand);
-                    if (op.id() != -1) {
-                        interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
-                    }
-
-                    assert checkState(block, op, inputState, interval.operand, interval.location(), interval.splitParent());
-                }
-            }
-        };
-
-        InstructionValueConsumer defConsumer = (op, operand, mode, flags) -> {
-            if (TraceLinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
-                TraceInterval interval = intervalAt(operand);
-                if (op.id() != -1) {
-                    interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
-                }
-
-                statePut(inputState, interval.location(), interval.splitParent());
-            }
-        };
-
-        // visit all instructions of the block
-        for (int i = 0; i < ops.size(); i++) {
-            final LIRInstruction op = ops.get(i);
-
-            if (Debug.isLogEnabled()) {
-                Debug.log("%s", op.toStringWithIdPrefix());
-            }
-
-            // check if input operands are correct
-            op.visitEachInput(useConsumer);
-            // invalidate all caller save registers at calls
-            if (op.destroysCallerSavedRegisters()) {
-                for (Register r : allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters()) {
-                    statePut(inputState, r.asValue(), null);
-                }
-            }
-            op.visitEachAlive(useConsumer);
-            // set temp operands (some operations use temp operands also as output operands, so
-            // can't set them null)
-            op.visitEachTemp(defConsumer);
-            // set output operands
-            op.visitEachOutput(defConsumer);
-        }
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceAllocationPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceAllocationPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -22,35 +22,23 @@
  */
 package com.oracle.graal.lir.alloc.trace;
 
-import java.util.List;
-
-import jdk.vm.ci.code.TargetDescription;
-
 import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
-import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
-import com.oracle.graal.lir.gen.LIRGenerationResult;
+import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
 import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 import com.oracle.graal.lir.phases.LIRPhase;
 
 public abstract class TraceAllocationPhase extends LIRPhase<TraceAllocationPhase.TraceAllocationContext> {
 
     public static final class TraceAllocationContext {
-        private final MoveFactory spillMoveFactory;
-        private final RegisterAllocationConfig registerAllocationConfig;
+        public final MoveFactory spillMoveFactory;
+        public final RegisterAllocationConfig registerAllocationConfig;
+        public final TraceBuilderResult<?> resultTraces;
 
-        public TraceAllocationContext(MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig) {
+        public TraceAllocationContext(MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig, TraceBuilderResult<?> resultTraces) {
             this.spillMoveFactory = spillMoveFactory;
             this.registerAllocationConfig = registerAllocationConfig;
+            this.resultTraces = resultTraces;
         }
     }
 
-    @Override
-    protected final <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
-                    TraceAllocationContext context) {
-        run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context.spillMoveFactory, context.registerAllocationConfig);
-    }
-
-    protected abstract <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
-                    MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig);
-
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -37,7 +37,6 @@
 import jdk.vm.ci.meta.AllocatableValue;
 import jdk.vm.ci.meta.Value;
 
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.debug.Debug;
@@ -58,16 +57,10 @@
         public abstract void addMapping(Value src, AllocatableValue dst);
     }
 
-    private final TraceBuilderResult<?> resultTraces;
-
-    public TraceGlobalMoveResolutionPhase(TraceBuilderResult<?> resultTraces) {
-        this.resultTraces = resultTraces;
-    }
-
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
-        resolveGlobalDataFlow(resultTraces, lirGenRes, spillMoveFactory, target.arch);
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, TraceAllocationContext context) {
+        MoveFactory spillMoveFactory = context.spillMoveFactory;
+        resolveGlobalDataFlow(context.resultTraces, lirGenRes, spillMoveFactory, target.arch);
     }
 
     @SuppressWarnings("try")
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceGlobalMoveResolver.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceGlobalMoveResolver.java	Tue Dec 08 12:30:15 2015 -0800
@@ -229,8 +229,7 @@
     }
 
     /**
-     * Checks if the {@linkplain TraceInterval#location() location} of {@code to} is not blocked or
-     * is only blocked by {@code from}.
+     * Checks if {@code to} is not blocked or is only blocked by {@code from}.
      */
     private boolean safeToProcessMove(Value fromLocation, Value toLocation) {
         if (mightBeBlocked(toLocation)) {
@@ -318,8 +317,8 @@
     }
 
     /**
-     * @param fromOpr {@link TraceInterval#operand operand} of the {@code from} interval
-     * @param toOpr {@link TraceInterval#operand operand} of the {@code to} interval
+     * @param fromOpr Operand of the {@code from} interval
+     * @param toOpr Operand of the {@code to} interval
      */
     private LIRInstruction createMove(Value fromOpr, AllocatableValue toOpr) {
         if (isStackSlotValue(toOpr) && isStackSlotValue(fromOpr)) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceInterval.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1100 +0,0 @@
-/*
- * Copyright (c) 2009, 2015, 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.alloc.trace;
-
-import static com.oracle.graal.compiler.common.GraalOptions.DetailedAsserts;
-import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
-import static com.oracle.graal.lir.LIRValueUtil.isVariable;
-import static com.oracle.graal.lir.LIRValueUtil.isVirtualStackSlot;
-import static jdk.vm.ci.code.ValueUtil.asRegister;
-import static jdk.vm.ci.code.ValueUtil.isIllegal;
-import static jdk.vm.ci.code.ValueUtil.isRegister;
-import static jdk.vm.ci.code.ValueUtil.isStackSlot;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.List;
-
-import jdk.vm.ci.code.BailoutException;
-import jdk.vm.ci.code.RegisterValue;
-import jdk.vm.ci.code.StackSlot;
-import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.meta.AllocatableValue;
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.LIRKind;
-import jdk.vm.ci.meta.Value;
-
-import com.oracle.graal.compiler.common.util.Util;
-import com.oracle.graal.debug.TTY;
-import com.oracle.graal.lir.LIRInstruction;
-import com.oracle.graal.lir.Variable;
-
-/**
- * Represents an interval in the {@linkplain TraceLinearScan linear scan register allocator}.
- */
-final class TraceInterval extends IntervalHint {
-
-    static final class AnyList {
-
-        /**
-         * List of intervals whose binding is currently {@link RegisterBinding#Any}.
-         */
-        public TraceInterval any;
-
-        public AnyList(TraceInterval any) {
-            this.any = any;
-        }
-
-        /**
-         * Gets the any list.
-         */
-        public TraceInterval getAny() {
-            return any;
-        }
-
-        /**
-         * Sets the any list.
-         */
-        public void setAny(TraceInterval list) {
-            any = list;
-        }
-
-        /**
-         * Adds an interval to a list sorted by {@linkplain TraceInterval#from() current from}
-         * positions.
-         *
-         * @param interval the interval to add
-         */
-        public void addToListSortedByFromPositions(TraceInterval interval) {
-            TraceInterval list = getAny();
-            TraceInterval prev = null;
-            TraceInterval cur = list;
-            while (cur.from() < interval.from()) {
-                prev = cur;
-                cur = cur.next;
-            }
-            TraceInterval result = list;
-            if (prev == null) {
-                // add to head of list
-                result = interval;
-            } else {
-                // add before 'cur'
-                prev.next = interval;
-            }
-            interval.next = cur;
-            setAny(result);
-        }
-
-        /**
-         * Adds an interval to a list sorted by {@linkplain TraceInterval#from() start} positions
-         * and {@linkplain TraceInterval#firstUsage(RegisterPriority) first usage} positions.
-         *
-         * @param interval the interval to add
-         */
-        public void addToListSortedByStartAndUsePositions(TraceInterval interval) {
-            TraceInterval list = getAny();
-            TraceInterval prev = null;
-            TraceInterval cur = list;
-            while (cur.from() < interval.from() || (cur.from() == interval.from() && cur.firstUsage(RegisterPriority.None) < interval.firstUsage(RegisterPriority.None))) {
-                prev = cur;
-                cur = cur.next;
-            }
-            if (prev == null) {
-                list = interval;
-            } else {
-                prev.next = interval;
-            }
-            interval.next = cur;
-            setAny(list);
-        }
-
-        /**
-         * Removes an interval from a list.
-         *
-         * @param i the interval to remove
-         */
-        public void removeAny(TraceInterval i) {
-            TraceInterval list = getAny();
-            TraceInterval prev = null;
-            TraceInterval cur = list;
-            while (cur != i) {
-                assert cur != null && cur != TraceInterval.EndMarker : "interval has not been found in list: " + i;
-                prev = cur;
-                cur = cur.next;
-            }
-            if (prev == null) {
-                setAny(cur.next);
-            } else {
-                prev.next = cur.next;
-            }
-        }
-    }
-
-    /**
-     * Constants denoting the register usage priority for an interval. The constants are declared in
-     * increasing order of priority are are used to optimize spilling when multiple overlapping
-     * intervals compete for limited registers.
-     */
-    public enum RegisterPriority {
-        /**
-         * No special reason for an interval to be allocated a register.
-         */
-        None,
-
-        /**
-         * Priority level for intervals live at the end of a loop.
-         */
-        LiveAtLoopEnd,
-
-        /**
-         * Priority level for intervals that should be allocated to a register.
-         */
-        ShouldHaveRegister,
-
-        /**
-         * Priority level for intervals that must be allocated to a register.
-         */
-        MustHaveRegister;
-
-        public static final RegisterPriority[] VALUES = values();
-
-        /**
-         * Determines if this priority is higher than or equal to a given priority.
-         */
-        public boolean greaterEqual(RegisterPriority other) {
-            return ordinal() >= other.ordinal();
-        }
-
-        /**
-         * Determines if this priority is lower than a given priority.
-         */
-        public boolean lessThan(RegisterPriority other) {
-            return ordinal() < other.ordinal();
-        }
-
-        public CharSequence shortName() {
-            return name().subSequence(0, 1);
-        }
-    }
-
-    /**
-     * Constants denoting whether an interval is bound to a specific register. This models platform
-     * dependencies on register usage for certain instructions.
-     */
-    enum RegisterBinding {
-        /**
-         * Interval is bound to a specific register as required by the platform.
-         */
-        Fixed,
-
-        /**
-         * Interval has no specific register requirements.
-         */
-        Any,
-
-        /**
-         * Interval is bound to a stack slot.
-         */
-        Stack;
-
-        public static final RegisterBinding[] VALUES = values();
-    }
-
-    /**
-     * Constants denoting the linear-scan states an interval may be in with respect to the
-     * {@linkplain TraceInterval#from() start} {@code position} of the interval being processed.
-     */
-    enum State {
-        /**
-         * An interval that starts after {@code position}.
-         */
-        Unhandled,
-
-        /**
-         * An interval that {@linkplain TraceInterval#covers covers} {@code position} and has an
-         * assigned register.
-         */
-        Active,
-
-        /**
-         * An interval that starts before and ends after {@code position} but does not
-         * {@linkplain TraceInterval#covers cover} it due to a lifetime hole.
-         */
-        Inactive,
-
-        /**
-         * An interval that ends before {@code position} or is spilled to memory.
-         */
-        Handled;
-    }
-
-    /**
-     * Constants used in optimization of spilling of an interval.
-     */
-    public enum SpillState {
-        /**
-         * Starting state of calculation: no definition found yet.
-         */
-        NoDefinitionFound,
-
-        /**
-         * One definition has already been found. Two consecutive definitions are treated as one
-         * (e.g. a consecutive move and add because of two-operand LIR form). The position of this
-         * definition is given by {@link TraceInterval#spillDefinitionPos()}.
-         */
-        NoSpillStore,
-
-        /**
-         * One spill move has already been inserted.
-         */
-        OneSpillStore,
-
-        /**
-         * The interval is spilled multiple times or is spilled in a loop. Place the store somewhere
-         * on the dominator path between the definition and the usages.
-         */
-        SpillInDominator,
-
-        /**
-         * The interval should be stored immediately after its definition to prevent multiple
-         * redundant stores.
-         */
-        StoreAtDefinition,
-
-        /**
-         * The interval starts in memory (e.g. method parameter), so a store is never necessary.
-         */
-        StartInMemory,
-
-        /**
-         * The interval has more than one definition (e.g. resulting from phi moves), so stores to
-         * memory are not optimized.
-         */
-        NoOptimization;
-
-        public static final EnumSet<SpillState> ALWAYS_IN_MEMORY = EnumSet.of(SpillInDominator, StoreAtDefinition, StartInMemory);
-    }
-
-    /**
-     * The {@linkplain RegisterValue register} or {@linkplain Variable variable} for this interval
-     * prior to register allocation.
-     */
-    public final AllocatableValue operand;
-
-    /**
-     * The operand number for this interval's {@linkplain #operand operand}.
-     */
-    public final int operandNumber;
-
-    /**
-     * The {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to this
-     * interval. In case of a spilled interval which is re-materialized this is
-     * {@link Value#ILLEGAL}.
-     */
-    private AllocatableValue location;
-
-    /**
-     * The stack slot to which all splits of this interval are spilled if necessary.
-     */
-    private AllocatableValue spillSlot;
-
-    /**
-     * The kind of this interval.
-     */
-    private LIRKind kind;
-
-    /**
-     * The start of the range, inclusive.
-     */
-    public int intFrom;
-
-    /**
-     * The end of the range, exclusive.
-     */
-    public int intTo;
-
-    /**
-     * List of (use-positions, register-priorities) pairs, sorted by use-positions.
-     */
-    private UsePosList usePosList;
-
-    /**
-     * Link to next interval in a sorted list of intervals that ends with {@link #EndMarker}.
-     */
-    TraceInterval next;
-
-    /**
-     * The linear-scan state of this interval.
-     */
-    State state;
-
-    /**
-     * The interval from which this one is derived. If this is a {@linkplain #isSplitParent() split
-     * parent}, it points to itself.
-     */
-    private TraceInterval splitParent;
-
-    /**
-     * List of all intervals that are split off from this interval. This is only used if this is a
-     * {@linkplain #isSplitParent() split parent}.
-     */
-    private List<TraceInterval> splitChildren = Collections.emptyList();
-
-    /**
-     * Current split child that has been active or inactive last (always stored in split parents).
-     */
-    private TraceInterval currentSplitChild;
-
-    /**
-     * Specifies if move is inserted between currentSplitChild and this interval when interval gets
-     * active the first time.
-     */
-    private boolean insertMoveWhenActivated;
-
-    /**
-     * For spill move optimization.
-     */
-    private SpillState spillState;
-
-    /**
-     * Position where this interval is defined (if defined only once).
-     */
-    private int spillDefinitionPos;
-
-    /**
-     * This interval should be assigned the same location as the hint interval.
-     */
-    private IntervalHint locationHint;
-
-    /**
-     * The value with which a spilled child interval can be re-materialized. Currently this must be
-     * a Constant.
-     */
-    private JavaConstant materializedValue;
-
-    /**
-     * The number of times {@link #addMaterializationValue(JavaConstant)} is called.
-     */
-    private int numMaterializationValuesAdded;
-
-    void assignLocation(AllocatableValue newLocation) {
-        if (isRegister(newLocation)) {
-            assert this.location == null : "cannot re-assign location for " + this;
-            if (newLocation.getLIRKind().equals(LIRKind.Illegal) && !kind.equals(LIRKind.Illegal)) {
-                this.location = asRegister(newLocation).asValue(kind);
-                return;
-            }
-        } else if (isIllegal(newLocation)) {
-            assert canMaterialize();
-        } else {
-            assert this.location == null || isRegister(this.location) || (isVirtualStackSlot(this.location) && isStackSlot(newLocation)) : "cannot re-assign location for " + this;
-            assert isStackSlotValue(newLocation);
-            assert !newLocation.getLIRKind().equals(LIRKind.Illegal);
-            assert newLocation.getLIRKind().equals(this.kind);
-        }
-        this.location = newLocation;
-    }
-
-    /**
-     * Gets the {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to
-     * this interval.
-     */
-    @Override
-    public AllocatableValue location() {
-        return location;
-    }
-
-    public LIRKind kind() {
-        assert !isRegister(operand) : "cannot access type for fixed interval";
-        return kind;
-    }
-
-    public void setKind(LIRKind kind) {
-        assert isRegister(operand) || this.kind().equals(LIRKind.Illegal) || this.kind().equals(kind) : "overwriting existing type";
-        this.kind = kind;
-    }
-
-    public boolean isEmpty() {
-        return intFrom == Integer.MAX_VALUE && intTo == Integer.MAX_VALUE;
-    }
-
-    public void setTo(int pos) {
-        assert intFrom == Integer.MAX_VALUE || intFrom < pos;
-        intTo = pos;
-    }
-
-    public void setFrom(int pos) {
-        assert intTo == Integer.MAX_VALUE || pos < intTo;
-        intFrom = pos;
-    }
-
-    @Override
-    public int from() {
-        return intFrom;
-    }
-
-    int to() {
-        return intTo;
-    }
-
-    int numUsePositions() {
-        return usePosList.size();
-    }
-
-    public void setLocationHint(IntervalHint interval) {
-        locationHint = interval;
-    }
-
-    public boolean isSplitParent() {
-        return splitParent == this;
-    }
-
-    boolean isSplitChild() {
-        return splitParent != this;
-    }
-
-    /**
-     * Gets the split parent for this interval.
-     */
-    public TraceInterval splitParent() {
-        assert splitParent.isSplitParent() : "not a split parent: " + this;
-        return splitParent;
-    }
-
-    /**
-     * Gets the canonical spill slot for this interval.
-     */
-    public AllocatableValue spillSlot() {
-        return splitParent().spillSlot;
-    }
-
-    public void setSpillSlot(AllocatableValue slot) {
-        assert isStackSlotValue(slot);
-        assert splitParent().spillSlot == null || (isVirtualStackSlot(splitParent().spillSlot) && isStackSlot(slot)) : "connot overwrite existing spill slot";
-        splitParent().spillSlot = slot;
-    }
-
-    TraceInterval currentSplitChild() {
-        return splitParent().currentSplitChild;
-    }
-
-    void makeCurrentSplitChild() {
-        splitParent().currentSplitChild = this;
-    }
-
-    boolean insertMoveWhenActivated() {
-        return insertMoveWhenActivated;
-    }
-
-    void setInsertMoveWhenActivated(boolean b) {
-        insertMoveWhenActivated = b;
-    }
-
-    // for spill optimization
-    public SpillState spillState() {
-        return splitParent().spillState;
-    }
-
-    public int spillDefinitionPos() {
-        return splitParent().spillDefinitionPos;
-    }
-
-    public void setSpillState(SpillState state) {
-        assert state.ordinal() >= spillState().ordinal() : "state cannot decrease";
-        splitParent().spillState = state;
-    }
-
-    public void setSpillDefinitionPos(int pos) {
-        assert spillState() == SpillState.SpillInDominator || spillState() == SpillState.NoDefinitionFound || spillDefinitionPos() == -1 : "cannot set the position twice";
-        splitParent().spillDefinitionPos = pos;
-    }
-
-    /**
-     * Returns true if this interval has a shadow copy on the stack that is correct after
-     * {@code opId}.
-     */
-    public boolean inMemoryAt(int opId) {
-        return SpillState.ALWAYS_IN_MEMORY.contains(spillState()) && !canMaterialize() && opId > spillDefinitionPos();
-    }
-
-    void removeFirstUsePos() {
-        usePosList.removeLowestUsePos();
-    }
-
-    // test intersection
-    boolean intersects(TraceInterval i) {
-        return intersectsAt(i) != -1;
-    }
-
-    int intersectsAt(TraceInterval i) {
-        TraceInterval i1;
-        TraceInterval i2;
-        if (i.from() < this.from()) {
-            i1 = i;
-            i2 = this;
-        } else {
-            i1 = this;
-            i2 = i;
-        }
-        assert i1.from() <= i2.from();
-
-        if (i1.to() <= i2.from()) {
-            return -1;
-        }
-        return i2.from();
-    }
-
-    /**
-     * Sentinel interval to denote the end of an interval list.
-     */
-    static final TraceInterval EndMarker = new TraceInterval(Value.ILLEGAL, -1);
-
-    TraceInterval(AllocatableValue operand, int operandNumber) {
-        assert operand != null;
-        this.operand = operand;
-        this.operandNumber = operandNumber;
-        if (isRegister(operand)) {
-            location = operand;
-        } else {
-            assert isIllegal(operand) || isVariable(operand);
-        }
-        this.kind = LIRKind.Illegal;
-        this.intFrom = Integer.MAX_VALUE;
-        this.intTo = Integer.MAX_VALUE;
-        this.usePosList = new UsePosList(4);
-        this.next = EndMarker;
-        this.spillState = SpillState.NoDefinitionFound;
-        this.spillDefinitionPos = -1;
-        splitParent = this;
-        currentSplitChild = this;
-    }
-
-    /**
-     * Sets the value which is used for re-materialization.
-     */
-    public void addMaterializationValue(JavaConstant value) {
-        if (numMaterializationValuesAdded == 0) {
-            materializedValue = value;
-        } else {
-            // Interval is defined on multiple places -> no materialization is possible.
-            materializedValue = null;
-        }
-        numMaterializationValuesAdded++;
-    }
-
-    /**
-     * Returns true if this interval can be re-materialized when spilled. This means that no
-     * spill-moves are needed. Instead of restore-moves the {@link #materializedValue} is restored.
-     */
-    public boolean canMaterialize() {
-        return getMaterializedValue() != null;
-    }
-
-    /**
-     * Returns a value which can be moved to a register instead of a restore-move from stack.
-     */
-    public JavaConstant getMaterializedValue() {
-        return splitParent().materializedValue;
-    }
-
-    // consistency check of split-children
-    boolean checkSplitChildren() {
-        if (!splitChildren.isEmpty()) {
-            assert isSplitParent() : "only split parents can have children";
-
-            for (int i = 0; i < splitChildren.size(); i++) {
-                TraceInterval i1 = splitChildren.get(i);
-
-                assert i1.splitParent() == this : "not a split child of this interval";
-                assert i1.kind().equals(kind()) : "must be equal for all split children";
-                assert (i1.spillSlot() == null && spillSlot == null) || i1.spillSlot().equals(spillSlot()) : "must be equal for all split children";
-
-                for (int j = i + 1; j < splitChildren.size(); j++) {
-                    TraceInterval i2 = splitChildren.get(j);
-
-                    assert !i1.operand.equals(i2.operand) : "same register number";
-
-                    if (i1.from() < i2.from()) {
-                        assert i1.to() <= i2.from() && i1.to() < i2.to() : "intervals overlapping";
-                    } else {
-                        assert i2.from() < i1.from() : "intervals start at same opId";
-                        assert i2.to() <= i1.from() && i2.to() < i1.to() : "intervals overlapping";
-                    }
-                }
-            }
-        }
-
-        return true;
-    }
-
-    public IntervalHint locationHint(boolean searchSplitChild) {
-        if (!searchSplitChild) {
-            return locationHint;
-        }
-
-        if (locationHint != null) {
-            assert !(locationHint instanceof TraceInterval) || ((TraceInterval) locationHint).isSplitParent() : "ony split parents are valid hint registers";
-
-            if (locationHint.location() != null && isRegister(locationHint.location())) {
-                return locationHint;
-            } else if (locationHint instanceof TraceInterval) {
-                TraceInterval hint = (TraceInterval) locationHint;
-                if (!hint.splitChildren.isEmpty()) {
-                    // search the first split child that has a register assigned
-                    int len = hint.splitChildren.size();
-                    for (int i = 0; i < len; i++) {
-                        TraceInterval interval = hint.splitChildren.get(i);
-                        if (interval.location != null && isRegister(interval.location)) {
-                            return interval;
-                        }
-                    }
-                }
-            }
-        }
-
-        // no hint interval found that has a register assigned
-        return null;
-    }
-
-    TraceInterval getSplitChildAtOpId(int opId, LIRInstruction.OperandMode mode, TraceLinearScan allocator) {
-        assert isSplitParent() : "can only be called for split parents";
-        assert opId >= 0 : "invalid opId (method cannot be called for spill moves)";
-
-        if (splitChildren.isEmpty()) {
-            assert this.covers(opId, mode) : this + " does not cover " + opId;
-            return this;
-        } else {
-            TraceInterval result = null;
-            int len = splitChildren.size();
-
-            // in outputMode, the end of the interval (opId == cur.to()) is not valid
-            int toOffset = (mode == LIRInstruction.OperandMode.DEF ? 0 : 1);
-
-            int i;
-            for (i = 0; i < len; i++) {
-                TraceInterval cur = splitChildren.get(i);
-                if (cur.from() <= opId && opId < cur.to() + toOffset) {
-                    if (i > 0) {
-                        // exchange current split child to start of list (faster access for next
-                        // call)
-                        Util.atPutGrow(splitChildren, i, splitChildren.get(0), null);
-                        Util.atPutGrow(splitChildren, 0, cur, null);
-                    }
-
-                    // interval found
-                    result = cur;
-                    break;
-                }
-            }
-
-            assert checkSplitChild(result, opId, allocator, toOffset, mode);
-            return result;
-        }
-    }
-
-    private boolean checkSplitChild(TraceInterval result, int opId, TraceLinearScan allocator, int toOffset, LIRInstruction.OperandMode mode) {
-        if (result == null) {
-            // this is an error
-            StringBuilder msg = new StringBuilder(this.toString()).append(" has no child at ").append(opId);
-            if (!splitChildren.isEmpty()) {
-                TraceInterval firstChild = splitChildren.get(0);
-                TraceInterval lastChild = splitChildren.get(splitChildren.size() - 1);
-                msg.append(" (first = ").append(firstChild).append(", last = ").append(lastChild).append(")");
-            }
-            throw new JVMCIError("Linear Scan Error: %s", msg);
-        }
-
-        if (!splitChildren.isEmpty()) {
-            for (TraceInterval interval : splitChildren) {
-                if (interval != result && interval.from() <= opId && opId < interval.to() + toOffset) {
-                    TTY.println(String.format("two valid result intervals found for opId %d: %d and %d", opId, result.operandNumber, interval.operandNumber));
-                    TTY.println(result.logString(allocator));
-                    TTY.println(interval.logString(allocator));
-                    throw new BailoutException("two valid result intervals found");
-                }
-            }
-        }
-        assert result.covers(opId, mode) : "opId not covered by interval";
-        return true;
-    }
-
-    // returns the interval that covers the given opId or null if there is none
-    TraceInterval getIntervalCoveringOpId(int opId) {
-        assert opId >= 0 : "invalid opId";
-        assert opId < to() : "can only look into the past";
-
-        if (opId >= from()) {
-            return this;
-        }
-
-        TraceInterval parent = splitParent();
-        TraceInterval result = null;
-
-        assert !parent.splitChildren.isEmpty() : "no split children available";
-        int len = parent.splitChildren.size();
-
-        for (int i = len - 1; i >= 0; i--) {
-            TraceInterval cur = parent.splitChildren.get(i);
-            if (cur.from() <= opId && opId < cur.to()) {
-                assert result == null : "covered by multiple split children " + result + " and " + cur;
-                result = cur;
-            }
-        }
-
-        return result;
-    }
-
-    // returns the last split child that ends before the given opId
-    TraceInterval getSplitChildBeforeOpId(int opId) {
-        assert opId >= 0 : "invalid opId";
-
-        TraceInterval parent = splitParent();
-        TraceInterval result = null;
-
-        assert !parent.splitChildren.isEmpty() : "no split children available";
-        int len = parent.splitChildren.size();
-
-        for (int i = len - 1; i >= 0; i--) {
-            TraceInterval cur = parent.splitChildren.get(i);
-            if (cur.to() <= opId && (result == null || result.to() < cur.to())) {
-                result = cur;
-            }
-        }
-
-        assert result != null : "no split child found";
-        return result;
-    }
-
-    // checks if opId is covered by any split child
-    boolean splitChildCovers(int opId, LIRInstruction.OperandMode mode) {
-        assert isSplitParent() : "can only be called for split parents";
-        assert opId >= 0 : "invalid opId (method can not be called for spill moves)";
-
-        if (splitChildren.isEmpty()) {
-            // simple case if interval was not split
-            return covers(opId, mode);
-
-        } else {
-            // extended case: check all split children
-            int len = splitChildren.size();
-            for (int i = 0; i < len; i++) {
-                TraceInterval cur = splitChildren.get(i);
-                if (cur.covers(opId, mode)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
-
-    private RegisterPriority adaptPriority(RegisterPriority priority) {
-        /*
-         * In case of re-materialized values we require that use-operands are registers, because we
-         * don't have the value in a stack location. (Note that ShouldHaveRegister means that the
-         * operand can also be a StackSlot).
-         */
-        if (priority == RegisterPriority.ShouldHaveRegister && canMaterialize()) {
-            return RegisterPriority.MustHaveRegister;
-        }
-        return priority;
-    }
-
-    // Note: use positions are sorted descending . first use has highest index
-    int firstUsage(RegisterPriority minRegisterPriority) {
-        assert isVariable(operand) : "cannot access use positions for fixed intervals";
-
-        for (int i = usePosList.size() - 1; i >= 0; --i) {
-            RegisterPriority registerPriority = adaptPriority(usePosList.registerPriority(i));
-            if (registerPriority.greaterEqual(minRegisterPriority)) {
-                return usePosList.usePos(i);
-            }
-        }
-        return Integer.MAX_VALUE;
-    }
-
-    int nextUsage(RegisterPriority minRegisterPriority, int from) {
-        assert isVariable(operand) : "cannot access use positions for fixed intervals";
-
-        for (int i = usePosList.size() - 1; i >= 0; --i) {
-            int usePos = usePosList.usePos(i);
-            if (usePos >= from && adaptPriority(usePosList.registerPriority(i)).greaterEqual(minRegisterPriority)) {
-                return usePos;
-            }
-        }
-        return Integer.MAX_VALUE;
-    }
-
-    int nextUsageExact(RegisterPriority exactRegisterPriority, int from) {
-        assert isVariable(operand) : "cannot access use positions for fixed intervals";
-
-        for (int i = usePosList.size() - 1; i >= 0; --i) {
-            int usePos = usePosList.usePos(i);
-            if (usePos >= from && adaptPriority(usePosList.registerPriority(i)) == exactRegisterPriority) {
-                return usePos;
-            }
-        }
-        return Integer.MAX_VALUE;
-    }
-
-    int previousUsage(RegisterPriority minRegisterPriority, int from) {
-        assert isVariable(operand) : "cannot access use positions for fixed intervals";
-
-        int prev = -1;
-        for (int i = usePosList.size() - 1; i >= 0; --i) {
-            int usePos = usePosList.usePos(i);
-            if (usePos > from) {
-                return prev;
-            }
-            if (adaptPriority(usePosList.registerPriority(i)).greaterEqual(minRegisterPriority)) {
-                prev = usePos;
-            }
-        }
-        return prev;
-    }
-
-    public void addUsePos(int pos, RegisterPriority registerPriority) {
-        assert isEmpty() || covers(pos, LIRInstruction.OperandMode.USE) : String.format("use position %d not covered by live range of interval %s", pos, this);
-
-        // do not add use positions for precolored intervals because they are never used
-        if (registerPriority != RegisterPriority.None && isVariable(operand)) {
-            if (DetailedAsserts.getValue()) {
-                for (int i = 0; i < usePosList.size(); i++) {
-                    assert pos <= usePosList.usePos(i) : "already added a use-position with lower position";
-                    if (i > 0) {
-                        assert usePosList.usePos(i) < usePosList.usePos(i - 1) : "not sorted descending";
-                    }
-                }
-            }
-
-            // Note: addUse is called in descending order, so list gets sorted
-            // automatically by just appending new use positions
-            int len = usePosList.size();
-            if (len == 0 || usePosList.usePos(len - 1) > pos) {
-                usePosList.add(pos, registerPriority);
-            } else if (usePosList.registerPriority(len - 1).lessThan(registerPriority)) {
-                assert usePosList.usePos(len - 1) == pos : "list not sorted correctly";
-                usePosList.setRegisterPriority(len - 1, registerPriority);
-            }
-        }
-    }
-
-    public void addRange(int from, int to) {
-        assert from < to : "invalid range";
-
-        if (from < intFrom) {
-            setFrom(from);
-        }
-        if (intTo == Integer.MAX_VALUE || intTo < to) {
-            setTo(to);
-        }
-    }
-
-    TraceInterval newSplitChild(TraceLinearScan allocator) {
-        // allocate new interval
-        TraceInterval parent = splitParent();
-        TraceInterval result = allocator.createDerivedInterval(parent);
-        result.setKind(kind());
-
-        result.splitParent = parent;
-        result.setLocationHint(parent);
-
-        // insert new interval in children-list of parent
-        if (parent.splitChildren.isEmpty()) {
-            assert isSplitParent() : "list must be initialized at first split";
-
-            // Create new non-shared list
-            parent.splitChildren = new ArrayList<>(4);
-            parent.splitChildren.add(this);
-        }
-        parent.splitChildren.add(result);
-
-        return result;
-    }
-
-    /**
-     * Splits this interval at a specified position and returns the remainder as a new <i>child</i>
-     * interval of this interval's {@linkplain #splitParent() parent} interval.
-     * <p>
-     * When an interval is split, a bi-directional link is established between the original
-     * <i>parent</i> interval and the <i>children</i> intervals that are split off this interval.
-     * When a split child is split again, the new created interval is a direct child of the original
-     * parent. That is, there is no tree of split children stored, just a flat list. All split
-     * children are spilled to the same {@linkplain #spillSlot spill slot}.
-     *
-     * @param splitPos the position at which to split this interval
-     * @param allocator the register allocator context
-     * @return the child interval split off from this interval
-     */
-    TraceInterval split(int splitPos, TraceLinearScan allocator) {
-        assert isVariable(operand) : "cannot split fixed intervals";
-
-        // allocate new interval
-        TraceInterval result = newSplitChild(allocator);
-
-        // split the ranges
-        result.setTo(intTo);
-        result.setFrom(splitPos);
-        intTo = splitPos;
-
-        // split list of use positions
-        result.usePosList = usePosList.splitAt(splitPos);
-
-        if (DetailedAsserts.getValue()) {
-            for (int i = 0; i < usePosList.size(); i++) {
-                assert usePosList.usePos(i) < splitPos;
-            }
-            for (int i = 0; i < result.usePosList.size(); i++) {
-                assert result.usePosList.usePos(i) >= splitPos;
-            }
-        }
-        return result;
-    }
-
-    // returns true if the opId is inside the interval
-    boolean covers(int opId, LIRInstruction.OperandMode mode) {
-        if (mode == LIRInstruction.OperandMode.DEF) {
-            return from() <= opId && opId < to();
-        }
-        return from() <= opId && opId <= to();
-    }
-
-    @Override
-    public String toString() {
-        String from = "?";
-        String to = "?";
-        if (!isEmpty()) {
-            from = String.valueOf(from());
-            to = String.valueOf(to());
-        }
-        String locationString = this.location == null ? "" : "@" + this.location;
-        return operandNumber + ":" + operand + (isRegister(operand) ? "" : locationString) + "[" + from + "," + to + "]";
-    }
-
-    /**
-     * Gets the use position information for this interval.
-     */
-    public UsePosList usePosList() {
-        return usePosList;
-    }
-
-    /**
-     * Gets a single line string for logging the details of this interval to a log stream.
-     *
-     * @param allocator the register allocator context
-     */
-    @Override
-    public String logString(TraceLinearScan allocator) {
-        StringBuilder buf = new StringBuilder(100);
-        buf.append("any ").append(operandNumber).append(':').append(operand).append(' ');
-        if (!isRegister(operand)) {
-            if (location != null) {
-                buf.append("location{").append(location).append("} ");
-            }
-        }
-
-        buf.append("hints{").append(splitParent.operandNumber);
-        IntervalHint hint = locationHint(false);
-        if (hint != null) {
-            buf.append(", ").append(hint.location());
-        }
-        buf.append("} ranges{");
-
-        // print range
-        buf.append("[" + from() + ", " + to() + "]");
-        buf.append("} uses{");
-
-        // print use positions
-        int prev = -1;
-        for (int i = usePosList.size() - 1; i >= 0; --i) {
-            assert prev < usePosList.usePos(i) : "use positions not sorted";
-            if (i != usePosList.size() - 1) {
-                buf.append(", ");
-            }
-            buf.append(usePosList.usePos(i)).append(':').append(usePosList.registerPriority(i).shortName());
-            prev = usePosList.usePos(i);
-        }
-        buf.append("} spill-state{").append(spillState()).append("}");
-        if (canMaterialize()) {
-            buf.append(" (remat:").append(getMaterializedValue().toString()).append(")");
-        }
-        return buf.toString();
-    }
-
-    List<TraceInterval> getSplitChildren() {
-        return Collections.unmodifiableList(splitChildren);
-    }
-
-    boolean isFixedInterval() {
-        return isRegister(operand);
-    }
-
-    private static boolean isDefinitionPosition(int usePos) {
-        return (usePos & 1) == 1;
-    }
-
-    int currentFrom(int currentPosition) {
-        assert isFixedInterval();
-        for (int i = 0; i < usePosList.size(); i++) {
-            int usePos = usePosList.usePos(i);
-            if (usePos <= currentPosition && isDefinitionPosition(usePos)) {
-                return usePos;
-            }
-
-        }
-        return Integer.MAX_VALUE;
-    }
-
-    int currentIntersectsAt(int currentPosition, TraceInterval current) {
-        assert isFixedInterval();
-        assert !current.isFixedInterval();
-        int from = Integer.MAX_VALUE;
-        int to = Integer.MIN_VALUE;
-
-        for (int i = 0; i < usePosList.size(); i++) {
-            int usePos = usePosList.usePos(i);
-            if (isDefinitionPosition(usePos)) {
-                if (usePos <= currentPosition) {
-                    from = usePos;
-                    break;
-                }
-                to = Integer.MIN_VALUE;
-            } else {
-                if (to < usePos) {
-                    to = usePos;
-                }
-            }
-        }
-        if (from < current.from()) {
-            if (to <= current.from()) {
-                return -1;
-            }
-            return current.from();
-        } else {
-            if (current.to() <= from) {
-                return -1;
-            }
-            return from;
-        }
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceIntervalDumper.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, 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.alloc.trace;
-
-import static jdk.vm.ci.code.ValueUtil.isRegister;
-import jdk.vm.ci.meta.AllocatableValue;
-import jdk.vm.ci.meta.Value;
-
-import com.oracle.graal.lir.debug.IntervalDumper;
-
-final class TraceIntervalDumper implements IntervalDumper {
-    private final FixedInterval[] fixedIntervals;
-    private final TraceInterval[] intervals;
-
-    public TraceIntervalDumper(FixedInterval[] fixedIntervals, TraceInterval[] intervals) {
-        this.fixedIntervals = fixedIntervals;
-        this.intervals = intervals;
-    }
-
-    public void visitIntervals(IntervalVisitor visitor) {
-        for (FixedInterval interval : fixedIntervals) {
-            if (interval != null) {
-                printFixedInterval(interval, visitor);
-            }
-        }
-        for (TraceInterval interval : intervals) {
-            if (interval != null) {
-                printInterval(interval, visitor);
-            }
-        }
-    }
-
-    private static void printFixedInterval(FixedInterval interval, IntervalVisitor visitor) {
-        Value hint = null;
-        AllocatableValue operand = interval.operand;
-        String type = "fixed";
-        char typeChar = operand.getPlatformKind().getTypeChar();
-        visitor.visitIntervalStart(operand, operand, operand, hint, type, typeChar);
-
-        // print ranges
-        for (FixedRange range = interval.first(); range != FixedRange.EndMarker; range = range.next) {
-            visitor.visitRange(range.from, range.to);
-        }
-
-        // no use positions
-
-        visitor.visitIntervalEnd("NOT_SUPPORTED");
-
-    }
-
-    private static void printInterval(TraceInterval interval, IntervalVisitor visitor) {
-        Value hint = interval.locationHint(false) != null ? interval.locationHint(false).location() : null;
-        AllocatableValue operand = interval.operand;
-        String type = isRegister(operand) ? "fixed" : operand.getLIRKind().getPlatformKind().toString();
-        char typeChar = operand.getPlatformKind().getTypeChar();
-        visitor.visitIntervalStart(interval.splitParent().operand, operand, interval.location(), hint, type, typeChar);
-
-        // print ranges
-        visitor.visitRange(interval.from(), interval.to());
-
-        // print use positions
-        int prev = -1;
-        UsePosList usePosList = interval.usePosList();
-        for (int i = usePosList.size() - 1; i >= 0; --i) {
-            assert prev < usePosList.usePos(i) : "use positions not sorted";
-            visitor.visitUsePos(usePosList.usePos(i), usePosList.registerPriority(i));
-            prev = usePosList.usePos(i);
-        }
-
-        visitor.visitIntervalEnd(interval.spillState());
-    }
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceIntervalWalker.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,323 +0,0 @@
-/*
- * Copyright (c) 2009, 2015, 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.alloc.trace;
-
-import jdk.vm.ci.common.JVMCIError;
-
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.Indent;
-import com.oracle.graal.lir.alloc.trace.FixedInterval.FixedList;
-import com.oracle.graal.lir.alloc.trace.TraceInterval.AnyList;
-import com.oracle.graal.lir.alloc.trace.TraceInterval.RegisterBinding;
-import com.oracle.graal.lir.alloc.trace.TraceInterval.State;
-
-/**
- */
-class TraceIntervalWalker {
-
-    protected final TraceLinearScan allocator;
-
-    /**
-     * Sorted list of intervals, not live before the current position.
-     */
-    protected AnyList unhandledAnyList;
-
-    /**
-     * Sorted list of intervals, live at the current position.
-     */
-    protected AnyList activeAnyList;
-    protected FixedList activeFixedList;
-
-    /**
-     * Sorted list of intervals in a life time hole at the current position.
-     */
-    protected FixedList inactiveFixedList;
-
-    /**
-     * The current position (intercept point through the intervals).
-     */
-    protected int currentPosition;
-
-    /**
-     * Processes the {@code currentInterval} interval in an attempt to allocate a physical register
-     * to it and thus allow it to be moved to a list of {@linkplain #activeAnyList active}
-     * intervals.
-     *
-     * @param currentInterval The interval to be activated.
-     *
-     * @return {@code true} if a register was allocated to the {@code currentInterval} interval
-     */
-    protected boolean activateCurrent(TraceInterval currentInterval) {
-        if (Debug.isLogEnabled()) {
-            logCurrentStatus();
-        }
-        return true;
-    }
-
-    @SuppressWarnings("try")
-    protected void logCurrentStatus() {
-        try (Indent i = Debug.logAndIndent("active:")) {
-            logList(activeFixedList.getFixed());
-            logList(activeAnyList.getAny());
-        }
-        try (Indent i = Debug.logAndIndent("inactive(fixed):")) {
-            logList(inactiveFixedList.getFixed());
-        }
-    }
-
-    private void logList(FixedInterval i) {
-        for (FixedInterval interval = i; interval != FixedInterval.EndMarker; interval = interval.next) {
-            Debug.log("%s", interval.logString(allocator));
-        }
-    }
-
-    private void logList(TraceInterval i) {
-        for (TraceInterval interval = i; interval != TraceInterval.EndMarker; interval = interval.next) {
-            Debug.log("%s", interval.logString(allocator));
-        }
-    }
-
-    void walkBefore(int lirOpId) {
-        walkTo(lirOpId - 1);
-    }
-
-    void walk() {
-        walkTo(Integer.MAX_VALUE);
-    }
-
-    /**
-     * Creates a new interval walker.
-     *
-     * @param allocator the register allocator context
-     * @param unhandledFixed the list of unhandled {@linkplain RegisterBinding#Fixed fixed}
-     *            intervals
-     * @param unhandledAny the list of unhandled {@linkplain RegisterBinding#Any non-fixed}
-     *            intervals
-     */
-    TraceIntervalWalker(TraceLinearScan allocator, FixedInterval unhandledFixed, TraceInterval unhandledAny) {
-        this.allocator = allocator;
-
-        unhandledAnyList = new AnyList(unhandledAny);
-        activeAnyList = new AnyList(TraceInterval.EndMarker);
-        activeFixedList = new FixedList(FixedInterval.EndMarker);
-        // we don't need a separate unhandled list for fixed.
-        inactiveFixedList = new FixedList(unhandledFixed);
-        currentPosition = -1;
-    }
-
-    protected void removeFromList(TraceInterval interval) {
-        if (interval.state == State.Active) {
-            activeAnyList.removeAny(interval);
-        } else {
-            assert interval.state == State.Inactive : "invalid state";
-            // inactiveAnyLists.removeAny(interval);
-            throw JVMCIError.shouldNotReachHere();
-        }
-    }
-
-    /**
-     * Walks up to {@code from} and updates the state of {@link FixedInterval fixed intervals}.
-     *
-     * Fixed intervals can switch back and forth between the states {@link State#Active} and
-     * {@link State#Inactive} (and eventually to {@link State#Handled} but handled intervals are not
-     * managed).
-     */
-    @SuppressWarnings("try")
-    private void walkToFixed(State state, int from) {
-        assert state == State.Active || state == State.Inactive : "wrong state";
-        FixedInterval prevprev = null;
-        FixedInterval prev = (state == State.Active) ? activeFixedList.getFixed() : inactiveFixedList.getFixed();
-        FixedInterval next = prev;
-        if (Debug.isLogEnabled()) {
-            try (Indent i = Debug.logAndIndent("walkToFixed(%s, %d):", state, from)) {
-                logList(next);
-            }
-        }
-        while (next.currentFrom() <= from) {
-            FixedInterval cur = next;
-            next = cur.next;
-
-            boolean rangeHasChanged = false;
-            while (cur.currentTo() <= from) {
-                cur.nextRange();
-                rangeHasChanged = true;
-            }
-
-            // also handle move from inactive list to active list
-            rangeHasChanged = rangeHasChanged || (state == State.Inactive && cur.currentFrom() <= from);
-
-            if (rangeHasChanged) {
-                // remove cur from list
-                if (prevprev == null) {
-                    if (state == State.Active) {
-                        activeFixedList.setFixed(next);
-                    } else {
-                        inactiveFixedList.setFixed(next);
-                    }
-                } else {
-                    prevprev.next = next;
-                }
-                prev = next;
-                TraceInterval.State newState;
-                if (cur.currentAtEnd()) {
-                    // move to handled state (not maintained as a list)
-                    newState = State.Handled;
-                } else {
-                    if (cur.currentFrom() <= from) {
-                        // sort into active list
-                        activeFixedList.addToListSortedByCurrentFromPositions(cur);
-                        newState = State.Active;
-                    } else {
-                        // sort into inactive list
-                        inactiveFixedList.addToListSortedByCurrentFromPositions(cur);
-                        newState = State.Inactive;
-                    }
-                    if (prev == cur) {
-                        assert state == newState;
-                        prevprev = prev;
-                        prev = cur.next;
-                    }
-                }
-                intervalMoved(cur, state, newState);
-            } else {
-                prevprev = prev;
-                prev = cur.next;
-            }
-        }
-    }
-
-    /**
-     * Walks up to {@code from} and updates the state of {@link TraceInterval intervals}.
-     *
-     * Trace intervals can switch once from {@link State#Unhandled} to {@link State#Active} and then
-     * to {@link State#Handled} but handled intervals are not managed.
-     */
-    @SuppressWarnings("try")
-    private void walkToAny(int from) {
-        TraceInterval prevprev = null;
-        TraceInterval prev = activeAnyList.getAny();
-        TraceInterval next = prev;
-        if (Debug.isLogEnabled()) {
-            try (Indent i = Debug.logAndIndent("walkToAny(%d):", from)) {
-                logList(next);
-            }
-        }
-        while (next.from() <= from) {
-            TraceInterval cur = next;
-            next = cur.next;
-
-            if (cur.to() <= from) {
-                // remove cur from list
-                if (prevprev == null) {
-                    activeAnyList.setAny(next);
-                } else {
-                    prevprev.next = next;
-                }
-                intervalMoved(cur, State.Active, State.Handled);
-            } else {
-                prevprev = prev;
-            }
-            prev = next;
-        }
-    }
-
-    /**
-     * Get the next interval from {@linkplain #unhandledAnyList} which starts before or at
-     * {@code toOpId}. The returned interval is removed.
-     *
-     * @postcondition all intervals in {@linkplain #unhandledAnyList} start after {@code toOpId}.
-     *
-     * @return The next interval or null if there is no {@linkplain #unhandledAnyList unhandled}
-     *         interval at position {@code toOpId}.
-     */
-    private TraceInterval nextInterval(int toOpId) {
-        TraceInterval any = unhandledAnyList.getAny();
-
-        if (any != TraceInterval.EndMarker) {
-            TraceInterval currentInterval = unhandledAnyList.getAny();
-            if (toOpId < currentInterval.from()) {
-                return null;
-            }
-
-            unhandledAnyList.setAny(currentInterval.next);
-            currentInterval.next = TraceInterval.EndMarker;
-            return currentInterval;
-        }
-        return null;
-
-    }
-
-    /**
-     * Walk up to {@code toOpId}.
-     *
-     * @postcondition {@link #currentPosition} is set to {@code toOpId}, {@link #activeFixedList}
-     *                and {@link #inactiveFixedList} are populated and {@link TraceInterval#state}s
-     *                are up to date.
-     */
-    @SuppressWarnings("try")
-    protected void walkTo(int toOpId) {
-        assert currentPosition <= toOpId : "can not walk backwards";
-        for (TraceInterval currentInterval = nextInterval(toOpId); currentInterval != null; currentInterval = nextInterval(toOpId)) {
-            int opId = currentInterval.from();
-
-            // set currentPosition prior to call of walkTo
-            currentPosition = opId;
-
-            // update unhandled stack intervals
-            // updateUnhandledStackIntervals(opId);
-
-            // call walkTo even if currentPosition == id
-            walkToFixed(State.Active, opId);
-            walkToFixed(State.Inactive, opId);
-            walkToAny(opId);
-
-            try (Indent indent = Debug.logAndIndent("walk to op %d", opId)) {
-                currentInterval.state = State.Active;
-                if (activateCurrent(currentInterval)) {
-                    activeAnyList.addToListSortedByFromPositions(currentInterval);
-                    intervalMoved(currentInterval, State.Unhandled, State.Active);
-                }
-            }
-        }
-        // set currentPosition prior to call of walkTo
-        currentPosition = toOpId;
-
-        if (currentPosition <= allocator.maxOpId()) {
-            // update unhandled stack intervals
-            // updateUnhandledStackIntervals(toOpId);
-
-            // call walkTo if still in range
-            walkToFixed(State.Active, toOpId);
-            walkToFixed(State.Inactive, toOpId);
-            walkToAny(toOpId);
-        }
-    }
-
-    private void intervalMoved(IntervalHint interval, State from, State to) {
-        // intervalMoved() is called whenever an interval moves from one interval list to another.
-        // In the implementation of this method it is prohibited to move the interval to any list.
-        if (Debug.isLogEnabled()) {
-            Debug.log("interval moved from %s to %s: %s", from, to, interval.logString(allocator));
-        }
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScan.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1012 +0,0 @@
-/*
- * Copyright (c) 2009, 2015, 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.alloc.trace;
-
-import static com.oracle.graal.compiler.common.GraalOptions.DetailedAsserts;
-import static com.oracle.graal.lir.LIRValueUtil.isVariable;
-import static jdk.vm.ci.code.CodeUtil.isEven;
-import static jdk.vm.ci.code.ValueUtil.asRegister;
-import static jdk.vm.ci.code.ValueUtil.asRegisterValue;
-import static jdk.vm.ci.code.ValueUtil.isIllegal;
-import static jdk.vm.ci.code.ValueUtil.isLegal;
-import static jdk.vm.ci.code.ValueUtil.isRegister;
-
-import java.util.Arrays;
-import java.util.BitSet;
-import java.util.EnumSet;
-import java.util.List;
-
-import jdk.vm.ci.code.BailoutException;
-import jdk.vm.ci.code.Register;
-import jdk.vm.ci.code.RegisterAttributes;
-import jdk.vm.ci.code.RegisterValue;
-import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.meta.AllocatableValue;
-import jdk.vm.ci.meta.LIRKind;
-import jdk.vm.ci.meta.Value;
-import jdk.vm.ci.options.NestedBooleanOptionValue;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
-
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
-import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
-import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
-import com.oracle.graal.compiler.common.cfg.BlockMap;
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.debug.Indent;
-import com.oracle.graal.lir.LIR;
-import com.oracle.graal.lir.LIRInstruction;
-import com.oracle.graal.lir.LIRInstruction.OperandFlag;
-import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.ValueConsumer;
-import com.oracle.graal.lir.Variable;
-import com.oracle.graal.lir.VirtualStackSlot;
-import com.oracle.graal.lir.alloc.trace.TraceLinearScanAllocationPhase.TraceLinearScanAllocationContext;
-import com.oracle.graal.lir.framemap.FrameMapBuilder;
-import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
-import com.oracle.graal.lir.phases.LIRPhase;
-
-/**
- * An implementation of the linear scan register allocator algorithm described in <a
- * href="http://doi.acm.org/10.1145/1064979.1064998"
- * >"Optimized Interval Splitting in a Linear Scan Register Allocator"</a> by Christian Wimmer and
- * Hanspeter Moessenboeck.
- */
-final class TraceLinearScan {
-
-    public static class Options {
-        // @formatter:off
-        @Option(help = "Enable spill position optimization", type = OptionType.Debug)
-        public static final OptionValue<Boolean> LIROptTraceRAEliminateSpillMoves = new NestedBooleanOptionValue(LIRPhase.Options.LIROptimization, true);
-        // @formatter:on
-    }
-
-    private static final TraceLinearScanRegisterAllocationPhase TRACE_LINEAR_SCAN_REGISTER_ALLOCATION_PHASE = new TraceLinearScanRegisterAllocationPhase();
-    private static final TraceLinearScanAssignLocationsPhase TRACE_LINEAR_SCAN_ASSIGN_LOCATIONS_PHASE = new TraceLinearScanAssignLocationsPhase();
-    private static final TraceLinearScanEliminateSpillMovePhase TRACE_LINEAR_SCAN_ELIMINATE_SPILL_MOVE_PHASE = new TraceLinearScanEliminateSpillMovePhase();
-    private static final TraceLinearScanResolveDataFlowPhase TRACE_LINEAR_SCAN_RESOLVE_DATA_FLOW_PHASE = new TraceLinearScanResolveDataFlowPhase();
-    private static final TraceLinearScanLifetimeAnalysisPhase TRACE_LINEAR_SCAN_LIFETIME_ANALYSIS_PHASE = new TraceLinearScanLifetimeAnalysisPhase();
-
-    public static class BlockData {
-
-        /**
-         * Bit map specifying which operands are live upon entry to this block. These are values
-         * used in this block or any of its successors where such value are not defined in this
-         * block. The bit index of an operand is its
-         * {@linkplain TraceLinearScan#operandNumber(Value) operand number}.
-         */
-        public BitSet liveIn;
-
-        /**
-         * Bit map specifying which operands are live upon exit from this block. These are values
-         * used in a successor block that are either defined in this block or were live upon entry
-         * to this block. The bit index of an operand is its
-         * {@linkplain TraceLinearScan#operandNumber(Value) operand number}.
-         */
-        public BitSet liveOut;
-
-        /**
-         * Bit map specifying which operands are used (before being defined) in this block. That is,
-         * these are the values that are live upon entry to the block. The bit index of an operand
-         * is its {@linkplain TraceLinearScan#operandNumber(Value) operand number}.
-         */
-        public BitSet liveGen;
-
-        /**
-         * Bit map specifying which operands are defined/overwritten in this block. The bit index of
-         * an operand is its {@linkplain TraceLinearScan#operandNumber(Value) operand number}.
-         */
-        public BitSet liveKill;
-    }
-
-    public static final int DOMINATOR_SPILL_MOVE_ID = -2;
-    private static final int SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT = 1;
-
-    private final LIR ir;
-    private final FrameMapBuilder frameMapBuilder;
-    private final RegisterAttributes[] registerAttributes;
-    private final Register[] registers;
-    private final RegisterAllocationConfig regAllocConfig;
-    private final MoveFactory moveFactory;
-
-    private final BlockMap<BlockData> blockData;
-
-    /**
-     * List of blocks in linear-scan order. This is only correct as long as the CFG does not change.
-     */
-    private final List<? extends AbstractBlockBase<?>> sortedBlocks;
-
-    /** @see #fixedIntervals() */
-    private final FixedInterval[] fixedIntervals;
-
-    /** @see #intervals() */
-    private TraceInterval[] intervals;
-
-    /**
-     * The number of valid entries in {@link #intervals}.
-     */
-    private int intervalsSize;
-
-    /**
-     * The index of the first entry in {@link #intervals} for a
-     * {@linkplain #createDerivedInterval(TraceInterval) derived interval}.
-     */
-    private int firstDerivedIntervalIndex = -1;
-
-    /**
-     * Intervals sorted by {@link TraceInterval#from()}.
-     */
-    private TraceInterval[] sortedIntervals;
-
-    /**
-     * Fixed intervals sorted by {@link FixedInterval#from()}.
-     */
-    private FixedInterval[] sortedFixedIntervals;
-
-    /**
-     * Map from an instruction {@linkplain LIRInstruction#id id} to the instruction. Entries should
-     * be retrieved with {@link #instructionForId(int)} as the id is not simply an index into this
-     * array.
-     */
-    private LIRInstruction[] opIdToInstructionMap;
-
-    /**
-     * Map from an instruction {@linkplain LIRInstruction#id id} to the
-     * {@linkplain AbstractBlockBase block} containing the instruction. Entries should be retrieved
-     * with {@link #blockForId(int)} as the id is not simply an index into this array.
-     */
-    private AbstractBlockBase<?>[] opIdToBlockMap;
-
-    protected final TraceBuilderResult<?> traceBuilderResult;
-    private final boolean neverSpillConstants;
-
-    protected TraceLinearScan(TargetDescription target, LIRGenerationResult res, MoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig,
-                    List<? extends AbstractBlockBase<?>> sortedBlocks, TraceBuilderResult<?> traceBuilderResult, boolean neverSpillConstants) {
-        this.ir = res.getLIR();
-        this.moveFactory = spillMoveFactory;
-        this.frameMapBuilder = res.getFrameMapBuilder();
-        this.sortedBlocks = sortedBlocks;
-        this.registerAttributes = regAllocConfig.getRegisterConfig().getAttributesMap();
-        this.regAllocConfig = regAllocConfig;
-
-        this.registers = target.arch.getRegisters();
-        this.fixedIntervals = new FixedInterval[registers.length];
-        this.blockData = new BlockMap<>(ir.getControlFlowGraph());
-        this.traceBuilderResult = traceBuilderResult;
-        this.neverSpillConstants = neverSpillConstants;
-    }
-
-    public int getFirstLirInstructionId(AbstractBlockBase<?> block) {
-        int result = ir.getLIRforBlock(block).get(0).id();
-        assert result >= 0;
-        return result;
-    }
-
-    public int getLastLirInstructionId(AbstractBlockBase<?> block) {
-        List<LIRInstruction> instructions = ir.getLIRforBlock(block);
-        int result = instructions.get(instructions.size() - 1).id();
-        assert result >= 0;
-        return result;
-    }
-
-    public MoveFactory getSpillMoveFactory() {
-        return moveFactory;
-    }
-
-    protected TraceLocalMoveResolver createMoveResolver() {
-        TraceLocalMoveResolver moveResolver = new TraceLocalMoveResolver(this);
-        assert moveResolver.checkEmpty();
-        return moveResolver;
-    }
-
-    public static boolean isVariableOrRegister(Value value) {
-        return isVariable(value) || isRegister(value);
-    }
-
-    /**
-     * Converts an operand (variable or register) to an index in a flat address space covering all
-     * the {@linkplain Variable variables} and {@linkplain RegisterValue registers} being processed
-     * by this allocator.
-     */
-    @SuppressWarnings("static-method")
-    int operandNumber(Value operand) {
-        assert !isRegister(operand) : "Register do not have operand numbers: " + operand;
-        assert isVariable(operand) : "Unsupported Value " + operand;
-        return ((Variable) operand).index;
-    }
-
-    /**
-     * Gets the number of operands. This value will increase by 1 for new variable.
-     */
-    int operandSize() {
-        return ir.numVariables();
-    }
-
-    /**
-     * Gets the number of registers. This value will never change.
-     */
-    int numRegisters() {
-        return registers.length;
-    }
-
-    public BlockData getBlockData(AbstractBlockBase<?> block) {
-        return blockData.get(block);
-    }
-
-    void initBlockData(AbstractBlockBase<?> block) {
-        blockData.put(block, new BlockData());
-    }
-
-    static final IntervalPredicate IS_PRECOLORED_INTERVAL = new IntervalPredicate() {
-
-        @Override
-        public boolean apply(TraceInterval i) {
-            return isRegister(i.operand);
-        }
-    };
-
-    static final IntervalPredicate IS_VARIABLE_INTERVAL = new IntervalPredicate() {
-
-        @Override
-        public boolean apply(TraceInterval i) {
-            return isVariable(i.operand);
-        }
-    };
-
-    static final IntervalPredicate IS_STACK_INTERVAL = new IntervalPredicate() {
-
-        @Override
-        public boolean apply(TraceInterval i) {
-            return !isRegister(i.operand);
-        }
-    };
-
-    /**
-     * Gets an object describing the attributes of a given register according to this register
-     * configuration.
-     */
-    public RegisterAttributes attributes(Register reg) {
-        return registerAttributes[reg.number];
-    }
-
-    void assignSpillSlot(TraceInterval interval) {
-        /*
-         * Assign the canonical spill slot of the parent (if a part of the interval is already
-         * spilled) or allocate a new spill slot.
-         */
-        if (interval.canMaterialize()) {
-            interval.assignLocation(Value.ILLEGAL);
-        } else if (interval.spillSlot() != null) {
-            interval.assignLocation(interval.spillSlot());
-        } else {
-            VirtualStackSlot slot = frameMapBuilder.allocateSpillSlot(interval.kind());
-            interval.setSpillSlot(slot);
-            interval.assignLocation(slot);
-        }
-    }
-
-    /**
-     * Map from {@linkplain #operandNumber(Value) operand numbers} to intervals.
-     */
-    public TraceInterval[] intervals() {
-        return intervals;
-    }
-
-    /**
-     * Map from {@linkplain #operandNumber(Value) operand numbers} to intervals.
-     */
-    public FixedInterval[] fixedIntervals() {
-        return fixedIntervals;
-    }
-
-    void initIntervals() {
-        intervalsSize = operandSize();
-        intervals = new TraceInterval[intervalsSize + (intervalsSize >> SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT)];
-    }
-
-    /**
-     * Creates a new fixed interval.
-     *
-     * @param reg the operand for the interval
-     * @return the created interval
-     */
-    FixedInterval createFixedInterval(RegisterValue reg) {
-        FixedInterval interval = new FixedInterval(reg);
-        int operandNumber = reg.getRegister().number;
-        assert fixedIntervals[operandNumber] == null;
-        fixedIntervals[operandNumber] = interval;
-        return interval;
-    }
-
-    /**
-     * Creates a new interval.
-     *
-     * @param operand the operand for the interval
-     * @return the created interval
-     */
-    TraceInterval createInterval(AllocatableValue operand) {
-        assert isLegal(operand);
-        int operandNumber = operandNumber(operand);
-        TraceInterval interval = new TraceInterval(operand, operandNumber);
-        assert operandNumber < intervalsSize;
-        assert intervals[operandNumber] == null;
-        intervals[operandNumber] = interval;
-        return interval;
-    }
-
-    /**
-     * Creates an interval as a result of splitting or spilling another interval.
-     *
-     * @param source an interval being split of spilled
-     * @return a new interval derived from {@code source}
-     */
-    TraceInterval createDerivedInterval(TraceInterval source) {
-        if (firstDerivedIntervalIndex == -1) {
-            firstDerivedIntervalIndex = intervalsSize;
-        }
-        if (intervalsSize == intervals.length) {
-            intervals = Arrays.copyOf(intervals, intervals.length + (intervals.length >> SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT));
-        }
-        intervalsSize++;
-        Variable variable = new Variable(source.kind(), ir.nextVariable());
-
-        TraceInterval interval = createInterval(variable);
-        assert intervals[intervalsSize - 1] == interval;
-        return interval;
-    }
-
-    // access to block list (sorted in linear scan order)
-    public int blockCount() {
-        return sortedBlocks.size();
-    }
-
-    public AbstractBlockBase<?> blockAt(int index) {
-        return sortedBlocks.get(index);
-    }
-
-    /**
-     * Gets the size of the {@link BlockData#liveIn} and {@link BlockData#liveOut} sets for a basic
-     * block. These sets do not include any operands allocated as a result of creating
-     * {@linkplain #createDerivedInterval(TraceInterval) derived intervals}.
-     */
-    public int liveSetSize() {
-        return firstDerivedIntervalIndex == -1 ? operandSize() : firstDerivedIntervalIndex;
-    }
-
-    int numLoops() {
-        return ir.getControlFlowGraph().getLoops().size();
-    }
-
-    public FixedInterval fixedIntervalFor(RegisterValue reg) {
-        return fixedIntervals[reg.getRegister().number];
-    }
-
-    public FixedInterval getOrCreateFixedInterval(RegisterValue reg) {
-        FixedInterval ret = fixedIntervalFor(reg);
-        if (ret == null) {
-            return createFixedInterval(reg);
-        } else {
-            return ret;
-        }
-    }
-
-    TraceInterval intervalFor(int operandNumber) {
-        return intervals[operandNumber];
-    }
-
-    public TraceInterval intervalFor(Value operand) {
-        int operandNumber = operandNumber(operand);
-        assert operandNumber < intervalsSize;
-        return intervals[operandNumber];
-    }
-
-    public TraceInterval getOrCreateInterval(AllocatableValue operand) {
-        TraceInterval ret = intervalFor(operand);
-        if (ret == null) {
-            return createInterval(operand);
-        } else {
-            return ret;
-        }
-    }
-
-    void initOpIdMaps(int numInstructions) {
-        opIdToInstructionMap = new LIRInstruction[numInstructions];
-        opIdToBlockMap = new AbstractBlockBase<?>[numInstructions];
-    }
-
-    void putOpIdMaps(int index, LIRInstruction op, AbstractBlockBase<?> block) {
-        opIdToInstructionMap[index] = op;
-        opIdToBlockMap[index] = block;
-    }
-
-    /**
-     * Gets the highest instruction id allocated by this object.
-     */
-    int maxOpId() {
-        assert opIdToInstructionMap.length > 0 : "no operations";
-        return (opIdToInstructionMap.length - 1) << 1;
-    }
-
-    /**
-     * Converts an {@linkplain LIRInstruction#id instruction id} to an instruction index. All LIR
-     * instructions in a method have an index one greater than their linear-scan order predecessor
-     * with the first instruction having an index of 0.
-     */
-    private static int opIdToIndex(int opId) {
-        return opId >> 1;
-    }
-
-    /**
-     * Retrieves the {@link LIRInstruction} based on its {@linkplain LIRInstruction#id id}.
-     *
-     * @param opId an instruction {@linkplain LIRInstruction#id id}
-     * @return the instruction whose {@linkplain LIRInstruction#id} {@code == id}
-     */
-    public LIRInstruction instructionForId(int opId) {
-        assert isEven(opId) : "opId not even";
-        LIRInstruction instr = opIdToInstructionMap[opIdToIndex(opId)];
-        assert instr.id() == opId;
-        return instr;
-    }
-
-    /**
-     * Gets the block containing a given instruction.
-     *
-     * @param opId an instruction {@linkplain LIRInstruction#id id}
-     * @return the block containing the instruction denoted by {@code opId}
-     */
-    public AbstractBlockBase<?> blockForId(int opId) {
-        assert opIdToBlockMap.length > 0 && opId >= 0 && opId <= maxOpId() + 1 : "opId out of range: " + opId;
-        return opIdToBlockMap[opIdToIndex(opId)];
-    }
-
-    boolean isBlockBegin(int opId) {
-        return opId == 0 || blockForId(opId) != blockForId(opId - 1);
-    }
-
-    boolean coversBlockBegin(int opId1, int opId2) {
-        return blockForId(opId1) != blockForId(opId2);
-    }
-
-    /**
-     * Determines if an {@link LIRInstruction} destroys all caller saved registers.
-     *
-     * @param opId an instruction {@linkplain LIRInstruction#id id}
-     * @return {@code true} if the instruction denoted by {@code id} destroys all caller saved
-     *         registers.
-     */
-    boolean hasCall(int opId) {
-        assert isEven(opId) : "opId not even";
-        return instructionForId(opId).destroysCallerSavedRegisters();
-    }
-
-    abstract static class IntervalPredicate {
-
-        abstract boolean apply(TraceInterval i);
-    }
-
-    public boolean isProcessed(Value operand) {
-        return !isRegister(operand) || attributes(asRegister(operand)).isAllocatable();
-    }
-
-    // * Phase 5: actual register allocation
-
-    private static <T extends IntervalHint> boolean isSorted(T[] intervals) {
-        int from = -1;
-        for (T interval : intervals) {
-            assert interval != null;
-            assert from <= interval.from();
-            from = interval.from();
-        }
-        return true;
-    }
-
-    private static TraceInterval addToList(TraceInterval first, TraceInterval prev, TraceInterval interval) {
-        TraceInterval newFirst = first;
-        if (prev != null) {
-            prev.next = interval;
-        } else {
-            newFirst = interval;
-        }
-        return newFirst;
-    }
-
-    TraceInterval createUnhandledList(IntervalPredicate isList1) {
-        assert isSorted(sortedIntervals) : "interval list is not sorted";
-
-        TraceInterval list1 = TraceInterval.EndMarker;
-
-        TraceInterval list1Prev = null;
-        TraceInterval v;
-
-        int n = sortedIntervals.length;
-        for (int i = 0; i < n; i++) {
-            v = sortedIntervals[i];
-            if (v == null) {
-                continue;
-            }
-
-            if (isList1.apply(v)) {
-                list1 = addToList(list1, list1Prev, v);
-                list1Prev = v;
-            }
-        }
-
-        if (list1Prev != null) {
-            list1Prev.next = TraceInterval.EndMarker;
-        }
-
-        assert list1Prev == null || list1Prev.next == TraceInterval.EndMarker : "linear list ends not with sentinel";
-
-        return list1;
-    }
-
-    private static FixedInterval addToList(FixedInterval first, FixedInterval prev, FixedInterval interval) {
-        FixedInterval newFirst = first;
-        if (prev != null) {
-            prev.next = interval;
-        } else {
-            newFirst = interval;
-        }
-        return newFirst;
-    }
-
-    FixedInterval createFixedUnhandledList() {
-        assert isSorted(sortedFixedIntervals) : "interval list is not sorted";
-
-        FixedInterval list1 = FixedInterval.EndMarker;
-
-        FixedInterval list1Prev = null;
-        FixedInterval v;
-
-        int n = sortedFixedIntervals.length;
-        for (int i = 0; i < n; i++) {
-            v = sortedFixedIntervals[i];
-            if (v == null) {
-                continue;
-            }
-
-            v.rewindRange();
-            list1 = addToList(list1, list1Prev, v);
-            list1Prev = v;
-        }
-
-        if (list1Prev != null) {
-            list1Prev.next = FixedInterval.EndMarker;
-        }
-
-        assert list1Prev == null || list1Prev.next == FixedInterval.EndMarker : "linear list ends not with sentinel";
-
-        return list1;
-    }
-
-    // SORTING
-
-    protected void sortIntervalsBeforeAllocation() {
-        int sortedLen = 0;
-        for (TraceInterval interval : intervals) {
-            if (interval != null) {
-                sortedLen++;
-            }
-        }
-        sortedIntervals = sortIntervalsBeforeAllocation(intervals, new TraceInterval[sortedLen]);
-    }
-
-    protected void sortFixedIntervalsBeforeAllocation() {
-        int sortedLen = 0;
-        for (FixedInterval interval : fixedIntervals) {
-            if (interval != null) {
-                sortedLen++;
-            }
-        }
-        sortedFixedIntervals = sortIntervalsBeforeAllocation(fixedIntervals, new FixedInterval[sortedLen]);
-    }
-
-    private static <T extends IntervalHint> T[] sortIntervalsBeforeAllocation(T[] intervals, T[] sortedList) {
-        int sortedIdx = 0;
-        int sortedFromMax = -1;
-
-        // special sorting algorithm: the original interval-list is almost sorted,
-        // only some intervals are swapped. So this is much faster than a complete QuickSort
-        for (T interval : intervals) {
-            if (interval != null) {
-                int from = interval.from();
-
-                if (sortedFromMax <= from) {
-                    sortedList[sortedIdx++] = interval;
-                    sortedFromMax = interval.from();
-                } else {
-                    // the assumption that the intervals are already sorted failed,
-                    // so this interval must be sorted in manually
-                    int j;
-                    for (j = sortedIdx - 1; j >= 0 && from < sortedList[j].from(); j--) {
-                        sortedList[j + 1] = sortedList[j];
-                    }
-                    sortedList[j + 1] = interval;
-                    sortedIdx++;
-                }
-            }
-        }
-        return sortedList;
-    }
-
-    void sortIntervalsAfterAllocation() {
-        if (firstDerivedIntervalIndex == -1) {
-            // no intervals have been added during allocation, so sorted list is already up to date
-            return;
-        }
-
-        TraceInterval[] oldList = sortedIntervals;
-        TraceInterval[] newList = Arrays.copyOfRange(intervals, firstDerivedIntervalIndex, intervalsSize);
-        int oldLen = oldList.length;
-        int newLen = newList.length;
-
-        // conventional sort-algorithm for new intervals
-        Arrays.sort(newList, (TraceInterval a, TraceInterval b) -> a.from() - b.from());
-
-        // merge old and new list (both already sorted) into one combined list
-        TraceInterval[] combinedList = new TraceInterval[oldLen + newLen];
-        int oldIdx = 0;
-        int newIdx = 0;
-
-        while (oldIdx + newIdx < combinedList.length) {
-            if (newIdx >= newLen || (oldIdx < oldLen && oldList[oldIdx].from() <= newList[newIdx].from())) {
-                combinedList[oldIdx + newIdx] = oldList[oldIdx];
-                oldIdx++;
-            } else {
-                combinedList[oldIdx + newIdx] = newList[newIdx];
-                newIdx++;
-            }
-        }
-
-        sortedIntervals = combinedList;
-    }
-
-    // wrapper for Interval.splitChildAtOpId that performs a bailout in product mode
-    // instead of returning null
-    public TraceInterval splitChildAtOpId(TraceInterval interval, int opId, LIRInstruction.OperandMode mode) {
-        TraceInterval result = interval.getSplitChildAtOpId(opId, mode, this);
-
-        if (result != null) {
-            if (Debug.isLogEnabled()) {
-                Debug.log("Split child at pos %d of interval %s is %s", opId, interval, result);
-            }
-            return result;
-        }
-
-        throw new BailoutException("LinearScan: interval is null");
-    }
-
-    static AllocatableValue canonicalSpillOpr(TraceInterval interval) {
-        assert interval.spillSlot() != null : "canonical spill slot not set";
-        return interval.spillSlot();
-    }
-
-    boolean isMaterialized(AllocatableValue operand, int opId, OperandMode mode) {
-        TraceInterval interval = intervalFor(operand);
-        assert interval != null : "interval must exist";
-
-        if (opId != -1) {
-            /*
-             * Operands are not changed when an interval is split during allocation, so search the
-             * right interval here.
-             */
-            interval = splitChildAtOpId(interval, opId, mode);
-        }
-
-        return isIllegal(interval.location()) && interval.canMaterialize();
-    }
-
-    boolean isCallerSave(Value operand) {
-        return attributes(asRegister(operand)).isCallerSave();
-    }
-
-    @SuppressWarnings("try")
-    protected <B extends AbstractBlockBase<B>> void allocate(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
-
-        /*
-         * This is the point to enable debug logging for the whole register allocation.
-         */
-        try (Indent indent = Debug.logAndIndent("LinearScan allocate")) {
-            TraceLinearScanAllocationContext context = new TraceLinearScanAllocationContext(spillMoveFactory, registerAllocationConfig, traceBuilderResult, this);
-
-            TRACE_LINEAR_SCAN_LIFETIME_ANALYSIS_PHASE.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
-
-            try (Scope s = Debug.scope("AfterLifetimeAnalysis", (Object) intervals())) {
-                sortIntervalsBeforeAllocation();
-                sortFixedIntervalsBeforeAllocation();
-
-                TRACE_LINEAR_SCAN_REGISTER_ALLOCATION_PHASE.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
-
-                // resolve intra-trace data-flow
-                TRACE_LINEAR_SCAN_RESOLVE_DATA_FLOW_PHASE.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
-                Debug.dump(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL, sortedBlocks(), "%s", TRACE_LINEAR_SCAN_RESOLVE_DATA_FLOW_PHASE.getName());
-
-                // eliminate spill moves
-                if (Options.LIROptTraceRAEliminateSpillMoves.getValue()) {
-                    TRACE_LINEAR_SCAN_ELIMINATE_SPILL_MOVE_PHASE.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
-                    Debug.dump(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL, sortedBlocks(), "%s", TRACE_LINEAR_SCAN_ELIMINATE_SPILL_MOVE_PHASE.getName());
-                }
-
-                TRACE_LINEAR_SCAN_ASSIGN_LOCATIONS_PHASE.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
-
-                if (DetailedAsserts.getValue()) {
-                    verifyIntervals();
-                }
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
-        }
-    }
-
-    @SuppressWarnings("try")
-    public void printIntervals(String label) {
-        if (Debug.isDumpEnabled(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL)) {
-            if (Debug.isLogEnabled()) {
-                try (Indent indent = Debug.logAndIndent("intervals %s", label)) {
-                    for (FixedInterval interval : fixedIntervals) {
-                        if (interval != null) {
-                            Debug.log("%s", interval.logString(this));
-                        }
-                    }
-
-                    for (TraceInterval interval : intervals) {
-                        if (interval != null) {
-                            Debug.log("%s", interval.logString(this));
-                        }
-                    }
-
-                    try (Indent indent2 = Debug.logAndIndent("Basic Blocks")) {
-                        for (int i = 0; i < blockCount(); i++) {
-                            AbstractBlockBase<?> block = blockAt(i);
-                            Debug.log("B%d [%d, %d, %s] ", block.getId(), getFirstLirInstructionId(block), getLastLirInstructionId(block), block.getLoop());
-                        }
-                    }
-                }
-            }
-            Debug.dump(new TraceIntervalDumper(Arrays.copyOf(fixedIntervals, fixedIntervals.length), Arrays.copyOf(intervals, intervalsSize)), label);
-        }
-    }
-
-    public void printLir(String label, @SuppressWarnings("unused") boolean hirValid) {
-        if (Debug.isDumpEnabled(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL)) {
-            Debug.dump(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL, sortedBlocks(), label);
-        }
-    }
-
-    boolean verify() {
-        // (check that all intervals have a correct register and that no registers are overwritten)
-        verifyIntervals();
-
-        verifyRegisters();
-
-        Debug.log("no errors found");
-
-        return true;
-    }
-
-    @SuppressWarnings("try")
-    private void verifyRegisters() {
-        // Enable this logging to get output for the verification process.
-        try (Indent indent = Debug.logAndIndent("verifying register allocation")) {
-            RegisterVerifier verifier = new RegisterVerifier(this);
-            verifier.verify(blockAt(0));
-        }
-    }
-
-    @SuppressWarnings("try")
-    protected void verifyIntervals() {
-        try (Indent indent = Debug.logAndIndent("verifying intervals")) {
-            int len = intervalsSize;
-
-            for (int i = 0; i < len; i++) {
-                final TraceInterval i1 = intervals[i];
-                if (i1 == null) {
-                    continue;
-                }
-
-                i1.checkSplitChildren();
-
-                if (i1.operandNumber != i) {
-                    Debug.log("Interval %d is on position %d in list", i1.operandNumber, i);
-                    Debug.log(i1.logString(this));
-                    throw new JVMCIError("");
-                }
-
-                if (isVariable(i1.operand) && i1.kind().equals(LIRKind.Illegal)) {
-                    Debug.log("Interval %d has no type assigned", i1.operandNumber);
-                    Debug.log(i1.logString(this));
-                    throw new JVMCIError("");
-                }
-
-                if (i1.location() == null) {
-                    Debug.log("Interval %d has no register assigned", i1.operandNumber);
-                    Debug.log(i1.logString(this));
-                    throw new JVMCIError("");
-                }
-
-                if (i1.isEmpty()) {
-                    Debug.log("Interval %d has no Range", i1.operandNumber);
-                    Debug.log(i1.logString(this));
-                    throw new JVMCIError("");
-                }
-
-                if (i1.from() >= i1.to()) {
-                    Debug.log("Interval %d has zero length range", i1.operandNumber);
-                    Debug.log(i1.logString(this));
-                    throw new JVMCIError("");
-                }
-
-                // special intervals that are created in MoveResolver
-                // . ignore them because the range information has no meaning there
-                if (i1.from() == 1 && i1.to() == 2) {
-                    continue;
-                }
-                // check any intervals
-                for (int j = i + 1; j < len; j++) {
-                    final TraceInterval i2 = intervals[j];
-                    if (i2 == null) {
-                        continue;
-                    }
-
-                    // special intervals that are created in MoveResolver
-                    // . ignore them because the range information has no meaning there
-                    if (i2.from() == 1 && i2.to() == 2) {
-                        continue;
-                    }
-                    Value l1 = i1.location();
-                    Value l2 = i2.location();
-                    boolean intersects = i1.intersects(i2);
-                    if (intersects && !isIllegal(l1) && (l1.equals(l2))) {
-                        if (DetailedAsserts.getValue()) {
-                            Debug.log("Intervals %s and %s overlap and have the same register assigned", i1, i2);
-                            Debug.log(i1.logString(this));
-                            Debug.log(i2.logString(this));
-                        }
-                        throw new BailoutException("");
-                    }
-                }
-                // check fixed intervals
-                for (FixedInterval i2 : fixedIntervals) {
-                    if (i2 == null) {
-                        continue;
-                    }
-
-                    Value l1 = i1.location();
-                    Value l2 = i2.location();
-                    boolean intersects = i2.intersects(i1);
-                    if (intersects && !isIllegal(l1) && (l1.equals(l2))) {
-                        if (DetailedAsserts.getValue()) {
-                            Debug.log("Intervals %s and %s overlap and have the same register assigned", i1, i2);
-                            Debug.log(i1.logString(this));
-                            Debug.log(i2.logString(this));
-                        }
-                        throw new BailoutException("");
-                    }
-                }
-            }
-        }
-    }
-
-    class CheckConsumer implements ValueConsumer {
-
-        boolean ok;
-        FixedInterval curInterval;
-
-        @Override
-        public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-            if (isRegister(operand)) {
-                if (fixedIntervalFor(asRegisterValue(operand)) == curInterval) {
-                    ok = true;
-                }
-            }
-        }
-    }
-
-    @SuppressWarnings("try")
-    void verifyNoOopsInFixedIntervals() {
-        try (Indent indent = Debug.logAndIndent("verifying that no oops are in fixed intervals *")) {
-            CheckConsumer checkConsumer = new CheckConsumer();
-
-            TraceInterval otherIntervals;
-            FixedInterval fixedInts = createFixedUnhandledList();
-            // to ensure a walking until the last instruction id, add a dummy interval
-            // with a high operation id
-            otherIntervals = new TraceInterval(Value.ILLEGAL, -1);
-            otherIntervals.addRange(Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1);
-            TraceIntervalWalker iw = new TraceIntervalWalker(this, fixedInts, otherIntervals);
-
-            for (AbstractBlockBase<?> block : sortedBlocks) {
-                List<LIRInstruction> instructions = ir.getLIRforBlock(block);
-
-                for (int j = 0; j < instructions.size(); j++) {
-                    LIRInstruction op = instructions.get(j);
-
-                    if (op.hasState()) {
-                        iw.walkBefore(op.id());
-                        boolean checkLive = true;
-
-                        /*
-                         * Make sure none of the fixed registers is live across an oopmap since we
-                         * can't handle that correctly.
-                         */
-                        if (checkLive) {
-                            for (FixedInterval interval = iw.activeFixedList.getFixed(); interval != FixedInterval.EndMarker; interval = interval.next) {
-                                if (interval.to() > op.id() + 1) {
-                                    /*
-                                     * This interval is live out of this op so make sure that this
-                                     * interval represents some value that's referenced by this op
-                                     * either as an input or output.
-                                     */
-                                    checkConsumer.curInterval = interval;
-                                    checkConsumer.ok = false;
-
-                                    op.visitEachInput(checkConsumer);
-                                    op.visitEachAlive(checkConsumer);
-                                    op.visitEachTemp(checkConsumer);
-                                    op.visitEachOutput(checkConsumer);
-
-                                    assert checkConsumer.ok : "fixed intervals should never be live across an oopmap point";
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    public LIR getLIR() {
-        return ir;
-    }
-
-    public FrameMapBuilder getFrameMapBuilder() {
-        return frameMapBuilder;
-    }
-
-    public List<? extends AbstractBlockBase<?>> sortedBlocks() {
-        return sortedBlocks;
-    }
-
-    public Register[] getRegisters() {
-        return registers;
-    }
-
-    public RegisterAllocationConfig getRegisterAllocationConfig() {
-        return regAllocConfig;
-    }
-
-    public boolean callKillsRegisters() {
-        return regAllocConfig.getRegisterConfig().areAllAllocatableRegistersCallerSaved();
-    }
-
-    boolean neverSpillConstants() {
-        return neverSpillConstants;
-    }
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanAllocationPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, 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.alloc.trace;
-
-import java.util.List;
-
-import jdk.vm.ci.code.TargetDescription;
-
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
-import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
-import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
-import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
-import com.oracle.graal.lir.phases.LIRPhase;
-
-public abstract class TraceLinearScanAllocationPhase extends LIRPhase<TraceLinearScanAllocationPhase.TraceLinearScanAllocationContext> {
-
-    public static final class TraceLinearScanAllocationContext {
-        private final MoveFactory spillMoveFactory;
-        private final RegisterAllocationConfig registerAllocationConfig;
-        private final TraceBuilderResult<?> traceBuilderResult;
-        private final TraceLinearScan allocator;
-
-        public TraceLinearScanAllocationContext(MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig, TraceBuilderResult<?> traceBuilderResult, TraceLinearScan allocator) {
-            this.spillMoveFactory = spillMoveFactory;
-            this.registerAllocationConfig = registerAllocationConfig;
-            this.traceBuilderResult = traceBuilderResult;
-            this.allocator = allocator;
-        }
-    }
-
-    @Override
-    protected final <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
-                    TraceLinearScanAllocationContext context) {
-        run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context.spillMoveFactory, context.registerAllocationConfig, context.traceBuilderResult, context.allocator);
-    }
-
-    protected abstract <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
-                    MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig, TraceBuilderResult<?> traceBuilderResult, TraceLinearScan allocator);
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanAssignLocationsPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,276 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, 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.alloc.trace;
-
-import static com.oracle.graal.compiler.common.GraalOptions.DetailedAsserts;
-import static com.oracle.graal.lir.LIRValueUtil.isConstantValue;
-import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
-import static com.oracle.graal.lir.LIRValueUtil.isVariable;
-import static com.oracle.graal.lir.LIRValueUtil.isVirtualStackSlot;
-import static com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase.Options.TraceRAshareSpillInformation;
-import static jdk.vm.ci.code.ValueUtil.isIllegal;
-import static jdk.vm.ci.code.ValueUtil.isRegister;
-
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.List;
-
-import jdk.vm.ci.code.RegisterValue;
-import jdk.vm.ci.code.StackSlot;
-import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.meta.AllocatableValue;
-import jdk.vm.ci.meta.Value;
-
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
-import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
-import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.Indent;
-import com.oracle.graal.lir.ConstantValue;
-import com.oracle.graal.lir.InstructionValueProcedure;
-import com.oracle.graal.lir.LIRFrameState;
-import com.oracle.graal.lir.LIRInstruction;
-import com.oracle.graal.lir.LIRInstruction.OperandFlag;
-import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.StandardOp;
-import com.oracle.graal.lir.StandardOp.BlockEndOp;
-import com.oracle.graal.lir.StandardOp.LabelOp;
-import com.oracle.graal.lir.StandardOp.MoveOp;
-import com.oracle.graal.lir.StandardOp.ValueMoveOp;
-import com.oracle.graal.lir.Variable;
-import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
-
-/**
- * Specialization of {@link com.oracle.graal.lir.alloc.lsra.LinearScanAssignLocationsPhase} that
- * inserts {@link ShadowedRegisterValue}s to describe {@link RegisterValue}s that are also available
- * on the {@link StackSlot stack}.
- */
-final class TraceLinearScanAssignLocationsPhase extends TraceLinearScanAllocationPhase {
-
-    @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig, TraceBuilderResult<?> traceBuilderResult, TraceLinearScan allocator) {
-        new Assigner(allocator).assignLocations();
-    }
-
-    private static final class Assigner {
-        private final TraceLinearScan allocator;
-
-        private Assigner(TraceLinearScan allocator) {
-            this.allocator = allocator;
-        }
-
-        /**
-         * Assigns the allocated location for an LIR instruction operand back into the instruction.
-         *
-         * @param op current {@link LIRInstruction}
-         * @param operand an LIR instruction operand
-         * @param mode the usage mode for {@code operand} by the instruction
-         * @return the location assigned for the operand
-         */
-        private Value colorLirOperand(LIRInstruction op, Variable operand, OperandMode mode) {
-            int opId = op.id();
-            TraceInterval interval = allocator.intervalFor(operand);
-            assert interval != null : "interval must exist";
-
-            if (opId != -1) {
-                if (DetailedAsserts.getValue()) {
-                    AbstractBlockBase<?> block = allocator.blockForId(opId);
-                    if (block.getSuccessorCount() <= 1 && opId == allocator.getLastLirInstructionId(block)) {
-                        /*
-                         * Check if spill moves could have been appended at the end of this block,
-                         * but before the branch instruction. So the split child information for
-                         * this branch would be incorrect.
-                         */
-                        LIRInstruction instr = allocator.getLIR().getLIRforBlock(block).get(allocator.getLIR().getLIRforBlock(block).size() - 1);
-                        if (instr instanceof StandardOp.JumpOp) {
-                            if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) {
-                                assert false : String.format(
-                                                "can't get split child for the last branch of a block because the information would be incorrect (moves are inserted before the branch in resolveDataFlow) block=%s, instruction=%s, operand=%s",
-                                                block, instr, operand);
-                            }
-                        }
-                    }
-                }
-
-                /*
-                 * Operands are not changed when an interval is split during allocation, so search
-                 * the right interval here.
-                 */
-                interval = allocator.splitChildAtOpId(interval, opId, mode);
-            }
-
-            if (isIllegal(interval.location()) && interval.canMaterialize()) {
-                assert mode != OperandMode.DEF;
-                return new ConstantValue(interval.kind(), interval.getMaterializedValue());
-            }
-            return interval.location();
-        }
-
-        /**
-         * @param op
-         * @param operand
-         * @param valueMode
-         * @param flags
-         * @see InstructionValueProcedure#doValue(LIRInstruction, Value, OperandMode, EnumSet)
-         */
-        private Value debugInfoProcedure(LIRInstruction op, Value operand, OperandMode valueMode, EnumSet<OperandFlag> flags) {
-            if (isVirtualStackSlot(operand)) {
-                return operand;
-            }
-            int tempOpId = op.id();
-            OperandMode mode = OperandMode.USE;
-            AbstractBlockBase<?> block = allocator.blockForId(tempOpId);
-            if (block.getSuccessorCount() == 1 && tempOpId == allocator.getLastLirInstructionId(block)) {
-                /*
-                 * Generating debug information for the last instruction of a block. If this
-                 * instruction is a branch, spill moves are inserted before this branch and so the
-                 * wrong operand would be returned (spill moves at block boundaries are not
-                 * considered in the live ranges of intervals).
-                 * 
-                 * Solution: use the first opId of the branch target block instead.
-                 */
-                final LIRInstruction instr = allocator.getLIR().getLIRforBlock(block).get(allocator.getLIR().getLIRforBlock(block).size() - 1);
-                if (instr instanceof StandardOp.JumpOp) {
-                    if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) {
-                        tempOpId = allocator.getFirstLirInstructionId(block.getSuccessors().iterator().next());
-                        mode = OperandMode.DEF;
-                    }
-                }
-            }
-
-            /*
-             * Get current location of operand. The operand must be live because debug information
-             * is considered when building the intervals if the interval is not live,
-             * colorLirOperand will cause an assert on failure.
-             */
-            Value result = colorLirOperand(op, (Variable) operand, mode);
-            assert !allocator.hasCall(tempOpId) || isStackSlotValue(result) || isConstantValue(result) || !allocator.isCallerSave(result) : "cannot have caller-save register operands at calls";
-            return result;
-        }
-
-        private void computeDebugInfo(final LIRInstruction op, LIRFrameState info) {
-            info.forEachState(op, this::debugInfoProcedure);
-        }
-
-        private void assignLocations(List<LIRInstruction> instructions) {
-            int numInst = instructions.size();
-            boolean hasDead = false;
-
-            for (int j = 0; j < numInst; j++) {
-                final LIRInstruction op = instructions.get(j);
-                if (op == null) {
-                    /*
-                     * this can happen when spill-moves are removed in eliminateSpillMoves
-                     */
-                    hasDead = true;
-                } else if (assignLocations(op)) {
-                    instructions.set(j, null);
-                    hasDead = true;
-                }
-            }
-
-            if (hasDead) {
-                // Remove null values from the list.
-                instructions.removeAll(Collections.singleton(null));
-            }
-        }
-
-        /**
-         * Assigns the operand of an {@link LIRInstruction}.
-         *
-         * @param op The {@link LIRInstruction} that should be colored.
-         * @return {@code true} if the instruction should be deleted.
-         */
-        private boolean assignLocations(LIRInstruction op) {
-            assert op != null;
-            if (TraceRAshareSpillInformation.getValue()) {
-                if (op instanceof BlockEndOp) {
-                    ((BlockEndOp) op).forEachOutgoingValue(colorOutgoingIncomingValues);
-                } else if (op instanceof LabelOp) {
-                    ((LabelOp) op).forEachIncomingValue(colorOutgoingIncomingValues);
-                }
-            }
-
-            InstructionValueProcedure assignProc = (inst, operand, mode, flags) -> isVariable(operand) ? colorLirOperand(inst, (Variable) operand, mode) : operand;
-            // remove useless moves
-            if (op instanceof MoveOp) {
-                AllocatableValue result = ((MoveOp) op).getResult();
-                if (isVariable(result) && allocator.isMaterialized(result, op.id(), OperandMode.DEF)) {
-                    /*
-                     * This happens if a materializable interval is originally not spilled but then
-                     * kicked out in LinearScanWalker.splitForSpilling(). When kicking out such an
-                     * interval this move operation was already generated.
-                     */
-                    return true;
-                }
-            }
-
-            op.forEachInput(assignProc);
-            op.forEachAlive(assignProc);
-            op.forEachTemp(assignProc);
-            op.forEachOutput(assignProc);
-
-            // compute reference map and debug information
-            op.forEachState((inst, state) -> computeDebugInfo(inst, state));
-
-            // remove useless moves
-            if (op instanceof ValueMoveOp) {
-                ValueMoveOp move = (ValueMoveOp) op;
-                if (move.getInput().equals(move.getResult())) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        @SuppressWarnings("try")
-        private void assignLocations() {
-            try (Indent indent = Debug.logAndIndent("assign locations")) {
-                for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
-                    try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) {
-                        assignLocations(allocator.getLIR().getLIRforBlock(block));
-                    }
-                }
-            }
-        }
-
-        private InstructionValueProcedure colorOutgoingIncomingValues = new InstructionValueProcedure() {
-
-            public Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-                if (isVariable(value)) {
-                    TraceInterval interval = allocator.intervalFor(value);
-                    assert interval != null : "interval must exist";
-                    interval = allocator.splitChildAtOpId(interval, instruction.id(), mode);
-
-                    if (interval.inMemoryAt(instruction.id()) && isRegister(interval.location())) {
-                        return new ShadowedRegisterValue((RegisterValue) interval.location(), interval.spillSlot());
-                    }
-                }
-                return value;
-            }
-        };
-    }
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanEliminateSpillMovePhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,222 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, 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.alloc.trace;
-
-import static com.oracle.graal.compiler.common.GraalOptions.DetailedAsserts;
-import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
-import static com.oracle.graal.lir.LIRValueUtil.isVariable;
-import static jdk.vm.ci.code.ValueUtil.isRegister;
-
-import java.util.List;
-
-import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.meta.AllocatableValue;
-
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
-import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
-import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.Indent;
-import com.oracle.graal.lir.LIRInsertionBuffer;
-import com.oracle.graal.lir.LIRInstruction;
-import com.oracle.graal.lir.StandardOp.LoadConstantOp;
-import com.oracle.graal.lir.StandardOp.MoveOp;
-import com.oracle.graal.lir.StandardOp.ValueMoveOp;
-import com.oracle.graal.lir.alloc.trace.TraceInterval.SpillState;
-import com.oracle.graal.lir.alloc.trace.TraceLinearScan.IntervalPredicate;
-import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
-
-final class TraceLinearScanEliminateSpillMovePhase extends TraceLinearScanAllocationPhase {
-
-    private static final IntervalPredicate mustStoreAtDefinition = new TraceLinearScan.IntervalPredicate() {
-
-        @Override
-        public boolean apply(TraceInterval i) {
-            return i.isSplitParent() && i.spillState() == SpillState.StoreAtDefinition;
-        }
-    };
-
-    @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig, TraceBuilderResult<?> traceBuilderResult, TraceLinearScan allocator) {
-        boolean shouldEliminateSpillMoves = shouldEliminateSpillMoves(traceBuilderResult, allocator);
-        eliminateSpillMoves(allocator, shouldEliminateSpillMoves, traceBuilderResult);
-    }
-
-    private static boolean shouldEliminateSpillMoves(TraceBuilderResult<?> traceBuilderResult, TraceLinearScan allocator) {
-        return !traceBuilderResult.incomingSideEdges(traceBuilderResult.getTraceForBlock(allocator.sortedBlocks().get(0)));
-    }
-
-    // called once before assignment of register numbers
-    @SuppressWarnings("try")
-    private static void eliminateSpillMoves(TraceLinearScan allocator, boolean shouldEliminateSpillMoves, TraceBuilderResult<?> traceBuilderResult) {
-        try (Indent indent = Debug.logAndIndent("Eliminating unnecessary spill moves: Trace%d", traceBuilderResult.getTraceForBlock(allocator.sortedBlocks().get(0)))) {
-
-            /*
-             * collect all intervals that must be stored after their definition. The list is sorted
-             * by Interval.spillDefinitionPos.
-             */
-            TraceInterval interval = allocator.createUnhandledList(mustStoreAtDefinition);
-            if (DetailedAsserts.getValue()) {
-                checkIntervals(interval);
-            }
-
-            LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer();
-            for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
-                try (Indent indent1 = Debug.logAndIndent("Handle %s", block)) {
-                    List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
-                    int numInst = instructions.size();
-
-                    int lastOpId = -1;
-                    // iterate all instructions of the block.
-                    for (int j = 0; j < numInst; j++) {
-                        LIRInstruction op = instructions.get(j);
-                        int opId = op.id();
-
-                        if (opId == -1) {
-                            MoveOp move = (MoveOp) op;
-                            /*
-                             * Remove move from register to stack if the stack slot is guaranteed to
-                             * be correct. Only moves that have been inserted by LinearScan can be
-                             * removed.
-                             */
-                            if (shouldEliminateSpillMoves && canEliminateSpillMove(allocator, block, move, lastOpId)) {
-                                /*
-                                 * Move target is a stack slot that is always correct, so eliminate
-                                 * instruction.
-                                 */
-                                if (Debug.isLogEnabled()) {
-                                    if (move instanceof ValueMoveOp) {
-                                        ValueMoveOp vmove = (ValueMoveOp) move;
-                                        Debug.log("eliminating move from interval %d (%s) to %d (%s) in block %s", allocator.operandNumber(vmove.getInput()), vmove.getInput(),
-                                                        allocator.operandNumber(vmove.getResult()), vmove.getResult(), block);
-                                    } else {
-                                        LoadConstantOp load = (LoadConstantOp) move;
-                                        Debug.log("eliminating constant load from %s to %d (%s) in block %s", load.getConstant(), allocator.operandNumber(load.getResult()), load.getResult(), block);
-                                    }
-                                }
-
-                                // null-instructions are deleted by assignRegNum
-                                instructions.set(j, null);
-                            }
-
-                        } else {
-                            lastOpId = opId;
-                            /*
-                             * Insert move from register to stack just after the beginning of the
-                             * interval.
-                             */
-                            assert interval == TraceInterval.EndMarker || interval.spillDefinitionPos() >= opId : "invalid order";
-                            assert interval == TraceInterval.EndMarker || (interval.isSplitParent() && interval.spillState() == SpillState.StoreAtDefinition) : "invalid interval";
-
-                            while (interval != TraceInterval.EndMarker && interval.spillDefinitionPos() == opId) {
-                                if (!interval.canMaterialize()) {
-                                    if (!insertionBuffer.initialized()) {
-                                        /*
-                                         * prepare insertion buffer (appended when all instructions
-                                         * in the block are processed)
-                                         */
-                                        insertionBuffer.init(instructions);
-                                    }
-
-                                    AllocatableValue fromLocation = interval.location();
-                                    AllocatableValue toLocation = TraceLinearScan.canonicalSpillOpr(interval);
-                                    if (!fromLocation.equals(toLocation)) {
-
-                                        assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" +
-                                                        interval.spillState();
-                                        assert isStackSlotValue(toLocation) : "to operand must be a stack slot";
-
-                                        LIRInstruction move = allocator.getSpillMoveFactory().createMove(toLocation, fromLocation);
-                                        insertionBuffer.append(j + 1, move);
-
-                                        if (Debug.isLogEnabled()) {
-                                            Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId);
-                                        }
-                                    }
-                                }
-                                interval = interval.next;
-                            }
-                        }
-                    } // end of instruction iteration
-
-                    if (insertionBuffer.initialized()) {
-                        insertionBuffer.finish();
-                    }
-                }
-            } // end of block iteration
-
-            assert interval == TraceInterval.EndMarker : "missed an interval";
-        }
-    }
-
-    /**
-     * @param allocator
-     * @param block The block {@code move} is located in.
-     * @param move Spill move.
-     * @param lastOpId The id of last "normal" instruction before the spill move. (Spill moves have
-     *            no valid opId but -1.)
-     */
-    private static boolean canEliminateSpillMove(TraceLinearScan allocator, AbstractBlockBase<?> block, MoveOp move, int lastOpId) {
-        assert isVariable(move.getResult()) : "LinearScan inserts only moves to variables: " + move;
-        assert lastOpId >= 0 : "Invalid lastOpId: " + lastOpId;
-
-        TraceInterval curInterval = allocator.intervalFor(move.getResult());
-
-        if (!isRegister(curInterval.location()) && curInterval.inMemoryAt(lastOpId) && isPhiResolutionMove(allocator, move)) {
-            assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location();
-            return true;
-        }
-        return false;
-    }
-
-    private static boolean isPhiResolutionMove(TraceLinearScan allocator, MoveOp move) {
-        TraceInterval curInterval = allocator.intervalFor(move.getResult());
-        return !curInterval.isSplitParent();
-    }
-
-    private static void checkIntervals(TraceInterval interval) {
-        TraceInterval prev = null;
-        TraceInterval temp = interval;
-        while (temp != TraceInterval.EndMarker) {
-            assert temp.spillDefinitionPos() >= 0 : "invalid spill definition pos";
-            if (prev != null) {
-                assert temp.from() >= prev.from() : "intervals not sorted";
-                assert temp.spillDefinitionPos() >= prev.spillDefinitionPos() : "when intervals are sorted by from :  then they must also be sorted by spillDefinitionPos";
-            }
-
-            assert temp.spillSlot() != null || temp.canMaterialize() : "interval has no spill slot assigned";
-            assert temp.spillDefinitionPos() >= temp.from() : "invalid order";
-            assert temp.spillDefinitionPos() <= temp.from() + 2 : "only intervals defined once at their start-pos can be optimized";
-
-            if (Debug.isLogEnabled()) {
-                Debug.log("interval %d (from %d to %d) must be stored at %d", temp.operandNumber, temp.from(), temp.to(), temp.spillDefinitionPos());
-            }
-
-            prev = temp;
-            temp = temp.next;
-        }
-    }
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanLifetimeAnalysisPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,667 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, 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.alloc.trace;
-
-import static com.oracle.graal.lir.LIRValueUtil.asVariable;
-import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
-import static com.oracle.graal.lir.LIRValueUtil.isVariable;
-import static com.oracle.graal.lir.alloc.trace.TraceLinearScan.isVariableOrRegister;
-import static com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase.Options.TraceRAshareSpillInformation;
-import static com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase.Options.TraceRAuseInterTraceHints;
-import static com.oracle.graal.lir.alloc.trace.TraceUtil.asShadowedRegisterValue;
-import static com.oracle.graal.lir.alloc.trace.TraceUtil.isShadowedRegisterValue;
-import static jdk.vm.ci.code.ValueUtil.asRegisterValue;
-import static jdk.vm.ci.code.ValueUtil.asStackSlot;
-import static jdk.vm.ci.code.ValueUtil.isRegister;
-import static jdk.vm.ci.code.ValueUtil.isStackSlot;
-
-import java.util.BitSet;
-import java.util.EnumSet;
-import java.util.List;
-
-import jdk.vm.ci.code.BailoutException;
-import jdk.vm.ci.code.Register;
-import jdk.vm.ci.code.RegisterValue;
-import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.meta.AllocatableValue;
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.LIRKind;
-import jdk.vm.ci.meta.Value;
-
-import com.oracle.graal.compiler.common.alloc.ComputeBlockOrder;
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
-import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
-import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.Indent;
-import com.oracle.graal.lir.InstructionValueConsumer;
-import com.oracle.graal.lir.LIR;
-import com.oracle.graal.lir.LIRInstruction;
-import com.oracle.graal.lir.LIRInstruction.OperandFlag;
-import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.LIRValueUtil;
-import com.oracle.graal.lir.StandardOp.BlockEndOp;
-import com.oracle.graal.lir.StandardOp.LabelOp;
-import com.oracle.graal.lir.StandardOp.LoadConstantOp;
-import com.oracle.graal.lir.StandardOp.ValueMoveOp;
-import com.oracle.graal.lir.ValueConsumer;
-import com.oracle.graal.lir.Variable;
-import com.oracle.graal.lir.alloc.trace.TraceInterval.RegisterPriority;
-import com.oracle.graal.lir.alloc.trace.TraceInterval.SpillState;
-import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
-import com.oracle.graal.lir.ssi.SSIUtil;
-
-final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanAllocationPhase {
-
-    @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig, TraceBuilderResult<?> traceBuilderResult, TraceLinearScan allocator) {
-        new Analyser(allocator, traceBuilderResult).analyze();
-    }
-
-    private static final class Analyser {
-        private static final int DUMP_DURING_ANALYSIS_LEVEL = 4;
-        private final TraceLinearScan allocator;
-        private final TraceBuilderResult<?> traceBuilderResult;
-
-        /**
-         * @param linearScan
-         * @param traceBuilderResult
-         */
-        private Analyser(TraceLinearScan linearScan, TraceBuilderResult<?> traceBuilderResult) {
-            allocator = linearScan;
-            this.traceBuilderResult = traceBuilderResult;
-        }
-
-        private void analyze() {
-            numberInstructions();
-            allocator.printLir("Before register allocation", true);
-            buildIntervals();
-        }
-
-        private boolean sameTrace(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
-            return traceBuilderResult.getTraceForBlock(b) == traceBuilderResult.getTraceForBlock(a);
-        }
-
-        private boolean isAllocatedOrCurrent(AbstractBlockBase<?> currentBlock, AbstractBlockBase<?> other) {
-            return traceBuilderResult.getTraceForBlock(other) <= traceBuilderResult.getTraceForBlock(currentBlock);
-        }
-
-        private static void setHint(final LIRInstruction op, TraceInterval to, IntervalHint from) {
-            IntervalHint currentHint = to.locationHint(false);
-            if (currentHint == null) {
-                /*
-                 * Update hint if there was none or if the hint interval starts after the hinted
-                 * interval.
-                 */
-                to.setLocationHint(from);
-                if (Debug.isLogEnabled()) {
-                    Debug.log("operation at opId %d: added hint from interval %s to %s", op.id(), from, to);
-                }
-            }
-        }
-
-        /**
-         * Numbers all instructions in all blocks. The numbering follows the
-         * {@linkplain ComputeBlockOrder linear scan order}.
-         */
-        private void numberInstructions() {
-
-            allocator.initIntervals();
-
-            ValueConsumer setVariableConsumer = (value, mode, flags) -> {
-                if (isVariable(value)) {
-                    allocator.getOrCreateInterval(asVariable(value));
-                }
-            };
-
-            // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node.
-            int numInstructions = 0;
-            for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
-                numInstructions += allocator.getLIR().getLIRforBlock(block).size();
-            }
-
-            // initialize with correct length
-            allocator.initOpIdMaps(numInstructions);
-
-            int opId = 0;
-            int index = 0;
-            for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
-                allocator.initBlockData(block);
-
-                List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
-
-                int numInst = instructions.size();
-                for (int j = 0; j < numInst; j++) {
-                    LIRInstruction op = instructions.get(j);
-                    op.setId(opId);
-
-                    allocator.putOpIdMaps(index, op, block);
-                    assert allocator.instructionForId(opId) == op : "must match";
-
-                    op.visitEachTemp(setVariableConsumer);
-                    op.visitEachOutput(setVariableConsumer);
-
-                    index++;
-                    opId += 2; // numbering of lirOps by two
-                }
-            }
-            assert index == numInstructions : "must match";
-            assert (index << 1) == opId : "must match: " + (index << 1);
-        }
-
-        private void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) {
-            if (!allocator.isProcessed(operand)) {
-                return;
-            }
-            if (isRegister(operand)) {
-                addFixedUse(asRegisterValue(operand), from, to);
-            } else {
-                assert isVariable(operand) : operand;
-                addVariableUse(asVariable(operand), from, to, registerPriority, kind);
-            }
-        }
-
-        private void addFixedUse(RegisterValue reg, int from, int to) {
-            FixedInterval interval = allocator.getOrCreateFixedInterval(reg);
-            interval.addRange(from, to);
-            if (Debug.isLogEnabled()) {
-                Debug.log("add fixed use: %s, at %d", interval, to);
-            }
-        }
-
-        private void addVariableUse(Variable operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) {
-            TraceInterval interval = allocator.getOrCreateInterval(operand);
-
-            if (!kind.equals(LIRKind.Illegal)) {
-                interval.setKind(kind);
-            }
-
-            interval.addRange(from, to);
-
-            // Register use position at even instruction id.
-            interval.addUsePos(to & ~1, registerPriority);
-
-            if (Debug.isLogEnabled()) {
-                Debug.log("add use: %s, at %d (%s)", interval, to, registerPriority.name());
-            }
-        }
-
-        private void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) {
-            if (!allocator.isProcessed(operand)) {
-                return;
-            }
-            if (isRegister(operand)) {
-                addFixedTemp(asRegisterValue(operand), tempPos);
-            } else {
-                assert isVariable(operand) : operand;
-                addVariableTemp(asVariable(operand), tempPos, registerPriority, kind);
-            }
-        }
-
-        private void addFixedTemp(RegisterValue reg, int tempPos) {
-            FixedInterval interval = allocator.getOrCreateFixedInterval(reg);
-            interval.addRange(tempPos, tempPos + 1);
-            if (Debug.isLogEnabled()) {
-                Debug.log("add fixed temp: %s, at %d", interval, tempPos);
-            }
-        }
-
-        private void addVariableTemp(Variable operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) {
-            TraceInterval interval = allocator.getOrCreateInterval(operand);
-
-            if (!kind.equals(LIRKind.Illegal)) {
-                interval.setKind(kind);
-            }
-
-            if (interval.isEmpty()) {
-                interval.addRange(tempPos, tempPos + 1);
-            } else if (interval.from() > tempPos) {
-                interval.setFrom(tempPos);
-            }
-
-            interval.addUsePos(tempPos, registerPriority);
-            interval.addMaterializationValue(null);
-
-            if (Debug.isLogEnabled()) {
-                Debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name());
-            }
-        }
-
-        private void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) {
-            if (!allocator.isProcessed(operand)) {
-                return;
-            }
-            if (isRegister(operand)) {
-                addFixedDef(asRegisterValue(operand), op);
-            } else {
-                assert isVariable(operand) : operand;
-                addVariableDef(asVariable(operand), op, registerPriority, kind);
-            }
-        }
-
-        private void addFixedDef(RegisterValue reg, LIRInstruction op) {
-            FixedInterval interval = allocator.getOrCreateFixedInterval(reg);
-            int defPos = op.id();
-            if (interval.from() <= defPos) {
-                /*
-                 * Update the starting point (when a range is first created for a use, its start is
-                 * the beginning of the current block until a def is encountered).
-                 */
-                interval.setFrom(defPos);
-
-            } else {
-                /*
-                 * Dead value - make vacuous interval also add register priority for dead intervals
-                 */
-                interval.addRange(defPos, defPos + 1);
-                if (Debug.isLogEnabled()) {
-                    Debug.log("Warning: def of operand %s at %d occurs without use", reg, defPos);
-                }
-            }
-            if (Debug.isLogEnabled()) {
-                Debug.log("add fixed def: %s, at %d", interval, defPos);
-            }
-        }
-
-        private void addVariableDef(Variable operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) {
-            int defPos = op.id();
-
-            TraceInterval interval = allocator.getOrCreateInterval(operand);
-
-            if (!kind.equals(LIRKind.Illegal)) {
-                interval.setKind(kind);
-            }
-
-            if (interval.isEmpty()) {
-                /*
-                 * Dead value - make vacuous interval also add register priority for dead intervals
-                 */
-                interval.addRange(defPos, defPos + 1);
-                interval.addUsePos(defPos, registerPriority);
-                if (Debug.isLogEnabled()) {
-                    Debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos);
-                }
-            } else {
-                /*
-                 * Update the starting point (when a range is first created for a use, its start is
-                 * the beginning of the current block until a def is encountered).
-                 */
-                interval.setFrom(defPos);
-                interval.addUsePos(defPos, registerPriority);
-            }
-
-            changeSpillDefinitionPos(op, operand, interval, defPos);
-            if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal() && isStackSlot(operand)) {
-                // detection of method-parameters and roundfp-results
-                interval.setSpillState(SpillState.StartInMemory);
-            }
-            interval.addMaterializationValue(getMaterializedValue(op, operand, interval));
-
-            if (Debug.isLogEnabled()) {
-                Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name());
-            }
-        }
-
-        private void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
-            if (flags.contains(OperandFlag.HINT) && TraceLinearScan.isVariableOrRegister(targetValue)) {
-
-                op.forEachRegisterHint(targetValue, mode, (registerHint, valueMode, valueFlags) -> {
-                    if (TraceLinearScan.isVariableOrRegister(registerHint)) {
-                        AllocatableValue fromValue;
-                        AllocatableValue toValue;
-                        /* hints always point from def to use */
-                        if (hintAtDef) {
-                            fromValue = (AllocatableValue) registerHint;
-                            toValue = (AllocatableValue) targetValue;
-                        } else {
-                            fromValue = (AllocatableValue) targetValue;
-                            toValue = (AllocatableValue) registerHint;
-                        }
-                        if (isRegister(toValue)) {
-                            /* fixed register: no need for a hint */
-                            return null;
-                        }
-
-                        TraceInterval to = allocator.getOrCreateInterval(toValue);
-                        IntervalHint from = getIntervalHint(fromValue);
-
-                        to.setLocationHint(from);
-                        if (Debug.isLogEnabled()) {
-                            Debug.log("operation at opId %d: added hint from interval %s to %s", op.id(), from, to);
-                        }
-
-                        return registerHint;
-                    }
-                    return null;
-                });
-            }
-        }
-
-        private IntervalHint getIntervalHint(AllocatableValue from) {
-            if (isRegister(from)) {
-                return allocator.getOrCreateFixedInterval(asRegisterValue(from));
-            }
-            return allocator.getOrCreateInterval(from);
-        }
-
-        /**
-         * Eliminates moves from register to stack if the stack slot is known to be correct.
-         *
-         * @param op
-         * @param operand
-         */
-        private void changeSpillDefinitionPos(LIRInstruction op, AllocatableValue operand, TraceInterval interval, int defPos) {
-            assert interval.isSplitParent() : "can only be called for split parents";
-
-            switch (interval.spillState()) {
-                case NoDefinitionFound:
-                    // assert interval.spillDefinitionPos() == -1 : "must no be set before";
-                    interval.setSpillDefinitionPos(defPos);
-                    if (!(op instanceof LabelOp)) {
-                        // Do not update state for labels. This will be done afterwards.
-                        interval.setSpillState(SpillState.NoSpillStore);
-                    }
-                    break;
-
-                case NoSpillStore:
-                    assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created";
-                    if (defPos < interval.spillDefinitionPos() - 2) {
-                        /*
-                         * Second definition found, so no spill optimization possible for this
-                         * interval.
-                         */
-                        interval.setSpillState(SpillState.NoOptimization);
-                    } else {
-                        // two consecutive definitions (because of two-operand LIR form)
-                        assert allocator.blockForId(defPos) == allocator.blockForId(interval.spillDefinitionPos()) : "block must be equal";
-                    }
-                    break;
-
-                case NoOptimization:
-                    // nothing to do
-                    break;
-
-                default:
-                    throw new BailoutException("other states not allowed at this time");
-            }
-        }
-
-        private static boolean optimizeMethodArgument(Value value) {
-            /*
-             * Object method arguments that are passed on the stack are currently not optimized
-             * because this requires that the runtime visits method arguments during stack walking.
-             */
-            return isStackSlot(value) && asStackSlot(value).isInCallerFrame() && value.getLIRKind().isValue();
-        }
-
-        /**
-         * Determines the register priority for an instruction's output/result operand.
-         */
-        private static RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) {
-            if (op instanceof LabelOp) {
-                // skip method header
-                return RegisterPriority.None;
-            }
-            if (op instanceof ValueMoveOp) {
-                ValueMoveOp move = (ValueMoveOp) op;
-                if (optimizeMethodArgument(move.getInput())) {
-                    return RegisterPriority.None;
-                }
-            }
-
-            // all other operands require a register
-            return RegisterPriority.MustHaveRegister;
-        }
-
-        /**
-         * Determines the priority which with an instruction's input operand will be allocated a
-         * register.
-         */
-        private static RegisterPriority registerPriorityOfInputOperand(EnumSet<OperandFlag> flags) {
-            if (flags.contains(OperandFlag.OUTGOING)) {
-                return RegisterPriority.None;
-            }
-            if (flags.contains(OperandFlag.STACK)) {
-                return RegisterPriority.ShouldHaveRegister;
-            }
-            // all other operands require a register
-            return RegisterPriority.MustHaveRegister;
-        }
-
-        @SuppressWarnings("try")
-        private void buildIntervals() {
-
-            try (Indent indent = Debug.logAndIndent("build intervals")) {
-                InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> {
-                    if (TraceLinearScan.isVariableOrRegister(operand)) {
-                        addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getLIRKind());
-                        addRegisterHint(op, operand, mode, flags, true);
-                    }
-                };
-
-                InstructionValueConsumer tempConsumer = (op, operand, mode, flags) -> {
-                    if (TraceLinearScan.isVariableOrRegister(operand)) {
-                        addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getLIRKind());
-                        addRegisterHint(op, operand, mode, flags, false);
-                    }
-                };
-
-                InstructionValueConsumer aliveConsumer = (op, operand, mode, flags) -> {
-                    if (TraceLinearScan.isVariableOrRegister(operand)) {
-                        RegisterPriority p = registerPriorityOfInputOperand(flags);
-                        int opId = op.id();
-                        int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
-                        addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getLIRKind());
-                        addRegisterHint(op, operand, mode, flags, false);
-                    }
-                };
-
-                InstructionValueConsumer inputConsumer = (op, operand, mode, flags) -> {
-                    if (TraceLinearScan.isVariableOrRegister(operand)) {
-                        int opId = op.id();
-                        RegisterPriority p = registerPriorityOfInputOperand(flags);
-                        int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
-                        addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getLIRKind());
-                        addRegisterHint(op, operand, mode, flags, false);
-                    }
-                };
-
-                InstructionValueConsumer stateProc = (op, operand, mode, flags) -> {
-                    if (TraceLinearScan.isVariableOrRegister(operand)) {
-                        int opId = op.id();
-                        int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
-                        addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getLIRKind());
-                    }
-                };
-
-                // create a list with all caller-save registers (cpu, fpu, xmm)
-                Register[] callerSaveRegs = allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters();
-
-                // iterate all blocks in reverse order
-                for (int i = allocator.blockCount() - 1; i >= 0; i--) {
-
-                    AbstractBlockBase<?> block = allocator.blockAt(i);
-                    // TODO (je) make empty bitset - remove
-                    allocator.getBlockData(block).liveIn = new BitSet();
-                    allocator.getBlockData(block).liveOut = new BitSet();
-                    try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) {
-
-                        List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
-
-                        /*
-                         * Iterate all instructions of the block in reverse order. definitions of
-                         * intervals are processed before uses.
-                         */
-                        for (int j = instructions.size() - 1; j >= 0; j--) {
-                            final LIRInstruction op = instructions.get(j);
-                            final int opId = op.id();
-
-                            try (Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op)) {
-
-                                // add a temp range for each register if operation destroys
-                                // caller-save registers
-                                if (op.destroysCallerSavedRegisters()) {
-                                    for (Register r : callerSaveRegs) {
-                                        if (allocator.attributes(r).isAllocatable()) {
-                                            addTemp(r.asValue(), opId, RegisterPriority.None, LIRKind.Illegal);
-                                        }
-                                    }
-                                    if (Debug.isLogEnabled()) {
-                                        Debug.log("operation destroys all caller-save registers");
-                                    }
-                                }
-
-                                op.visitEachOutput(outputConsumer);
-                                op.visitEachTemp(tempConsumer);
-                                op.visitEachAlive(aliveConsumer);
-                                op.visitEachInput(inputConsumer);
-
-                                /*
-                                 * Add uses of live locals from interpreter's point of view for
-                                 * proper debug information generation. Treat these operands as temp
-                                 * values (if the live range is extended to a call site, the value
-                                 * would be in a register at the call otherwise).
-                                 */
-                                op.visitEachState(stateProc);
-                            }
-
-                        } // end of instruction iteration
-                    }
-                    if (Debug.isDumpEnabled(DUMP_DURING_ANALYSIS_LEVEL)) {
-                        allocator.printIntervals("After Block " + block);
-                    }
-                } // end of block iteration
-
-                // fix spill state for phi/sigma intervals
-                for (TraceInterval interval : allocator.intervals()) {
-                    if (interval != null && interval.spillState().equals(SpillState.NoDefinitionFound) && interval.spillDefinitionPos() != -1) {
-                        // there was a definition in a phi/sigma
-                        interval.setSpillState(SpillState.NoSpillStore);
-                    }
-                }
-                if (TraceRAuseInterTraceHints.getValue()) {
-                    addInterTraceHints();
-                }
-                /*
-                 * Add the range [-1, 0] to all fixed intervals. the register allocator need not
-                 * handle unhandled fixed intervals.
-                 */
-                for (FixedInterval interval : allocator.fixedIntervals()) {
-                    if (interval != null) {
-                        /* We use [-1, 0] to avoid intersection with incoming values. */
-                        interval.addRange(-1, 0);
-                    }
-                }
-            }
-        }
-
-        private void addInterTraceHints() {
-            // set hints for phi/sigma intervals
-            LIR lir = allocator.getLIR();
-            for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
-                LabelOp label = SSIUtil.incoming(lir, block);
-                for (AbstractBlockBase<?> pred : block.getPredecessors()) {
-                    if (isAllocatedOrCurrent(block, pred)) {
-                        BlockEndOp outgoing = SSIUtil.outgoing(lir, pred);
-                        for (int i = 0; i < outgoing.getOutgoingSize(); i++) {
-                            Value toValue = label.getIncomingValue(i);
-                            assert !isShadowedRegisterValue(toValue) : "Shadowed Registers are not allowed here: " + toValue;
-                            if (isVariable(toValue)) {
-                                Value fromValue = outgoing.getOutgoingValue(i);
-                                assert sameTrace(block, pred) || !isVariable(fromValue) : "Unallocated variable: " + fromValue;
-                                if (!LIRValueUtil.isConstantValue(fromValue)) {
-                                    addInterTraceHint(label, (AllocatableValue) toValue, fromValue);
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        private void addInterTraceHint(LabelOp label, AllocatableValue toValue, Value fromValue) {
-            assert isVariable(toValue) : "Wrong toValue: " + toValue;
-            assert isRegister(fromValue) || isVariable(fromValue) || isStackSlotValue(fromValue) || isShadowedRegisterValue(fromValue) : "Wrong fromValue: " + fromValue;
-            if (isVariableOrRegister(fromValue)) {
-                TraceInterval to = allocator.getOrCreateInterval(toValue);
-                IntervalHint from = getIntervalHint((AllocatableValue) fromValue);
-                setHint(label, to, from);
-            } else if (isStackSlotValue(fromValue)) {
-                TraceInterval to = allocator.getOrCreateInterval(toValue);
-                to.setSpillSlot((AllocatableValue) fromValue);
-                to.setSpillState(SpillState.StartInMemory);
-            } else if (TraceRAshareSpillInformation.getValue() && isShadowedRegisterValue(fromValue)) {
-                ShadowedRegisterValue shadowedRegisterValue = asShadowedRegisterValue(fromValue);
-                IntervalHint from = getIntervalHint(shadowedRegisterValue.getRegister());
-                TraceInterval to = allocator.getOrCreateInterval(toValue);
-                setHint(label, to, from);
-                to.setSpillSlot(shadowedRegisterValue.getStackSlot());
-                to.setSpillState(SpillState.StartInMemory);
-            } else {
-                throw JVMCIError.shouldNotReachHere();
-            }
-        }
-
-        /**
-         * Returns a value for a interval definition, which can be used for re-materialization.
-         *
-         * @param op An instruction which defines a value
-         * @param operand The destination operand of the instruction
-         * @param interval The interval for this defined value.
-         * @return Returns the value which is moved to the instruction and which can be reused at
-         *         all reload-locations in case the interval of this instruction is spilled.
-         *         Currently this can only be a {@link JavaConstant}.
-         */
-        private JavaConstant getMaterializedValue(LIRInstruction op, Value operand, TraceInterval interval) {
-            if (op instanceof LoadConstantOp) {
-                LoadConstantOp move = (LoadConstantOp) op;
-                if (move.getConstant() instanceof JavaConstant) {
-                    if (!allocator.neverSpillConstants()) {
-                        if (!allocator.getSpillMoveFactory().allowConstantToStackMove(move.getConstant())) {
-                            return null;
-                        }
-                        /*
-                         * Check if the interval has any uses which would accept an stack location
-                         * (priority == ShouldHaveRegister). Rematerialization of such intervals can
-                         * result in a degradation, because rematerialization always inserts a
-                         * constant load, even if the value is not needed in a register.
-                         */
-                        UsePosList usePosList = interval.usePosList();
-                        int numUsePos = usePosList.size();
-                        for (int useIdx = 0; useIdx < numUsePos; useIdx++) {
-                            TraceInterval.RegisterPriority priority = usePosList.registerPriority(useIdx);
-                            if (priority == TraceInterval.RegisterPriority.ShouldHaveRegister) {
-                                return null;
-                            }
-                        }
-                    }
-                    return (JavaConstant) move.getConstant();
-                }
-            }
-            return null;
-        }
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanRegisterAllocationPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, 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.alloc.trace;
-
-import java.util.List;
-
-import jdk.vm.ci.code.TargetDescription;
-
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
-import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
-import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.Indent;
-import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
-
-final class TraceLinearScanRegisterAllocationPhase extends TraceLinearScanAllocationPhase {
-
-    @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig, TraceBuilderResult<?> traceBuilderResult, TraceLinearScan allocator) {
-        allocator.printIntervals("Before register allocation");
-        allocateRegisters(allocator);
-        allocator.printIntervals("After register allocation");
-    }
-
-    @SuppressWarnings("try")
-    private static void allocateRegisters(TraceLinearScan allocator) {
-        try (Indent indent = Debug.logAndIndent("allocate registers")) {
-            FixedInterval precoloredIntervals = allocator.createFixedUnhandledList();
-            TraceInterval notPrecoloredIntervals = allocator.createUnhandledList(TraceLinearScan.IS_VARIABLE_INTERVAL);
-
-            // allocate cpu registers
-            TraceLinearScanWalker lsw = new TraceLinearScanWalker(allocator, precoloredIntervals, notPrecoloredIntervals);
-            lsw.walk();
-            lsw.finishAllocation();
-        }
-    }
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanResolveDataFlowPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,240 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, 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.alloc.trace;
-
-import static com.oracle.graal.compiler.common.GraalOptions.DetailedAsserts;
-import static com.oracle.graal.lir.LIRValueUtil.asConstant;
-import static com.oracle.graal.lir.LIRValueUtil.isConstantValue;
-import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
-import static com.oracle.graal.lir.LIRValueUtil.isVirtualStackSlot;
-import static jdk.vm.ci.code.ValueUtil.isRegister;
-
-import java.util.BitSet;
-import java.util.List;
-import java.util.ListIterator;
-
-import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.meta.Value;
-
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
-import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
-import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.DebugMetric;
-import com.oracle.graal.debug.Indent;
-import com.oracle.graal.lir.LIRInstruction;
-import com.oracle.graal.lir.StandardOp;
-import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
-import com.oracle.graal.lir.ssa.SSAUtil.PhiValueVisitor;
-import com.oracle.graal.lir.ssi.SSIUtil;
-
-/**
- * Phase 6: resolve data flow
- *
- * Insert moves at edges between blocks if intervals have been split.
- */
-final class TraceLinearScanResolveDataFlowPhase extends TraceLinearScanAllocationPhase {
-
-    @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig, TraceBuilderResult<?> traceBuilderResult, TraceLinearScan allocator) {
-        new Resolver(allocator, traceBuilderResult).resolveDataFlow(allocator.sortedBlocks());
-    }
-
-    private static final class Resolver {
-        private final TraceLinearScan allocator;
-        private final TraceBuilderResult<?> traceBuilderResult;
-
-        private Resolver(TraceLinearScan allocator, TraceBuilderResult<?> traceBuilderResult) {
-            this.allocator = allocator;
-            this.traceBuilderResult = traceBuilderResult;
-        }
-
-        private void resolveFindInsertPos(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, TraceLocalMoveResolver moveResolver) {
-            if (fromBlock.getSuccessorCount() <= 1) {
-                if (Debug.isLogEnabled()) {
-                    Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId());
-                }
-
-                List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(fromBlock);
-                LIRInstruction instr = instructions.get(instructions.size() - 1);
-                if (instr instanceof StandardOp.JumpOp) {
-                    // insert moves before branch
-                    moveResolver.setInsertPosition(instructions, instructions.size() - 1);
-                } else {
-                    moveResolver.setInsertPosition(instructions, instructions.size());
-                }
-
-            } else {
-                if (Debug.isLogEnabled()) {
-                    Debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId());
-                }
-
-                if (DetailedAsserts.getValue()) {
-                    assert allocator.getLIR().getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label";
-
-                    /*
-                     * Because the number of predecessor edges matches the number of successor
-                     * edges, blocks which are reached by switch statements may have be more than
-                     * one predecessor but it will be guaranteed that all predecessors will be the
-                     * same.
-                     */
-                    for (AbstractBlockBase<?> predecessor : toBlock.getPredecessors()) {
-                        assert fromBlock == predecessor : "all critical edges must be broken";
-                    }
-                }
-
-                moveResolver.setInsertPosition(allocator.getLIR().getLIRforBlock(toBlock), 1);
-            }
-        }
-
-        /**
-         * Inserts necessary moves (spilling or reloading) at edges between blocks for intervals
-         * that have been split.
-         */
-        @SuppressWarnings("try")
-        private void resolveDataFlow(List<? extends AbstractBlockBase<?>> blocks) {
-            if (blocks.size() < 2) {
-                // no resolution necessary
-                return;
-            }
-            try (Indent indent = Debug.logAndIndent("resolve data flow")) {
-
-                TraceLocalMoveResolver moveResolver = allocator.createMoveResolver();
-                ListIterator<? extends AbstractBlockBase<?>> it = blocks.listIterator();
-                AbstractBlockBase<?> toBlock = null;
-                for (AbstractBlockBase<?> fromBlock = it.next(); it.hasNext(); fromBlock = toBlock) {
-                    toBlock = it.next();
-                    assert containedInTrace(fromBlock) : "Not in Trace: " + fromBlock;
-                    assert containedInTrace(toBlock) : "Not in Trace: " + toBlock;
-                    resolveCollectMappings(fromBlock, toBlock, moveResolver);
-                }
-                assert blocks.get(blocks.size() - 1).equals(toBlock);
-                if (toBlock.isLoopEnd()) {
-                    assert toBlock.getSuccessorCount() == 1;
-                    AbstractBlockBase<?> loopHeader = toBlock.getSuccessors().get(0);
-                    if (containedInTrace(loopHeader)) {
-                        resolveCollectMappings(toBlock, loopHeader, moveResolver);
-                    }
-                }
-
-            }
-        }
-
-        @SuppressWarnings("try")
-        private void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, TraceLocalMoveResolver moveResolver) {
-            try (Indent indent0 = Debug.logAndIndent("Edge %s -> %s", fromBlock, toBlock)) {
-                collectLSRAMappings(fromBlock, toBlock, moveResolver);
-                collectSSIMappings(fromBlock, toBlock, moveResolver);
-            }
-        }
-
-        protected void collectLSRAMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, TraceLocalMoveResolver moveResolver) {
-            assert moveResolver.checkEmpty();
-
-            int toBlockFirstInstructionId = allocator.getFirstLirInstructionId(toBlock);
-            int fromBlockLastInstructionId = allocator.getLastLirInstructionId(fromBlock) + 1;
-            int numOperands = allocator.operandSize();
-            BitSet liveAtEdge = allocator.getBlockData(toBlock).liveIn;
-
-            // visit all variables for which the liveAtEdge bit is set
-            for (int operandNum = liveAtEdge.nextSetBit(0); operandNum >= 0; operandNum = liveAtEdge.nextSetBit(operandNum + 1)) {
-                assert operandNum < numOperands : "live information set for not exisiting interval";
-                assert allocator.getBlockData(fromBlock).liveOut.get(operandNum) && allocator.getBlockData(toBlock).liveIn.get(operandNum) : "interval not live at this edge";
-
-                TraceInterval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(operandNum), fromBlockLastInstructionId, LIRInstruction.OperandMode.DEF);
-                TraceInterval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(operandNum), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF);
-
-                if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) {
-                    // need to insert move instruction
-                    moveResolver.addMapping(fromInterval, toInterval);
-                }
-            }
-        }
-
-        protected void collectSSIMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, TraceLocalMoveResolver moveResolver) {
-            // collect all intervals that have been split between
-            // fromBlock and toBlock
-            SSIUtil.forEachValuePair(allocator.getLIR(), toBlock, fromBlock, new MyPhiValueVisitor(moveResolver, toBlock, fromBlock));
-            if (moveResolver.hasMappings()) {
-                resolveFindInsertPos(fromBlock, toBlock, moveResolver);
-                moveResolver.resolveAndAppendMoves();
-            }
-        }
-
-        private boolean containedInTrace(AbstractBlockBase<?> block) {
-            return currentTrace() == traceBuilderResult.getTraceForBlock(block);
-        }
-
-        private int currentTrace() {
-            return traceBuilderResult.getTraceForBlock(allocator.sortedBlocks().get(0));
-        }
-
-        private static final DebugMetric numSSIResolutionMoves = Debug.metric("SSI LSRA[numSSIResolutionMoves]");
-        private static final DebugMetric numStackToStackMoves = Debug.metric("SSI LSRA[numStackToStackMoves]");
-
-        private class MyPhiValueVisitor implements PhiValueVisitor {
-            final TraceLocalMoveResolver moveResolver;
-            final int toId;
-            final int fromId;
-
-            public MyPhiValueVisitor(TraceLocalMoveResolver moveResolver, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> fromBlock) {
-                this.moveResolver = moveResolver;
-                toId = allocator.getFirstLirInstructionId(toBlock);
-                fromId = allocator.getLastLirInstructionId(fromBlock);
-                assert fromId >= 0;
-            }
-
-            public void visit(Value phiIn, Value phiOut) {
-                assert !isRegister(phiOut) : "Out is a register: " + phiOut;
-                assert !isRegister(phiIn) : "In is a register: " + phiIn;
-                if (Value.ILLEGAL.equals(phiIn)) {
-                    // The value not needed in this branch.
-                    return;
-                }
-                if (isVirtualStackSlot(phiIn) && isVirtualStackSlot(phiOut) && phiIn.equals(phiOut)) {
-                    // no need to handle virtual stack slots
-                    return;
-                }
-                TraceInterval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiIn), toId, LIRInstruction.OperandMode.DEF);
-                if (isConstantValue(phiOut)) {
-                    numSSIResolutionMoves.increment();
-                    moveResolver.addMapping(asConstant(phiOut), toInterval);
-                } else {
-                    TraceInterval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiOut), fromId, LIRInstruction.OperandMode.DEF);
-                    if (fromInterval != toInterval) {
-                        numSSIResolutionMoves.increment();
-                        if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) {
-                            moveResolver.addMapping(fromInterval, toInterval);
-                        } else {
-                            numStackToStackMoves.increment();
-                            moveResolver.addMapping(fromInterval, toInterval);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanWalker.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1036 +0,0 @@
-/*
- * Copyright (c) 2009, 2015, 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.alloc.trace;
-
-import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
-import static com.oracle.graal.lir.LIRValueUtil.isVariable;
-import static jdk.vm.ci.code.CodeUtil.isOdd;
-import static jdk.vm.ci.code.ValueUtil.asRegister;
-import static jdk.vm.ci.code.ValueUtil.isRegister;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import jdk.vm.ci.code.BailoutException;
-import jdk.vm.ci.code.Register;
-import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.meta.Value;
-
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig.AllocatableRegisters;
-import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
-import com.oracle.graal.compiler.common.util.Util;
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.Indent;
-import com.oracle.graal.lir.LIRInstruction;
-import com.oracle.graal.lir.StandardOp.BlockEndOp;
-import com.oracle.graal.lir.StandardOp.LabelOp;
-import com.oracle.graal.lir.StandardOp.ValueMoveOp;
-import com.oracle.graal.lir.alloc.lsra.OutOfRegistersException;
-import com.oracle.graal.lir.alloc.trace.TraceInterval.RegisterPriority;
-import com.oracle.graal.lir.alloc.trace.TraceInterval.SpillState;
-import com.oracle.graal.lir.alloc.trace.TraceInterval.State;
-
-/**
- */
-final class TraceLinearScanWalker extends TraceIntervalWalker {
-
-    private Register[] availableRegs;
-
-    private final int[] usePos;
-    private final int[] blockPos;
-
-    private List<TraceInterval>[] spillIntervals;
-
-    private TraceLocalMoveResolver moveResolver; // for ordering spill moves
-
-    private int minReg;
-
-    private int maxReg;
-
-    /**
-     * Only 10% of the lists in {@link #spillIntervals} are actually used. But when they are used,
-     * they can grow quite long. The maximum length observed was 45 (all numbers taken from a
-     * bootstrap run of Graal). Therefore, we initialize {@link #spillIntervals} with this marker
-     * value, and allocate a "real" list only on demand in {@link #setUsePos}.
-     */
-    private static final List<TraceInterval> EMPTY_LIST = new ArrayList<>(0);
-
-    // accessors mapped to same functions in class LinearScan
-    private int blockCount() {
-        return allocator.blockCount();
-    }
-
-    private AbstractBlockBase<?> blockAt(int idx) {
-        return allocator.blockAt(idx);
-    }
-
-    @SuppressWarnings("unused")
-    private AbstractBlockBase<?> blockOfOpWithId(int opId) {
-        return allocator.blockForId(opId);
-    }
-
-    TraceLinearScanWalker(TraceLinearScan allocator, FixedInterval unhandledFixedFirst, TraceInterval unhandledAnyFirst) {
-        super(allocator, unhandledFixedFirst, unhandledAnyFirst);
-
-        moveResolver = allocator.createMoveResolver();
-        spillIntervals = Util.uncheckedCast(new List<?>[allocator.getRegisters().length]);
-        for (int i = 0; i < allocator.getRegisters().length; i++) {
-            spillIntervals[i] = EMPTY_LIST;
-        }
-        usePos = new int[allocator.getRegisters().length];
-        blockPos = new int[allocator.getRegisters().length];
-    }
-
-    private void initUseLists(boolean onlyProcessUsePos) {
-        for (Register register : availableRegs) {
-            int i = register.number;
-            usePos[i] = Integer.MAX_VALUE;
-
-            if (!onlyProcessUsePos) {
-                blockPos[i] = Integer.MAX_VALUE;
-                spillIntervals[i].clear();
-            }
-        }
-    }
-
-    private int maxRegisterNumber() {
-        return maxReg;
-    }
-
-    private int minRegisterNumber() {
-        return minReg;
-    }
-
-    private boolean isRegisterInRange(int reg) {
-        return reg >= minRegisterNumber() && reg <= maxRegisterNumber();
-    }
-
-    private void excludeFromUse(IntervalHint i) {
-        Value location = i.location();
-        int i1 = asRegister(location).number;
-        if (isRegisterInRange(i1)) {
-            usePos[i1] = 0;
-        }
-    }
-
-    private void setUsePos(TraceInterval interval, int usePos, boolean onlyProcessUsePos) {
-        if (usePos != -1) {
-            assert usePos != 0 : "must use excludeFromUse to set usePos to 0";
-            int i = asRegister(interval.location()).number;
-            if (isRegisterInRange(i)) {
-                if (this.usePos[i] > usePos) {
-                    this.usePos[i] = usePos;
-                }
-                if (!onlyProcessUsePos) {
-                    List<TraceInterval> list = spillIntervals[i];
-                    if (list == EMPTY_LIST) {
-                        list = new ArrayList<>(2);
-                        spillIntervals[i] = list;
-                    }
-                    list.add(interval);
-                }
-            }
-        }
-    }
-
-    private void setUsePos(FixedInterval interval, int usePos, boolean onlyProcessUsePos) {
-        assert onlyProcessUsePos;
-        if (usePos != -1) {
-            assert usePos != 0 : "must use excludeFromUse to set usePos to 0";
-            int i = asRegister(interval.location()).number;
-            if (isRegisterInRange(i)) {
-                if (this.usePos[i] > usePos) {
-                    this.usePos[i] = usePos;
-                }
-            }
-        }
-    }
-
-    private void setBlockPos(IntervalHint i, int blockPos) {
-        if (blockPos != -1) {
-            int reg = asRegister(i.location()).number;
-            if (isRegisterInRange(reg)) {
-                if (this.blockPos[reg] > blockPos) {
-                    this.blockPos[reg] = blockPos;
-                }
-                if (usePos[reg] > blockPos) {
-                    usePos[reg] = blockPos;
-                }
-            }
-        }
-    }
-
-    private void freeExcludeActiveFixed() {
-        FixedInterval interval = activeFixedList.getFixed();
-        while (interval != FixedInterval.EndMarker) {
-            assert isRegister(interval.location()) : "active interval must have a register assigned";
-            excludeFromUse(interval);
-            interval = interval.next;
-        }
-    }
-
-    private void freeExcludeActiveAny() {
-        TraceInterval interval = activeAnyList.getAny();
-        while (interval != TraceInterval.EndMarker) {
-            assert isRegister(interval.location()) : "active interval must have a register assigned";
-            excludeFromUse(interval);
-            interval = interval.next;
-        }
-    }
-
-    private void freeCollectInactiveFixed(TraceInterval current) {
-        FixedInterval interval = inactiveFixedList.getFixed();
-        while (interval != FixedInterval.EndMarker) {
-            if (current.to() <= interval.from()) {
-                assert interval.intersectsAt(current) == -1 : "must not intersect";
-                setUsePos(interval, interval.from(), true);
-            } else {
-                setUsePos(interval, interval.currentIntersectsAt(current), true);
-            }
-            interval = interval.next;
-        }
-    }
-
-    private void spillExcludeActiveFixed() {
-        FixedInterval interval = activeFixedList.getFixed();
-        while (interval != FixedInterval.EndMarker) {
-            excludeFromUse(interval);
-            interval = interval.next;
-        }
-    }
-
-    private void spillBlockInactiveFixed(TraceInterval current) {
-        FixedInterval interval = inactiveFixedList.getFixed();
-        while (interval != FixedInterval.EndMarker) {
-            if (current.to() > interval.currentFrom()) {
-                setBlockPos(interval, interval.currentIntersectsAt(current));
-            } else {
-                assert interval.currentIntersectsAt(current) == -1 : "invalid optimization: intervals intersect";
-            }
-
-            interval = interval.next;
-        }
-    }
-
-    private void spillCollectActiveAny(RegisterPriority registerPriority) {
-        TraceInterval interval = activeAnyList.getAny();
-        while (interval != TraceInterval.EndMarker) {
-            setUsePos(interval, Math.min(interval.nextUsage(registerPriority, currentPosition), interval.to()), false);
-            interval = interval.next;
-        }
-    }
-
-    @SuppressWarnings("unused")
-    private int insertIdAtBasicBlockBoundary(int opId) {
-        assert allocator.isBlockBegin(opId) : "Not a block begin: " + opId;
-        assert allocator.instructionForId(opId) instanceof LabelOp;
-        assert allocator.instructionForId(opId - 2) instanceof BlockEndOp;
-
-        AbstractBlockBase<?> toBlock = allocator.blockForId(opId);
-        AbstractBlockBase<?> fromBlock = allocator.blockForId(opId - 2);
-
-        if (fromBlock.getSuccessorCount() == 1) {
-            // insert move in predecessor
-            return opId - 2;
-        }
-        assert toBlock.getPredecessorCount() == 1 : String.format("Critical Edge? %s->%s", fromBlock, toBlock);
-        // insert move in successor
-        return opId + 2;
-    }
-
-    private void insertMove(int operandId, TraceInterval srcIt, TraceInterval dstIt) {
-        // output all moves here. When source and target are equal, the move is
-        // optimized away later in assignRegNums
-
-        int opId = (operandId + 1) & ~1;
-        AbstractBlockBase<?> opBlock = allocator.blockForId(opId);
-        assert opId > 0 && allocator.blockForId(opId - 2) == opBlock : "cannot insert move at block boundary";
-
-        // calculate index of instruction inside instruction list of current block
-        // the minimal index (for a block with no spill moves) can be calculated because the
-        // numbering of instructions is known.
-        // When the block already contains spill moves, the index must be increased until the
-        // correct index is reached.
-        List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(opBlock);
-        int index = (opId - instructions.get(0).id()) >> 1;
-        assert instructions.get(index).id() <= opId : "error in calculation";
-
-        while (instructions.get(index).id() != opId) {
-            index++;
-            assert 0 <= index && index < instructions.size() : "index out of bounds";
-        }
-        assert 1 <= index && index < instructions.size() : "index out of bounds";
-        assert instructions.get(index).id() == opId : "error in calculation";
-
-        // insert new instruction before instruction at position index
-        moveResolver.moveInsertPosition(instructions, index);
-        moveResolver.addMapping(srcIt, dstIt);
-    }
-
-    private int findOptimalSplitPos(AbstractBlockBase<?> minBlock, AbstractBlockBase<?> maxBlock, int maxSplitPos) {
-        int fromBlockNr = minBlock.getLinearScanNumber();
-        int toBlockNr = maxBlock.getLinearScanNumber();
-
-        assert 0 <= fromBlockNr && fromBlockNr < blockCount() : "out of range";
-        assert 0 <= toBlockNr && toBlockNr < blockCount() : "out of range";
-        assert fromBlockNr < toBlockNr : "must cross block boundary";
-
-        // Try to split at end of maxBlock. If this would be after
-        // maxSplitPos, then use the begin of maxBlock
-        int optimalSplitPos = allocator.getLastLirInstructionId(maxBlock) + 2;
-        if (optimalSplitPos > maxSplitPos) {
-            optimalSplitPos = allocator.getFirstLirInstructionId(maxBlock);
-        }
-
-        // minimal block probability
-        double minProbability = maxBlock.probability();
-        for (int i = toBlockNr - 1; i >= fromBlockNr; i--) {
-            AbstractBlockBase<?> cur = blockAt(i);
-
-            if (cur.probability() < minProbability) {
-                // Block with lower probability found. Split at the end of this block.
-                minProbability = cur.probability();
-                optimalSplitPos = allocator.getLastLirInstructionId(cur) + 2;
-            }
-        }
-        assert optimalSplitPos > allocator.maxOpId() || allocator.isBlockBegin(optimalSplitPos) : "algorithm must move split pos to block boundary";
-
-        return optimalSplitPos;
-    }
-
-    private int findOptimalSplitPos(TraceInterval interval, int minSplitPos, int maxSplitPos, boolean doLoopOptimization) {
-        int optimalSplitPos = findOptimalSplitPos0(interval, minSplitPos, maxSplitPos, doLoopOptimization);
-        if (Debug.isLogEnabled()) {
-            Debug.log("optimal split position: %d", optimalSplitPos);
-        }
-        return optimalSplitPos;
-    }
-
-    @SuppressWarnings({"unused"})
-    private int findOptimalSplitPos0(TraceInterval interval, int minSplitPos, int maxSplitPos, boolean doLoopOptimization) {
-        // TODO (je) implement
-        if (minSplitPos == maxSplitPos) {
-            // trivial case, no optimization of split position possible
-            if (Debug.isLogEnabled()) {
-                Debug.log("min-pos and max-pos are equal, no optimization possible");
-            }
-            return minSplitPos;
-
-        }
-        assert minSplitPos < maxSplitPos : "must be true then";
-        assert minSplitPos > 0 : "cannot access minSplitPos - 1 otherwise";
-
-        // reason for using minSplitPos - 1: when the minimal split pos is exactly at the
-        // beginning of a block, then minSplitPos is also a possible split position.
-        // Use the block before as minBlock, because then minBlock.lastLirInstructionId() + 2 ==
-        // minSplitPos
-        AbstractBlockBase<?> minBlock = allocator.blockForId(minSplitPos - 1);
-
-        // reason for using maxSplitPos - 1: otherwise there would be an assert on failure
-        // when an interval ends at the end of the last block of the method
-        // (in this case, maxSplitPos == allocator().maxLirOpId() + 2, and there is no
-        // block at this opId)
-        AbstractBlockBase<?> maxBlock = allocator.blockForId(maxSplitPos - 1);
-
-        assert minBlock.getLinearScanNumber() <= maxBlock.getLinearScanNumber() : "invalid order";
-        if (minBlock == maxBlock) {
-            // split position cannot be moved to block boundary : so split as late as possible
-            if (Debug.isLogEnabled()) {
-                Debug.log("cannot move split pos to block boundary because minPos and maxPos are in same block");
-            }
-            return maxSplitPos;
-
-        }
-        // seach optimal block boundary between minSplitPos and maxSplitPos
-        if (Debug.isLogEnabled()) {
-            Debug.log("moving split pos to optimal block boundary between block B%d and B%d", minBlock.getId(), maxBlock.getId());
-        }
-
-        return findOptimalSplitPos(minBlock, maxBlock, maxSplitPos);
-    }
-
-    // split an interval at the optimal position between minSplitPos and
-    // maxSplitPos in two parts:
-    // 1) the left part has already a location assigned
-    // 2) the right part is sorted into to the unhandled-list
-    @SuppressWarnings("try")
-    private void splitBeforeUsage(TraceInterval interval, int minSplitPos, int maxSplitPos) {
-
-        try (Indent indent = Debug.logAndIndent("splitting interval %s between %d and %d", interval, minSplitPos, maxSplitPos)) {
-
-            assert interval.from() < minSplitPos : "cannot split at start of interval";
-            assert currentPosition < minSplitPos : "cannot split before current position";
-            assert minSplitPos <= maxSplitPos : "invalid order";
-            assert maxSplitPos <= interval.to() : "cannot split after end of interval";
-
-            final int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, true);
-
-            if (optimalSplitPos == interval.to() && interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos) == Integer.MAX_VALUE) {
-                // the split position would be just before the end of the interval
-                // . no split at all necessary
-                if (Debug.isLogEnabled()) {
-                    Debug.log("no split necessary because optimal split position is at end of interval");
-                }
-                return;
-            }
-            // must calculate this before the actual split is performed and before split position is
-            // moved to odd opId
-            final int optimalSplitPosFinal;
-            boolean blockBegin = allocator.isBlockBegin(optimalSplitPos);
-            if (blockBegin) {
-                assert (optimalSplitPos & 1) == 0 : "Block begins must be even: " + optimalSplitPos;
-                // move position after the label (odd optId)
-                optimalSplitPosFinal = optimalSplitPos + 1;
-            } else {
-                // move position before actual instruction (odd opId)
-                optimalSplitPosFinal = (optimalSplitPos - 1) | 1;
-            }
-
-            // TODO( je) better define what min split pos max split pos mean.
-            assert minSplitPos <= optimalSplitPosFinal && optimalSplitPosFinal <= maxSplitPos || minSplitPos == maxSplitPos && optimalSplitPosFinal == minSplitPos - 1 : "out of range";
-            assert optimalSplitPosFinal <= interval.to() : "cannot split after end of interval";
-            assert optimalSplitPosFinal > interval.from() : "cannot split at start of interval";
-
-            if (Debug.isLogEnabled()) {
-                Debug.log("splitting at position %d", optimalSplitPosFinal);
-            }
-            assert optimalSplitPosFinal > currentPosition : "Can not split interval " + interval + " at current position: " + currentPosition;
-
-            // was:
-            // assert isBlockBegin || ((optimalSplitPos1 & 1) == 1) :
-            // "split pos must be odd when not on block boundary";
-            // assert !isBlockBegin || ((optimalSplitPos1 & 1) == 0) :
-            // "split pos must be even on block boundary";
-            assert (optimalSplitPosFinal & 1) == 1 : "split pos must be odd";
-
-            // TODO (je) duplicate code. try to fold
-            if (optimalSplitPosFinal == interval.to() && interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos) == Integer.MAX_VALUE) {
-                // the split position would be just before the end of the interval
-                // . no split at all necessary
-                if (Debug.isLogEnabled()) {
-                    Debug.log("no split necessary because optimal split position is at end of interval");
-                }
-                return;
-            }
-            TraceInterval splitPart = interval.split(optimalSplitPosFinal, allocator);
-
-            boolean moveNecessary = true;
-            splitPart.setInsertMoveWhenActivated(moveNecessary);
-
-            assert splitPart.from() >= currentPosition : "cannot append new interval before current walk position";
-            unhandledAnyList.addToListSortedByStartAndUsePositions(splitPart);
-
-            if (Debug.isLogEnabled()) {
-                Debug.log("left interval  %s: %s", moveNecessary ? "      " : "", interval.logString(allocator));
-                Debug.log("right interval %s: %s", moveNecessary ? "(move)" : "", splitPart.logString(allocator));
-            }
-        }
-    }
-
-    // split an interval at the optimal position between minSplitPos and
-    // maxSplitPos in two parts:
-    // 1) the left part has already a location assigned
-    // 2) the right part is always on the stack and therefore ignored in further processing
-    @SuppressWarnings("try")
-    private void splitForSpilling(TraceInterval interval) {
-        // calculate allowed range of splitting position
-        int maxSplitPos = currentPosition;
-        int previousUsage = interval.previousUsage(RegisterPriority.ShouldHaveRegister, maxSplitPos);
-        if (previousUsage == currentPosition) {
-            /*
-             * If there is a usage with ShouldHaveRegister priority at the current position fall
-             * back to MustHaveRegister priority. This only happens if register priority was
-             * downgraded to MustHaveRegister in #allocLockedRegister.
-             */
-            previousUsage = interval.previousUsage(RegisterPriority.MustHaveRegister, maxSplitPos);
-        }
-        int minSplitPos = Math.max(previousUsage + 1, interval.from());
-
-        try (Indent indent = Debug.logAndIndent("splitting and spilling interval %s between %d and %d", interval, minSplitPos, maxSplitPos)) {
-
-            assert interval.state == State.Active : "why spill interval that is not active?";
-            assert interval.from() <= minSplitPos : "cannot split before start of interval";
-            assert minSplitPos <= maxSplitPos : "invalid order";
-            assert maxSplitPos < interval.to() : "cannot split at end end of interval";
-            assert currentPosition < interval.to() : "interval must not end before current position";
-
-            if (minSplitPos == interval.from()) {
-                // the whole interval is never used, so spill it entirely to memory
-
-                try (Indent indent2 = Debug.logAndIndent("spilling entire interval because split pos is at beginning of interval (use positions: %d)", interval.usePosList().size())) {
-
-                    assert interval.firstUsage(RegisterPriority.MustHaveRegister) > currentPosition : String.format("interval %s must not have use position before currentPosition %d", interval,
-                                    currentPosition);
-
-                    allocator.assignSpillSlot(interval);
-                    handleSpillSlot(interval);
-                    changeSpillState(interval, minSplitPos);
-
-                    // Also kick parent intervals out of register to memory when they have no use
-                    // position. This avoids short interval in register surrounded by intervals in
-                    // memory . avoid useless moves from memory to register and back
-                    TraceInterval parent = interval;
-                    while (parent != null && parent.isSplitChild()) {
-                        parent = parent.getSplitChildBeforeOpId(parent.from());
-
-                        if (isRegister(parent.location())) {
-                            if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) {
-                                // parent is never used, so kick it out of its assigned register
-                                if (Debug.isLogEnabled()) {
-                                    Debug.log("kicking out interval %d out of its register because it is never used", parent.operandNumber);
-                                }
-                                allocator.assignSpillSlot(parent);
-                                handleSpillSlot(parent);
-                            } else {
-                                // do not go further back because the register is actually used by
-                                // the interval
-                                parent = null;
-                            }
-                        }
-                    }
-                }
-
-            } else {
-                // search optimal split pos, split interval and spill only the right hand part
-                int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, false);
-
-                assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range";
-                assert optimalSplitPos < interval.to() : "cannot split at end of interval";
-                assert optimalSplitPos >= interval.from() : "cannot split before start of interval";
-
-                if (!allocator.isBlockBegin(optimalSplitPos)) {
-                    // move position before actual instruction (odd opId)
-                    optimalSplitPos = (optimalSplitPos - 1) | 1;
-                }
-
-                try (Indent indent2 = Debug.logAndIndent("splitting at position %d", optimalSplitPos)) {
-                    assert allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 1) : "split pos must be odd when not on block boundary";
-                    assert !allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 0) : "split pos must be even on block boundary";
-
-                    TraceInterval spilledPart = interval.split(optimalSplitPos, allocator);
-                    allocator.assignSpillSlot(spilledPart);
-                    handleSpillSlot(spilledPart);
-                    changeSpillState(spilledPart, optimalSplitPos);
-
-                    if (!allocator.isBlockBegin(optimalSplitPos)) {
-                        if (Debug.isLogEnabled()) {
-                            Debug.log("inserting move from interval %s to %s", interval, spilledPart);
-                        }
-                        insertMove(optimalSplitPos, interval, spilledPart);
-                    } else {
-                        if (Debug.isLogEnabled()) {
-                            Debug.log("no need to insert move. done by data-flow resolution");
-                        }
-                    }
-
-                    // the currentSplitChild is needed later when moves are inserted for reloading
-                    assert spilledPart.currentSplitChild() == interval : "overwriting wrong currentSplitChild";
-                    spilledPart.makeCurrentSplitChild();
-
-                    if (Debug.isLogEnabled()) {
-                        Debug.log("left interval: %s", interval.logString(allocator));
-                        Debug.log("spilled interval   : %s", spilledPart.logString(allocator));
-                    }
-                }
-            }
-        }
-    }
-
-    // called during register allocation
-    private void changeSpillState(TraceInterval interval, int spillPos) {
-        if (TraceLinearScan.Options.LIROptTraceRAEliminateSpillMoves.getValue()) {
-            switch (interval.spillState()) {
-                case NoSpillStore: {
-                    int defLoopDepth = allocator.blockForId(interval.spillDefinitionPos()).getLoopDepth();
-                    int spillLoopDepth = allocator.blockForId(spillPos).getLoopDepth();
-
-                    if (defLoopDepth < spillLoopDepth) {
-                        /*
-                         * The loop depth of the spilling position is higher then the loop depth at
-                         * the definition of the interval. Move write to memory out of loop.
-                         */
-                        // store at definition of the interval
-                        interval.setSpillState(SpillState.StoreAtDefinition);
-                    } else {
-                        /*
-                         * The interval is currently spilled only once, so for now there is no
-                         * reason to store the interval at the definition.
-                         */
-                        interval.setSpillState(SpillState.OneSpillStore);
-                    }
-                    break;
-                }
-
-                case OneSpillStore: {
-                    // It is better to store it to memory at the definition.
-                    interval.setSpillState(SpillState.StoreAtDefinition);
-                    break;
-                }
-
-                case SpillInDominator:
-                case StoreAtDefinition:
-                case StartInMemory:
-                case NoOptimization:
-                case NoDefinitionFound:
-                    // nothing to do
-                    break;
-
-                default:
-                    throw new BailoutException("other states not allowed at this time");
-            }
-        } else {
-            interval.setSpillState(SpillState.NoOptimization);
-        }
-    }
-
-    /**
-     * This is called for every interval that is assigned to a stack slot.
-     */
-    private static void handleSpillSlot(TraceInterval interval) {
-        assert interval.location() != null && (interval.canMaterialize() || isStackSlotValue(interval.location())) : "interval not assigned to a stack slot " + interval;
-        // Do nothing. Stack slots are not processed in this implementation.
-    }
-
-    private void splitStackInterval(TraceInterval interval) {
-        int minSplitPos = currentPosition + 1;
-        int maxSplitPos = Math.min(interval.firstUsage(RegisterPriority.ShouldHaveRegister), interval.to());
-
-        splitBeforeUsage(interval, minSplitPos, maxSplitPos);
-    }
-
-    private void splitWhenPartialRegisterAvailable(TraceInterval interval, int registerAvailableUntil) {
-        int minSplitPos = Math.max(interval.previousUsage(RegisterPriority.ShouldHaveRegister, registerAvailableUntil), interval.from() + 1);
-        splitBeforeUsage(interval, minSplitPos, registerAvailableUntil);
-    }
-
-    private void splitAndSpillInterval(TraceInterval interval) {
-        assert interval.state == State.Active || interval.state == State.Inactive : "other states not allowed";
-
-        int currentPos = currentPosition;
-        if (interval.state == State.Inactive) {
-            // the interval is currently inactive, so no spill slot is needed for now.
-            // when the split part is activated, the interval has a new chance to get a register,
-            // so in the best case no stack slot is necessary
-            throw JVMCIError.shouldNotReachHere("TraceIntervals can not be inactive!");
-
-        } else {
-            // search the position where the interval must have a register and split
-            // at the optimal position before.
-            // The new created part is added to the unhandled list and will get a register
-            // when it is activated
-            int minSplitPos = currentPos + 1;
-            int maxSplitPos = interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos);
-
-            if (maxSplitPos <= interval.to()) {
-                splitBeforeUsage(interval, minSplitPos, maxSplitPos);
-            } else {
-                Debug.log("No more usage, no need to split: %s", interval);
-            }
-
-            assert interval.nextUsage(RegisterPriority.MustHaveRegister, currentPos) == Integer.MAX_VALUE : "the remaining part is spilled to stack and therefore has no register";
-            splitForSpilling(interval);
-        }
-    }
-
-    @SuppressWarnings("try")
-    private boolean allocFreeRegister(TraceInterval interval) {
-        try (Indent indent = Debug.logAndIndent("trying to find free register for %s", interval)) {
-
-            initUseLists(true);
-            freeExcludeActiveFixed();
-            freeCollectInactiveFixed(interval);
-            freeExcludeActiveAny();
-            // freeCollectUnhandled(fixedKind, cur);
-
-            // usePos contains the start of the next interval that has this register assigned
-            // (either as a fixed register or a normal allocated register in the past)
-            // only intervals overlapping with cur are processed, non-overlapping invervals can be
-            // ignored safely
-            if (Debug.isLogEnabled()) {
-                // Enable this logging to see all register states
-                try (Indent indent2 = Debug.logAndIndent("state of registers:")) {
-                    for (Register register : availableRegs) {
-                        int i = register.number;
-                        Debug.log("reg %d (%s): usePos: %d", register.number, register, usePos[i]);
-                    }
-                }
-            }
-
-            Register hint = null;
-            IntervalHint locationHint = interval.locationHint(true);
-            if (locationHint != null && locationHint.location() != null && isRegister(locationHint.location())) {
-                hint = asRegister(locationHint.location());
-                if (Debug.isLogEnabled()) {
-                    Debug.log("hint register %3d (%4s) from interval %s", hint.number, hint, locationHint);
-                }
-            }
-            assert interval.location() == null : "register already assigned to interval";
-
-            // the register must be free at least until this position
-            int regNeededUntil = interval.from() + 1;
-            int intervalTo = interval.to();
-
-            boolean needSplit = false;
-            int splitPos = -1;
-
-            Register reg = null;
-            Register minFullReg = null;
-            Register maxPartialReg = null;
-
-            for (Register availableReg : availableRegs) {
-                int number = availableReg.number;
-                if (usePos[number] >= intervalTo) {
-                    // this register is free for the full interval
-                    if (minFullReg == null || availableReg.equals(hint) || (usePos[number] < usePos[minFullReg.number] && !minFullReg.equals(hint))) {
-                        minFullReg = availableReg;
-                    }
-                } else if (usePos[number] > regNeededUntil) {
-                    // this register is at least free until regNeededUntil
-                    if (maxPartialReg == null || availableReg.equals(hint) || (usePos[number] > usePos[maxPartialReg.number] && !maxPartialReg.equals(hint))) {
-                        maxPartialReg = availableReg;
-                    }
-                }
-            }
-
-            if (minFullReg != null) {
-                reg = minFullReg;
-            } else if (maxPartialReg != null) {
-                needSplit = true;
-                reg = maxPartialReg;
-            } else {
-                return false;
-            }
-
-            splitPos = usePos[reg.number];
-            interval.assignLocation(reg.asValue(interval.kind()));
-            if (Debug.isLogEnabled()) {
-                Debug.log("selected register %d (%s)", reg.number, reg);
-            }
-
-            assert splitPos > 0 : "invalid splitPos";
-            if (needSplit) {
-                // register not available for full interval, so split it
-                splitWhenPartialRegisterAvailable(interval, splitPos);
-            }
-            // only return true if interval is completely assigned
-            return true;
-        }
-    }
-
-    private void splitAndSpillIntersectingIntervals(Register reg) {
-        assert reg != null : "no register assigned";
-
-        for (int i = 0; i < spillIntervals[reg.number].size(); i++) {
-            TraceInterval interval = spillIntervals[reg.number].get(i);
-            removeFromList(interval);
-            splitAndSpillInterval(interval);
-        }
-    }
-
-    // Split an Interval and spill it to memory so that cur can be placed in a register
-    @SuppressWarnings("try")
-    private void allocLockedRegister(TraceInterval interval) {
-        try (Indent indent = Debug.logAndIndent("alloc locked register: need to split and spill to get register for %s", interval)) {
-
-            // the register must be free at least until this position
-            int firstUsage = interval.firstUsage(RegisterPriority.MustHaveRegister);
-            int firstShouldHaveUsage = interval.firstUsage(RegisterPriority.ShouldHaveRegister);
-            int regNeededUntil = Math.min(firstUsage, interval.from() + 1);
-            int intervalTo = interval.to();
-            assert regNeededUntil >= 0 && regNeededUntil < Integer.MAX_VALUE : "interval has no use";
-
-            Register reg;
-            Register ignore;
-            /*
-             * In the common case we don't spill registers that have _any_ use position that is
-             * closer than the next use of the current interval, but if we can't spill the current
-             * interval we weaken this strategy and also allow spilling of intervals that have a
-             * non-mandatory requirements (no MustHaveRegister use position).
-             */
-            for (RegisterPriority registerPriority = RegisterPriority.LiveAtLoopEnd; true; registerPriority = RegisterPriority.MustHaveRegister) {
-                // collect current usage of registers
-                initUseLists(false);
-                spillExcludeActiveFixed();
-                // spillBlockUnhandledFixed(cur);
-                spillBlockInactiveFixed(interval);
-                spillCollectActiveAny(registerPriority);
-                if (Debug.isLogEnabled()) {
-                    printRegisterState();
-                }
-
-                reg = null;
-                ignore = interval.location() != null && isRegister(interval.location()) ? asRegister(interval.location()) : null;
-
-                for (Register availableReg : availableRegs) {
-                    int number = availableReg.number;
-                    if (availableReg.equals(ignore)) {
-                        // this register must be ignored
-                    } else if (usePos[number] > regNeededUntil) {
-                        if (reg == null || (usePos[number] > usePos[reg.number])) {
-                            reg = availableReg;
-                        }
-                    }
-                }
-
-                int regUsePos = (reg == null ? 0 : usePos[reg.number]);
-                if (regUsePos <= firstShouldHaveUsage) {
-                    if (Debug.isLogEnabled()) {
-                        Debug.log("able to spill current interval. firstUsage(register): %d, usePos: %d", firstUsage, regUsePos);
-                    }
-
-                    if (firstUsage <= interval.from() + 1) {
-                        if (registerPriority.equals(RegisterPriority.LiveAtLoopEnd)) {
-                            /*
-                             * Tool of last resort: we can not spill the current interval so we try
-                             * to spill an active interval that has a usage but do not require a
-                             * register.
-                             */
-                            Debug.log("retry with register priority must have register");
-                            continue;
-                        }
-                        String description = "cannot spill interval (" + interval + ") that is used in first instruction (possible reason: no register found) firstUsage=" + firstUsage +
-                                        ", interval.from()=" + interval.from() + "; already used candidates: " + Arrays.toString(availableRegs);
-                        /*
-                         * assign a reasonable register and do a bailout in product mode to avoid
-                         * errors
-                         */
-                        allocator.assignSpillSlot(interval);
-                        Debug.dump(allocator.getLIR(), description);
-                        allocator.printIntervals(description);
-                        throw new OutOfRegistersException("LinearScan: no register found", description);
-                    }
-
-                    splitAndSpillInterval(interval);
-                    return;
-                }
-                break;
-            }
-
-            boolean needSplit = blockPos[reg.number] <= intervalTo;
-
-            int splitPos = blockPos[reg.number];
-
-            if (Debug.isLogEnabled()) {
-                Debug.log("decided to use register %d", reg.number);
-            }
-            assert splitPos > 0 : "invalid splitPos";
-            assert needSplit || splitPos > interval.from() : "splitting interval at from";
-
-            interval.assignLocation(reg.asValue(interval.kind()));
-            if (needSplit) {
-                // register not available for full interval : so split it
-                splitWhenPartialRegisterAvailable(interval, splitPos);
-            }
-
-            // perform splitting and spilling for all affected intervals
-            splitAndSpillIntersectingIntervals(reg);
-            return;
-        }
-    }
-
-    @SuppressWarnings("try")
-    private void printRegisterState() {
-        try (Indent indent2 = Debug.logAndIndent("state of registers:")) {
-            for (Register reg : availableRegs) {
-                int i = reg.number;
-                try (Indent indent3 = Debug.logAndIndent("reg %d: usePos: %d, blockPos: %d, intervals: ", i, usePos[i], blockPos[i])) {
-                    for (int j = 0; j < spillIntervals[i].size(); j++) {
-                        Debug.log("%s ", spillIntervals[i].get(j));
-                    }
-                }
-            }
-        }
-    }
-
-    private boolean noAllocationPossible(TraceInterval interval) {
-        if (allocator.callKillsRegisters()) {
-            // fast calculation of intervals that can never get a register because the
-            // the next instruction is a call that blocks all registers
-            // Note: this only works if a call kills all registers
-
-            // check if this interval is the result of a split operation
-            // (an interval got a register until this position)
-            int pos = interval.from();
-            if (isOdd(pos)) {
-                // the current instruction is a call that blocks all registers
-                if (pos < allocator.maxOpId() && allocator.hasCall(pos + 1) && interval.to() > pos + 1) {
-                    if (Debug.isLogEnabled()) {
-                        Debug.log("free register cannot be available because all registers blocked by following call");
-                    }
-
-                    // safety check that there is really no register available
-                    assert !allocFreeRegister(interval) : "found a register for this interval";
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    private void initVarsForAlloc(TraceInterval interval) {
-        AllocatableRegisters allocatableRegisters = allocator.getRegisterAllocationConfig().getAllocatableRegisters(interval.kind().getPlatformKind());
-        availableRegs = allocatableRegisters.allocatableRegisters;
-        minReg = allocatableRegisters.minRegisterNumber;
-        maxReg = allocatableRegisters.maxRegisterNumber;
-    }
-
-    private static boolean isMove(LIRInstruction op, TraceInterval from, TraceInterval to) {
-        if (op instanceof ValueMoveOp) {
-            ValueMoveOp move = (ValueMoveOp) op;
-            if (isVariable(move.getInput()) && isVariable(move.getResult())) {
-                return move.getInput() != null && move.getInput().equals(from.operand) && move.getResult() != null && move.getResult().equals(to.operand);
-            }
-        }
-        return false;
-    }
-
-    // optimization (especially for phi functions of nested loops):
-    // assign same spill slot to non-intersecting intervals
-    private void combineSpilledIntervals(TraceInterval interval) {
-        if (interval.isSplitChild()) {
-            // optimization is only suitable for split parents
-            return;
-        }
-
-        IntervalHint locationHint = interval.locationHint(false);
-        if (locationHint == null || !(locationHint instanceof TraceInterval)) {
-            return;
-        }
-        TraceInterval registerHint = (TraceInterval) locationHint;
-        assert registerHint.isSplitParent() : "register hint must be split parent";
-
-        if (interval.spillState() != SpillState.NoOptimization || registerHint.spillState() != SpillState.NoOptimization) {
-            // combining the stack slots for intervals where spill move optimization is applied
-            // is not benefitial and would cause problems
-            return;
-        }
-
-        int beginPos = interval.from();
-        int endPos = interval.to();
-        if (endPos > allocator.maxOpId() || isOdd(beginPos) || isOdd(endPos)) {
-            // safety check that lirOpWithId is allowed
-            return;
-        }
-
-        if (!isMove(allocator.instructionForId(beginPos), registerHint, interval) || !isMove(allocator.instructionForId(endPos), interval, registerHint)) {
-            // cur and registerHint are not connected with two moves
-            return;
-        }
-
-        TraceInterval beginHint = registerHint.getSplitChildAtOpId(beginPos, LIRInstruction.OperandMode.USE, allocator);
-        TraceInterval endHint = registerHint.getSplitChildAtOpId(endPos, LIRInstruction.OperandMode.DEF, allocator);
-        if (beginHint == endHint || beginHint.to() != beginPos || endHint.from() != endPos) {
-            // registerHint must be split : otherwise the re-writing of use positions does not work
-            return;
-        }
-
-        assert beginHint.location() != null : "must have register assigned";
-        assert endHint.location() == null : "must not have register assigned";
-        assert interval.firstUsage(RegisterPriority.MustHaveRegister) == beginPos : "must have use position at begin of interval because of move";
-        assert endHint.firstUsage(RegisterPriority.MustHaveRegister) == endPos : "must have use position at begin of interval because of move";
-
-        if (isRegister(beginHint.location())) {
-            // registerHint is not spilled at beginPos : so it would not be benefitial to
-            // immediately spill cur
-            return;
-        }
-        assert registerHint.spillSlot() != null : "must be set when part of interval was spilled";
-
-        // modify intervals such that cur gets the same stack slot as registerHint
-        // delete use positions to prevent the intervals to get a register at beginning
-        interval.setSpillSlot(registerHint.spillSlot());
-        interval.removeFirstUsePos();
-        endHint.removeFirstUsePos();
-    }
-
-    // allocate a physical register or memory location to an interval
-    @Override
-    @SuppressWarnings("try")
-    protected boolean activateCurrent(TraceInterval interval) {
-        if (Debug.isLogEnabled()) {
-            logCurrentStatus();
-        }
-        boolean result = true;
-
-        try (Indent indent = Debug.logAndIndent("activating interval %s,  splitParent: %d", interval, interval.splitParent().operandNumber)) {
-
-            final Value operand = interval.operand;
-            if (interval.location() != null && isStackSlotValue(interval.location())) {
-                // activating an interval that has a stack slot assigned . split it at first use
-                // position
-                // used for method parameters
-                if (Debug.isLogEnabled()) {
-                    Debug.log("interval has spill slot assigned (method parameter) . split it before first use");
-                }
-                splitStackInterval(interval);
-                result = false;
-
-            } else {
-                if (interval.location() == null) {
-                    // interval has not assigned register . normal allocation
-                    // (this is the normal case for most intervals)
-                    if (Debug.isLogEnabled()) {
-                        Debug.log("normal allocation of register");
-                    }
-
-                    // assign same spill slot to non-intersecting intervals
-                    combineSpilledIntervals(interval);
-
-                    initVarsForAlloc(interval);
-                    if (noAllocationPossible(interval) || !allocFreeRegister(interval)) {
-                        // no empty register available.
-                        // split and spill another interval so that this interval gets a register
-                        allocLockedRegister(interval);
-                    }
-
-                    // spilled intervals need not be move to active-list
-                    if (!isRegister(interval.location())) {
-                        result = false;
-                    }
-                }
-            }
-
-            // load spilled values that become active from stack slot to register
-            if (interval.insertMoveWhenActivated()) {
-                assert interval.isSplitChild();
-                assert interval.currentSplitChild() != null;
-                assert !interval.currentSplitChild().operand.equals(operand) : "cannot insert move between same interval";
-                if (Debug.isLogEnabled()) {
-                    Debug.log("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber);
-                }
-
-                insertMove(interval.from(), interval.currentSplitChild(), interval);
-            }
-            interval.makeCurrentSplitChild();
-
-        }
-
-        return result; // true = interval is moved to active list
-    }
-
-    void finishAllocation() {
-        // must be called when all intervals are allocated
-        moveResolver.resolveAndAppendMoves();
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLocalMoveResolver.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,550 +0,0 @@
-/*
- * Copyright (c) 2009, 2015, 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.alloc.trace;
-
-import static com.oracle.graal.lir.LIRValueUtil.asVirtualStackSlot;
-import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
-import static com.oracle.graal.lir.LIRValueUtil.isVirtualStackSlot;
-import static jdk.vm.ci.code.ValueUtil.asRegister;
-import static jdk.vm.ci.code.ValueUtil.asStackSlot;
-import static jdk.vm.ci.code.ValueUtil.isIllegal;
-import static jdk.vm.ci.code.ValueUtil.isRegister;
-import static jdk.vm.ci.code.ValueUtil.isStackSlot;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-
-import jdk.vm.ci.code.StackSlot;
-import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.meta.AllocatableValue;
-import jdk.vm.ci.meta.Constant;
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.LIRKind;
-import jdk.vm.ci.meta.Value;
-
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.Indent;
-import com.oracle.graal.lir.LIRInsertionBuffer;
-import com.oracle.graal.lir.LIRInstruction;
-import com.oracle.graal.lir.VirtualStackSlot;
-import com.oracle.graal.lir.framemap.FrameMap;
-import com.oracle.graal.lir.framemap.FrameMapBuilderTool;
-
-/**
- */
-public class TraceLocalMoveResolver {
-
-    private static final int STACK_SLOT_IN_CALLER_FRAME_IDX = -1;
-    private final TraceLinearScan allocator;
-
-    private int insertIdx;
-    private LIRInsertionBuffer insertionBuffer; // buffer where moves are inserted
-
-    private final List<TraceInterval> mappingFrom;
-    private final List<Constant> mappingFromOpr;
-    private final List<TraceInterval> mappingTo;
-    private final int[] registerBlocked;
-
-    private int[] stackBlocked;
-    private final int firstVirtualStackIndex;
-
-    private int getStackArrayIndex(Value stackSlotValue) {
-        if (isStackSlot(stackSlotValue)) {
-            return getStackArrayIndex(asStackSlot(stackSlotValue));
-        }
-        if (isVirtualStackSlot(stackSlotValue)) {
-            return getStackArrayIndex(asVirtualStackSlot(stackSlotValue));
-        }
-        throw JVMCIError.shouldNotReachHere("value is not a stack slot: " + stackSlotValue);
-    }
-
-    private int getStackArrayIndex(StackSlot stackSlot) {
-        int stackIdx;
-        if (stackSlot.isInCallerFrame()) {
-            // incoming stack arguments can be ignored
-            stackIdx = STACK_SLOT_IN_CALLER_FRAME_IDX;
-        } else {
-            assert stackSlot.getRawAddFrameSize() : "Unexpected stack slot: " + stackSlot;
-            int offset = -stackSlot.getRawOffset();
-            assert 0 <= offset && offset < firstVirtualStackIndex : String.format("Wrong stack slot offset: %d (first virtual stack slot index: %d", offset, firstVirtualStackIndex);
-            stackIdx = offset;
-        }
-        return stackIdx;
-    }
-
-    private int getStackArrayIndex(VirtualStackSlot virtualStackSlot) {
-        return firstVirtualStackIndex + virtualStackSlot.getId();
-    }
-
-    protected void setValueBlocked(Value location, int direction) {
-        assert direction == 1 || direction == -1 : "out of bounds";
-        if (isStackSlotValue(location)) {
-            int stackIdx = getStackArrayIndex(location);
-            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
-                // incoming stack arguments can be ignored
-                return;
-            }
-            if (stackIdx >= stackBlocked.length) {
-                stackBlocked = Arrays.copyOf(stackBlocked, stackIdx + 1);
-            }
-            stackBlocked[stackIdx] += direction;
-        } else {
-            assert direction == 1 || direction == -1 : "out of bounds";
-            if (isRegister(location)) {
-                registerBlocked[asRegister(location).number] += direction;
-            } else {
-                throw JVMCIError.shouldNotReachHere("unhandled value " + location);
-            }
-        }
-    }
-
-    protected TraceInterval getMappingFrom(int i) {
-        return mappingFrom.get(i);
-    }
-
-    protected int mappingFromSize() {
-        return mappingFrom.size();
-    }
-
-    protected int valueBlocked(Value location) {
-        if (isStackSlotValue(location)) {
-            int stackIdx = getStackArrayIndex(location);
-            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
-                // incoming stack arguments are always blocked (aka they can not be written)
-                return 1;
-            }
-            if (stackIdx >= stackBlocked.length) {
-                return 0;
-            }
-            return stackBlocked[stackIdx];
-        }
-        if (isRegister(location)) {
-            return registerBlocked[asRegister(location).number];
-        }
-        throw JVMCIError.shouldNotReachHere("unhandled value " + location);
-    }
-
-    protected boolean areMultipleReadsAllowed() {
-        return true;
-    }
-
-    boolean hasMappings() {
-        return mappingFrom.size() > 0;
-    }
-
-    protected TraceLinearScan getAllocator() {
-        return allocator;
-    }
-
-    protected TraceLocalMoveResolver(TraceLinearScan allocator) {
-
-        this.allocator = allocator;
-        this.mappingFrom = new ArrayList<>(8);
-        this.mappingFromOpr = new ArrayList<>(8);
-        this.mappingTo = new ArrayList<>(8);
-        this.insertIdx = -1;
-        this.insertionBuffer = new LIRInsertionBuffer();
-        this.registerBlocked = new int[allocator.getRegisters().length];
-        FrameMapBuilderTool frameMapBuilderTool = (FrameMapBuilderTool) allocator.getFrameMapBuilder();
-        FrameMap frameMap = frameMapBuilderTool.getFrameMap();
-        this.stackBlocked = new int[frameMapBuilderTool.getNumberOfStackSlots()];
-        this.firstVirtualStackIndex = !frameMap.frameNeedsAllocating() ? 0 : frameMap.currentFrameSize() + 1;
-    }
-
-    protected boolean checkEmpty() {
-        assert mappingFrom.size() == 0 && mappingFromOpr.size() == 0 && mappingTo.size() == 0 : "list must be empty before and after processing";
-        for (int i = 0; i < stackBlocked.length; i++) {
-            assert stackBlocked[i] == 0 : "stack map must be empty before and after processing";
-        }
-        for (int i = 0; i < getAllocator().getRegisters().length; i++) {
-            assert registerBlocked[i] == 0 : "register map must be empty before and after processing";
-        }
-        checkMultipleReads();
-        return true;
-    }
-
-    protected void checkMultipleReads() {
-        // multiple reads are allowed in SSA LSRA
-    }
-
-    private boolean verifyBeforeResolve() {
-        assert mappingFrom.size() == mappingFromOpr.size() : "length must be equal";
-        assert mappingFrom.size() == mappingTo.size() : "length must be equal";
-        assert insertIdx != -1 : "insert position not set";
-
-        int i;
-        int j;
-        if (!areMultipleReadsAllowed()) {
-            for (i = 0; i < mappingFrom.size(); i++) {
-                for (j = i + 1; j < mappingFrom.size(); j++) {
-                    assert mappingFrom.get(i) == null || mappingFrom.get(i) != mappingFrom.get(j) : "cannot read from same interval twice";
-                }
-            }
-        }
-
-        for (i = 0; i < mappingTo.size(); i++) {
-            for (j = i + 1; j < mappingTo.size(); j++) {
-                assert mappingTo.get(i) != mappingTo.get(j) : "cannot write to same interval twice";
-            }
-        }
-
-        HashSet<Value> usedRegs = new HashSet<>();
-        if (!areMultipleReadsAllowed()) {
-            for (i = 0; i < mappingFrom.size(); i++) {
-                TraceInterval interval = mappingFrom.get(i);
-                if (interval != null && !isIllegal(interval.location())) {
-                    boolean unique = usedRegs.add(interval.location());
-                    assert unique : "cannot read from same register twice";
-                }
-            }
-        }
-
-        usedRegs.clear();
-        for (i = 0; i < mappingTo.size(); i++) {
-            TraceInterval interval = mappingTo.get(i);
-            if (isIllegal(interval.location())) {
-                // After insertion the location may become illegal, so don't check it since multiple
-                // intervals might be illegal.
-                continue;
-            }
-            boolean unique = usedRegs.add(interval.location());
-            assert unique : "cannot write to same register twice";
-        }
-
-        verifyStackSlotMapping();
-
-        return true;
-    }
-
-    protected void verifyStackSlotMapping() {
-        // relax disjoint stack maps invariant
-    }
-
-    // mark assignedReg and assignedRegHi of the interval as blocked
-    private void blockRegisters(TraceInterval interval) {
-        Value location = interval.location();
-        if (mightBeBlocked(location)) {
-            assert areMultipleReadsAllowed() || valueBlocked(location) == 0 : "location already marked as used: " + location;
-            int direction = 1;
-            setValueBlocked(location, direction);
-            Debug.log("block %s", location);
-        }
-    }
-
-    // mark assignedReg and assignedRegHi of the interval as unblocked
-    private void unblockRegisters(TraceInterval interval) {
-        Value location = interval.location();
-        if (mightBeBlocked(location)) {
-            assert valueBlocked(location) > 0 : "location already marked as unused: " + location;
-            setValueBlocked(location, -1);
-            Debug.log("unblock %s", location);
-        }
-    }
-
-    /**
-     * Checks if the {@linkplain TraceInterval#location() location} of {@code to} is not blocked or
-     * is only blocked by {@code from}.
-     */
-    private boolean safeToProcessMove(TraceInterval from, TraceInterval to) {
-        Value fromReg = from != null ? from.location() : null;
-
-        Value location = to.location();
-        if (mightBeBlocked(location)) {
-            if ((valueBlocked(location) > 1 || (valueBlocked(location) == 1 && !isMoveToSelf(fromReg, location)))) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    protected boolean isMoveToSelf(Value from, Value to) {
-        assert to != null;
-        if (to.equals(from)) {
-            return true;
-        }
-        if (from != null && isRegister(from) && isRegister(to) && asRegister(from).equals(asRegister(to))) {
-            assert LIRKind.verifyMoveKinds(to.getLIRKind(), from.getLIRKind()) : String.format("Same register but Kind mismatch %s <- %s", to, from);
-            return true;
-        }
-        return false;
-    }
-
-    protected boolean mightBeBlocked(Value location) {
-        if (isRegister(location)) {
-            return true;
-        }
-        if (isStackSlotValue(location)) {
-            return true;
-        }
-        return false;
-    }
-
-    private void createInsertionBuffer(List<LIRInstruction> list) {
-        assert !insertionBuffer.initialized() : "overwriting existing buffer";
-        insertionBuffer.init(list);
-    }
-
-    private void appendInsertionBuffer() {
-        if (insertionBuffer.initialized()) {
-            insertionBuffer.finish();
-        }
-        assert !insertionBuffer.initialized() : "must be uninitialized now";
-
-        insertIdx = -1;
-    }
-
-    private void insertMove(TraceInterval fromInterval, TraceInterval toInterval) {
-        assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
-        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : "move between different types";
-        assert insertIdx != -1 : "must setup insert position first";
-
-        insertionBuffer.append(insertIdx, createMove(fromInterval.operand, toInterval.operand, fromInterval.location(), toInterval.location()));
-
-        if (Debug.isLogEnabled()) {
-            Debug.log("insert move from %s to %s at %d", fromInterval, toInterval, insertIdx);
-        }
-    }
-
-    /**
-     * @param fromOpr {@link TraceInterval#operand operand} of the {@code from} interval
-     * @param toOpr {@link TraceInterval#operand operand} of the {@code to} interval
-     * @param fromLocation {@link TraceInterval#location() location} of the {@code to} interval
-     * @param toLocation {@link TraceInterval#location() location} of the {@code to} interval
-     */
-    protected LIRInstruction createMove(AllocatableValue fromOpr, AllocatableValue toOpr, AllocatableValue fromLocation, AllocatableValue toLocation) {
-        if (isStackSlotValue(toLocation) && isStackSlotValue(fromLocation)) {
-            return getAllocator().getSpillMoveFactory().createStackMove(toOpr, fromOpr);
-        }
-        return getAllocator().getSpillMoveFactory().createMove(toOpr, fromOpr);
-    }
-
-    private void insertMove(Constant fromOpr, TraceInterval toInterval) {
-        assert insertIdx != -1 : "must setup insert position first";
-
-        AllocatableValue toOpr = toInterval.operand;
-        LIRInstruction move = getAllocator().getSpillMoveFactory().createLoad(toOpr, fromOpr);
-        insertionBuffer.append(insertIdx, move);
-
-        if (Debug.isLogEnabled()) {
-            Debug.log("insert move from value %s to %s at %d", fromOpr, toInterval, insertIdx);
-        }
-    }
-
-    @SuppressWarnings("try")
-    private void resolveMappings() {
-        try (Indent indent = Debug.logAndIndent("resolveMapping")) {
-            assert verifyBeforeResolve();
-            if (Debug.isLogEnabled()) {
-                printMapping();
-            }
-
-            // Block all registers that are used as input operands of a move.
-            // When a register is blocked, no move to this register is emitted.
-            // This is necessary for detecting cycles in moves.
-            int i;
-            for (i = mappingFrom.size() - 1; i >= 0; i--) {
-                TraceInterval fromInterval = mappingFrom.get(i);
-                if (fromInterval != null) {
-                    blockRegisters(fromInterval);
-                }
-            }
-
-            int spillCandidate = -1;
-            while (mappingFrom.size() > 0) {
-                boolean processedInterval = false;
-
-                for (i = mappingFrom.size() - 1; i >= 0; i--) {
-                    TraceInterval fromInterval = mappingFrom.get(i);
-                    TraceInterval toInterval = mappingTo.get(i);
-
-                    if (safeToProcessMove(fromInterval, toInterval)) {
-                        // this interval can be processed because target is free
-                        if (fromInterval != null) {
-                            insertMove(fromInterval, toInterval);
-                            unblockRegisters(fromInterval);
-                        } else {
-                            insertMove(mappingFromOpr.get(i), toInterval);
-                        }
-                        mappingFrom.remove(i);
-                        mappingFromOpr.remove(i);
-                        mappingTo.remove(i);
-
-                        processedInterval = true;
-                    } else if (fromInterval != null && isRegister(fromInterval.location())) {
-                        // this interval cannot be processed now because target is not free
-                        // it starts in a register, so it is a possible candidate for spilling
-                        spillCandidate = i;
-                    }
-                }
-
-                if (!processedInterval) {
-                    breakCycle(spillCandidate);
-                }
-            }
-        }
-
-        // check that all intervals have been processed
-        assert checkEmpty();
-    }
-
-    protected void breakCycle(int spillCandidate) {
-        if (spillCandidate != -1) {
-            // no move could be processed because there is a cycle in the move list
-            // (e.g. r1 . r2, r2 . r1), so one interval must be spilled to memory
-            assert spillCandidate != -1 : "no interval in register for spilling found";
-
-            // create a new spill interval and assign a stack slot to it
-            TraceInterval fromInterval1 = mappingFrom.get(spillCandidate);
-            // do not allocate a new spill slot for temporary interval, but
-            // use spill slot assigned to fromInterval. Otherwise moves from
-            // one stack slot to another can happen (not allowed by LIRAssembler
-            AllocatableValue spillSlot1 = fromInterval1.spillSlot();
-            if (spillSlot1 == null) {
-                spillSlot1 = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval1.kind());
-                fromInterval1.setSpillSlot(spillSlot1);
-            }
-            spillInterval(spillCandidate, fromInterval1, spillSlot1);
-            return;
-        }
-        assert mappingFromSize() > 1;
-        // Arbitrarily select the first entry for spilling.
-        int stackSpillCandidate = 0;
-        TraceInterval fromInterval = getMappingFrom(stackSpillCandidate);
-        assert isStackSlotValue(fromInterval.location());
-        // allocate new stack slot
-        VirtualStackSlot spillSlot = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval.kind());
-        spillInterval(stackSpillCandidate, fromInterval, spillSlot);
-    }
-
-    protected void spillInterval(int spillCandidate, TraceInterval fromInterval, AllocatableValue spillSlot) {
-        assert mappingFrom.get(spillCandidate).equals(fromInterval);
-        TraceInterval spillInterval = getAllocator().createDerivedInterval(fromInterval);
-        spillInterval.setKind(fromInterval.kind());
-
-        // add a dummy range because real position is difficult to calculate
-        // Note: this range is a special case when the integrity of the allocation is
-        // checked
-        spillInterval.addRange(1, 2);
-
-        spillInterval.assignLocation(spillSlot);
-
-        if (Debug.isLogEnabled()) {
-            Debug.log("created new Interval for spilling: %s", spillInterval);
-        }
-        blockRegisters(spillInterval);
-
-        // insert a move from register to stack and update the mapping
-        insertMove(fromInterval, spillInterval);
-        mappingFrom.set(spillCandidate, spillInterval);
-        unblockRegisters(fromInterval);
-    }
-
-    @SuppressWarnings("try")
-    private void printMapping() {
-        try (Indent indent = Debug.logAndIndent("Mapping")) {
-            for (int i = mappingFrom.size() - 1; i >= 0; i--) {
-                TraceInterval fromInterval = mappingFrom.get(i);
-                TraceInterval toInterval = mappingTo.get(i);
-                String from;
-                Value to = toInterval.location();
-                if (fromInterval == null) {
-                    from = mappingFromOpr.get(i).toString();
-                } else {
-                    from = fromInterval.location().toString();
-                }
-                Debug.log("move %s <- %s", from, to);
-            }
-        }
-    }
-
-    void setInsertPosition(List<LIRInstruction> insertList, int insertIdx) {
-        assert this.insertIdx == -1 : "use moveInsertPosition instead of setInsertPosition when data already set";
-
-        createInsertionBuffer(insertList);
-        this.insertIdx = insertIdx;
-    }
-
-    void moveInsertPosition(List<LIRInstruction> newInsertList, int newInsertIdx) {
-        if (insertionBuffer.lirList() != null && (insertionBuffer.lirList() != newInsertList || this.insertIdx != newInsertIdx)) {
-            // insert position changed . resolve current mappings
-            resolveMappings();
-        }
-
-        assert insertionBuffer.lirList() != newInsertList || newInsertIdx >= insertIdx : String.format("Decreasing insert index: old=%d new=%d", insertIdx, newInsertIdx);
-
-        if (insertionBuffer.lirList() != newInsertList) {
-            // block changed . append insertionBuffer because it is
-            // bound to a specific block and create a new insertionBuffer
-            appendInsertionBuffer();
-            createInsertionBuffer(newInsertList);
-        }
-
-        this.insertIdx = newInsertIdx;
-    }
-
-    public void addMapping(TraceInterval fromInterval, TraceInterval toInterval) {
-
-        if (isIllegal(toInterval.location()) && toInterval.canMaterialize()) {
-            if (Debug.isLogEnabled()) {
-                Debug.log("no store to rematerializable interval %s needed", toInterval);
-            }
-            return;
-        }
-        if (isIllegal(fromInterval.location()) && fromInterval.canMaterialize()) {
-            // Instead of a reload, re-materialize the value
-            JavaConstant rematValue = fromInterval.getMaterializedValue();
-            addMapping(rematValue, toInterval);
-            return;
-        }
-        if (Debug.isLogEnabled()) {
-            Debug.log("add move mapping from %s to %s", fromInterval, toInterval);
-        }
-
-        assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
-        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", fromInterval.kind(), toInterval.kind(), fromInterval,
-                        toInterval);
-        mappingFrom.add(fromInterval);
-        mappingFromOpr.add(null);
-        mappingTo.add(toInterval);
-    }
-
-    public void addMapping(Constant fromOpr, TraceInterval toInterval) {
-        if (Debug.isLogEnabled()) {
-            Debug.log("add move mapping from %s to %s", fromOpr, toInterval);
-        }
-
-        mappingFrom.add(null);
-        mappingFromOpr.add(fromOpr);
-        mappingTo.add(toInterval);
-    }
-
-    void resolveAndAppendMoves() {
-        if (hasMappings()) {
-            resolveMappings();
-        }
-        appendInsertionBuffer();
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceRegisterAllocationPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceRegisterAllocationPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.lir.alloc.trace;
 
-import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
-
 import java.util.List;
 
 import jdk.vm.ci.code.TargetDescription;
@@ -44,8 +42,8 @@
 import com.oracle.graal.lir.LIRInstruction;
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.StandardOp.LabelOp;
-import com.oracle.graal.lir.StandardOp.ValueMoveOp;
 import com.oracle.graal.lir.alloc.trace.TraceAllocationPhase.TraceAllocationContext;
+import com.oracle.graal.lir.alloc.trace.lsra.TraceLinearScan;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 import com.oracle.graal.lir.phases.AllocationPhase;
@@ -68,14 +66,18 @@
         // @formatter:on
     }
 
-    static final int TRACE_DUMP_LEVEL = 3;
+    private static final TraceGlobalMoveResolutionPhase TRACE_GLOBAL_MOVE_RESOLUTION_PHASE = new TraceGlobalMoveResolutionPhase();
+    private static final TraceTrivialAllocator TRACE_TRIVIAL_ALLOCATOR = new TraceTrivialAllocator();
+
+    public static final int TRACE_DUMP_LEVEL = 3;
     private static final DebugMetric trivialTracesMetric = Debug.metric("TraceRA[trivialTraces]");
     private static final DebugMetric tracesMetric = Debug.metric("TraceRA[traces]");
 
     @Override
     @SuppressWarnings("try")
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext context) {
+        MoveFactory spillMoveFactory = context.spillMoveFactory;
+        RegisterAllocationConfig registerAllocationConfig = context.registerAllocationConfig;
         LIR lir = lirGenRes.getLIR();
         assert SSIVerifier.verify(lir) : "LIR not in SSI form.";
         B startBlock = linearScanOrder.get(0);
@@ -83,6 +85,8 @@
         TraceBuilderResult<B> resultTraces = TraceBuilder.computeTraces(startBlock, linearScanOrder);
         TraceStatisticsPrinter.printTraceStatistics(resultTraces, lirGenRes.getCompilationUnitName());
 
+        TraceAllocationContext traceContext = new TraceAllocationContext(spillMoveFactory, registerAllocationConfig, resultTraces);
+
         Debug.dump(lir, "Before TraceRegisterAllocation");
         int traceNumber = 0;
         for (List<B> trace : resultTraces.getTraces()) {
@@ -93,7 +97,7 @@
                 }
                 Debug.dump(TRACE_DUMP_LEVEL, trace, "Trace" + traceNumber + ": " + trace);
                 if (Options.TraceRAtrivialBlockAllocator.getValue() && isTrivialTrace(lir, trace)) {
-                    new TraceTrivialAllocator(resultTraces).apply(target, lirGenRes, codeEmittingOrder, trace, new TraceAllocationContext(spillMoveFactory, registerAllocationConfig), false);
+                    TRACE_TRIVIAL_ALLOCATOR.apply(target, lirGenRes, codeEmittingOrder, trace, traceContext, false);
                 } else {
                     TraceLinearScan allocator = new TraceLinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig, trace, resultTraces, false);
                     allocator.allocate(target, lirGenRes, codeEmittingOrder, linearScanOrder, spillMoveFactory, registerAllocationConfig);
@@ -107,26 +111,26 @@
         }
         Debug.dump(lir, "After trace allocation");
 
-        new TraceGlobalMoveResolutionPhase(resultTraces).apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, new TraceAllocationContext(spillMoveFactory, registerAllocationConfig));
+        TRACE_GLOBAL_MOVE_RESOLUTION_PHASE.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, traceContext);
+        deconstructSSIForm(lir);
+    }
 
-        try (Scope s = Debug.scope("TraceRegisterAllocationFixup")) {
-            if (replaceStackToStackMoves(lir, spillMoveFactory)) {
-                Debug.dump(lir, "After fixing stack to stack moves");
-            }
-            /*
-             * Incoming Values are needed for the RegisterVerifier, otherwise SIGMAs/PHIs where the
-             * Out and In value matches (ie. there is no resolution move) are falsely detected as
-             * errors.
-             */
-            for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
-                try (Indent i = Debug.logAndIndent("Fixup Block %s", block)) {
-                    if (block.getPredecessorCount() != 0) {
-                        SSIUtil.removeIncoming(lir, block);
-                    } else {
-                        assert lir.getControlFlowGraph().getStartBlock().equals(block);
-                    }
-                    SSIUtil.removeOutgoing(lir, block);
+    /**
+     * Remove Phi/Sigma In/Out.
+     *
+     * Note: Incoming Values are needed for the RegisterVerifier, otherwise SIGMAs/PHIs where the
+     * Out and In value matches (ie. there is no resolution move) are falsely detected as errors.
+     */
+    @SuppressWarnings("try")
+    private static void deconstructSSIForm(LIR lir) {
+        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+            try (Indent i = Debug.logAndIndent("Fixup Block %s", block)) {
+                if (block.getPredecessorCount() != 0) {
+                    SSIUtil.removeIncoming(lir, block);
+                } else {
+                    assert lir.getControlFlowGraph().getStartBlock().equals(block);
                 }
+                SSIUtil.removeOutgoing(lir, block);
             }
         }
     }
@@ -147,30 +151,6 @@
         return instructions.get(1) instanceof JumpOp;
     }
 
-    /**
-     * Fixup stack to stack moves introduced by stack arguments.
-     *
-     * TODO (je) find a better solution.
-     */
-    private static boolean replaceStackToStackMoves(LIR lir, MoveFactory spillMoveFactory) {
-        boolean changed = false;
-        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
-            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-            for (int i = 0; i < instructions.size(); i++) {
-                LIRInstruction inst = instructions.get(i);
-
-                if (inst instanceof ValueMoveOp) {
-                    ValueMoveOp move = (ValueMoveOp) inst;
-                    if (isStackSlotValue(move.getInput()) && isStackSlotValue(move.getResult())) {
-                        instructions.set(i, spillMoveFactory.createStackMove(move.getResult(), move.getInput()));
-                        changed = true;
-                    }
-                }
-            }
-        }
-        return changed;
-    }
-
     private static void unnumberInstructions(List<? extends AbstractBlockBase<?>> trace, LIR lir) {
         trace.stream().flatMap(b -> lir.getLIRforBlock(b).stream()).forEach(op -> op.setId(-1));
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceTrivialAllocator.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceTrivialAllocator.java	Tue Dec 08 12:30:15 2015 -0800
@@ -31,7 +31,6 @@
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.Value;
 
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.lir.LIR;
@@ -42,7 +41,6 @@
 import com.oracle.graal.lir.ValueProcedure;
 import com.oracle.graal.lir.Variable;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 import com.oracle.graal.lir.ssi.SSIUtil;
 import com.oracle.graal.lir.util.VariableVirtualStackValueMap;
 
@@ -52,16 +50,10 @@
  */
 final class TraceTrivialAllocator extends TraceAllocationPhase {
 
-    private final TraceBuilderResult<?> resultTraces;
-
-    public TraceTrivialAllocator(TraceBuilderResult<?> resultTraces) {
-        this.resultTraces = resultTraces;
-    }
-
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> trace, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> trace, TraceAllocationContext context) {
         LIR lir = lirGenRes.getLIR();
+        TraceBuilderResult<?> resultTraces = context.resultTraces;
         assert isTrivialTrace(lir, trace) : "Not a trivial trace! " + trace;
         B block = trace.iterator().next();
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceUtil.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceUtil.java	Tue Dec 08 12:30:15 2015 -0800
@@ -27,9 +27,9 @@
 import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 
-class TraceUtil {
+public class TraceUtil {
 
-    static AbstractBlockBase<?> getBestTraceInterPredecessor(TraceBuilderResult<?> traceResult, AbstractBlockBase<?> block) {
+    public static AbstractBlockBase<?> getBestTraceInterPredecessor(TraceBuilderResult<?> traceResult, AbstractBlockBase<?> block) {
         AbstractBlockBase<?> bestPred = null;
         int bestTraceId = traceResult.getTraceForBlock(block);
         for (AbstractBlockBase<?> pred : block.getPredecessors()) {
@@ -42,12 +42,12 @@
         return bestPred;
     }
 
-    static boolean isShadowedRegisterValue(Value value) {
+    public static boolean isShadowedRegisterValue(Value value) {
         assert value != null;
         return value instanceof ShadowedRegisterValue;
     }
 
-    static ShadowedRegisterValue asShadowedRegisterValue(Value value) {
+    public static ShadowedRegisterValue asShadowedRegisterValue(Value value) {
         assert isShadowedRegisterValue(value);
         return (ShadowedRegisterValue) value;
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/UsePosList.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, 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.alloc.trace;
-
-import com.oracle.graal.compiler.common.util.IntList;
-import com.oracle.graal.lir.alloc.trace.TraceInterval.RegisterPriority;
-
-/**
- * List of use positions. Each entry in the list records the use position and register priority
- * associated with the use position. The entries in the list are in descending order of use
- * position.
- *
- */
-public final class UsePosList {
-
-    private IntList list;
-
-    /**
-     * Creates a use list.
-     *
-     * @param initialCapacity the initial capacity of the list in terms of entries
-     */
-    public UsePosList(int initialCapacity) {
-        list = new IntList(initialCapacity * 2);
-    }
-
-    private UsePosList(IntList list) {
-        this.list = list;
-    }
-
-    /**
-     * Splits this list around a given position. All entries in this list with a use position
-     * greater or equal than {@code splitPos} are removed from this list and added to the returned
-     * list.
-     *
-     * @param splitPos the position for the split
-     * @return a use position list containing all entries removed from this list that have a use
-     *         position greater or equal than {@code splitPos}
-     */
-    public UsePosList splitAt(int splitPos) {
-        int i = size() - 1;
-        int len = 0;
-        while (i >= 0 && usePos(i) < splitPos) {
-            --i;
-            len += 2;
-        }
-        int listSplitIndex = (i + 1) * 2;
-        IntList childList = list;
-        list = IntList.copy(this.list, listSplitIndex, len);
-        childList.setSize(listSplitIndex);
-        UsePosList child = new UsePosList(childList);
-        return child;
-    }
-
-    /**
-     * Gets the use position at a specified index in this list.
-     *
-     * @param index the index of the entry for which the use position is returned
-     * @return the use position of entry {@code index} in this list
-     */
-    public int usePos(int index) {
-        return list.get(index << 1);
-    }
-
-    /**
-     * Gets the register priority for the use position at a specified index in this list.
-     *
-     * @param index the index of the entry for which the register priority is returned
-     * @return the register priority of entry {@code index} in this list
-     */
-    public RegisterPriority registerPriority(int index) {
-        return RegisterPriority.VALUES[list.get((index << 1) + 1)];
-    }
-
-    public void add(int usePos, RegisterPriority registerPriority) {
-        assert list.size() == 0 || usePos(size() - 1) > usePos;
-        list.add(usePos);
-        list.add(registerPriority.ordinal());
-    }
-
-    public int size() {
-        return list.size() >> 1;
-    }
-
-    public void removeLowestUsePos() {
-        list.setSize(list.size() - 2);
-    }
-
-    public void setRegisterPriority(int index, RegisterPriority registerPriority) {
-        list.set((index << 1) + 1, registerPriority.ordinal());
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder buf = new StringBuilder("[");
-        for (int i = size() - 1; i >= 0; --i) {
-            if (buf.length() != 1) {
-                buf.append(", ");
-            }
-            RegisterPriority prio = registerPriority(i);
-            buf.append(usePos(i)).append(" -> ").append(prio.ordinal()).append(':').append(prio);
-        }
-        return buf.append("]").toString();
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/FixedInterval.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2015, 2015, 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.alloc.trace.lsra;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+import com.oracle.graal.lir.LIRInstruction;
+
+/**
+ * Represents a fixed interval.
+ */
+final class FixedInterval extends IntervalHint {
+
+    static final class FixedList {
+
+        public FixedInterval fixed;
+
+        public FixedList(FixedInterval fixed) {
+            this.fixed = fixed;
+        }
+
+        /**
+         * Gets the fixed list.
+         */
+        public FixedInterval getFixed() {
+            return fixed;
+        }
+
+        /**
+         * Sets the fixed list.
+         */
+        public void setFixed(FixedInterval list) {
+            fixed = list;
+        }
+
+        /**
+         * Adds an interval to a list sorted by {@linkplain FixedInterval#currentFrom() current
+         * from} positions.
+         *
+         * @param interval the interval to add
+         */
+        public void addToListSortedByCurrentFromPositions(FixedInterval interval) {
+            FixedInterval list = getFixed();
+            FixedInterval prev = null;
+            FixedInterval cur = list;
+            while (cur.currentFrom() < interval.currentFrom()) {
+                prev = cur;
+                cur = cur.next;
+            }
+            FixedInterval result = list;
+            if (prev == null) {
+                // add to head of list
+                result = interval;
+            } else {
+                // add before 'cur'
+                prev.next = interval;
+            }
+            interval.next = cur;
+            setFixed(result);
+        }
+
+    }
+
+    /**
+     * The fixed operand of this interval.
+     */
+    public final AllocatableValue operand;
+
+    /**
+     * The head of the list of ranges describing this interval. This list is sorted by
+     * {@linkplain LIRInstruction#id instruction ids}.
+     */
+    private FixedRange first;
+
+    /**
+     * Iterator used to traverse the ranges of an interval.
+     */
+    private FixedRange current;
+
+    /**
+     * Link to next interval in a sorted list of intervals that ends with {@link #EndMarker}.
+     */
+    FixedInterval next;
+
+    private int cachedTo; // cached value: to of last range (-1: not cached)
+
+    public FixedRange first() {
+        return first;
+    }
+
+    @Override
+    public int from() {
+        return first.from;
+    }
+
+    public int to() {
+        if (cachedTo == -1) {
+            cachedTo = calcTo();
+        }
+        assert cachedTo == calcTo() : "invalid cached value";
+        return cachedTo;
+    }
+
+    // test intersection
+    boolean intersects(TraceInterval i) {
+        return first.intersects(i);
+    }
+
+    int intersectsAt(TraceInterval i) {
+        return first.intersectsAt(i);
+    }
+
+    // range iteration
+    void rewindRange() {
+        current = first;
+    }
+
+    void nextRange() {
+        assert this != EndMarker : "not allowed on sentinel";
+        current = current.next;
+    }
+
+    int currentFrom() {
+        return current.from;
+    }
+
+    int currentTo() {
+        return current.to;
+    }
+
+    boolean currentAtEnd() {
+        return current == FixedRange.EndMarker;
+    }
+
+    boolean currentIntersects(TraceInterval it) {
+        return current.intersects(it);
+    }
+
+    int currentIntersectsAt(TraceInterval it) {
+        return current.intersectsAt(it);
+    }
+
+    // range creation
+    public void setFrom(int from) {
+        assert !isEmpty();
+        first().from = from;
+    }
+
+    private boolean isEmpty() {
+        return first() == FixedRange.EndMarker;
+    }
+
+    public void addRange(int from, int to) {
+        if (isEmpty()) {
+            first = new FixedRange(from, to, first());
+            return;
+        }
+        if (to <= to() && from >= from()) {
+            return;
+        }
+        if (from() == to) {
+            first().from = from;
+        } else {
+            first = new FixedRange(from, to, first());
+        }
+    }
+
+    @Override
+    public AllocatableValue location() {
+        return operand;
+    }
+
+    /**
+     * Sentinel interval to denote the end of an interval list.
+     */
+    static final FixedInterval EndMarker = new FixedInterval(Value.ILLEGAL);
+
+    FixedInterval(AllocatableValue operand) {
+        assert operand != null;
+        this.operand = operand;
+        this.first = FixedRange.EndMarker;
+        this.current = FixedRange.EndMarker;
+        this.next = FixedInterval.EndMarker;
+        this.cachedTo = -1;
+    }
+
+    int calcTo() {
+        assert first != FixedRange.EndMarker : "interval has no range";
+
+        FixedRange r = first;
+        while (r.next != FixedRange.EndMarker) {
+            r = r.next;
+        }
+        return r.to;
+    }
+
+    // returns true if the opId is inside the interval
+    boolean covers(int opId, LIRInstruction.OperandMode mode) {
+        FixedRange cur = first;
+
+        while (cur != FixedRange.EndMarker && cur.to < opId) {
+            cur = cur.next;
+        }
+        if (cur != FixedRange.EndMarker) {
+            assert cur.to != cur.next.from : "ranges not separated";
+
+            if (mode == LIRInstruction.OperandMode.DEF) {
+                return cur.from <= opId && opId < cur.to;
+            } else {
+                return cur.from <= opId && opId <= cur.to;
+            }
+        }
+        return false;
+    }
+
+    // returns true if the interval has any hole between holeFrom and holeTo
+    // (even if the hole has only the length 1)
+    boolean hasHoleBetween(int holeFrom, int holeTo) {
+        assert holeFrom < holeTo : "check";
+        assert from() <= holeFrom && holeTo <= to() : "index out of interval";
+
+        FixedRange cur = first;
+        while (cur != FixedRange.EndMarker) {
+            assert cur.to < cur.next.from : "no space between ranges";
+
+            // hole-range starts before this range . hole
+            if (holeFrom < cur.from) {
+                return true;
+
+                // hole-range completely inside this range . no hole
+            } else {
+                if (holeTo <= cur.to) {
+                    return false;
+
+                    // overlapping of hole-range with this range . hole
+                } else {
+                    if (holeFrom <= cur.to) {
+                        return true;
+                    }
+                }
+            }
+
+            cur = cur.next;
+        }
+
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        String from = "?";
+        String to = "?";
+        if (first != null && first != FixedRange.EndMarker) {
+            from = String.valueOf(from());
+            // to() may cache a computed value, modifying the current object, which is a bad idea
+            // for a printing function. Compute it directly instead.
+            to = String.valueOf(calcTo());
+        }
+        String locationString = "@" + this.operand;
+        return asRegister(operand).number + ":" + operand + (isRegister(operand) ? "" : locationString) + "[" + from + "," + to + "]";
+    }
+
+    /**
+     * Gets a single line string for logging the details of this interval to a log stream.
+     */
+    @Override
+    public String logString(TraceLinearScan allocator) {
+        StringBuilder buf = new StringBuilder(100);
+        buf.append("fix ").append(asRegister(operand).number).append(':').append(operand).append(' ');
+
+        buf.append(" ranges{");
+
+        // print ranges
+        FixedRange cur = first;
+        while (cur != FixedRange.EndMarker) {
+            if (cur != first) {
+                buf.append(", ");
+            }
+            buf.append(cur);
+            cur = cur.next;
+            assert cur != null : "range list not closed with range sentinel";
+        }
+        buf.append("}");
+        return buf.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/FixedRange.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015, 2015, 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.alloc.trace.lsra;
+
+/**
+ * Represents a range of integers from a start (inclusive) to an end (exclusive).
+ */
+final class FixedRange {
+
+    public static final FixedRange EndMarker = new FixedRange(Integer.MAX_VALUE, Integer.MAX_VALUE, null);
+
+    /**
+     * The start of the range, inclusive.
+     */
+    public int from;
+
+    /**
+     * The end of the range, exclusive.
+     */
+    public int to;
+
+    /**
+     * A link to allow the range to be put into a singly linked list.
+     */
+    public FixedRange next;
+
+    boolean intersects(TraceInterval i) {
+        return intersectsAt(i) != -1;
+    }
+
+    /**
+     * Creates a new range.
+     *
+     * @param from the start of the range, inclusive
+     * @param to the end of the range, exclusive
+     * @param next link to the next range in a linked list
+     */
+    FixedRange(int from, int to, FixedRange next) {
+        this.from = from;
+        this.to = to;
+        this.next = next;
+    }
+
+    int intersectsAt(TraceInterval other) {
+        FixedRange range = this;
+        assert other != null : "null ranges not allowed";
+        assert range != EndMarker && other != TraceInterval.EndMarker : "empty ranges not allowed";
+        int intervalFrom = other.from();
+        int intervalTo = other.to();
+
+        do {
+            if (range.from < intervalFrom) {
+                if (range.to <= intervalFrom) {
+                    range = range.next;
+                    if (range == EndMarker) {
+                        return -1;
+                    }
+                } else {
+                    return intervalFrom;
+                }
+            } else {
+                if (intervalFrom < range.from) {
+                    if (intervalTo <= range.from) {
+                        return -1;
+                    }
+                    return range.from;
+                } else {
+                    assert range.from == intervalFrom;
+                    if (range.from == range.to) {
+                        range = range.next;
+                        if (range == EndMarker) {
+                            return -1;
+                        }
+                    } else {
+                        if (intervalFrom == intervalTo) {
+                            return -1;
+                        }
+                        return range.from;
+                    }
+                }
+            }
+        } while (true);
+    }
+
+    @Override
+    public String toString() {
+        return "[" + from + ", " + to + "]";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/IntervalHint.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015, 2015, 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.alloc.trace.lsra;
+
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * An interval that is a hint for an {@code TraceInterval interval}.
+ */
+abstract class IntervalHint {
+
+    public abstract AllocatableValue location();
+
+    public abstract int from();
+
+    public abstract String logString(TraceLinearScan allocator);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/RegisterVerifier.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2009, 2012, 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.alloc.trace.lsra;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.Value;
+
+import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
+import com.oracle.graal.compiler.common.util.ArrayMap;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.debug.Indent;
+import com.oracle.graal.lir.InstructionValueConsumer;
+import com.oracle.graal.lir.LIRInstruction;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+
+/**
+ */
+final class RegisterVerifier {
+
+    TraceLinearScan allocator;
+    List<AbstractBlockBase<?>> workList; // all blocks that must be processed
+    ArrayMap<TraceInterval[]> savedStates; // saved information of previous check
+
+    // simplified access to methods of LinearScan
+    TraceInterval intervalAt(Value operand) {
+        return allocator.intervalFor(operand);
+    }
+
+    // currently, only registers are processed
+    int stateSize() {
+        return allocator.numRegisters();
+    }
+
+    // accessors
+    TraceInterval[] stateForBlock(AbstractBlockBase<?> block) {
+        return savedStates.get(block.getId());
+    }
+
+    void setStateForBlock(AbstractBlockBase<?> block, TraceInterval[] savedState) {
+        savedStates.put(block.getId(), savedState);
+    }
+
+    void addToWorkList(AbstractBlockBase<?> block) {
+        if (!workList.contains(block)) {
+            workList.add(block);
+        }
+    }
+
+    RegisterVerifier(TraceLinearScan allocator) {
+        this.allocator = allocator;
+        workList = new ArrayList<>(16);
+        this.savedStates = new ArrayMap<>();
+
+    }
+
+    @SuppressWarnings("try")
+    void verify(AbstractBlockBase<?> start) {
+        try (Scope s = Debug.scope("RegisterVerifier")) {
+            // setup input registers (method arguments) for first block
+            TraceInterval[] inputState = new TraceInterval[stateSize()];
+            setStateForBlock(start, inputState);
+            addToWorkList(start);
+
+            // main loop for verification
+            do {
+                AbstractBlockBase<?> block = workList.get(0);
+                workList.remove(0);
+
+                processBlock(block);
+            } while (!workList.isEmpty());
+        }
+    }
+
+    @SuppressWarnings("try")
+    private void processBlock(AbstractBlockBase<?> block) {
+        try (Indent indent = Debug.logAndIndent("processBlock B%d", block.getId())) {
+            // must copy state because it is modified
+            TraceInterval[] inputState = copy(stateForBlock(block));
+
+            try (Indent indent2 = Debug.logAndIndent("Input-State of intervals:")) {
+                printState(inputState);
+            }
+
+            // process all operations of the block
+            processOperations(block, inputState);
+
+            try (Indent indent2 = Debug.logAndIndent("Output-State of intervals:")) {
+                printState(inputState);
+            }
+
+            // iterate all successors
+            for (AbstractBlockBase<?> succ : block.getSuccessors()) {
+                processSuccessor(succ, inputState);
+            }
+        }
+    }
+
+    protected void printState(TraceInterval[] inputState) {
+        for (int i = 0; i < stateSize(); i++) {
+            Register reg = allocator.getRegisters()[i];
+            assert reg.number == i;
+            if (inputState[i] != null) {
+                Debug.log(" %6s %4d  --  %s", reg, inputState[i].operandNumber, inputState[i]);
+            } else {
+                Debug.log(" %6s   __", reg);
+            }
+        }
+    }
+
+    private void processSuccessor(AbstractBlockBase<?> block, TraceInterval[] inputState) {
+        TraceInterval[] savedState = stateForBlock(block);
+
+        if (savedState != null) {
+            // this block was already processed before.
+            // check if new inputState is consistent with savedState
+
+            boolean savedStateCorrect = true;
+            for (int i = 0; i < stateSize(); i++) {
+                if (inputState[i] != savedState[i]) {
+                    // current inputState and previous savedState assume a different
+                    // interval in this register . assume that this register is invalid
+                    if (savedState[i] != null) {
+                        // invalidate old calculation only if it assumed that
+                        // register was valid. when the register was already invalid,
+                        // then the old calculation was correct.
+                        savedStateCorrect = false;
+                        savedState[i] = null;
+
+                        Debug.log("processSuccessor B%d: invalidating slot %d", block.getId(), i);
+                    }
+                }
+            }
+
+            if (savedStateCorrect) {
+                // already processed block with correct inputState
+                Debug.log("processSuccessor B%d: previous visit already correct", block.getId());
+            } else {
+                // must re-visit this block
+                Debug.log("processSuccessor B%d: must re-visit because input state changed", block.getId());
+                addToWorkList(block);
+            }
+
+        } else {
+            // block was not processed before, so set initial inputState
+            Debug.log("processSuccessor B%d: initial visit", block.getId());
+
+            setStateForBlock(block, copy(inputState));
+            addToWorkList(block);
+        }
+    }
+
+    static TraceInterval[] copy(TraceInterval[] inputState) {
+        return inputState.clone();
+    }
+
+    static void statePut(TraceInterval[] inputState, Value location, TraceInterval interval) {
+        if (location != null && isRegister(location)) {
+            Register reg = asRegister(location);
+            int regNum = reg.number;
+            if (interval != null) {
+                Debug.log("%s = %s", reg, interval.operand);
+            } else if (inputState[regNum] != null) {
+                Debug.log("%s = null", reg);
+            }
+
+            inputState[regNum] = interval;
+        }
+    }
+
+    static boolean checkState(AbstractBlockBase<?> block, LIRInstruction op, TraceInterval[] inputState, Value operand, Value reg, TraceInterval interval) {
+        if (reg != null && isRegister(reg)) {
+            if (inputState[asRegister(reg).number] != interval) {
+                throw new JVMCIError(
+                                "Error in register allocation: operation (%s) in block %s expected register %s (operand %s) to contain the value of interval %s but data-flow says it contains interval %s",
+                                op, block, reg, operand, interval, inputState[asRegister(reg).number]);
+            }
+        }
+        return true;
+    }
+
+    void processOperations(AbstractBlockBase<?> block, final TraceInterval[] inputState) {
+        List<LIRInstruction> ops = allocator.getLIR().getLIRforBlock(block);
+        InstructionValueConsumer useConsumer = new InstructionValueConsumer() {
+
+            @Override
+            public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                // we skip spill moves inserted by the spill position optimization
+                if (TraceLinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand) && op.id() != TraceLinearScan.DOMINATOR_SPILL_MOVE_ID) {
+                    TraceInterval interval = intervalAt(operand);
+                    if (op.id() != -1) {
+                        interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
+                    }
+
+                    assert checkState(block, op, inputState, interval.operand, interval.location(), interval.splitParent());
+                }
+            }
+        };
+
+        InstructionValueConsumer defConsumer = (op, operand, mode, flags) -> {
+            if (TraceLinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
+                TraceInterval interval = intervalAt(operand);
+                if (op.id() != -1) {
+                    interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
+                }
+
+                statePut(inputState, interval.location(), interval.splitParent());
+            }
+        };
+
+        // visit all instructions of the block
+        for (int i = 0; i < ops.size(); i++) {
+            final LIRInstruction op = ops.get(i);
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("%s", op.toStringWithIdPrefix());
+            }
+
+            // check if input operands are correct
+            op.visitEachInput(useConsumer);
+            // invalidate all caller save registers at calls
+            if (op.destroysCallerSavedRegisters()) {
+                for (Register r : allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters()) {
+                    statePut(inputState, r.asValue(), null);
+                }
+            }
+            op.visitEachAlive(useConsumer);
+            // set temp operands (some operations use temp operands also as output operands, so
+            // can't set them null)
+            op.visitEachTemp(defConsumer);
+            // set output operands
+            op.visitEachOutput(defConsumer);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/TraceInterval.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,1091 @@
+/*
+ * Copyright (c) 2009, 2015, 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.alloc.trace.lsra;
+
+import static com.oracle.graal.compiler.common.GraalOptions.DetailedAsserts;
+import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
+import static com.oracle.graal.lir.LIRValueUtil.isVariable;
+import static com.oracle.graal.lir.LIRValueUtil.isVirtualStackSlot;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.LIRKind;
+import jdk.vm.ci.meta.Value;
+
+import com.oracle.graal.compiler.common.util.Util;
+import com.oracle.graal.debug.TTY;
+import com.oracle.graal.lir.LIRInstruction;
+import com.oracle.graal.lir.Variable;
+
+/**
+ * Represents an interval in the {@linkplain TraceLinearScan linear scan register allocator}.
+ */
+final class TraceInterval extends IntervalHint {
+
+    static final class AnyList {
+
+        /**
+         * List of intervals whose binding is currently {@link RegisterBinding#Any}.
+         */
+        public TraceInterval any;
+
+        public AnyList(TraceInterval any) {
+            this.any = any;
+        }
+
+        /**
+         * Gets the any list.
+         */
+        public TraceInterval getAny() {
+            return any;
+        }
+
+        /**
+         * Sets the any list.
+         */
+        public void setAny(TraceInterval list) {
+            any = list;
+        }
+
+        /**
+         * Adds an interval to a list sorted by {@linkplain TraceInterval#from() current from}
+         * positions.
+         *
+         * @param interval the interval to add
+         */
+        public void addToListSortedByFromPositions(TraceInterval interval) {
+            TraceInterval list = getAny();
+            TraceInterval prev = null;
+            TraceInterval cur = list;
+            while (cur.from() < interval.from()) {
+                prev = cur;
+                cur = cur.next;
+            }
+            TraceInterval result = list;
+            if (prev == null) {
+                // add to head of list
+                result = interval;
+            } else {
+                // add before 'cur'
+                prev.next = interval;
+            }
+            interval.next = cur;
+            setAny(result);
+        }
+
+        /**
+         * Adds an interval to a list sorted by {@linkplain TraceInterval#from() start} positions
+         * and {@linkplain TraceInterval#firstUsage(RegisterPriority) first usage} positions.
+         *
+         * @param interval the interval to add
+         */
+        public void addToListSortedByStartAndUsePositions(TraceInterval interval) {
+            TraceInterval list = getAny();
+            TraceInterval prev = null;
+            TraceInterval cur = list;
+            while (cur.from() < interval.from() || (cur.from() == interval.from() && cur.firstUsage(RegisterPriority.None) < interval.firstUsage(RegisterPriority.None))) {
+                prev = cur;
+                cur = cur.next;
+            }
+            if (prev == null) {
+                list = interval;
+            } else {
+                prev.next = interval;
+            }
+            interval.next = cur;
+            setAny(list);
+        }
+
+        /**
+         * Removes an interval from a list.
+         *
+         * @param i the interval to remove
+         */
+        public void removeAny(TraceInterval i) {
+            TraceInterval list = getAny();
+            TraceInterval prev = null;
+            TraceInterval cur = list;
+            while (cur != i) {
+                assert cur != null && cur != TraceInterval.EndMarker : "interval has not been found in list: " + i;
+                prev = cur;
+                cur = cur.next;
+            }
+            if (prev == null) {
+                setAny(cur.next);
+            } else {
+                prev.next = cur.next;
+            }
+        }
+    }
+
+    /**
+     * Constants denoting the register usage priority for an interval. The constants are declared in
+     * increasing order of priority are are used to optimize spilling when multiple overlapping
+     * intervals compete for limited registers.
+     */
+    public enum RegisterPriority {
+        /**
+         * No special reason for an interval to be allocated a register.
+         */
+        None,
+
+        /**
+         * Priority level for intervals live at the end of a loop.
+         */
+        LiveAtLoopEnd,
+
+        /**
+         * Priority level for intervals that should be allocated to a register.
+         */
+        ShouldHaveRegister,
+
+        /**
+         * Priority level for intervals that must be allocated to a register.
+         */
+        MustHaveRegister;
+
+        public static final RegisterPriority[] VALUES = values();
+
+        /**
+         * Determines if this priority is higher than or equal to a given priority.
+         */
+        public boolean greaterEqual(RegisterPriority other) {
+            return ordinal() >= other.ordinal();
+        }
+
+        /**
+         * Determines if this priority is lower than a given priority.
+         */
+        public boolean lessThan(RegisterPriority other) {
+            return ordinal() < other.ordinal();
+        }
+
+        public CharSequence shortName() {
+            return name().subSequence(0, 1);
+        }
+    }
+
+    /**
+     * Constants denoting whether an interval is bound to a specific register. This models platform
+     * dependencies on register usage for certain instructions.
+     */
+    enum RegisterBinding {
+        /**
+         * Interval is bound to a specific register as required by the platform.
+         */
+        Fixed,
+
+        /**
+         * Interval has no specific register requirements.
+         */
+        Any,
+
+        /**
+         * Interval is bound to a stack slot.
+         */
+        Stack;
+
+        public static final RegisterBinding[] VALUES = values();
+    }
+
+    /**
+     * Constants denoting the linear-scan states an interval may be in with respect to the
+     * {@linkplain TraceInterval#from() start} {@code position} of the interval being processed.
+     */
+    enum State {
+        /**
+         * An interval that starts after {@code position}.
+         */
+        Unhandled,
+
+        /**
+         * An interval that {@linkplain TraceInterval#covers covers} {@code position} and has an
+         * assigned register.
+         */
+        Active,
+
+        /**
+         * An interval that starts before and ends after {@code position} but does not
+         * {@linkplain TraceInterval#covers cover} it due to a lifetime hole.
+         */
+        Inactive,
+
+        /**
+         * An interval that ends before {@code position} or is spilled to memory.
+         */
+        Handled;
+    }
+
+    /**
+     * Constants used in optimization of spilling of an interval.
+     */
+    public enum SpillState {
+        /**
+         * Starting state of calculation: no definition found yet.
+         */
+        NoDefinitionFound,
+
+        /**
+         * One definition has already been found. Two consecutive definitions are treated as one
+         * (e.g. a consecutive move and add because of two-operand LIR form). The position of this
+         * definition is given by {@link TraceInterval#spillDefinitionPos()}.
+         */
+        NoSpillStore,
+
+        /**
+         * A spill move has already been inserted.
+         */
+        SpillStore,
+
+        /**
+         * The interval starts in memory (e.g. method parameter), so a store is never necessary.
+         */
+        StartInMemory,
+
+        /**
+         * The interval has more than one definition (e.g. resulting from phi moves), so stores to
+         * memory are not optimized.
+         */
+        NoOptimization;
+
+        public static final EnumSet<SpillState> IN_MEMORY = EnumSet.of(SpillStore, StartInMemory);
+    }
+
+    /**
+     * The {@linkplain RegisterValue register} or {@linkplain Variable variable} for this interval
+     * prior to register allocation.
+     */
+    public final AllocatableValue operand;
+
+    /**
+     * The operand number for this interval's {@linkplain #operand operand}.
+     */
+    public final int operandNumber;
+
+    /**
+     * The {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to this
+     * interval. In case of a spilled interval which is re-materialized this is
+     * {@link Value#ILLEGAL}.
+     */
+    private AllocatableValue location;
+
+    /**
+     * The stack slot to which all splits of this interval are spilled if necessary.
+     */
+    private AllocatableValue spillSlot;
+
+    /**
+     * The kind of this interval.
+     */
+    private LIRKind kind;
+
+    /**
+     * The start of the range, inclusive.
+     */
+    public int intFrom;
+
+    /**
+     * The end of the range, exclusive.
+     */
+    public int intTo;
+
+    /**
+     * List of (use-positions, register-priorities) pairs, sorted by use-positions.
+     */
+    private UsePosList usePosList;
+
+    /**
+     * Link to next interval in a sorted list of intervals that ends with {@link #EndMarker}.
+     */
+    TraceInterval next;
+
+    /**
+     * The linear-scan state of this interval.
+     */
+    State state;
+
+    /**
+     * The interval from which this one is derived. If this is a {@linkplain #isSplitParent() split
+     * parent}, it points to itself.
+     */
+    private TraceInterval splitParent;
+
+    /**
+     * List of all intervals that are split off from this interval. This is only used if this is a
+     * {@linkplain #isSplitParent() split parent}.
+     */
+    private List<TraceInterval> splitChildren = Collections.emptyList();
+
+    /**
+     * Current split child that has been active or inactive last (always stored in split parents).
+     */
+    private TraceInterval currentSplitChild;
+
+    /**
+     * Specifies if move is inserted between currentSplitChild and this interval when interval gets
+     * active the first time.
+     */
+    private boolean insertMoveWhenActivated;
+
+    /**
+     * For spill move optimization.
+     */
+    private SpillState spillState;
+
+    /**
+     * Position where this interval is defined (if defined only once).
+     */
+    private int spillDefinitionPos;
+
+    /**
+     * This interval should be assigned the same location as the hint interval.
+     */
+    private IntervalHint locationHint;
+
+    /**
+     * The value with which a spilled child interval can be re-materialized. Currently this must be
+     * a Constant.
+     */
+    private JavaConstant materializedValue;
+
+    /**
+     * The number of times {@link #addMaterializationValue(JavaConstant)} is called.
+     */
+    private int numMaterializationValuesAdded;
+
+    void assignLocation(AllocatableValue newLocation) {
+        if (isRegister(newLocation)) {
+            assert this.location == null : "cannot re-assign location for " + this;
+            if (newLocation.getLIRKind().equals(LIRKind.Illegal) && !kind.equals(LIRKind.Illegal)) {
+                this.location = asRegister(newLocation).asValue(kind);
+                return;
+            }
+        } else if (isIllegal(newLocation)) {
+            assert canMaterialize();
+        } else {
+            assert this.location == null || isRegister(this.location) || (isVirtualStackSlot(this.location) && isStackSlot(newLocation)) : "cannot re-assign location for " + this;
+            assert isStackSlotValue(newLocation);
+            assert !newLocation.getLIRKind().equals(LIRKind.Illegal);
+            assert newLocation.getLIRKind().equals(this.kind);
+        }
+        this.location = newLocation;
+    }
+
+    /**
+     * Gets the {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to
+     * this interval.
+     */
+    @Override
+    public AllocatableValue location() {
+        return location;
+    }
+
+    public LIRKind kind() {
+        assert !isRegister(operand) : "cannot access type for fixed interval";
+        return kind;
+    }
+
+    public void setKind(LIRKind kind) {
+        assert isRegister(operand) || this.kind().equals(LIRKind.Illegal) || this.kind().equals(kind) : "overwriting existing type";
+        this.kind = kind;
+    }
+
+    public boolean isEmpty() {
+        return intFrom == Integer.MAX_VALUE && intTo == Integer.MAX_VALUE;
+    }
+
+    public void setTo(int pos) {
+        assert intFrom == Integer.MAX_VALUE || intFrom < pos;
+        intTo = pos;
+    }
+
+    public void setFrom(int pos) {
+        assert intTo == Integer.MAX_VALUE || pos < intTo;
+        intFrom = pos;
+    }
+
+    @Override
+    public int from() {
+        return intFrom;
+    }
+
+    int to() {
+        return intTo;
+    }
+
+    int numUsePositions() {
+        return usePosList.size();
+    }
+
+    public void setLocationHint(IntervalHint interval) {
+        locationHint = interval;
+    }
+
+    public boolean isSplitParent() {
+        return splitParent == this;
+    }
+
+    boolean isSplitChild() {
+        return splitParent != this;
+    }
+
+    /**
+     * Gets the split parent for this interval.
+     */
+    public TraceInterval splitParent() {
+        assert splitParent.isSplitParent() : "not a split parent: " + this;
+        return splitParent;
+    }
+
+    /**
+     * Gets the canonical spill slot for this interval.
+     */
+    public AllocatableValue spillSlot() {
+        return splitParent().spillSlot;
+    }
+
+    public void setSpillSlot(AllocatableValue slot) {
+        assert isStackSlotValue(slot);
+        assert splitParent().spillSlot == null || (isVirtualStackSlot(splitParent().spillSlot) && isStackSlot(slot)) : "connot overwrite existing spill slot";
+        splitParent().spillSlot = slot;
+    }
+
+    TraceInterval currentSplitChild() {
+        return splitParent().currentSplitChild;
+    }
+
+    void makeCurrentSplitChild() {
+        splitParent().currentSplitChild = this;
+    }
+
+    boolean insertMoveWhenActivated() {
+        return insertMoveWhenActivated;
+    }
+
+    void setInsertMoveWhenActivated(boolean b) {
+        insertMoveWhenActivated = b;
+    }
+
+    // for spill optimization
+    public SpillState spillState() {
+        return splitParent().spillState;
+    }
+
+    public int spillDefinitionPos() {
+        return splitParent().spillDefinitionPos;
+    }
+
+    public void setSpillState(SpillState state) {
+        assert state.ordinal() >= spillState().ordinal() : "state cannot decrease";
+        splitParent().spillState = state;
+    }
+
+    public void setSpillDefinitionPos(int pos) {
+        assert spillState() == SpillState.NoDefinitionFound || spillState() == SpillState.NoSpillStore || spillDefinitionPos() == -1 : "cannot set the position twice";
+        int to = to();
+        assert pos < to : String.format("Cannot spill %s at %d", this, pos);
+        splitParent().spillDefinitionPos = pos;
+    }
+
+    /**
+     * Returns true if this interval has a shadow copy on the stack that is correct after
+     * {@code opId}.
+     */
+    public boolean inMemoryAt(int opId) {
+        SpillState spillSt = spillState();
+        return spillSt == SpillState.StartInMemory || (spillSt == SpillState.SpillStore && opId > spillDefinitionPos() && !canMaterialize());
+    }
+
+    void removeFirstUsePos() {
+        usePosList.removeLowestUsePos();
+    }
+
+    // test intersection
+    boolean intersects(TraceInterval i) {
+        return intersectsAt(i) != -1;
+    }
+
+    int intersectsAt(TraceInterval i) {
+        TraceInterval i1;
+        TraceInterval i2;
+        if (i.from() < this.from()) {
+            i1 = i;
+            i2 = this;
+        } else {
+            i1 = this;
+            i2 = i;
+        }
+        assert i1.from() <= i2.from();
+
+        if (i1.to() <= i2.from()) {
+            return -1;
+        }
+        return i2.from();
+    }
+
+    /**
+     * Sentinel interval to denote the end of an interval list.
+     */
+    static final TraceInterval EndMarker = new TraceInterval(Value.ILLEGAL, -1);
+
+    TraceInterval(AllocatableValue operand, int operandNumber) {
+        assert operand != null;
+        this.operand = operand;
+        this.operandNumber = operandNumber;
+        if (isRegister(operand)) {
+            location = operand;
+        } else {
+            assert isIllegal(operand) || isVariable(operand);
+        }
+        this.kind = LIRKind.Illegal;
+        this.intFrom = Integer.MAX_VALUE;
+        this.intTo = Integer.MAX_VALUE;
+        this.usePosList = new UsePosList(4);
+        this.next = EndMarker;
+        this.spillState = SpillState.NoDefinitionFound;
+        this.spillDefinitionPos = -1;
+        splitParent = this;
+        currentSplitChild = this;
+    }
+
+    /**
+     * Sets the value which is used for re-materialization.
+     */
+    public void addMaterializationValue(JavaConstant value) {
+        if (numMaterializationValuesAdded == 0) {
+            materializedValue = value;
+        } else {
+            // Interval is defined on multiple places -> no materialization is possible.
+            materializedValue = null;
+        }
+        numMaterializationValuesAdded++;
+    }
+
+    /**
+     * Returns true if this interval can be re-materialized when spilled. This means that no
+     * spill-moves are needed. Instead of restore-moves the {@link #materializedValue} is restored.
+     */
+    public boolean canMaterialize() {
+        return getMaterializedValue() != null;
+    }
+
+    /**
+     * Returns a value which can be moved to a register instead of a restore-move from stack.
+     */
+    public JavaConstant getMaterializedValue() {
+        return splitParent().materializedValue;
+    }
+
+    // consistency check of split-children
+    boolean checkSplitChildren() {
+        if (!splitChildren.isEmpty()) {
+            assert isSplitParent() : "only split parents can have children";
+
+            for (int i = 0; i < splitChildren.size(); i++) {
+                TraceInterval i1 = splitChildren.get(i);
+
+                assert i1.splitParent() == this : "not a split child of this interval";
+                assert i1.kind().equals(kind()) : "must be equal for all split children";
+                assert (i1.spillSlot() == null && spillSlot == null) || i1.spillSlot().equals(spillSlot()) : "must be equal for all split children";
+
+                for (int j = i + 1; j < splitChildren.size(); j++) {
+                    TraceInterval i2 = splitChildren.get(j);
+
+                    assert !i1.operand.equals(i2.operand) : "same register number";
+
+                    if (i1.from() < i2.from()) {
+                        assert i1.to() <= i2.from() && i1.to() < i2.to() : "intervals overlapping";
+                    } else {
+                        assert i2.from() < i1.from() : "intervals start at same opId";
+                        assert i2.to() <= i1.from() && i2.to() < i1.to() : "intervals overlapping";
+                    }
+                }
+            }
+        }
+
+        return true;
+    }
+
+    public IntervalHint locationHint(boolean searchSplitChild) {
+        if (!searchSplitChild) {
+            return locationHint;
+        }
+
+        if (locationHint != null) {
+            assert !(locationHint instanceof TraceInterval) || ((TraceInterval) locationHint).isSplitParent() : "ony split parents are valid hint registers";
+
+            if (locationHint.location() != null && isRegister(locationHint.location())) {
+                return locationHint;
+            } else if (locationHint instanceof TraceInterval) {
+                TraceInterval hint = (TraceInterval) locationHint;
+                if (!hint.splitChildren.isEmpty()) {
+                    // search the first split child that has a register assigned
+                    int len = hint.splitChildren.size();
+                    for (int i = 0; i < len; i++) {
+                        TraceInterval interval = hint.splitChildren.get(i);
+                        if (interval.location != null && isRegister(interval.location)) {
+                            return interval;
+                        }
+                    }
+                }
+            }
+        }
+
+        // no hint interval found that has a register assigned
+        return null;
+    }
+
+    TraceInterval getSplitChildAtOpId(int opId, LIRInstruction.OperandMode mode, TraceLinearScan allocator) {
+        assert isSplitParent() : "can only be called for split parents";
+        assert opId >= 0 : "invalid opId (method cannot be called for spill moves)";
+
+        if (splitChildren.isEmpty()) {
+            assert this.covers(opId, mode) : this + " does not cover " + opId;
+            return this;
+        } else {
+            TraceInterval result = null;
+            int len = splitChildren.size();
+
+            // in outputMode, the end of the interval (opId == cur.to()) is not valid
+            int toOffset = (mode == LIRInstruction.OperandMode.DEF ? 0 : 1);
+
+            int i;
+            for (i = 0; i < len; i++) {
+                TraceInterval cur = splitChildren.get(i);
+                if (cur.from() <= opId && opId < cur.to() + toOffset) {
+                    if (i > 0) {
+                        // exchange current split child to start of list (faster access for next
+                        // call)
+                        Util.atPutGrow(splitChildren, i, splitChildren.get(0), null);
+                        Util.atPutGrow(splitChildren, 0, cur, null);
+                    }
+
+                    // interval found
+                    result = cur;
+                    break;
+                }
+            }
+
+            assert checkSplitChild(result, opId, allocator, toOffset, mode);
+            return result;
+        }
+    }
+
+    private boolean checkSplitChild(TraceInterval result, int opId, TraceLinearScan allocator, int toOffset, LIRInstruction.OperandMode mode) {
+        if (result == null) {
+            // this is an error
+            StringBuilder msg = new StringBuilder(this.toString()).append(" has no child at ").append(opId);
+            if (!splitChildren.isEmpty()) {
+                TraceInterval firstChild = splitChildren.get(0);
+                TraceInterval lastChild = splitChildren.get(splitChildren.size() - 1);
+                msg.append(" (first = ").append(firstChild).append(", last = ").append(lastChild).append(")");
+            }
+            throw new JVMCIError("Linear Scan Error: %s", msg);
+        }
+
+        if (!splitChildren.isEmpty()) {
+            for (TraceInterval interval : splitChildren) {
+                if (interval != result && interval.from() <= opId && opId < interval.to() + toOffset) {
+                    TTY.println(String.format("two valid result intervals found for opId %d: %d and %d", opId, result.operandNumber, interval.operandNumber));
+                    TTY.println(result.logString(allocator));
+                    TTY.println(interval.logString(allocator));
+                    throw new BailoutException("two valid result intervals found");
+                }
+            }
+        }
+        assert result.covers(opId, mode) : "opId not covered by interval";
+        return true;
+    }
+
+    // returns the interval that covers the given opId or null if there is none
+    TraceInterval getIntervalCoveringOpId(int opId) {
+        assert opId >= 0 : "invalid opId";
+        assert opId < to() : "can only look into the past";
+
+        if (opId >= from()) {
+            return this;
+        }
+
+        TraceInterval parent = splitParent();
+        TraceInterval result = null;
+
+        assert !parent.splitChildren.isEmpty() : "no split children available";
+        int len = parent.splitChildren.size();
+
+        for (int i = len - 1; i >= 0; i--) {
+            TraceInterval cur = parent.splitChildren.get(i);
+            if (cur.from() <= opId && opId < cur.to()) {
+                assert result == null : "covered by multiple split children " + result + " and " + cur;
+                result = cur;
+            }
+        }
+
+        return result;
+    }
+
+    // returns the last split child that ends before the given opId
+    TraceInterval getSplitChildBeforeOpId(int opId) {
+        assert opId >= 0 : "invalid opId";
+
+        TraceInterval parent = splitParent();
+        TraceInterval result = null;
+
+        assert !parent.splitChildren.isEmpty() : "no split children available";
+        int len = parent.splitChildren.size();
+
+        for (int i = len - 1; i >= 0; i--) {
+            TraceInterval cur = parent.splitChildren.get(i);
+            if (cur.to() <= opId && (result == null || result.to() < cur.to())) {
+                result = cur;
+            }
+        }
+
+        assert result != null : "no split child found";
+        return result;
+    }
+
+    // checks if opId is covered by any split child
+    boolean splitChildCovers(int opId, LIRInstruction.OperandMode mode) {
+        assert isSplitParent() : "can only be called for split parents";
+        assert opId >= 0 : "invalid opId (method can not be called for spill moves)";
+
+        if (splitChildren.isEmpty()) {
+            // simple case if interval was not split
+            return covers(opId, mode);
+
+        } else {
+            // extended case: check all split children
+            int len = splitChildren.size();
+            for (int i = 0; i < len; i++) {
+                TraceInterval cur = splitChildren.get(i);
+                if (cur.covers(opId, mode)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    private RegisterPriority adaptPriority(RegisterPriority priority) {
+        /*
+         * In case of re-materialized values we require that use-operands are registers, because we
+         * don't have the value in a stack location. (Note that ShouldHaveRegister means that the
+         * operand can also be a StackSlot).
+         */
+        if (priority == RegisterPriority.ShouldHaveRegister && canMaterialize()) {
+            return RegisterPriority.MustHaveRegister;
+        }
+        return priority;
+    }
+
+    // Note: use positions are sorted descending . first use has highest index
+    int firstUsage(RegisterPriority minRegisterPriority) {
+        assert isVariable(operand) : "cannot access use positions for fixed intervals";
+
+        for (int i = usePosList.size() - 1; i >= 0; --i) {
+            RegisterPriority registerPriority = adaptPriority(usePosList.registerPriority(i));
+            if (registerPriority.greaterEqual(minRegisterPriority)) {
+                return usePosList.usePos(i);
+            }
+        }
+        return Integer.MAX_VALUE;
+    }
+
+    int nextUsage(RegisterPriority minRegisterPriority, int from) {
+        assert isVariable(operand) : "cannot access use positions for fixed intervals";
+
+        for (int i = usePosList.size() - 1; i >= 0; --i) {
+            int usePos = usePosList.usePos(i);
+            if (usePos >= from && adaptPriority(usePosList.registerPriority(i)).greaterEqual(minRegisterPriority)) {
+                return usePos;
+            }
+        }
+        return Integer.MAX_VALUE;
+    }
+
+    int nextUsageExact(RegisterPriority exactRegisterPriority, int from) {
+        assert isVariable(operand) : "cannot access use positions for fixed intervals";
+
+        for (int i = usePosList.size() - 1; i >= 0; --i) {
+            int usePos = usePosList.usePos(i);
+            if (usePos >= from && adaptPriority(usePosList.registerPriority(i)) == exactRegisterPriority) {
+                return usePos;
+            }
+        }
+        return Integer.MAX_VALUE;
+    }
+
+    int previousUsage(RegisterPriority minRegisterPriority, int from) {
+        assert isVariable(operand) : "cannot access use positions for fixed intervals";
+
+        int prev = -1;
+        for (int i = usePosList.size() - 1; i >= 0; --i) {
+            int usePos = usePosList.usePos(i);
+            if (usePos > from) {
+                return prev;
+            }
+            if (adaptPriority(usePosList.registerPriority(i)).greaterEqual(minRegisterPriority)) {
+                prev = usePos;
+            }
+        }
+        return prev;
+    }
+
+    public void addUsePos(int pos, RegisterPriority registerPriority) {
+        assert isEmpty() || covers(pos, LIRInstruction.OperandMode.USE) : String.format("use position %d not covered by live range of interval %s", pos, this);
+
+        // do not add use positions for precolored intervals because they are never used
+        if (registerPriority != RegisterPriority.None && isVariable(operand)) {
+            if (DetailedAsserts.getValue()) {
+                for (int i = 0; i < usePosList.size(); i++) {
+                    assert pos <= usePosList.usePos(i) : "already added a use-position with lower position";
+                    if (i > 0) {
+                        assert usePosList.usePos(i) < usePosList.usePos(i - 1) : "not sorted descending";
+                    }
+                }
+            }
+
+            // Note: addUse is called in descending order, so list gets sorted
+            // automatically by just appending new use positions
+            int len = usePosList.size();
+            if (len == 0 || usePosList.usePos(len - 1) > pos) {
+                usePosList.add(pos, registerPriority);
+            } else if (usePosList.registerPriority(len - 1).lessThan(registerPriority)) {
+                assert usePosList.usePos(len - 1) == pos : "list not sorted correctly";
+                usePosList.setRegisterPriority(len - 1, registerPriority);
+            }
+        }
+    }
+
+    public void addRange(int from, int to) {
+        assert from < to : "invalid range";
+
+        if (from < intFrom) {
+            setFrom(from);
+        }
+        if (intTo == Integer.MAX_VALUE || intTo < to) {
+            setTo(to);
+        }
+    }
+
+    TraceInterval newSplitChild(TraceLinearScan allocator) {
+        // allocate new interval
+        TraceInterval parent = splitParent();
+        TraceInterval result = allocator.createDerivedInterval(parent);
+        result.setKind(kind());
+
+        result.splitParent = parent;
+        result.setLocationHint(parent);
+
+        // insert new interval in children-list of parent
+        if (parent.splitChildren.isEmpty()) {
+            assert isSplitParent() : "list must be initialized at first split";
+
+            // Create new non-shared list
+            parent.splitChildren = new ArrayList<>(4);
+            parent.splitChildren.add(this);
+        }
+        parent.splitChildren.add(result);
+
+        return result;
+    }
+
+    /**
+     * Splits this interval at a specified position and returns the remainder as a new <i>child</i>
+     * interval of this interval's {@linkplain #splitParent() parent} interval.
+     * <p>
+     * When an interval is split, a bi-directional link is established between the original
+     * <i>parent</i> interval and the <i>children</i> intervals that are split off this interval.
+     * When a split child is split again, the new created interval is a direct child of the original
+     * parent. That is, there is no tree of split children stored, just a flat list. All split
+     * children are spilled to the same {@linkplain #spillSlot spill slot}.
+     *
+     * @param splitPos the position at which to split this interval
+     * @param allocator the register allocator context
+     * @return the child interval split off from this interval
+     */
+    TraceInterval split(int splitPos, TraceLinearScan allocator) {
+        assert isVariable(operand) : "cannot split fixed intervals";
+
+        // allocate new interval
+        TraceInterval result = newSplitChild(allocator);
+
+        // split the ranges
+        result.setTo(intTo);
+        result.setFrom(splitPos);
+        intTo = splitPos;
+
+        // split list of use positions
+        result.usePosList = usePosList.splitAt(splitPos);
+
+        if (DetailedAsserts.getValue()) {
+            for (int i = 0; i < usePosList.size(); i++) {
+                assert usePosList.usePos(i) < splitPos;
+            }
+            for (int i = 0; i < result.usePosList.size(); i++) {
+                assert result.usePosList.usePos(i) >= splitPos;
+            }
+        }
+        return result;
+    }
+
+    // returns true if the opId is inside the interval
+    boolean covers(int opId, LIRInstruction.OperandMode mode) {
+        if (mode == LIRInstruction.OperandMode.DEF) {
+            return from() <= opId && opId < to();
+        }
+        return from() <= opId && opId <= to();
+    }
+
+    @Override
+    public String toString() {
+        String from = "?";
+        String to = "?";
+        if (!isEmpty()) {
+            from = String.valueOf(from());
+            to = String.valueOf(to());
+        }
+        String locationString = this.location == null ? "" : "@" + this.location;
+        return operandNumber + ":" + operand + (isRegister(operand) ? "" : locationString) + "[" + from + "," + to + "]";
+    }
+
+    /**
+     * Gets the use position information for this interval.
+     */
+    public UsePosList usePosList() {
+        return usePosList;
+    }
+
+    /**
+     * Gets a single line string for logging the details of this interval to a log stream.
+     *
+     * @param allocator the register allocator context
+     */
+    @Override
+    public String logString(TraceLinearScan allocator) {
+        StringBuilder buf = new StringBuilder(100);
+        buf.append("any ").append(operandNumber).append(':').append(operand).append(' ');
+        if (!isRegister(operand)) {
+            if (location != null) {
+                buf.append("location{").append(location).append("} ");
+            }
+        }
+
+        buf.append("hints{").append(splitParent.operandNumber);
+        IntervalHint hint = locationHint(false);
+        if (hint != null) {
+            buf.append(", ").append(hint.location());
+        }
+        buf.append("} ranges{");
+
+        // print range
+        buf.append("[" + from() + ", " + to() + "]");
+        buf.append("} uses{");
+
+        // print use positions
+        int prev = -1;
+        for (int i = usePosList.size() - 1; i >= 0; --i) {
+            assert prev < usePosList.usePos(i) : "use positions not sorted";
+            if (i != usePosList.size() - 1) {
+                buf.append(", ");
+            }
+            buf.append(usePosList.usePos(i)).append(':').append(usePosList.registerPriority(i).shortName());
+            prev = usePosList.usePos(i);
+        }
+        buf.append("} spill-state{").append(spillState()).append("}");
+        if (canMaterialize()) {
+            buf.append(" (remat:").append(getMaterializedValue().toString()).append(")");
+        }
+        return buf.toString();
+    }
+
+    List<TraceInterval> getSplitChildren() {
+        return Collections.unmodifiableList(splitChildren);
+    }
+
+    boolean isFixedInterval() {
+        return isRegister(operand);
+    }
+
+    private static boolean isDefinitionPosition(int usePos) {
+        return (usePos & 1) == 1;
+    }
+
+    int currentFrom(int currentPosition) {
+        assert isFixedInterval();
+        for (int i = 0; i < usePosList.size(); i++) {
+            int usePos = usePosList.usePos(i);
+            if (usePos <= currentPosition && isDefinitionPosition(usePos)) {
+                return usePos;
+            }
+
+        }
+        return Integer.MAX_VALUE;
+    }
+
+    int currentIntersectsAt(int currentPosition, TraceInterval current) {
+        assert isFixedInterval();
+        assert !current.isFixedInterval();
+        int from = Integer.MAX_VALUE;
+        int to = Integer.MIN_VALUE;
+
+        for (int i = 0; i < usePosList.size(); i++) {
+            int usePos = usePosList.usePos(i);
+            if (isDefinitionPosition(usePos)) {
+                if (usePos <= currentPosition) {
+                    from = usePos;
+                    break;
+                }
+                to = Integer.MIN_VALUE;
+            } else {
+                if (to < usePos) {
+                    to = usePos;
+                }
+            }
+        }
+        if (from < current.from()) {
+            if (to <= current.from()) {
+                return -1;
+            }
+            return current.from();
+        } else {
+            if (current.to() <= from) {
+                return -1;
+            }
+            return from;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/TraceIntervalDumper.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015, 2015, 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.alloc.trace.lsra;
+
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+import com.oracle.graal.lir.debug.IntervalDumper;
+
+final class TraceIntervalDumper implements IntervalDumper {
+    private final FixedInterval[] fixedIntervals;
+    private final TraceInterval[] intervals;
+
+    public TraceIntervalDumper(FixedInterval[] fixedIntervals, TraceInterval[] intervals) {
+        this.fixedIntervals = fixedIntervals;
+        this.intervals = intervals;
+    }
+
+    public void visitIntervals(IntervalVisitor visitor) {
+        for (FixedInterval interval : fixedIntervals) {
+            if (interval != null) {
+                printFixedInterval(interval, visitor);
+            }
+        }
+        for (TraceInterval interval : intervals) {
+            if (interval != null) {
+                printInterval(interval, visitor);
+            }
+        }
+    }
+
+    private static void printFixedInterval(FixedInterval interval, IntervalVisitor visitor) {
+        Value hint = null;
+        AllocatableValue operand = interval.operand;
+        String type = "fixed";
+        char typeChar = operand.getPlatformKind().getTypeChar();
+        visitor.visitIntervalStart(operand, operand, operand, hint, type, typeChar);
+
+        // print ranges
+        for (FixedRange range = interval.first(); range != FixedRange.EndMarker; range = range.next) {
+            visitor.visitRange(range.from, range.to);
+        }
+
+        // no use positions
+
+        visitor.visitIntervalEnd("NOT_SUPPORTED");
+
+    }
+
+    private static void printInterval(TraceInterval interval, IntervalVisitor visitor) {
+        Value hint = interval.locationHint(false) != null ? interval.locationHint(false).location() : null;
+        AllocatableValue operand = interval.operand;
+        String type = isRegister(operand) ? "fixed" : operand.getLIRKind().getPlatformKind().toString();
+        char typeChar = operand.getPlatformKind().getTypeChar();
+        visitor.visitIntervalStart(interval.splitParent().operand, operand, interval.location(), hint, type, typeChar);
+
+        // print ranges
+        visitor.visitRange(interval.from(), interval.to());
+
+        // print use positions
+        int prev = -1;
+        UsePosList usePosList = interval.usePosList();
+        for (int i = usePosList.size() - 1; i >= 0; --i) {
+            assert prev < usePosList.usePos(i) : "use positions not sorted";
+            visitor.visitUsePos(usePosList.usePos(i), usePosList.registerPriority(i));
+            prev = usePosList.usePos(i);
+        }
+
+        visitor.visitIntervalEnd(interval.spillState());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/TraceIntervalWalker.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2009, 2015, 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.alloc.trace.lsra;
+
+import jdk.vm.ci.common.JVMCIError;
+
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.Indent;
+import com.oracle.graal.lir.alloc.trace.lsra.FixedInterval.FixedList;
+import com.oracle.graal.lir.alloc.trace.lsra.TraceInterval.AnyList;
+import com.oracle.graal.lir.alloc.trace.lsra.TraceInterval.RegisterBinding;
+import com.oracle.graal.lir.alloc.trace.lsra.TraceInterval.State;
+
+/**
+ */
+class TraceIntervalWalker {
+
+    protected final TraceLinearScan allocator;
+
+    /**
+     * Sorted list of intervals, not live before the current position.
+     */
+    protected AnyList unhandledAnyList;
+
+    /**
+     * Sorted list of intervals, live at the current position.
+     */
+    protected AnyList activeAnyList;
+    protected FixedList activeFixedList;
+
+    /**
+     * Sorted list of intervals in a life time hole at the current position.
+     */
+    protected FixedList inactiveFixedList;
+
+    /**
+     * The current position (intercept point through the intervals).
+     */
+    protected int currentPosition;
+
+    /**
+     * Processes the {@code currentInterval} interval in an attempt to allocate a physical register
+     * to it and thus allow it to be moved to a list of {@linkplain #activeAnyList active}
+     * intervals.
+     *
+     * @param currentInterval The interval to be activated.
+     *
+     * @return {@code true} if a register was allocated to the {@code currentInterval} interval
+     */
+    protected boolean activateCurrent(TraceInterval currentInterval) {
+        if (Debug.isLogEnabled()) {
+            logCurrentStatus();
+        }
+        return true;
+    }
+
+    @SuppressWarnings("try")
+    protected void logCurrentStatus() {
+        try (Indent i = Debug.logAndIndent("active:")) {
+            logList(activeFixedList.getFixed());
+            logList(activeAnyList.getAny());
+        }
+        try (Indent i = Debug.logAndIndent("inactive(fixed):")) {
+            logList(inactiveFixedList.getFixed());
+        }
+    }
+
+    private void logList(FixedInterval i) {
+        for (FixedInterval interval = i; interval != FixedInterval.EndMarker; interval = interval.next) {
+            Debug.log("%s", interval.logString(allocator));
+        }
+    }
+
+    private void logList(TraceInterval i) {
+        for (TraceInterval interval = i; interval != TraceInterval.EndMarker; interval = interval.next) {
+            Debug.log("%s", interval.logString(allocator));
+        }
+    }
+
+    void walkBefore(int lirOpId) {
+        walkTo(lirOpId - 1);
+    }
+
+    void walk() {
+        walkTo(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Creates a new interval walker.
+     *
+     * @param allocator the register allocator context
+     * @param unhandledFixed the list of unhandled {@linkplain RegisterBinding#Fixed fixed}
+     *            intervals
+     * @param unhandledAny the list of unhandled {@linkplain RegisterBinding#Any non-fixed}
+     *            intervals
+     */
+    TraceIntervalWalker(TraceLinearScan allocator, FixedInterval unhandledFixed, TraceInterval unhandledAny) {
+        this.allocator = allocator;
+
+        unhandledAnyList = new AnyList(unhandledAny);
+        activeAnyList = new AnyList(TraceInterval.EndMarker);
+        activeFixedList = new FixedList(FixedInterval.EndMarker);
+        // we don't need a separate unhandled list for fixed.
+        inactiveFixedList = new FixedList(unhandledFixed);
+        currentPosition = -1;
+    }
+
+    protected void removeFromList(TraceInterval interval) {
+        if (interval.state == State.Active) {
+            activeAnyList.removeAny(interval);
+        } else {
+            assert interval.state == State.Inactive : "invalid state";
+            // inactiveAnyLists.removeAny(interval);
+            throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * Walks up to {@code from} and updates the state of {@link FixedInterval fixed intervals}.
+     *
+     * Fixed intervals can switch back and forth between the states {@link State#Active} and
+     * {@link State#Inactive} (and eventually to {@link State#Handled} but handled intervals are not
+     * managed).
+     */
+    @SuppressWarnings("try")
+    private void walkToFixed(State state, int from) {
+        assert state == State.Active || state == State.Inactive : "wrong state";
+        FixedInterval prevprev = null;
+        FixedInterval prev = (state == State.Active) ? activeFixedList.getFixed() : inactiveFixedList.getFixed();
+        FixedInterval next = prev;
+        if (Debug.isLogEnabled()) {
+            try (Indent i = Debug.logAndIndent("walkToFixed(%s, %d):", state, from)) {
+                logList(next);
+            }
+        }
+        while (next.currentFrom() <= from) {
+            FixedInterval cur = next;
+            next = cur.next;
+
+            boolean rangeHasChanged = false;
+            while (cur.currentTo() <= from) {
+                cur.nextRange();
+                rangeHasChanged = true;
+            }
+
+            // also handle move from inactive list to active list
+            rangeHasChanged = rangeHasChanged || (state == State.Inactive && cur.currentFrom() <= from);
+
+            if (rangeHasChanged) {
+                // remove cur from list
+                if (prevprev == null) {
+                    if (state == State.Active) {
+                        activeFixedList.setFixed(next);
+                    } else {
+                        inactiveFixedList.setFixed(next);
+                    }
+                } else {
+                    prevprev.next = next;
+                }
+                prev = next;
+                TraceInterval.State newState;
+                if (cur.currentAtEnd()) {
+                    // move to handled state (not maintained as a list)
+                    newState = State.Handled;
+                } else {
+                    if (cur.currentFrom() <= from) {
+                        // sort into active list
+                        activeFixedList.addToListSortedByCurrentFromPositions(cur);
+                        newState = State.Active;
+                    } else {
+                        // sort into inactive list
+                        inactiveFixedList.addToListSortedByCurrentFromPositions(cur);
+                        newState = State.Inactive;
+                    }
+                    if (prev == cur) {
+                        assert state == newState;
+                        prevprev = prev;
+                        prev = cur.next;
+                    }
+                }
+                intervalMoved(cur, state, newState);
+            } else {
+                prevprev = prev;
+                prev = cur.next;
+            }
+        }
+    }
+
+    /**
+     * Walks up to {@code from} and updates the state of {@link TraceInterval intervals}.
+     *
+     * Trace intervals can switch once from {@link State#Unhandled} to {@link State#Active} and then
+     * to {@link State#Handled} but handled intervals are not managed.
+     */
+    @SuppressWarnings("try")
+    private void walkToAny(int from) {
+        TraceInterval prevprev = null;
+        TraceInterval prev = activeAnyList.getAny();
+        TraceInterval next = prev;
+        if (Debug.isLogEnabled()) {
+            try (Indent i = Debug.logAndIndent("walkToAny(%d):", from)) {
+                logList(next);
+            }
+        }
+        while (next.from() <= from) {
+            TraceInterval cur = next;
+            next = cur.next;
+
+            if (cur.to() <= from) {
+                // remove cur from list
+                if (prevprev == null) {
+                    activeAnyList.setAny(next);
+                } else {
+                    prevprev.next = next;
+                }
+                intervalMoved(cur, State.Active, State.Handled);
+            } else {
+                prevprev = prev;
+            }
+            prev = next;
+        }
+    }
+
+    /**
+     * Get the next interval from {@linkplain #unhandledAnyList} which starts before or at
+     * {@code toOpId}. The returned interval is removed.
+     *
+     * @postcondition all intervals in {@linkplain #unhandledAnyList} start after {@code toOpId}.
+     *
+     * @return The next interval or null if there is no {@linkplain #unhandledAnyList unhandled}
+     *         interval at position {@code toOpId}.
+     */
+    private TraceInterval nextInterval(int toOpId) {
+        TraceInterval any = unhandledAnyList.getAny();
+
+        if (any != TraceInterval.EndMarker) {
+            TraceInterval currentInterval = unhandledAnyList.getAny();
+            if (toOpId < currentInterval.from()) {
+                return null;
+            }
+
+            unhandledAnyList.setAny(currentInterval.next);
+            currentInterval.next = TraceInterval.EndMarker;
+            return currentInterval;
+        }
+        return null;
+
+    }
+
+    /**
+     * Walk up to {@code toOpId}.
+     *
+     * @postcondition {@link #currentPosition} is set to {@code toOpId}, {@link #activeFixedList}
+     *                and {@link #inactiveFixedList} are populated and {@link TraceInterval#state}s
+     *                are up to date.
+     */
+    @SuppressWarnings("try")
+    protected void walkTo(int toOpId) {
+        assert currentPosition <= toOpId : "can not walk backwards";
+        for (TraceInterval currentInterval = nextInterval(toOpId); currentInterval != null; currentInterval = nextInterval(toOpId)) {
+            int opId = currentInterval.from();
+
+            // set currentPosition prior to call of walkTo
+            currentPosition = opId;
+
+            // update unhandled stack intervals
+            // updateUnhandledStackIntervals(opId);
+
+            // call walkTo even if currentPosition == id
+            walkToFixed(State.Active, opId);
+            walkToFixed(State.Inactive, opId);
+            walkToAny(opId);
+
+            try (Indent indent = Debug.logAndIndent("walk to op %d", opId)) {
+                currentInterval.state = State.Active;
+                if (activateCurrent(currentInterval)) {
+                    activeAnyList.addToListSortedByFromPositions(currentInterval);
+                    intervalMoved(currentInterval, State.Unhandled, State.Active);
+                }
+            }
+        }
+        // set currentPosition prior to call of walkTo
+        currentPosition = toOpId;
+
+        if (currentPosition <= allocator.maxOpId()) {
+            // update unhandled stack intervals
+            // updateUnhandledStackIntervals(toOpId);
+
+            // call walkTo if still in range
+            walkToFixed(State.Active, toOpId);
+            walkToFixed(State.Inactive, toOpId);
+            walkToAny(toOpId);
+        }
+    }
+
+    private void intervalMoved(IntervalHint interval, State from, State to) {
+        // intervalMoved() is called whenever an interval moves from one interval list to another.
+        // In the implementation of this method it is prohibited to move the interval to any list.
+        if (Debug.isLogEnabled()) {
+            Debug.log("interval moved from %s to %s: %s", from, to, interval.logString(allocator));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/TraceLinearScan.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,1045 @@
+/*
+ * Copyright (c) 2009, 2015, 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.alloc.trace.lsra;
+
+import static com.oracle.graal.compiler.common.GraalOptions.DetailedAsserts;
+import static com.oracle.graal.lir.LIRValueUtil.isVariable;
+import static jdk.vm.ci.code.CodeUtil.isEven;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.asRegisterValue;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isLegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.EnumSet;
+import java.util.List;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterAttributes;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.LIRKind;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.options.NestedBooleanOptionValue;
+import jdk.vm.ci.options.Option;
+import jdk.vm.ci.options.OptionType;
+import jdk.vm.ci.options.OptionValue;
+
+import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
+import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
+import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
+import com.oracle.graal.compiler.common.cfg.BlockMap;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.debug.Indent;
+import com.oracle.graal.lir.LIR;
+import com.oracle.graal.lir.LIRInstruction;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.ValueConsumer;
+import com.oracle.graal.lir.Variable;
+import com.oracle.graal.lir.VirtualStackSlot;
+import com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase;
+import com.oracle.graal.lir.alloc.trace.lsra.TraceLinearScanAllocationPhase.TraceLinearScanAllocationContext;
+import com.oracle.graal.lir.framemap.FrameMapBuilder;
+import com.oracle.graal.lir.gen.LIRGenerationResult;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
+import com.oracle.graal.lir.phases.LIRPhase;
+
+/**
+ * An implementation of the linear scan register allocator algorithm described in <a
+ * href="http://doi.acm.org/10.1145/1064979.1064998"
+ * >"Optimized Interval Splitting in a Linear Scan Register Allocator"</a> by Christian Wimmer and
+ * Hanspeter Moessenboeck.
+ */
+public final class TraceLinearScan {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Enable spill position optimization", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LIROptTraceRAEliminateSpillMoves = new NestedBooleanOptionValue(LIRPhase.Options.LIROptimization, true);
+        // @formatter:on
+    }
+
+    private static final TraceLinearScanRegisterAllocationPhase TRACE_LINEAR_SCAN_REGISTER_ALLOCATION_PHASE = new TraceLinearScanRegisterAllocationPhase();
+    private static final TraceLinearScanAssignLocationsPhase TRACE_LINEAR_SCAN_ASSIGN_LOCATIONS_PHASE = new TraceLinearScanAssignLocationsPhase();
+    private static final TraceLinearScanEliminateSpillMovePhase TRACE_LINEAR_SCAN_ELIMINATE_SPILL_MOVE_PHASE = new TraceLinearScanEliminateSpillMovePhase();
+    private static final TraceLinearScanResolveDataFlowPhase TRACE_LINEAR_SCAN_RESOLVE_DATA_FLOW_PHASE = new TraceLinearScanResolveDataFlowPhase();
+    private static final TraceLinearScanLifetimeAnalysisPhase TRACE_LINEAR_SCAN_LIFETIME_ANALYSIS_PHASE = new TraceLinearScanLifetimeAnalysisPhase();
+
+    public static class BlockData {
+
+        /**
+         * Bit map specifying which operands are live upon entry to this block. These are values
+         * used in this block or any of its successors where such value are not defined in this
+         * block. The bit index of an operand is its
+         * {@linkplain TraceLinearScan#operandNumber(Value) operand number}.
+         */
+        public BitSet liveIn;
+
+        /**
+         * Bit map specifying which operands are live upon exit from this block. These are values
+         * used in a successor block that are either defined in this block or were live upon entry
+         * to this block. The bit index of an operand is its
+         * {@linkplain TraceLinearScan#operandNumber(Value) operand number}.
+         */
+        public BitSet liveOut;
+
+        /**
+         * Bit map specifying which operands are used (before being defined) in this block. That is,
+         * these are the values that are live upon entry to the block. The bit index of an operand
+         * is its {@linkplain TraceLinearScan#operandNumber(Value) operand number}.
+         */
+        public BitSet liveGen;
+
+        /**
+         * Bit map specifying which operands are defined/overwritten in this block. The bit index of
+         * an operand is its {@linkplain TraceLinearScan#operandNumber(Value) operand number}.
+         */
+        public BitSet liveKill;
+    }
+
+    public static final int DOMINATOR_SPILL_MOVE_ID = -2;
+    private static final int SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT = 1;
+
+    private final LIR ir;
+    private final FrameMapBuilder frameMapBuilder;
+    private final RegisterAttributes[] registerAttributes;
+    private final Register[] registers;
+    private final RegisterAllocationConfig regAllocConfig;
+    private final MoveFactory moveFactory;
+
+    private final BlockMap<BlockData> blockData;
+
+    /**
+     * List of blocks in linear-scan order. This is only correct as long as the CFG does not change.
+     */
+    private final List<? extends AbstractBlockBase<?>> sortedBlocks;
+
+    /** @see #fixedIntervals() */
+    private final FixedInterval[] fixedIntervals;
+
+    /** @see #intervals() */
+    private TraceInterval[] intervals;
+
+    /**
+     * The number of valid entries in {@link #intervals}.
+     */
+    private int intervalsSize;
+
+    /**
+     * The index of the first entry in {@link #intervals} for a
+     * {@linkplain #createDerivedInterval(TraceInterval) derived interval}.
+     */
+    private int firstDerivedIntervalIndex = -1;
+
+    /**
+     * Intervals sorted by {@link TraceInterval#from()}.
+     */
+    private TraceInterval[] sortedIntervals;
+
+    /**
+     * Fixed intervals sorted by {@link FixedInterval#from()}.
+     */
+    private FixedInterval[] sortedFixedIntervals;
+
+    /**
+     * Map from an instruction {@linkplain LIRInstruction#id id} to the instruction. Entries should
+     * be retrieved with {@link #instructionForId(int)} as the id is not simply an index into this
+     * array.
+     */
+    private LIRInstruction[] opIdToInstructionMap;
+
+    /**
+     * Map from an instruction {@linkplain LIRInstruction#id id} to the
+     * {@linkplain AbstractBlockBase block} containing the instruction. Entries should be retrieved
+     * with {@link #blockForId(int)} as the id is not simply an index into this array.
+     */
+    private AbstractBlockBase<?>[] opIdToBlockMap;
+
+    protected final TraceBuilderResult<?> traceBuilderResult;
+    private final boolean neverSpillConstants;
+
+    public TraceLinearScan(TargetDescription target, LIRGenerationResult res, MoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig, List<? extends AbstractBlockBase<?>> sortedBlocks,
+                    TraceBuilderResult<?> traceBuilderResult, boolean neverSpillConstants) {
+        this.ir = res.getLIR();
+        this.moveFactory = spillMoveFactory;
+        this.frameMapBuilder = res.getFrameMapBuilder();
+        this.sortedBlocks = sortedBlocks;
+        this.registerAttributes = regAllocConfig.getRegisterConfig().getAttributesMap();
+        this.regAllocConfig = regAllocConfig;
+
+        this.registers = target.arch.getRegisters();
+        this.fixedIntervals = new FixedInterval[registers.length];
+        this.blockData = new BlockMap<>(ir.getControlFlowGraph());
+        this.traceBuilderResult = traceBuilderResult;
+        this.neverSpillConstants = neverSpillConstants;
+    }
+
+    public int getFirstLirInstructionId(AbstractBlockBase<?> block) {
+        int result = ir.getLIRforBlock(block).get(0).id();
+        assert result >= 0;
+        return result;
+    }
+
+    public int getLastLirInstructionId(AbstractBlockBase<?> block) {
+        List<LIRInstruction> instructions = ir.getLIRforBlock(block);
+        int result = instructions.get(instructions.size() - 1).id();
+        assert result >= 0;
+        return result;
+    }
+
+    public MoveFactory getSpillMoveFactory() {
+        return moveFactory;
+    }
+
+    protected TraceLocalMoveResolver createMoveResolver() {
+        TraceLocalMoveResolver moveResolver = new TraceLocalMoveResolver(this);
+        assert moveResolver.checkEmpty();
+        return moveResolver;
+    }
+
+    public static boolean isVariableOrRegister(Value value) {
+        return isVariable(value) || isRegister(value);
+    }
+
+    /**
+     * Converts an operand (variable or register) to an index in a flat address space covering all
+     * the {@linkplain Variable variables} and {@linkplain RegisterValue registers} being processed
+     * by this allocator.
+     */
+    @SuppressWarnings("static-method")
+    int operandNumber(Value operand) {
+        assert !isRegister(operand) : "Register do not have operand numbers: " + operand;
+        assert isVariable(operand) : "Unsupported Value " + operand;
+        return ((Variable) operand).index;
+    }
+
+    /**
+     * Gets the number of operands. This value will increase by 1 for new variable.
+     */
+    int operandSize() {
+        return ir.numVariables();
+    }
+
+    /**
+     * Gets the number of registers. This value will never change.
+     */
+    int numRegisters() {
+        return registers.length;
+    }
+
+    public BlockData getBlockData(AbstractBlockBase<?> block) {
+        return blockData.get(block);
+    }
+
+    void initBlockData(AbstractBlockBase<?> block) {
+        blockData.put(block, new BlockData());
+    }
+
+    static final IntervalPredicate IS_PRECOLORED_INTERVAL = new IntervalPredicate() {
+
+        @Override
+        public boolean apply(TraceInterval i) {
+            return isRegister(i.operand);
+        }
+    };
+
+    static final IntervalPredicate IS_VARIABLE_INTERVAL = new IntervalPredicate() {
+
+        @Override
+        public boolean apply(TraceInterval i) {
+            return isVariable(i.operand);
+        }
+    };
+
+    static final IntervalPredicate IS_STACK_INTERVAL = new IntervalPredicate() {
+
+        @Override
+        public boolean apply(TraceInterval i) {
+            return !isRegister(i.operand);
+        }
+    };
+
+    /**
+     * Gets an object describing the attributes of a given register according to this register
+     * configuration.
+     */
+    public RegisterAttributes attributes(Register reg) {
+        return registerAttributes[reg.number];
+    }
+
+    void assignSpillSlot(TraceInterval interval) {
+        /*
+         * Assign the canonical spill slot of the parent (if a part of the interval is already
+         * spilled) or allocate a new spill slot.
+         */
+        if (interval.canMaterialize()) {
+            interval.assignLocation(Value.ILLEGAL);
+        } else if (interval.spillSlot() != null) {
+            interval.assignLocation(interval.spillSlot());
+        } else {
+            VirtualStackSlot slot = frameMapBuilder.allocateSpillSlot(interval.kind());
+            interval.setSpillSlot(slot);
+            interval.assignLocation(slot);
+        }
+    }
+
+    /**
+     * Map from {@linkplain #operandNumber(Value) operand numbers} to intervals.
+     */
+    public TraceInterval[] intervals() {
+        return intervals;
+    }
+
+    /**
+     * Map from {@linkplain #operandNumber(Value) operand numbers} to intervals.
+     */
+    public FixedInterval[] fixedIntervals() {
+        return fixedIntervals;
+    }
+
+    void initIntervals() {
+        intervalsSize = operandSize();
+        intervals = new TraceInterval[intervalsSize + (intervalsSize >> SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT)];
+    }
+
+    /**
+     * Creates a new fixed interval.
+     *
+     * @param reg the operand for the interval
+     * @return the created interval
+     */
+    FixedInterval createFixedInterval(RegisterValue reg) {
+        FixedInterval interval = new FixedInterval(reg);
+        int operandNumber = reg.getRegister().number;
+        assert fixedIntervals[operandNumber] == null;
+        fixedIntervals[operandNumber] = interval;
+        return interval;
+    }
+
+    /**
+     * Creates a new interval.
+     *
+     * @param operand the operand for the interval
+     * @return the created interval
+     */
+    TraceInterval createInterval(AllocatableValue operand) {
+        assert isLegal(operand);
+        int operandNumber = operandNumber(operand);
+        TraceInterval interval = new TraceInterval(operand, operandNumber);
+        assert operandNumber < intervalsSize;
+        assert intervals[operandNumber] == null;
+        intervals[operandNumber] = interval;
+        return interval;
+    }
+
+    /**
+     * Creates an interval as a result of splitting or spilling another interval.
+     *
+     * @param source an interval being split of spilled
+     * @return a new interval derived from {@code source}
+     */
+    TraceInterval createDerivedInterval(TraceInterval source) {
+        if (firstDerivedIntervalIndex == -1) {
+            firstDerivedIntervalIndex = intervalsSize;
+        }
+        if (intervalsSize == intervals.length) {
+            intervals = Arrays.copyOf(intervals, intervals.length + (intervals.length >> SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT));
+        }
+        intervalsSize++;
+        Variable variable = new Variable(source.kind(), ir.nextVariable());
+
+        TraceInterval interval = createInterval(variable);
+        assert intervals[intervalsSize - 1] == interval;
+        return interval;
+    }
+
+    // access to block list (sorted in linear scan order)
+    public int blockCount() {
+        return sortedBlocks.size();
+    }
+
+    public AbstractBlockBase<?> blockAt(int index) {
+        return sortedBlocks.get(index);
+    }
+
+    /**
+     * Gets the size of the {@link BlockData#liveIn} and {@link BlockData#liveOut} sets for a basic
+     * block. These sets do not include any operands allocated as a result of creating
+     * {@linkplain #createDerivedInterval(TraceInterval) derived intervals}.
+     */
+    public int liveSetSize() {
+        return firstDerivedIntervalIndex == -1 ? operandSize() : firstDerivedIntervalIndex;
+    }
+
+    int numLoops() {
+        return ir.getControlFlowGraph().getLoops().size();
+    }
+
+    public FixedInterval fixedIntervalFor(RegisterValue reg) {
+        return fixedIntervals[reg.getRegister().number];
+    }
+
+    public FixedInterval getOrCreateFixedInterval(RegisterValue reg) {
+        FixedInterval ret = fixedIntervalFor(reg);
+        if (ret == null) {
+            return createFixedInterval(reg);
+        } else {
+            return ret;
+        }
+    }
+
+    TraceInterval intervalFor(int operandNumber) {
+        return intervals[operandNumber];
+    }
+
+    public TraceInterval intervalFor(Value operand) {
+        int operandNumber = operandNumber(operand);
+        assert operandNumber < intervalsSize;
+        return intervals[operandNumber];
+    }
+
+    public TraceInterval getOrCreateInterval(AllocatableValue operand) {
+        TraceInterval ret = intervalFor(operand);
+        if (ret == null) {
+            return createInterval(operand);
+        } else {
+            return ret;
+        }
+    }
+
+    void initOpIdMaps(int numInstructions) {
+        opIdToInstructionMap = new LIRInstruction[numInstructions];
+        opIdToBlockMap = new AbstractBlockBase<?>[numInstructions];
+    }
+
+    void putOpIdMaps(int index, LIRInstruction op, AbstractBlockBase<?> block) {
+        opIdToInstructionMap[index] = op;
+        opIdToBlockMap[index] = block;
+    }
+
+    /**
+     * Gets the highest instruction id allocated by this object.
+     */
+    int maxOpId() {
+        assert opIdToInstructionMap.length > 0 : "no operations";
+        return (opIdToInstructionMap.length - 1) << 1;
+    }
+
+    /**
+     * Converts an {@linkplain LIRInstruction#id instruction id} to an instruction index. All LIR
+     * instructions in a method have an index one greater than their linear-scan order predecessor
+     * with the first instruction having an index of 0.
+     */
+    private static int opIdToIndex(int opId) {
+        return opId >> 1;
+    }
+
+    /**
+     * Retrieves the {@link LIRInstruction} based on its {@linkplain LIRInstruction#id id}.
+     *
+     * @param opId an instruction {@linkplain LIRInstruction#id id}
+     * @return the instruction whose {@linkplain LIRInstruction#id} {@code == id}
+     */
+    public LIRInstruction instructionForId(int opId) {
+        assert isEven(opId) : "opId not even";
+        LIRInstruction instr = opIdToInstructionMap[opIdToIndex(opId)];
+        assert instr.id() == opId;
+        return instr;
+    }
+
+    /**
+     * Gets the block containing a given instruction.
+     *
+     * @param opId an instruction {@linkplain LIRInstruction#id id}
+     * @return the block containing the instruction denoted by {@code opId}
+     */
+    public AbstractBlockBase<?> blockForId(int opId) {
+        assert opIdToBlockMap.length > 0 && opId >= 0 && opId <= maxOpId() + 1 : "opId out of range: " + opId;
+        return opIdToBlockMap[opIdToIndex(opId)];
+    }
+
+    boolean isBlockBegin(int opId) {
+        return opId == 0 || blockForId(opId) != blockForId(opId - 1);
+    }
+
+    boolean isBlockEnd(int opId) {
+        boolean isBlockBegin = isBlockBegin(opId + 2);
+        assert isBlockBegin == (instructionForId(opId & (~1)) instanceof BlockEndOp);
+        return isBlockBegin;
+    }
+
+    boolean coversBlockBegin(int opId1, int opId2) {
+        return blockForId(opId1) != blockForId(opId2);
+    }
+
+    /**
+     * Determines if an {@link LIRInstruction} destroys all caller saved registers.
+     *
+     * @param opId an instruction {@linkplain LIRInstruction#id id}
+     * @return {@code true} if the instruction denoted by {@code id} destroys all caller saved
+     *         registers.
+     */
+    boolean hasCall(int opId) {
+        assert isEven(opId) : "opId not even";
+        return instructionForId(opId).destroysCallerSavedRegisters();
+    }
+
+    abstract static class IntervalPredicate {
+
+        abstract boolean apply(TraceInterval i);
+    }
+
+    public boolean isProcessed(Value operand) {
+        return !isRegister(operand) || attributes(asRegister(operand)).isAllocatable();
+    }
+
+    // * Phase 5: actual register allocation
+
+    private static <T extends IntervalHint> boolean isSortedByFrom(T[] intervals) {
+        int from = -1;
+        for (T interval : intervals) {
+            assert interval != null;
+            assert from <= interval.from();
+            from = interval.from();
+        }
+        return true;
+    }
+
+    private static boolean isSortedBySpillPos(TraceInterval[] intervals) {
+        int from = -1;
+        for (TraceInterval interval : intervals) {
+            assert interval != null;
+            assert from <= interval.spillDefinitionPos();
+            from = interval.spillDefinitionPos();
+        }
+        return true;
+    }
+
+    private static TraceInterval addToList(TraceInterval first, TraceInterval prev, TraceInterval interval) {
+        TraceInterval newFirst = first;
+        if (prev != null) {
+            prev.next = interval;
+        } else {
+            newFirst = interval;
+        }
+        return newFirst;
+    }
+
+    TraceInterval createUnhandledListByFrom(IntervalPredicate isList1) {
+        assert isSortedByFrom(sortedIntervals) : "interval list is not sorted";
+        return createUnhandledList(isList1);
+    }
+
+    TraceInterval createUnhandledListBySpillPos(IntervalPredicate isList1) {
+        assert isSortedBySpillPos(sortedIntervals) : "interval list is not sorted";
+        return createUnhandledList(isList1);
+    }
+
+    private TraceInterval createUnhandledList(IntervalPredicate isList1) {
+
+        TraceInterval list1 = TraceInterval.EndMarker;
+
+        TraceInterval list1Prev = null;
+        TraceInterval v;
+
+        int n = sortedIntervals.length;
+        for (int i = 0; i < n; i++) {
+            v = sortedIntervals[i];
+            if (v == null) {
+                continue;
+            }
+
+            if (isList1.apply(v)) {
+                list1 = addToList(list1, list1Prev, v);
+                list1Prev = v;
+            }
+        }
+
+        if (list1Prev != null) {
+            list1Prev.next = TraceInterval.EndMarker;
+        }
+
+        assert list1Prev == null || list1Prev.next == TraceInterval.EndMarker : "linear list ends not with sentinel";
+
+        return list1;
+    }
+
+    private static FixedInterval addToList(FixedInterval first, FixedInterval prev, FixedInterval interval) {
+        FixedInterval newFirst = first;
+        if (prev != null) {
+            prev.next = interval;
+        } else {
+            newFirst = interval;
+        }
+        return newFirst;
+    }
+
+    FixedInterval createFixedUnhandledList() {
+        assert isSortedByFrom(sortedFixedIntervals) : "interval list is not sorted";
+
+        FixedInterval list1 = FixedInterval.EndMarker;
+
+        FixedInterval list1Prev = null;
+        FixedInterval v;
+
+        int n = sortedFixedIntervals.length;
+        for (int i = 0; i < n; i++) {
+            v = sortedFixedIntervals[i];
+            if (v == null) {
+                continue;
+            }
+
+            v.rewindRange();
+            list1 = addToList(list1, list1Prev, v);
+            list1Prev = v;
+        }
+
+        if (list1Prev != null) {
+            list1Prev.next = FixedInterval.EndMarker;
+        }
+
+        assert list1Prev == null || list1Prev.next == FixedInterval.EndMarker : "linear list ends not with sentinel";
+
+        return list1;
+    }
+
+    // SORTING
+
+    protected void sortIntervalsBeforeAllocation() {
+        int sortedLen = 0;
+        for (TraceInterval interval : intervals) {
+            if (interval != null) {
+                sortedLen++;
+            }
+        }
+        sortedIntervals = sortIntervalsBeforeAllocation(intervals, new TraceInterval[sortedLen]);
+    }
+
+    protected void sortFixedIntervalsBeforeAllocation() {
+        int sortedLen = 0;
+        for (FixedInterval interval : fixedIntervals) {
+            if (interval != null) {
+                sortedLen++;
+            }
+        }
+        sortedFixedIntervals = sortIntervalsBeforeAllocation(fixedIntervals, new FixedInterval[sortedLen]);
+    }
+
+    private static <T extends IntervalHint> T[] sortIntervalsBeforeAllocation(T[] intervals, T[] sortedList) {
+        int sortedIdx = 0;
+        int sortedFromMax = -1;
+
+        // special sorting algorithm: the original interval-list is almost sorted,
+        // only some intervals are swapped. So this is much faster than a complete QuickSort
+        for (T interval : intervals) {
+            if (interval != null) {
+                int from = interval.from();
+
+                if (sortedFromMax <= from) {
+                    sortedList[sortedIdx++] = interval;
+                    sortedFromMax = interval.from();
+                } else {
+                    // the assumption that the intervals are already sorted failed,
+                    // so this interval must be sorted in manually
+                    int j;
+                    for (j = sortedIdx - 1; j >= 0 && from < sortedList[j].from(); j--) {
+                        sortedList[j + 1] = sortedList[j];
+                    }
+                    sortedList[j + 1] = interval;
+                    sortedIdx++;
+                }
+            }
+        }
+        return sortedList;
+    }
+
+    void sortIntervalsAfterAllocation() {
+        if (firstDerivedIntervalIndex == -1) {
+            // no intervals have been added during allocation, so sorted list is already up to date
+            return;
+        }
+
+        TraceInterval[] oldList = sortedIntervals;
+        TraceInterval[] newList = Arrays.copyOfRange(intervals, firstDerivedIntervalIndex, intervalsSize);
+        int oldLen = oldList.length;
+        int newLen = newList.length;
+
+        // conventional sort-algorithm for new intervals
+        Arrays.sort(newList, (TraceInterval a, TraceInterval b) -> a.from() - b.from());
+
+        // merge old and new list (both already sorted) into one combined list
+        TraceInterval[] combinedList = new TraceInterval[oldLen + newLen];
+        int oldIdx = 0;
+        int newIdx = 0;
+
+        while (oldIdx + newIdx < combinedList.length) {
+            if (newIdx >= newLen || (oldIdx < oldLen && oldList[oldIdx].from() <= newList[newIdx].from())) {
+                combinedList[oldIdx + newIdx] = oldList[oldIdx];
+                oldIdx++;
+            } else {
+                combinedList[oldIdx + newIdx] = newList[newIdx];
+                newIdx++;
+            }
+        }
+
+        sortedIntervals = combinedList;
+    }
+
+    void sortIntervalsBySpillPos() {
+        // TODO (JE): better algorithm?
+        // conventional sort-algorithm for new intervals
+        Arrays.sort(sortedIntervals, (TraceInterval a, TraceInterval b) -> a.spillDefinitionPos() - b.spillDefinitionPos());
+    }
+
+    // wrapper for Interval.splitChildAtOpId that performs a bailout in product mode
+    // instead of returning null
+    public TraceInterval splitChildAtOpId(TraceInterval interval, int opId, LIRInstruction.OperandMode mode) {
+        TraceInterval result = interval.getSplitChildAtOpId(opId, mode, this);
+
+        if (result != null) {
+            if (Debug.isLogEnabled()) {
+                Debug.log("Split child at pos %d of interval %s is %s", opId, interval, result);
+            }
+            return result;
+        }
+
+        throw new BailoutException("LinearScan: interval is null");
+    }
+
+    static AllocatableValue canonicalSpillOpr(TraceInterval interval) {
+        assert interval.spillSlot() != null : "canonical spill slot not set";
+        return interval.spillSlot();
+    }
+
+    boolean isMaterialized(AllocatableValue operand, int opId, OperandMode mode) {
+        TraceInterval interval = intervalFor(operand);
+        assert interval != null : "interval must exist";
+
+        if (opId != -1) {
+            /*
+             * Operands are not changed when an interval is split during allocation, so search the
+             * right interval here.
+             */
+            interval = splitChildAtOpId(interval, opId, mode);
+        }
+
+        return isIllegal(interval.location()) && interval.canMaterialize();
+    }
+
+    boolean isCallerSave(Value operand) {
+        return attributes(asRegister(operand)).isCallerSave();
+    }
+
+    @SuppressWarnings("try")
+    public <B extends AbstractBlockBase<B>> void allocate(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
+                    RegisterAllocationConfig registerAllocationConfig) {
+
+        /*
+         * This is the point to enable debug logging for the whole register allocation.
+         */
+        try (Indent indent = Debug.logAndIndent("LinearScan allocate")) {
+            TraceLinearScanAllocationContext context = new TraceLinearScanAllocationContext(spillMoveFactory, registerAllocationConfig, traceBuilderResult, this);
+
+            TRACE_LINEAR_SCAN_LIFETIME_ANALYSIS_PHASE.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
+
+            try (Scope s = Debug.scope("AfterLifetimeAnalysis", (Object) intervals())) {
+                sortIntervalsBeforeAllocation();
+                sortFixedIntervalsBeforeAllocation();
+
+                TRACE_LINEAR_SCAN_REGISTER_ALLOCATION_PHASE.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
+
+                // resolve intra-trace data-flow
+                TRACE_LINEAR_SCAN_RESOLVE_DATA_FLOW_PHASE.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
+                Debug.dump(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL, sortedBlocks(), "%s", TRACE_LINEAR_SCAN_RESOLVE_DATA_FLOW_PHASE.getName());
+
+                // eliminate spill moves
+                if (Options.LIROptTraceRAEliminateSpillMoves.getValue()) {
+                    TRACE_LINEAR_SCAN_ELIMINATE_SPILL_MOVE_PHASE.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
+                    Debug.dump(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL, sortedBlocks(), "%s", TRACE_LINEAR_SCAN_ELIMINATE_SPILL_MOVE_PHASE.getName());
+                }
+
+                TRACE_LINEAR_SCAN_ASSIGN_LOCATIONS_PHASE.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false);
+
+                if (DetailedAsserts.getValue()) {
+                    verifyIntervals();
+                }
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        }
+    }
+
+    @SuppressWarnings("try")
+    public void printIntervals(String label) {
+        if (Debug.isDumpEnabled(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL)) {
+            if (Debug.isLogEnabled()) {
+                try (Indent indent = Debug.logAndIndent("intervals %s", label)) {
+                    for (FixedInterval interval : fixedIntervals) {
+                        if (interval != null) {
+                            Debug.log("%s", interval.logString(this));
+                        }
+                    }
+
+                    for (TraceInterval interval : intervals) {
+                        if (interval != null) {
+                            Debug.log("%s", interval.logString(this));
+                        }
+                    }
+
+                    try (Indent indent2 = Debug.logAndIndent("Basic Blocks")) {
+                        for (int i = 0; i < blockCount(); i++) {
+                            AbstractBlockBase<?> block = blockAt(i);
+                            Debug.log("B%d [%d, %d, %s] ", block.getId(), getFirstLirInstructionId(block), getLastLirInstructionId(block), block.getLoop());
+                        }
+                    }
+                }
+            }
+            Debug.dump(new TraceIntervalDumper(Arrays.copyOf(fixedIntervals, fixedIntervals.length), Arrays.copyOf(intervals, intervalsSize)), label);
+        }
+    }
+
+    public void printLir(String label, @SuppressWarnings("unused") boolean hirValid) {
+        if (Debug.isDumpEnabled(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL)) {
+            Debug.dump(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL, sortedBlocks(), label);
+        }
+    }
+
+    boolean verify() {
+        // (check that all intervals have a correct register and that no registers are overwritten)
+        verifyIntervals();
+
+        verifyRegisters();
+
+        Debug.log("no errors found");
+
+        return true;
+    }
+
+    @SuppressWarnings("try")
+    private void verifyRegisters() {
+        // Enable this logging to get output for the verification process.
+        try (Indent indent = Debug.logAndIndent("verifying register allocation")) {
+            RegisterVerifier verifier = new RegisterVerifier(this);
+            verifier.verify(blockAt(0));
+        }
+    }
+
+    @SuppressWarnings("try")
+    protected void verifyIntervals() {
+        try (Indent indent = Debug.logAndIndent("verifying intervals")) {
+            int len = intervalsSize;
+
+            for (int i = 0; i < len; i++) {
+                final TraceInterval i1 = intervals[i];
+                if (i1 == null) {
+                    continue;
+                }
+
+                i1.checkSplitChildren();
+
+                if (i1.operandNumber != i) {
+                    Debug.log("Interval %d is on position %d in list", i1.operandNumber, i);
+                    Debug.log(i1.logString(this));
+                    throw new JVMCIError("");
+                }
+
+                if (isVariable(i1.operand) && i1.kind().equals(LIRKind.Illegal)) {
+                    Debug.log("Interval %d has no type assigned", i1.operandNumber);
+                    Debug.log(i1.logString(this));
+                    throw new JVMCIError("");
+                }
+
+                if (i1.location() == null) {
+                    Debug.log("Interval %d has no register assigned", i1.operandNumber);
+                    Debug.log(i1.logString(this));
+                    throw new JVMCIError("");
+                }
+
+                if (i1.isEmpty()) {
+                    Debug.log("Interval %d has no Range", i1.operandNumber);
+                    Debug.log(i1.logString(this));
+                    throw new JVMCIError("");
+                }
+
+                if (i1.from() >= i1.to()) {
+                    Debug.log("Interval %d has zero length range", i1.operandNumber);
+                    Debug.log(i1.logString(this));
+                    throw new JVMCIError("");
+                }
+
+                // special intervals that are created in MoveResolver
+                // . ignore them because the range information has no meaning there
+                if (i1.from() == 1 && i1.to() == 2) {
+                    continue;
+                }
+                // check any intervals
+                for (int j = i + 1; j < len; j++) {
+                    final TraceInterval i2 = intervals[j];
+                    if (i2 == null) {
+                        continue;
+                    }
+
+                    // special intervals that are created in MoveResolver
+                    // . ignore them because the range information has no meaning there
+                    if (i2.from() == 1 && i2.to() == 2) {
+                        continue;
+                    }
+                    Value l1 = i1.location();
+                    Value l2 = i2.location();
+                    boolean intersects = i1.intersects(i2);
+                    if (intersects && !isIllegal(l1) && (l1.equals(l2))) {
+                        if (DetailedAsserts.getValue()) {
+                            Debug.log("Intervals %s and %s overlap and have the same register assigned", i1, i2);
+                            Debug.log(i1.logString(this));
+                            Debug.log(i2.logString(this));
+                        }
+                        throw new BailoutException("");
+                    }
+                }
+                // check fixed intervals
+                for (FixedInterval i2 : fixedIntervals) {
+                    if (i2 == null) {
+                        continue;
+                    }
+
+                    Value l1 = i1.location();
+                    Value l2 = i2.location();
+                    boolean intersects = i2.intersects(i1);
+                    if (intersects && !isIllegal(l1) && (l1.equals(l2))) {
+                        if (DetailedAsserts.getValue()) {
+                            Debug.log("Intervals %s and %s overlap and have the same register assigned", i1, i2);
+                            Debug.log(i1.logString(this));
+                            Debug.log(i2.logString(this));
+                        }
+                        throw new BailoutException("");
+                    }
+                }
+            }
+        }
+    }
+
+    class CheckConsumer implements ValueConsumer {
+
+        boolean ok;
+        FixedInterval curInterval;
+
+        @Override
+        public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+            if (isRegister(operand)) {
+                if (fixedIntervalFor(asRegisterValue(operand)) == curInterval) {
+                    ok = true;
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("try")
+    void verifyNoOopsInFixedIntervals() {
+        try (Indent indent = Debug.logAndIndent("verifying that no oops are in fixed intervals *")) {
+            CheckConsumer checkConsumer = new CheckConsumer();
+
+            TraceInterval otherIntervals;
+            FixedInterval fixedInts = createFixedUnhandledList();
+            // to ensure a walking until the last instruction id, add a dummy interval
+            // with a high operation id
+            otherIntervals = new TraceInterval(Value.ILLEGAL, -1);
+            otherIntervals.addRange(Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1);
+            TraceIntervalWalker iw = new TraceIntervalWalker(this, fixedInts, otherIntervals);
+
+            for (AbstractBlockBase<?> block : sortedBlocks) {
+                List<LIRInstruction> instructions = ir.getLIRforBlock(block);
+
+                for (int j = 0; j < instructions.size(); j++) {
+                    LIRInstruction op = instructions.get(j);
+
+                    if (op.hasState()) {
+                        iw.walkBefore(op.id());
+                        boolean checkLive = true;
+
+                        /*
+                         * Make sure none of the fixed registers is live across an oopmap since we
+                         * can't handle that correctly.
+                         */
+                        if (checkLive) {
+                            for (FixedInterval interval = iw.activeFixedList.getFixed(); interval != FixedInterval.EndMarker; interval = interval.next) {
+                                if (interval.to() > op.id() + 1) {
+                                    /*
+                                     * This interval is live out of this op so make sure that this
+                                     * interval represents some value that's referenced by this op
+                                     * either as an input or output.
+                                     */
+                                    checkConsumer.curInterval = interval;
+                                    checkConsumer.ok = false;
+
+                                    op.visitEachInput(checkConsumer);
+                                    op.visitEachAlive(checkConsumer);
+                                    op.visitEachTemp(checkConsumer);
+                                    op.visitEachOutput(checkConsumer);
+
+                                    assert checkConsumer.ok : "fixed intervals should never be live across an oopmap point";
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public LIR getLIR() {
+        return ir;
+    }
+
+    public FrameMapBuilder getFrameMapBuilder() {
+        return frameMapBuilder;
+    }
+
+    public List<? extends AbstractBlockBase<?>> sortedBlocks() {
+        return sortedBlocks;
+    }
+
+    public Register[] getRegisters() {
+        return registers;
+    }
+
+    public RegisterAllocationConfig getRegisterAllocationConfig() {
+        return regAllocConfig;
+    }
+
+    public boolean callKillsRegisters() {
+        return regAllocConfig.getRegisterConfig().areAllAllocatableRegistersCallerSaved();
+    }
+
+    boolean neverSpillConstants() {
+        return neverSpillConstants;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/TraceLinearScanAllocationPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, 2015, 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.alloc.trace.lsra;
+
+import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
+import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
+import com.oracle.graal.lir.phases.LIRPhase;
+
+abstract class TraceLinearScanAllocationPhase extends LIRPhase<TraceLinearScanAllocationPhase.TraceLinearScanAllocationContext> {
+
+    static final class TraceLinearScanAllocationContext {
+        public final MoveFactory spillMoveFactory;
+        public final RegisterAllocationConfig registerAllocationConfig;
+        public final TraceBuilderResult<?> traceBuilderResult;
+        public final TraceLinearScan allocator;
+
+        TraceLinearScanAllocationContext(MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig, TraceBuilderResult<?> traceBuilderResult, TraceLinearScan allocator) {
+            this.spillMoveFactory = spillMoveFactory;
+            this.registerAllocationConfig = registerAllocationConfig;
+            this.traceBuilderResult = traceBuilderResult;
+            this.allocator = allocator;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/TraceLinearScanAssignLocationsPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2015, 2015, 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.alloc.trace.lsra;
+
+import static com.oracle.graal.compiler.common.GraalOptions.DetailedAsserts;
+import static com.oracle.graal.lir.LIRValueUtil.isConstantValue;
+import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
+import static com.oracle.graal.lir.LIRValueUtil.isVariable;
+import static com.oracle.graal.lir.LIRValueUtil.isVirtualStackSlot;
+import static com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase.Options.TraceRAshareSpillInformation;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
+
+import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.Indent;
+import com.oracle.graal.lir.ConstantValue;
+import com.oracle.graal.lir.InstructionValueProcedure;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.LIRInstruction;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.StandardOp;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.StandardOp.ValueMoveOp;
+import com.oracle.graal.lir.Variable;
+import com.oracle.graal.lir.alloc.trace.ShadowedRegisterValue;
+import com.oracle.graal.lir.gen.LIRGenerationResult;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
+
+/**
+ * Specialization of {@link com.oracle.graal.lir.alloc.lsra.LinearScanAssignLocationsPhase} that
+ * inserts {@link ShadowedRegisterValue}s to describe {@link RegisterValue}s that are also available
+ * on the {@link StackSlot stack}.
+ */
+final class TraceLinearScanAssignLocationsPhase extends TraceLinearScanAllocationPhase {
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    TraceLinearScanAllocationContext context) {
+        TraceLinearScan allocator = context.allocator;
+        MoveFactory spillMoveFactory = context.spillMoveFactory;
+        new Assigner(allocator, spillMoveFactory).assignLocations();
+    }
+
+    private static final class Assigner {
+        private final TraceLinearScan allocator;
+        private final MoveFactory spillMoveFactory;
+
+        private Assigner(TraceLinearScan allocator, MoveFactory spillMoveFactory) {
+            this.allocator = allocator;
+            this.spillMoveFactory = spillMoveFactory;
+        }
+
+        /**
+         * Assigns the allocated location for an LIR instruction operand back into the instruction.
+         *
+         * @param op current {@link LIRInstruction}
+         * @param operand an LIR instruction operand
+         * @param mode the usage mode for {@code operand} by the instruction
+         * @return the location assigned for the operand
+         */
+        private Value colorLirOperand(LIRInstruction op, Variable operand, OperandMode mode) {
+            int opId = op.id();
+            TraceInterval interval = allocator.intervalFor(operand);
+            assert interval != null : "interval must exist";
+
+            if (opId != -1) {
+                if (DetailedAsserts.getValue()) {
+                    AbstractBlockBase<?> block = allocator.blockForId(opId);
+                    if (block.getSuccessorCount() <= 1 && opId == allocator.getLastLirInstructionId(block)) {
+                        /*
+                         * Check if spill moves could have been appended at the end of this block,
+                         * but before the branch instruction. So the split child information for
+                         * this branch would be incorrect.
+                         */
+                        LIRInstruction instr = allocator.getLIR().getLIRforBlock(block).get(allocator.getLIR().getLIRforBlock(block).size() - 1);
+                        if (instr instanceof StandardOp.JumpOp) {
+                            if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) {
+                                assert false : String.format(
+                                                "can't get split child for the last branch of a block because the information would be incorrect (moves are inserted before the branch in resolveDataFlow) block=%s, instruction=%s, operand=%s",
+                                                block, instr, operand);
+                            }
+                        }
+                    }
+                }
+
+                /*
+                 * Operands are not changed when an interval is split during allocation, so search
+                 * the right interval here.
+                 */
+                interval = allocator.splitChildAtOpId(interval, opId, mode);
+            }
+
+            if (isIllegal(interval.location()) && interval.canMaterialize()) {
+                assert mode != OperandMode.DEF;
+                return new ConstantValue(interval.kind(), interval.getMaterializedValue());
+            }
+            return interval.location();
+        }
+
+        /**
+         * @param op
+         * @param operand
+         * @param valueMode
+         * @param flags
+         * @see InstructionValueProcedure#doValue(LIRInstruction, Value, OperandMode, EnumSet)
+         */
+        private Value debugInfoProcedure(LIRInstruction op, Value operand, OperandMode valueMode, EnumSet<OperandFlag> flags) {
+            if (isVirtualStackSlot(operand)) {
+                return operand;
+            }
+            int tempOpId = op.id();
+            OperandMode mode = OperandMode.USE;
+            AbstractBlockBase<?> block = allocator.blockForId(tempOpId);
+            if (block.getSuccessorCount() == 1 && tempOpId == allocator.getLastLirInstructionId(block)) {
+                /*
+                 * Generating debug information for the last instruction of a block. If this
+                 * instruction is a branch, spill moves are inserted before this branch and so the
+                 * wrong operand would be returned (spill moves at block boundaries are not
+                 * considered in the live ranges of intervals).
+                 *
+                 * Solution: use the first opId of the branch target block instead.
+                 */
+                final LIRInstruction instr = allocator.getLIR().getLIRforBlock(block).get(allocator.getLIR().getLIRforBlock(block).size() - 1);
+                if (instr instanceof StandardOp.JumpOp) {
+                    if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) {
+                        tempOpId = allocator.getFirstLirInstructionId(block.getSuccessors().iterator().next());
+                        mode = OperandMode.DEF;
+                    }
+                }
+            }
+
+            /*
+             * Get current location of operand. The operand must be live because debug information
+             * is considered when building the intervals if the interval is not live,
+             * colorLirOperand will cause an assert on failure.
+             */
+            Value result = colorLirOperand(op, (Variable) operand, mode);
+            assert !allocator.hasCall(tempOpId) || isStackSlotValue(result) || isConstantValue(result) || !allocator.isCallerSave(result) : "cannot have caller-save register operands at calls";
+            return result;
+        }
+
+        private void computeDebugInfo(final LIRInstruction op, LIRFrameState info) {
+            info.forEachState(op, this::debugInfoProcedure);
+        }
+
+        private void assignLocations(List<LIRInstruction> instructions) {
+            int numInst = instructions.size();
+            boolean hasDead = false;
+
+            for (int j = 0; j < numInst; j++) {
+                final LIRInstruction op = instructions.get(j);
+                if (op == null) {
+                    /*
+                     * this can happen when spill-moves are removed in eliminateSpillMoves
+                     */
+                    hasDead = true;
+                } else if (assignLocations(op, instructions, j)) {
+                    hasDead = true;
+                }
+            }
+
+            if (hasDead) {
+                // Remove null values from the list.
+                instructions.removeAll(Collections.singleton(null));
+            }
+        }
+
+        /**
+         * Assigns the operand of an {@link LIRInstruction}.
+         *
+         * @param op The {@link LIRInstruction} that should be colored.
+         * @param j The index of {@code op} in the {@code instructions} list.
+         * @param instructions The instructions of the current block.
+         * @return {@code true} if the instruction was deleted.
+         */
+        private boolean assignLocations(LIRInstruction op, List<LIRInstruction> instructions, int j) {
+            assert op != null && instructions.get(j) == op;
+            if (TraceRAshareSpillInformation.getValue()) {
+                if (op instanceof BlockEndOp) {
+                    ((BlockEndOp) op).forEachOutgoingValue(colorOutgoingIncomingValues);
+                } else if (op instanceof LabelOp) {
+                    ((LabelOp) op).forEachIncomingValue(colorOutgoingIncomingValues);
+                }
+            }
+
+            InstructionValueProcedure assignProc = (inst, operand, mode, flags) -> isVariable(operand) ? colorLirOperand(inst, (Variable) operand, mode) : operand;
+            // remove useless moves
+            if (op instanceof MoveOp) {
+                AllocatableValue result = ((MoveOp) op).getResult();
+                if (isVariable(result) && allocator.isMaterialized(result, op.id(), OperandMode.DEF)) {
+                    /*
+                     * This happens if a materializable interval is originally not spilled but then
+                     * kicked out in LinearScanWalker.splitForSpilling(). When kicking out such an
+                     * interval this move operation was already generated.
+                     */
+                    instructions.set(j, null);
+                    return true;
+                }
+            }
+
+            op.forEachInput(assignProc);
+            op.forEachAlive(assignProc);
+            op.forEachTemp(assignProc);
+            op.forEachOutput(assignProc);
+
+            // compute reference map and debug information
+            op.forEachState((inst, state) -> computeDebugInfo(inst, state));
+
+            // remove useless moves
+            if (op instanceof ValueMoveOp) {
+                ValueMoveOp move = (ValueMoveOp) op;
+                if (move.getInput().equals(move.getResult())) {
+                    instructions.set(j, null);
+                    return true;
+                }
+                if (isStackSlotValue(move.getInput()) && isStackSlotValue(move.getResult())) {
+                    // rewrite stack to stack moves
+                    instructions.set(j, spillMoveFactory.createStackMove(move.getResult(), move.getInput()));
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @SuppressWarnings("try")
+        private void assignLocations() {
+            try (Indent indent = Debug.logAndIndent("assign locations")) {
+                for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+                    try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) {
+                        assignLocations(allocator.getLIR().getLIRforBlock(block));
+                    }
+                }
+            }
+        }
+
+        private InstructionValueProcedure colorOutgoingIncomingValues = new InstructionValueProcedure() {
+
+            public Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (isVariable(value)) {
+                    TraceInterval interval = allocator.intervalFor(value);
+                    assert interval != null : "interval must exist";
+                    interval = allocator.splitChildAtOpId(interval, instruction.id(), mode);
+
+                    if (interval.inMemoryAt(instruction.id()) && isRegister(interval.location())) {
+                        return new ShadowedRegisterValue((RegisterValue) interval.location(), interval.spillSlot());
+                    }
+                }
+                return value;
+            }
+        };
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/TraceLinearScanEliminateSpillMovePhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2015, 2015, 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.alloc.trace.lsra;
+
+import static com.oracle.graal.compiler.common.GraalOptions.DetailedAsserts;
+import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
+import static com.oracle.graal.lir.LIRValueUtil.isVariable;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.List;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.AllocatableValue;
+
+import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
+import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.Indent;
+import com.oracle.graal.lir.LIRInsertionBuffer;
+import com.oracle.graal.lir.LIRInstruction;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.StandardOp.LoadConstantOp;
+import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.StandardOp.ValueMoveOp;
+import com.oracle.graal.lir.alloc.trace.lsra.TraceInterval.SpillState;
+import com.oracle.graal.lir.alloc.trace.lsra.TraceLinearScan.IntervalPredicate;
+import com.oracle.graal.lir.gen.LIRGenerationResult;
+
+final class TraceLinearScanEliminateSpillMovePhase extends TraceLinearScanAllocationPhase {
+
+    private static final IntervalPredicate spilledIntervals = new TraceLinearScan.IntervalPredicate() {
+
+        @Override
+        public boolean apply(TraceInterval i) {
+            return i.isSplitParent() && SpillState.IN_MEMORY.contains(i.spillState());
+        }
+    };
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    TraceLinearScanAllocationContext context) {
+        TraceBuilderResult<?> traceBuilderResult = context.traceBuilderResult;
+        TraceLinearScan allocator = context.allocator;
+        boolean shouldEliminateSpillMoves = shouldEliminateSpillMoves(traceBuilderResult, allocator);
+        eliminateSpillMoves(allocator, shouldEliminateSpillMoves, traceBuilderResult);
+    }
+
+    private static boolean shouldEliminateSpillMoves(TraceBuilderResult<?> traceBuilderResult, TraceLinearScan allocator) {
+        return !traceBuilderResult.incomingSideEdges(traceBuilderResult.getTraceForBlock(allocator.sortedBlocks().get(0)));
+    }
+
+    // called once before assignment of register numbers
+    @SuppressWarnings("try")
+    private static void eliminateSpillMoves(TraceLinearScan allocator, boolean shouldEliminateSpillMoves, TraceBuilderResult<?> traceBuilderResult) {
+        try (Indent indent = Debug.logAndIndent("Eliminating unnecessary spill moves: Trace%d", traceBuilderResult.getTraceForBlock(allocator.sortedBlocks().get(0)))) {
+            allocator.sortIntervalsBySpillPos();
+
+            /*
+             * collect all intervals that must be stored after their definition. The list is sorted
+             * by Interval.spillDefinitionPos.
+             */
+            TraceInterval interval = allocator.createUnhandledListBySpillPos(spilledIntervals);
+            if (DetailedAsserts.getValue()) {
+                checkIntervals(interval);
+            }
+            if (Debug.isLogEnabled()) {
+                try (Indent indent2 = Debug.logAndIndent("Sorted intervals")) {
+                    for (TraceInterval i = interval; i != null; i = i.next) {
+                        Debug.log("%5d: %s", i.spillDefinitionPos(), i);
+                    }
+                }
+            }
+
+            LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer();
+            for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+                try (Indent indent1 = Debug.logAndIndent("Handle %s", block)) {
+                    List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
+                    int numInst = instructions.size();
+
+                    int lastOpId = -1;
+                    // iterate all instructions of the block.
+                    for (int j = 0; j < numInst; j++) {
+                        LIRInstruction op = instructions.get(j);
+                        int opId = op.id();
+                        try (Indent indent2 = Debug.logAndIndent("%5d %s", opId, op)) {
+
+                            if (opId == -1) {
+                                MoveOp move = (MoveOp) op;
+                                /*
+                                 * Remove move from register to stack if the stack slot is
+                                 * guaranteed to be correct. Only moves that have been inserted by
+                                 * LinearScan can be removed.
+                                 */
+                                if (shouldEliminateSpillMoves && canEliminateSpillMove(allocator, block, move, lastOpId)) {
+                                    /*
+                                     * Move target is a stack slot that is always correct, so
+                                     * eliminate instruction.
+                                     */
+                                    if (Debug.isLogEnabled()) {
+                                        if (move instanceof ValueMoveOp) {
+                                            ValueMoveOp vmove = (ValueMoveOp) move;
+                                            Debug.log("eliminating move from interval %d (%s) to %d (%s) in block %s", allocator.operandNumber(vmove.getInput()), vmove.getInput(),
+                                                            allocator.operandNumber(vmove.getResult()), vmove.getResult(), block);
+                                        } else {
+                                            LoadConstantOp load = (LoadConstantOp) move;
+                                            Debug.log("eliminating constant load from %s to %d (%s) in block %s", load.getConstant(), allocator.operandNumber(load.getResult()), load.getResult(),
+                                                            block);
+                                        }
+                                    }
+
+                                    // null-instructions are deleted by assignRegNum
+                                    instructions.set(j, null);
+                                }
+
+                            } else {
+                                lastOpId = opId;
+                                /*
+                                 * Insert move from register to stack just after the beginning of
+                                 * the interval.
+                                 */
+                                // assert interval == TraceInterval.EndMarker ||
+                                // interval.spillDefinitionPos() >= opId : "invalid order";
+                                assert interval == TraceInterval.EndMarker || (interval.isSplitParent() && SpillState.IN_MEMORY.contains(interval.spillState())) : "invalid interval";
+
+                                while (interval != TraceInterval.EndMarker && interval.spillDefinitionPos() == opId) {
+                                    Debug.log("handle %s", interval);
+                                    if (!interval.canMaterialize() && interval.spillState() != SpillState.StartInMemory) {
+
+                                        AllocatableValue fromLocation = interval.getSplitChildAtOpId(opId, OperandMode.DEF, allocator).location();
+                                        AllocatableValue toLocation = TraceLinearScan.canonicalSpillOpr(interval);
+                                        if (!fromLocation.equals(toLocation)) {
+
+                                            if (!insertionBuffer.initialized()) {
+                                                /*
+                                                 * prepare insertion buffer (appended when all
+                                                 * instructions in the block are processed)
+                                                 */
+                                                insertionBuffer.init(instructions);
+                                            }
+
+                                            assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" +
+                                                            interval.spillState();
+                                            assert isStackSlotValue(toLocation) : "to operand must be a stack slot";
+
+                                            LIRInstruction move = allocator.getSpillMoveFactory().createMove(toLocation, fromLocation);
+                                            insertionBuffer.append(j + 1, move);
+
+                                            if (Debug.isLogEnabled()) {
+                                                Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId);
+                                            }
+                                        }
+                                    }
+                                    interval = interval.next;
+                                }
+                            }
+                        }
+                    } // end of instruction iteration
+
+                    if (insertionBuffer.initialized()) {
+                        insertionBuffer.finish();
+                    }
+                }
+            } // end of block iteration
+
+            assert interval == TraceInterval.EndMarker : "missed an interval";
+        }
+    }
+
+    /**
+     * @param allocator
+     * @param block The block {@code move} is located in.
+     * @param move Spill move.
+     * @param lastOpId The id of last "normal" instruction before the spill move. (Spill moves have
+     *            no valid opId but -1.)
+     */
+    private static boolean canEliminateSpillMove(TraceLinearScan allocator, AbstractBlockBase<?> block, MoveOp move, int lastOpId) {
+        assert ((LIRInstruction) move).id() == -1 : "Not a spill move: " + move;
+        assert isVariable(move.getResult()) : "LinearScan inserts only moves to variables: " + move;
+        assert lastOpId >= 0 : "Invalid lastOpId: " + lastOpId;
+
+        TraceInterval curInterval = allocator.intervalFor(move.getResult());
+
+        if (!isRegister(curInterval.location()) && curInterval.inMemoryAt(lastOpId) && !isPhiResolutionMove(allocator, move)) {
+            /* Phi resolution moves cannot be removed because they define the value. */
+            // TODO (je) check if the comment is still valid!
+            assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Checks if a (spill or split) move is a Phi resolution move.
+     *
+     * A spill or split move connects a split parent or a split child with another split child.
+     * Therefore the destination of the move is always a split child. Phi resolution moves look like
+     * spill moves (i.e. {@link LIRInstruction#id() id} is {@code 0}, but they define a new
+     * variable. As a result the destination interval is a split parent.
+     */
+    private static boolean isPhiResolutionMove(TraceLinearScan allocator, MoveOp move) {
+        assert ((LIRInstruction) move).id() == -1 : "Not a spill move: " + move;
+        TraceInterval curInterval = allocator.intervalFor(move.getResult());
+        return curInterval.isSplitParent();
+    }
+
+    private static void checkIntervals(TraceInterval interval) {
+        TraceInterval prev = null;
+        TraceInterval temp = interval;
+        while (temp != TraceInterval.EndMarker) {
+            assert temp.spillDefinitionPos() >= 0 : "invalid spill definition pos";
+            if (prev != null) {
+                // assert temp.from() >= prev.from() : "intervals not sorted";
+                assert temp.spillDefinitionPos() >= prev.spillDefinitionPos() : "when intervals are sorted by from :  then they must also be sorted by spillDefinitionPos";
+            }
+
+            assert temp.spillSlot() != null || temp.canMaterialize() : "interval has no spill slot assigned";
+            assert temp.spillDefinitionPos() >= temp.from() : "invalid order";
+            // assert temp.spillDefinitionPos() <= temp.from() + 2 :
+            // "only intervals defined once at their start-pos can be optimized";
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("interval %d (from %d to %d) must be stored at %d", temp.operandNumber, temp.from(), temp.to(), temp.spillDefinitionPos());
+            }
+
+            prev = temp;
+            temp = temp.next;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,678 @@
+/*
+ * Copyright (c) 2015, 2015, 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.alloc.trace.lsra;
+
+import static com.oracle.graal.lir.LIRValueUtil.asVariable;
+import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
+import static com.oracle.graal.lir.LIRValueUtil.isVariable;
+import static com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase.Options.TraceRAshareSpillInformation;
+import static com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase.Options.TraceRAuseInterTraceHints;
+import static com.oracle.graal.lir.alloc.trace.TraceUtil.asShadowedRegisterValue;
+import static com.oracle.graal.lir.alloc.trace.TraceUtil.isShadowedRegisterValue;
+import static com.oracle.graal.lir.alloc.trace.lsra.TraceLinearScan.isVariableOrRegister;
+import static jdk.vm.ci.code.ValueUtil.asRegisterValue;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.BitSet;
+import java.util.EnumSet;
+import java.util.List;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.LIRKind;
+import jdk.vm.ci.meta.Value;
+
+import com.oracle.graal.compiler.common.alloc.ComputeBlockOrder;
+import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
+import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.Indent;
+import com.oracle.graal.lir.InstructionValueConsumer;
+import com.oracle.graal.lir.LIR;
+import com.oracle.graal.lir.LIRInstruction;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.LIRValueUtil;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.lir.StandardOp.LoadConstantOp;
+import com.oracle.graal.lir.StandardOp.ValueMoveOp;
+import com.oracle.graal.lir.ValueConsumer;
+import com.oracle.graal.lir.Variable;
+import com.oracle.graal.lir.alloc.trace.ShadowedRegisterValue;
+import com.oracle.graal.lir.alloc.trace.lsra.TraceInterval.RegisterPriority;
+import com.oracle.graal.lir.alloc.trace.lsra.TraceInterval.SpillState;
+import com.oracle.graal.lir.gen.LIRGenerationResult;
+import com.oracle.graal.lir.ssi.SSIUtil;
+
+final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanAllocationPhase {
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    TraceLinearScanAllocationContext context) {
+        TraceBuilderResult<?> traceBuilderResult = context.traceBuilderResult;
+        TraceLinearScan allocator = context.allocator;
+        new Analyser(allocator, traceBuilderResult).analyze();
+    }
+
+    private static final class Analyser {
+        private static final int DUMP_DURING_ANALYSIS_LEVEL = 4;
+        private final TraceLinearScan allocator;
+        private final TraceBuilderResult<?> traceBuilderResult;
+
+        /**
+         * @param linearScan
+         * @param traceBuilderResult
+         */
+        private Analyser(TraceLinearScan linearScan, TraceBuilderResult<?> traceBuilderResult) {
+            allocator = linearScan;
+            this.traceBuilderResult = traceBuilderResult;
+        }
+
+        private void analyze() {
+            numberInstructions();
+            allocator.printLir("Before register allocation", true);
+            buildIntervals();
+        }
+
+        private boolean sameTrace(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
+            return traceBuilderResult.getTraceForBlock(b) == traceBuilderResult.getTraceForBlock(a);
+        }
+
+        private boolean isAllocatedOrCurrent(AbstractBlockBase<?> currentBlock, AbstractBlockBase<?> other) {
+            return traceBuilderResult.getTraceForBlock(other) <= traceBuilderResult.getTraceForBlock(currentBlock);
+        }
+
+        private static void setHint(final LIRInstruction op, TraceInterval to, IntervalHint from) {
+            IntervalHint currentHint = to.locationHint(false);
+            if (currentHint == null) {
+                /*
+                 * Update hint if there was none or if the hint interval starts after the hinted
+                 * interval.
+                 */
+                to.setLocationHint(from);
+                if (Debug.isLogEnabled()) {
+                    Debug.log("operation at opId %d: added hint from interval %s to %s", op.id(), from, to);
+                }
+            }
+        }
+
+        /**
+         * Numbers all instructions in all blocks. The numbering follows the
+         * {@linkplain ComputeBlockOrder linear scan order}.
+         */
+        private void numberInstructions() {
+
+            allocator.initIntervals();
+
+            ValueConsumer setVariableConsumer = (value, mode, flags) -> {
+                if (isVariable(value)) {
+                    allocator.getOrCreateInterval(asVariable(value));
+                }
+            };
+
+            // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node.
+            int numInstructions = 0;
+            for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+                numInstructions += allocator.getLIR().getLIRforBlock(block).size();
+            }
+
+            // initialize with correct length
+            allocator.initOpIdMaps(numInstructions);
+
+            int opId = 0;
+            int index = 0;
+            for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+                allocator.initBlockData(block);
+
+                List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
+
+                int numInst = instructions.size();
+                for (int j = 0; j < numInst; j++) {
+                    LIRInstruction op = instructions.get(j);
+                    op.setId(opId);
+
+                    allocator.putOpIdMaps(index, op, block);
+                    assert allocator.instructionForId(opId) == op : "must match";
+
+                    op.visitEachTemp(setVariableConsumer);
+                    op.visitEachOutput(setVariableConsumer);
+
+                    index++;
+                    opId += 2; // numbering of lirOps by two
+                }
+            }
+            assert index == numInstructions : "must match";
+            assert (index << 1) == opId : "must match: " + (index << 1);
+        }
+
+        private void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) {
+            if (!allocator.isProcessed(operand)) {
+                return;
+            }
+            if (isRegister(operand)) {
+                addFixedUse(asRegisterValue(operand), from, to);
+            } else {
+                assert isVariable(operand) : operand;
+                addVariableUse(asVariable(operand), from, to, registerPriority, kind);
+            }
+        }
+
+        private void addFixedUse(RegisterValue reg, int from, int to) {
+            FixedInterval interval = allocator.getOrCreateFixedInterval(reg);
+            interval.addRange(from, to);
+            if (Debug.isLogEnabled()) {
+                Debug.log("add fixed use: %s, at %d", interval, to);
+            }
+        }
+
+        private void addVariableUse(Variable operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) {
+            TraceInterval interval = allocator.getOrCreateInterval(operand);
+
+            if (!kind.equals(LIRKind.Illegal)) {
+                interval.setKind(kind);
+            }
+
+            interval.addRange(from, to);
+
+            // Register use position at even instruction id.
+            interval.addUsePos(to & ~1, registerPriority);
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("add use: %s, at %d (%s)", interval, to, registerPriority.name());
+            }
+        }
+
+        private void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) {
+            if (!allocator.isProcessed(operand)) {
+                return;
+            }
+            if (isRegister(operand)) {
+                addFixedTemp(asRegisterValue(operand), tempPos);
+            } else {
+                assert isVariable(operand) : operand;
+                addVariableTemp(asVariable(operand), tempPos, registerPriority, kind);
+            }
+        }
+
+        private void addFixedTemp(RegisterValue reg, int tempPos) {
+            FixedInterval interval = allocator.getOrCreateFixedInterval(reg);
+            interval.addRange(tempPos, tempPos + 1);
+            if (Debug.isLogEnabled()) {
+                Debug.log("add fixed temp: %s, at %d", interval, tempPos);
+            }
+        }
+
+        private void addVariableTemp(Variable operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) {
+            TraceInterval interval = allocator.getOrCreateInterval(operand);
+
+            if (!kind.equals(LIRKind.Illegal)) {
+                interval.setKind(kind);
+            }
+
+            if (interval.isEmpty()) {
+                interval.addRange(tempPos, tempPos + 1);
+            } else if (interval.from() > tempPos) {
+                interval.setFrom(tempPos);
+            }
+
+            interval.addUsePos(tempPos, registerPriority);
+            interval.addMaterializationValue(null);
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name());
+            }
+        }
+
+        private void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) {
+            if (!allocator.isProcessed(operand)) {
+                return;
+            }
+            if (isRegister(operand)) {
+                addFixedDef(asRegisterValue(operand), op);
+            } else {
+                assert isVariable(operand) : operand;
+                addVariableDef(asVariable(operand), op, registerPriority, kind);
+            }
+        }
+
+        private void addFixedDef(RegisterValue reg, LIRInstruction op) {
+            FixedInterval interval = allocator.getOrCreateFixedInterval(reg);
+            int defPos = op.id();
+            if (interval.from() <= defPos) {
+                /*
+                 * Update the starting point (when a range is first created for a use, its start is
+                 * the beginning of the current block until a def is encountered).
+                 */
+                interval.setFrom(defPos);
+
+            } else {
+                /*
+                 * Dead value - make vacuous interval also add register priority for dead intervals
+                 */
+                interval.addRange(defPos, defPos + 1);
+                if (Debug.isLogEnabled()) {
+                    Debug.log("Warning: def of operand %s at %d occurs without use", reg, defPos);
+                }
+            }
+            if (Debug.isLogEnabled()) {
+                Debug.log("add fixed def: %s, at %d", interval, defPos);
+            }
+        }
+
+        private void addVariableDef(Variable operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) {
+            int defPos = op.id();
+
+            TraceInterval interval = allocator.getOrCreateInterval(operand);
+
+            if (!kind.equals(LIRKind.Illegal)) {
+                interval.setKind(kind);
+            }
+
+            if (interval.isEmpty()) {
+                /*
+                 * Dead value - make vacuous interval also add register priority for dead intervals
+                 */
+                interval.addRange(defPos, defPos + 1);
+                interval.addUsePos(defPos, registerPriority);
+                if (Debug.isLogEnabled()) {
+                    Debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos);
+                }
+            } else {
+                /*
+                 * Update the starting point (when a range is first created for a use, its start is
+                 * the beginning of the current block until a def is encountered).
+                 */
+                interval.setFrom(defPos);
+                interval.addUsePos(defPos, registerPriority);
+            }
+
+            changeSpillDefinitionPos(op, operand, interval, defPos);
+            if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal() && isStackSlot(operand)) {
+                // detection of method-parameters and roundfp-results
+                interval.setSpillState(SpillState.StartInMemory);
+            }
+            interval.addMaterializationValue(getMaterializedValue(op, operand, interval));
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name());
+            }
+        }
+
+        private void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
+            if (flags.contains(OperandFlag.HINT) && TraceLinearScan.isVariableOrRegister(targetValue)) {
+
+                op.forEachRegisterHint(targetValue, mode, (registerHint, valueMode, valueFlags) -> {
+                    if (TraceLinearScan.isVariableOrRegister(registerHint)) {
+                        /*
+                         * TODO (je): clean up
+                         */
+                        final AllocatableValue fromValue;
+                        final AllocatableValue toValue;
+                        /* hints always point from def to use */
+                        if (hintAtDef) {
+                            fromValue = (AllocatableValue) registerHint;
+                            toValue = (AllocatableValue) targetValue;
+                        } else {
+                            fromValue = (AllocatableValue) targetValue;
+                            toValue = (AllocatableValue) registerHint;
+                        }
+                        Debug.log("addRegisterHint %s to %s", fromValue, toValue);
+                        final TraceInterval to;
+                        final IntervalHint from;
+                        if (isRegister(toValue)) {
+                            if (isRegister(fromValue)) {
+                                // fixed to fixed move
+                                return null;
+                            }
+                            from = getIntervalHint(toValue);
+                            to = allocator.getOrCreateInterval(fromValue);
+                        } else {
+                            to = allocator.getOrCreateInterval(toValue);
+                            from = getIntervalHint(fromValue);
+                        }
+
+                        to.setLocationHint(from);
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("operation at opId %d: added hint from interval %s to %s", op.id(), from, to);
+                        }
+
+                        return registerHint;
+                    }
+                    return null;
+                });
+            }
+        }
+
+        private IntervalHint getIntervalHint(AllocatableValue from) {
+            if (isRegister(from)) {
+                return allocator.getOrCreateFixedInterval(asRegisterValue(from));
+            }
+            return allocator.getOrCreateInterval(from);
+        }
+
+        /**
+         * Eliminates moves from register to stack if the stack slot is known to be correct.
+         *
+         * @param op
+         * @param operand
+         */
+        private void changeSpillDefinitionPos(LIRInstruction op, AllocatableValue operand, TraceInterval interval, int defPos) {
+            assert interval.isSplitParent() : "can only be called for split parents";
+
+            switch (interval.spillState()) {
+                case NoDefinitionFound:
+                    // assert interval.spillDefinitionPos() == -1 : "must no be set before";
+                    interval.setSpillDefinitionPos(defPos);
+                    if (!(op instanceof LabelOp)) {
+                        // Do not update state for labels. This will be done afterwards.
+                        interval.setSpillState(SpillState.NoSpillStore);
+                    }
+                    break;
+
+                case NoSpillStore:
+                    assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created";
+                    if (defPos < interval.spillDefinitionPos() - 2) {
+                        /*
+                         * Second definition found, so no spill optimization possible for this
+                         * interval.
+                         */
+                        interval.setSpillState(SpillState.NoOptimization);
+                    } else {
+                        // two consecutive definitions (because of two-operand LIR form)
+                        assert allocator.blockForId(defPos) == allocator.blockForId(interval.spillDefinitionPos()) : "block must be equal";
+                    }
+                    break;
+
+                case NoOptimization:
+                    // nothing to do
+                    break;
+
+                default:
+                    throw new BailoutException("other states not allowed at this time");
+            }
+        }
+
+        private static boolean optimizeMethodArgument(Value value) {
+            /*
+             * Object method arguments that are passed on the stack are currently not optimized
+             * because this requires that the runtime visits method arguments during stack walking.
+             */
+            return isStackSlot(value) && asStackSlot(value).isInCallerFrame() && value.getLIRKind().isValue();
+        }
+
+        /**
+         * Determines the register priority for an instruction's output/result operand.
+         */
+        private static RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) {
+            if (op instanceof LabelOp) {
+                // skip method header
+                return RegisterPriority.None;
+            }
+            if (op instanceof ValueMoveOp) {
+                ValueMoveOp move = (ValueMoveOp) op;
+                if (optimizeMethodArgument(move.getInput())) {
+                    return RegisterPriority.None;
+                }
+            }
+
+            // all other operands require a register
+            return RegisterPriority.MustHaveRegister;
+        }
+
+        /**
+         * Determines the priority which with an instruction's input operand will be allocated a
+         * register.
+         */
+        private static RegisterPriority registerPriorityOfInputOperand(EnumSet<OperandFlag> flags) {
+            if (flags.contains(OperandFlag.OUTGOING)) {
+                return RegisterPriority.None;
+            }
+            if (flags.contains(OperandFlag.STACK)) {
+                return RegisterPriority.ShouldHaveRegister;
+            }
+            // all other operands require a register
+            return RegisterPriority.MustHaveRegister;
+        }
+
+        @SuppressWarnings("try")
+        private void buildIntervals() {
+
+            try (Indent indent = Debug.logAndIndent("build intervals")) {
+                InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> {
+                    if (TraceLinearScan.isVariableOrRegister(operand)) {
+                        addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getLIRKind());
+                        addRegisterHint(op, operand, mode, flags, true);
+                    }
+                };
+
+                InstructionValueConsumer tempConsumer = (op, operand, mode, flags) -> {
+                    if (TraceLinearScan.isVariableOrRegister(operand)) {
+                        addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getLIRKind());
+                        addRegisterHint(op, operand, mode, flags, false);
+                    }
+                };
+
+                InstructionValueConsumer aliveConsumer = (op, operand, mode, flags) -> {
+                    if (TraceLinearScan.isVariableOrRegister(operand)) {
+                        RegisterPriority p = registerPriorityOfInputOperand(flags);
+                        int opId = op.id();
+                        int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
+                        addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getLIRKind());
+                        addRegisterHint(op, operand, mode, flags, false);
+                    }
+                };
+
+                InstructionValueConsumer inputConsumer = (op, operand, mode, flags) -> {
+                    if (TraceLinearScan.isVariableOrRegister(operand)) {
+                        int opId = op.id();
+                        RegisterPriority p = registerPriorityOfInputOperand(flags);
+                        int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
+                        addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getLIRKind());
+                        addRegisterHint(op, operand, mode, flags, false);
+                    }
+                };
+
+                InstructionValueConsumer stateProc = (op, operand, mode, flags) -> {
+                    if (TraceLinearScan.isVariableOrRegister(operand)) {
+                        int opId = op.id();
+                        int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
+                        addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getLIRKind());
+                    }
+                };
+
+                // create a list with all caller-save registers (cpu, fpu, xmm)
+                Register[] callerSaveRegs = allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters();
+
+                // iterate all blocks in reverse order
+                for (int i = allocator.blockCount() - 1; i >= 0; i--) {
+
+                    AbstractBlockBase<?> block = allocator.blockAt(i);
+                    // TODO (je) make empty bitset - remove
+                    allocator.getBlockData(block).liveIn = new BitSet();
+                    allocator.getBlockData(block).liveOut = new BitSet();
+                    try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) {
+
+                        List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
+
+                        /*
+                         * Iterate all instructions of the block in reverse order. definitions of
+                         * intervals are processed before uses.
+                         */
+                        for (int j = instructions.size() - 1; j >= 0; j--) {
+                            final LIRInstruction op = instructions.get(j);
+                            final int opId = op.id();
+
+                            try (Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op)) {
+
+                                // add a temp range for each register if operation destroys
+                                // caller-save registers
+                                if (op.destroysCallerSavedRegisters()) {
+                                    for (Register r : callerSaveRegs) {
+                                        if (allocator.attributes(r).isAllocatable()) {
+                                            addTemp(r.asValue(), opId, RegisterPriority.None, LIRKind.Illegal);
+                                        }
+                                    }
+                                    if (Debug.isLogEnabled()) {
+                                        Debug.log("operation destroys all caller-save registers");
+                                    }
+                                }
+
+                                op.visitEachOutput(outputConsumer);
+                                op.visitEachTemp(tempConsumer);
+                                op.visitEachAlive(aliveConsumer);
+                                op.visitEachInput(inputConsumer);
+
+                                /*
+                                 * Add uses of live locals from interpreter's point of view for
+                                 * proper debug information generation. Treat these operands as temp
+                                 * values (if the live range is extended to a call site, the value
+                                 * would be in a register at the call otherwise).
+                                 */
+                                op.visitEachState(stateProc);
+                            }
+
+                        } // end of instruction iteration
+                    }
+                    if (Debug.isDumpEnabled(DUMP_DURING_ANALYSIS_LEVEL)) {
+                        allocator.printIntervals("After Block " + block);
+                    }
+                } // end of block iteration
+
+                // fix spill state for phi/sigma intervals
+                for (TraceInterval interval : allocator.intervals()) {
+                    if (interval != null && interval.spillState().equals(SpillState.NoDefinitionFound) && interval.spillDefinitionPos() != -1) {
+                        // there was a definition in a phi/sigma
+                        interval.setSpillState(SpillState.NoSpillStore);
+                    }
+                }
+                if (TraceRAuseInterTraceHints.getValue()) {
+                    addInterTraceHints();
+                }
+                /*
+                 * Add the range [-1, 0] to all fixed intervals. the register allocator need not
+                 * handle unhandled fixed intervals.
+                 */
+                for (FixedInterval interval : allocator.fixedIntervals()) {
+                    if (interval != null) {
+                        /* We use [-1, 0] to avoid intersection with incoming values. */
+                        interval.addRange(-1, 0);
+                    }
+                }
+            }
+        }
+
+        private void addInterTraceHints() {
+            // set hints for phi/sigma intervals
+            LIR lir = allocator.getLIR();
+            for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
+                LabelOp label = SSIUtil.incoming(lir, block);
+                for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+                    if (isAllocatedOrCurrent(block, pred)) {
+                        BlockEndOp outgoing = SSIUtil.outgoing(lir, pred);
+                        for (int i = 0; i < outgoing.getOutgoingSize(); i++) {
+                            Value toValue = label.getIncomingValue(i);
+                            assert !isShadowedRegisterValue(toValue) : "Shadowed Registers are not allowed here: " + toValue;
+                            if (isVariable(toValue)) {
+                                Value fromValue = outgoing.getOutgoingValue(i);
+                                assert sameTrace(block, pred) || !isVariable(fromValue) : "Unallocated variable: " + fromValue;
+                                if (!LIRValueUtil.isConstantValue(fromValue)) {
+                                    addInterTraceHint(label, (AllocatableValue) toValue, fromValue);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        private void addInterTraceHint(LabelOp label, AllocatableValue toValue, Value fromValue) {
+            assert isVariable(toValue) : "Wrong toValue: " + toValue;
+            assert isRegister(fromValue) || isVariable(fromValue) || isStackSlotValue(fromValue) || isShadowedRegisterValue(fromValue) : "Wrong fromValue: " + fromValue;
+            if (isVariableOrRegister(fromValue)) {
+                TraceInterval to = allocator.getOrCreateInterval(toValue);
+                IntervalHint from = getIntervalHint((AllocatableValue) fromValue);
+                setHint(label, to, from);
+            } else if (isStackSlotValue(fromValue)) {
+                TraceInterval to = allocator.getOrCreateInterval(toValue);
+                to.setSpillSlot((AllocatableValue) fromValue);
+                to.setSpillState(SpillState.StartInMemory);
+            } else if (TraceRAshareSpillInformation.getValue() && isShadowedRegisterValue(fromValue)) {
+                ShadowedRegisterValue shadowedRegisterValue = asShadowedRegisterValue(fromValue);
+                IntervalHint from = getIntervalHint(shadowedRegisterValue.getRegister());
+                TraceInterval to = allocator.getOrCreateInterval(toValue);
+                setHint(label, to, from);
+                to.setSpillSlot(shadowedRegisterValue.getStackSlot());
+                to.setSpillState(SpillState.StartInMemory);
+            } else {
+                throw JVMCIError.shouldNotReachHere();
+            }
+        }
+
+        /**
+         * Returns a value for a interval definition, which can be used for re-materialization.
+         *
+         * @param op An instruction which defines a value
+         * @param operand The destination operand of the instruction
+         * @param interval The interval for this defined value.
+         * @return Returns the value which is moved to the instruction and which can be reused at
+         *         all reload-locations in case the interval of this instruction is spilled.
+         *         Currently this can only be a {@link JavaConstant}.
+         */
+        private JavaConstant getMaterializedValue(LIRInstruction op, Value operand, TraceInterval interval) {
+            if (op instanceof LoadConstantOp) {
+                LoadConstantOp move = (LoadConstantOp) op;
+                if (move.getConstant() instanceof JavaConstant) {
+                    if (!allocator.neverSpillConstants()) {
+                        if (!allocator.getSpillMoveFactory().allowConstantToStackMove(move.getConstant())) {
+                            return null;
+                        }
+                        /*
+                         * Check if the interval has any uses which would accept an stack location
+                         * (priority == ShouldHaveRegister). Rematerialization of such intervals can
+                         * result in a degradation, because rematerialization always inserts a
+                         * constant load, even if the value is not needed in a register.
+                         */
+                        UsePosList usePosList = interval.usePosList();
+                        int numUsePos = usePosList.size();
+                        for (int useIdx = 0; useIdx < numUsePos; useIdx++) {
+                            TraceInterval.RegisterPriority priority = usePosList.registerPriority(useIdx);
+                            if (priority == TraceInterval.RegisterPriority.ShouldHaveRegister) {
+                                return null;
+                            }
+                        }
+                    }
+                    return (JavaConstant) move.getConstant();
+                }
+            }
+            return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/TraceLinearScanRegisterAllocationPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, 2015, 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.alloc.trace.lsra;
+
+import java.util.List;
+
+import jdk.vm.ci.code.TargetDescription;
+
+import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.Indent;
+import com.oracle.graal.lir.gen.LIRGenerationResult;
+
+final class TraceLinearScanRegisterAllocationPhase extends TraceLinearScanAllocationPhase {
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    TraceLinearScanAllocationContext context) {
+        TraceLinearScan allocator = context.allocator;
+        allocator.printIntervals("Before register allocation");
+        allocateRegisters(allocator);
+        allocator.printIntervals("After register allocation");
+    }
+
+    @SuppressWarnings("try")
+    private static void allocateRegisters(TraceLinearScan allocator) {
+        try (Indent indent = Debug.logAndIndent("allocate registers")) {
+            FixedInterval precoloredIntervals = allocator.createFixedUnhandledList();
+            TraceInterval notPrecoloredIntervals = allocator.createUnhandledListByFrom(TraceLinearScan.IS_VARIABLE_INTERVAL);
+
+            // allocate cpu registers
+            TraceLinearScanWalker lsw = new TraceLinearScanWalker(allocator, precoloredIntervals, notPrecoloredIntervals);
+            lsw.walk();
+            lsw.finishAllocation();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/TraceLinearScanResolveDataFlowPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2015, 2015, 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.alloc.trace.lsra;
+
+import static com.oracle.graal.compiler.common.GraalOptions.DetailedAsserts;
+import static com.oracle.graal.lir.LIRValueUtil.asConstant;
+import static com.oracle.graal.lir.LIRValueUtil.isConstantValue;
+import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
+import static com.oracle.graal.lir.LIRValueUtil.isVirtualStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.BitSet;
+import java.util.List;
+import java.util.ListIterator;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.Value;
+
+import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
+import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.debug.Indent;
+import com.oracle.graal.lir.LIRInstruction;
+import com.oracle.graal.lir.StandardOp;
+import com.oracle.graal.lir.gen.LIRGenerationResult;
+import com.oracle.graal.lir.ssa.SSAUtil.PhiValueVisitor;
+import com.oracle.graal.lir.ssi.SSIUtil;
+
+/**
+ * Phase 6: resolve data flow
+ *
+ * Insert moves at edges between blocks if intervals have been split.
+ */
+final class TraceLinearScanResolveDataFlowPhase extends TraceLinearScanAllocationPhase {
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    TraceLinearScanAllocationContext context) {
+        TraceBuilderResult<?> traceBuilderResult = context.traceBuilderResult;
+        TraceLinearScan allocator = context.allocator;
+        new Resolver(allocator, traceBuilderResult).resolveDataFlow(allocator.sortedBlocks());
+    }
+
+    private static final class Resolver {
+        private final TraceLinearScan allocator;
+        private final TraceBuilderResult<?> traceBuilderResult;
+
+        private Resolver(TraceLinearScan allocator, TraceBuilderResult<?> traceBuilderResult) {
+            this.allocator = allocator;
+            this.traceBuilderResult = traceBuilderResult;
+        }
+
+        private void resolveFindInsertPos(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, TraceLocalMoveResolver moveResolver) {
+            if (fromBlock.getSuccessorCount() <= 1) {
+                if (Debug.isLogEnabled()) {
+                    Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId());
+                }
+
+                List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(fromBlock);
+                LIRInstruction instr = instructions.get(instructions.size() - 1);
+                if (instr instanceof StandardOp.JumpOp) {
+                    // insert moves before branch
+                    moveResolver.setInsertPosition(instructions, instructions.size() - 1);
+                } else {
+                    moveResolver.setInsertPosition(instructions, instructions.size());
+                }
+
+            } else {
+                if (Debug.isLogEnabled()) {
+                    Debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId());
+                }
+
+                if (DetailedAsserts.getValue()) {
+                    assert allocator.getLIR().getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label";
+
+                    /*
+                     * Because the number of predecessor edges matches the number of successor
+                     * edges, blocks which are reached by switch statements may have be more than
+                     * one predecessor but it will be guaranteed that all predecessors will be the
+                     * same.
+                     */
+                    for (AbstractBlockBase<?> predecessor : toBlock.getPredecessors()) {
+                        assert fromBlock == predecessor : "all critical edges must be broken";
+                    }
+                }
+
+                moveResolver.setInsertPosition(allocator.getLIR().getLIRforBlock(toBlock), 1);
+            }
+        }
+
+        /**
+         * Inserts necessary moves (spilling or reloading) at edges between blocks for intervals
+         * that have been split.
+         */
+        @SuppressWarnings("try")
+        private void resolveDataFlow(List<? extends AbstractBlockBase<?>> blocks) {
+            if (blocks.size() < 2) {
+                // no resolution necessary
+                return;
+            }
+            try (Indent indent = Debug.logAndIndent("resolve data flow")) {
+
+                TraceLocalMoveResolver moveResolver = allocator.createMoveResolver();
+                ListIterator<? extends AbstractBlockBase<?>> it = blocks.listIterator();
+                AbstractBlockBase<?> toBlock = null;
+                for (AbstractBlockBase<?> fromBlock = it.next(); it.hasNext(); fromBlock = toBlock) {
+                    toBlock = it.next();
+                    assert containedInTrace(fromBlock) : "Not in Trace: " + fromBlock;
+                    assert containedInTrace(toBlock) : "Not in Trace: " + toBlock;
+                    resolveCollectMappings(fromBlock, toBlock, moveResolver);
+                }
+                assert blocks.get(blocks.size() - 1).equals(toBlock);
+                if (toBlock.isLoopEnd()) {
+                    assert toBlock.getSuccessorCount() == 1;
+                    AbstractBlockBase<?> loopHeader = toBlock.getSuccessors().get(0);
+                    if (containedInTrace(loopHeader)) {
+                        resolveCollectMappings(toBlock, loopHeader, moveResolver);
+                    }
+                }
+
+            }
+        }
+
+        @SuppressWarnings("try")
+        private void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, TraceLocalMoveResolver moveResolver) {
+            try (Indent indent0 = Debug.logAndIndent("Edge %s -> %s", fromBlock, toBlock)) {
+                collectLSRAMappings(fromBlock, toBlock, moveResolver);
+                collectSSIMappings(fromBlock, toBlock, moveResolver);
+            }
+        }
+
+        protected void collectLSRAMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, TraceLocalMoveResolver moveResolver) {
+            assert moveResolver.checkEmpty();
+
+            int toBlockFirstInstructionId = allocator.getFirstLirInstructionId(toBlock);
+            int fromBlockLastInstructionId = allocator.getLastLirInstructionId(fromBlock) + 1;
+            int numOperands = allocator.operandSize();
+            BitSet liveAtEdge = allocator.getBlockData(toBlock).liveIn;
+
+            // visit all variables for which the liveAtEdge bit is set
+            for (int operandNum = liveAtEdge.nextSetBit(0); operandNum >= 0; operandNum = liveAtEdge.nextSetBit(operandNum + 1)) {
+                assert operandNum < numOperands : "live information set for not exisiting interval";
+                assert allocator.getBlockData(fromBlock).liveOut.get(operandNum) && allocator.getBlockData(toBlock).liveIn.get(operandNum) : "interval not live at this edge";
+
+                TraceInterval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(operandNum), fromBlockLastInstructionId, LIRInstruction.OperandMode.DEF);
+                TraceInterval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(operandNum), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF);
+
+                if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) {
+                    // need to insert move instruction
+                    moveResolver.addMapping(fromInterval, toInterval);
+                }
+            }
+        }
+
+        protected void collectSSIMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, TraceLocalMoveResolver moveResolver) {
+            // collect all intervals that have been split between
+            // fromBlock and toBlock
+            SSIUtil.forEachValuePair(allocator.getLIR(), toBlock, fromBlock, new MyPhiValueVisitor(moveResolver, toBlock, fromBlock));
+            if (moveResolver.hasMappings()) {
+                resolveFindInsertPos(fromBlock, toBlock, moveResolver);
+                moveResolver.resolveAndAppendMoves();
+            }
+        }
+
+        private boolean containedInTrace(AbstractBlockBase<?> block) {
+            return currentTrace() == traceBuilderResult.getTraceForBlock(block);
+        }
+
+        private int currentTrace() {
+            return traceBuilderResult.getTraceForBlock(allocator.sortedBlocks().get(0));
+        }
+
+        private static final DebugMetric numSSIResolutionMoves = Debug.metric("SSI LSRA[numSSIResolutionMoves]");
+        private static final DebugMetric numStackToStackMoves = Debug.metric("SSI LSRA[numStackToStackMoves]");
+
+        private class MyPhiValueVisitor implements PhiValueVisitor {
+            final TraceLocalMoveResolver moveResolver;
+            final int toId;
+            final int fromId;
+
+            public MyPhiValueVisitor(TraceLocalMoveResolver moveResolver, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> fromBlock) {
+                this.moveResolver = moveResolver;
+                toId = allocator.getFirstLirInstructionId(toBlock);
+                fromId = allocator.getLastLirInstructionId(fromBlock);
+                assert fromId >= 0;
+            }
+
+            public void visit(Value phiIn, Value phiOut) {
+                assert !isRegister(phiOut) : "Out is a register: " + phiOut;
+                assert !isRegister(phiIn) : "In is a register: " + phiIn;
+                if (Value.ILLEGAL.equals(phiIn)) {
+                    // The value not needed in this branch.
+                    return;
+                }
+                if (isVirtualStackSlot(phiIn) && isVirtualStackSlot(phiOut) && phiIn.equals(phiOut)) {
+                    // no need to handle virtual stack slots
+                    return;
+                }
+                TraceInterval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiIn), toId, LIRInstruction.OperandMode.DEF);
+                if (isConstantValue(phiOut)) {
+                    numSSIResolutionMoves.increment();
+                    moveResolver.addMapping(asConstant(phiOut), toInterval);
+                } else {
+                    TraceInterval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiOut), fromId, LIRInstruction.OperandMode.DEF);
+                    if (fromInterval != toInterval) {
+                        numSSIResolutionMoves.increment();
+                        if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) {
+                            moveResolver.addMapping(fromInterval, toInterval);
+                        } else {
+                            numStackToStackMoves.increment();
+                            moveResolver.addMapping(fromInterval, toInterval);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/TraceLinearScanWalker.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,1126 @@
+/*
+ * Copyright (c) 2009, 2015, 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.alloc.trace.lsra;
+
+import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
+import static com.oracle.graal.lir.LIRValueUtil.isVariable;
+import static jdk.vm.ci.code.CodeUtil.isOdd;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.List;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.Value;
+
+import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig.AllocatableRegisters;
+import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
+import com.oracle.graal.compiler.common.util.Util;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.Indent;
+import com.oracle.graal.lir.LIRInstruction;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.lir.StandardOp.ValueMoveOp;
+import com.oracle.graal.lir.alloc.lsra.OutOfRegistersException;
+import com.oracle.graal.lir.alloc.trace.lsra.TraceInterval.RegisterPriority;
+import com.oracle.graal.lir.alloc.trace.lsra.TraceInterval.SpillState;
+import com.oracle.graal.lir.alloc.trace.lsra.TraceInterval.State;
+
+/**
+ */
+final class TraceLinearScanWalker extends TraceIntervalWalker {
+
+    private Register[] availableRegs;
+
+    private final int[] usePos;
+    private final int[] blockPos;
+    private final BitSet isInMemory;
+
+    private List<TraceInterval>[] spillIntervals;
+
+    private TraceLocalMoveResolver moveResolver; // for ordering spill moves
+
+    private int minReg;
+
+    private int maxReg;
+
+    /**
+     * Only 10% of the lists in {@link #spillIntervals} are actually used. But when they are used,
+     * they can grow quite long. The maximum length observed was 45 (all numbers taken from a
+     * bootstrap run of Graal). Therefore, we initialize {@link #spillIntervals} with this marker
+     * value, and allocate a "real" list only on demand in {@link #setUsePos}.
+     */
+    private static final List<TraceInterval> EMPTY_LIST = new ArrayList<>(0);
+
+    // accessors mapped to same functions in class LinearScan
+    private int blockCount() {
+        return allocator.blockCount();
+    }
+
+    private AbstractBlockBase<?> blockAt(int idx) {
+        return allocator.blockAt(idx);
+    }
+
+    @SuppressWarnings("unused")
+    private AbstractBlockBase<?> blockOfOpWithId(int opId) {
+        return allocator.blockForId(opId);
+    }
+
+    TraceLinearScanWalker(TraceLinearScan allocator, FixedInterval unhandledFixedFirst, TraceInterval unhandledAnyFirst) {
+        super(allocator, unhandledFixedFirst, unhandledAnyFirst);
+
+        moveResolver = allocator.createMoveResolver();
+        int numRegs = allocator.getRegisters().length;
+        spillIntervals = Util.uncheckedCast(new List<?>[numRegs]);
+        for (int i = 0; i < numRegs; i++) {
+            spillIntervals[i] = EMPTY_LIST;
+        }
+        usePos = new int[numRegs];
+        blockPos = new int[numRegs];
+        isInMemory = new BitSet(numRegs);
+    }
+
+    private void initUseLists(boolean onlyProcessUsePos) {
+        for (Register register : availableRegs) {
+            int i = register.number;
+            usePos[i] = Integer.MAX_VALUE;
+
+            if (!onlyProcessUsePos) {
+                blockPos[i] = Integer.MAX_VALUE;
+                spillIntervals[i].clear();
+                isInMemory.clear(i);
+            }
+        }
+    }
+
+    private int maxRegisterNumber() {
+        return maxReg;
+    }
+
+    private int minRegisterNumber() {
+        return minReg;
+    }
+
+    private boolean isRegisterInRange(int reg) {
+        return reg >= minRegisterNumber() && reg <= maxRegisterNumber();
+    }
+
+    private void excludeFromUse(IntervalHint i) {
+        Value location = i.location();
+        int i1 = asRegister(location).number;
+        if (isRegisterInRange(i1)) {
+            usePos[i1] = 0;
+        }
+    }
+
+    private void setUsePos(TraceInterval interval, int usePos, boolean onlyProcessUsePos) {
+        if (usePos != -1) {
+            assert usePos != 0 : "must use excludeFromUse to set usePos to 0";
+            int i = asRegister(interval.location()).number;
+            if (isRegisterInRange(i)) {
+                if (this.usePos[i] > usePos) {
+                    this.usePos[i] = usePos;
+                }
+                if (!onlyProcessUsePos) {
+                    List<TraceInterval> list = spillIntervals[i];
+                    if (list == EMPTY_LIST) {
+                        list = new ArrayList<>(2);
+                        spillIntervals[i] = list;
+                    }
+                    list.add(interval);
+                    // set is in memory flag
+                    if (interval.inMemoryAt(currentPosition)) {
+                        isInMemory.set(i);
+                    }
+                }
+            }
+        }
+    }
+
+    private void setUsePos(FixedInterval interval, int usePos, boolean onlyProcessUsePos) {
+        assert onlyProcessUsePos;
+        if (usePos != -1) {
+            assert usePos != 0 : "must use excludeFromUse to set usePos to 0";
+            int i = asRegister(interval.location()).number;
+            if (isRegisterInRange(i)) {
+                if (this.usePos[i] > usePos) {
+                    this.usePos[i] = usePos;
+                }
+            }
+        }
+    }
+
+    private void setBlockPos(IntervalHint i, int blockPos) {
+        if (blockPos != -1) {
+            int reg = asRegister(i.location()).number;
+            if (isRegisterInRange(reg)) {
+                if (this.blockPos[reg] > blockPos) {
+                    this.blockPos[reg] = blockPos;
+                }
+                if (usePos[reg] > blockPos) {
+                    usePos[reg] = blockPos;
+                }
+            }
+        }
+    }
+
+    private void freeExcludeActiveFixed() {
+        FixedInterval interval = activeFixedList.getFixed();
+        while (interval != FixedInterval.EndMarker) {
+            assert isRegister(interval.location()) : "active interval must have a register assigned";
+            excludeFromUse(interval);
+            interval = interval.next;
+        }
+    }
+
+    private void freeExcludeActiveAny() {
+        TraceInterval interval = activeAnyList.getAny();
+        while (interval != TraceInterval.EndMarker) {
+            assert isRegister(interval.location()) : "active interval must have a register assigned";
+            excludeFromUse(interval);
+            interval = interval.next;
+        }
+    }
+
+    private void freeCollectInactiveFixed(TraceInterval current) {
+        FixedInterval interval = inactiveFixedList.getFixed();
+        while (interval != FixedInterval.EndMarker) {
+            if (current.to() <= interval.from()) {
+                assert interval.intersectsAt(current) == -1 : "must not intersect";
+                setUsePos(interval, interval.from(), true);
+            } else {
+                setUsePos(interval, interval.currentIntersectsAt(current), true);
+            }
+            interval = interval.next;
+        }
+    }
+
+    private void spillExcludeActiveFixed() {
+        FixedInterval interval = activeFixedList.getFixed();
+        while (interval != FixedInterval.EndMarker) {
+            excludeFromUse(interval);
+            interval = interval.next;
+        }
+    }
+
+    private void spillBlockInactiveFixed(TraceInterval current) {
+        FixedInterval interval = inactiveFixedList.getFixed();
+        while (interval != FixedInterval.EndMarker) {
+            if (current.to() > interval.currentFrom()) {
+                setBlockPos(interval, interval.currentIntersectsAt(current));
+            } else {
+                assert interval.currentIntersectsAt(current) == -1 : "invalid optimization: intervals intersect";
+            }
+
+            interval = interval.next;
+        }
+    }
+
+    private void spillCollectActiveAny(RegisterPriority registerPriority) {
+        TraceInterval interval = activeAnyList.getAny();
+        while (interval != TraceInterval.EndMarker) {
+            setUsePos(interval, Math.min(interval.nextUsage(registerPriority, currentPosition), interval.to()), false);
+            interval = interval.next;
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private int insertIdAtBasicBlockBoundary(int opId) {
+        assert allocator.isBlockBegin(opId) : "Not a block begin: " + opId;
+        assert allocator.instructionForId(opId) instanceof LabelOp;
+        assert allocator.instructionForId(opId - 2) instanceof BlockEndOp;
+
+        AbstractBlockBase<?> toBlock = allocator.blockForId(opId);
+        AbstractBlockBase<?> fromBlock = allocator.blockForId(opId - 2);
+
+        if (fromBlock.getSuccessorCount() == 1) {
+            // insert move in predecessor
+            return opId - 2;
+        }
+        assert toBlock.getPredecessorCount() == 1 : String.format("Critical Edge? %s->%s", fromBlock, toBlock);
+        // insert move in successor
+        return opId + 2;
+    }
+
+    private void insertMove(int operandId, TraceInterval srcIt, TraceInterval dstIt) {
+        // output all moves here. When source and target are equal, the move is
+        // optimized away later in assignRegNums
+
+        int opId = (operandId + 1) & ~1;
+        AbstractBlockBase<?> opBlock = allocator.blockForId(opId);
+        assert opId > 0 && allocator.blockForId(opId - 2) == opBlock : "cannot insert move at block boundary";
+
+        // calculate index of instruction inside instruction list of current block
+        // the minimal index (for a block with no spill moves) can be calculated because the
+        // numbering of instructions is known.
+        // When the block already contains spill moves, the index must be increased until the
+        // correct index is reached.
+        List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(opBlock);
+        int index = (opId - instructions.get(0).id()) >> 1;
+        assert instructions.get(index).id() <= opId : "error in calculation";
+
+        while (instructions.get(index).id() != opId) {
+            index++;
+            assert 0 <= index && index < instructions.size() : "index out of bounds";
+        }
+        assert 1 <= index && index < instructions.size() : "index out of bounds";
+        assert instructions.get(index).id() == opId : "error in calculation";
+
+        // insert new instruction before instruction at position index
+        moveResolver.moveInsertPosition(instructions, index);
+        moveResolver.addMapping(srcIt, dstIt);
+    }
+
+    private int findOptimalSplitPos(AbstractBlockBase<?> minBlock, AbstractBlockBase<?> maxBlock, int maxSplitPos) {
+        int fromBlockNr = minBlock.getLinearScanNumber();
+        int toBlockNr = maxBlock.getLinearScanNumber();
+
+        assert 0 <= fromBlockNr && fromBlockNr < blockCount() : "out of range";
+        assert 0 <= toBlockNr && toBlockNr < blockCount() : "out of range";
+        assert fromBlockNr < toBlockNr : "must cross block boundary";
+
+        // Try to split at end of maxBlock. If this would be after
+        // maxSplitPos, then use the begin of maxBlock
+        int optimalSplitPos = allocator.getLastLirInstructionId(maxBlock) + 2;
+        if (optimalSplitPos > maxSplitPos) {
+            optimalSplitPos = allocator.getFirstLirInstructionId(maxBlock);
+        }
+
+        // minimal block probability
+        double minProbability = maxBlock.probability();
+        for (int i = toBlockNr - 1; i >= fromBlockNr; i--) {
+            AbstractBlockBase<?> cur = blockAt(i);
+
+            if (cur.probability() < minProbability) {
+                // Block with lower probability found. Split at the end of this block.
+                minProbability = cur.probability();
+                optimalSplitPos = allocator.getLastLirInstructionId(cur) + 2;
+            }
+        }
+        assert optimalSplitPos > allocator.maxOpId() || allocator.isBlockBegin(optimalSplitPos) : "algorithm must move split pos to block boundary";
+
+        return optimalSplitPos;
+    }
+
+    @SuppressWarnings({"unused"})
+    private int findOptimalSplitPos(TraceInterval interval, int minSplitPos, int maxSplitPos, boolean doLoopOptimization) {
+        int optimalSplitPos = findOptimalSplitPos0(minSplitPos, maxSplitPos);
+        if (Debug.isLogEnabled()) {
+            Debug.log("optimal split position: %d", optimalSplitPos);
+        }
+        return optimalSplitPos;
+    }
+
+    private int findOptimalSplitPos0(int minSplitPos, int maxSplitPos) {
+        if (minSplitPos == maxSplitPos) {
+            // trivial case, no optimization of split position possible
+            if (Debug.isLogEnabled()) {
+                Debug.log("min-pos and max-pos are equal, no optimization possible");
+            }
+            return minSplitPos;
+
+        }
+        assert minSplitPos < maxSplitPos : "must be true then";
+        assert minSplitPos > 0 : "cannot access minSplitPos - 1 otherwise";
+
+        // reason for using minSplitPos - 1: when the minimal split pos is exactly at the
+        // beginning of a block, then minSplitPos is also a possible split position.
+        // Use the block before as minBlock, because then minBlock.lastLirInstructionId() + 2 ==
+        // minSplitPos
+        AbstractBlockBase<?> minBlock = allocator.blockForId(minSplitPos - 1);
+
+        // reason for using maxSplitPos - 1: otherwise there would be an assert on failure
+        // when an interval ends at the end of the last block of the method
+        // (in this case, maxSplitPos == allocator().maxLirOpId() + 2, and there is no
+        // block at this opId)
+        AbstractBlockBase<?> maxBlock = allocator.blockForId(maxSplitPos - 1);
+
+        assert minBlock.getLinearScanNumber() <= maxBlock.getLinearScanNumber() : "invalid order";
+        if (minBlock == maxBlock) {
+            // split position cannot be moved to block boundary : so split as late as possible
+            if (Debug.isLogEnabled()) {
+                Debug.log("cannot move split pos to block boundary because minPos and maxPos are in same block");
+            }
+            return maxSplitPos;
+
+        }
+        // seach optimal block boundary between minSplitPos and maxSplitPos
+        if (Debug.isLogEnabled()) {
+            Debug.log("moving split pos to optimal block boundary between block B%d and B%d", minBlock.getId(), maxBlock.getId());
+        }
+
+        return findOptimalSplitPos(minBlock, maxBlock, maxSplitPos);
+    }
+
+    // split an interval at the optimal position between minSplitPos and
+    // maxSplitPos in two parts:
+    // 1) the left part has already a location assigned
+    // 2) the right part is sorted into to the unhandled-list
+    @SuppressWarnings("try")
+    private void splitBeforeUsage(TraceInterval interval, int minSplitPos, int maxSplitPos) {
+
+        try (Indent indent = Debug.logAndIndent("splitting interval %s between %d and %d", interval, minSplitPos, maxSplitPos)) {
+
+            assert interval.from() < minSplitPos : "cannot split at start of interval";
+            assert currentPosition < minSplitPos : "cannot split before current position";
+            assert minSplitPos <= maxSplitPos : "invalid order";
+            assert maxSplitPos <= interval.to() : "cannot split after end of interval";
+
+            final int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, true);
+
+            if (optimalSplitPos == interval.to() && interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos) == Integer.MAX_VALUE) {
+                // the split position would be just before the end of the interval
+                // . no split at all necessary
+                if (Debug.isLogEnabled()) {
+                    Debug.log("no split necessary because optimal split position is at end of interval");
+                }
+                return;
+            }
+            // must calculate this before the actual split is performed and before split position is
+            // moved to odd opId
+            final int optimalSplitPosFinal;
+            boolean blockBegin = allocator.isBlockBegin(optimalSplitPos);
+            if (blockBegin) {
+                assert (optimalSplitPos & 1) == 0 : "Block begins must be even: " + optimalSplitPos;
+                // move position after the label (odd optId)
+                optimalSplitPosFinal = optimalSplitPos + 1;
+            } else {
+                // move position before actual instruction (odd opId)
+                optimalSplitPosFinal = (optimalSplitPos - 1) | 1;
+            }
+
+            // TODO( je) better define what min split pos max split pos mean.
+            assert minSplitPos <= optimalSplitPosFinal && optimalSplitPosFinal <= maxSplitPos || minSplitPos == maxSplitPos && optimalSplitPosFinal == minSplitPos - 1 : "out of range";
+            assert optimalSplitPosFinal <= interval.to() : "cannot split after end of interval";
+            assert optimalSplitPosFinal > interval.from() : "cannot split at start of interval";
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("splitting at position %d", optimalSplitPosFinal);
+            }
+            assert optimalSplitPosFinal > currentPosition : "Can not split interval " + interval + " at current position: " + currentPosition;
+
+            // was:
+            // assert isBlockBegin || ((optimalSplitPos1 & 1) == 1) :
+            // "split pos must be odd when not on block boundary";
+            // assert !isBlockBegin || ((optimalSplitPos1 & 1) == 0) :
+            // "split pos must be even on block boundary";
+            assert (optimalSplitPosFinal & 1) == 1 : "split pos must be odd";
+
+            // TODO (je) duplicate code. try to fold
+            if (optimalSplitPosFinal == interval.to() && interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos) == Integer.MAX_VALUE) {
+                // the split position would be just before the end of the interval
+                // . no split at all necessary
+                if (Debug.isLogEnabled()) {
+                    Debug.log("no split necessary because optimal split position is at end of interval");
+                }
+                return;
+            }
+            TraceInterval splitPart = interval.split(optimalSplitPosFinal, allocator);
+
+            boolean moveNecessary = true;
+            splitPart.setInsertMoveWhenActivated(moveNecessary);
+
+            assert splitPart.from() >= currentPosition : "cannot append new interval before current walk position";
+            unhandledAnyList.addToListSortedByStartAndUsePositions(splitPart);
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("left interval  %s: %s", moveNecessary ? "      " : "", interval.logString(allocator));
+                Debug.log("right interval %s: %s", moveNecessary ? "(move)" : "", splitPart.logString(allocator));
+            }
+        }
+    }
+
+    // split an interval at the optimal position between minSplitPos and
+    // maxSplitPos in two parts:
+    // 1) the left part has already a location assigned
+    // 2) the right part is always on the stack and therefore ignored in further processing
+    @SuppressWarnings("try")
+    private void splitForSpilling(TraceInterval interval) {
+        // calculate allowed range of splitting position
+        int maxSplitPos = currentPosition;
+        int previousUsage = interval.previousUsage(RegisterPriority.ShouldHaveRegister, maxSplitPos);
+        if (previousUsage == currentPosition) {
+            /*
+             * If there is a usage with ShouldHaveRegister priority at the current position fall
+             * back to MustHaveRegister priority. This only happens if register priority was
+             * downgraded to MustHaveRegister in #allocLockedRegister.
+             */
+            previousUsage = interval.previousUsage(RegisterPriority.MustHaveRegister, maxSplitPos);
+        }
+        int minSplitPos = Math.max(previousUsage + 1, interval.from());
+
+        try (Indent indent = Debug.logAndIndent("splitting and spilling interval %s between %d and %d", interval, minSplitPos, maxSplitPos)) {
+
+            assert interval.state == State.Active : "why spill interval that is not active?";
+            assert interval.from() <= minSplitPos : "cannot split before start of interval";
+            assert minSplitPos <= maxSplitPos : "invalid order";
+            assert maxSplitPos < interval.to() : "cannot split at end end of interval";
+            assert currentPosition < interval.to() : "interval must not end before current position";
+
+            if (minSplitPos == interval.from()) {
+                // the whole interval is never used, so spill it entirely to memory
+
+                try (Indent indent2 = Debug.logAndIndent("spilling entire interval because split pos is at beginning of interval (use positions: %d)", interval.usePosList().size())) {
+
+                    assert interval.firstUsage(RegisterPriority.MustHaveRegister) > currentPosition : String.format("interval %s must not have use position before currentPosition %d", interval,
+                                    currentPosition);
+
+                    allocator.assignSpillSlot(interval);
+                    handleSpillSlot(interval);
+                    changeSpillState(interval, minSplitPos);
+
+                    // Also kick parent intervals out of register to memory when they have no use
+                    // position. This avoids short interval in register surrounded by intervals in
+                    // memory . avoid useless moves from memory to register and back
+                    TraceInterval parent = interval;
+                    while (parent != null && parent.isSplitChild()) {
+                        parent = parent.getSplitChildBeforeOpId(parent.from());
+
+                        if (isRegister(parent.location())) {
+                            if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) {
+                                // parent is never used, so kick it out of its assigned register
+                                if (Debug.isLogEnabled()) {
+                                    Debug.log("kicking out interval %d out of its register because it is never used", parent.operandNumber);
+                                }
+                                allocator.assignSpillSlot(parent);
+                                handleSpillSlot(parent);
+                            } else {
+                                // do not go further back because the register is actually used by
+                                // the interval
+                                parent = null;
+                            }
+                        }
+                    }
+                }
+
+            } else {
+                // search optimal split pos, split interval and spill only the right hand part
+                int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, false);
+
+                assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range";
+                assert optimalSplitPos < interval.to() : "cannot split at end of interval";
+                assert optimalSplitPos >= interval.from() : "cannot split before start of interval";
+
+                if (!allocator.isBlockBegin(optimalSplitPos)) {
+                    // move position before actual instruction (odd opId)
+                    optimalSplitPos = (optimalSplitPos - 1) | 1;
+                }
+
+                try (Indent indent2 = Debug.logAndIndent("splitting at position %d", optimalSplitPos)) {
+                    assert allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 1) : "split pos must be odd when not on block boundary";
+                    assert !allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 0) : "split pos must be even on block boundary";
+
+                    TraceInterval spilledPart = interval.split(optimalSplitPos, allocator);
+                    allocator.assignSpillSlot(spilledPart);
+                    handleSpillSlot(spilledPart);
+                    changeSpillState(spilledPart, optimalSplitPos);
+
+                    if (!allocator.isBlockBegin(optimalSplitPos)) {
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("inserting move from interval %s to %s", interval, spilledPart);
+                        }
+                        insertMove(optimalSplitPos, interval, spilledPart);
+                    } else {
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("no need to insert move. done by data-flow resolution");
+                        }
+                    }
+
+                    // the currentSplitChild is needed later when moves are inserted for reloading
+                    assert spilledPart.currentSplitChild() == interval : "overwriting wrong currentSplitChild";
+                    spilledPart.makeCurrentSplitChild();
+
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("left interval: %s", interval.logString(allocator));
+                        Debug.log("spilled interval   : %s", spilledPart.logString(allocator));
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Change spill state of an interval.
+     *
+     * Note: called during register allocation.
+     *
+     * @param spillPos position of the spill
+     */
+    private void changeSpillState(TraceInterval interval, int spillPos) {
+        if (TraceLinearScan.Options.LIROptTraceRAEliminateSpillMoves.getValue()) {
+            switch (interval.spillState()) {
+                case NoSpillStore:
+                    final int minSpillPos = interval.spillDefinitionPos();
+                    final int maxSpillPost = spillPos;
+
+                    final int optimalSpillPos = findOptimalSpillPos(minSpillPos, maxSpillPost);
+
+                    // assert !allocator.isBlockBegin(optimalSpillPos);
+                    assert !allocator.isBlockEnd(optimalSpillPos);
+                    assert (optimalSpillPos & 1) == 0 : "Spill pos must be even";
+
+                    interval.setSpillDefinitionPos(optimalSpillPos);
+                    interval.setSpillState(SpillState.SpillStore);
+                    break;
+                case SpillStore:
+                case StartInMemory:
+                case NoOptimization:
+                case NoDefinitionFound:
+                    // nothing to do
+                    break;
+
+                default:
+                    throw new BailoutException("other states not allowed at this time");
+            }
+        } else {
+            interval.setSpillState(SpillState.NoOptimization);
+        }
+    }
+
+    /**
+     * @param minSpillPos minimal spill position
+     * @param maxSpillPos maximal spill position
+     */
+    private int findOptimalSpillPos(int minSpillPos, int maxSpillPos) {
+        int optimalSpillPos = findOptimalSpillPos0(minSpillPos, maxSpillPos) & (~1);
+        if (Debug.isLogEnabled()) {
+            Debug.log("optimal spill position: %d", optimalSpillPos);
+        }
+        return optimalSpillPos;
+    }
+
+    private int findOptimalSpillPos0(int minSpillPos, int maxSpillPos) {
+        if (minSpillPos == maxSpillPos) {
+            // trivial case, no optimization of split position possible
+            if (Debug.isLogEnabled()) {
+                Debug.log("min-pos and max-pos are equal, no optimization possible");
+            }
+            return minSpillPos;
+
+        }
+        assert minSpillPos < maxSpillPos : "must be true then";
+        assert minSpillPos >= 0 : "cannot access minSplitPos - 1 otherwise";
+
+        AbstractBlockBase<?> minBlock = allocator.blockForId(minSpillPos);
+        AbstractBlockBase<?> maxBlock = allocator.blockForId(maxSpillPos);
+
+        assert minBlock.getLinearScanNumber() <= maxBlock.getLinearScanNumber() : "invalid order";
+        if (minBlock == maxBlock) {
+            // split position cannot be moved to block boundary : so split as late as possible
+            if (Debug.isLogEnabled()) {
+                Debug.log("cannot move split pos to block boundary because minPos and maxPos are in same block");
+            }
+            return maxSpillPos;
+
+        }
+        // search optimal block boundary between minSplitPos and maxSplitPos
+        if (Debug.isLogEnabled()) {
+            Debug.log("moving split pos to optimal block boundary between block B%d and B%d", minBlock.getId(), maxBlock.getId());
+        }
+
+        // currently using the same heuristic as for splitting
+        return findOptimalSpillPos(minBlock, maxBlock, maxSpillPos);
+    }
+
+    private int findOptimalSpillPos(AbstractBlockBase<?> minBlock, AbstractBlockBase<?> maxBlock, int maxSplitPos) {
+        int fromBlockNr = minBlock.getLinearScanNumber();
+        int toBlockNr = maxBlock.getLinearScanNumber();
+
+        assert 0 <= fromBlockNr && fromBlockNr < blockCount() : "out of range";
+        assert 0 <= toBlockNr && toBlockNr < blockCount() : "out of range";
+        assert fromBlockNr < toBlockNr : "must cross block boundary";
+
+        /*
+         * Try to split at end of maxBlock. If this would be after maxSplitPos, then use the begin
+         * of maxBlock. We use last instruction -2 because we want to insert the move before the
+         * block end op.
+         */
+        int optimalSplitPos = allocator.getLastLirInstructionId(maxBlock) - 2;
+        if (optimalSplitPos > maxSplitPos) {
+            optimalSplitPos = allocator.getFirstLirInstructionId(maxBlock);
+        }
+
+        // minimal block probability
+        double minProbability = maxBlock.probability();
+        for (int i = toBlockNr - 1; i >= fromBlockNr; i--) {
+            AbstractBlockBase<?> cur = blockAt(i);
+
+            if (cur.probability() < minProbability) {
+                // Block with lower probability found. Split at the end of this block.
+                minProbability = cur.probability();
+                optimalSplitPos = allocator.getLastLirInstructionId(cur) - 2;
+            }
+        }
+        assert optimalSplitPos > allocator.maxOpId() || allocator.isBlockBegin(optimalSplitPos) || allocator.isBlockEnd(optimalSplitPos + 2) : "algorithm must move split pos to block boundary";
+
+        return optimalSplitPos;
+    }
+
+    /**
+     * This is called for every interval that is assigned to a stack slot.
+     */
+    private static void handleSpillSlot(TraceInterval interval) {
+        assert interval.location() != null && (interval.canMaterialize() || isStackSlotValue(interval.location())) : "interval not assigned to a stack slot " + interval;
+        // Do nothing. Stack slots are not processed in this implementation.
+    }
+
+    private void splitStackInterval(TraceInterval interval) {
+        int minSplitPos = currentPosition + 1;
+        int maxSplitPos = Math.min(interval.firstUsage(RegisterPriority.ShouldHaveRegister), interval.to());
+
+        splitBeforeUsage(interval, minSplitPos, maxSplitPos);
+    }
+
+    private void splitWhenPartialRegisterAvailable(TraceInterval interval, int registerAvailableUntil) {
+        int minSplitPos = Math.max(interval.previousUsage(RegisterPriority.ShouldHaveRegister, registerAvailableUntil), interval.from() + 1);
+        splitBeforeUsage(interval, minSplitPos, registerAvailableUntil);
+    }
+
+    private void splitAndSpillInterval(TraceInterval interval) {
+        assert interval.state == State.Active || interval.state == State.Inactive : "other states not allowed";
+
+        int currentPos = currentPosition;
+        if (interval.state == State.Inactive) {
+            // the interval is currently inactive, so no spill slot is needed for now.
+            // when the split part is activated, the interval has a new chance to get a register,
+            // so in the best case no stack slot is necessary
+            throw JVMCIError.shouldNotReachHere("TraceIntervals can not be inactive!");
+
+        } else {
+            // search the position where the interval must have a register and split
+            // at the optimal position before.
+            // The new created part is added to the unhandled list and will get a register
+            // when it is activated
+            int minSplitPos = currentPos + 1;
+            int maxSplitPos = interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos);
+
+            if (maxSplitPos <= interval.to()) {
+                splitBeforeUsage(interval, minSplitPos, maxSplitPos);
+            } else {
+                Debug.log("No more usage, no need to split: %s", interval);
+            }
+
+            assert interval.nextUsage(RegisterPriority.MustHaveRegister, currentPos) == Integer.MAX_VALUE : "the remaining part is spilled to stack and therefore has no register";
+            splitForSpilling(interval);
+        }
+    }
+
+    @SuppressWarnings("try")
+    private boolean allocFreeRegister(TraceInterval interval) {
+        try (Indent indent = Debug.logAndIndent("trying to find free register for %s", interval)) {
+
+            initUseLists(true);
+            freeExcludeActiveFixed();
+            freeCollectInactiveFixed(interval);
+            freeExcludeActiveAny();
+            // freeCollectUnhandled(fixedKind, cur);
+
+            // usePos contains the start of the next interval that has this register assigned
+            // (either as a fixed register or a normal allocated register in the past)
+            // only intervals overlapping with cur are processed, non-overlapping invervals can be
+            // ignored safely
+            if (Debug.isLogEnabled()) {
+                // Enable this logging to see all register states
+                try (Indent indent2 = Debug.logAndIndent("state of registers:")) {
+                    for (Register register : availableRegs) {
+                        int i = register.number;
+                        Debug.log("reg %d (%s): usePos: %d", register.number, register, usePos[i]);
+                    }
+                }
+            }
+
+            Register hint = null;
+            IntervalHint locationHint = interval.locationHint(true);
+            if (locationHint != null && locationHint.location() != null && isRegister(locationHint.location())) {
+                hint = asRegister(locationHint.location());
+                if (Debug.isLogEnabled()) {
+                    Debug.log("hint register %3d (%4s) from interval %s", hint.number, hint, locationHint);
+                }
+            }
+            assert interval.location() == null : "register already assigned to interval";
+
+            // the register must be free at least until this position
+            int regNeededUntil = interval.from() + 1;
+            int intervalTo = interval.to();
+
+            boolean needSplit = false;
+            int splitPos = -1;
+
+            Register reg = null;
+            Register minFullReg = null;
+            Register maxPartialReg = null;
+
+            for (Register availableReg : availableRegs) {
+                int number = availableReg.number;
+                if (usePos[number] >= intervalTo) {
+                    // this register is free for the full interval
+                    if (minFullReg == null || availableReg.equals(hint) || (usePos[number] < usePos[minFullReg.number] && !minFullReg.equals(hint))) {
+                        minFullReg = availableReg;
+                    }
+                } else if (usePos[number] > regNeededUntil) {
+                    // this register is at least free until regNeededUntil
+                    if (maxPartialReg == null || availableReg.equals(hint) || (usePos[number] > usePos[maxPartialReg.number] && !maxPartialReg.equals(hint))) {
+                        maxPartialReg = availableReg;
+                    }
+                }
+            }
+
+            if (minFullReg != null) {
+                reg = minFullReg;
+            } else if (maxPartialReg != null) {
+                needSplit = true;
+                reg = maxPartialReg;
+            } else {
+                return false;
+            }
+
+            splitPos = usePos[reg.number];
+            interval.assignLocation(reg.asValue(interval.kind()));
+            if (Debug.isLogEnabled()) {
+                Debug.log("selected register %d (%s)", reg.number, reg);
+            }
+
+            assert splitPos > 0 : "invalid splitPos";
+            if (needSplit) {
+                // register not available for full interval, so split it
+                splitWhenPartialRegisterAvailable(interval, splitPos);
+            }
+            // only return true if interval is completely assigned
+            return true;
+        }
+    }
+
+    private void splitAndSpillIntersectingIntervals(Register reg) {
+        assert reg != null : "no register assigned";
+
+        for (int i = 0; i < spillIntervals[reg.number].size(); i++) {
+            TraceInterval interval = spillIntervals[reg.number].get(i);
+            removeFromList(interval);
+            splitAndSpillInterval(interval);
+        }
+    }
+
+    // Split an Interval and spill it to memory so that cur can be placed in a register
+    @SuppressWarnings("try")
+    private void allocLockedRegister(TraceInterval interval) {
+        try (Indent indent = Debug.logAndIndent("alloc locked register: need to split and spill to get register for %s", interval)) {
+
+            // the register must be free at least until this position
+            int firstUsage = interval.firstUsage(RegisterPriority.MustHaveRegister);
+            int firstShouldHaveUsage = interval.firstUsage(RegisterPriority.ShouldHaveRegister);
+            int regNeededUntil = Math.min(firstUsage, interval.from() + 1);
+            int intervalTo = interval.to();
+            assert regNeededUntil >= 0 && regNeededUntil < Integer.MAX_VALUE : "interval has no use";
+
+            Register reg;
+            Register ignore;
+            /*
+             * In the common case we don't spill registers that have _any_ use position that is
+             * closer than the next use of the current interval, but if we can't spill the current
+             * interval we weaken this strategy and also allow spilling of intervals that have a
+             * non-mandatory requirements (no MustHaveRegister use position).
+             */
+            for (RegisterPriority registerPriority = RegisterPriority.LiveAtLoopEnd; true; registerPriority = RegisterPriority.MustHaveRegister) {
+                // collect current usage of registers
+                initUseLists(false);
+                spillExcludeActiveFixed();
+                // spillBlockUnhandledFixed(cur);
+                spillBlockInactiveFixed(interval);
+                spillCollectActiveAny(registerPriority);
+                if (Debug.isLogEnabled()) {
+                    printRegisterState();
+                }
+
+                reg = null;
+                ignore = interval.location() != null && isRegister(interval.location()) ? asRegister(interval.location()) : null;
+
+                for (Register availableReg : availableRegs) {
+                    int number = availableReg.number;
+                    if (availableReg.equals(ignore)) {
+                        // this register must be ignored
+                    } else if (usePos[number] > regNeededUntil) {
+                        /*
+                         * If the use position is the same, prefer registers (active intervals)
+                         * where the value is already on the stack.
+                         */
+                        if (reg == null || (usePos[number] > usePos[reg.number]) || (usePos[number] == usePos[reg.number] && (!isInMemory.get(reg.number) && isInMemory.get(number)))) {
+                            reg = availableReg;
+                        }
+                    }
+                }
+
+                if (Debug.isLogEnabled()) {
+                    Debug.log("Register Selected: %s", reg);
+                }
+
+                int regUsePos = (reg == null ? 0 : usePos[reg.number]);
+                if (regUsePos <= firstShouldHaveUsage) {
+                    /* Check if there is another interval that is already in memory. */
+                    if (reg == null || interval.inMemoryAt(currentPosition) || !isInMemory.get(reg.number)) {
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("able to spill current interval. firstUsage(register): %d, usePos: %d", firstUsage, regUsePos);
+                        }
+
+                        if (firstUsage <= interval.from() + 1) {
+                            if (registerPriority.equals(RegisterPriority.LiveAtLoopEnd)) {
+                                /*
+                                 * Tool of last resort: we can not spill the current interval so we
+                                 * try to spill an active interval that has a usage but do not
+                                 * require a register.
+                                 */
+                                Debug.log("retry with register priority must have register");
+                                continue;
+                            }
+                            String description = "cannot spill interval (" + interval + ") that is used in first instruction (possible reason: no register found) firstUsage=" + firstUsage +
+                                            ", interval.from()=" + interval.from() + "; already used candidates: " + Arrays.toString(availableRegs);
+                            /*
+                             * assign a reasonable register and do a bailout in product mode to
+                             * avoid errors
+                             */
+                            allocator.assignSpillSlot(interval);
+                            Debug.dump(allocator.getLIR(), description);
+                            allocator.printIntervals(description);
+                            throw new OutOfRegistersException("LinearScan: no register found", description);
+                        }
+
+                        splitAndSpillInterval(interval);
+                        return;
+                    }
+                }
+                // common case: break out of the loop
+                break;
+            }
+
+            boolean needSplit = blockPos[reg.number] <= intervalTo;
+
+            int splitPos = blockPos[reg.number];
+
+            if (Debug.isLogEnabled()) {
+                Debug.log("decided to use register %d", reg.number);
+            }
+            assert splitPos > 0 : "invalid splitPos";
+            assert needSplit || splitPos > interval.from() : "splitting interval at from";
+
+            interval.assignLocation(reg.asValue(interval.kind()));
+            if (needSplit) {
+                // register not available for full interval : so split it
+                splitWhenPartialRegisterAvailable(interval, splitPos);
+            }
+
+            // perform splitting and spilling for all affected intervals
+            splitAndSpillIntersectingIntervals(reg);
+            return;
+        }
+    }
+
+    @SuppressWarnings("try")
+    private void printRegisterState() {
+        try (Indent indent2 = Debug.logAndIndent("state of registers:")) {
+            for (Register reg : availableRegs) {
+                int i = reg.number;
+                try (Indent indent3 = Debug.logAndIndent("reg %d: usePos: %d, blockPos: %d, inMemory: %b, intervals: ", i, usePos[i], blockPos[i], isInMemory.get(i))) {
+                    for (int j = 0; j < spillIntervals[i].size(); j++) {
+                        Debug.log("%s", spillIntervals[i].get(j));
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean noAllocationPossible(TraceInterval interval) {
+        if (allocator.callKillsRegisters()) {
+            // fast calculation of intervals that can never get a register because the
+            // the next instruction is a call that blocks all registers
+            // Note: this only works if a call kills all registers
+
+            // check if this interval is the result of a split operation
+            // (an interval got a register until this position)
+            int pos = interval.from();
+            if (isOdd(pos)) {
+                // the current instruction is a call that blocks all registers
+                if (pos < allocator.maxOpId() && allocator.hasCall(pos + 1) && interval.to() > pos + 1) {
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("free register cannot be available because all registers blocked by following call");
+                    }
+
+                    // safety check that there is really no register available
+                    assert !allocFreeRegister(interval) : "found a register for this interval";
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private void initVarsForAlloc(TraceInterval interval) {
+        AllocatableRegisters allocatableRegisters = allocator.getRegisterAllocationConfig().getAllocatableRegisters(interval.kind().getPlatformKind());
+        availableRegs = allocatableRegisters.allocatableRegisters;
+        minReg = allocatableRegisters.minRegisterNumber;
+        maxReg = allocatableRegisters.maxRegisterNumber;
+    }
+
+    private static boolean isMove(LIRInstruction op, TraceInterval from, TraceInterval to) {
+        if (op instanceof ValueMoveOp) {
+            ValueMoveOp move = (ValueMoveOp) op;
+            if (isVariable(move.getInput()) && isVariable(move.getResult())) {
+                return move.getInput() != null && move.getInput().equals(from.operand) && move.getResult() != null && move.getResult().equals(to.operand);
+            }
+        }
+        return false;
+    }
+
+    // optimization (especially for phi functions of nested loops):
+    // assign same spill slot to non-intersecting intervals
+    private void combineSpilledIntervals(TraceInterval interval) {
+        if (interval.isSplitChild()) {
+            // optimization is only suitable for split parents
+            return;
+        }
+
+        IntervalHint locationHint = interval.locationHint(false);
+        if (locationHint == null || !(locationHint instanceof TraceInterval)) {
+            return;
+        }
+        TraceInterval registerHint = (TraceInterval) locationHint;
+        assert registerHint.isSplitParent() : "register hint must be split parent";
+
+        if (interval.spillState() != SpillState.NoOptimization || registerHint.spillState() != SpillState.NoOptimization) {
+            // combining the stack slots for intervals where spill move optimization is applied
+            // is not benefitial and would cause problems
+            return;
+        }
+
+        int beginPos = interval.from();
+        int endPos = interval.to();
+        if (endPos > allocator.maxOpId() || isOdd(beginPos) || isOdd(endPos)) {
+            // safety check that lirOpWithId is allowed
+            return;
+        }
+
+        if (!isMove(allocator.instructionForId(beginPos), registerHint, interval) || !isMove(allocator.instructionForId(endPos), interval, registerHint)) {
+            // cur and registerHint are not connected with two moves
+            return;
+        }
+
+        TraceInterval beginHint = registerHint.getSplitChildAtOpId(beginPos, LIRInstruction.OperandMode.USE, allocator);
+        TraceInterval endHint = registerHint.getSplitChildAtOpId(endPos, LIRInstruction.OperandMode.DEF, allocator);
+        if (beginHint == endHint || beginHint.to() != beginPos || endHint.from() != endPos) {
+            // registerHint must be split : otherwise the re-writing of use positions does not work
+            return;
+        }
+
+        assert beginHint.location() != null : "must have register assigned";
+        assert endHint.location() == null : "must not have register assigned";
+        assert interval.firstUsage(RegisterPriority.MustHaveRegister) == beginPos : "must have use position at begin of interval because of move";
+        assert endHint.firstUsage(RegisterPriority.MustHaveRegister) == endPos : "must have use position at begin of interval because of move";
+
+        if (isRegister(beginHint.location())) {
+            // registerHint is not spilled at beginPos : so it would not be benefitial to
+            // immediately spill cur
+            return;
+        }
+        assert registerHint.spillSlot() != null : "must be set when part of interval was spilled";
+
+        // modify intervals such that cur gets the same stack slot as registerHint
+        // delete use positions to prevent the intervals to get a register at beginning
+        interval.setSpillSlot(registerHint.spillSlot());
+        interval.removeFirstUsePos();
+        endHint.removeFirstUsePos();
+    }
+
+    // allocate a physical register or memory location to an interval
+    @Override
+    @SuppressWarnings("try")
+    protected boolean activateCurrent(TraceInterval interval) {
+        if (Debug.isLogEnabled()) {
+            logCurrentStatus();
+        }
+        boolean result = true;
+
+        try (Indent indent = Debug.logAndIndent("activating interval %s,  splitParent: %d", interval, interval.splitParent().operandNumber)) {
+
+            final Value operand = interval.operand;
+            if (interval.location() != null && isStackSlotValue(interval.location())) {
+                // activating an interval that has a stack slot assigned . split it at first use
+                // position
+                // used for method parameters
+                if (Debug.isLogEnabled()) {
+                    Debug.log("interval has spill slot assigned (method parameter) . split it before first use");
+                }
+                splitStackInterval(interval);
+                result = false;
+
+            } else {
+                if (interval.location() == null) {
+                    // interval has not assigned register . normal allocation
+                    // (this is the normal case for most intervals)
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("normal allocation of register");
+                    }
+
+                    // assign same spill slot to non-intersecting intervals
+                    combineSpilledIntervals(interval);
+
+                    initVarsForAlloc(interval);
+                    if (noAllocationPossible(interval) || !allocFreeRegister(interval)) {
+                        // no empty register available.
+                        // split and spill another interval so that this interval gets a register
+                        allocLockedRegister(interval);
+                    }
+
+                    // spilled intervals need not be move to active-list
+                    if (!isRegister(interval.location())) {
+                        result = false;
+                    }
+                }
+            }
+
+            // load spilled values that become active from stack slot to register
+            if (interval.insertMoveWhenActivated()) {
+                assert interval.isSplitChild();
+                assert interval.currentSplitChild() != null;
+                assert !interval.currentSplitChild().operand.equals(operand) : "cannot insert move between same interval";
+                if (Debug.isLogEnabled()) {
+                    Debug.log("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber);
+                }
+
+                insertMove(interval.from(), interval.currentSplitChild(), interval);
+            }
+            interval.makeCurrentSplitChild();
+
+        }
+
+        return result; // true = interval is moved to active list
+    }
+
+    void finishAllocation() {
+        // must be called when all intervals are allocated
+        moveResolver.resolveAndAppendMoves();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/TraceLocalMoveResolver.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,553 @@
+/*
+ * Copyright (c) 2009, 2015, 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.alloc.trace.lsra;
+
+import static com.oracle.graal.lir.LIRValueUtil.asVirtualStackSlot;
+import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
+import static com.oracle.graal.lir.LIRValueUtil.isVirtualStackSlot;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isIllegal;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.LIRKind;
+import jdk.vm.ci.meta.Value;
+
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.Indent;
+import com.oracle.graal.lir.LIRInsertionBuffer;
+import com.oracle.graal.lir.LIRInstruction;
+import com.oracle.graal.lir.VirtualStackSlot;
+import com.oracle.graal.lir.framemap.FrameMap;
+import com.oracle.graal.lir.framemap.FrameMapBuilderTool;
+
+/**
+ */
+final class TraceLocalMoveResolver {
+
+    private static final int STACK_SLOT_IN_CALLER_FRAME_IDX = -1;
+    private final TraceLinearScan allocator;
+
+    private int insertIdx;
+    private LIRInsertionBuffer insertionBuffer; // buffer where moves are inserted
+
+    private final List<TraceInterval> mappingFrom;
+    private final List<Constant> mappingFromOpr;
+    private final List<TraceInterval> mappingTo;
+    private final int[] registerBlocked;
+
+    private int[] stackBlocked;
+    private final int firstVirtualStackIndex;
+
+    private int getStackArrayIndex(Value stackSlotValue) {
+        if (isStackSlot(stackSlotValue)) {
+            return getStackArrayIndex(asStackSlot(stackSlotValue));
+        }
+        if (isVirtualStackSlot(stackSlotValue)) {
+            return getStackArrayIndex(asVirtualStackSlot(stackSlotValue));
+        }
+        throw JVMCIError.shouldNotReachHere("value is not a stack slot: " + stackSlotValue);
+    }
+
+    private int getStackArrayIndex(StackSlot stackSlot) {
+        int stackIdx;
+        if (stackSlot.isInCallerFrame()) {
+            // incoming stack arguments can be ignored
+            stackIdx = STACK_SLOT_IN_CALLER_FRAME_IDX;
+        } else {
+            assert stackSlot.getRawAddFrameSize() : "Unexpected stack slot: " + stackSlot;
+            int offset = -stackSlot.getRawOffset();
+            assert 0 <= offset && offset < firstVirtualStackIndex : String.format("Wrong stack slot offset: %d (first virtual stack slot index: %d", offset, firstVirtualStackIndex);
+            stackIdx = offset;
+        }
+        return stackIdx;
+    }
+
+    private int getStackArrayIndex(VirtualStackSlot virtualStackSlot) {
+        return firstVirtualStackIndex + virtualStackSlot.getId();
+    }
+
+    protected void setValueBlocked(Value location, int direction) {
+        assert direction == 1 || direction == -1 : "out of bounds";
+        if (isStackSlotValue(location)) {
+            int stackIdx = getStackArrayIndex(location);
+            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
+                // incoming stack arguments can be ignored
+                return;
+            }
+            if (stackIdx >= stackBlocked.length) {
+                stackBlocked = Arrays.copyOf(stackBlocked, stackIdx + 1);
+            }
+            stackBlocked[stackIdx] += direction;
+        } else {
+            assert direction == 1 || direction == -1 : "out of bounds";
+            if (isRegister(location)) {
+                registerBlocked[asRegister(location).number] += direction;
+            } else {
+                throw JVMCIError.shouldNotReachHere("unhandled value " + location);
+            }
+        }
+    }
+
+    protected TraceInterval getMappingFrom(int i) {
+        return mappingFrom.get(i);
+    }
+
+    protected int mappingFromSize() {
+        return mappingFrom.size();
+    }
+
+    protected int valueBlocked(Value location) {
+        if (isStackSlotValue(location)) {
+            int stackIdx = getStackArrayIndex(location);
+            if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) {
+                // incoming stack arguments are always blocked (aka they can not be written)
+                return 1;
+            }
+            if (stackIdx >= stackBlocked.length) {
+                return 0;
+            }
+            return stackBlocked[stackIdx];
+        }
+        if (isRegister(location)) {
+            return registerBlocked[asRegister(location).number];
+        }
+        throw JVMCIError.shouldNotReachHere("unhandled value " + location);
+    }
+
+    /*
+     * TODO (je) remove?
+     */
+    protected static boolean areMultipleReadsAllowed() {
+        return true;
+    }
+
+    boolean hasMappings() {
+        return mappingFrom.size() > 0;
+    }
+
+    protected TraceLinearScan getAllocator() {
+        return allocator;
+    }
+
+    protected TraceLocalMoveResolver(TraceLinearScan allocator) {
+
+        this.allocator = allocator;
+        this.mappingFrom = new ArrayList<>(8);
+        this.mappingFromOpr = new ArrayList<>(8);
+        this.mappingTo = new ArrayList<>(8);
+        this.insertIdx = -1;
+        this.insertionBuffer = new LIRInsertionBuffer();
+        this.registerBlocked = new int[allocator.getRegisters().length];
+        FrameMapBuilderTool frameMapBuilderTool = (FrameMapBuilderTool) allocator.getFrameMapBuilder();
+        FrameMap frameMap = frameMapBuilderTool.getFrameMap();
+        this.stackBlocked = new int[frameMapBuilderTool.getNumberOfStackSlots()];
+        this.firstVirtualStackIndex = !frameMap.frameNeedsAllocating() ? 0 : frameMap.currentFrameSize() + 1;
+    }
+
+    protected boolean checkEmpty() {
+        assert mappingFrom.size() == 0 && mappingFromOpr.size() == 0 && mappingTo.size() == 0 : "list must be empty before and after processing";
+        for (int i = 0; i < stackBlocked.length; i++) {
+            assert stackBlocked[i] == 0 : "stack map must be empty before and after processing";
+        }
+        for (int i = 0; i < getAllocator().getRegisters().length; i++) {
+            assert registerBlocked[i] == 0 : "register map must be empty before and after processing";
+        }
+        checkMultipleReads();
+        return true;
+    }
+
+    protected void checkMultipleReads() {
+        // multiple reads are allowed in SSA LSRA
+    }
+
+    private boolean verifyBeforeResolve() {
+        assert mappingFrom.size() == mappingFromOpr.size() : "length must be equal";
+        assert mappingFrom.size() == mappingTo.size() : "length must be equal";
+        assert insertIdx != -1 : "insert position not set";
+
+        int i;
+        int j;
+        if (!areMultipleReadsAllowed()) {
+            for (i = 0; i < mappingFrom.size(); i++) {
+                for (j = i + 1; j < mappingFrom.size(); j++) {
+                    assert mappingFrom.get(i) == null || mappingFrom.get(i) != mappingFrom.get(j) : "cannot read from same interval twice";
+                }
+            }
+        }
+
+        for (i = 0; i < mappingTo.size(); i++) {
+            for (j = i + 1; j < mappingTo.size(); j++) {
+                assert mappingTo.get(i) != mappingTo.get(j) : "cannot write to same interval twice";
+            }
+        }
+
+        HashSet<Value> usedRegs = new HashSet<>();
+        if (!areMultipleReadsAllowed()) {
+            for (i = 0; i < mappingFrom.size(); i++) {
+                TraceInterval interval = mappingFrom.get(i);
+                if (interval != null && !isIllegal(interval.location())) {
+                    boolean unique = usedRegs.add(interval.location());
+                    assert unique : "cannot read from same register twice";
+                }
+            }
+        }
+
+        usedRegs.clear();
+        for (i = 0; i < mappingTo.size(); i++) {
+            TraceInterval interval = mappingTo.get(i);
+            if (isIllegal(interval.location())) {
+                // After insertion the location may become illegal, so don't check it since multiple
+                // intervals might be illegal.
+                continue;
+            }
+            boolean unique = usedRegs.add(interval.location());
+            assert unique : "cannot write to same register twice";
+        }
+
+        verifyStackSlotMapping();
+
+        return true;
+    }
+
+    protected void verifyStackSlotMapping() {
+        // relax disjoint stack maps invariant
+    }
+
+    // mark assignedReg and assignedRegHi of the interval as blocked
+    private void blockRegisters(TraceInterval interval) {
+        Value location = interval.location();
+        if (mightBeBlocked(location)) {
+            assert areMultipleReadsAllowed() || valueBlocked(location) == 0 : "location already marked as used: " + location;
+            int direction = 1;
+            setValueBlocked(location, direction);
+            Debug.log("block %s", location);
+        }
+    }
+
+    // mark assignedReg and assignedRegHi of the interval as unblocked
+    private void unblockRegisters(TraceInterval interval) {
+        Value location = interval.location();
+        if (mightBeBlocked(location)) {
+            assert valueBlocked(location) > 0 : "location already marked as unused: " + location;
+            setValueBlocked(location, -1);
+            Debug.log("unblock %s", location);
+        }
+    }
+
+    /**
+     * Checks if the {@linkplain TraceInterval#location() location} of {@code to} is not blocked or
+     * is only blocked by {@code from}.
+     */
+    private boolean safeToProcessMove(TraceInterval from, TraceInterval to) {
+        Value fromReg = from != null ? from.location() : null;
+
+        Value location = to.location();
+        if (mightBeBlocked(location)) {
+            if ((valueBlocked(location) > 1 || (valueBlocked(location) == 1 && !isMoveToSelf(fromReg, location)))) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    protected static boolean isMoveToSelf(Value from, Value to) {
+        assert to != null;
+        if (to.equals(from)) {
+            return true;
+        }
+        if (from != null && isRegister(from) && isRegister(to) && asRegister(from).equals(asRegister(to))) {
+            assert LIRKind.verifyMoveKinds(to.getLIRKind(), from.getLIRKind()) : String.format("Same register but Kind mismatch %s <- %s", to, from);
+            return true;
+        }
+        return false;
+    }
+
+    protected static boolean mightBeBlocked(Value location) {
+        if (isRegister(location)) {
+            return true;
+        }
+        if (isStackSlotValue(location)) {
+            return true;
+        }
+        return false;
+    }
+
+    private void createInsertionBuffer(List<LIRInstruction> list) {
+        assert !insertionBuffer.initialized() : "overwriting existing buffer";
+        insertionBuffer.init(list);
+    }
+
+    private void appendInsertionBuffer() {
+        if (insertionBuffer.initialized()) {
+            insertionBuffer.finish();
+        }
+        assert !insertionBuffer.initialized() : "must be uninitialized now";
+
+        insertIdx = -1;
+    }
+
+    private void insertMove(TraceInterval fromInterval, TraceInterval toInterval) {
+        assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
+        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : "move between different types";
+        assert insertIdx != -1 : "must setup insert position first";
+
+        insertionBuffer.append(insertIdx, createMove(fromInterval.operand, toInterval.operand, fromInterval.location(), toInterval.location()));
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("insert move from %s to %s at %d", fromInterval, toInterval, insertIdx);
+        }
+    }
+
+    /**
+     * @param fromOpr {@link TraceInterval#operand operand} of the {@code from} interval
+     * @param toOpr {@link TraceInterval#operand operand} of the {@code to} interval
+     * @param fromLocation {@link TraceInterval#location() location} of the {@code to} interval
+     * @param toLocation {@link TraceInterval#location() location} of the {@code to} interval
+     */
+    protected LIRInstruction createMove(AllocatableValue fromOpr, AllocatableValue toOpr, AllocatableValue fromLocation, AllocatableValue toLocation) {
+        if (isStackSlotValue(toLocation) && isStackSlotValue(fromLocation)) {
+            return getAllocator().getSpillMoveFactory().createStackMove(toOpr, fromOpr);
+        }
+        return getAllocator().getSpillMoveFactory().createMove(toOpr, fromOpr);
+    }
+
+    private void insertMove(Constant fromOpr, TraceInterval toInterval) {
+        assert insertIdx != -1 : "must setup insert position first";
+
+        AllocatableValue toOpr = toInterval.operand;
+        LIRInstruction move = getAllocator().getSpillMoveFactory().createLoad(toOpr, fromOpr);
+        insertionBuffer.append(insertIdx, move);
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("insert move from value %s to %s at %d", fromOpr, toInterval, insertIdx);
+        }
+    }
+
+    @SuppressWarnings("try")
+    private void resolveMappings() {
+        try (Indent indent = Debug.logAndIndent("resolveMapping")) {
+            assert verifyBeforeResolve();
+            if (Debug.isLogEnabled()) {
+                printMapping();
+            }
+
+            // Block all registers that are used as input operands of a move.
+            // When a register is blocked, no move to this register is emitted.
+            // This is necessary for detecting cycles in moves.
+            int i;
+            for (i = mappingFrom.size() - 1; i >= 0; i--) {
+                TraceInterval fromInterval = mappingFrom.get(i);
+                if (fromInterval != null) {
+                    blockRegisters(fromInterval);
+                }
+            }
+
+            int spillCandidate = -1;
+            while (mappingFrom.size() > 0) {
+                boolean processedInterval = false;
+
+                for (i = mappingFrom.size() - 1; i >= 0; i--) {
+                    TraceInterval fromInterval = mappingFrom.get(i);
+                    TraceInterval toInterval = mappingTo.get(i);
+
+                    if (safeToProcessMove(fromInterval, toInterval)) {
+                        // this interval can be processed because target is free
+                        if (fromInterval != null) {
+                            insertMove(fromInterval, toInterval);
+                            unblockRegisters(fromInterval);
+                        } else {
+                            insertMove(mappingFromOpr.get(i), toInterval);
+                        }
+                        mappingFrom.remove(i);
+                        mappingFromOpr.remove(i);
+                        mappingTo.remove(i);
+
+                        processedInterval = true;
+                    } else if (fromInterval != null && isRegister(fromInterval.location())) {
+                        // this interval cannot be processed now because target is not free
+                        // it starts in a register, so it is a possible candidate for spilling
+                        spillCandidate = i;
+                    }
+                }
+
+                if (!processedInterval) {
+                    breakCycle(spillCandidate);
+                }
+            }
+        }
+
+        // check that all intervals have been processed
+        assert checkEmpty();
+    }
+
+    protected void breakCycle(int spillCandidate) {
+        if (spillCandidate != -1) {
+            // no move could be processed because there is a cycle in the move list
+            // (e.g. r1 . r2, r2 . r1), so one interval must be spilled to memory
+            assert spillCandidate != -1 : "no interval in register for spilling found";
+
+            // create a new spill interval and assign a stack slot to it
+            TraceInterval fromInterval1 = mappingFrom.get(spillCandidate);
+            // do not allocate a new spill slot for temporary interval, but
+            // use spill slot assigned to fromInterval. Otherwise moves from
+            // one stack slot to another can happen (not allowed by LIRAssembler
+            AllocatableValue spillSlot1 = fromInterval1.spillSlot();
+            if (spillSlot1 == null) {
+                spillSlot1 = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval1.kind());
+                fromInterval1.setSpillSlot(spillSlot1);
+            }
+            spillInterval(spillCandidate, fromInterval1, spillSlot1);
+            return;
+        }
+        assert mappingFromSize() > 1;
+        // Arbitrarily select the first entry for spilling.
+        int stackSpillCandidate = 0;
+        TraceInterval fromInterval = getMappingFrom(stackSpillCandidate);
+        assert isStackSlotValue(fromInterval.location());
+        // allocate new stack slot
+        VirtualStackSlot spillSlot = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval.kind());
+        spillInterval(stackSpillCandidate, fromInterval, spillSlot);
+    }
+
+    protected void spillInterval(int spillCandidate, TraceInterval fromInterval, AllocatableValue spillSlot) {
+        assert mappingFrom.get(spillCandidate).equals(fromInterval);
+        TraceInterval spillInterval = getAllocator().createDerivedInterval(fromInterval);
+        spillInterval.setKind(fromInterval.kind());
+
+        // add a dummy range because real position is difficult to calculate
+        // Note: this range is a special case when the integrity of the allocation is
+        // checked
+        spillInterval.addRange(1, 2);
+
+        spillInterval.assignLocation(spillSlot);
+
+        if (Debug.isLogEnabled()) {
+            Debug.log("created new Interval for spilling: %s", spillInterval);
+        }
+        blockRegisters(spillInterval);
+
+        // insert a move from register to stack and update the mapping
+        insertMove(fromInterval, spillInterval);
+        mappingFrom.set(spillCandidate, spillInterval);
+        unblockRegisters(fromInterval);
+    }
+
+    @SuppressWarnings("try")
+    private void printMapping() {
+        try (Indent indent = Debug.logAndIndent("Mapping")) {
+            for (int i = mappingFrom.size() - 1; i >= 0; i--) {
+                TraceInterval fromInterval = mappingFrom.get(i);
+                TraceInterval toInterval = mappingTo.get(i);
+                String from;
+                Value to = toInterval.location();
+                if (fromInterval == null) {
+                    from = mappingFromOpr.get(i).toString();
+                } else {
+                    from = fromInterval.location().toString();
+                }
+                Debug.log("move %s <- %s", from, to);
+            }
+        }
+    }
+
+    void setInsertPosition(List<LIRInstruction> insertList, int insertIdx) {
+        assert this.insertIdx == -1 : "use moveInsertPosition instead of setInsertPosition when data already set";
+
+        createInsertionBuffer(insertList);
+        this.insertIdx = insertIdx;
+    }
+
+    void moveInsertPosition(List<LIRInstruction> newInsertList, int newInsertIdx) {
+        if (insertionBuffer.lirList() != null && (insertionBuffer.lirList() != newInsertList || this.insertIdx != newInsertIdx)) {
+            // insert position changed . resolve current mappings
+            resolveMappings();
+        }
+
+        assert insertionBuffer.lirList() != newInsertList || newInsertIdx >= insertIdx : String.format("Decreasing insert index: old=%d new=%d", insertIdx, newInsertIdx);
+
+        if (insertionBuffer.lirList() != newInsertList) {
+            // block changed . append insertionBuffer because it is
+            // bound to a specific block and create a new insertionBuffer
+            appendInsertionBuffer();
+            createInsertionBuffer(newInsertList);
+        }
+
+        this.insertIdx = newInsertIdx;
+    }
+
+    public void addMapping(TraceInterval fromInterval, TraceInterval toInterval) {
+
+        if (isIllegal(toInterval.location()) && toInterval.canMaterialize()) {
+            if (Debug.isLogEnabled()) {
+                Debug.log("no store to rematerializable interval %s needed", toInterval);
+            }
+            return;
+        }
+        if (isIllegal(fromInterval.location()) && fromInterval.canMaterialize()) {
+            // Instead of a reload, re-materialize the value
+            JavaConstant rematValue = fromInterval.getMaterializedValue();
+            addMapping(rematValue, toInterval);
+            return;
+        }
+        if (Debug.isLogEnabled()) {
+            Debug.log("add move mapping from %s to %s", fromInterval, toInterval);
+        }
+
+        assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
+        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", fromInterval.kind(), toInterval.kind(), fromInterval,
+                        toInterval);
+        mappingFrom.add(fromInterval);
+        mappingFromOpr.add(null);
+        mappingTo.add(toInterval);
+    }
+
+    public void addMapping(Constant fromOpr, TraceInterval toInterval) {
+        if (Debug.isLogEnabled()) {
+            Debug.log("add move mapping from %s to %s", fromOpr, toInterval);
+        }
+
+        mappingFrom.add(null);
+        mappingFromOpr.add(fromOpr);
+        mappingTo.add(toInterval);
+    }
+
+    void resolveAndAppendMoves() {
+        if (hasMappings()) {
+            resolveMappings();
+        }
+        appendInsertionBuffer();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/UsePosList.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2015, 2015, 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.alloc.trace.lsra;
+
+import com.oracle.graal.compiler.common.util.IntList;
+import com.oracle.graal.lir.alloc.trace.lsra.TraceInterval.RegisterPriority;
+
+/**
+ * List of use positions. Each entry in the list records the use position and register priority
+ * associated with the use position. The entries in the list are in descending order of use
+ * position.
+ *
+ */
+public final class UsePosList {
+
+    private IntList list;
+
+    /**
+     * Creates a use list.
+     *
+     * @param initialCapacity the initial capacity of the list in terms of entries
+     */
+    public UsePosList(int initialCapacity) {
+        list = new IntList(initialCapacity * 2);
+    }
+
+    private UsePosList(IntList list) {
+        this.list = list;
+    }
+
+    /**
+     * Splits this list around a given position. All entries in this list with a use position
+     * greater or equal than {@code splitPos} are removed from this list and added to the returned
+     * list.
+     *
+     * @param splitPos the position for the split
+     * @return a use position list containing all entries removed from this list that have a use
+     *         position greater or equal than {@code splitPos}
+     */
+    public UsePosList splitAt(int splitPos) {
+        int i = size() - 1;
+        int len = 0;
+        while (i >= 0 && usePos(i) < splitPos) {
+            --i;
+            len += 2;
+        }
+        int listSplitIndex = (i + 1) * 2;
+        IntList childList = list;
+        list = IntList.copy(this.list, listSplitIndex, len);
+        childList.setSize(listSplitIndex);
+        UsePosList child = new UsePosList(childList);
+        return child;
+    }
+
+    /**
+     * Gets the use position at a specified index in this list.
+     *
+     * @param index the index of the entry for which the use position is returned
+     * @return the use position of entry {@code index} in this list
+     */
+    public int usePos(int index) {
+        return list.get(index << 1);
+    }
+
+    /**
+     * Gets the register priority for the use position at a specified index in this list.
+     *
+     * @param index the index of the entry for which the register priority is returned
+     * @return the register priority of entry {@code index} in this list
+     */
+    public RegisterPriority registerPriority(int index) {
+        return RegisterPriority.VALUES[list.get((index << 1) + 1)];
+    }
+
+    public void add(int usePos, RegisterPriority registerPriority) {
+        assert list.size() == 0 || usePos(size() - 1) > usePos;
+        list.add(usePos);
+        list.add(registerPriority.ordinal());
+    }
+
+    public int size() {
+        return list.size() >> 1;
+    }
+
+    public void removeLowestUsePos() {
+        list.setSize(list.size() - 2);
+    }
+
+    public void setRegisterPriority(int index, RegisterPriority registerPriority) {
+        list.set((index << 1) + 1, registerPriority.ordinal());
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder("[");
+        for (int i = size() - 1; i >= 0; --i) {
+            if (buf.length() != 1) {
+                buf.append(", ");
+            }
+            RegisterPriority prio = registerPriority(i);
+            buf.append(usePos(i)).append(" -> ").append(prio.ordinal()).append(':').append(prio);
+        }
+        return buf.append("]").toString();
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Tue Dec 08 12:30:15 2015 -0800
@@ -147,7 +147,7 @@
     /**
      * Sets the {@linkplain CompilationResult#setTargetCode(byte[], int) code} and
      * {@linkplain CompilationResult#recordExceptionHandler(int, int) exception handler} fields of
-     * the compilation result.
+     * the compilation result and then {@linkplain #closeCompilationResult() closes} it.
      */
     public void finish() {
         int position = asm.position();
@@ -160,6 +160,14 @@
                 compilationResult.recordExceptionHandler(codeOffset, ei.exceptionEdge.label().position());
             }
         }
+        closeCompilationResult();
+    }
+
+    /**
+     * Calls {@link CompilationResult#close()} on {@link #compilationResult}.
+     */
+    protected void closeCompilationResult() {
+        compilationResult.close();
     }
 
     public void recordExceptionHandlers(int pcOffset, LIRFrameState info) {
@@ -417,9 +425,9 @@
         }
     }
 
-    public void reset() {
+    public void resetForEmittingCode() {
         asm.reset();
-        compilationResult.reset();
+        compilationResult.resetForEmittingCode();
         if (exceptionInfoList != null) {
             exceptionInfoList.clear();
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Tue Dec 08 12:30:15 2015 -0800
@@ -77,7 +77,9 @@
     }
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRGeneratorTool lirGen) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    PreAllocationOptimizationContext context) {
+        LIRGeneratorTool lirGen = context.lirGen;
         new Optimization(lirGenRes.getLIR(), lirGen).apply();
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LocationMarkerPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LocationMarkerPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -34,7 +34,6 @@
 import jdk.vm.ci.meta.LIRKind;
 import jdk.vm.ci.meta.Value;
 
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.lir.LIR;
 import com.oracle.graal.lir.LIRFrameState;
@@ -42,7 +41,6 @@
 import com.oracle.graal.lir.framemap.FrameMap;
 import com.oracle.graal.lir.framemap.ReferenceMapBuilder;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 import com.oracle.graal.lir.phases.AllocationPhase;
 
 /**
@@ -52,8 +50,7 @@
 public final class LocationMarkerPhase extends AllocationPhase {
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext context) {
         new Marker<B>(lirGenRes.getLIR(), lirGenRes.getFrameMap()).build();
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/MarkBasePointersPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/MarkBasePointersPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -27,7 +27,6 @@
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.Value;
 
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.lir.LIR;
 import com.oracle.graal.lir.LIRFrameState;
@@ -35,7 +34,6 @@
 import com.oracle.graal.lir.Variable;
 import com.oracle.graal.lir.framemap.FrameMap;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 import com.oracle.graal.lir.phases.AllocationPhase;
 import com.oracle.graal.lir.util.IndexedValueMap;
 import com.oracle.graal.lir.util.ValueSet;
@@ -46,8 +44,7 @@
 public final class MarkBasePointersPhase extends AllocationPhase {
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext context) {
         new Marker<B>(lirGenRes.getLIR(), null).build();
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Tue Dec 08 12:30:15 2015 -0800
@@ -276,7 +276,7 @@
         if (op instanceof SimpleInfopointOp) {
             currentInfo = null;
         } else if (currentInfo != null) {
-            lirForBlock.add(new SimpleInfopointOp(InfopointReason.LINE_NUMBER, currentInfo));
+            lirForBlock.add(new SimpleInfopointOp(InfopointReason.BYTECODE_POSITION, currentInfo));
             currentInfo = null;
         }
         lirForBlock.add(op);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/AllocationPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/AllocationPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -22,20 +22,14 @@
  */
 package com.oracle.graal.lir.phases;
 
-import java.util.List;
-
-import jdk.vm.ci.code.TargetDescription;
-
 import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
-import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
-import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 
 public abstract class AllocationPhase extends LIRPhase<AllocationPhase.AllocationContext> {
 
     public static final class AllocationContext {
-        private final MoveFactory spillMoveFactory;
-        private final RegisterAllocationConfig registerAllocationConfig;
+        public final MoveFactory spillMoveFactory;
+        public final RegisterAllocationConfig registerAllocationConfig;
 
         public AllocationContext(MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig) {
             this.spillMoveFactory = spillMoveFactory;
@@ -43,12 +37,4 @@
         }
     }
 
-    @Override
-    protected final <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext context) {
-        run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context.spillMoveFactory, context.registerAllocationConfig);
-    }
-
-    protected abstract <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
-                    MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig);
-
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PostAllocationOptimizationPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PostAllocationOptimizationPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -22,31 +22,15 @@
  */
 package com.oracle.graal.lir.phases;
 
-import java.util.List;
-
-import jdk.vm.ci.code.TargetDescription;
-
-import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.lir.gen.BenchmarkCounterFactory;
-import com.oracle.graal.lir.gen.LIRGenerationResult;
 
 public abstract class PostAllocationOptimizationPhase extends LIRPhase<PostAllocationOptimizationPhase.PostAllocationOptimizationContext> {
 
     public static final class PostAllocationOptimizationContext {
-        private final BenchmarkCounterFactory counterFactory;
+        public final BenchmarkCounterFactory counterFactory;
 
         public PostAllocationOptimizationContext(BenchmarkCounterFactory counterFactory) {
             this.counterFactory = counterFactory;
         }
     }
-
-    @Override
-    protected final <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
-                    PostAllocationOptimizationContext context) {
-        run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context.counterFactory);
-    }
-
-    protected abstract <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
-                    BenchmarkCounterFactory counterFactory);
-
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PreAllocationOptimizationPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PreAllocationOptimizationPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -22,18 +22,12 @@
  */
 package com.oracle.graal.lir.phases;
 
-import java.util.List;
-
-import jdk.vm.ci.code.TargetDescription;
-
-import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
-import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.lir.gen.LIRGeneratorTool;
 
 public abstract class PreAllocationOptimizationPhase extends LIRPhase<PreAllocationOptimizationPhase.PreAllocationOptimizationContext> {
 
     public static final class PreAllocationOptimizationContext {
-        private final LIRGeneratorTool lirGen;
+        public final LIRGeneratorTool lirGen;
 
         public PreAllocationOptimizationContext(LIRGeneratorTool lirGen) {
             this.lirGen = lirGen;
@@ -41,12 +35,4 @@
 
     }
 
-    @Override
-    protected final <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
-                    PreAllocationOptimizationContext context) {
-        run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context.lirGen);
-    }
-
-    protected abstract <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRGeneratorTool lirGen);
-
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java	Tue Dec 08 12:30:15 2015 -0800
@@ -54,7 +54,8 @@
 
     @Override
     protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
-                    BenchmarkCounterFactory counterFactory) {
+                    PostAllocationOptimizationContext context) {
+        BenchmarkCounterFactory counterFactory = context.counterFactory;
         new Analyzer(target, lirGenRes.getLIR(), counterFactory).run();
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssa/SSADestructionPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssa/SSADestructionPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -39,7 +39,9 @@
 public final class SSADestructionPhase extends PreAllocationOptimizationPhase {
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRGeneratorTool lirGen) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    PreAllocationOptimizationContext context) {
+        LIRGeneratorTool lirGen = context.lirGen;
         LIR lir = lirGenRes.getLIR();
         AbstractControlFlowGraph<?> cfg = lir.getControlFlowGraph();
         for (AbstractBlockBase<?> block : cfg.getBlocks()) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssi/SSIConstructionPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssi/SSIConstructionPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -46,7 +46,9 @@
 public final class SSIConstructionPhase extends PreAllocationOptimizationPhase {
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRGeneratorTool lirGen) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    PreAllocationOptimizationContext context) {
+        LIRGeneratorTool lirGen = context.lirGen;
         assert SSAUtil.verifySSAForm(lirGenRes.getLIR());
         LIR lir = lirGenRes.getLIR();
         new SSIBuilder(lir, lirGenRes.getFrameMapBuilder()).build(lirGen);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Tue Dec 08 12:30:15 2015 -0800
@@ -44,7 +44,6 @@
 import jdk.vm.ci.options.Option;
 import jdk.vm.ci.options.OptionType;
 
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.Debug.Scope;
@@ -61,7 +60,6 @@
 import com.oracle.graal.lir.framemap.SimpleVirtualStackSlot;
 import com.oracle.graal.lir.framemap.VirtualStackSlotRange;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 import com.oracle.graal.lir.phases.AllocationPhase;
 
 /**
@@ -91,8 +89,7 @@
     private static final DebugTimer AssignSlotsTimer = Debug.timer("LSStackSlotAllocator[AssignSlots]");
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext context) {
         lirGenRes.buildFrameMap(this);
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java	Tue Dec 08 12:30:15 2015 -0800
@@ -31,7 +31,6 @@
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.common.JVMCIError;
 
-import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.Debug.Scope;
@@ -43,14 +42,12 @@
 import com.oracle.graal.lir.framemap.SimpleVirtualStackSlot;
 import com.oracle.graal.lir.framemap.VirtualStackSlotRange;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
-import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 import com.oracle.graal.lir.phases.AllocationPhase;
 
 public class SimpleStackSlotAllocator extends AllocationPhase implements StackSlotAllocator {
 
     @Override
-    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, MoveFactory spillMoveFactory,
-                    RegisterAllocationConfig registerAllocationConfig) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext context) {
         lirGenRes.buildFrameMap(this);
     }
 
--- a/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -53,13 +53,13 @@
                 }
             }
         }
-        for (LoopEx loop : loops.countedLoops()) {
+        for (LoopEx loop : loops.loops()) {
             for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) {
                 Block b = loops.getCFG().blockFor(loopEnd);
                 blocks: while (b != loop.loop().getHeader()) {
                     assert b != null;
                     for (FixedNode node : b.getNodes()) {
-                        if (node instanceof Invoke || node instanceof ForeignCallNode) {
+                        if (node instanceof Invoke || (node instanceof ForeignCallNode && ((ForeignCallNode) node).isGuaranteedSafepoint())) {
                             loopEnd.disableSafepoint();
                             break blocks;
                         }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Tue Dec 08 12:30:15 2015 -0800
@@ -258,7 +258,6 @@
                     } else {
                         return false;
                     }
-                    oneOff = true;
                     break;
                 }
                 case LE:
--- a/graal/com.oracle.graal.microbenchmarks/src/com/oracle/graal/microbenchmarks/graal/ArrayDuplicationBenchmark.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.microbenchmarks/src/com/oracle/graal/microbenchmarks/graal/ArrayDuplicationBenchmark.java	Tue Dec 08 12:30:15 2015 -0800
@@ -33,7 +33,7 @@
 import org.openjdk.jmh.annotations.TearDown;
 
 @State(Scope.Thread)
-public class ArrayDuplicationBenchmark {
+public class ArrayDuplicationBenchmark extends GraalBenchmark {
 
     /** How large should the test-arrays be. */
     private static final int TESTSIZE = 300;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.microbenchmarks/src/com/oracle/graal/microbenchmarks/graal/SimpleSyncBenchmark.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015, 2015, 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.microbenchmarks.graal;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+
+/**
+ * Benchmarks cost of non-contended synchronization.
+ */
+public class SimpleSyncBenchmark extends GraalBenchmark {
+
+    public static class Person {
+        public int age;
+
+        public Person(int age) {
+            this.age = age;
+        }
+
+        public synchronized int getAge() {
+            return age;
+        }
+
+        public synchronized void setAge(int age) {
+            this.age = age;
+        }
+
+        public synchronized void setAgeIfNonZero(int age) {
+            if (age != 0) {
+                this.age = age;
+            }
+        }
+    }
+
+    @State(Scope.Benchmark)
+    public static class ThreadState {
+        Person person = new Person(22);
+        int newAge = 45;
+    }
+
+    @Benchmark
+    @Warmup(iterations = 20)
+    public void setAgeCond(ThreadState state) {
+        Person person = state.person;
+        person.setAgeIfNonZero(state.newAge);
+    }
+
+    @Benchmark
+    @Warmup(iterations = 20)
+    public int getAge(ThreadState state) {
+        Person person = state.person;
+        return person.getAge();
+    }
+
+    @Benchmark
+    @Warmup(iterations = 20)
+    public int getAndIncAge(ThreadState state) {
+        Person person = state.person;
+        int oldAge = person.getAge();
+        person.setAge(oldAge + 1);
+        return oldAge;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.microbenchmarks/src/com/oracle/graal/microbenchmarks/graal/TestJMH.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, 2015, 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.microbenchmarks.graal;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Warmup;
+
+@Warmup(iterations = 1)
+@Measurement(iterations = 1)
+@Fork(1)
+/**
+ * This dummy class is used to verify that the JMH microbenchmarking environment is set up properly.
+ */
+public class TestJMH {
+
+    @Benchmark
+    public void testJMH() {
+        // This method was intentionally left blank.
+    }
+
+}
--- a/graal/com.oracle.graal.microbenchmarks/src/com/oracle/graal/microbenchmarks/graal/util/GraalUtil.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.microbenchmarks/src/com/oracle/graal/microbenchmarks/graal/util/GraalUtil.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -29,11 +29,11 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 import com.oracle.graal.graph.Node;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.tiers.HighTierContext;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Tue Dec 08 12:30:15 2015 -0800
@@ -463,21 +463,25 @@
     }
 
     public static ConstantNode defaultForKind(JavaKind kind, StructuredGraph graph) {
+        return unique(graph, defaultForKind(kind));
+    }
+
+    public static ConstantNode defaultForKind(JavaKind kind) {
         switch (kind) {
             case Boolean:
             case Byte:
             case Char:
             case Short:
             case Int:
-                return ConstantNode.forInt(0, graph);
+                return ConstantNode.forInt(0);
             case Double:
-                return ConstantNode.forDouble(0.0, graph);
+                return ConstantNode.forDouble(0.0);
             case Float:
-                return ConstantNode.forFloat(0.0f, graph);
+                return ConstantNode.forFloat(0.0f);
             case Long:
-                return ConstantNode.forLong(0L, graph);
+                return ConstantNode.forLong(0L);
             case Object:
-                return ConstantNode.forConstant(JavaConstant.NULL_POINTER, null, graph);
+                return ConstantNode.forConstant(JavaConstant.NULL_POINTER, null);
             default:
                 return null;
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Tue Dec 08 12:30:15 2015 -0800
@@ -36,6 +36,9 @@
 import com.oracle.graal.graph.spi.CanonicalizerTool;
 import com.oracle.graal.nodeinfo.NodeInfo;
 import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.nodes.extended.UnsafeLoadNode;
+import com.oracle.graal.nodes.java.LoadFieldNode;
+import com.oracle.graal.nodes.java.LoadIndexedNode;
 import com.oracle.graal.nodes.spi.LIRLowerable;
 import com.oracle.graal.nodes.spi.NodeLIRBuilderTool;
 import com.oracle.graal.nodes.spi.ValueProxy;
@@ -79,6 +82,10 @@
         this.piStamp = stamp;
     }
 
+    public PiNode(ValueNode object, ValueNode anchor) {
+        this(object, object.stamp().join(StampFactory.objectNonNull()), anchor);
+    }
+
     public PiNode(ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) {
         this(object, StampFactory.object(toType, exactType, nonNull || StampTool.isPointerNonNull(object.stamp()), true));
     }
@@ -116,19 +123,43 @@
             return this;
         }
         inferStamp();
-        if (stamp().equals(object().stamp())) {
-            return object();
+        ValueNode o = object();
+
+        // The pi node does not give any additional information => skip it.
+        if (stamp().equals(o.stamp())) {
+            return o;
         }
-        if (getGuard() != null) {
-            for (PiNode otherPi : getGuard().asNode().usages().filter(PiNode.class)) {
-                if (object() == otherPi.object() && stamp().equals(otherPi.stamp())) {
-                    /*
-                     * Two PiNodes with the same guard and same result, so return the one with the
-                     * more precise piStamp.
-                     */
-                    Stamp newStamp = piStamp.join(otherPi.piStamp);
-                    if (newStamp.equals(otherPi.piStamp)) {
-                        return otherPi;
+
+        GuardingNode g = getGuard();
+        if (g == null) {
+
+            // Try to merge the pi node with a load node.
+            if (o instanceof LoadFieldNode) {
+                LoadFieldNode loadFieldNode = (LoadFieldNode) o;
+                loadFieldNode.setStamp(loadFieldNode.stamp().improveWith(this.piStamp));
+                return loadFieldNode;
+            } else if (o instanceof UnsafeLoadNode) {
+                UnsafeLoadNode unsafeLoadNode = (UnsafeLoadNode) o;
+                unsafeLoadNode.setStamp(unsafeLoadNode.stamp().improveWith(this.piStamp));
+                return unsafeLoadNode;
+            } else if (o instanceof LoadIndexedNode) {
+                LoadIndexedNode loadIndexedNode = (LoadIndexedNode) o;
+                loadIndexedNode.setStamp(loadIndexedNode.stamp().improveWith(this.piStamp));
+                return loadIndexedNode;
+            }
+        } else {
+            for (Node n : g.asNode().usages()) {
+                if (n instanceof PiNode) {
+                    PiNode otherPi = (PiNode) n;
+                    if (o == otherPi.object() && stamp().equals(otherPi.stamp())) {
+                        /*
+                         * Two PiNodes with the same guard and same result, so return the one with
+                         * the more precise piStamp.
+                         */
+                        Stamp newStamp = piStamp.join(otherPi.piStamp);
+                        if (newStamp.equals(otherPi.piStamp)) {
+                            return otherPi;
+                        }
                     }
                 }
             }
@@ -148,6 +179,13 @@
         return asNonNullClassIntrinsic(object, Class.class, true, true);
     }
 
+    /**
+     * Casts an object to have an exact, non-null stamp representing {@link Class}.
+     */
+    public static Class<?> asNonNullObject(Object object) {
+        return asNonNullClassIntrinsic(object, Object.class, false, true);
+    }
+
     @NodeIntrinsic(PiNode.class)
     private static native Class<?> asNonNullClassIntrinsic(Object object, @ConstantNodeParameter Class<?> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull);
 
@@ -158,13 +196,20 @@
     public static native Object piCast(Object object, @ConstantNodeParameter Stamp stamp);
 
     /**
-     * Changes the stamp of an object and ensures the newly stamped value does float above a given
-     * anchor.
+     * Changes the stamp of an object and ensures the newly stamped value does not float above a
+     * given anchor.
      */
     @NodeIntrinsic
     public static native Object piCast(Object object, @ConstantNodeParameter Stamp stamp, GuardingNode anchor);
 
     /**
+     * Changes the stamp of an object and ensures the newly stamped value is non-null and does not
+     * float above a given anchor.
+     */
+    @NodeIntrinsic
+    public static native Object piCastNonNull(Object object, GuardingNode anchor);
+
+    /**
      * Changes the stamp of an object to represent a given type and to indicate that the object is
      * not null.
      */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Tue Dec 08 12:30:15 2015 -0800
@@ -27,6 +27,8 @@
 
 import com.oracle.graal.compiler.common.calc.Condition;
 import com.oracle.graal.compiler.common.type.IntegerStamp;
+import com.oracle.graal.compiler.common.type.Stamp;
+import com.oracle.graal.compiler.common.type.StampFactory;
 import com.oracle.graal.graph.NodeClass;
 import com.oracle.graal.graph.spi.Canonicalizable;
 import com.oracle.graal.graph.spi.CanonicalizerTool;
@@ -83,7 +85,33 @@
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(trueValue.stamp().meet(falseValue.stamp()));
+        Stamp valueStamp = trueValue.stamp().meet(falseValue.stamp());
+        if (condition instanceof IntegerLessThanNode) {
+            IntegerLessThanNode lessThan = (IntegerLessThanNode) condition;
+            if (lessThan.getX() == trueValue && lessThan.getY() == falseValue) {
+                // this encodes a min operation
+                JavaConstant constant = lessThan.getX().asJavaConstant();
+                if (constant == null) {
+                    constant = lessThan.getY().asJavaConstant();
+                }
+                if (constant != null) {
+                    IntegerStamp bounds = StampFactory.forInteger(constant.getJavaKind(), constant.getJavaKind().getMinValue(), constant.asLong());
+                    valueStamp = valueStamp.join(bounds);
+                }
+            } else if (lessThan.getX() == falseValue && lessThan.getY() == trueValue) {
+                // this encodes a max operation
+                JavaConstant constant = lessThan.getX().asJavaConstant();
+                if (constant == null) {
+                    constant = lessThan.getY().asJavaConstant();
+                }
+                if (constant != null) {
+                    IntegerStamp bounds = StampFactory.forInteger(constant.getJavaKind(), constant.asLong(), constant.getJavaKind().getMaxValue());
+                    valueStamp = valueStamp.join(bounds);
+                }
+            }
+
+        }
+        return updateStamp(valueStamp);
     }
 
     public ValueNode trueValue() {
@@ -124,6 +152,27 @@
             return trueValue();
         }
 
+        if (condition instanceof IntegerLessThanNode && trueValue().stamp() instanceof IntegerStamp) {
+            /*
+             * Convert a conditional add ((x < 0) ? (x + y) : x) into (x + (y & (x >> (bits - 1))))
+             * to avoid the test.
+             */
+            IntegerLessThanNode lt = (IntegerLessThanNode) condition;
+            if (lt.getY().isConstant() && lt.getY().asConstant().isDefaultForKind()) {
+                if (falseValue() == lt.getX()) {
+                    if (trueValue() instanceof AddNode) {
+                        AddNode add = (AddNode) trueValue();
+                        if (add.getX() == falseValue()) {
+                            int bits = ((IntegerStamp) trueValue().stamp()).getBits();
+                            ValueNode shift = new RightShiftNode(lt.getX(), ConstantNode.forIntegerBits(32, bits - 1));
+                            ValueNode and = new AndNode(shift, add.getY());
+                            return new AddNode(add.getX(), and);
+                        }
+                    }
+                }
+            }
+        }
+
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Tue Dec 08 12:30:15 2015 -0800
@@ -297,7 +297,7 @@
                     }
                 }
 
-                if (graph.hasValueProxies()) {
+                if (graph.getGuardsStage() != GuardsStage.AFTER_FSA) {
                     // The following loop can add new blocks to the end of the loop's block list.
                     int size = loop.getBlocks().size();
                     for (int i = 0; i < size; ++i) {
@@ -353,7 +353,7 @@
                 if (block.getLoop() == loop) {
                     nextState = stepOut;
                 } else {
-                    assert block.loop == loop.getParent();
+                    assert block.loop == loop.getParent() : block;
                     block.loop = c.loop;
 
                     assert !c.loop.getBlocks().contains(block);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Tue Dec 08 12:30:15 2015 -0800
@@ -42,6 +42,7 @@
 import com.oracle.graal.nodes.DeoptimizingNode;
 import com.oracle.graal.nodes.FrameState;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
 import com.oracle.graal.nodes.memory.AbstractMemoryCheckpoint;
 import com.oracle.graal.nodes.memory.MemoryCheckpoint;
 import com.oracle.graal.nodes.spi.LIRLowerable;
@@ -61,11 +62,36 @@
     protected final ForeignCallDescriptor descriptor;
     protected int bci = BytecodeFrame.UNKNOWN_BCI;
 
-    public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
+    public static boolean intrinsify(GraphBuilderContext b, @InjectedNodeParameter Stamp returnStamp, @InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor,
+                    ValueNode... arguments) {
+        ForeignCallNode node = new ForeignCallNode(foreignCalls, descriptor, arguments);
+        node.setStamp(returnStamp);
+
+        /*
+         * Need to update the BCI of a ForeignCallNode so that it gets the stateDuring in the case
+         * that the foreign call can deoptimize. As with all deoptimization, we need a state in a
+         * non-intrinsic method.
+         */
+        GraphBuilderContext nonIntrinsicAncestor = b.getNonIntrinsicAncestor();
+        if (nonIntrinsicAncestor != null) {
+            node.setBci(nonIntrinsicAncestor.bci());
+        }
+
+        JavaKind returnKind = returnStamp.getStackKind();
+        if (returnKind == JavaKind.Void) {
+            b.add(node);
+        } else {
+            b.addPush(returnKind, node);
+        }
+
+        return true;
+    }
+
+    public ForeignCallNode(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
         this(TYPE, foreignCalls, descriptor, arguments);
     }
 
-    public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp, List<ValueNode> arguments) {
+    public ForeignCallNode(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp, List<ValueNode> arguments) {
         super(TYPE, stamp);
         this.arguments = new NodeInputList<>(this, arguments);
         this.descriptor = descriptor;
@@ -73,7 +99,7 @@
         assert descriptor.getArgumentTypes().length == this.arguments.size() : "wrong number of arguments to " + this;
     }
 
-    public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) {
+    public ForeignCallNode(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) {
         super(TYPE, stamp);
         this.arguments = new NodeInputList<>(this);
         this.descriptor = descriptor;
@@ -176,4 +202,8 @@
     public boolean canDeoptimize() {
         return foreignCalls.canDeoptimize(descriptor);
     }
+
+    public boolean isGuaranteedSafepoint() {
+        return foreignCalls.isGuaranteedSafepoint(descriptor);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Tue Dec 08 12:30:15 2015 -0800
@@ -34,9 +34,9 @@
 import com.oracle.graal.graph.spi.CanonicalizerTool;
 import com.oracle.graal.nodeinfo.NodeInfo;
 import com.oracle.graal.nodes.ConstantNode;
-import com.oracle.graal.nodes.FloatingGuardedNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.calc.FloatingNode;
 import com.oracle.graal.nodes.spi.Lowerable;
 import com.oracle.graal.nodes.spi.LoweringTool;
 import com.oracle.graal.nodes.spi.StampProvider;
@@ -47,7 +47,7 @@
  * Loads an object's hub. The object is not null-checked by this operation.
  */
 @NodeInfo
-public final class LoadHubNode extends FloatingGuardedNode implements Lowerable, Canonicalizable, Virtualizable {
+public final class LoadHubNode extends FloatingNode implements Lowerable, Canonicalizable, Virtualizable {
 
     public static final NodeClass<LoadHubNode> TYPE = NodeClass.create(LoadHubNode.class);
     @Input ValueNode value;
@@ -67,20 +67,15 @@
         if (synonym != null) {
             return synonym;
         }
-        return new LoadHubNode(stamp, value, null);
+        return new LoadHubNode(stamp, value);
     }
 
     public LoadHubNode(@InjectedNodeParameter StampProvider stampProvider, ValueNode value) {
-        this(stampProvider, value, null);
+        this(hubStamp(stampProvider, value), value);
     }
 
-    public LoadHubNode(@InjectedNodeParameter StampProvider stampProvider, ValueNode value, ValueNode guard) {
-        this(hubStamp(stampProvider, value), value, guard);
-    }
-
-    public LoadHubNode(Stamp stamp, ValueNode value, ValueNode guard) {
-        super(TYPE, stamp, (GuardingNode) guard);
-        assert value != guard;
+    public LoadHubNode(Stamp stamp, ValueNode value) {
+        super(TYPE, stamp);
         this.value = value;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCopyNode.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCopyNode.java	Tue Dec 08 12:30:15 2015 -0800
@@ -25,93 +25,24 @@
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.LocationIdentity;
 
-import com.oracle.graal.compiler.common.type.StampFactory;
-import com.oracle.graal.graph.NodeClass;
-import com.oracle.graal.nodeinfo.InputType;
-import com.oracle.graal.nodeinfo.NodeInfo;
-import com.oracle.graal.nodes.FixedWithNextNode;
-import com.oracle.graal.nodes.FrameState;
-import com.oracle.graal.nodes.StateSplit;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
 
 /**
  * Copy a value at a location specified as an offset relative to a source object to another location
  * specified as an offset relative to destination object. No null checks are performed.
- *
- * This node must be replaced during processing of node intrinsics with an {@link UnsafeLoadNode}
- * and {@link UnsafeStoreNode} pair.
  */
-@NodeInfo
-public final class UnsafeCopyNode extends FixedWithNextNode implements StateSplit {
-
-    public static final NodeClass<UnsafeCopyNode> TYPE = NodeClass.create(UnsafeCopyNode.class);
-    @Input ValueNode sourceObject;
-    @Input ValueNode destinationObject;
-    @Input ValueNode sourceOffset;
-    @Input ValueNode destinationOffset;
-    protected final JavaKind accessKind;
-    protected final LocationIdentity locationIdentity;
-    @OptionalInput(InputType.State) FrameState stateAfter;
-
-    public UnsafeCopyNode(ValueNode sourceObject, ValueNode sourceOffset, ValueNode destinationObject, ValueNode destinationOffset, JavaKind accessKind, LocationIdentity locationIdentity) {
-        this(sourceObject, sourceOffset, destinationObject, destinationOffset, accessKind, locationIdentity, null);
-    }
-
-    public UnsafeCopyNode(ValueNode sourceObject, ValueNode sourceOffset, ValueNode destinationObject, ValueNode destinationOffset, JavaKind accessKind, LocationIdentity locationIdentity,
-                    FrameState stateAfter) {
-        super(TYPE, StampFactory.forVoid());
-        this.sourceObject = sourceObject;
-        this.sourceOffset = sourceOffset;
-        this.destinationObject = destinationObject;
-        this.destinationOffset = destinationOffset;
-        this.accessKind = accessKind;
-        this.locationIdentity = locationIdentity;
-        this.stateAfter = stateAfter;
-        assert accessKind != JavaKind.Void && accessKind != JavaKind.Illegal;
-    }
-
-    public ValueNode sourceObject() {
-        return sourceObject;
-    }
+public final class UnsafeCopyNode {
 
-    public ValueNode destinationObject() {
-        return destinationObject;
-    }
-
-    public LocationIdentity getLocationIdentity() {
-        return locationIdentity;
-    }
-
-    public ValueNode sourceOffset() {
-        return sourceOffset;
-    }
-
-    public ValueNode destinationOffset() {
-        return destinationOffset;
-    }
-
-    public JavaKind accessKind() {
-        return accessKind;
-    }
-
-    public FrameState stateAfter() {
-        return stateAfter;
-    }
-
-    public void setStateAfter(FrameState x) {
-        assert x == null || x.isAlive() : "frame state must be in a graph";
-        updateUsages(stateAfter, x);
-        stateAfter = x;
-    }
-
-    public boolean hasSideEffect() {
+    public static boolean intrinsify(GraphBuilderContext b, ValueNode sourceObject, ValueNode sourceOffset, ValueNode destinationObject, ValueNode destinationOffset, JavaKind accessKind,
+                    LocationIdentity locationIdentity) {
+        UnsafeLoadNode value = b.add(new UnsafeLoadNode(sourceObject, sourceOffset, accessKind, locationIdentity));
+        b.add(new UnsafeStoreNode(destinationObject, destinationOffset, value, accessKind, locationIdentity));
         return true;
     }
 
-    public FrameState getState() {
-        return stateAfter;
-    }
-
     @NodeIntrinsic
     public static native void copy(Object srcObject, long srcOffset, Object destObject, long destOffset, @ConstantNodeParameter JavaKind kind, @ConstantNodeParameter LocationIdentity locationIdentity);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/ForeignCallPlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2015, 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.graphbuilderconf;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import com.oracle.graal.compiler.common.spi.ForeignCallDescriptor;
+import com.oracle.graal.compiler.common.spi.ForeignCallsProvider;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.extended.ForeignCallNode;
+
+/**
+ * {@link InvocationPlugin} for converting a method call directly to a foreign call.
+ */
+public final class ForeignCallPlugin implements InvocationPlugin {
+    private final ForeignCallsProvider foreignCalls;
+    private final ForeignCallDescriptor descriptor;
+
+    public ForeignCallPlugin(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor) {
+        this.foreignCalls = foreignCalls;
+        this.descriptor = descriptor;
+    }
+
+    public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] args) {
+        ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, descriptor, args);
+        foreignCall.setBci(b.bci());
+        b.addPush(targetMethod.getSignature().getReturnKind(), foreignCall);
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/GeneratedInvocationPlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, 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.graphbuilderconf;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import com.oracle.graal.nodes.ValueNode;
+
+public abstract class GeneratedInvocationPlugin implements InvocationPlugin {
+
+    public abstract boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] args);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/GraphBuilderConfiguration.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2011, 2015, 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.graphbuilderconf;
+
+import java.util.Arrays;
+
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+import com.oracle.graal.compiler.common.GraalOptions;
+import com.oracle.graal.nodes.FullInfopointNode;
+import com.oracle.graal.nodes.SimpleInfopointNode;
+
+public class GraphBuilderConfiguration {
+
+    public static class Plugins {
+        private final InvocationPlugins invocationPlugins;
+        private NodePlugin[] nodePlugins;
+        private ParameterPlugin[] parameterPlugins;
+        private InlineInvokePlugin[] inlineInvokePlugins;
+        private LoopExplosionPlugin loopExplosionPlugin;
+
+        /**
+         * Creates a copy of a given set of plugins. The {@link InvocationPlugins} in
+         * {@code copyFrom} become the {@linkplain InvocationPlugins#getParent() default}
+         * {@linkplain #getInvocationPlugins() invocation plugins} in this object.
+         */
+        public Plugins(Plugins copyFrom) {
+            this.invocationPlugins = new InvocationPlugins(copyFrom.invocationPlugins);
+            this.nodePlugins = copyFrom.nodePlugins;
+            this.parameterPlugins = copyFrom.parameterPlugins;
+            this.inlineInvokePlugins = copyFrom.inlineInvokePlugins;
+            this.loopExplosionPlugin = copyFrom.loopExplosionPlugin;
+        }
+
+        /**
+         * Creates a new set of plugins.
+         *
+         * @param invocationPlugins the {@linkplain #getInvocationPlugins() invocation plugins} in
+         *            this object
+         */
+        public Plugins(InvocationPlugins invocationPlugins) {
+            this.invocationPlugins = invocationPlugins;
+            this.nodePlugins = new NodePlugin[0];
+            this.parameterPlugins = new ParameterPlugin[0];
+            this.inlineInvokePlugins = new InlineInvokePlugin[0];
+        }
+
+        public InvocationPlugins getInvocationPlugins() {
+            return invocationPlugins;
+        }
+
+        public NodePlugin[] getNodePlugins() {
+            return nodePlugins;
+        }
+
+        public void appendNodePlugin(NodePlugin plugin) {
+            nodePlugins = Arrays.copyOf(nodePlugins, nodePlugins.length + 1);
+            nodePlugins[nodePlugins.length - 1] = plugin;
+        }
+
+        public void prependNodePlugin(NodePlugin plugin) {
+            NodePlugin[] newPlugins = new NodePlugin[nodePlugins.length + 1];
+            System.arraycopy(nodePlugins, 0, newPlugins, 1, nodePlugins.length);
+            newPlugins[0] = plugin;
+            nodePlugins = newPlugins;
+        }
+
+        public void clearNodePlugin() {
+            nodePlugins = new NodePlugin[0];
+        }
+
+        public ParameterPlugin[] getParameterPlugins() {
+            return parameterPlugins;
+        }
+
+        public void appendParameterPlugin(ParameterPlugin plugin) {
+            parameterPlugins = Arrays.copyOf(parameterPlugins, parameterPlugins.length + 1);
+            parameterPlugins[parameterPlugins.length - 1] = plugin;
+        }
+
+        public void prependParameterPlugin(ParameterPlugin plugin) {
+            ParameterPlugin[] newPlugins = new ParameterPlugin[parameterPlugins.length + 1];
+            System.arraycopy(parameterPlugins, 0, newPlugins, 1, parameterPlugins.length);
+            newPlugins[0] = plugin;
+            parameterPlugins = newPlugins;
+        }
+
+        public void clearParameterPlugin() {
+            parameterPlugins = new ParameterPlugin[0];
+        }
+
+        public InlineInvokePlugin[] getInlineInvokePlugins() {
+            return inlineInvokePlugins;
+        }
+
+        public void appendInlineInvokePlugin(InlineInvokePlugin plugin) {
+            inlineInvokePlugins = Arrays.copyOf(inlineInvokePlugins, inlineInvokePlugins.length + 1);
+            inlineInvokePlugins[inlineInvokePlugins.length - 1] = plugin;
+        }
+
+        public void prependInlineInvokePlugin(InlineInvokePlugin plugin) {
+            InlineInvokePlugin[] newPlugins = new InlineInvokePlugin[inlineInvokePlugins.length + 1];
+            System.arraycopy(inlineInvokePlugins, 0, newPlugins, 1, inlineInvokePlugins.length);
+            newPlugins[0] = plugin;
+            inlineInvokePlugins = newPlugins;
+        }
+
+        public void clearInlineInvokePlugins() {
+            inlineInvokePlugins = new InlineInvokePlugin[0];
+        }
+
+        public LoopExplosionPlugin getLoopExplosionPlugin() {
+            return loopExplosionPlugin;
+        }
+
+        public void setLoopExplosionPlugin(LoopExplosionPlugin plugin) {
+            this.loopExplosionPlugin = plugin;
+        }
+    }
+
+    private static final ResolvedJavaType[] EMPTY = new ResolvedJavaType[]{};
+
+    private final boolean eagerResolving;
+    private final boolean omitAllExceptionEdges;
+    private final boolean omitAssertions;
+    private final ResolvedJavaType[] skippedExceptionTypes;
+    private final DebugInfoMode debugInfoMode;
+    private final boolean clearNonLiveLocals;
+    private boolean useProfiling;
+    private final Plugins plugins;
+
+    public static enum DebugInfoMode {
+        SafePointsOnly,
+        /**
+         * This mode inserts {@link SimpleInfopointNode}s in places where no safepoints would be
+         * inserted: inlining boundaries, and line number switches.
+         * <p>
+         * In this mode the infopoint only have a location (method and bytecode index) and no
+         * values.
+         * <p>
+         * This is useful to have better program counter to bci mapping and has no influence on the
+         * generated code. However it can increase the amount of metadata and does not allow access
+         * to accessing values at runtime.
+         */
+        Simple,
+        /**
+         * In this mode, {@link FullInfopointNode}s are generated in the same locations as in
+         * {@link #Simple} mode but the infopoints have access to the runtime values.
+         * <p>
+         * This is relevant when code is to be generated for native, machine-code level debugging
+         * but can have a limit the amount of optimization applied to the code.
+         */
+        Full,
+    }
+
+    protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, boolean omitAssertions, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes,
+                    boolean clearNonLiveLocals, Plugins plugins) {
+        this.eagerResolving = eagerResolving;
+        this.omitAllExceptionEdges = omitAllExceptionEdges;
+        this.omitAssertions = omitAssertions;
+        this.debugInfoMode = debugInfoMode;
+        this.skippedExceptionTypes = skippedExceptionTypes;
+        this.clearNonLiveLocals = clearNonLiveLocals;
+        this.useProfiling = true;
+        this.plugins = plugins;
+    }
+
+    /**
+     * Creates a copy of this configuration with all its plugins. The {@link InvocationPlugins} in
+     * this configuration become the {@linkplain InvocationPlugins#getParent() parent} of the
+     * {@link InvocationPlugins} in the copy.
+     */
+    public GraphBuilderConfiguration copy() {
+        Plugins newPlugins = new Plugins(plugins);
+        GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, newPlugins);
+        result.useProfiling = useProfiling;
+        return result;
+    }
+
+    public boolean getUseProfiling() {
+        return useProfiling;
+    }
+
+    public void setUseProfiling(boolean b) {
+        this.useProfiling = b;
+    }
+
+    public GraphBuilderConfiguration withEagerResolving(boolean newEagerResolving) {
+        return new GraphBuilderConfiguration(newEagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, plugins);
+    }
+
+    public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, newSkippedExceptionTypes, clearNonLiveLocals, plugins);
+    }
+
+    public GraphBuilderConfiguration withOmitAllExceptionEdges(boolean newOmitAllExceptionEdges) {
+        return new GraphBuilderConfiguration(eagerResolving, newOmitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, plugins);
+    }
+
+    public GraphBuilderConfiguration withOmitAssertions(boolean newOmitAssertions) {
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newOmitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, plugins);
+    }
+
+    public GraphBuilderConfiguration withDebugInfoMode(DebugInfoMode newDebugInfoMode) {
+        ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length);
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, newDebugInfoMode, newSkippedExceptionTypes, clearNonLiveLocals, plugins);
+    }
+
+    public GraphBuilderConfiguration withClearNonLiveLocals(boolean newClearNonLiveLocals) {
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, newClearNonLiveLocals, plugins);
+    }
+
+    public ResolvedJavaType[] getSkippedExceptionTypes() {
+        return skippedExceptionTypes;
+    }
+
+    public boolean eagerResolving() {
+        return eagerResolving;
+    }
+
+    public boolean omitAllExceptionEdges() {
+        return omitAllExceptionEdges;
+    }
+
+    public boolean omitAssertions() {
+        return omitAssertions;
+    }
+
+    public boolean insertNonSafepointDebugInfo() {
+        return debugInfoMode.ordinal() >= DebugInfoMode.Simple.ordinal();
+    }
+
+    public boolean insertFullDebugInfo() {
+        return debugInfoMode.ordinal() >= DebugInfoMode.Full.ordinal();
+    }
+
+    public boolean insertSimpleDebugInfo() {
+        return debugInfoMode == DebugInfoMode.Simple;
+    }
+
+    public boolean clearNonLiveLocals() {
+        return clearNonLiveLocals;
+    }
+
+    public static GraphBuilderConfiguration getDefault(Plugins plugins) {
+        return new GraphBuilderConfiguration(false, false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
+    }
+
+    public static GraphBuilderConfiguration getInfopointDefault(Plugins plugins) {
+        return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
+    }
+
+    public static GraphBuilderConfiguration getEagerDefault(Plugins plugins) {
+        return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
+    }
+
+    public static GraphBuilderConfiguration getInfopointEagerDefault(Plugins plugins) {
+        return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
+    }
+
+    public static GraphBuilderConfiguration getSnippetDefault(Plugins plugins) {
+        return new GraphBuilderConfiguration(true, true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
+    }
+
+    public static GraphBuilderConfiguration getFullDebugDefault(Plugins plugins) {
+        return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Full, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
+    }
+
+    /**
+     * Returns {@code true} if it is an error for a class/field/method resolution to fail. The
+     * default is the same result as returned by {@link #eagerResolving()}. However, it may be
+     * overridden to allow failure even when {@link #eagerResolving} is {@code true}.
+     */
+    public boolean unresolvedIsError() {
+        return eagerResolving;
+    }
+
+    public Plugins getPlugins() {
+        return plugins;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/GraphBuilderContext.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2015, 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.graphbuilderconf;
+
+import static com.oracle.graal.compiler.common.type.StampFactory.objectNonNull;
+import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
+import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+import com.oracle.graal.compiler.common.type.ObjectStamp;
+import com.oracle.graal.compiler.common.type.Stamp;
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.FixedGuardNode;
+import com.oracle.graal.nodes.PiNode;
+import com.oracle.graal.nodes.StateSplit;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.nodes.spi.StampProvider;
+import com.oracle.graal.nodes.type.StampTool;
+
+/**
+ * Used by a {@link GraphBuilderPlugin} to interface with an object that parses the bytecode of a
+ * single {@linkplain #getMethod() method} as part of building a {@linkplain #getGraph() graph} .
+ */
+public interface GraphBuilderContext {
+
+    /**
+     * Raw operation for adding a node to the graph when neither {@link #add} nor
+     * {@link #addPush(JavaKind, ValueNode)} can be used.
+     *
+     * @return either the node added or an equivalent node
+     */
+    <T extends ValueNode> T append(T value);
+
+    /**
+     * Adds the given node to the graph and also adds recursively all referenced inputs.
+     *
+     * @param value the node to be added to the graph
+     * @return either the node added or an equivalent node
+     */
+    <T extends ValueNode> T recursiveAppend(T value);
+
+    /**
+     * Pushes a given value to the frame state stack using an explicit kind. This should be used
+     * when {@code value.getJavaKind()} is different from the kind that the bytecode instruction
+     * currently being parsed pushes to the stack.
+     *
+     * @param kind the kind to use when type checking this operation
+     * @param value the value to push to the stack. The value must already have been
+     *            {@linkplain #append(ValueNode) appended}.
+     */
+    void push(JavaKind kind, ValueNode value);
+
+    /**
+     * Adds a node to the graph. If the returned node is a {@link StateSplit} with a null
+     * {@linkplain StateSplit#stateAfter() frame state}, the frame state is initialized.
+     *
+     * @param value the value to add to the graph and push to the stack. The
+     *            {@code value.getJavaKind()} kind is used when type checking this operation.
+     * @return a node equivalent to {@code value} in the graph
+     */
+    default <T extends ValueNode> T add(T value) {
+        if (value.graph() != null) {
+            assert !(value instanceof StateSplit) || ((StateSplit) value).stateAfter() != null;
+            return value;
+        }
+        T equivalentValue = append(value);
+        if (equivalentValue instanceof StateSplit) {
+            StateSplit stateSplit = (StateSplit) equivalentValue;
+            if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
+                setStateAfter(stateSplit);
+            }
+        }
+        return equivalentValue;
+    }
+
+    /**
+     * Adds a node with a non-void kind to the graph, pushes it to the stack. If the returned node
+     * is a {@link StateSplit} with a null {@linkplain StateSplit#stateAfter() frame state}, the
+     * frame state is initialized.
+     *
+     * @param kind the kind to use when type checking this operation
+     * @param value the value to add to the graph and push to the stack
+     * @return a node equivalent to {@code value} in the graph
+     */
+    default <T extends ValueNode> T addPush(JavaKind kind, T value) {
+        T equivalentValue = value.graph() != null ? value : append(value);
+        push(kind, equivalentValue);
+        if (equivalentValue instanceof StateSplit) {
+            StateSplit stateSplit = (StateSplit) equivalentValue;
+            if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
+                setStateAfter(stateSplit);
+            }
+        }
+        return equivalentValue;
+    }
+
+    /**
+     * Handles an invocation that a plugin determines can replace the original invocation (i.e., the
+     * one for which the plugin was applied). This applies all standard graph builder processing to
+     * the replaced invocation including applying any relevant plugins.
+     *
+     * @param invokeKind the kind of the replacement invocation
+     * @param targetMethod the target of the replacement invocation
+     * @param args the arguments to the replacement invocation
+     * @param forceInlineEverything specifies if all invocations encountered in the scope of
+     *            handling the replaced invoke are to be force inlined
+     */
+    void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean forceInlineEverything);
+
+    /**
+     * Intrinsifies an invocation of a given method by inlining the bytecodes of a given
+     * substitution method.
+     *
+     * @param targetMethod the method being intrinsified
+     * @param substitute the intrinsic implementation
+     * @param args the arguments with which to inline the invocation
+     */
+    void intrinsify(ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, ValueNode[] args);
+
+    StampProvider getStampProvider();
+
+    MetaAccessProvider getMetaAccess();
+
+    default Assumptions getAssumptions() {
+        return getGraph().getAssumptions();
+    }
+
+    ConstantReflectionProvider getConstantReflection();
+
+    /**
+     * Gets the graph being constructed.
+     */
+    StructuredGraph getGraph();
+
+    /**
+     * Creates a snap shot of the current frame state with the BCI of the instruction after the one
+     * currently being parsed and assigns it to a given {@linkplain StateSplit#hasSideEffect() side
+     * effect} node.
+     *
+     * @param sideEffect a side effect node just appended to the graph
+     */
+    void setStateAfter(StateSplit sideEffect);
+
+    /**
+     * Gets the parsing context for the method that inlines the method being parsed by this context.
+     */
+    GraphBuilderContext getParent();
+
+    /**
+     * Gets the first ancestor parsing context that is not parsing a
+     * {@linkplain #parsingIntrinsic() intrinsic}.
+     */
+    default GraphBuilderContext getNonIntrinsicAncestor() {
+        GraphBuilderContext ancestor = getParent();
+        while (ancestor != null && ancestor.parsingIntrinsic()) {
+            ancestor = ancestor.getParent();
+        }
+        return ancestor;
+    }
+
+    /**
+     * Gets the method being parsed by this context.
+     */
+    ResolvedJavaMethod getMethod();
+
+    /**
+     * Gets the index of the bytecode instruction currently being parsed.
+     */
+    int bci();
+
+    /**
+     * Gets the kind of invocation currently being parsed.
+     */
+    InvokeKind getInvokeKind();
+
+    /**
+     * Gets the return type of the invocation currently being parsed.
+     */
+    JavaType getInvokeReturnType();
+
+    default Stamp getInvokeReturnStamp() {
+        JavaType returnType = getInvokeReturnType();
+        if (returnType.getJavaKind() == JavaKind.Object && returnType instanceof ResolvedJavaType) {
+            return StampFactory.declared((ResolvedJavaType) returnType);
+        } else {
+            return StampFactory.forKind(returnType.getJavaKind());
+        }
+    }
+
+    /**
+     * Gets the inline depth of this context. A return value of 0 implies that this is the context
+     * for the parse root.
+     */
+    default int getDepth() {
+        GraphBuilderContext parent = getParent();
+        return parent == null ? 0 : 1 + parent.getDepth();
+    }
+
+    /**
+     * Determines if this parsing context is within the bytecode of an intrinsic or a method inlined
+     * by an intrinsic.
+     */
+    default boolean parsingIntrinsic() {
+        return getIntrinsic() != null;
+    }
+
+    /**
+     * Gets the intrinsic of the current parsing context or {@code null} if not
+     * {@link #parsingIntrinsic() parsing an intrinsic}.
+     */
+    IntrinsicContext getIntrinsic();
+
+    BailoutException bailout(String string);
+
+    /**
+     * Gets a version of a given value that has a {@linkplain StampTool#isPointerNonNull(ValueNode)
+     * non-null} stamp.
+     */
+    default ValueNode nullCheckedValue(ValueNode value) {
+        if (!StampTool.isPointerNonNull(value.stamp())) {
+            IsNullNode condition = getGraph().unique(new IsNullNode(value));
+            ObjectStamp receiverStamp = (ObjectStamp) value.stamp();
+            Stamp stamp = receiverStamp.join(objectNonNull());
+            FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, NullCheckException, InvalidateReprofile, true));
+            PiNode nonNullReceiver = getGraph().unique(new PiNode(value, stamp));
+            nonNullReceiver.setGuard(fixedGuard);
+            // TODO: Propogating the non-null into the frame state would
+            // remove subsequent null-checks on the same value. However,
+            // it currently causes an assertion failure when merging states.
+            //
+            // frameState.replace(value, nonNullReceiver);
+            return nonNullReceiver;
+        }
+        return value;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/GraphBuilderPlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, 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.graphbuilderconf;
+
+/**
+ * Marker interface for graph builder plugins.
+ */
+public interface GraphBuilderPlugin {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/InlineInvokePlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2015, 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.graphbuilderconf;
+
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.ValueNode;
+
+/**
+ * Plugin for specifying what is inlined during graph parsing. This plugin is also notified
+ * {@link #notifyBeforeInline before} and {@link #notifyAfterInline} the inlining, as well as of
+ * {@link #notifyNotInlined non-inlined} invocations (i.e., those for which an {@link Invoke} node
+ * is created).
+ */
+public interface InlineInvokePlugin extends GraphBuilderPlugin {
+
+    /**
+     * Result of a {@link #shouldInlineInvoke inlining decision}.
+     */
+    public static class InlineInfo {
+
+        /**
+         * Denotes a call site that must not be inlined and should be implemented by a node that
+         * does not speculate on the call not raising an exception.
+         */
+        public static final InlineInfo DO_NOT_INLINE_WITH_EXCEPTION = new InlineInfo(null, false);
+
+        /**
+         * Denotes a call site must not be inlined and can be implemented by a node that speculates
+         * the call will not throw an exception.
+         */
+        public static final InlineInfo DO_NOT_INLINE_NO_EXCEPTION = new InlineInfo(null, false);
+
+        private final ResolvedJavaMethod methodToInline;
+        private final boolean isIntrinsic;
+
+        public InlineInfo(ResolvedJavaMethod methodToInline, boolean isIntrinsic) {
+            this.methodToInline = methodToInline;
+            this.isIntrinsic = isIntrinsic;
+        }
+
+        /**
+         * Returns the method to be inlined, or {@code null} if the call site must not be inlined.
+         */
+        public ResolvedJavaMethod getMethodToInline() {
+            return methodToInline;
+        }
+
+        /**
+         * Specifies if {@link #methodToInline} is an intrinsic for the original method (i.e., the
+         * {@code method} passed to {@link InlineInvokePlugin#shouldInlineInvoke}).
+         */
+        public boolean isIntrinsic() {
+            return isIntrinsic;
+        }
+    }
+
+    /**
+     * Determines whether a call to a given method is to be inlined. The return value is a
+     * tri-state:
+     * <p>
+     * Non-null return value with a non-null {@link InlineInfo#getMethodToInline method}: That
+     * {@link InlineInfo#getMethodToInline method} is inlined. Note that it can be a different
+     * method than the one specified here as the parameter, which allows method substitutions.
+     * <p>
+     * Non-null return value with a null {@link InlineInfo#getMethodToInline method}, e.g.,
+     * {@link InlineInfo#DO_NOT_INLINE_WITH_EXCEPTION}: The method is not inlined, and other plugins
+     * with a lower priority cannot overwrite this decision.
+     * <p>
+     * Null return value: This plugin made no decision, other plugins with a lower priority are
+     * asked.
+     *
+     * @param b the context
+     * @param method the target method of an invoke
+     * @param args the arguments to the invoke
+     * @param returnType the return type derived from {@code method}'s signature
+     */
+    default InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
+        return null;
+    }
+
+    /**
+     * Notification that a method is about to be inlined.
+     *
+     * @param methodToInline the inlined method
+     */
+    default void notifyBeforeInline(ResolvedJavaMethod methodToInline) {
+    }
+
+    /**
+     * Notification that a method was inlined.
+     *
+     * @param methodToInline the inlined method
+     */
+    default void notifyAfterInline(ResolvedJavaMethod methodToInline) {
+    }
+
+    /**
+     * Notifies this plugin of the {@link Invoke} node created for a method that was not inlined per
+     * {@link #shouldInlineInvoke}.
+     *
+     * @param b the context
+     * @param method the method that was not inlined
+     * @param invoke the invoke node created for the call to {@code method}
+     */
+    default void notifyNotInlined(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/IntrinsicContext.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2015, 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.graphbuilderconf;
+
+import static com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
+import static com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
+import static jdk.vm.ci.code.BytecodeFrame.AFTER_BCI;
+import static jdk.vm.ci.code.BytecodeFrame.BEFORE_BCI;
+import static jdk.vm.ci.code.BytecodeFrame.INVALID_FRAMESTATE_BCI;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import com.oracle.graal.nodes.AbstractMergeNode;
+import com.oracle.graal.nodes.FrameState;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.StateSplit;
+import com.oracle.graal.nodes.StructuredGraph;
+
+/**
+ * An intrinsic is a substitute implementation of a Java method (or a bytecode in the case of
+ * snippets) that is itself implemented in Java. This interface provides information about the
+ * intrinsic currently being processed by the graph builder.
+ *
+ * When in the scope of an intrinsic, the graph builder does not check the value kinds flowing
+ * through the JVM state since intrinsics can employ non-Java kinds to represent values such as raw
+ * machine words and pointers.
+ */
+public class IntrinsicContext {
+
+    /**
+     * Gets the method being intrinsified.
+     */
+    final ResolvedJavaMethod method;
+
+    /**
+     * Gets the method providing the intrinsic implementation.
+     */
+    final ResolvedJavaMethod intrinsic;
+
+    public ResolvedJavaMethod getOriginalMethod() {
+        return method;
+    }
+
+    public ResolvedJavaMethod getIntrinsicMethod() {
+        return intrinsic;
+    }
+
+    /**
+     * Determines if a call within the compilation scope of this intrinsic represents a call to the
+     * {@linkplain #getOriginalMethod() original} method. This denotes the path where a partial
+     * intrinsification falls back to the original method.
+     */
+    public boolean isCallToOriginal(ResolvedJavaMethod targetMethod) {
+        return method.equals(targetMethod) || intrinsic.equals(targetMethod);
+    }
+
+    final CompilationContext compilationContext;
+
+    public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, CompilationContext compilationContext) {
+        this.method = method;
+        this.intrinsic = intrinsic;
+        this.compilationContext = compilationContext;
+        assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)");
+    }
+
+    public boolean isPostParseInlined() {
+        return compilationContext.equals(INLINE_AFTER_PARSING);
+    }
+
+    public boolean isCompilationRoot() {
+        return compilationContext.equals(ROOT_COMPILATION);
+    }
+
+    /**
+     * Denotes the compilation context in which an intrinsic is being parsed.
+     */
+    public enum CompilationContext {
+        /**
+         * An intrinsic is being processed when parsing an invoke bytecode that calls the
+         * intrinsified method.
+         */
+        INLINE_DURING_PARSING,
+
+        /**
+         * An intrinsic is being processed when inlining an {@link Invoke} in an existing graph.
+         */
+        INLINE_AFTER_PARSING,
+
+        /**
+         * An intrinsic is the root of compilation.
+         */
+        ROOT_COMPILATION
+    }
+
+    /**
+     * Models the state of a graph in terms of {@link StateSplit#hasSideEffect() side effects} that
+     * are control flow predecessors of the current point in a graph.
+     */
+    public interface SideEffectsState {
+
+        /**
+         * Determines if the current program point is preceded by one or more side effects.
+         */
+        boolean isAfterSideEffect();
+
+        /**
+         * Gets the side effects preceding the current program point.
+         */
+        Iterable<StateSplit> sideEffects();
+
+        /**
+         * Records a side effect for the current program point.
+         */
+        void addSideEffect(StateSplit sideEffect);
+    }
+
+    public FrameState createFrameState(StructuredGraph graph, SideEffectsState sideEffects, StateSplit forStateSplit) {
+        assert forStateSplit != graph.start();
+        if (forStateSplit.hasSideEffect()) {
+            if (sideEffects.isAfterSideEffect()) {
+                // Only the last side effect on any execution path in a replacement
+                // can inherit the stateAfter of the replaced node
+                FrameState invalid = graph.add(new FrameState(INVALID_FRAMESTATE_BCI));
+                for (StateSplit lastSideEffect : sideEffects.sideEffects()) {
+                    lastSideEffect.setStateAfter(invalid);
+                }
+            }
+            sideEffects.addSideEffect(forStateSplit);
+            return graph.add(new FrameState(AFTER_BCI));
+        } else {
+            if (forStateSplit instanceof AbstractMergeNode) {
+                // Merge nodes always need a frame state
+                if (sideEffects.isAfterSideEffect()) {
+                    // A merge after one or more side effects
+                    return graph.add(new FrameState(AFTER_BCI));
+                } else {
+                    // A merge before any side effects
+                    return graph.add(new FrameState(BEFORE_BCI));
+                }
+            } else {
+                // Other non-side-effects do not need a state
+                return null;
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", intrinsic: " + intrinsic.format("%H.%n(%p)") + ", context: " + compilationContext + "}";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/InvocationPlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2015, 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.graphbuilderconf;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.reflect.Method;
+
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.type.StampTool;
+
+/**
+ * Plugin for handling a specific method invocation.
+ */
+public interface InvocationPlugin extends GraphBuilderPlugin {
+
+    /**
+     * The receiver in a non-static method. The class literal for this interface must be used with
+     * {@link InvocationPlugins#put(InvocationPlugin, boolean, boolean, boolean, Class, String, Class...)}
+     * to denote the receiver argument for such a non-static method.
+     */
+    public interface Receiver {
+        /**
+         * Gets the receiver value, null checking it first if necessary.
+         *
+         * @return the receiver value with a {@linkplain StampTool#isPointerNonNull(ValueNode)
+         *         non-null} stamp
+         */
+        ValueNode get();
+
+        /**
+         * Determines if the receiver is constant.
+         */
+        default boolean isConstant() {
+            return false;
+        }
+    }
+
+    /**
+     * Determines if this plugin is for a method with a polymorphic signature (e.g.
+     * {@link MethodHandle#invokeExact(Object...)}).
+     */
+    default boolean isSignaturePolymorphic() {
+        return false;
+    }
+
+    /**
+     * Determines if this plugin can only be used when inlining the method is it associated with.
+     * That is, this plugin cannot be used when the associated method is the compilation root.
+     */
+    default boolean inlineOnly() {
+        return isSignaturePolymorphic();
+    }
+
+    /**
+     * Handles invocation of a signature polymorphic method.
+     *
+     * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static
+     * @param argsIncludingReceiver all arguments to the invocation include the raw receiver in
+     *            position 0 if {@code targetMethod} is not static
+     * @see #execute
+     */
+    default boolean applyPolymorphic(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode... argsIncludingReceiver) {
+        return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver) {
+        return defaultHandler(b, targetMethod, receiver);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg) {
+        return defaultHandler(b, targetMethod, receiver, arg);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2) {
+        return defaultHandler(b, targetMethod, receiver, arg1, arg2);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
+        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) {
+        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4);
+    }
+
+    /**
+     * @see #execute
+     */
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) {
+        return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4, arg5);
+    }
+
+    /**
+     * Executes this plugin against a set of invocation arguments.
+     *
+     * The default implementation in {@link InvocationPlugin} dispatches to the {@code apply(...)}
+     * method that matches the number of arguments or to {@link #applyPolymorphic} if {@code plugin}
+     * is {@linkplain #isSignaturePolymorphic() signature polymorphic}.
+     *
+     * @param targetMethod the method for which this plugin is being applied
+     * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static
+     * @param argsIncludingReceiver all arguments to the invocation include the receiver in position
+     *            0 if {@code targetMethod} is not static
+     * @return {@code true} if this plugin handled the invocation of {@code targetMethod}
+     *         {@code false} if the graph builder should process the invoke further (e.g., by
+     *         inlining it or creating an {@link Invoke} node). A plugin that does not handle an
+     *         invocation must not modify the graph being constructed.
+     */
+    default boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver) {
+        if (isSignaturePolymorphic()) {
+            return applyPolymorphic(b, targetMethod, receiver, argsIncludingReceiver);
+        } else if (receiver != null) {
+            assert !targetMethod.isStatic();
+            assert argsIncludingReceiver.length > 0;
+            if (argsIncludingReceiver.length == 1) {
+                return apply(b, targetMethod, receiver);
+            } else if (argsIncludingReceiver.length == 2) {
+                return apply(b, targetMethod, receiver, argsIncludingReceiver[1]);
+            } else if (argsIncludingReceiver.length == 3) {
+                return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2]);
+            } else if (argsIncludingReceiver.length == 4) {
+                return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3]);
+            } else if (argsIncludingReceiver.length == 5) {
+                return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4]);
+            } else {
+                return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
+            }
+        } else {
+            assert targetMethod.isStatic();
+            if (argsIncludingReceiver.length == 0) {
+                return apply(b, targetMethod, null);
+            } else if (argsIncludingReceiver.length == 1) {
+                return apply(b, targetMethod, null, argsIncludingReceiver[0]);
+            } else if (argsIncludingReceiver.length == 2) {
+                return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1]);
+            } else if (argsIncludingReceiver.length == 3) {
+                return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2]);
+            } else if (argsIncludingReceiver.length == 4) {
+                return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3]);
+            } else if (argsIncludingReceiver.length == 5) {
+                return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4]);
+            } else {
+                return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver);
+            }
+
+        }
+    }
+
+    /**
+     * Handles an invocation when a specific {@code apply} method is not available.
+     */
+    default boolean defaultHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, @SuppressWarnings("unused") InvocationPlugin.Receiver receiver,
+                    ValueNode... args) {
+        throw new JVMCIError("Invocation plugin for %s does not handle invocations with %d arguments", targetMethod.format("%H.%n(%p)"), args.length);
+    }
+
+    default StackTraceElement getApplySourceLocation(MetaAccessProvider metaAccess) {
+        Class<?> c = getClass();
+        for (Method m : c.getDeclaredMethods()) {
+            if (m.getName().equals("apply")) {
+                return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
+            } else if (m.getName().equals("defaultHandler")) {
+                return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
+            }
+        }
+        throw new JVMCIError("could not find method named \"apply\" or \"defaultHandler\" in " + c.getName());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/InvocationPlugins.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,627 @@
+/*
+ * Copyright (c) 2015, 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.graphbuilderconf;
+
+import static java.lang.String.format;
+
+import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.iterators.NodeIterable;
+import com.oracle.graal.nodes.ValueNode;
+
+/**
+ * Manages a set of {@link InvocationPlugin}s.
+ */
+public class InvocationPlugins {
+
+    public static class InvocationPluginReceiver implements InvocationPlugin.Receiver {
+        private final GraphBuilderContext parser;
+        private ValueNode[] args;
+        private ValueNode value;
+
+        public InvocationPluginReceiver(GraphBuilderContext parser) {
+            this.parser = parser;
+        }
+
+        @Override
+        public ValueNode get() {
+            assert args != null : "Cannot get the receiver of a static method";
+            if (value == null) {
+                value = parser.nullCheckedValue(args[0]);
+                if (value != args[0]) {
+                    args[0] = value;
+                }
+            }
+            return value;
+        }
+
+        @Override
+        public boolean isConstant() {
+            return args[0].isConstant();
+        }
+
+        public InvocationPluginReceiver init(ResolvedJavaMethod targetMethod, ValueNode[] newArgs) {
+            if (!targetMethod.isStatic()) {
+                this.args = newArgs;
+                this.value = null;
+                return this;
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Utility for
+     * {@linkplain InvocationPlugins#register(InvocationPlugin, Class, String, Class...)
+     * registration} of invocation plugins.
+     */
+    public static class Registration {
+
+        private final InvocationPlugins plugins;
+        private final Class<?> declaringClass;
+        private boolean allowOverwrite;
+
+        /**
+         * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
+         * given class.
+         *
+         * @param plugins where to register the plugins
+         * @param declaringClass the class declaring the methods for which plugins will be
+         *            registered via this object
+         */
+        public Registration(InvocationPlugins plugins, Class<?> declaringClass) {
+            this.plugins = plugins;
+            this.declaringClass = declaringClass;
+        }
+
+        /**
+         * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
+         * given class.
+         *
+         * @param plugins where to register the plugins
+         * @param declaringClassName the name of the class class declaring the methods for which
+         *            plugins will be registered via this object
+         */
+        public Registration(InvocationPlugins plugins, String declaringClassName) {
+            this.plugins = plugins;
+            try {
+                this.declaringClass = Class.forName(declaringClassName);
+            } catch (ClassNotFoundException ex) {
+                throw JVMCIError.shouldNotReachHere(ex);
+            }
+        }
+
+        /**
+         * Configures this registration to allow or disallow overwriting of invocation plugins.
+         */
+        public Registration setAllowOverwrite(boolean allowOverwrite) {
+            this.allowOverwrite = allowOverwrite;
+            return this;
+        }
+
+        /**
+         * Registers a plugin for a method with no arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register0(String name, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringClass, name);
+        }
+
+        /**
+         * Registers a plugin for a method with 1 argument.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register1(String name, Class<?> arg, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringClass, name, arg);
+        }
+
+        /**
+         * Registers a plugin for a method with 2 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register2(String name, Class<?> arg1, Class<?> arg2, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringClass, name, arg1, arg2);
+        }
+
+        /**
+         * Registers a plugin for a method with 3 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register3(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringClass, name, arg1, arg2, arg3);
+        }
+
+        /**
+         * Registers a plugin for a method with 4 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register4(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringClass, name, arg1, arg2, arg3, arg4);
+        }
+
+        /**
+         * Registers a plugin for a method with 5 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register5(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, Class<?> arg5, InvocationPlugin plugin) {
+            plugins.register(plugin, false, allowOverwrite, declaringClass, name, arg1, arg2, arg3, arg4, arg5);
+        }
+
+        /**
+         * Registers a plugin for an optional method with no arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerOptional0(String name, InvocationPlugin plugin) {
+            plugins.register(plugin, true, allowOverwrite, declaringClass, name);
+        }
+
+        /**
+         * Registers a plugin for an optional method with 1 argument.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerOptional1(String name, Class<?> arg, InvocationPlugin plugin) {
+            plugins.register(plugin, true, allowOverwrite, declaringClass, name, arg);
+        }
+
+        /**
+         * Registers a plugin for an optional method with 2 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerOptional2(String name, Class<?> arg1, Class<?> arg2, InvocationPlugin plugin) {
+            plugins.register(plugin, true, allowOverwrite, declaringClass, name, arg1, arg2);
+        }
+
+        /**
+         * Registers a plugin for an optional method with 3 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerOptional3(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, InvocationPlugin plugin) {
+            plugins.register(plugin, true, allowOverwrite, declaringClass, name, arg1, arg2, arg3);
+        }
+
+        /**
+         * Registers a plugin for an optional method with 4 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerOptional4(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, InvocationPlugin plugin) {
+            plugins.register(plugin, true, allowOverwrite, declaringClass, name, arg1, arg2, arg3, arg4);
+        }
+
+        /**
+         * Registers a plugin that implements a method based on the bytecode of a substitute method.
+         *
+         * @param substituteDeclaringClass the class declaring the substitute method
+         * @param name the name of both the original and substitute method
+         * @param argumentTypes the argument types of the method. Element 0 of this array must be
+         *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
+         *            is non-static. Upon returning, element 0 will have been rewritten to
+         *            {@code declaringClass}
+         */
+        public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, Class<?>... argumentTypes) {
+            registerMethodSubstitution(substituteDeclaringClass, name, name, argumentTypes);
+        }
+
+        /**
+         * Registers a plugin that implements a method based on the bytecode of a substitute method.
+         *
+         * @param substituteDeclaringClass the class declaring the substitute method
+         * @param name the name of both the original method
+         * @param substituteName the name of the substitute method
+         * @param argumentTypes the argument types of the method. Element 0 of this array must be
+         *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
+         *            is non-static. Upon returning, element 0 will have been rewritten to
+         *            {@code declaringClass}
+         */
+        public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, String substituteName, Class<?>... argumentTypes) {
+            MethodSubstitutionPlugin plugin = new MethodSubstitutionPlugin(substituteDeclaringClass, substituteName, argumentTypes);
+            plugins.register(plugin, false, allowOverwrite, declaringClass, name, argumentTypes);
+        }
+    }
+
+    /**
+     * Key for a method.
+     */
+    static class MethodKey {
+        final boolean isStatic;
+
+        /**
+         * This method is optional. This is used for new API methods not present in previous JDK
+         * versions.
+         */
+        final boolean isOptional;
+
+        final Class<?> declaringClass;
+        final String name;
+        final Class<?>[] argumentTypes;
+        final InvocationPlugin value;
+
+        MethodKey(InvocationPlugin data, boolean isStatic, boolean isOptional, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
+            assert isStatic || argumentTypes[0] == declaringClass;
+            this.value = data;
+            this.isStatic = isStatic;
+            this.isOptional = isOptional;
+            this.declaringClass = declaringClass;
+            this.name = name;
+            this.argumentTypes = argumentTypes;
+            assert isOptional || resolveJava() != null;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof MethodKey) {
+                MethodKey that = (MethodKey) obj;
+                boolean res = this.name.equals(that.name) && this.declaringClass.equals(that.declaringClass) && Arrays.equals(this.argumentTypes, that.argumentTypes);
+                assert !res || this.isStatic == that.isStatic;
+                return res;
+            }
+            return false;
+        }
+
+        public int getDeclaredParameterCount() {
+            return isStatic ? argumentTypes.length : argumentTypes.length - 1;
+        }
+
+        @Override
+        public int hashCode() {
+            // Replay compilation mandates use of stable hash codes
+            return declaringClass.getName().hashCode() ^ name.hashCode();
+        }
+
+        private ResolvedJavaMethod resolve(MetaAccessProvider metaAccess) {
+            Executable method = resolveJava();
+            if (method == null) {
+                return null;
+            }
+            return metaAccess.lookupJavaMethod(method);
+        }
+
+        private Executable resolveJava() {
+            try {
+                Executable res;
+                Class<?>[] parameterTypes = isStatic ? argumentTypes : Arrays.copyOfRange(argumentTypes, 1, argumentTypes.length);
+                if (name.equals("<init>")) {
+                    res = declaringClass.getDeclaredConstructor(parameterTypes);
+                } else {
+                    res = declaringClass.getDeclaredMethod(name, parameterTypes);
+                }
+                assert Modifier.isStatic(res.getModifiers()) == isStatic;
+                return res;
+            } catch (NoSuchMethodException | SecurityException e) {
+                if (isOptional) {
+                    return null;
+                }
+                throw new InternalError(e);
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(declaringClass.getName()).append('.').append(name).append('(');
+            for (Class<?> p : argumentTypes) {
+                if (sb.charAt(sb.length() - 1) != '(') {
+                    sb.append(", ");
+                }
+                sb.append(p.getSimpleName());
+            }
+            return sb.append(')').toString();
+        }
+    }
+
+    private final MetaAccessProvider metaAccess;
+
+    /**
+     * Initial list of entries.
+     */
+    private final List<MethodKey> registrations = new ArrayList<>(INITIAL_CAPACITY);
+
+    /**
+     * Deferred registrations as well as guard for initialization of {@link #entries}. The guard
+     * uses double-checked locking which is why this field is {@code volatile}.
+     */
+    private volatile List<Runnable> deferredRegistrations = new ArrayList<>();
+
+    /**
+     * Adds a {@link Runnable} for doing registration deferred until the first time
+     * {@link #get(ResolvedJavaMethod)} or {@link #closeRegistration()} is called on this object.
+     */
+    public void defer(Runnable deferrable) {
+        assert entries == null && deferredRegistrations != null : "registration is closed";
+        deferredRegistrations.add(deferrable);
+    }
+
+    /**
+     * Entry map that is initialized by {@link #initializeMap()}.
+     */
+    private Map<ResolvedJavaMethod, InvocationPlugin> entries;
+
+    private static final int INITIAL_CAPACITY = 64;
+
+    /**
+     * Adds an entry to this map for a specified method.
+     *
+     * @param value value to be associated with the specified method
+     * @param isStatic specifies if the method is static
+     * @param isOptional specifies if the method is optional
+     * @param declaringClass the class declaring the method
+     * @param name the name of the method
+     * @param argumentTypes the argument types of the method. Element 0 of this array must be
+     *            {@code declaringClass} iff the method is non-static.
+     * @return an object representing the method
+     */
+    MethodKey put(InvocationPlugin value, boolean isStatic, boolean isOptional, boolean allowOverwrite, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
+        assert isStatic || argumentTypes[0] == declaringClass;
+        MethodKey methodKey = new MethodKey(value, isStatic, isOptional, declaringClass, name, argumentTypes);
+        assert entries == null : "registration is closed";
+        assert allowOverwrite || !registrations.contains(methodKey) : "a value is already registered for " + methodKey;
+        registrations.add(methodKey);
+        return methodKey;
+    }
+
+    /**
+     * Determines if a method denoted by a given {@link MethodKey} is in this map.
+     */
+    boolean containsKey(MethodKey key) {
+        return registrations.contains(key);
+    }
+
+    InvocationPlugin get(ResolvedJavaMethod method) {
+        if (deferredRegistrations != null) {
+            initializeMap();
+        }
+        return entries.get(method);
+    }
+
+    /**
+     * Disallows new registrations of new plugins, and creates the internal tables for method
+     * lookup.
+     */
+    public void closeRegistration() {
+        if (deferredRegistrations != null) {
+            initializeMap();
+        }
+    }
+
+    void initializeMap() {
+        if (deferredRegistrations != null) {
+            synchronized (this) {
+                if (deferredRegistrations != null) {
+                    List<Runnable> localDeferredRegistrations = deferredRegistrations;
+                    for (Runnable deferrable : localDeferredRegistrations) {
+                        deferrable.run();
+                    }
+                    if (registrations.isEmpty()) {
+                        entries = Collections.emptyMap();
+                    } else {
+                        Map<ResolvedJavaMethod, InvocationPlugin> newEntries = new HashMap<>();
+                        for (MethodKey methodKey : registrations) {
+                            ResolvedJavaMethod m = methodKey.resolve(metaAccess);
+                            newEntries.put(m, methodKey.value);
+                        }
+                        entries = newEntries;
+                    }
+                    deferredRegistrations = null;
+                }
+            }
+        }
+    }
+
+    public int size() {
+        return registrations.size();
+    }
+
+    /**
+     * The plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched} before searching in
+     * this object.
+     */
+    protected final InvocationPlugins parent;
+
+    private InvocationPlugins(InvocationPlugins parent, MetaAccessProvider metaAccess) {
+        this.metaAccess = metaAccess;
+        InvocationPlugins p = parent;
+        this.parent = p;
+    }
+
+    /**
+     * Creates a set of invocation plugins with a non-null {@linkplain #getParent() parent}.
+     */
+    public InvocationPlugins(InvocationPlugins parent) {
+        this(parent, parent.getMetaAccess());
+    }
+
+    public MetaAccessProvider getMetaAccess() {
+        return metaAccess;
+    }
+
+    public InvocationPlugins(MetaAccessProvider metaAccess) {
+        this(null, metaAccess);
+    }
+
+    private void register(InvocationPlugin plugin, boolean isOptional, boolean allowOverwrite, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
+        boolean isStatic = argumentTypes.length == 0 || argumentTypes[0] != InvocationPlugin.Receiver.class;
+        if (!isStatic) {
+            argumentTypes[0] = declaringClass;
+        }
+        MethodKey methodInfo = put(plugin, isStatic, isOptional, allowOverwrite, declaringClass, name, argumentTypes);
+        assert Checker.check(this, methodInfo, plugin);
+    }
+
+    /**
+     * Registers an invocation plugin for a given method. There must be no plugin currently
+     * registered for {@code method}.
+     *
+     * @param argumentTypes the argument types of the method. Element 0 of this array must be the
+     *            {@link Class} value for {@link InvocationPlugin.Receiver} iff the method is
+     *            non-static. Upon returning, element 0 will have been rewritten to
+     *            {@code declaringClass}
+     */
+    public void register(InvocationPlugin plugin, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
+        register(plugin, false, false, declaringClass, name, argumentTypes);
+    }
+
+    /**
+     * Registers an invocation plugin for a given, optional method. There must be no plugin
+     * currently registered for {@code method}.
+     *
+     * @param argumentTypes the argument types of the method. Element 0 of this array must be the
+     *            {@link Class} value for {@link InvocationPlugin.Receiver} iff the method is
+     *            non-static. Upon returning, element 0 will have been rewritten to
+     *            {@code declaringClass}
+     */
+    public void registerOptional(InvocationPlugin plugin, Class<?> declaringClass, String name, Class<?>... argumentTypes) {
+        register(plugin, true, false, declaringClass, name, argumentTypes);
+    }
+
+    /**
+     * Gets the plugin for a given method.
+     *
+     * @param method the method to lookup
+     * @return the plugin associated with {@code method} or {@code null} if none exists
+     */
+    public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
+        if (parent != null) {
+            InvocationPlugin plugin = parent.lookupInvocation(method);
+            if (plugin != null) {
+                return plugin;
+            }
+        }
+        return get(method);
+    }
+
+    /**
+     * Gets the invocation plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched}
+     * before searching in this object.
+     */
+    public InvocationPlugins getParent() {
+        return parent;
+    }
+
+    @Override
+    public String toString() {
+        return registrations.stream().map(MethodKey::toString).collect(Collectors.joining(", ")) + " / parent: " + this.parent;
+    }
+
+    private static class Checker {
+        private static final int MAX_ARITY = 5;
+        /**
+         * The set of all {@link InvocationPlugin#apply} method signatures.
+         */
+        static final Class<?>[][] SIGS;
+
+        static {
+            ArrayList<Class<?>[]> sigs = new ArrayList<>(MAX_ARITY);
+            for (Method method : InvocationPlugin.class.getDeclaredMethods()) {
+                if (!Modifier.isStatic(method.getModifiers()) && method.getName().equals("apply")) {
+                    Class<?>[] sig = method.getParameterTypes();
+                    assert sig[0] == GraphBuilderContext.class;
+                    assert sig[1] == ResolvedJavaMethod.class;
+                    assert sig[2] == InvocationPlugin.Receiver.class;
+                    assert Arrays.asList(sig).subList(3, sig.length).stream().allMatch(c -> c == ValueNode.class);
+                    while (sigs.size() < sig.length - 2) {
+                        sigs.add(null);
+                    }
+                    sigs.set(sig.length - 3, sig);
+                }
+            }
+            assert sigs.indexOf(null) == -1 : format("need to add an apply() method to %s that takes %d %s arguments ", InvocationPlugin.class.getName(), sigs.indexOf(null),
+                            ValueNode.class.getSimpleName());
+            SIGS = sigs.toArray(new Class<?>[sigs.size()][]);
+        }
+
+        public static boolean check(InvocationPlugins plugins, MethodKey method, InvocationPlugin plugin) {
+            InvocationPlugins p = plugins.parent;
+            while (p != null) {
+                assert !p.containsKey(method) : "a plugin is already registered for " + method;
+                p = p.parent;
+            }
+            if (plugin instanceof ForeignCallPlugin || plugin instanceof GeneratedInvocationPlugin) {
+                return true;
+            }
+            if (plugin instanceof MethodSubstitutionPlugin) {
+                MethodSubstitutionPlugin msplugin = (MethodSubstitutionPlugin) plugin;
+                msplugin.getJavaSubstitute();
+                return true;
+            }
+            int arguments = method.getDeclaredParameterCount();
+            assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method);
+            for (Method m : plugin.getClass().getDeclaredMethods()) {
+                if (m.getName().equals("apply")) {
+                    Class<?>[] parameterTypes = m.getParameterTypes();
+                    if (Arrays.equals(SIGS[arguments], parameterTypes)) {
+                        return true;
+                    }
+                }
+            }
+            throw new AssertionError(format("graph builder plugin for %s not found", method));
+        }
+    }
+
+    /**
+     * Checks a set of nodes added to the graph by an {@link InvocationPlugin}.
+     *
+     * @param b the graph builder that applied the plugin
+     * @param plugin a plugin that was just applied
+     * @param newNodes the nodes added to the graph by {@code plugin}
+     * @throws AssertionError if any check fail
+     */
+    public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable<Node> newNodes) {
+        if (parent != null) {
+            parent.checkNewNodes(b, plugin, newNodes);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/LoopExplosionPlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015, 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.graphbuilderconf;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public interface LoopExplosionPlugin extends GraphBuilderPlugin {
+    boolean shouldExplodeLoops(ResolvedJavaMethod method);
+
+    boolean shouldMergeExplosions(ResolvedJavaMethod method);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/MethodSubstitutionPlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2015, 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.graphbuilderconf;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import sun.misc.Launcher;
+
+import com.oracle.graal.nodes.ValueNode;
+
+/**
+ * An {@link InvocationPlugin} for a method where the implementation of the method is provided by a
+ * {@linkplain #getSubstitute(MetaAccessProvider) substitute} method. A substitute method must be
+ * static even if the substituted method is not.
+ */
+public final class MethodSubstitutionPlugin implements InvocationPlugin {
+
+    private ResolvedJavaMethod cachedSubstitute;
+
+    /**
+     * The class in which the substitute method is declared.
+     */
+    private final Class<?> declaringClass;
+
+    /**
+     * The name of the original and substitute method.
+     */
+    private final String name;
+
+    /**
+     * The parameter types of the substitute method.
+     */
+    private final Class<?>[] parameters;
+
+    private final boolean originalIsStatic;
+
+    /**
+     * Creates a method substitution plugin.
+     *
+     * @param declaringClass the class in which the substitute method is declared
+     * @param name the name of the substitute method
+     * @param parameters the parameter types of the substitute method. If the original method is not
+     *            static, then {@code parameters[0]} must be the {@link Class} value denoting
+     *            {@link InvocationPlugin.Receiver}
+     */
+    public MethodSubstitutionPlugin(Class<?> declaringClass, String name, Class<?>... parameters) {
+        this.declaringClass = declaringClass;
+        this.name = name;
+        this.parameters = parameters;
+        this.originalIsStatic = parameters.length == 0 || parameters[0] != InvocationPlugin.Receiver.class;
+    }
+
+    /**
+     * Creates a method substitution plugin.
+     *
+     * @param declaringClass the class in which the substitute method is declared
+     * @param name the name of the substitute method
+     * @param parameters the parameter types of the substitute method
+     */
+    public MethodSubstitutionPlugin(boolean originalIsStatic, Class<?> declaringClass, String name, Class<?>... parameters) {
+        this.declaringClass = declaringClass;
+        this.name = name;
+        this.parameters = parameters;
+        this.originalIsStatic = originalIsStatic;
+    }
+
+    public boolean inlineOnly() {
+        // Conservatively assume MacroNodes may be used in a substitution
+        return true;
+    }
+
+    /**
+     * Gets the substitute method, resolving it first if necessary.
+     */
+    public ResolvedJavaMethod getSubstitute(MetaAccessProvider metaAccess) {
+        if (cachedSubstitute == null) {
+            cachedSubstitute = metaAccess.lookupJavaMethod(getJavaSubstitute());
+        }
+        return cachedSubstitute;
+    }
+
+    /**
+     * Gets the reflection API version of the substitution method.
+     */
+    Method getJavaSubstitute() throws JVMCIError {
+        Method substituteMethod = lookupSubstitute();
+        int modifiers = substituteMethod.getModifiers();
+        if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+            throw new JVMCIError("Substitution method must not be abstract or native: " + substituteMethod);
+        }
+        if (!Modifier.isStatic(modifiers)) {
+            throw new JVMCIError("Substitution method must be static: " + substituteMethod);
+        }
+        return substituteMethod;
+    }
+
+    /**
+     * Determines if a given method is the substitute method of this plugin.
+     */
+    private boolean isSubstitute(Method m) {
+        if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(name)) {
+            if (parameters.length == m.getParameterCount()) {
+                Class<?>[] mparams = m.getParameterTypes();
+                int start = 0;
+                if (!originalIsStatic) {
+                    start = 1;
+                    if (!mparams[0].isAssignableFrom(parameters[0])) {
+                        return false;
+                    }
+                }
+                for (int i = start; i < mparams.length; i++) {
+                    if (mparams[i] != parameters[i]) {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Gets the substitute method of this plugin.
+     */
+    private Method lookupSubstitute() {
+        for (Method m : declaringClass.getDeclaredMethods()) {
+            if (isSubstitute(m)) {
+                return m;
+            }
+        }
+        throw new JVMCIError("No method found specified by %s", this);
+    }
+
+    /**
+     * Resolves a name to a class.
+     *
+     * @param className the name of the class to resolve
+     * @param optional if true, resolution failure returns null
+     * @return the resolved class or null if resolution fails and {@code optional} is true
+     */
+    public static Class<?> resolveClass(String className, boolean optional) {
+        try {
+            // Need to use launcher class path to handle classes
+            // that are not on the boot class path
+            ClassLoader cl = Launcher.getLauncher().getClassLoader();
+            return Class.forName(className, false, cl);
+        } catch (ClassNotFoundException e) {
+            if (optional) {
+                return null;
+            }
+            throw new JVMCIError("Could not resolve type " + className);
+        }
+    }
+
+    @Override
+    public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver) {
+        ResolvedJavaMethod subst = getSubstitute(b.getMetaAccess());
+        if (receiver != null) {
+            receiver.get();
+        }
+        b.intrinsify(targetMethod, subst, argsIncludingReceiver);
+        return true;
+    }
+
+    public StackTraceElement getApplySourceLocation(MetaAccessProvider metaAccess) {
+        Class<?> c = getClass();
+        for (Method m : c.getDeclaredMethods()) {
+            if (m.getName().equals("execute")) {
+                return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
+            }
+        }
+        throw new JVMCIError("could not find method named \"execute\" in " + c.getName());
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s[%s.%s(%s)]", getClass().getSimpleName(), declaringClass.getName(), name,
+                        Arrays.asList(parameters).stream().map(c -> c.getSimpleName()).collect(Collectors.joining(", ")));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/NodeIntrinsicPluginFactory.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015, 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.graphbuilderconf;
+
+import com.oracle.graal.compiler.common.type.Stamp;
+
+public interface NodeIntrinsicPluginFactory {
+
+    public interface InjectionProvider {
+
+        <T> T getInjectedArgument(Class<T> type);
+
+        Stamp getReturnStamp(Class<?> type);
+    }
+
+    void registerPlugin(InvocationPlugins plugins, InjectionProvider injection);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/NodePlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2015, 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.graphbuilderconf;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaTypeProfile;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Signature;
+
+import com.oracle.graal.nodes.ValueNode;
+
+public interface NodePlugin extends GraphBuilderPlugin {
+    /**
+     * Handle the parsing of a method invocation bytecode to a method that can be bound statically.
+     * If the method returns true, it must {@link GraphBuilderContext#push push} a value as the
+     * result of the method invocation using the {@link Signature#getReturnKind return kind} of the
+     * method.
+     *
+     * @param b the context
+     * @param method the statically bound, invoked method
+     * @param args the arguments of the method invocation
+     * @return true if the plugin handles the invocation, false otherwise
+     */
+    default boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a GETFIELD bytecode. If the method returns true, it must
+     * {@link GraphBuilderContext#push push} a value using the
+     * {@link ResolvedJavaField#getJavaKind() kind} of the field.
+     *
+     * @param b the context
+     * @param object the receiver object for the field access
+     * @param field the accessed field
+     * @return true if the plugin handles the field access, false otherwise
+     */
+    default boolean handleLoadField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a GETSTATIC bytecode. If the method returns true, it must
+     * {@link GraphBuilderContext#push push} a value using the
+     * {@link ResolvedJavaField#getJavaKind() kind} of the field.
+     *
+     * @param b the context
+     * @param field the accessed field
+     * @return true if the plugin handles the field access, false otherwise
+     */
+    default boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField field) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a PUTFIELD bytecode.
+     *
+     * @param b the context
+     * @param object the receiver object for the field access
+     * @param field the accessed field
+     * @param value the value to be stored into the field
+     * @return true if the plugin handles the field access, false otherwise
+     */
+    default boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a PUTSTATIC bytecode.
+     *
+     * @param b the context
+     * @param field the accessed field
+     * @param value the value to be stored into the field
+     * @return true if the plugin handles the field access, false otherwise.
+     */
+    default boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of an array load bytecode. If the method returns true, it must
+     * {@link GraphBuilderContext#push push} a value using the provided elementKind.
+     *
+     * @param b the context
+     * @param array the accessed array
+     * @param index the index for the array access
+     * @param elementKind the element kind of the accessed array
+     * @return true if the plugin handles the array access, false otherwise.
+     */
+    default boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of an array store bytecode.
+     *
+     * @param b the context
+     * @param array the accessed array
+     * @param index the index for the array access
+     * @param elementKind the element kind of the accessed array
+     * @param value the value to be stored into the array
+     * @return true if the plugin handles the array access, false otherwise.
+     */
+    default boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind, ValueNode value) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a CHECKCAST bytecode. If the method returns true, it must
+     * {@link GraphBuilderContext#push push} a value with the result of the cast using
+     * {@link JavaKind#Object}.
+     *
+     * @param b the context
+     * @param object the object to be type checked
+     * @param type the type that the object is checked against
+     * @param profile the profiling information for the type check, or null if no profiling
+     *            information is available
+     * @return true if the plugin handles the cast, false otherwise
+     */
+    default boolean handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a INSTANCEOF bytecode. If the method returns true, it must
+     * {@link GraphBuilderContext#push push} a value with the result of the instanceof using
+     * {@link JavaKind#Int}.
+     *
+     * @param b the context
+     * @param object the object to be type checked
+     * @param type the type that the object is checked against
+     * @param profile the profiling information for the type check, or null if no profiling
+     *            information is available
+     * @return true if the plugin handles the instanceof, false otherwise
+     */
+    default boolean handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a NEW bytecode. If the method returns true, it must
+     * {@link GraphBuilderContext#push push} a value with the result of the allocation using
+     * {@link JavaKind#Object}.
+     *
+     * @param b the context
+     * @param type the type to be instantiated
+     * @return true if the plugin handles the bytecode, false otherwise
+     */
+    default boolean handleNewInstance(GraphBuilderContext b, ResolvedJavaType type) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a NEWARRAY and ANEWARRAY bytecode. If the method returns true, it must
+     * {@link GraphBuilderContext#push push} a value with the result of the allocation using
+     * {@link JavaKind#Object}.
+     *
+     * @param b the context
+     * @param elementType the element type of the array to be instantiated
+     * @param length the length of the new array
+     * @return true if the plugin handles the bytecode, false otherwise
+     */
+    default boolean handleNewArray(GraphBuilderContext b, ResolvedJavaType elementType, ValueNode length) {
+        return false;
+    }
+
+    /**
+     * Handle the parsing of a MULTIANEWARRAY bytecode. If the method returns true, it must
+     * {@link GraphBuilderContext#push push} a value with the result of the allocation using
+     * {@link JavaKind#Object}.
+     *
+     * @param b the context
+     * @param type the type of the outermost array to be instantiated
+     * @param dimensions the array of lengths for all the dimensions to be instantiated
+     * @return true if the plugin handles the bytecode, false otherwise
+     */
+    default boolean handleNewMultiArray(GraphBuilderContext b, ResolvedJavaType type, ValueNode[] dimensions) {
+        return false;
+    }
+
+    /**
+     * If the plugin {@link GraphBuilderContext#push pushes} a value with a different
+     * {@link JavaKind} than specified by the bytecode, it must override this method and return
+     * {@code true}. This disables assertion checking for value kinds.
+     *
+     * @param b the context
+     */
+    default boolean canChangeStackKind(GraphBuilderContext b) {
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/ParameterPlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, 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.graphbuilderconf;
+
+import com.oracle.graal.compiler.common.type.Stamp;
+import com.oracle.graal.nodes.calc.FloatingNode;
+
+public interface ParameterPlugin extends GraphBuilderPlugin {
+    FloatingNode interceptParameter(GraphBuilderContext b, int index, Stamp stamp);
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/WriteNode.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/WriteNode.java	Tue Dec 08 12:30:15 2015 -0800
@@ -49,7 +49,7 @@
 
     public static final NodeClass<WriteNode> TYPE = NodeClass.create(WriteNode.class);
 
-    private WriteNode(ValueNode address, LocationIdentity location, ValueNode value, BarrierType barrierType) {
+    protected WriteNode(ValueNode address, LocationIdentity location, ValueNode value, BarrierType barrierType) {
         this((AddressNode) address, location, value, barrierType);
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -242,9 +242,23 @@
                     return true;
                 }
             }
+            assert assertLeafGVN(node, nodeClass);
             return false;
         }
 
+        /**
+         * Ensure that leaf nodes have already been GVN'ed. This is normally handled automatically
+         * but it's possible to add nodes to the graph with looking for duplicates and it's the
+         * responsibility of code that does that to clean it up.
+         */
+        private boolean assertLeafGVN(Node node, NodeClass<?> nodeClass) {
+            if (node.isAlive() && nodeClass.valueNumberable() && nodeClass.isLeafNode()) {
+                Node newNode = node.graph().findDuplicate(node);
+                return (newNode == null || newNode == node);
+            }
+            return true;
+        }
+
         private AutoCloseable getCanonicalizeableContractAssertion(Node node) {
             boolean needsAssertion = false;
             assert (needsAssertion = true) == true;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DominatorConditionalEliminationPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DominatorConditionalEliminationPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -568,6 +568,9 @@
 
         private Iterable<InfoElement> getInfoElements(ValueNode proxiedValue) {
             ValueNode value = GraphUtil.unproxify(proxiedValue);
+            if (value == null) {
+                return Collections.emptyList();
+            }
             Info info = map.get(value);
             if (info == null) {
                 return Collections.emptyList();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -22,11 +22,11 @@
  */
 package com.oracle.graal.phases.common;
 
+import com.oracle.graal.nodes.EntryProxyNode;
 import com.oracle.graal.nodes.FrameState;
 import com.oracle.graal.nodes.LoopExitNode;
 import com.oracle.graal.nodes.ProxyNode;
 import com.oracle.graal.nodes.StructuredGraph;
-import com.oracle.graal.nodes.ValueProxyNode;
 import com.oracle.graal.nodes.util.GraphUtil;
 import com.oracle.graal.phases.Phase;
 
@@ -35,7 +35,7 @@
     @Override
     protected void run(StructuredGraph graph) {
         for (ProxyNode vpn : graph.getNodes(ProxyNode.TYPE)) {
-            if (vpn instanceof ValueProxyNode) {
+            if (!(vpn instanceof EntryProxyNode)) {
                 graph.replaceFloating(vpn, vpn.value());
             }
         }
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64GraphBuilderPlugins.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64GraphBuilderPlugins.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -32,14 +32,14 @@
 import sun.misc.Unsafe;
 
 import com.oracle.graal.compiler.common.spi.ForeignCallsProvider;
-import com.oracle.graal.graphbuilderconf.ForeignCallPlugin;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin.Receiver;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.graphbuilderconf.ForeignCallPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin.Receiver;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.java.AtomicReadAndAddNode;
 import com.oracle.graal.nodes.java.AtomicReadAndWriteNode;
 import com.oracle.graal.nodes.memory.address.AddressNode;
@@ -54,10 +54,14 @@
 
     public static void register(Plugins plugins, ForeignCallsProvider foreignCalls, AMD64 arch) {
         InvocationPlugins invocationPlugins = plugins.getInvocationPlugins();
-        registerIntegerLongPlugins(invocationPlugins, IntegerSubstitutions.class, JavaKind.Int, arch);
-        registerIntegerLongPlugins(invocationPlugins, LongSubstitutions.class, JavaKind.Long, arch);
-        registerUnsafePlugins(invocationPlugins);
-        registerMathPlugins(invocationPlugins, foreignCalls);
+        invocationPlugins.defer(new Runnable() {
+            public void run() {
+                registerIntegerLongPlugins(invocationPlugins, IntegerSubstitutions.class, JavaKind.Int, arch);
+                registerIntegerLongPlugins(invocationPlugins, LongSubstitutions.class, JavaKind.Long, arch);
+                registerUnsafePlugins(invocationPlugins);
+                registerMathPlugins(invocationPlugins, foreignCalls);
+            }
+        });
     }
 
     private static void registerIntegerLongPlugins(InvocationPlugins plugins, Class<?> substituteDeclaringClass, JavaKind kind, AMD64 arch) {
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64MathSubstitutions.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64MathSubstitutions.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, 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
@@ -114,9 +114,9 @@
         }
     }
 
-    @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true)
+    @NodeIntrinsic(value = ForeignCallNode.class)
     private static native double callDouble1(@ConstantNodeParameter ForeignCallDescriptor descriptor, double value);
 
-    @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true)
+    @NodeIntrinsic(value = ForeignCallNode.class)
     private static native double callDouble2(@ConstantNodeParameter ForeignCallDescriptor descriptor, double a, double b);
 }
--- a/graal/com.oracle.graal.replacements.sparc/src/com/oracle/graal/replacements/sparc/SPARCGraphBuilderPlugins.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements.sparc/src/com/oracle/graal/replacements/sparc/SPARCGraphBuilderPlugins.java	Tue Dec 08 12:30:15 2015 -0800
@@ -33,13 +33,13 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 import com.oracle.graal.compiler.common.spi.ForeignCallsProvider;
-import com.oracle.graal.graphbuilderconf.ForeignCallPlugin;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.graphbuilderconf.ForeignCallPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.replacements.IntegerSubstitutions;
 import com.oracle.graal.replacements.LongSubstitutions;
 import com.oracle.graal.replacements.nodes.BitCountNode;
@@ -48,9 +48,13 @@
 
     public static void register(Plugins plugins, ForeignCallsProvider foreignCalls) {
         InvocationPlugins invocationPlugins = plugins.getInvocationPlugins();
-        registerIntegerLongPlugins(invocationPlugins, IntegerSubstitutions.class, JavaKind.Int);
-        registerIntegerLongPlugins(invocationPlugins, LongSubstitutions.class, JavaKind.Long);
-        registerMathPlugins(invocationPlugins, foreignCalls);
+        invocationPlugins.defer(new Runnable() {
+            public void run() {
+                registerIntegerLongPlugins(invocationPlugins, IntegerSubstitutions.class, JavaKind.Int);
+                registerIntegerLongPlugins(invocationPlugins, LongSubstitutions.class, JavaKind.Long);
+                registerMathPlugins(invocationPlugins, foreignCalls);
+            }
+        });
     }
 
     private static void registerIntegerLongPlugins(InvocationPlugins plugins, Class<?> substituteDeclaringClass, JavaKind kind) {
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DerivedOopTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DerivedOopTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -31,12 +31,12 @@
 
 import com.oracle.graal.api.directives.GraalDirectives;
 import com.oracle.graal.compiler.test.GraalCompilerTest;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.replacements.Snippets;
 import com.oracle.graal.word.Word;
 import com.oracle.graal.word.nodes.WordCastNode;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/FoldTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2015, 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.replacements.test;
+
+import org.junit.Test;
+
+import com.oracle.graal.api.directives.GraalDirectives;
+import com.oracle.graal.api.replacements.ClassSubstitution;
+import com.oracle.graal.api.replacements.Fold;
+import com.oracle.graal.api.replacements.MethodSubstitution;
+import com.oracle.graal.compiler.test.GraalCompilerTest;
+import com.oracle.graal.nodes.ReturnNode;
+import com.oracle.graal.nodes.StartNode;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.nodes.graphbuilderconf.NodeIntrinsicPluginFactory.InjectionProvider;
+import com.oracle.graal.replacements.NodeIntrinsificationProvider;
+
+public class FoldTest extends GraalCompilerTest {
+
+    private static class TestMethod {
+
+        public static int test() {
+            return 42;
+        }
+    }
+
+    static class FoldUtils {
+
+        private int number;
+
+        FoldUtils(int number) {
+            this.number = number;
+        }
+
+        @Fold
+        static int multiply(int a, int b) {
+            // we want to test whether @Fold works, so prevent automatic constant folding
+            return a * GraalDirectives.opaque(b);
+        }
+
+        @Fold
+        int getNumber() {
+            // we want to test whether @Fold works, so prevent automatic constant folding
+            return GraalDirectives.opaque(number);
+        }
+    }
+
+    @ClassSubstitution(TestMethod.class)
+    private static class TestMethodSubstitution {
+
+        private static final FoldUtils utils = new FoldUtils(21);
+
+        @MethodSubstitution
+        public static int test() {
+            return FoldUtils.multiply(utils.getNumber(), 2);
+        }
+    }
+
+    private static boolean substitutionsInstalled;
+
+    public FoldTest() {
+        if (!substitutionsInstalled) {
+            getProviders().getReplacements().registerSubstitutions(TestMethod.class, TestMethodSubstitution.class);
+            substitutionsInstalled = true;
+        }
+    }
+
+    public static int callTest() {
+        return TestMethod.test();
+    }
+
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins ret = super.getDefaultGraphBuilderPlugins();
+        // manually register generated factories, jvmci service providers don't work from unit tests
+        InjectionProvider injection = new NodeIntrinsificationProvider(getMetaAccess(), getSnippetReflection(), getProviders().getForeignCalls(), null);
+        new FoldFactory_FoldTest_FoldUtils_getNumber().registerPlugin(ret.getInvocationPlugins(), injection);
+        new FoldFactory_FoldTest_FoldUtils_multiply_255f288().registerPlugin(ret.getInvocationPlugins(), injection);
+        return ret;
+    }
+
+    @Override
+    protected boolean checkHighTierGraph(StructuredGraph graph) {
+        // check that folding happened correctly
+        StartNode start = graph.start();
+        assert start.next() instanceof ReturnNode : "expected ReturnNode, got " + start.next();
+
+        ReturnNode ret = (ReturnNode) start.next();
+        assert ret.result().isConstant() : "expected ConstantNode, got " + ret.result();
+        return true;
+    }
+
+    @Test
+    public void snippetTest() {
+        test("callTest");
+    }
+}
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PEGraphDecoderTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PEGraphDecoderTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -32,16 +32,16 @@
 import com.oracle.graal.compiler.common.type.StampFactory;
 import com.oracle.graal.compiler.test.GraalCompilerTest;
 import com.oracle.graal.debug.Debug;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InlineInvokePlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.AbstractBeginNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InlineInvokePlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.memory.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.memory.ReadNode;
 import com.oracle.graal.nodes.memory.address.AddressNode;
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTrackingTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTrackingTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -31,11 +31,11 @@
 import com.oracle.graal.compiler.test.GraalCompilerTest;
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.DebugConfigScope;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.replacements.Snippets;
 import com.oracle.graal.word.Word;
 
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -35,6 +35,7 @@
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.nodes.PiNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.spi.Replacements;
 import com.oracle.graal.runtime.RuntimeProvider;
 
@@ -43,6 +44,14 @@
  */
 public class ReplacementsParseTest extends GraalCompilerTest {
 
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins ret = super.getDefaultGraphBuilderPlugins();
+        // manually register generated factory, jvmci service providers don't work from unit tests
+        new NodeIntrinsicFactory_ReplacementsParseTest_TestMethodsSubstitutions_asNonNullStringIntrinsic_2bfccb54().registerPlugin(ret.getInvocationPlugins(), null);
+        return ret;
+    }
+
     private static final Object THROW_EXCEPTION_MARKER = new Object() {
         @Override
         public String toString() {
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/SubstitutionsTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/SubstitutionsTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -46,12 +46,13 @@
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.calc.FloatingNode;
 import com.oracle.graal.nodes.extended.GuardingNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.memory.MemoryNode;
 
 public class SubstitutionsTest extends GraalCompilerTest {
 
     @NodeInfo(allowedUsageTypes = {Memory})
-    private static class TestMemory extends FixedWithNextNode implements MemoryNode {
+    static class TestMemory extends FixedWithNextNode implements MemoryNode {
         private static final NodeClass<TestMemory> TYPE = NodeClass.create(TestMemory.class);
 
         public TestMemory() {
@@ -63,7 +64,7 @@
     }
 
     @NodeInfo(allowedUsageTypes = {Guard})
-    private static class TestGuard extends FloatingNode implements GuardingNode {
+    static class TestGuard extends FloatingNode implements GuardingNode {
         private static final NodeClass<TestGuard> TYPE = NodeClass.create(TestGuard.class);
 
         @Input(Memory) MemoryNode memory;
@@ -78,7 +79,7 @@
     }
 
     @NodeInfo
-    private static class TestValue extends FloatingNode {
+    static class TestValue extends FloatingNode {
         private static final NodeClass<TestValue> TYPE = NodeClass.create(TestValue.class);
 
         @Input(Guard) GuardingNode guard;
@@ -124,6 +125,16 @@
     }
 
     @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins ret = super.getDefaultGraphBuilderPlugins();
+        // manually register generated factories, jvmci service providers don't work from unit tests
+        new NodeIntrinsicFactory_SubstitutionsTest_TestGuard_guard_1c2b7e8f().registerPlugin(ret.getInvocationPlugins(), null);
+        new NodeIntrinsicFactory_SubstitutionsTest_TestMemory_memory().registerPlugin(ret.getInvocationPlugins(), null);
+        new NodeIntrinsicFactory_SubstitutionsTest_TestValue_value_a22f0f5f().registerPlugin(ret.getInvocationPlugins(), null);
+        return ret;
+    }
+
+    @Override
     protected boolean checkHighTierGraph(StructuredGraph graph) {
         // Check that the graph contains the expected test nodes.
         NodeIterable<ReturnNode> retNodes = graph.getNodes().filter(ReturnNode.class);
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/APHotSpotSignature.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/APHotSpotSignature.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -26,9 +26,18 @@
 import java.util.List;
 
 import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.PackageElement;
 import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
 import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.WildcardType;
 import javax.tools.Diagnostic.Kind;
 
 /**
@@ -96,6 +105,81 @@
         return cur;
     }
 
+    private static void getSignatureName(StringBuilder ret, Element element) {
+        Element enclosing = element.getEnclosingElement();
+        if (enclosing.getKind() == ElementKind.PACKAGE) {
+            ret.append(((PackageElement) enclosing).getQualifiedName().toString().replace('.', '/'));
+            ret.append('/');
+        } else {
+            getSignatureName(ret, enclosing);
+            ret.append('$');
+        }
+        ret.append(element.getSimpleName());
+    }
+
+    private static void getSignatureString(StringBuilder ret, TypeMirror type) {
+        switch (type.getKind()) {
+            case ARRAY:
+                ret.append('[');
+                getSignatureString(ret, ((ArrayType) type).getComponentType());
+                break;
+            case BOOLEAN:
+                ret.append('Z');
+                break;
+            case BYTE:
+                ret.append('B');
+                break;
+            case SHORT:
+                ret.append('S');
+                break;
+            case CHAR:
+                ret.append('C');
+                break;
+            case INT:
+                ret.append('I');
+                break;
+            case LONG:
+                ret.append('J');
+                break;
+            case FLOAT:
+                ret.append('F');
+                break;
+            case DOUBLE:
+                ret.append('D');
+                break;
+            case VOID:
+                ret.append('V');
+                break;
+            case DECLARED:
+                ret.append('L');
+                getSignatureName(ret, ((DeclaredType) type).asElement());
+                ret.append(';');
+                break;
+            case TYPEVAR:
+                getSignatureString(ret, ((TypeVariable) type).getUpperBound());
+                break;
+            case WILDCARD:
+                getSignatureString(ret, ((WildcardType) type).getExtendsBound());
+                break;
+            case INTERSECTION:
+                ret.append("Ljava/lang/Object;");
+                break;
+            default:
+                throw new IllegalArgumentException(type.toString());
+        }
+    }
+
+    public static String toSignature(ExecutableElement intrinsicMethod) {
+        StringBuilder ret = new StringBuilder();
+        ret.append('(');
+        for (VariableElement param : intrinsicMethod.getParameters()) {
+            getSignatureString(ret, param.asType());
+        }
+        ret.append(')');
+        getSignatureString(ret, intrinsicMethod.getReturnType());
+        return ret.toString();
+    }
+
     public int getParameterCount(boolean withReceiver) {
         return arguments.size() + (withReceiver ? 1 : 0);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/FoldPluginGenerator.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2015, 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.replacements.verifier;
+
+import java.io.PrintWriter;
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic.Kind;
+
+import com.oracle.graal.api.replacements.Fold;
+import com.oracle.graal.replacements.verifier.InjectedDependencies.WellKnownDependency;
+
+/**
+ * Create graph builder plugins for {@link Fold} methods.
+ */
+public class FoldPluginGenerator extends PluginGenerator {
+
+    private class FoldVerifier extends AbstractVerifier {
+
+        public FoldVerifier(ProcessingEnvironment env) {
+            super(env);
+        }
+
+        @Override
+        public void verify(Element element, AnnotationMirror annotation) {
+            if (element.getKind() != ElementKind.METHOD) {
+                assert false : "Element is guaranteed to be a method.";
+                return;
+            }
+
+            ExecutableElement intrinsicMethod = (ExecutableElement) element;
+            if (intrinsicMethod.getModifiers().contains(Modifier.PRIVATE)) {
+                env.getMessager().printMessage(Kind.ERROR, "@Fold method can not be private.", element);
+            } else {
+                FoldPluginGenerator.this.createPluginFactory(intrinsicMethod, null, null);
+            }
+        }
+
+        @Override
+        public Class<? extends Annotation> getAnnotationClass() {
+            return Fold.class;
+        }
+    }
+
+    private TypeMirror stringType() {
+        return env.getElementUtils().getTypeElement("java.lang.String").asType();
+    }
+
+    public FoldPluginGenerator(ProcessingEnvironment env) {
+        super(env);
+    }
+
+    public AbstractVerifier getVerifier() {
+        return new FoldVerifier(env);
+    }
+
+    @Override
+    protected String getBaseName() {
+        return "FoldFactory";
+    }
+
+    @Override
+    protected void createImports(PrintWriter out, ExecutableElement intrinsicMethod, ExecutableElement targetMethod) {
+        out.printf("import jdk.vm.ci.meta.JavaConstant;\n");
+        out.printf("import jdk.vm.ci.meta.JavaKind;\n");
+        out.printf("import com.oracle.graal.nodes.ConstantNode;\n");
+        super.createImports(out, intrinsicMethod, targetMethod);
+    }
+
+    @Override
+    protected InjectedDependencies createExecute(PrintWriter out, ExecutableElement intrinsicMethod, ExecutableElement constructor, TypeMirror[] signature) {
+        InjectedDependencies deps = new InjectedDependencies();
+        List<? extends VariableElement> params = intrinsicMethod.getParameters();
+
+        int argCount = 0;
+        Object receiver;
+        if (intrinsicMethod.getModifiers().contains(Modifier.STATIC)) {
+            receiver = intrinsicMethod.getEnclosingElement();
+        } else {
+            receiver = "arg0";
+            TypeElement type = (TypeElement) intrinsicMethod.getEnclosingElement();
+            constantArgument(out, deps, argCount, type.asType(), argCount);
+            argCount++;
+        }
+
+        int firstArg = argCount;
+        for (VariableElement param : params) {
+            constantArgument(out, deps, argCount, param.asType(), argCount);
+            argCount++;
+        }
+
+        if (intrinsicMethod.getAnnotation(Deprecated.class) != null) {
+            out.printf("            @SuppressWarnings(\"deprecation\")\n");
+        }
+        out.printf("            %s result = %s.%s(", intrinsicMethod.getReturnType(), receiver, intrinsicMethod.getSimpleName());
+        if (argCount > firstArg) {
+            out.printf("arg%d", firstArg);
+            for (int i = firstArg + 1; i < argCount; i++) {
+                out.printf(", arg%d", i);
+            }
+        }
+        out.printf(");\n");
+
+        TypeMirror returnType = intrinsicMethod.getReturnType();
+        switch (returnType.getKind()) {
+            case BOOLEAN:
+                out.printf("            JavaConstant constant = JavaConstant.forInt(result ? 1 : 0);\n");
+                break;
+            case BYTE:
+            case SHORT:
+            case CHAR:
+            case INT:
+                out.printf("            JavaConstant constant = JavaConstant.forInt(result);\n");
+                break;
+            case LONG:
+                out.printf("            JavaConstant constant = JavaConstant.forLong(result);\n");
+                break;
+            case FLOAT:
+                out.printf("            JavaConstant constant = JavaConstant.forFloat(result);\n");
+                break;
+            case DOUBLE:
+                out.printf("            JavaConstant constant = JavaConstant.forDouble(result);\n");
+                break;
+            case ARRAY:
+            case TYPEVAR:
+            case DECLARED:
+                if (returnType.equals(stringType())) {
+                    out.printf("            JavaConstant constant = %s.forString(result);\n", deps.use(WellKnownDependency.CONSTANT_REFLECTION));
+                } else {
+                    out.printf("            JavaConstant constant = %s.forObject(result);\n", deps.use(WellKnownDependency.SNIPPET_REFLECTION));
+                }
+                break;
+            default:
+                throw new IllegalArgumentException(returnType.toString());
+        }
+
+        out.printf("            ConstantNode node = ConstantNode.forConstant(constant, %s, %s);\n", deps.use(WellKnownDependency.META_ACCESS), deps.use(WellKnownDependency.STRUCTURED_GRAPH));
+        out.printf("            b.push(JavaKind.%s, node);\n", getReturnKind(intrinsicMethod).name());
+        out.printf("            return true;\n");
+
+        return deps;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/InjectedDependencies.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2015, 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.replacements.verifier;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+import com.oracle.graal.replacements.verifier.InjectedDependencies.Dependency;
+
+public class InjectedDependencies implements Iterable<Dependency> {
+
+    public abstract static class Dependency {
+
+        public final String name;
+        public final String type;
+
+        private Dependency(String name, String type) {
+            this.name = name;
+            this.type = type;
+        }
+
+        public abstract String inject(ExecutableElement inject);
+    }
+
+    private static final class InjectedDependency extends Dependency {
+
+        private InjectedDependency(String name, String type) {
+            super(name, type);
+        }
+
+        @Override
+        public String inject(ExecutableElement inject) {
+            return String.format("injection.getInjectedArgument(%s.class)", type);
+        }
+    }
+
+    private static final class StampDependency extends Dependency {
+
+        private StampDependency() {
+            super("returnStamp", "com.oracle.graal.compiler.common.type.Stamp");
+        }
+
+        @Override
+        public String inject(ExecutableElement inject) {
+            return String.format("injection.getReturnStamp(%s.class)", NodeIntrinsicPluginGenerator.getErasedType(inject.getReturnType()));
+        }
+    }
+
+    public enum WellKnownDependency {
+        CONSTANT_REFLECTION("b.getConstantReflection()", "jdk.vm.ci.meta.ConstantReflectionProvider"),
+        META_ACCESS("b.getMetaAccess()", "jdk.vm.ci.meta.MetaAccessProvider"),
+        RETURN_STAMP(new StampDependency()),
+        SNIPPET_REFLECTION(new InjectedDependency("snippetReflection", "com.oracle.graal.api.replacements.SnippetReflectionProvider")),
+        STAMP_PROVIDER("b.getStampProvider()", "com.oracle.graal.nodes.spi.StampProvider"),
+        STRUCTURED_GRAPH("b.getGraph()", "com.oracle.graal.nodes.StructuredGraph");
+
+        private final String expr;
+        private final String type;
+        private final Dependency generateMember;
+
+        private WellKnownDependency(String expr, String type) {
+            this.expr = expr;
+            this.type = type;
+            this.generateMember = null;
+        }
+
+        private WellKnownDependency(Dependency generateMember) {
+            this.expr = generateMember.name;
+            this.type = generateMember.type;
+            this.generateMember = generateMember;
+        }
+
+        private TypeMirror getType(ProcessingEnvironment env) {
+            return env.getElementUtils().getTypeElement(type).asType();
+        }
+    }
+
+    private final HashMap<String, Dependency> deps;
+
+    public InjectedDependencies() {
+        deps = new HashMap<>();
+    }
+
+    public String use(WellKnownDependency wellKnown) {
+        if (wellKnown.generateMember != null) {
+            deps.put(wellKnown.type, wellKnown.generateMember);
+        }
+        return wellKnown.expr;
+    }
+
+    public String use(ProcessingEnvironment env, DeclaredType type) {
+        for (WellKnownDependency wellKnown : WellKnownDependency.values()) {
+            if (env.getTypeUtils().isAssignable(wellKnown.getType(env), type)) {
+                return use(wellKnown);
+            }
+        }
+
+        String typeName = type.toString();
+        Dependency ret = deps.get(typeName);
+        if (ret == null) {
+            ret = new InjectedDependency("injected" + type.asElement().getSimpleName(), typeName);
+            deps.put(typeName, ret);
+        }
+        return ret.name;
+    }
+
+    public Iterator<Dependency> iterator() {
+        return deps.values().iterator();
+    }
+
+    public boolean isEmpty() {
+        return deps.isEmpty();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/NodeIntrinsicPluginGenerator.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2015, 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.replacements.verifier;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic.Kind;
+
+import jdk.vm.ci.meta.JavaKind;
+
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.InjectedNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.replacements.verifier.InjectedDependencies.WellKnownDependency;
+
+/**
+ * Create graph builder plugins for {@link NodeIntrinsic} methods.
+ */
+public class NodeIntrinsicPluginGenerator extends PluginGenerator {
+
+    public NodeIntrinsicPluginGenerator(ProcessingEnvironment env) {
+        super(env);
+    }
+
+    private TypeMirror valueNodeType() {
+        return env.getElementUtils().getTypeElement("com.oracle.graal.nodes.ValueNode").asType();
+    }
+
+    @Override
+    protected String getBaseName() {
+        return "NodeIntrinsicFactory";
+    }
+
+    @Override
+    protected void createImports(PrintWriter out, ExecutableElement intrinsicMethod, ExecutableElement targetMethod) {
+        if (targetMethod.getKind() == ElementKind.CONSTRUCTOR && getReturnKind(intrinsicMethod) != JavaKind.Void) {
+            out.printf("import jdk.vm.ci.meta.JavaKind;\n");
+        }
+        super.createImports(out, intrinsicMethod, targetMethod);
+    }
+
+    @Override
+    protected InjectedDependencies createExecute(PrintWriter out, ExecutableElement intrinsicMethod, ExecutableElement constructor, TypeMirror[] signature) {
+        InjectedDependencies deps = new InjectedDependencies();
+
+        List<? extends VariableElement> params = constructor.getParameters();
+
+        boolean customFactory = constructor.getKind() != ElementKind.CONSTRUCTOR;
+        int idx = customFactory ? 1 : 0;
+        for (; idx < params.size(); idx++) {
+            VariableElement param = params.get(idx);
+            if (param.getAnnotation(InjectedNodeParameter.class) == null) {
+                break;
+            }
+
+            out.printf("            %s arg%d = %s;\n", param.asType(), idx, deps.use(env, (DeclaredType) param.asType()));
+        }
+
+        for (int i = 0; i < signature.length; i++, idx++) {
+            if (intrinsicMethod.getParameters().get(i).getAnnotation(ConstantNodeParameter.class) != null) {
+                constantArgument(out, deps, idx, signature[i], i);
+            } else {
+                if (signature[i].equals(valueNodeType())) {
+                    out.printf("            ValueNode arg%d = args[%d];\n", idx, i);
+                } else {
+                    out.printf("            %s arg%d = (%s) args[%d];\n", signature[i], idx, signature[i], i);
+                }
+            }
+        }
+
+        if (customFactory) {
+            out.printf("            return %s.%s(b", constructor.getEnclosingElement(), constructor.getSimpleName());
+            for (int i = 1; i < idx; i++) {
+                out.printf(", arg%d", i);
+            }
+            out.printf(");\n");
+
+            if (intrinsicMethod.getAnnotation(NodeIntrinsic.class).setStampFromReturnType()) {
+                env.getMessager().printMessage(Kind.WARNING, "Ignoring setStampFromReturnType because a custom 'intrinsify' method is used.", intrinsicMethod);
+            }
+        } else {
+            out.printf("            %s node = new %s(", constructor.getEnclosingElement(), constructor.getEnclosingElement());
+            if (idx > 0) {
+                out.printf("arg0");
+                for (int i = 1; i < idx; i++) {
+                    out.printf(", arg%d", i);
+                }
+            }
+            out.printf(");\n");
+
+            if (intrinsicMethod.getAnnotation(NodeIntrinsic.class).setStampFromReturnType()) {
+                out.printf("            node.setStamp(%s);\n", deps.use(WellKnownDependency.RETURN_STAMP));
+            }
+
+            JavaKind returnKind = getReturnKind(intrinsicMethod);
+            if (returnKind == JavaKind.Void) {
+                out.printf("            b.add(node);\n");
+            } else {
+                out.printf("            b.addPush(JavaKind.%s, node);\n", returnKind.name());
+            }
+            out.printf("            return true;\n");
+        }
+
+        return deps;
+    }
+}
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/NodeIntrinsicVerifier.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/NodeIntrinsicVerifier.java	Tue Dec 08 12:30:15 2015 -0800
@@ -73,8 +73,15 @@
         return env.getElementUtils().getTypeElement("com.oracle.graal.nodeinfo.StructuralInput").asType();
     }
 
+    private TypeMirror graphBuilderContextType() {
+        return env.getElementUtils().getTypeElement("com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext").asType();
+    }
+
+    private final NodeIntrinsicPluginGenerator factoryGen;
+
     public NodeIntrinsicVerifier(ProcessingEnvironment env) {
         super(env);
+        factoryGen = new NodeIntrinsicPluginGenerator(env);
     }
 
     @Override
@@ -114,20 +121,28 @@
             env.getMessager().printMessage(Kind.ERROR, "@NodeIntrinsic cannot have a generic return type.", element, annotation);
         }
 
-        if (isNodeType(nodeClass)) {
-            if (nodeClass.getModifiers().contains(Modifier.ABSTRACT)) {
-                env.getMessager().printMessage(Kind.ERROR, String.format("Cannot make @NodeIntrinsic for abstract node class %s.", nodeClass.getSimpleName()), element, annotation);
+        TypeMirror[] constructorSignature = constructorSignature(intrinsicMethod);
+        ExecutableElement custom = findCustomIntrinsifyMethod(nodeClass, constructorSignature);
+        if (custom != null) {
+            factoryGen.createPluginFactory(intrinsicMethod, custom, constructorSignature);
+        } else {
+            if (isNodeType(nodeClass)) {
+                if (nodeClass.getModifiers().contains(Modifier.ABSTRACT)) {
+                    env.getMessager().printMessage(Kind.ERROR, String.format("Cannot make @NodeIntrinsic for abstract node class %s.", nodeClass.getSimpleName()), element, annotation);
+                } else {
+                    TypeMirror ret = intrinsicMethod.getReturnType();
+                    if (env.getTypeUtils().isAssignable(ret, structuralInputType())) {
+                        checkInputType(nodeClass, ret, element, annotation);
+                    }
+
+                    ExecutableElement constructor = findConstructor(nodeClass, constructorSignature, intrinsicMethod, annotation);
+                    if (constructor != null) {
+                        factoryGen.createPluginFactory(intrinsicMethod, constructor, constructorSignature);
+                    }
+                }
             } else {
-                TypeMirror ret = intrinsicMethod.getReturnType();
-                if (env.getTypeUtils().isAssignable(ret, structuralInputType())) {
-                    checkInputType(nodeClass, ret, element, annotation);
-                }
-
-                TypeMirror[] constructorSignature = constructorSignature(intrinsicMethod);
-                findConstructor(nodeClass, constructorSignature, intrinsicMethod, annotation);
+                env.getMessager().printMessage(Kind.ERROR, String.format("The class %s is not a Node subclass.", nodeClass.getSimpleName()), element, annotation);
             }
-        } else {
-            env.getMessager().printMessage(Kind.ERROR, String.format("The class %s is not a Node subclass.", nodeClass.getSimpleName()), element, annotation);
         }
     }
 
@@ -185,47 +200,18 @@
         return parameters;
     }
 
-    private void findConstructor(TypeElement nodeClass, TypeMirror[] signature, ExecutableElement intrinsicMethod, AnnotationMirror intrinsicAnnotation) {
+    private ExecutableElement findConstructor(TypeElement nodeClass, TypeMirror[] signature, ExecutableElement intrinsicMethod, AnnotationMirror intrinsicAnnotation) {
         List<ExecutableElement> constructors = ElementFilter.constructorsIn(nodeClass.getEnclosedElements());
         List<String> failureReasons = new ArrayList<>();
 
-        nextConstructor: for (ExecutableElement constructor : constructors) {
-            int sIdx = 0;
-            int cIdx = 0;
-            while (cIdx < constructor.getParameters().size()) {
-                VariableElement parameter = constructor.getParameters().get(cIdx++);
-                if (parameter.getAnnotation(InjectedNodeParameter.class) != null) {
-                    // skip injected parameters
-                    continue;
-                }
-
-                TypeMirror paramType = parameter.asType();
-                if (cIdx == constructor.getParameters().size() && paramType.getKind() == TypeKind.ARRAY) {
-                    // last argument of constructor is varargs, match remaining intrinsic arguments
-                    TypeMirror varargsType = ((ArrayType) paramType).getComponentType();
-                    while (sIdx < signature.length) {
-                        if (!isTypeCompatible(varargsType, signature[sIdx++])) {
-                            failureReasons.add(String.format("Constructor %s failed because the types of argument %d are incompatible: %s != %s", constructor, sIdx, varargsType, signature[sIdx - 1]));
-                            continue nextConstructor;
-                        }
-                    }
-                } else if (sIdx >= signature.length) {
-                    // too many arguments in intrinsic method
-                    failureReasons.add(String.format("Too many arguments for %s", constructor));
-                    continue nextConstructor;
-                } else if (!isTypeCompatible(paramType, signature[sIdx++])) {
-                    failureReasons.add(String.format("Constructor %s failed because the types of argument %d are incompatible: %s != %s", constructor, sIdx, paramType, signature[sIdx - 1]));
-                    continue nextConstructor;
-                }
+        for (ExecutableElement constructor : constructors) {
+            String failureReason = matchSignature(false, constructor, signature);
+            if (failureReason == null) {
+                // found
+                return constructor;
             }
 
-            if (sIdx == signature.length) {
-                // found
-                return;
-            }
-
-            // too many arguments in constructor
-            failureReasons.add(String.format("Not enough arguments for %s", constructor));
+            failureReasons.add(failureReason);
         }
 
         // not found
@@ -236,6 +222,70 @@
                 env.getMessager().printMessage(Kind.ERROR, reason, intrinsicMethod, intrinsicAnnotation);
             }
         }
+
+        return null;
+    }
+
+    private ExecutableElement findCustomIntrinsifyMethod(TypeElement nodeClass, TypeMirror[] signature) {
+        List<ExecutableElement> methods = ElementFilter.methodsIn(nodeClass.getEnclosedElements());
+        for (ExecutableElement method : methods) {
+            if (!method.getSimpleName().toString().equals("intrinsify")) {
+                continue;
+            }
+
+            if (method.getParameters().isEmpty()) {
+                continue;
+            }
+
+            VariableElement firstArg = method.getParameters().get(0);
+            if (!isTypeCompatible(firstArg.asType(), graphBuilderContextType())) {
+                continue;
+            }
+
+            String failureReason = matchSignature(true, method, signature);
+            if (failureReason == null) {
+                // found
+                return method;
+            }
+        }
+
+        return null;
+    }
+
+    private String matchSignature(boolean skipFirst, ExecutableElement method, TypeMirror[] signature) {
+        int sIdx = 0;
+        int cIdx = skipFirst ? 1 : 0;
+        while (cIdx < method.getParameters().size()) {
+            VariableElement parameter = method.getParameters().get(cIdx++);
+            if (parameter.getAnnotation(InjectedNodeParameter.class) != null) {
+                // skip injected parameters
+                continue;
+            }
+
+            TypeMirror paramType = parameter.asType();
+            if (cIdx == method.getParameters().size() && paramType.getKind() == TypeKind.ARRAY) {
+                // last argument of constructor is varargs, match remaining intrinsic arguments
+                TypeMirror varargsType = ((ArrayType) paramType).getComponentType();
+                while (sIdx < signature.length) {
+                    if (!isTypeCompatible(varargsType, signature[sIdx++])) {
+                        return String.format("%s failed because the types of argument %d are incompatible: %s != %s", method, sIdx, varargsType, signature[sIdx - 1]);
+                    }
+                }
+            } else if (sIdx >= signature.length) {
+                // too many arguments in intrinsic method
+                return String.format("Too many arguments for %s", method);
+            } else if (!isTypeCompatible(paramType, signature[sIdx++])) {
+                return String.format("%s failed because the types of argument %d are incompatible: %s != %s", method, sIdx, paramType, signature[sIdx - 1]);
+            }
+        }
+
+        if (sIdx == signature.length) {
+            // found
+            return null;
+        }
+
+        // too many arguments in constructor
+        return String.format("Not enough arguments for %s", method);
     }
 
     private boolean isTypeCompatible(TypeMirror originalType, TypeMirror substitutionType) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/PluginGenerator.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2015, 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.replacements.verifier;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.WildcardType;
+import javax.tools.Diagnostic;
+import javax.tools.JavaFileObject;
+
+import jdk.vm.ci.meta.JavaKind;
+
+import com.oracle.graal.replacements.verifier.InjectedDependencies.Dependency;
+import com.oracle.graal.replacements.verifier.InjectedDependencies.WellKnownDependency;
+
+public abstract class PluginGenerator {
+
+    protected final ProcessingEnvironment env;
+
+    public PluginGenerator(ProcessingEnvironment env) {
+        this.env = env;
+    }
+
+    private TypeMirror resolvedJavaTypeType() {
+        return env.getElementUtils().getTypeElement("jdk.vm.ci.meta.ResolvedJavaType").asType();
+    }
+
+    private static Element getTopLevelClass(Element element) {
+        Element prev = element;
+        Element enclosing = element.getEnclosingElement();
+        while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) {
+            prev = enclosing;
+            enclosing = enclosing.getEnclosingElement();
+        }
+        return prev;
+    }
+
+    private static void mkClassName(StringBuilder ret, Element cls) {
+        Element enclosingClass = cls.getEnclosingElement();
+        if (enclosingClass.getKind() == ElementKind.CLASS || enclosingClass.getKind() == ElementKind.INTERFACE) {
+            mkClassName(ret, enclosingClass);
+            ret.append('_');
+        }
+        ret.append(cls.getSimpleName());
+    }
+
+    static String getErasedType(TypeMirror type) {
+        switch (type.getKind()) {
+            case DECLARED:
+                DeclaredType declared = (DeclaredType) type;
+                TypeElement element = (TypeElement) declared.asElement();
+                return element.getQualifiedName().toString();
+            case TYPEVAR:
+                return getErasedType(((TypeVariable) type).getUpperBound());
+            case WILDCARD:
+                return getErasedType(((WildcardType) type).getExtendsBound());
+            case ARRAY:
+                return getErasedType(((ArrayType) type).getComponentType()) + "[]";
+            default:
+                return type.toString();
+        }
+    }
+
+    protected abstract String getBaseName();
+
+    private String mkFactoryClassName(ExecutableElement intrinsicMethod) {
+        StringBuilder ret = new StringBuilder();
+        ret.append(getBaseName());
+        ret.append('_');
+        mkClassName(ret, intrinsicMethod.getEnclosingElement());
+        ret.append('_');
+        ret.append(intrinsicMethod.getSimpleName());
+        if (!intrinsicMethod.getParameters().isEmpty()) {
+            ret.append('_');
+            ret.append(Integer.toHexString(APHotSpotSignature.toSignature(intrinsicMethod).hashCode()));
+        }
+        return ret.toString();
+    }
+
+    void createPluginFactory(ExecutableElement intrinsicMethod, ExecutableElement targetMethod, TypeMirror[] constructorSignature) {
+        Element declaringClass = intrinsicMethod.getEnclosingElement();
+        Element topLevelClass = getTopLevelClass(declaringClass);
+        PackageElement pkg = (PackageElement) topLevelClass.getEnclosingElement();
+
+        String genClassName = mkFactoryClassName(intrinsicMethod);
+
+        try {
+            JavaFileObject factory = env.getFiler().createSourceFile(pkg.getQualifiedName() + "." + genClassName, topLevelClass, declaringClass, intrinsicMethod);
+            try (PrintWriter out = new PrintWriter(factory.openWriter())) {
+                out.printf("// CheckStyle: stop header check\n");
+                out.printf("// CheckStyle: stop line length check\n");
+                out.printf("// GENERATED CONTENT - DO NOT EDIT\n");
+                out.printf("package %s;\n", pkg.getQualifiedName());
+                out.printf("\n");
+                createImports(out, intrinsicMethod, targetMethod);
+                out.printf("\n");
+                out.printf("@ServiceProvider(NodeIntrinsicPluginFactory.class)\n");
+                out.printf("public class %s implements NodeIntrinsicPluginFactory {\n", genClassName);
+                out.printf("\n");
+                out.printf("    private static final class Plugin extends GeneratedInvocationPlugin {\n");
+                out.printf("\n");
+
+                out.printf("        @Override\n");
+                out.printf("        public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] args) {\n");
+                out.printf("            if (!b.parsingIntrinsic()) {\n");
+                out.printf("                return false;\n");
+                out.printf("            }\n");
+                InjectedDependencies deps = createExecute(out, intrinsicMethod, targetMethod, constructorSignature);
+                out.printf("        }\n");
+
+                createPrivateMembers(out, intrinsicMethod, deps);
+
+                out.printf("    }\n");
+                out.printf("\n");
+                createPluginFactoryMethod(out, intrinsicMethod, deps);
+                out.printf("}\n");
+            }
+        } catch (IOException e) {
+            env.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage());
+        }
+    }
+
+    protected abstract InjectedDependencies createExecute(PrintWriter out, ExecutableElement intrinsicMethod, ExecutableElement constructor, TypeMirror[] signature);
+
+    protected void createImports(PrintWriter out, @SuppressWarnings("unused") ExecutableElement intrinsicMethod, @SuppressWarnings("unused") ExecutableElement targetMethod) {
+        out.printf("import jdk.vm.ci.meta.ResolvedJavaMethod;\n");
+        out.printf("import jdk.vm.ci.service.ServiceProvider;\n");
+        out.printf("\n");
+        out.printf("import com.oracle.graal.nodes.ValueNode;\n");
+        out.printf("import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;\n");
+        out.printf("import com.oracle.graal.nodes.graphbuilderconf.GeneratedInvocationPlugin;\n");
+        out.printf("import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;\n");
+        out.printf("import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;\n");
+        out.printf("import com.oracle.graal.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;\n");
+    }
+
+    private static void createPrivateMembers(PrintWriter out, ExecutableElement intrinsicMethod, InjectedDependencies deps) {
+        if (!deps.isEmpty()) {
+            out.printf("\n");
+            for (Dependency dep : deps) {
+                out.printf("        private final %s %s;\n", dep.type, dep.name);
+            }
+
+            out.printf("\n");
+            out.printf("        private Plugin(InjectionProvider injection) {\n");
+            for (Dependency dep : deps) {
+                out.printf("            this.%s = %s;\n", dep.name, dep.inject(intrinsicMethod));
+            }
+            out.printf("        }\n");
+        }
+    }
+
+    private static void createPluginFactoryMethod(PrintWriter out, ExecutableElement intrinsicMethod, InjectedDependencies deps) {
+        out.printf("    public void registerPlugin(InvocationPlugins plugins, InjectionProvider injection) {\n");
+        out.printf("        Plugin plugin = new Plugin(%s);\n", deps.isEmpty() ? "" : "injection");
+        out.printf("        plugins.register(plugin, %s.class, \"%s\"", intrinsicMethod.getEnclosingElement(), intrinsicMethod.getSimpleName());
+        if (!intrinsicMethod.getModifiers().contains(Modifier.STATIC)) {
+            out.printf(", InvocationPlugin.Receiver.class");
+        }
+        for (VariableElement arg : intrinsicMethod.getParameters()) {
+            out.printf(", %s.class", getErasedType(arg.asType()));
+        }
+        out.printf(");\n");
+        out.printf("    }\n");
+    }
+
+    protected static JavaKind getReturnKind(ExecutableElement method) {
+        switch (method.getReturnType().getKind()) {
+            case BOOLEAN:
+            case BYTE:
+            case SHORT:
+            case CHAR:
+            case INT:
+                return JavaKind.Int;
+            case LONG:
+                return JavaKind.Long;
+            case FLOAT:
+                return JavaKind.Float;
+            case DOUBLE:
+                return JavaKind.Double;
+            case VOID:
+                return JavaKind.Void;
+            case ARRAY:
+            case TYPEVAR:
+            case DECLARED:
+                return JavaKind.Object;
+            default:
+                throw new IllegalArgumentException(method.getReturnType().toString());
+        }
+    }
+
+    protected void constantArgument(PrintWriter out, InjectedDependencies deps, int argIdx, TypeMirror type, int nodeIdx) {
+        out.printf("            %s arg%d;\n", type, argIdx);
+        out.printf("            if (args[%d].isConstant()) {\n", nodeIdx);
+        if (type.equals(resolvedJavaTypeType())) {
+            out.printf("                arg%d = %s.asJavaType(args[%d].asConstant());\n", argIdx, deps.use(WellKnownDependency.CONSTANT_REFLECTION), nodeIdx);
+        } else {
+            switch (type.getKind()) {
+                case BOOLEAN:
+                    out.printf("                arg%d = args[%d].asJavaConstant().asInt() != 0;\n", argIdx, nodeIdx);
+                    break;
+                case BYTE:
+                    out.printf("                arg%d = (byte) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
+                    break;
+                case CHAR:
+                    out.printf("                arg%d = (char) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
+                    break;
+                case SHORT:
+                    out.printf("                arg%d = (short) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
+                    break;
+                case INT:
+                    out.printf("                arg%d = args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
+                    break;
+                case LONG:
+                    out.printf("                arg%d = args[%d].asJavaConstant().asLong();\n", argIdx, nodeIdx);
+                    break;
+                case FLOAT:
+                    out.printf("                arg%d = args[%d].asJavaConstant().asFloat();\n", argIdx, nodeIdx);
+                    break;
+                case DOUBLE:
+                    out.printf("                arg%d = args[%d].asJavaConstant().asDouble();\n", argIdx, nodeIdx);
+                    break;
+                case DECLARED:
+                    out.printf("                arg%d = %s.asObject(%s.class, args[%d].asJavaConstant());\n", argIdx, deps.use(WellKnownDependency.SNIPPET_REFLECTION), type, nodeIdx);
+                    break;
+                default:
+                    throw new IllegalArgumentException();
+            }
+        }
+        out.printf("            } else {\n");
+        out.printf("                return false;\n");
+        out.printf("            }\n");
+    }
+}
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/VerifierAnnotationProcessor.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/VerifierAnnotationProcessor.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -84,6 +84,7 @@
             verifiers.add(new ClassSubstitutionVerifier(this.processingEnv));
             verifiers.add(new MethodSubstitutionVerifier(this.processingEnv));
             verifiers.add(new NodeIntrinsicVerifier(this.processingEnv));
+            verifiers.add(new FoldPluginGenerator(this.processingEnv).getVerifier());
         }
         return verifiers;
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CachingPEGraphDecoder.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CachingPEGraphDecoder.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.replacements;
 
-import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
+import static com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -31,13 +31,13 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 import com.oracle.graal.debug.Debug;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.IntrinsicContext;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.nodes.EncodedGraph;
 import com.oracle.graal.nodes.GraphEncoder;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.tiers.PhaseContext;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ConstantBindingParameterPlugin.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ConstantBindingParameterPlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -27,10 +27,10 @@
 
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
 import com.oracle.graal.compiler.common.type.Stamp;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.ParameterPlugin;
 import com.oracle.graal.nodes.ConstantNode;
 import com.oracle.graal.nodes.calc.FloatingNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.ParameterPlugin;
 
 /**
  * A {@link ParameterPlugin} that binds constant values to some parameters.
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Tue Dec 08 12:30:15 2015 -0800
@@ -192,7 +192,7 @@
     }
 
     private void lowerTypeCheckNode(TypeCheckNode n, LoweringTool tool, StructuredGraph graph) {
-        ValueNode hub = createReadHub(graph, n.getValue(), null, tool);
+        ValueNode hub = createReadHub(graph, n.getValue(), tool);
         ValueNode clazz = graph.unique(ConstantNode.forConstant(tool.getStampProvider().createHubStamp((ObjectStamp) n.getValue().stamp()), n.type().getObjectHub(), tool.getMetaAccess()));
         LogicNode objectEquals = graph.unique(PointerEqualsNode.create(hub, clazz));
         n.replaceAndDelete(objectEquals);
@@ -344,7 +344,7 @@
                  */
                 GuardingNode nullCheck = nullCheckReturn[0];
                 assert nullCheckReturn[0] != null || createNullCheck(array, storeIndexed, tool) == null;
-                ValueNode arrayClass = createReadHub(graph, array, nullCheck, tool);
+                ValueNode arrayClass = createReadHub(graph, graph.unique(new PiNode(array, (ValueNode) nullCheck)), tool);
                 ValueNode componentHub = createReadArrayComponentHub(graph, arrayClass, storeIndexed);
                 checkCastNode = graph.add(new CheckCastDynamicNode(componentHub, value, true));
                 graph.addBeforeFixed(storeIndexed, checkCastNode);
@@ -383,7 +383,7 @@
         if (graph.getGuardsStage().allowsFloatingGuards()) {
             return;
         }
-        ValueNode hub = createReadHub(graph, loadHub.getValue(), loadHub.getGuard(), tool);
+        ValueNode hub = createReadHub(graph, loadHub.getValue(), tool);
         graph.replaceFloating(loadHub, hub);
     }
 
@@ -715,40 +715,63 @@
         return stamp;
     }
 
-    public ValueNode implicitLoadConvert(StructuredGraph graph, JavaKind kind, ValueNode value) {
+    public final ValueNode implicitLoadConvert(StructuredGraph graph, JavaKind kind, ValueNode value) {
         return implicitLoadConvert(graph, kind, value, true);
+    }
 
+    public ValueNode implicitLoadConvert(JavaKind kind, ValueNode value) {
+        return implicitLoadConvert(kind, value, true);
     }
 
-    protected ValueNode implicitLoadConvert(StructuredGraph graph, JavaKind kind, ValueNode value, @SuppressWarnings("unused") boolean compressible) {
+    protected final ValueNode implicitLoadConvert(StructuredGraph graph, JavaKind kind, ValueNode value, boolean compressible) {
+        ValueNode ret = implicitLoadConvert(kind, value, compressible);
+        if (!ret.isAlive()) {
+            ret = graph.addOrUnique(ret);
+        }
+        return ret;
+    }
+
+    protected ValueNode implicitLoadConvert(JavaKind kind, ValueNode value, @SuppressWarnings("unused") boolean compressible) {
         switch (kind) {
             case Byte:
             case Short:
-                return graph.unique(new SignExtendNode(value, 32));
+                return new SignExtendNode(value, 32);
             case Boolean:
             case Char:
-                return graph.unique(new ZeroExtendNode(value, 32));
+                return new ZeroExtendNode(value, 32);
         }
         return value;
     }
 
-    public ValueNode implicitStoreConvert(StructuredGraph graph, JavaKind kind, ValueNode value) {
+    public final ValueNode implicitStoreConvert(StructuredGraph graph, JavaKind kind, ValueNode value) {
         return implicitStoreConvert(graph, kind, value, true);
     }
 
-    protected ValueNode implicitStoreConvert(StructuredGraph graph, JavaKind kind, ValueNode value, @SuppressWarnings("unused") boolean compressible) {
+    public ValueNode implicitStoreConvert(JavaKind kind, ValueNode value) {
+        return implicitStoreConvert(kind, value, true);
+    }
+
+    protected final ValueNode implicitStoreConvert(StructuredGraph graph, JavaKind kind, ValueNode value, boolean compressible) {
+        ValueNode ret = implicitStoreConvert(kind, value, compressible);
+        if (!ret.isAlive()) {
+            ret = graph.addOrUnique(ret);
+        }
+        return ret;
+    }
+
+    protected ValueNode implicitStoreConvert(JavaKind kind, ValueNode value, @SuppressWarnings("unused") boolean compressible) {
         switch (kind) {
             case Boolean:
             case Byte:
-                return graph.unique(new NarrowNode(value, 8));
+                return new NarrowNode(value, 8);
             case Char:
             case Short:
-                return graph.unique(new NarrowNode(value, 16));
+                return new NarrowNode(value, 16);
         }
         return value;
     }
 
-    protected abstract ValueNode createReadHub(StructuredGraph graph, ValueNode object, GuardingNode guard, LoweringTool tool);
+    protected abstract ValueNode createReadHub(StructuredGraph graph, ValueNode object, LoweringTool tool);
 
     protected abstract ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor);
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Tue Dec 08 12:30:15 2015 -0800
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.replacements;
 
-import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
+import static com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
 
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
@@ -39,9 +39,6 @@
 
 import com.oracle.graal.graph.Graph;
 import com.oracle.graal.graph.Node;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.IntrinsicContext;
 import com.oracle.graal.java.FrameStateBuilder;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.nodes.AbstractBeginNode;
@@ -60,6 +57,9 @@
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.calc.FloatingNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
 import com.oracle.graal.nodes.type.StampTool;
 import com.oracle.graal.phases.OptimisticOptimizations;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InlineDuringParsingPlugin.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InlineDuringParsingPlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -27,9 +27,9 @@
 import jdk.vm.ci.meta.JavaType;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InlineInvokePlugin;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InlineInvokePlugin;
 
 public final class InlineDuringParsingPlugin implements InlineInvokePlugin {
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Tue Dec 08 12:30:15 2015 -0800
@@ -110,7 +110,7 @@
      */
     protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, Instantiation instantiation, Node usage, final StructuredGraph graph) {
         InstanceOfUsageReplacer replacer;
-        if (usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ShortCircuitOrNode || usage instanceof ConditionAnchorNode) {
+        if (!canMaterialize(usage)) {
             ValueNode trueValue = ConstantNode.forInt(1, graph);
             ValueNode falseValue = ConstantNode.forInt(0, graph);
             if (instantiation.isInitialized() && (trueValue != instantiation.trueValue || falseValue != instantiation.falseValue)) {
@@ -131,6 +131,20 @@
     }
 
     /**
+     * Determines if an {@code instanceof} usage can be materialized.
+     */
+    protected boolean canMaterialize(Node usage) {
+        if (usage instanceof ConditionalNode) {
+            ConditionalNode cn = (ConditionalNode) usage;
+            return cn.trueValue().isConstant() && cn.falseValue().isConstant();
+        }
+        if (usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ShortCircuitOrNode || usage instanceof ConditionAnchorNode) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
      * The result of instantiating an instanceof snippet. This enables a snippet instantiation to be
      * re-used which reduces compile time and produces better code.
      */
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java	Tue Dec 08 12:30:15 2015 -0800
@@ -35,10 +35,6 @@
 
 import com.oracle.graal.compiler.common.type.Stamp;
 import com.oracle.graal.compiler.common.type.StampFactory;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.IntrinsicContext;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin.Receiver;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.FixedNode;
 import com.oracle.graal.nodes.FixedWithNextNode;
@@ -50,6 +46,10 @@
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.calc.FloatingNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin.Receiver;
 import com.oracle.graal.nodes.spi.StampProvider;
 
 /**
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MethodHandlePlugin.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MethodHandlePlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -29,10 +29,10 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 import com.oracle.graal.graph.NodeInputList;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.NodePlugin;
 import com.oracle.graal.nodes.CallTargetNode;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.NodePlugin;
 import com.oracle.graal.nodes.InvokeNode;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.replacements.nodes.MethodHandleNode;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,506 +0,0 @@
-/*
- * Copyright (c) 2011, 2015, 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.replacements;
-
-import static jdk.vm.ci.meta.MetaUtil.resolveJavaTypes;
-
-import java.lang.reflect.Array;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.meta.Constant;
-import jdk.vm.ci.meta.ConstantReflectionProvider;
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.JavaMethod;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.meta.PrimitiveConstant;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaType;
-
-import com.oracle.graal.api.replacements.Fold;
-import com.oracle.graal.api.replacements.SnippetReflectionProvider;
-import com.oracle.graal.compiler.common.spi.ForeignCallsProvider;
-import com.oracle.graal.compiler.common.type.Stamp;
-import com.oracle.graal.compiler.common.type.StampFactory;
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.internal.DebugScope;
-import com.oracle.graal.graph.Node;
-import com.oracle.graal.graph.Node.ConstantNodeParameter;
-import com.oracle.graal.graph.Node.InjectedNodeParameter;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.nodes.ConstantNode;
-import com.oracle.graal.nodes.FrameState;
-import com.oracle.graal.nodes.LogicConstantNode;
-import com.oracle.graal.nodes.PiNode;
-import com.oracle.graal.nodes.ProxyNode;
-import com.oracle.graal.nodes.ReturnNode;
-import com.oracle.graal.nodes.StructuredGraph;
-import com.oracle.graal.nodes.ValueNode;
-import com.oracle.graal.nodes.ValueProxyNode;
-import com.oracle.graal.nodes.calc.FloatingNode;
-import com.oracle.graal.nodes.calc.IsNullNode;
-import com.oracle.graal.nodes.extended.UnboxNode;
-import com.oracle.graal.nodes.extended.UnsafeStoreNode;
-import com.oracle.graal.nodes.extended.ValueAnchorNode;
-import com.oracle.graal.nodes.java.CheckCastNode;
-import com.oracle.graal.nodes.java.LoadFieldNode;
-import com.oracle.graal.nodes.java.MethodCallTargetNode;
-import com.oracle.graal.nodes.spi.StampProvider;
-import com.oracle.graal.nodes.util.GraphUtil;
-import com.oracle.graal.phases.Phase;
-
-/**
- * Replaces calls to {@link NodeIntrinsic}s with nodes and calls to methods annotated with
- * {@link Fold} with the result of invoking the annotated method via reflection.
- */
-public class NodeIntrinsificationPhase extends Phase {
-
-    private final MetaAccessProvider metaAccess;
-    private final ConstantReflectionProvider constantReflection;
-    private final SnippetReflectionProvider snippetReflection;
-    private final ForeignCallsProvider foreignCalls;
-    private final StampProvider stampProvider;
-
-    public NodeIntrinsificationPhase(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls,
-                    StampProvider stampProvider) {
-        this.metaAccess = metaAccess;
-        this.constantReflection = constantReflection;
-        this.snippetReflection = snippetReflection;
-        this.foreignCalls = foreignCalls;
-        this.stampProvider = stampProvider;
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        ArrayList<Node> cleanUpReturnList = new ArrayList<>();
-        for (MethodCallTargetNode node : graph.getNodes(MethodCallTargetNode.TYPE)) {
-            tryIntrinsify(node, cleanUpReturnList);
-        }
-
-        for (Node node : cleanUpReturnList) {
-            cleanUpReturnCheckCast(node);
-        }
-    }
-
-    protected boolean tryIntrinsify(MethodCallTargetNode methodCallTargetNode, List<Node> cleanUpReturnList) {
-        ResolvedJavaMethod target = methodCallTargetNode.targetMethod();
-        ResolvedJavaType declaringClass = target.getDeclaringClass();
-        StructuredGraph graph = methodCallTargetNode.graph();
-
-        NodeIntrinsic intrinsic = getIntrinsic(target);
-        if (intrinsic != null) {
-            Stamp stamp = methodCallTargetNode.invoke().asNode().stamp();
-            Node newInstance = createIntrinsicNode(methodCallTargetNode.arguments(), stamp, target, graph, intrinsic);
-            if (newInstance == null) {
-                return false;
-            }
-
-            // Replace the invoke with the new node.
-            newInstance = graph.addOrUnique(newInstance);
-            methodCallTargetNode.invoke().intrinsify(newInstance);
-
-            // Clean up checkcast instructions inserted by javac if the return type is generic.
-            cleanUpReturnList.add(newInstance);
-        } else if (isFoldable(target)) {
-            ResolvedJavaType[] parameterTypes = resolveJavaTypes(target.toParameterTypes(), declaringClass);
-            JavaConstant constant = tryFold(methodCallTargetNode.arguments(), parameterTypes, target);
-            if (constant != null && constant.equals(COULD_NOT_FOLD)) {
-                return false;
-            }
-
-            if (constant != null) {
-                // Replace the invoke with the result of the call
-                ConstantNode node = ConstantNode.forConstant(constant, metaAccess, methodCallTargetNode.graph());
-                methodCallTargetNode.invoke().intrinsify(node);
-
-                // Clean up checkcast instructions inserted by javac if the return type is generic.
-                cleanUpReturnList.add(node);
-            } else {
-                // Remove the invoke
-                methodCallTargetNode.invoke().intrinsify(null);
-            }
-        }
-        return true;
-    }
-
-    public static final JavaConstant COULD_NOT_FOLD = new PrimitiveConstant(JavaKind.Illegal, 100) {
-        @Override
-        public boolean equals(Object o) {
-            return this == o;
-        }
-    };
-
-    public JavaConstant tryFold(List<ValueNode> args, ResolvedJavaType[] parameterTypes, ResolvedJavaMethod target) {
-        JavaConstant[] reflectArgs = (JavaConstant[]) prepareArguments(args, parameterTypes, target, true);
-        if (reflectArgs == null) {
-            return COULD_NOT_FOLD;
-        }
-        JavaConstant receiver = null;
-        if (!target.isStatic()) {
-            receiver = reflectArgs[0];
-            reflectArgs = Arrays.copyOfRange(reflectArgs, 1, reflectArgs.length);
-        }
-
-        // Call the method
-        return target.invoke(receiver, reflectArgs);
-    }
-
-    /**
-     * Attempts to create a node to replace a call to a {@link NodeIntrinsic} annotated method.
-     *
-     * @param arguments the arguments of the call
-     * @param stamp the stamp to use for the returned node
-     * @param method the method annotated with {@link NodeIntrinsic}
-     * @param graph the graph into which the created node will be added
-     * @return {@code null} if intrinsification could not (yet) be performed, otherwise the node
-     *         representing the intrinsic
-     */
-    public ValueNode createIntrinsicNode(List<ValueNode> arguments, Stamp stamp, ResolvedJavaMethod method, StructuredGraph graph, NodeIntrinsic intrinsic) {
-        assert method.getAnnotation(Fold.class) == null;
-        assert method.isStatic() : "node intrinsic must be static: " + method;
-
-        ResolvedJavaType[] parameterTypes = resolveJavaTypes(method.toParameterTypes(), method.getDeclaringClass());
-
-        // Prepare the arguments for the reflective constructor call on the node class.
-        Object[] nodeConstructorArguments = prepareArguments(arguments, parameterTypes, method, false);
-        if (nodeConstructorArguments == null) {
-            return null;
-        }
-
-        // Create the new node instance.
-        ResolvedJavaType c = getNodeClass(method, intrinsic);
-        return createNodeInstance(graph, c, parameterTypes, stamp, intrinsic.setStampFromReturnType(), nodeConstructorArguments);
-    }
-
-    /**
-     * Permits a subclass to override the default definition of "intrinsic".
-     */
-    public NodeIntrinsic getIntrinsic(ResolvedJavaMethod method) {
-        return method.getAnnotation(Node.NodeIntrinsic.class);
-    }
-
-    /**
-     * Permits a subclass to override the default definition of "foldable".
-     */
-    public boolean isFoldable(ResolvedJavaMethod method) {
-        return method.getAnnotation(Fold.class) != null;
-    }
-
-    /**
-     * Converts the arguments of an invoke node to object values suitable for use as the arguments
-     * to a reflective invocation of a Java constructor or method.
-     *
-     * @param folding specifies if the invocation is for handling a {@link Fold} annotation
-     * @return the arguments for the reflective invocation or null if an argument of {@code invoke}
-     *         that is expected to be constant isn't
-     */
-    private Object[] prepareArguments(List<ValueNode> arguments, ResolvedJavaType[] parameterTypes, ResolvedJavaMethod target, boolean folding) {
-        Object[] reflectionCallArguments = folding ? new JavaConstant[arguments.size()] : new Object[arguments.size()];
-        for (int i = 0; i < reflectionCallArguments.length; ++i) {
-            int parameterIndex = i;
-            if (!target.isStatic()) {
-                parameterIndex--;
-            }
-            ValueNode argument = arguments.get(i);
-            if (folding || target.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex) != null) {
-                if (!(argument instanceof ConstantNode)) {
-                    return null;
-                }
-                ConstantNode constantNode = (ConstantNode) argument;
-                Constant constant = constantNode.asConstant();
-                /*
-                 * For intrinsification (but not for folding) if we have a Class<?> object we want
-                 * the corresponding ResolvedJavaType.
-                 */
-                ResolvedJavaType type = folding ? null : constantReflection.asJavaType(constant);
-                Object arg;
-                if (type != null) {
-                    /* If we found such a type then it's our arg */
-                    arg = type;
-                    parameterTypes[i] = metaAccess.lookupJavaType(ResolvedJavaType.class);
-                } else {
-                    JavaConstant javaConstant = (JavaConstant) constant;
-                    if (folding) {
-                        /* For folding we want JavaConstants */
-                        arg = javaConstant;
-                    } else {
-                        /* For intrinsification we want want corresponding objects */
-                        if (parameterTypes[i].getJavaKind() == JavaKind.Boolean) {
-                            arg = Boolean.valueOf(javaConstant.asInt() != 0);
-                        } else if (parameterTypes[i].getJavaKind() == JavaKind.Byte) {
-                            arg = Byte.valueOf((byte) javaConstant.asInt());
-                        } else if (parameterTypes[i].getJavaKind() == JavaKind.Short) {
-                            arg = Short.valueOf((short) javaConstant.asInt());
-                        } else if (parameterTypes[i].getJavaKind() == JavaKind.Char) {
-                            arg = Character.valueOf((char) javaConstant.asInt());
-                        } else if (parameterTypes[i].getJavaKind() == JavaKind.Object) {
-                            arg = snippetReflection.asObject(parameterTypes[i], javaConstant);
-                        } else {
-                            arg = javaConstant.asBoxedPrimitive();
-                        }
-                    }
-                }
-
-                assert folding || !(arg instanceof JavaConstant);
-                reflectionCallArguments[i] = arg;
-            } else {
-                reflectionCallArguments[i] = argument;
-                parameterTypes[i] = metaAccess.lookupJavaType(ValueNode.class);
-            }
-        }
-        return reflectionCallArguments;
-    }
-
-    public ResolvedJavaType getNodeClass(ResolvedJavaMethod target, NodeIntrinsic intrinsic) {
-        ResolvedJavaType result;
-        if (intrinsic.value() == NodeIntrinsic.class) {
-            result = target.getDeclaringClass();
-        } else {
-            result = metaAccess.lookupJavaType(intrinsic.value());
-        }
-        assert metaAccess.lookupJavaType(ValueNode.class).isAssignableFrom(result) : "Node intrinsic class " + result.toJavaName(false) + " derived from @" + NodeIntrinsic.class.getSimpleName() +
-                        " annotation on " + target.format("%H.%n(%p)") + " is not a subclass of " + ValueNode.class;
-        return result;
-    }
-
-    protected ValueNode createNodeInstance(StructuredGraph graph, ResolvedJavaType nodeClass, ResolvedJavaType[] parameterTypes, Stamp invokeStamp, boolean setStampFromReturnType,
-                    Object[] nodeConstructorArguments) {
-        ResolvedJavaMethod constructor = null;
-        Object[] arguments = null;
-
-        for (ResolvedJavaMethod c : nodeClass.getDeclaredConstructors()) {
-            Object[] match = match(graph, invokeStamp, c, parameterTypes, nodeConstructorArguments);
-
-            if (match != null) {
-                if (constructor == null) {
-                    constructor = c;
-                    arguments = match;
-                    if (!Debug.isEnabled()) {
-                        // Don't verify there's a unique match in non-debug mode
-                        break;
-                    }
-                } else {
-                    throw new JVMCIError("Found multiple constructors in %s compatible with signature %s: %s, %s", nodeClass.toJavaName(), sigString(parameterTypes), constructor, c);
-                }
-            }
-        }
-        if (constructor == null) {
-            throw new JVMCIError("Could not find constructor in %s compatible with signature %s", nodeClass.toJavaName(), sigString(parameterTypes));
-        }
-
-        try {
-            ValueNode intrinsicNode = (ValueNode) invokeConstructor(constructor, arguments);
-
-            if (setStampFromReturnType) {
-                intrinsicNode.setStamp(invokeStamp);
-            }
-            return intrinsicNode;
-        } catch (Exception e) {
-            throw new RuntimeException(constructor + Arrays.toString(nodeConstructorArguments), e);
-        }
-    }
-
-    protected Object invokeConstructor(ResolvedJavaMethod constructor, Object[] arguments) {
-        return snippetReflection.invoke(constructor, null, arguments);
-    }
-
-    private static String sigString(ResolvedJavaType[] types) {
-        StringBuilder sb = new StringBuilder("(");
-        for (int i = 0; i < types.length; i++) {
-            if (i != 0) {
-                sb.append(", ");
-            }
-            sb.append(types[i].toJavaName());
-        }
-        return sb.append(")").toString();
-    }
-
-    private static boolean checkNoMoreInjected(ResolvedJavaMethod c, int start) {
-        int count = c.getSignature().getParameterCount(false);
-        for (int i = start; i < count; i++) {
-            if (c.getParameterAnnotation(InjectedNodeParameter.class, i) != null) {
-                throw new JVMCIError("Injected parameter %d of type %s must precede all non-injected parameters of %s", i,
-                                c.getSignature().getParameterType(i, c.getDeclaringClass()).toJavaName(false), c.format("%H.%n(%p)"));
-            }
-        }
-        return true;
-    }
-
-    private Object[] match(StructuredGraph graph, Stamp invokeStamp, ResolvedJavaMethod c, ResolvedJavaType[] parameterTypes, Object[] nodeConstructorArguments) {
-        Object[] arguments = null;
-        Object[] injected = null;
-
-        ResolvedJavaType[] signature = resolveJavaTypes(c.getSignature().toParameterTypes(null), c.getDeclaringClass());
-        for (int i = 0; i < signature.length; i++) {
-            if (c.getParameterAnnotation(InjectedNodeParameter.class, i) != null) {
-                injected = injected == null ? new Object[1] : Arrays.copyOf(injected, injected.length + 1);
-                Object injectedParameter = snippetReflection.getInjectedNodeIntrinsicParameter(signature[i]);
-                if (injectedParameter != null) {
-                    injected[injected.length - 1] = injectedParameter;
-                } else if (signature[i].equals(metaAccess.lookupJavaType(MetaAccessProvider.class))) {
-                    injected[injected.length - 1] = metaAccess;
-                } else if (signature[i].equals(metaAccess.lookupJavaType(StructuredGraph.class))) {
-                    injected[injected.length - 1] = graph;
-                } else if (signature[i].equals(metaAccess.lookupJavaType(ForeignCallsProvider.class))) {
-                    injected[injected.length - 1] = foreignCalls;
-                } else if (signature[i].equals(metaAccess.lookupJavaType(SnippetReflectionProvider.class))) {
-                    injected[injected.length - 1] = snippetReflection;
-                } else if (signature[i].isAssignableFrom(metaAccess.lookupJavaType(Stamp.class))) {
-                    injected[injected.length - 1] = invokeStamp;
-                } else if (signature[i].isAssignableFrom(metaAccess.lookupJavaType(StampProvider.class))) {
-                    injected[injected.length - 1] = stampProvider;
-                } else {
-                    throw new JVMCIError("Cannot handle injected argument of type %s in %s", signature[i].toJavaName(), c.format("%H.%n(%p)"));
-                }
-            } else {
-                assert checkNoMoreInjected(c, i);
-                break;
-            }
-        }
-        if (injected != null) {
-            // Chop injected arguments from signature
-            signature = Arrays.copyOfRange(signature, injected.length, signature.length);
-        }
-
-        if (Arrays.equals(parameterTypes, signature)) {
-            // Exact match
-            arguments = nodeConstructorArguments;
-
-        } else if (signature.length > 0 && signature[signature.length - 1].isArray()) {
-            // Last constructor parameter is an array, so check if we have a vararg match
-            int fixedArgs = signature.length - 1;
-            if (parameterTypes.length < fixedArgs) {
-                return null;
-            }
-            for (int i = 0; i < fixedArgs; i++) {
-                if (!parameterTypes[i].equals(signature[i])) {
-                    return null;
-                }
-            }
-
-            ResolvedJavaType componentType = signature[fixedArgs].getComponentType();
-            assert componentType != null;
-            for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) {
-                if (!parameterTypes[i].equals(componentType)) {
-                    return null;
-                }
-            }
-            arguments = Arrays.copyOf(nodeConstructorArguments, fixedArgs + 1);
-            arguments[fixedArgs] = snippetReflection.newArray(componentType, nodeConstructorArguments.length - fixedArgs);
-
-            Object varargs = arguments[fixedArgs];
-            for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) {
-                if (componentType.isPrimitive()) {
-                    Array.set(varargs, i - fixedArgs, nodeConstructorArguments[i]);
-                } else {
-                    ((Object[]) varargs)[i - fixedArgs] = nodeConstructorArguments[i];
-                }
-            }
-        } else {
-            return null;
-        }
-
-        if (injected != null) {
-            Object[] copy = new Object[injected.length + arguments.length];
-            System.arraycopy(injected, 0, copy, 0, injected.length);
-            System.arraycopy(arguments, 0, copy, injected.length, arguments.length);
-            arguments = copy;
-        }
-        return arguments;
-    }
-
-    private static String sourceLocation(Node n) {
-        String loc = GraphUtil.approxSourceLocation(n);
-        return loc == null ? "<unknown>" : loc;
-    }
-
-    public void cleanUpReturnCheckCast(Node newInstance) {
-        if (newInstance instanceof ValueNode && (((ValueNode) newInstance).getStackKind() != JavaKind.Object || ((ValueNode) newInstance).stamp() == StampFactory.forNodeIntrinsic())) {
-            StructuredGraph graph = (StructuredGraph) newInstance.graph();
-            for (CheckCastNode checkCastNode : newInstance.usages().filter(CheckCastNode.class).snapshot()) {
-                for (Node checkCastUsage : checkCastNode.usages().snapshot()) {
-                    checkCheckCastUsage(graph, newInstance, checkCastNode, checkCastUsage);
-                }
-                GraphUtil.unlinkFixedNode(checkCastNode);
-                GraphUtil.killCFG(checkCastNode);
-            }
-        }
-    }
-
-    private static void checkCheckCastUsage(StructuredGraph graph, Node intrinsifiedNode, Node input, Node usage) {
-        if (usage instanceof ValueAnchorNode) {
-            ValueAnchorNode valueAnchorNode = (ValueAnchorNode) usage;
-            valueAnchorNode.removeAnchoredNode();
-            Debug.log("%s: Removed a ValueAnchor input", Debug.contextSnapshot(JavaMethod.class));
-        } else if (usage instanceof UnboxNode) {
-            UnboxNode unbox = (UnboxNode) usage;
-            unbox.replaceAtUsages(intrinsifiedNode);
-            graph.removeFixed(unbox);
-            Debug.log("%s: Removed an UnboxNode", Debug.contextSnapshot(JavaMethod.class));
-        } else if (usage instanceof UnsafeStoreNode) {
-            UnsafeStoreNode store = (UnsafeStoreNode) usage;
-            store.replaceFirstInput(input, intrinsifiedNode);
-        } else if (usage instanceof LoadFieldNode) {
-            LoadFieldNode load = (LoadFieldNode) usage;
-            load.replaceAtUsages(intrinsifiedNode);
-            graph.removeFixed(load);
-        } else if (usage instanceof MethodCallTargetNode) {
-            MethodCallTargetNode checkCastCallTarget = (MethodCallTargetNode) usage;
-            assert checkCastCallTarget.targetMethod().getAnnotation(NodeIntrinsic.class) != null : "checkcast at " + sourceLocation(input) +
-                            " not used by an unboxing method or node intrinsic, but by a call at " + sourceLocation(checkCastCallTarget.usages().first()) + " to " + checkCastCallTarget.targetMethod();
-            usage.replaceFirstInput(input, intrinsifiedNode);
-            Debug.log("%s: Checkcast used in an other node intrinsic", Debug.contextSnapshot(JavaMethod.class));
-        } else if (usage instanceof FrameState) {
-            usage.replaceFirstInput(input, null);
-            Debug.log("%s: Checkcast used in a FS", Debug.contextSnapshot(JavaMethod.class));
-        } else if (usage instanceof ReturnNode && ((ValueNode) intrinsifiedNode).stamp() == StampFactory.forNodeIntrinsic()) {
-            usage.replaceFirstInput(input, intrinsifiedNode);
-            Debug.log("%s: Checkcast used in a return with forNodeIntrinsic stamp", Debug.contextSnapshot(JavaMethod.class));
-        } else if (usage instanceof IsNullNode) {
-            if (!usage.hasNoUsages()) {
-                assert usage.getUsageCount() == 1 && usage.usages().first().predecessor() == input : usage + " " + input;
-                graph.replaceFloating((FloatingNode) usage, LogicConstantNode.contradiction(graph));
-                Debug.log("%s: Replaced IsNull with false", Debug.contextSnapshot(JavaMethod.class));
-            } else {
-                // Removed as usage of a GuardingPiNode
-            }
-        } else if (usage instanceof ProxyNode) {
-            ProxyNode proxy = (ProxyNode) usage;
-            assert proxy instanceof ValueProxyNode;
-            ProxyNode newProxy = ProxyNode.forValue((ValueNode) intrinsifiedNode, proxy.proxyPoint(), graph);
-            for (Node proxyUsage : usage.usages().snapshot()) {
-                checkCheckCastUsage(graph, newProxy, proxy, proxyUsage);
-            }
-        } else if (usage instanceof PiNode) {
-            for (Node piUsage : usage.usages().snapshot()) {
-                checkCheckCastUsage(graph, intrinsifiedNode, usage, piUsage);
-            }
-        } else {
-            DebugScope.forceDump(graph, "exception");
-            assert false : sourceLocation(usage) + " has unexpected usage " + usage + " of checkcast " + input + " at " + sourceLocation(input);
-        }
-    }
-}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPlugin.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -22,55 +22,21 @@
  */
 package com.oracle.graal.replacements;
 
-import static com.oracle.graal.replacements.NodeIntrinsificationPhase.COULD_NOT_FOLD;
-import static jdk.vm.ci.meta.MetaUtil.resolveJavaTypes;
-
-import java.util.Arrays;
-import java.util.List;
-
 import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.JavaType;
-import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.meta.Signature;
 
 import com.oracle.graal.api.replacements.Fold;
-import com.oracle.graal.compiler.common.type.ObjectStamp;
-import com.oracle.graal.compiler.common.type.Stamp;
-import com.oracle.graal.compiler.common.type.StampFactory;
 import com.oracle.graal.debug.MethodFilter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.NodePlugin;
-import com.oracle.graal.nodeinfo.InputType;
-import com.oracle.graal.nodeinfo.StructuralInput;
-import com.oracle.graal.nodeinfo.StructuralInput.MarkerType;
-import com.oracle.graal.nodes.ConstantNode;
 import com.oracle.graal.nodes.ValueNode;
-import com.oracle.graal.nodes.extended.ForeignCallNode;
-import com.oracle.graal.nodes.extended.UnsafeCopyNode;
-import com.oracle.graal.nodes.extended.UnsafeLoadNode;
-import com.oracle.graal.nodes.extended.UnsafeStoreNode;
-import com.oracle.graal.word.WordTypes;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.NodePlugin;
 
 /**
  * An {@link NodePlugin} that handles methods annotated by {@link Fold} and {@link NodeIntrinsic}.
  */
 public class NodeIntrinsificationPlugin implements NodePlugin {
-    protected final NodeIntrinsificationPhase nodeIntrinsification;
-    private final WordTypes wordTypes;
-    private final ResolvedJavaType structuralInputType;
-    private final boolean mustIntrinsify;
-
-    public NodeIntrinsificationPlugin(MetaAccessProvider metaAccess, NodeIntrinsificationPhase nodeIntrinsification, WordTypes wordTypes, boolean mustIntrinsify) {
-        this.nodeIntrinsification = nodeIntrinsification;
-        this.wordTypes = wordTypes;
-        this.mustIntrinsify = mustIntrinsify;
-        this.structuralInputType = metaAccess.lookupJavaType(StructuralInput.class);
-    }
 
     /**
      * Calls in replacements to methods matching one of these filters are elided. Only void methods
@@ -89,46 +55,7 @@
 
     @Override
     public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
-        NodeIntrinsic intrinsic = nodeIntrinsification.getIntrinsic(method);
-        if (intrinsic != null) {
-            Signature sig = method.getSignature();
-            JavaKind returnKind = sig.getReturnKind();
-            Stamp stamp = StampFactory.forKind(returnKind);
-            if (returnKind == JavaKind.Object) {
-                JavaType returnType = sig.getReturnType(method.getDeclaringClass());
-                if (returnType instanceof ResolvedJavaType) {
-                    ResolvedJavaType resolvedReturnType = (ResolvedJavaType) returnType;
-                    if (wordTypes.isWord(resolvedReturnType)) {
-                        stamp = wordTypes.getWordStamp(resolvedReturnType);
-                    } else {
-                        stamp = StampFactory.declared(resolvedReturnType);
-                    }
-                }
-            }
-
-            boolean result = processNodeIntrinsic(b, method, intrinsic, Arrays.asList(args), returnKind, stamp);
-            if (!result && mustIntrinsify) {
-                reportIntrinsificationFailure(b, method, args);
-            }
-            return result;
-
-        } else if (nodeIntrinsification.isFoldable(method)) {
-            ResolvedJavaType[] parameterTypes = resolveJavaTypes(method.toParameterTypes(), method.getDeclaringClass());
-            JavaConstant constant = nodeIntrinsification.tryFold(Arrays.asList(args), parameterTypes, method);
-            if (!COULD_NOT_FOLD.equals(constant)) {
-                if (constant != null) {
-                    // Replace the invoke with the result of the call
-                    b.push(method.getSignature().getReturnKind(), ConstantNode.forConstant(constant, b.getMetaAccess(), b.getGraph()));
-                } else {
-                    // This must be a void invoke
-                    assert method.getSignature().getReturnKind() == JavaKind.Void;
-                }
-                return true;
-            } else if (mustIntrinsify) {
-                reportIntrinsificationFailure(b, method, args);
-            }
-
-        } else if (MethodsElidedInSnippets != null) {
+        if (MethodsElidedInSnippets != null) {
             if (MethodFilter.matches(MethodsElidedInSnippets, method)) {
                 if (method.getSignature().getReturnKind() != JavaKind.Void) {
                     throw new JVMCIError("Cannot elide non-void method " + method.format("%H.%n(%p)"));
@@ -138,79 +65,4 @@
         }
         return false;
     }
-
-    private static boolean reportIntrinsificationFailure(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
-        StringBuilder msg = new StringBuilder();
-        msg.append("Call in ").append(b.getMethod().format("%H.%n(%p)"));
-        msg.append(" to ").append(method.format("%H.%n(%p)"));
-        msg.append(" cannot be intrinsified or folded, probably because an argument is not a constant. Arguments: ");
-        String sep = "";
-        for (ValueNode node : args) {
-            msg.append(sep).append(node.toString());
-            sep = ", ";
-        }
-        throw new JVMCIError(msg.toString());
-    }
-
-    private InputType getInputType(ResolvedJavaType type) {
-        if (type != null && structuralInputType.isAssignableFrom(type)) {
-            MarkerType markerType = type.getAnnotation(MarkerType.class);
-            if (markerType != null) {
-                return markerType.value();
-            } else {
-                throw JVMCIError.shouldNotReachHere(String.format("%s extends StructuralInput, but is not annotated with @MarkerType", type));
-            }
-        } else {
-            return InputType.Value;
-        }
-    }
-
-    private boolean processNodeIntrinsic(GraphBuilderContext b, ResolvedJavaMethod method, NodeIntrinsic intrinsic, List<ValueNode> args, JavaKind returnKind, Stamp stamp) {
-        ValueNode res = createNodeIntrinsic(b, method, intrinsic, args, stamp);
-        if (res == null) {
-            return false;
-        }
-        if (res instanceof UnsafeCopyNode) {
-            UnsafeCopyNode copy = (UnsafeCopyNode) res;
-            UnsafeLoadNode value = b.add(new UnsafeLoadNode(copy.sourceObject(), copy.sourceOffset(), copy.accessKind(), copy.getLocationIdentity()));
-            b.add(new UnsafeStoreNode(copy.destinationObject(), copy.destinationOffset(), value, copy.accessKind(), copy.getLocationIdentity()));
-            return true;
-        } else if (res instanceof ForeignCallNode) {
-            /*
-             * Need to update the BCI of a ForeignCallNode so that it gets the stateDuring in the
-             * case that the foreign call can deoptimize. As with all deoptimization, we need a
-             * state in a non-intrinsic method.
-             */
-            GraphBuilderContext nonIntrinsicAncestor = b.getNonIntrinsicAncestor();
-            if (nonIntrinsicAncestor != null) {
-                ForeignCallNode foreign = (ForeignCallNode) res;
-                foreign.setBci(nonIntrinsicAncestor.bci());
-            }
-        }
-
-        boolean nonValueType = false;
-        if (returnKind == JavaKind.Object && stamp instanceof ObjectStamp) {
-            ResolvedJavaType type = ((ObjectStamp) stamp).type();
-            if (type != null && structuralInputType.isAssignableFrom(type)) {
-                assert res.isAllowedUsageType(getInputType(type));
-                nonValueType = true;
-            }
-        }
-
-        if (returnKind != JavaKind.Void) {
-            assert nonValueType || res.getStackKind() != JavaKind.Void;
-            res = b.addPush(returnKind, res);
-        } else {
-            assert res.getStackKind() == JavaKind.Void;
-            res = b.add(res);
-        }
-
-        return true;
-    }
-
-    private ValueNode createNodeIntrinsic(GraphBuilderContext b, ResolvedJavaMethod method, NodeIntrinsic intrinsic, List<ValueNode> args, Stamp stamp) {
-        ValueNode res = nodeIntrinsification.createIntrinsicNode(args, stamp, method, b.getGraph(), intrinsic);
-        assert res != null : String.format("Could not create node intrinsic for call to %s as one of the arguments expected to be constant isn't: arguments=%s", method.format("%H.%n(%p)"), args);
-        return res;
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationProvider.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2011, 2015, 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.replacements;
+
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+import com.oracle.graal.api.replacements.SnippetReflectionProvider;
+import com.oracle.graal.compiler.common.spi.ForeignCallsProvider;
+import com.oracle.graal.compiler.common.type.Stamp;
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.nodes.graphbuilderconf.NodeIntrinsicPluginFactory.InjectionProvider;
+import com.oracle.graal.word.WordTypes;
+
+public class NodeIntrinsificationProvider implements InjectionProvider {
+
+    private final MetaAccessProvider metaAccess;
+    private final SnippetReflectionProvider snippetReflection;
+    private final ForeignCallsProvider foreignCalls;
+    private final WordTypes wordTypes;
+
+    public NodeIntrinsificationProvider(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, WordTypes wordTypes) {
+        this.metaAccess = metaAccess;
+        this.snippetReflection = snippetReflection;
+        this.foreignCalls = foreignCalls;
+        this.wordTypes = wordTypes;
+    }
+
+    @Override
+    public Stamp getReturnStamp(Class<?> type) {
+        JavaKind kind = JavaKind.fromJavaClass(type);
+        if (kind == JavaKind.Object) {
+            ResolvedJavaType returnType = metaAccess.lookupJavaType(type);
+            if (wordTypes.isWord(returnType)) {
+                return wordTypes.getWordStamp(returnType);
+            } else {
+                return StampFactory.declared(returnType);
+            }
+        } else {
+            return StampFactory.forKind(kind);
+        }
+    }
+
+    @Override
+    public <T> T getInjectedArgument(Class<T> type) {
+        T injected = snippetReflection.getInjectedNodeIntrinsicParameter(type);
+        if (injected != null) {
+            return injected;
+        } else if (type.equals(ForeignCallsProvider.class)) {
+            return type.cast(foreignCalls);
+        } else if (type.equals(SnippetReflectionProvider.class)) {
+            return type.cast(snippetReflection);
+        } else {
+            throw new JVMCIError("Cannot handle injected argument of type %s.", type.getName());
+        }
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -53,15 +53,6 @@
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.NodeClass;
 import com.oracle.graal.graph.spi.Canonicalizable;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InlineInvokePlugin;
-import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo;
-import com.oracle.graal.graphbuilderconf.IntrinsicContext;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver;
-import com.oracle.graal.graphbuilderconf.LoopExplosionPlugin;
-import com.oracle.graal.graphbuilderconf.ParameterPlugin;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.nodeinfo.NodeInfo;
 import com.oracle.graal.nodes.AbstractBeginNode;
@@ -87,6 +78,15 @@
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.extended.ForeignCallNode;
 import com.oracle.graal.nodes.extended.IntegerSwitchNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InlineInvokePlugin;
+import com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.LoopExplosionPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.ParameterPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver;
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
 import com.oracle.graal.nodes.java.MonitorIdNode;
 import com.oracle.graal.nodes.spi.StampProvider;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Tue Dec 08 12:30:15 2015 -0800
@@ -24,9 +24,9 @@
 
 import static com.oracle.graal.compiler.common.GraalOptions.DeoptALot;
 import static com.oracle.graal.compiler.common.GraalOptions.OptCanonicalizer;
-import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
 import static com.oracle.graal.java.BytecodeParserOptions.InlineDuringParsing;
 import static com.oracle.graal.java.BytecodeParserOptions.InlineIntrinsicsDuringParsing;
+import static com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.Required;
 import static java.lang.String.format;
 import static jdk.vm.ci.meta.MetaUtil.toInternalName;
@@ -73,13 +73,6 @@
 import com.oracle.graal.debug.DebugTimer;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InlineInvokePlugin;
-import com.oracle.graal.graphbuilderconf.IntrinsicContext;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
-import com.oracle.graal.graphbuilderconf.MethodSubstitutionPlugin;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.java.GraphBuilderPhase.Instance;
 import com.oracle.graal.nodes.CallTargetNode;
@@ -88,6 +81,14 @@
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.graphbuilderconf.GeneratedInvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InlineInvokePlugin;
+import com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.MethodSubstitutionPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
 import com.oracle.graal.nodes.spi.Replacements;
 import com.oracle.graal.nodes.spi.StampProvider;
@@ -120,8 +121,12 @@
         return graphBuilderPlugins;
     }
 
+    protected boolean hasGeneratedInvocationPluginAnnotation(ResolvedJavaMethod method) {
+        return method.getAnnotation(Node.NodeIntrinsic.class) != null || method.getAnnotation(Fold.class) != null;
+    }
+
     protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) {
-        return method.getAnnotation(Node.NodeIntrinsic.class) != null || method.getAnnotation(Word.Operation.class) != null || method.getAnnotation(Fold.class) != null;
+        return method.getAnnotation(Word.Operation.class) != null;
     }
 
     private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough
@@ -144,7 +149,8 @@
             return null;
         }
         if (b.parsingIntrinsic()) {
-            assert !hasGenericInvocationPluginAnnotation(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), NodeIntrinsificationPlugin.class.getName());
+            assert !hasGeneratedInvocationPluginAnnotation(method) : format("%s should have been handled by a %s", method.format("%H.%n(%p)"), GeneratedInvocationPlugin.class.getSimpleName());
+            assert !hasGenericInvocationPluginAnnotation(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), WordOperationPlugin.class.getSimpleName());
 
             assert b.getDepth() < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded";
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounterNode.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounterNode.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -127,7 +127,7 @@
     static class SnippetCounterSnippets implements Snippets {
 
         @Fold
-        private static int countOffset() {
+        static int countOffset() {
             try {
                 return (int) UNSAFE.objectFieldOffset(SnippetCounter.class.getDeclaredField("value"));
             } catch (Exception e) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Tue Dec 08 12:30:15 2015 -0800
@@ -41,12 +41,6 @@
 import com.oracle.graal.graph.Edges;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.NodeList;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin.Receiver;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
-import com.oracle.graal.graphbuilderconf.MethodSubstitutionPlugin;
 import com.oracle.graal.nodes.ConstantNode;
 import com.oracle.graal.nodes.DeoptimizeNode;
 import com.oracle.graal.nodes.FixedGuardNode;
@@ -78,6 +72,12 @@
 import com.oracle.graal.nodes.extended.UnboxNode;
 import com.oracle.graal.nodes.extended.UnsafeLoadNode;
 import com.oracle.graal.nodes.extended.UnsafeStoreNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.MethodSubstitutionPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin.Receiver;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.java.ClassIsAssignableFromNode;
 import com.oracle.graal.nodes.java.CompareAndSwapNode;
 import com.oracle.graal.nodes.java.DynamicNewArrayNode;
@@ -488,10 +488,9 @@
         for (Class<?> c : new Class<?>[]{Node.class, NodeList.class}) {
             r.register2("get" + c.getSimpleName() + "Unsafe", Node.class, long.class, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset) {
-                    ValueNode value = b.add(new UnsafeLoadNode(node, offset, JavaKind.Object, LocationIdentity.any()));
-                    boolean exactType = false;
-                    boolean nonNull = false;
-                    b.addPush(JavaKind.Object, new PiNode(value, metaAccess.lookupJavaType(c), exactType, nonNull));
+                    UnsafeLoadNode value = b.add(new UnsafeLoadNode(node, offset, JavaKind.Object, LocationIdentity.any()));
+                    value.setStamp(StampFactory.declared(metaAccess.lookupJavaType(c)));
+                    b.addPush(JavaKind.Object, value);
                     return true;
                 }
             });
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -23,7 +23,7 @@
 package com.oracle.graal.replacements;
 
 import com.oracle.graal.compiler.common.SuppressFBWarnings;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
 import com.oracle.graal.nodes.java.LoadFieldNode;
 import com.oracle.graal.replacements.nodes.ArrayEqualsNode;
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -39,10 +39,6 @@
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
 import com.oracle.graal.compiler.common.calc.Condition;
 import com.oracle.graal.compiler.common.type.Stamp;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InlineInvokePlugin;
-import com.oracle.graal.graphbuilderconf.NodePlugin;
-import com.oracle.graal.graphbuilderconf.ParameterPlugin;
 import com.oracle.graal.nodes.ConstantNode;
 import com.oracle.graal.nodes.Invoke;
 import com.oracle.graal.nodes.ParameterNode;
@@ -59,6 +55,10 @@
 import com.oracle.graal.nodes.calc.ZeroExtendNode;
 import com.oracle.graal.nodes.extended.JavaReadNode;
 import com.oracle.graal.nodes.extended.JavaWriteNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InlineInvokePlugin;
+import com.oracle.graal.nodes.graphbuilderconf.NodePlugin;
+import com.oracle.graal.nodes.graphbuilderconf.ParameterPlugin;
 import com.oracle.graal.nodes.java.LoadFieldNode;
 import com.oracle.graal.nodes.java.LoadIndexedNode;
 import com.oracle.graal.nodes.java.StoreIndexedNode;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DeferredPiNode.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DeferredPiNode.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, 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
@@ -36,12 +36,11 @@
 import com.oracle.graal.nodes.PiNode;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.calc.FloatingNode;
-import com.oracle.graal.replacements.NodeIntrinsificationPhase;
 
 /**
  * A node for use in method substitutions or snippets that changes the type of its input where the
- * type is not immediately available at {@link NodeIntrinsificationPhase intrinsification} time. It
- * is replaced by a {@link PiNode} once the type becomes constant (which <b>must</b> happen).
+ * type is not immediately available at intrinsification time. It is replaced by a {@link PiNode}
+ * once the type becomes constant (which <b>must</b> happen).
  */
 @NodeInfo
 public final class DeferredPiNode extends FloatingNode implements Canonicalizable {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ResolvedMethodHandleCallTargetNode.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ResolvedMethodHandleCallTargetNode.java	Tue Dec 08 12:30:15 2015 -0800
@@ -22,11 +22,6 @@
  */
 package com.oracle.graal.replacements.nodes;
 
-import static sun.misc.Version.jdkMajorVersion;
-import static sun.misc.Version.jdkMicroVersion;
-import static sun.misc.Version.jdkMinorVersion;
-import static sun.misc.Version.jdkUpdateVersion;
-
 import java.lang.invoke.MethodHandle;
 
 import jdk.vm.ci.common.JVMCIError;
@@ -65,10 +60,6 @@
      */
     public static MethodCallTargetNode create(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod,
                     ValueNode[] originalArguments, JavaType originalReturnType) {
-        if (jdkMajorVersion() >= 1 && jdkMinorVersion() >= 8 && jdkMicroVersion() >= 0 && jdkUpdateVersion() >= 60) {
-            // https://bugs.openjdk.java.net/browse/JDK-8072008 is targeted for 8u60
-            return new MethodCallTargetNode(invokeKind, targetMethod, arguments, returnType, null);
-        }
         return new ResolvedMethodHandleCallTargetNode(invokeKind, targetMethod, arguments, returnType, originalTargetMethod, originalArguments, originalReturnType);
     }
 
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Tue Dec 08 12:30:15 2015 -0800
@@ -64,9 +64,6 @@
 import com.oracle.graal.debug.DebugEnvironment;
 import com.oracle.graal.debug.GraalDebugConfig;
 import com.oracle.graal.debug.TTY;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
 import com.oracle.graal.hotspot.HotSpotBackend;
 import com.oracle.graal.hotspot.meta.HotSpotProviders;
 import com.oracle.graal.java.GraphBuilderPhase;
@@ -74,6 +71,9 @@
 import com.oracle.graal.lir.phases.LIRSuites;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.phases.BasePhase;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.PhaseSuite;
@@ -160,11 +160,20 @@
     @Override
     public TruffleCompiler getTruffleCompiler() {
         if (truffleCompiler == null) {
-            truffleCompiler = DefaultTruffleCompiler.create(this);
+            initializeTruffleCompiler();
         }
         return truffleCompiler;
     }
 
+    private void initializeTruffleCompiler() {
+        synchronized (this) {
+            // might occur for multiple compiler threads at the same time.
+            if (truffleCompiler == null) {
+                truffleCompiler = DefaultTruffleCompiler.create(this);
+            }
+        }
+    }
+
     @Override
     public RootCallTarget createCallTarget(RootNode rootNode) {
         return createCallTargetImpl(null, rootNode);
@@ -280,14 +289,6 @@
     }
 
     @Override
-    public void compile(OptimizedCallTarget optimizedCallTarget, boolean mayBeAsynchronous) {
-        /* Ensure compiler is created. */
-        getTruffleCompiler();
-
-        super.compile(optimizedCallTarget, mayBeAsynchronous);
-    }
-
-    @Override
     public boolean cancelInstalledTask(OptimizedCallTarget optimizedCallTarget, Object source, CharSequence reason) {
         if (lazy == null) {
             // if truffle wasn't initialized yet, this is a noop
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ConditionAnchoringTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ConditionAnchoringTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -36,10 +36,6 @@
 
 import com.oracle.graal.compiler.test.GraalCompilerTest;
 import com.oracle.graal.graph.iterators.NodeIterable;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InlineInvokePlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.BeginNode;
 import com.oracle.graal.nodes.ConditionAnchorNode;
 import com.oracle.graal.nodes.IfNode;
@@ -47,6 +43,10 @@
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.extended.UnsafeLoadNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InlineInvokePlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.memory.FloatingReadNode;
 import com.oracle.graal.nodes.memory.ReadNode;
 import com.oracle.graal.nodes.spi.LoweringTool.StandardLoweringStage;
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -25,7 +25,7 @@
 import org.junit.Test;
 
 import com.oracle.graal.compiler.test.GraalCompilerTest;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import com.oracle.graal.truffle.substitutions.TruffleGraphBuilderPlugins;
 import com.oracle.truffle.api.ExactMath;
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleCompiler.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleCompiler.java	Tue Dec 08 12:30:15 2015 -0800
@@ -26,9 +26,9 @@
 
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
 import com.oracle.graal.compiler.target.Backend;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.lir.phases.LIRSuites;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.phases.BasePhase;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.tiers.HighTierContext;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Tue Dec 08 12:30:15 2015 -0800
@@ -281,7 +281,7 @@
         checkSlotIndex(slotIndex);
         boolean condition = getTags()[slotIndex] == tag;
         if (!condition) {
-            CompilerDirectives.transferToInterpreter();
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             throw new FrameSlotTypeException();
         }
         return condition;
@@ -303,7 +303,7 @@
     public Object getValue(FrameSlot slot) {
         int slotIndex = slot.getIndex();
         if (CompilerDirectives.inInterpreter() && slotIndex >= getTags().length) {
-            CompilerDirectives.transferToInterpreter();
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             resize();
         }
         byte tag = getTags()[slotIndex];
@@ -357,7 +357,7 @@
             return cachedTags[slotIndex];
         }
 
-        CompilerDirectives.transferToInterpreter();
+        CompilerDirectives.transferToInterpreterAndInvalidate();
         resize();
         return getTags()[slotIndex];
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Tue Dec 08 12:30:15 2015 -0800
@@ -359,7 +359,7 @@
     private void doCompile0(OptimizedCallTarget optimizedCallTarget) {
         boolean success = true;
         try (Scope s = Debug.scope("Truffle", new TruffleDebugJavaMethod(optimizedCallTarget))) {
-            truffleCompiler.compileMethod(optimizedCallTarget);
+            getTruffleCompiler().compileMethod(optimizedCallTarget);
         } catch (Throwable e) {
             optimizedCallTarget.notifyCompilationFailed(e);
             success = false;
@@ -371,14 +371,13 @@
     protected abstract BackgroundCompileQueue getCompileQueue();
 
     public void compile(OptimizedCallTarget optimizedCallTarget, boolean mayBeAsynchronous) {
-        Runnable r = new Runnable() {
+        BackgroundCompileQueue l = getCompileQueue();
+        Future<?> future = l.compileQueue.submit(new Runnable() {
             @Override
             public void run() {
                 doCompile(optimizedCallTarget);
             }
-        };
-        BackgroundCompileQueue l = getCompileQueue();
-        Future<?> future = l.compileQueue.submit(r);
+        });
         l.compilations.put(optimizedCallTarget, future);
         getCompilationNotify().notifyCompilationQueued(optimizedCallTarget);
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Tue Dec 08 12:30:15 2015 -0800
@@ -194,6 +194,7 @@
     public Object call(Object... args) {
         compilationProfile.reportIndirectCall();
         if (profiledArgumentTypesAssumption != null && profiledArgumentTypesAssumption.isValid()) {
+            // Argument profiling is not possible for targets of indirect calls.
             CompilerDirectives.transferToInterpreterAndInvalidate();
             profiledArgumentTypesAssumption.invalidate();
             profiledArgumentTypes = null;
@@ -232,20 +233,26 @@
 
     @ExplodeLoop
     void profileArguments(Object[] args) {
-        if (profiledArgumentTypesAssumption == null) {
+        Assumption typesAssumption = profiledArgumentTypesAssumption;
+        if (typesAssumption == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             initializeProfiledArgumentTypes(args);
-        } else if (profiledArgumentTypes != null) {
-            if (profiledArgumentTypes.length != args.length) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                profiledArgumentTypesAssumption.invalidate();
-                profiledArgumentTypes = null;
-            } else if (TruffleArgumentTypeSpeculation.getValue() && profiledArgumentTypesAssumption.isValid()) {
-                for (int i = 0; i < profiledArgumentTypes.length; i++) {
-                    if (profiledArgumentTypes[i] != null && !profiledArgumentTypes[i].isInstance(args[i])) {
-                        CompilerDirectives.transferToInterpreterAndInvalidate();
-                        updateProfiledArgumentTypes(args);
-                        break;
+        } else {
+            Class<?>[] types = profiledArgumentTypes;
+            if (types != null) {
+                if (types.length != args.length) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    typesAssumption.invalidate();
+                    profiledArgumentTypes = null;
+                } else if (typesAssumption.isValid()) {
+                    for (int i = 0; i < types.length; i++) {
+                        Class<?> type = types[i];
+                        Object value = args[i];
+                        if (type != null && (value == null || value.getClass() != type)) {
+                            CompilerDirectives.transferToInterpreterAndInvalidate();
+                            updateProfiledArgumentTypes(args, types);
+                            break;
+                        }
                     }
                 }
             }
@@ -255,19 +262,21 @@
     private void initializeProfiledArgumentTypes(Object[] args) {
         CompilerAsserts.neverPartOfCompilation();
         profiledArgumentTypesAssumption = Truffle.getRuntime().createAssumption("Profiled Argument Types");
-        profiledArgumentTypes = new Class<?>[args.length];
         if (TruffleArgumentTypeSpeculation.getValue()) {
+            Class<?>[] result = new Class<?>[args.length];
             for (int i = 0; i < args.length; i++) {
-                profiledArgumentTypes[i] = classOf(args[i]);
+                result[i] = classOf(args[i]);
             }
+
+            profiledArgumentTypes = result;
         }
     }
 
-    private void updateProfiledArgumentTypes(Object[] args) {
+    private void updateProfiledArgumentTypes(Object[] args, Class<?>[] types) {
         CompilerAsserts.neverPartOfCompilation();
         profiledArgumentTypesAssumption.invalidate();
-        for (int j = 0; j < profiledArgumentTypes.length; j++) {
-            profiledArgumentTypes[j] = joinTypes(profiledArgumentTypes[j], classOf(args[j]));
+        for (int j = 0; j < types.length; j++) {
+            types[j] = joinTypes(types[j], classOf(args[j]));
         }
         profiledArgumentTypesAssumption = Truffle.getRuntime().createAssumption("Profiled Argument Types");
     }
@@ -279,14 +288,8 @@
     private static Class<?> joinTypes(Class<?> class1, Class<?> class2) {
         if (class1 == class2) {
             return class1;
-        } else if (class1 == null || class2 == null) {
+        } else {
             return null;
-        } else if (class1.isAssignableFrom(class2)) {
-            return class1;
-        } else if (class2.isAssignableFrom(class1)) {
-            return class2;
-        } else {
-            return Object.class;
         }
     }
 
@@ -308,9 +311,10 @@
 
     public final Object callRoot(Object[] originalArguments) {
         Object[] args = originalArguments;
-        if (this.profiledArgumentTypesAssumption != null && CompilerDirectives.inCompiledCode() && profiledArgumentTypesAssumption.isValid()) {
-            args = unsafeCast(castArrayFixedLength(args, profiledArgumentTypes.length), Object[].class, true, true);
-            if (TruffleArgumentTypeSpeculation.getValue()) {
+        if (CompilerDirectives.inCompiledCode()) {
+            Assumption argumentTypesAssumption = this.profiledArgumentTypesAssumption;
+            if (argumentTypesAssumption != null && argumentTypesAssumption.isValid()) {
+                args = unsafeCast(castArrayFixedLength(args, profiledArgumentTypes.length), Object[].class, true, true);
                 args = castArguments(args);
             }
         }
@@ -324,7 +328,8 @@
     }
 
     void profileReturnType(Object result) {
-        if (profiledReturnTypeAssumption == null) {
+        Assumption returnTypeAssumption = profiledReturnTypeAssumption;
+        if (returnTypeAssumption == null) {
             if (TruffleReturnTypeSpeculation.getValue()) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
                 profiledReturnType = (result == null ? null : result.getClass());
@@ -334,7 +339,7 @@
             if (result == null || profiledReturnType != result.getClass()) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
                 profiledReturnType = null;
-                profiledReturnTypeAssumption.invalidate();
+                returnTypeAssumption.invalidate();
             }
         }
     }
@@ -475,9 +480,10 @@
 
     @ExplodeLoop
     private Object[] castArguments(Object[] originalArguments) {
-        Object[] castArguments = new Object[profiledArgumentTypes.length];
-        for (int i = 0; i < profiledArgumentTypes.length; i++) {
-            castArguments[i] = profiledArgumentTypes[i] != null ? unsafeCast(originalArguments[i], profiledArgumentTypes[i], true, true) : originalArguments[i];
+        Class<?>[] types = profiledArgumentTypes;
+        Object[] castArguments = new Object[types.length];
+        for (int i = 0; i < types.length; i++) {
+            castArguments[i] = types[i] != null ? unsafeCast(originalArguments[i], types[i], true, true) : originalArguments[i];
         }
         return castArguments;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Dec 08 12:30:15 2015 -0800
@@ -50,13 +50,6 @@
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.Indent;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InlineInvokePlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
-import com.oracle.graal.graphbuilderconf.LoopExplosionPlugin;
-import com.oracle.graal.graphbuilderconf.ParameterPlugin;
 import com.oracle.graal.java.ComputeLoopFrequenciesClosure;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.nodes.ConstantNode;
@@ -64,6 +57,13 @@
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.calc.FloatingNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InlineInvokePlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.LoopExplosionPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.ParameterPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.java.CheckCastNode;
 import com.oracle.graal.nodes.java.InstanceOfNode;
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
@@ -159,7 +159,7 @@
     @SuppressWarnings("try")
     public StructuredGraph createGraph(final OptimizedCallTarget callTarget, AllowAssumptions allowAssumptions) {
         try (Scope c = Debug.scope("TruffleTree")) {
-            Debug.dump(callTarget, callTarget.toString());
+            Debug.dump(callTarget, "%s", callTarget);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilationResultBuilderFactory.java	Tue Dec 08 12:30:15 2015 -0800
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.CompilationResult;
+import jdk.vm.ci.meta.Assumptions.Assumption;
+
+import com.oracle.graal.asm.Assembler;
+import com.oracle.graal.compiler.common.spi.ForeignCallsProvider;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+import com.oracle.graal.lir.asm.CompilationResultBuilderFactory;
+import com.oracle.graal.lir.asm.FrameContext;
+import com.oracle.graal.lir.framemap.FrameMap;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.truffle.nodes.AssumptionValidAssumption;
+
+/**
+ * A mechanism for Truffle to update a {@link CompilationResult} before it is
+ * {@linkplain CompilationResult#close() closed} by the Graal compiler.
+ */
+class TruffleCompilationResultBuilderFactory implements CompilationResultBuilderFactory {
+
+    /**
+     * The graph being compiled.
+     */
+    private final StructuredGraph graph;
+
+    /**
+     * List into which {@link AssumptionValidAssumption}s are added.
+     */
+    private final List<AssumptionValidAssumption> validAssumptions;
+
+    public TruffleCompilationResultBuilderFactory(StructuredGraph graph, List<AssumptionValidAssumption> validAssumptions) {
+        this.graph = graph;
+        this.validAssumptions = validAssumptions;
+    }
+
+    public CompilationResultBuilder createBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, FrameContext frameContext,
+                    CompilationResult compilationResult) {
+        return new CompilationResultBuilder(codeCache, foreignCalls, frameMap, asm, frameContext, compilationResult) {
+            @Override
+            protected void closeCompilationResult() {
+                CompilationResult result = this.compilationResult;
+                result.setMethods(graph.method(), graph.getInlinedMethods());
+                result.setBytecodeSize(graph.getBytecodeSize());
+
+                Set<Assumption> newAssumptions = new HashSet<>();
+                for (Assumption assumption : graph.getAssumptions()) {
+                    TruffleCompilationResultBuilderFactory.processAssumption(newAssumptions, assumption, validAssumptions);
+                }
+
+                if (result.getAssumptions() != null) {
+                    for (Assumption assumption : result.getAssumptions()) {
+                        TruffleCompilationResultBuilderFactory.processAssumption(newAssumptions, assumption, validAssumptions);
+                    }
+                }
+
+                result.setAssumptions(newAssumptions.toArray(new Assumption[newAssumptions.size()]));
+                super.closeCompilationResult();
+            }
+        };
+    }
+
+    static void processAssumption(Set<Assumption> newAssumptions, Assumption assumption, List<AssumptionValidAssumption> manual) {
+        if (assumption != null) {
+            if (assumption instanceof AssumptionValidAssumption) {
+                AssumptionValidAssumption assumptionValidAssumption = (AssumptionValidAssumption) assumption;
+                manual.add(assumptionValidAssumption);
+            } else {
+                newAssumptions.add(assumption);
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java	Tue Dec 08 12:30:15 2015 -0800
@@ -27,16 +27,13 @@
 import static jdk.vm.ci.code.CodeUtil.getCallingConvention;
 
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
 import jdk.vm.ci.code.CallingConvention;
 import jdk.vm.ci.code.CallingConvention.Type;
 import jdk.vm.ci.code.CodeCacheProvider;
 import jdk.vm.ci.code.CompilationResult;
 import jdk.vm.ci.code.InstalledCode;
-import jdk.vm.ci.meta.Assumptions.Assumption;
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaType;
@@ -50,12 +47,11 @@
 import com.oracle.graal.debug.DebugEnvironment;
 import com.oracle.graal.debug.DebugMemUseTracker;
 import com.oracle.graal.debug.DebugTimer;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.lir.asm.CompilationResultBuilderFactory;
 import com.oracle.graal.lir.phases.LIRSuites;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.tiers.HighTierContext;
@@ -178,6 +174,8 @@
         }
 
         CompilationResult result = null;
+        List<AssumptionValidAssumption> validAssumptions = new ArrayList<>();
+        TruffleCompilationResultBuilderFactory factory = new TruffleCompilationResultBuilderFactory(graph, validAssumptions);
         try (DebugCloseable a = CompilationTime.start(); Scope s = Debug.scope("TruffleGraal.GraalCompiler", graph, providers.getCodeCache()); DebugCloseable c = CompilationMemUse.start()) {
             SpeculationLog speculationLog = graph.getSpeculationLog();
             if (speculationLog != null) {
@@ -187,31 +185,13 @@
             CodeCacheProvider codeCache = providers.getCodeCache();
             CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false);
             CompilationResult compilationResult = new CompilationResult(name);
-            result = compileGraph(graph, cc, graph.method(), providers, backend, graphBuilderSuite, Optimizations, getProfilingInfo(graph), suites, lirSuites, compilationResult,
-                            CompilationResultBuilderFactory.Default);
+            result = compileGraph(graph, cc, graph.method(), providers, backend, graphBuilderSuite, Optimizations, getProfilingInfo(graph), suites, lirSuites, compilationResult, factory);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
 
         compilationNotify.notifyCompilationGraalTierFinished((OptimizedCallTarget) predefinedInstalledCode, graph);
 
-        result.setMethods(graph.method(), graph.getInlinedMethods());
-        result.setBytecodeSize(graph.getBytecodeSize());
-
-        List<AssumptionValidAssumption> validAssumptions = new ArrayList<>();
-        Set<Assumption> newAssumptions = new HashSet<>();
-        for (Assumption assumption : graph.getAssumptions()) {
-            processAssumption(newAssumptions, assumption, validAssumptions);
-        }
-
-        if (result.getAssumptions() != null) {
-            for (Assumption assumption : result.getAssumptions()) {
-                processAssumption(newAssumptions, assumption, validAssumptions);
-            }
-        }
-
-        result.setAssumptions(newAssumptions.toArray(new Assumption[newAssumptions.size()]));
-
         InstalledCode installedCode;
         try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); DebugCloseable a = CodeInstallationTime.start(); DebugCloseable c = CodeInstallationMemUse.start()) {
             installedCode = providers.getCodeCache().addCode(graph.method(), result, graph.getSpeculationLog(), predefinedInstalledCode);
@@ -228,17 +208,6 @@
 
     protected abstract PhaseSuite<HighTierContext> createGraphBuilderSuite();
 
-    public void processAssumption(Set<Assumption> newAssumptions, Assumption assumption, List<AssumptionValidAssumption> manual) {
-        if (assumption != null) {
-            if (assumption instanceof AssumptionValidAssumption) {
-                AssumptionValidAssumption assumptionValidAssumption = (AssumptionValidAssumption) assumption;
-                manual.add(assumptionValidAssumption);
-            } else {
-                newAssumptions.add(assumption);
-            }
-        }
-    }
-
     public PartialEvaluator getPartialEvaluator() {
         return partialEvaluator;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/HistogramInlineInvokePlugin.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/HistogramInlineInvokePlugin.java	Tue Dec 08 12:30:15 2015 -0800
@@ -31,11 +31,11 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 import com.oracle.graal.graph.Node;
-import com.oracle.graal.graphbuilderconf.InlineInvokePlugin;
 import com.oracle.graal.nodes.BeginNode;
 import com.oracle.graal.nodes.DeoptimizeNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.VirtualState;
+import com.oracle.graal.nodes.graphbuilderconf.InlineInvokePlugin;
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
 import com.oracle.graal.nodes.virtual.VirtualObjectNode;
 import com.oracle.graal.truffle.OptimizedCallTarget;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Tue Dec 08 12:30:15 2015 -0800
@@ -43,11 +43,6 @@
 import com.oracle.graal.compiler.common.type.StampFactory;
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.graph.Node;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin;
-import com.oracle.graal.graphbuilderconf.InvocationPlugin.Receiver;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.CallTargetNode;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.ConditionAnchorNode;
@@ -65,6 +60,11 @@
 import com.oracle.graal.nodes.extended.BranchProbabilityNode;
 import com.oracle.graal.nodes.extended.UnsafeLoadNode;
 import com.oracle.graal.nodes.extended.UnsafeStoreNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin.Receiver;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
 import com.oracle.graal.nodes.virtual.EnsureVirtualizedNode;
 import com.oracle.graal.replacements.nodes.arithmetic.IntegerAddExactNode;
@@ -228,7 +228,7 @@
                      * and constant folding could still eliminate the call to bailout(). However, we
                      * also want to stop parsing, since we are sure that we will never need the
                      * graph beyond the bailout point.
-                     * 
+                     *
                      * Therefore, we manually emit the call to bailout, which will be intrinsified
                      * later when intrinsifications can no longer be delayed. The call is followed
                      * by a NeverPartOfCompilationNode, which is a control sink and therefore stops
@@ -398,17 +398,24 @@
                         } else {
                             piStamp = StampFactory.declaredTrusted(javaType, nonNull.asJavaConstant().asInt() != 0);
                         }
-                        LogicNode compareNode = CompareNode.createCompareNode(object.graph(), Condition.EQ, condition, ConstantNode.forBoolean(true, object.graph()), constantReflection);
-                        boolean skipAnchor = false;
-                        if (compareNode instanceof LogicConstantNode) {
-                            LogicConstantNode logicConstantNode = (LogicConstantNode) compareNode;
-                            if (logicConstantNode.getValue()) {
-                                skipAnchor = true;
+
+                        ConditionAnchorNode valueAnchorNode = null;
+                        if (condition.isConstant() && condition.asJavaConstant().asInt() == 1) {
+                            // Nothing to do.
+                        } else {
+                            boolean skipAnchor = false;
+                            LogicNode compareNode = CompareNode.createCompareNode(object.graph(), Condition.EQ, condition, ConstantNode.forBoolean(true, object.graph()), constantReflection);
+
+                            if (compareNode instanceof LogicConstantNode) {
+                                LogicConstantNode logicConstantNode = (LogicConstantNode) compareNode;
+                                if (logicConstantNode.getValue()) {
+                                    skipAnchor = true;
+                                }
                             }
-                        }
-                        ConditionAnchorNode valueAnchorNode = null;
-                        if (!skipAnchor) {
-                            valueAnchorNode = b.add(new ConditionAnchorNode(compareNode));
+
+                            if (!skipAnchor) {
+                                valueAnchorNode = b.add(new ConditionAnchorNode(compareNode));
+                            }
                         }
                         b.addPush(JavaKind.Object, new PiNode(object, piStamp, valueAnchorNode));
                     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleInvocationPluginProvider.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleInvocationPluginProvider.java	Tue Dec 08 12:30:15 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -25,7 +25,7 @@
 import jdk.vm.ci.meta.MetaAccessProvider;
 
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
 
 public interface TruffleInvocationPluginProvider {
     void registerInvocationPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins, boolean canDelayIntrinsification, SnippetReflectionProvider snippetReflection);
--- a/graal/com.oracle.graal.virtual.bench/src/com/oracle/graal/virtual/bench/PartialEscapeBench.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.virtual.bench/src/com/oracle/graal/virtual/bench/PartialEscapeBench.java	Tue Dec 08 12:30:15 2015 -0800
@@ -27,7 +27,9 @@
 import org.openjdk.jmh.annotations.State;
 import org.openjdk.jmh.annotations.Warmup;
 
-public class PartialEscapeBench {
+import com.oracle.graal.microbenchmarks.graal.GraalBenchmark;
+
+public class PartialEscapeBench extends GraalBenchmark {
 
     private static class Thing {
         final int id;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Tue Dec 08 12:29:24 2015 -0800
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Tue Dec 08 12:30:15 2015 -0800
@@ -122,6 +122,27 @@
     }
 
     protected void postIteration(final StructuredGraph graph, final PhaseContextT context, Set<Node> changedNodes) {
+        /*
+         * The nodes were added without uniqueing them first so GVN the leaf nodes now. The normal
+         * CanonicalizerPhase will GVN non-leaf value numberable nodes.
+         */
+        for (Node node : changedNodes) {
+            if (node.isAlive() && node.getNodeClass().valueNumberable() && node.getNodeClass().isLeafNode()) {
+                Node duplicate = graph.findDuplicate(node);
+                if (duplicate != node) {
+                    if (duplicate == null) {
+                        /*
+                         * There's no version of this constant in the leaf node cache so create a
+                         * copy to add it to the table.
+                         */
+                        duplicate = node.copyWithInputs();
+                        assert duplicate == graph.findDuplicate(duplicate);
+                    }
+                    node.replaceAtUsages(duplicate);
+                    node.safeDelete();
+                }
+            }
+        }
         if (canonicalizer != null) {
             canonicalizer.applyIncremental(graph, context, changedNodes);
         }
--- a/mx.graal/mx_graal_8.py	Tue Dec 08 12:29:24 2015 -0800
+++ b/mx.graal/mx_graal_8.py	Tue Dec 08 12:30:15 2015 -0800
@@ -113,12 +113,10 @@
             vmArgs = ['-XX:-UseJVMCIClassLoader'] + vmArgs
 
     # look for -f in JMH arguments
-    containsF = False
     forking = True
     for i in range(len(jmhArgs)):
         arg = jmhArgs[i]
         if arg.startswith('-f'):
-            containsF = True
             if arg == '-f' and (i+1) < len(jmhArgs):
                 arg += jmhArgs[i+1]
             try:
@@ -133,10 +131,6 @@
         if not forking:
             args += vmArgs
     else:
-        # default to -f1 if not specified otherwise
-        if not containsF:
-            jmhArgs += ['-f1']
-
         # find all projects with a direct JMH dependency
         jmhProjects = []
         for p in mx.projects_opt_limit_to_suites():
@@ -237,6 +231,15 @@
                         out = None
                     run_vm(self.args + _noneAsEmptyList(extraVMarguments) + ['-XX:-TieredCompilation', '-XX:+BootstrapJVMCI', '-version'], out=out)
 
+class MicrobenchRun:
+    def __init__(self, name, args):
+        self.name = name
+        self.args = args
+
+    def run(self, tasks, extraVMarguments=None):
+        with Task(self.name + ': hosted-product ', tasks) as t:
+            if t: microbench(_noneAsEmptyList(extraVMarguments) + ['--'] + self.args)
+
 def compiler_gate_runner(suites, unit_test_runs, bootstrap_tests, tasks, extraVMarguments=None):
 
     # Build server-hosted-jvmci now so we can run the unit tests
@@ -248,6 +251,11 @@
         for r in unit_test_runs:
             r.run(suites, tasks, extraVMarguments)
 
+    # Run microbench on server-hosted-jvmci (only for testing the JMH setup)
+    with VM('server', 'product'):
+        for r in [MicrobenchRun('Microbench', ['TestJMH'])]:
+            r.run(tasks, extraVMarguments)
+
     # Run ctw against rt.jar on server-hosted-jvmci
     with VM('server', 'product'):
         with Task('CTW:hosted-product', tasks) as t:
@@ -289,8 +297,8 @@
 graal_bootstrap_tests = [
     BootstrapTest('BootstrapWithSystemAssertions', 'fastdebug', ['-esa']),
     BootstrapTest('BootstrapWithSystemAssertionsNoCoop', 'fastdebug', ['-esa', '-XX:-UseCompressedOops', '-G:+ExitVMOnException']),
-    BootstrapTest('BootstrapWithGCVecification', 'product', ['-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-G:+ExitVMOnException'], suppress=['VerifyAfterGC:', 'VerifyBeforeGC:']),
-    BootstrapTest('BootstrapWithG1GCVecification', 'product', ['-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-G:+ExitVMOnException'], suppress=['VerifyAfterGC:', 'VerifyBeforeGC:']),
+    BootstrapTest('BootstrapWithGCVerification', 'product', ['-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-G:+ExitVMOnException'], suppress=['VerifyAfterGC:', 'VerifyBeforeGC:']),
+    BootstrapTest('BootstrapWithG1GCVerification', 'product', ['-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-G:+ExitVMOnException'], suppress=['VerifyAfterGC:', 'VerifyBeforeGC:']),
     BootstrapTest('BootstrapEconomyWithSystemAssertions', 'fastdebug', ['-esa', '-Djvmci.compiler=graal-economy', '-G:+ExitVMOnException']),
     BootstrapTest('BootstrapWithExceptionEdges', 'fastdebug', ['-esa', '-G:+StressInvokeWithExceptionNode', '-G:+ExitVMOnException']),
     BootstrapTest('BootstrapWithRegisterPressure', 'product', ['-esa', '-G:RegisterPressure=' + _registers, '-G:+ExitVMOnException']),
--- a/mx.graal/mx_graal_9.py	Tue Dec 08 12:29:24 2015 -0800
+++ b/mx.graal/mx_graal_9.py	Tue Dec 08 12:30:15 2015 -0800
@@ -127,12 +127,10 @@
     vmArgs, jmhArgs = mx.extract_VM_args(args, useDoubleDash=True)
 
     # look for -f in JMH arguments
-    containsF = False
     forking = True
     for i in range(len(jmhArgs)):
         arg = jmhArgs[i]
         if arg.startswith('-f'):
-            containsF = True
             if arg == '-f' and (i+1) < len(jmhArgs):
                 arg += jmhArgs[i+1]
             try:
@@ -147,10 +145,6 @@
         if not forking:
             args += vmArgs
     else:
-        # default to -f1 if not specified otherwise
-        if not containsF:
-            jmhArgs += ['-f1']
-
         # find all projects with a direct JMH dependency
         jmhProjects = []
         for p in mx.projects_opt_limit_to_suites():
@@ -235,6 +229,15 @@
                         out = None
                     run_vm(self.args + _noneAsEmptyList(extraVMarguments) + ['-XX:-TieredCompilation', '-XX:+BootstrapJVMCI', '-version'], out=out)
 
+class MicrobenchRun:
+    def __init__(self, name, args):
+        self.name = name
+        self.args = args
+
+    def run(self, tasks, extraVMarguments=None):
+        with Task(self.name + ': hosted-product ', tasks) as t:
+            if t: microbench(_noneAsEmptyList(extraVMarguments) + ['--'] + self.args)
+
 def compiler_gate_runner(suites, unit_test_runs, bootstrap_tests, tasks, extraVMarguments=None):
 
     # Run unit tests in hosted mode
@@ -242,6 +245,11 @@
         for r in unit_test_runs:
             r.run(suites, tasks, extraVMarguments)
 
+    # Run microbench in hosted mode (only for testing the JMH setup)
+    with JVMCIMode('hosted'):
+        for r in [MicrobenchRun('Microbench', ['TestJMH'])]:
+            r.run(tasks, extraVMarguments)
+
     # Run ctw against rt.jar on server-hosted-jvmci
     with JVMCIMode('hosted'):
         with Task('CTW:hosted', tasks) as t:
@@ -278,8 +286,8 @@
 graal_bootstrap_tests = [
     BootstrapTest('BootstrapWithSystemAssertions', 'fastdebug', ['-esa']),
     BootstrapTest('BootstrapWithSystemAssertionsNoCoop', 'fastdebug', ['-esa', '-XX:-UseCompressedOops', '-G:+ExitVMOnException']),
-    BootstrapTest('BootstrapWithGCVecification', 'product', ['-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-G:+ExitVMOnException'], suppress=['VerifyAfterGC:', 'VerifyBeforeGC:']),
-    BootstrapTest('BootstrapWithG1GCVecification', 'product', ['-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-G:+ExitVMOnException'], suppress=['VerifyAfterGC:', 'VerifyBeforeGC:']),
+    BootstrapTest('BootstrapWithGCVerification', 'product', ['-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-G:+ExitVMOnException'], suppress=['VerifyAfterGC:', 'VerifyBeforeGC:']),
+    BootstrapTest('BootstrapWithG1GCVerification', 'product', ['-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-G:+ExitVMOnException'], suppress=['VerifyAfterGC:', 'VerifyBeforeGC:']),
     BootstrapTest('BootstrapEconomyWithSystemAssertions', 'fastdebug', ['-esa', '-Djvmci.compiler=graal-economy', '-G:+ExitVMOnException']),
     BootstrapTest('BootstrapWithExceptionEdges', 'fastdebug', ['-esa', '-G:+StressInvokeWithExceptionNode', '-G:+ExitVMOnException']),
     BootstrapTest('BootstrapWithRegisterPressure', 'product', ['-esa', '-G:RegisterPressure=' + _registers, '-G:+ExitVMOnException']),
--- a/mx.graal/suite.py	Tue Dec 08 12:29:24 2015 -0800
+++ b/mx.graal/suite.py	Tue Dec 08 12:30:15 2015 -0800
@@ -39,7 +39,7 @@
             {
                "name" : "jvmci",
                "optional" : "true",
-               "version" : "2dea101cdfe9aacf55083cf5bd6f84cb23106f4e",
+               "version" : "9ed36a1fec521a62bd9fdccec022c78cf2599244",
                "urls" : [
                     {"url" : "http://lafo.ssw.uni-linz.ac.at/hg/graal-jvmci-8", "kind" : "hg"},
                     {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"},
@@ -47,7 +47,7 @@
             },
             {
                "name" : "truffle",
-               "version" : "fd53ccebb10b21af953de2da4340a7d17b85e5ed",
+               "version" : "bc1e026ef5b1ab8a1f68a3e78437e48f2d91fd91",
                "urls" : [
                     {"url" : "http://lafo.ssw.uni-linz.ac.at/hg/truffle", "kind" : "hg"},
                     {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"},
@@ -85,18 +85,18 @@
     },
 
     "JMH" : {
-      "sha1" : "be2e08e6776191e9c559a65b7d34e92e86b4fa5c",
-      "urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/jmh/jmh-runner-1.10.4.jar"],
+      "sha1" : "0fe92ac8718909c632345d4ecb4e596d1fa40071",
+      "urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/jmh/jmh-runner-1.11.2.jar"],
     },
 
     # Library that allows Graal to compile against JVMCI without the jvmci suite.
     # This library is not added to the boot class path at run time and so code
     # compiled against this library must be run on (JVMCI enabled) JDK9.
     "JVMCI" : {
-        "sha1" : "9482b9ba7760c09cd95d78f08ce28171b4081268",
-        "urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/jvmci-1648ffb0158e.jar"],
-        "sourceSha1" : "b34c184cb1d383aec07bcadefadff01543f10222",
-        "sourceUrls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/jvmci-1648ffb0158e.src.zip"],
+        "sha1" : "31c6bb33db89e7863d716641518bb6997fe2d340",
+        "urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/jvmci-7a570929c5e5.jar"],
+        "sourceSha1" : "8020f243ce1d5453c7a3b9f2bba52ad69ce689b4",
+        "sourceUrls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/jvmci-7a570929c5e5.src.zip"],
         "license": "GPLv2-CPE",
      },
   }),
@@ -518,6 +518,7 @@
       "javaCompliance" : "1.8",
       "annotationProcessors" : [
         "GRAAL_NODEINFO_PROCESSOR",
+        "GRAAL_REPLACEMENTS_VERIFIER",
       ],
       "workingSets" : "Graal,Replacements,AMD64",
     },
@@ -541,7 +542,10 @@
         "com.oracle.graal.compiler.test",
         "com.oracle.graal.replacements",
       ],
-      "annotationProcessors" : ["GRAAL_NODEINFO_PROCESSOR"],
+      "annotationProcessors" : [
+        "GRAAL_NODEINFO_PROCESSOR",
+        "GRAAL_REPLACEMENTS_VERIFIER"
+      ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,Replacements,Test",
@@ -639,7 +643,7 @@
     "com.oracle.graal.virtual.bench" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
-      "dependencies" : ["JMH"],
+      "dependencies" : ["JMH", "com.oracle.graal.microbenchmarks"],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "annotationProcessors" : ["JMH"],
@@ -784,7 +788,6 @@
       "sourceDirs" : ["src"],
       "dependencies" : [
         "com.oracle.graal.phases",
-        "com.oracle.graal.graphbuilderconf",
       ],
       "annotationProcessors" : deps(["jvmci:JVMCI_OPTIONS_PROCESSOR"]),
       "checkstyle" : "com.oracle.graal.graph",
@@ -792,17 +795,6 @@
       "workingSets" : "Graal,Java",
     },
 
-    "com.oracle.graal.graphbuilderconf" : {
-      "subDir" : "graal",
-      "sourceDirs" : ["src"],
-      "dependencies" : [
-        "com.oracle.graal.nodes",
-      ],
-      "checkstyle" : "com.oracle.graal.graph",
-      "javaCompliance" : "1.8",
-      "workingSets" : "Graal,Java",
-    },
-
     "com.oracle.graal.compiler.common" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
@@ -1123,9 +1115,10 @@
     "GRAAL_REPLACEMENTS_VERIFIER" : {
       "subDir" : "graal",
       "dependencies" : ["com.oracle.graal.replacements.verifier"],
-      "distDependencies" : [
+      "distDependencies" : deps([
         "GRAAL_API",
-      ],
+        "jvmci:JVMCI_SERVICE_PROCESSOR",
+      ])
     },
 
     "GRAAL_COMPILER_MATCH_PROCESSOR" : {