changeset 21298:7e72615e0441

Merge
author Tom Rodriguez <tom.rodriguez@oracle.com>
date Mon, 11 May 2015 17:56:16 -0700
parents bea2f27524ba (current diff) 8eadc82f4a93 (diff)
children 21993236a219
files graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java
diffstat 37 files changed, 624 insertions(+), 527 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java	Mon May 11 17:56:16 2015 -0700
@@ -294,6 +294,9 @@
      */
     public static StringBuilder append(StringBuilder sb, BytecodeFrame frame) {
         MetaUtil.appendLocation(sb.append("at "), frame.getMethod(), frame.getBCI());
+        assert sb.charAt(sb.length() - 1) == ']';
+        sb.deleteCharAt(sb.length() - 1);
+        sb.append(", duringCall: ").append(frame.duringCall).append(", rethrow: ").append(frame.rethrowException).append(']');
         if (frame.values != null && frame.values.length > 0) {
             sb.append(NEW_LINE);
             String table = tabulateValues(frame);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Mon May 11 17:56:16 2015 -0700
@@ -23,12 +23,14 @@
 package com.oracle.graal.compiler.test.ea;
 
 import java.lang.ref.*;
+
 import org.junit.*;
 
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.common.*;
@@ -191,6 +193,23 @@
         assertTrue(graph.getNodes().filter(ReturnNode.class).first().result() == graph.getParameter(0));
     }
 
+    public static int testBoxLoopSnippet(int n) {
+        Integer sum = 0;
+        for (Integer i = 0; i < n; i++) {
+            if (sum == null) {
+                sum = null;
+            } else {
+                sum += i;
+            }
+        }
+        return sum;
+    }
+
+    @Test
+    public void testBoxLoop() {
+        testPartialEscapeAnalysis("testBoxLoopSnippet", 0, 0, BoxNode.class, UnboxNode.class);
+    }
+
     @SafeVarargs
     protected final void testPartialEscapeAnalysis(String snippet, double expectedProbability, int expectedCount, Class<? extends Node>... invalidNodeClasses) {
         prepareGraph(snippet, false);
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Mon May 11 17:56:16 2015 -0700
@@ -115,8 +115,8 @@
         T equivalentValue = append(value);
         if (equivalentValue instanceof StateSplit) {
             StateSplit stateSplit = (StateSplit) equivalentValue;
-            if (stateSplit.stateAfter() == null) {
-                stateSplit.setStateAfter(createStateAfter());
+            if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
+                setStateAfter(stateSplit);
             }
         }
         return equivalentValue;
@@ -149,8 +149,8 @@
         push(kind.getStackKind(), equivalentValue);
         if (equivalentValue instanceof StateSplit) {
             StateSplit stateSplit = (StateSplit) equivalentValue;
-            if (stateSplit.stateAfter() == null) {
-                stateSplit.setStateAfter(createStateAfter());
+            if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
+                setStateAfter(stateSplit);
             }
         }
         return equivalentValue;
@@ -194,9 +194,12 @@
 
     /**
      * Creates a snap shot of the current frame state with the BCI of the instruction after the one
-     * currently being parsed.
+     * 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
      */
-    FrameState createStateAfter();
+    void setStateAfter(StateSplit sideEffect);
 
     /**
      * Gets the parsing context for the method that inlines the method being parsed by this context.
@@ -204,6 +207,18 @@
     GraphBuilderContext getParent();
 
     /**
+     * Gets the first ancestor parsing context that is not parsing a
+     * {@linkplain #parsingReplacement() replacement}.
+     */
+    default GraphBuilderContext getNonReplacementAncestor() {
+        GraphBuilderContext ancestor = getParent();
+        while (ancestor != null && ancestor.parsingReplacement()) {
+            ancestor = ancestor.getParent();
+        }
+        return ancestor;
+    }
+
+    /**
      * Gets the method currently being parsed.
      */
     ResolvedJavaMethod getMethod();
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java	Mon May 11 17:56:16 2015 -0700
@@ -26,8 +26,9 @@
 import com.oracle.graal.nodes.*;
 
 /**
- * Plugin for specifying what is inlined during graph parsing or for post-processing non-inlined
- * invocations that result in {@link Invoke} nodes.
+ * Plugin for specifying what is inlined during graph parsing. This plugin is also
+ * {@linkplain #notifyOfNoninlinedInvoke notified} of non-inlined invocations (i.e., those for which
+ * an {@link Invoke} node is created).
  */
 public interface InlineInvokePlugin extends GraphBuilderPlugin {
 
@@ -46,9 +47,7 @@
         public final boolean isReplacement;
 
         /**
-         * Specifies if {@link #methodToInline} is an intrinsic for the original method. If so, any
-         * {@link StateSplit} node created in the (recursive) inlining scope will be given a frame
-         * state that restarts the interpreter just before the intrinsified invocation.
+         * Specifies if {@link #methodToInline} is an intrinsic for the original method.
          */
         public final boolean isIntrinsic;
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Mon May 11 17:56:16 2015 -0700
@@ -132,7 +132,7 @@
                     StructuredGraph graph = new StructuredGraph(substMethod, AllowAssumptions.YES);
                     Plugins plugins = new Plugins(((HotSpotProviders) getProviders()).getGraphBuilderPlugins());
                     GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
-                    IntrinsicContext initialReplacementContext = new IntrinsicContext(installedCodeOwner, substMethod, null, ROOT_COMPILATION_BCI);
+                    IntrinsicContext initialReplacementContext = new IntrinsicContext(installedCodeOwner, substMethod, ROOT_COMPILATION_BCI);
                     new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(graph);
                     Assert.assertNotNull(getCode(installedCodeOwner, graph, true));
                     atLeastOneCompiled = true;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Mon May 11 17:56:16 2015 -0700
@@ -305,7 +305,7 @@
                 }
                 if (excludeMethodFilters != null && excludeMethodFilters.length > 0) {
                     String exclude = Arrays.asList(excludeMethodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", "));
-                    println("CompileTheWorld : Excluding all methods matching one of the follwing filters: " + exclude);
+                    println("CompileTheWorld : Excluding all methods matching one of the following filters: " + exclude);
                 }
                 println();
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Mon May 11 17:56:16 2015 -0700
@@ -35,7 +35,6 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
 
 /**
@@ -314,7 +313,7 @@
         ResolvedJavaMethod initMethod = null;
         try {
             Class<?> rjm = ResolvedJavaMethod.class;
-            makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm, FrameStateProcessing.class));
+            makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm));
             initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class));
         } catch (NoSuchMethodException | SecurityException e) {
             throw new GraalInternalError(e);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Mon May 11 17:56:16 2015 -0700
@@ -119,7 +119,7 @@
      * for equality.
      */
     private boolean appendGraphEncoderTest(PhaseSuite<HighTierContext> suite) {
-        suite.appendPhase(new BasePhase<HighTierContext>() {
+        suite.appendPhase(new BasePhase<HighTierContext>("VerifyEncodingDecoding") {
             @Override
             protected void run(StructuredGraph graph, HighTierContext context) {
                 EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, runtime.getTarget().arch);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Mon May 11 17:56:16 2015 -0700
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
+import static com.oracle.graal.java.IntrinsicContext.*;
+
 import java.lang.reflect.*;
 
 import com.oracle.graal.api.meta.*;
@@ -94,7 +96,7 @@
 
         assert SnippetGraphUnderConstruction.get() == null;
         SnippetGraphUnderConstruction.set(graph);
-        ReplacementContext initialReplacementContext = new ReplacementContext(method, method);
+        ReplacementContext initialReplacementContext = new IntrinsicContext(method, method, POST_PARSE_INLINE_BCI);
         new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(graph);
         SnippetGraphUnderConstruction.set(null);
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon May 11 17:56:16 2015 -0700
@@ -52,6 +52,7 @@
 import com.oracle.graal.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock;
+import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
@@ -84,6 +85,87 @@
         return graphBuilderConfig;
     }
 
+    static class ReplacementScope implements AutoCloseable {
+        FrameState stateBefore;
+        final Mark mark;
+        final BytecodeParser parser;
+
+        static ReplacementScope create(boolean enteringReplacement, BytecodeParser parser, HIRFrameStateBuilder currentFrameState, ValueNode[] args) {
+            if (enteringReplacement) {
+                return new ReplacementScope(parser, currentFrameState, args);
+            }
+            return null;
+        }
+
+        public ReplacementScope(BytecodeParser parser, HIRFrameStateBuilder currentFrameState, ValueNode[] args) {
+            this.parser = parser;
+            if (args == null) {
+                assert parser.parent == null;
+                assert parser.bci() == 0;
+                mark = null;
+            } else {
+                mark = parser.getGraph().getMark();
+                for (ValueNode arg : args) {
+                    currentFrameState.push(arg.getKind(), arg);
+                }
+                stateBefore = currentFrameState.create(parser.bci(), null);
+                for (int i = args.length - 1; i >= 0; i--) {
+                    ValueNode arg = args[i];
+                    currentFrameState.pop(arg.getKind());
+                }
+            }
+        }
+
+        public void close() {
+            IntrinsicContext intrinsic = (IntrinsicContext) parser.replacementContext;
+            if (intrinsic != null && intrinsic.isPostParseInlined()) {
+                return;
+            }
+
+            FrameState stateAfterReturn = null;
+            StructuredGraph graph = parser.getGraph();
+            for (Node node : graph.getNewNodes(mark)) {
+                if (node instanceof FrameState) {
+                    FrameState fs = (FrameState) node;
+                    if (BytecodeFrame.isPlaceholderBci(fs.bci)) {
+                        if (fs.bci == BytecodeFrame.AFTER_BCI) {
+                            if (fs.stackSize() != 0) {
+                                assert fs.usages().count() == 1;
+                                ValueNode returnVal = fs.stackAt(0);
+                                assert returnVal == fs.usages().first();
+
+                                ValueNode tos = parser.frameState.pop(returnVal.getKind());
+                                parser.frameState.push(returnVal.getKind(), returnVal);
+                                FrameState newFs = parser.frameState.create(parser.stream.nextBCI(), null);
+                                fs.replaceAndDelete(newFs);
+                                parser.frameState.pop(returnVal.getKind());
+                                parser.frameState.push(tos.getKind(), tos);
+                            } else {
+                                if (stateAfterReturn == null) {
+                                    if (intrinsic != null && intrinsic.isCompilationRoot()) {
+                                        stateAfterReturn = graph.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI));
+                                    } else {
+                                        stateAfterReturn = parser.frameState.create(parser.stream.nextBCI(), null);
+                                    }
+                                }
+                                fs.replaceAndDelete(stateAfterReturn);
+                            }
+                        } else if (fs.bci == BytecodeFrame.BEFORE_BCI) {
+                            if (stateBefore == null) {
+                                stateBefore = graph.start().stateAfter();
+                            }
+                            if (stateBefore != fs) {
+                                fs.replaceAndDelete(stateBefore);
+                            }
+                        } else {
+                            assert fs.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     // Fully qualified name is a workaround for JDK-8056066
     public static class Instance extends com.oracle.graal.phases.Phase {
 
@@ -123,8 +205,10 @@
                 HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(parser, method, graph);
 
                 frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || replacementContext != null, graphBuilderConfig.getPlugins().getParameterPlugin());
-                parser.build(graph.start(), frameState);
 
+                try (ReplacementScope rs = ReplacementScope.create(replacementContext != null, parser, frameState, null)) {
+                    parser.build(graph.start(), frameState);
+                }
                 GraphUtil.normalizeLoops(graph);
 
                 // Remove dead parameters.
@@ -327,17 +411,27 @@
                     if (startInstruction == graph.start()) {
                         StartNode startNode = graph.start();
                         if (method.isSynchronized()) {
-                            startNode.setStateAfter(createFrameState(BytecodeFrame.BEFORE_BCI));
+                            assert !parsingReplacement();
+                            startNode.setStateAfter(createFrameState(BytecodeFrame.BEFORE_BCI, startNode));
                         } else {
-
-                            if (graph.method() != null && graph.method().isJavaLangObjectInit()) {
-                                // Don't clear the receiver when Object.<init> is the compilation
-                                // root. The receiver is needed as input to RegisterFinalizerNode.
+                            if (!parsingReplacement()) {
+                                if (graph.method() != null && graph.method().isJavaLangObjectInit()) {
+                                    /*
+                                     * Don't clear the receiver when Object.<init> is the
+                                     * compilation root. The receiver is needed as input to
+                                     * RegisterFinalizerNode.
+                                     */
+                                } else {
+                                    frameState.clearNonLiveLocals(startBlock, liveness, true);
+                                }
+                                assert bci() == 0;
+                                startNode.setStateAfter(createFrameState(bci(), startNode));
                             } else {
-                                frameState.clearNonLiveLocals(startBlock, liveness, true);
+                                if (startNode.stateAfter() == null) {
+                                    FrameState stateAfterStart = createStateAfterStartOfReplacementGraph();
+                                    startNode.setStateAfter(stateAfterStart);
+                                }
                             }
-                            assert bci() == 0;
-                            startNode.setStateAfter(createFrameState(bci()));
                         }
                     }
 
@@ -379,6 +473,42 @@
                 }
             }
 
+            /**
+             * Creates the frame state after the start node of a graph for a
+             * {@link ReplacementContext replacement} that is the parse root (either for root
+             * compiling or for post-parse inlining).
+             */
+            private FrameState createStateAfterStartOfReplacementGraph() {
+                assert parent == null;
+                assert frameState.method.equals(replacementContext.replacement);
+                assert bci() == 0;
+                assert frameState.stackSize == 0;
+                FrameState stateAfterStart;
+                if (replacementContext.isIntrinsic() && replacementContext.asIntrinsic().isPostParseInlined()) {
+                    stateAfterStart = graph.add(new FrameState(BytecodeFrame.BEFORE_BCI));
+                } else {
+                    ResolvedJavaMethod original = replacementContext.method;
+                    ValueNode[] locals;
+                    if (original.getMaxLocals() == frameState.localsSize() || original.isNative()) {
+                        locals = frameState.locals;
+                    } else {
+                        locals = new ValueNode[original.getMaxLocals()];
+                        int parameterCount = original.getSignature().getParameterCount(!original.isStatic());
+                        for (int i = 0; i < parameterCount; i++) {
+                            ValueNode param = frameState.locals[i];
+                            locals[i] = param;
+                            assert param == null || param instanceof ParameterNode || param.isConstant();
+                        }
+                    }
+                    ValueNode[] stack = {};
+                    int stackSize = 0;
+                    ValueNode[] locks = {};
+                    List<MonitorIdNode> monitorIds = Collections.emptyList();
+                    stateAfterStart = graph.add(new FrameState(null, original, 0, locals, stack, stackSize, locks, monitorIds, false, false));
+                }
+                return stateAfterStart;
+            }
+
             private void detectLoops(FixedNode startInstruction) {
                 NodeBitMap visited = graph.createNodeBitMap();
                 NodeBitMap active = graph.createNodeBitMap();
@@ -735,11 +865,11 @@
                     dispatchBegin = graph.add(new ExceptionObjectNode(metaAccess));
                     dispatchState.apush(dispatchBegin);
                     dispatchState.setRethrowException(true);
-                    dispatchBegin.setStateAfter(dispatchState.create(bci));
+                    dispatchBegin.setStateAfter(dispatchState.create(bci, dispatchBegin));
                 } else {
                     dispatchBegin = graph.add(new DispatchBeginNode());
                     dispatchState.apush(exceptionObject);
-                    dispatchBegin.setStateAfter(dispatchState.create(bci));
+                    dispatchBegin.setStateAfter(dispatchState.create(bci, dispatchBegin));
                     dispatchState.setRethrowException(true);
                 }
                 this.controlFlowSplit = true;
@@ -953,7 +1083,7 @@
                 append(new IfNode(graph.unique(new IsNullNode(receiver)), exception, falseSucc, 0.01));
                 lastInstr = falseSucc;
 
-                exception.setStateAfter(createFrameState(bci()));
+                exception.setStateAfter(createFrameState(bci(), exception));
                 exception.setNext(handleException(exception, bci()));
                 return nonNullReceiver;
             }
@@ -965,7 +1095,7 @@
                 append(new IfNode(graph.unique(IntegerBelowNode.create(index, length, constantReflection)), trueSucc, exception, 0.99));
                 lastInstr = trueSucc;
 
-                exception.setStateAfter(createFrameState(bci()));
+                exception.setStateAfter(createFrameState(bci(), exception));
                 exception.setNext(handleException(exception, bci()));
             }
 
@@ -978,7 +1108,7 @@
             protected void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value) {
                 StoreFieldNode storeFieldNode = new StoreFieldNode(receiver, field, value);
                 append(storeFieldNode);
-                storeFieldNode.setStateAfter(this.createFrameState(stream.nextBCI()));
+                storeFieldNode.setStateAfter(this.createFrameState(stream.nextBCI(), storeFieldNode));
             }
 
             /**
@@ -1217,8 +1347,8 @@
                         for (Node n : newNodes) {
                             if (n instanceof StateSplit) {
                                 StateSplit stateSplit = (StateSplit) n;
-                                assert stateSplit.stateAfter() != null : error("%s node added by plugin for %s need to have a non-null frame state: %s", StateSplit.class.getSimpleName(),
-                                                targetMethod.format("%H.%n(%p)"), stateSplit);
+                                assert stateSplit.stateAfter() != null || !stateSplit.hasSideEffect() : error("%s node added by plugin for %s need to have a non-null frame state: %s",
+                                                StateSplit.class.getSimpleName(), targetMethod.format("%H.%n(%p)"), stateSplit);
                             }
                         }
                         try {
@@ -1294,14 +1424,18 @@
                     if (intrinsic != null) {
                         if (intrinsic.isCompilationRoot()) {
                             // A root compiled intrinsic needs to deoptimize
-                            // if the slow path is taken
-                            DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint));
-                            deopt.setStateBefore(intrinsic.getInvokeStateBefore(graph, null));
+                            // if the slow path is taken. During frame state
+                            // assignment, the deopt node will get its stateBefore
+                            // from the start node of the intrinsic
+                            append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint));
                             return true;
                         } else {
                             // Otherwise inline the original method. Any frame state created
                             // during the inlining will exclude frame(s) in the
                             // intrinsic method (see HIRFrameStateBuilder.create(int bci)).
+                            if (context.method.isNative()) {
+                                return false;
+                            }
                             parseAndInlineCallee(context.method, args, null);
                             return true;
                         }
@@ -1319,8 +1453,9 @@
                     if (context == null && isReplacement) {
                         assert !inlinedMethod.equals(targetMethod);
                         if (isIntrinsic) {
-                            context = new IntrinsicContext(targetMethod, inlinedMethod, args, bci);
+                            context = new IntrinsicContext(targetMethod, inlinedMethod, bci);
                         } else {
+                            assert false;
                             context = new ReplacementContext(targetMethod, inlinedMethod);
                         }
                     }
@@ -1370,33 +1505,37 @@
             }
 
             private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, ReplacementContext calleeReplacementContext) {
-                BytecodeParser parser = new BytecodeParser(this, metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, calleeReplacementContext);
-                HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(parser, targetMethod, graph);
-                if (!targetMethod.isStatic()) {
-                    args[0] = nullCheckedValue(args[0]);
-                }
-                startFrameState.initializeFromArgumentsArray(args);
-                parser.build(this.lastInstr, startFrameState);
+                try (ReplacementScope rs = ReplacementScope.create(calleeReplacementContext != null && !parsingReplacement(), this, frameState, args)) {
+
+                    BytecodeParser parser = new BytecodeParser(this, metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, calleeReplacementContext);
+                    HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(parser, targetMethod, graph);
+                    if (!targetMethod.isStatic()) {
+                        args[0] = nullCheckedValue(args[0]);
+                    }
+                    startFrameState.initializeFromArgumentsArray(args);
+                    parser.build(this.lastInstr, startFrameState);
 
-                FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode();
-                this.lastInstr = calleeBeforeReturnNode;
-                if (calleeBeforeReturnNode != null) {
-                    ValueNode calleeReturnValue = parser.getReturnValue();
-                    if (calleeReturnValue != null) {
-                        frameState.push(targetMethod.getSignature().getReturnKind().getStackKind(), calleeReturnValue);
+                    FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode();
+                    this.lastInstr = calleeBeforeReturnNode;
+                    Kind calleeReturnKind = targetMethod.getSignature().getReturnKind();
+                    if (calleeBeforeReturnNode != null) {
+                        ValueNode calleeReturnValue = parser.getReturnValue();
+                        if (calleeReturnValue != null) {
+                            frameState.push(calleeReturnKind.getStackKind(), calleeReturnValue);
+                        }
                     }
-                }
 
-                FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode();
-                if (calleeBeforeUnwindNode != null) {
-                    ValueNode calleeUnwindValue = parser.getUnwindValue();
-                    assert calleeUnwindValue != null;
-                    calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci()));
-                }
+                    FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode();
+                    if (calleeBeforeUnwindNode != null) {
+                        ValueNode calleeUnwindValue = parser.getUnwindValue();
+                        assert calleeUnwindValue != null;
+                        calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci()));
+                    }
 
-                // Record inlined method dependency in the graph
-                if (graph.isInlinedMethodRecordingEnabled()) {
-                    graph.getInlinedMethods().add(targetMethod);
+                    // Record inlined method dependency in the graph
+                    if (graph.isInlinedMethodRecordingEnabled()) {
+                        graph.getInlinedMethods().add(targetMethod);
+                    }
                 }
             }
 
@@ -1407,7 +1546,7 @@
             protected InvokeNode createInvoke(CallTargetNode callTarget, Kind resultType) {
                 InvokeNode invoke = append(new InvokeNode(callTarget, bci()));
                 frameState.pushReturn(resultType, invoke);
-                invoke.setStateAfter(createFrameState(stream.nextBCI()));
+                invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke));
                 return invoke;
             }
 
@@ -1415,13 +1554,35 @@
                 DispatchBeginNode exceptionEdge = handleException(null, bci());
                 InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci()));
                 frameState.pushReturn(resultType, invoke);
-                invoke.setStateAfter(createFrameState(stream.nextBCI()));
+                invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke));
                 return invoke;
             }
 
             @Override
             protected void genReturn(ValueNode returnVal, Kind returnKind) {
-
+                if (parsingReplacement() && returnVal != null) {
+                    if (returnVal instanceof StateSplit) {
+                        StateSplit stateSplit = (StateSplit) returnVal;
+                        FrameState stateAfter = stateSplit.stateAfter();
+                        if (stateSplit.hasSideEffect()) {
+                            assert stateSplit != null;
+                            if (stateAfter.bci == BytecodeFrame.AFTER_BCI) {
+                                assert stateAfter.usages().count() == 1;
+                                assert stateAfter.usages().first() == stateSplit;
+                                stateAfter.replaceAtUsages(graph.add(new FrameState(BytecodeFrame.AFTER_BCI, returnVal)));
+                                GraphUtil.killWithUnusedFloatingInputs(stateAfter);
+                            } else {
+                                /*
+                                 * This must be the return value from within a partial
+                                 * intrinsification.
+                                 */
+                                assert !BytecodeFrame.isPlaceholderBci(stateAfter.bci);
+                            }
+                        } else {
+                            assert stateAfter == null;
+                        }
+                    }
+                }
                 if (parent == null) {
                     frameState.setRethrowException(false);
                     frameState.clearStack();
@@ -1465,7 +1626,7 @@
                 MonitorIdNode monitorId = graph.add(new MonitorIdNode(frameState.lockDepth()));
                 MonitorEnterNode monitorEnter = append(new MonitorEnterNode(x, monitorId));
                 frameState.pushLock(x, monitorId);
-                monitorEnter.setStateAfter(createFrameState(bci));
+                monitorEnter.setStateAfter(createFrameState(bci, monitorEnter));
             }
 
             @Override
@@ -1476,7 +1637,7 @@
                     throw bailout(String.format("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject)));
                 }
                 MonitorExitNode monitorExit = append(new MonitorExitNode(x, monitorId, escapedReturnValue));
-                monitorExit.setStateAfter(createFrameState(bci));
+                monitorExit.setStateAfter(createFrameState(bci, monitorExit));
             }
 
             @Override
@@ -1627,7 +1788,7 @@
                             lastLoopExit = loopExit;
                             Debug.log("Target %s Exits %s, scanning framestates...", targetBlock, loop);
                             newState.insertLoopProxies(loopExit, getEntryState(loop, this.getCurrentDimension()));
-                            loopExit.setStateAfter(newState.create(bci));
+                            loopExit.setStateAfter(newState.create(bci, loopExit));
                         }
 
                         lastLoopExit.setNext(target);
@@ -1972,7 +2133,7 @@
                     if (block instanceof ExceptionDispatchBlock) {
                         bci = ((ExceptionDispatchBlock) block).deoptBci;
                     }
-                    abstractMergeNode.setStateAfter(createFrameState(bci));
+                    abstractMergeNode.setStateAfter(createFrameState(bci, abstractMergeNode));
                 }
             }
 
@@ -2055,7 +2216,7 @@
 
                     // Create phi functions for all local variables and operand stack slots.
                     frameState.insertLoopPhis(liveness, block.loopId, loopBegin);
-                    loopBegin.setStateAfter(createFrameState(block.startBci));
+                    loopBegin.setStateAfter(createFrameState(block.startBci, loopBegin));
 
                     /*
                      * We have seen all forward branches. All subsequent backward branches will
@@ -2108,7 +2269,7 @@
                         }
                         EntryMarkerNode x = append(new EntryMarkerNode());
                         frameState.insertProxies(x);
-                        x.setStateAfter(createFrameState(bci));
+                        x.setStateAfter(createFrameState(bci, x));
                     }
 
                     try {
@@ -2125,7 +2286,7 @@
                     bci = stream.currentBCI();
 
                     assert block == currentBlock;
-                    assert !(lastInstr instanceof StateSplit) || lastInstr instanceof BeginNode || ((StateSplit) lastInstr).stateAfter() != null : lastInstr;
+                    assert checkLastInstruction();
                     lastInstr = finishInstruction(lastInstr, frameState);
                     if (bci < endBCI) {
                         if (bci > block.endBci) {
@@ -2139,6 +2300,18 @@
                 }
             }
 
+            protected boolean checkLastInstruction() {
+                if (lastInstr instanceof BeginNode) {
+                    // ignore
+                } else if (lastInstr instanceof StateSplit) {
+                    StateSplit stateSplit = (StateSplit) lastInstr;
+                    if (stateSplit.hasSideEffect()) {
+                        assert stateSplit.stateAfter() != null : "side effect " + lastInstr + " requires a non-null stateAfter";
+                    }
+                }
+                return true;
+            }
+
             private LoopBeginNode appendLoopBegin(FixedWithNextNode fixedWithNext) {
                 EndNode preLoopEnd = graph.add(new EndNode());
                 LoopBeginNode loopBegin = graph.add(new LoopBeginNode());
@@ -2161,7 +2334,7 @@
 
             private InfopointNode createInfoPointNode(InfopointReason reason) {
                 if (graphBuilderConfig.insertFullDebugInfo()) {
-                    return new FullInfopointNode(reason, createFrameState(bci()));
+                    return new FullInfopointNode(reason, createFrameState(bci(), null));
                 } else {
                     BytecodePosition position = createBytecodePosition();
                     // Update the previous infopoint position if no new fixed nodes were inserted
@@ -2423,21 +2596,23 @@
             }
 
             public BailoutException bailout(String string) {
-                FrameState currentFrameState = createFrameState(bci());
+                FrameState currentFrameState = createFrameState(bci(), null);
                 StackTraceElement[] elements = GraphUtil.approxSourceStackTraceElement(currentFrameState);
                 BailoutException bailout = new BailoutException(string);
                 throw GraphUtil.createBailoutException(string, bailout, elements);
             }
 
-            private FrameState createFrameState(int bci) {
+            private FrameState createFrameState(int bci, StateSplit forStateSplit) {
                 if (currentBlock != null && bci > currentBlock.endBci) {
                     frameState.clearNonLiveLocals(currentBlock, liveness, false);
                 }
-                return frameState.create(bci);
+                return frameState.create(bci, forStateSplit);
             }
 
-            public FrameState createStateAfter() {
-                return createFrameState(stream.nextBCI());
+            public void setStateAfter(StateSplit sideEffect) {
+                assert sideEffect.hasSideEffect();
+                FrameState stateAfter = createFrameState(stream.nextBCI(), sideEffect);
+                sideEffect.setStateAfter(stateAfter);
             }
 
             private BytecodePosition createBytecodePosition() {
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Mon May 11 17:56:16 2015 -0700
@@ -62,6 +62,12 @@
     private FrameState outerFrameState;
 
     /**
+     * The closest {@link StateSplit#hasSideEffect() side-effect} predecessors. There will be more
+     * than one when the current block contains no side-effects but merging predecessor blocks do.
+     */
+    protected StateSplit[] lastSideEffects;
+
+    /**
      * Creates a new frame state builder for the given method and the given target graph.
      *
      * @param method the method whose frame is simulated
@@ -144,14 +150,6 @@
             javaIndex += kind.getSlotCount();
             index++;
         }
-
-        if (parser.replacementContext instanceof IntrinsicContext) {
-            IntrinsicContext intrinsic = (IntrinsicContext) parser.replacementContext;
-            if (intrinsic.isCompilationRoot()) {
-                // Records the parameters to an root compiled intrinsic
-                intrinsic.args = locals.clone();
-            }
-        }
     }
 
     private HIRFrameStateBuilder(HIRFrameStateBuilder other) {
@@ -202,25 +200,22 @@
         return sb.toString();
     }
 
-    public FrameState create(int bci) {
-        BytecodeParser parent = parser.getParent();
+    public FrameState create(int bci, StateSplit forStateSplit) {
         if (parser.parsingReplacement()) {
             IntrinsicContext intrinsic = parser.replacementContext.asIntrinsic();
             if (intrinsic != null) {
-                return intrinsic.getInvokeStateBefore(parser.getGraph(), parent);
+                return intrinsic.createFrameState(parser.getGraph(), this, forStateSplit);
             }
         }
-        // If this is the recursive call in a partial intrinsification
-        // the frame(s) of the intrinsic method are omitted
-        while (parent != null && parent.parsingReplacement() && parent.replacementContext.asIntrinsic() != null) {
-            parent = parent.getParent();
-        }
+
+        // Skip intrinsic frames
+        BytecodeParser parent = (BytecodeParser) parser.getNonReplacementAncestor();
         return create(bci, parent, false);
     }
 
     public FrameState create(int bci, BytecodeParser parent, boolean duringCall) {
         if (outerFrameState == null && parent != null) {
-            outerFrameState = parent.getFrameState().create(parent.bci());
+            outerFrameState = parent.getFrameState().create(parent.bci(), null);
         }
         if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
             FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0));
@@ -316,6 +311,17 @@
             lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block);
             assert monitorIds[i] == other.monitorIds[i];
         }
+
+        if (lastSideEffects == null) {
+            lastSideEffects = other.lastSideEffects;
+        } else {
+            if (other.lastSideEffects != null) {
+                int thisLength = lastSideEffects.length;
+                int otherLength = other.lastSideEffects.length;
+                lastSideEffects = Arrays.copyOf(lastSideEffects, thisLength + otherLength);
+                System.arraycopy(other.lastSideEffects, 0, lastSideEffects, thisLength, otherLength);
+            }
+        }
     }
 
     private ValueNode merge(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) {
@@ -1003,4 +1009,15 @@
             }
         }
     }
+
+    public void addLastSideEffect(StateSplit sideEffect) {
+        assert sideEffect != null;
+        assert sideEffect.hasSideEffect();
+        if (lastSideEffects == null) {
+            lastSideEffects = new StateSplit[]{sideEffect};
+        } else {
+            lastSideEffects = Arrays.copyOf(lastSideEffects, lastSideEffects.length + 1);
+            lastSideEffects[lastSideEffects.length - 1] = sideEffect;
+        }
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/IntrinsicContext.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/IntrinsicContext.java	Mon May 11 17:56:16 2015 -0700
@@ -22,25 +22,19 @@
  */
 package com.oracle.graal.java;
 
-import static com.oracle.graal.java.HIRFrameStateBuilder.*;
-
-import java.util.*;
+import static com.oracle.graal.api.code.BytecodeFrame.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.java.GraphBuilderPhase.Instance.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
 
 /**
- * Context for a replacement being inlined as a compiler intrinsic. Deoptimization within a compiler
- * intrinsic must replay the intrinsified call. This context object retains the information required
- * to build a frame state denoting the JVM state just before the intrinsified call.
+ * Context for a replacement being inlined as a compiler intrinsic.
  */
 public class IntrinsicContext extends ReplacementContext {
 
     /**
-     * BCI denoting an intrinsic is being parsed for inlining after the caller has been parsed.
+     * BCI denoting an intrinsic is being parsed for inlining after the graph of the caller has been
+     * built.
      */
     public static final int POST_PARSE_INLINE_BCI = -1;
 
@@ -50,24 +44,15 @@
     public static final int ROOT_COMPILATION_BCI = -2;
 
     /**
-     * The arguments to the intrinsic.
-     */
-    ValueNode[] args;
-
-    /**
      * The BCI of the intrinsified invocation, {@link #POST_PARSE_INLINE_BCI} or
      * {@link #ROOT_COMPILATION_BCI}.
      */
     final int bci;
 
-    private FrameState stateBeforeCache;
-
-    public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute, ValueNode[] args, int bci) {
+    public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute, int bci) {
         super(method, substitute);
-        assert bci != POST_PARSE_INLINE_BCI || args == null;
-        this.args = args;
         this.bci = bci;
-        assert !isCompilationRoot() || method.hasBytecodes() : "Cannot intrinsic for native or abstract method " + method.format("%H.%n(%p)");
+        assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)");
     }
 
     @Override
@@ -83,34 +68,33 @@
         return bci == ROOT_COMPILATION_BCI;
     }
 
-    public FrameState getInvokeStateBefore(StructuredGraph graph, BytecodeParser parent) {
-        if (isCompilationRoot()) {
-            int maxLocals = method.getMaxLocals();
-            // The 'args' were initialized based on the intrinsic method but a
-            // frame state's 'locals' needs to have the same length as the frame
-            // state method's 'max_locals'.
-            ValueNode[] locals = maxLocals == args.length ? args : Arrays.copyOf(args, maxLocals);
-            ValueNode[] stack = EMPTY_ARRAY;
-            int stackSize = 0;
-            ValueNode[] locks = EMPTY_ARRAY;
-            List<MonitorIdNode> monitorIds = Collections.emptyList();
-            return graph.add(new FrameState(null, method, 0, locals, stack, stackSize, locks, monitorIds, false, false));
-        } else if (isPostParseInlined()) {
-            return graph.add(new FrameState(BytecodeFrame.BEFORE_BCI));
+    public FrameState createFrameState(StructuredGraph graph, HIRFrameStateBuilder frameState, StateSplit forStateSplit) {
+        assert forStateSplit != graph.start();
+        if (forStateSplit.hasSideEffect()) {
+            if (frameState.lastSideEffects != null) {
+                // 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 : frameState.lastSideEffects) {
+                    lastSideEffect.setStateAfter(invalid);
+                }
+            }
+            frameState.addLastSideEffect(forStateSplit);
+            return graph.add(new FrameState(AFTER_BCI));
         } else {
-            assert !parent.parsingReplacement() || parent.replacementContext instanceof IntrinsicContext;
-            if (stateBeforeCache == null) {
-
-                // Find the non-intrinsic ancestor calling the intrinsified method
-                BytecodeParser ancestor = parent;
-                while (ancestor.parsingReplacement()) {
-                    assert ancestor.replacementContext instanceof IntrinsicContext;
-                    ancestor = ancestor.getParent();
+            if (forStateSplit instanceof AbstractMergeNode) {
+                // Merge nodes always need a frame state
+                if (frameState.lastSideEffects != null) {
+                    // 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));
                 }
-                FrameState stateDuring = ancestor.getFrameState().create(ancestor.bci(), ancestor.getParent(), true);
-                stateBeforeCache = stateDuring.duplicateModifiedBeforeCall(bci, Kind.Void, args);
+            } else {
+                // Other non-side-effects do not need a state
+                return null;
             }
-            return stateBeforeCache;
         }
     }
 
@@ -121,7 +105,6 @@
 
     @Override
     public String toString() {
-        return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", replacement: " + replacement.format("%H.%n(%p)") + ", bci: " + bci + (args == null ? "" : ", args: " + Arrays.toString(args)) +
-                        (stateBeforeCache == null ? "" : ", stateBefore: " + stateBeforeCache) + "}";
+        return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", replacement: " + replacement.format("%H.%n(%p)") + ", bci: " + bci + "}";
     }
 }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java	Mon May 11 17:56:16 2015 -0700
@@ -44,6 +44,21 @@
     }
 
     @Test
+    public void runFirst() throws Throwable {
+        /*
+         * Execute Double.isNaN enough times to create a profile indicating that the path returning
+         * false is never taken. Then compile and execute the test with a NaN value to test that
+         * deoptimization works in the case of an uncommon trap inlined into an intrinsic. Of
+         * course, this relies on Double.isNaN never having yet been called with NaN. if it has,
+         * this test is equivalent to run0.
+         */
+        for (int i = 0; i < 10000; i++) {
+            Double.isNaN(1D);
+        }
+        executeActual(getResolvedJavaMethod("test"), null, java.lang.Double.NaN);
+    }
+
+    @Test
     public void run0() throws Throwable {
         runTest("test", java.lang.Double.NaN);
     }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java	Mon May 11 17:56:16 2015 -0700
@@ -67,7 +67,7 @@
 
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         runTest("test");
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Mon May 11 17:56:16 2015 -0700
@@ -117,6 +117,19 @@
                         bci == BytecodeFrame.INVALID_FRAMESTATE_BCI;
     }
 
+    /**
+     * Creates a placeholder frame state with a single element on the stack representing a return
+     * value. This allows the parsing of an intrinsic to communicate the returned value in a
+     * {@link StateSplit#stateAfter() stateAfter} to the inlining call site.
+     *
+     * @param bci this must be {@link BytecodeFrame#AFTER_BCI}
+     */
+    public FrameState(int bci, ValueNode returnValue) {
+        this(null, null, bci, 0, returnValue.getKind().getSlotCount(), 0, false, false, null, Collections.<EscapeObjectState> emptyList());
+        assert bci == BytecodeFrame.AFTER_BCI;
+        this.values.initialize(0, returnValue);
+    }
+
     public FrameState(FrameState outerFrameState, ResolvedJavaMethod method, int bci, ValueNode[] locals, ValueNode[] stack, int stackSize, ValueNode[] locks, List<MonitorIdNode> monitorIds,
                     boolean rethrowException, boolean duringCall) {
         this(outerFrameState, method, bci, locals.length, stackSize, locks.length, rethrowException, duringCall, monitorIds, Collections.<EscapeObjectState> emptyList());
@@ -421,7 +434,11 @@
         String nl = CodeUtil.NEW_LINE;
         FrameState fs = frameState;
         while (fs != null) {
-            MetaUtil.appendLocation(sb, fs.method, fs.bci).append(nl);
+            MetaUtil.appendLocation(sb, fs.method, fs.bci);
+            if (BytecodeFrame.isPlaceholderBci(fs.bci)) {
+                sb.append("//").append(getPlaceholderBciName(fs.bci));
+            }
+            sb.append(nl);
             sb.append("locals: [");
             for (int i = 0; i < fs.localsSize(); i++) {
                 sb.append(i == 0 ? "" : ", ").append(fs.localAt(i) == null ? "_" : fs.localAt(i).toString(Verbosity.Id));
@@ -445,7 +462,11 @@
         if (verbosity == Verbosity.Debugger) {
             return toString(this);
         } else if (verbosity == Verbosity.Name) {
-            return super.toString(Verbosity.Name) + "@" + bci;
+            String res = super.toString(Verbosity.Name) + "@" + bci;
+            if (BytecodeFrame.isPlaceholderBci(bci)) {
+                res += "[" + getPlaceholderBciName(bci) + "]";
+            }
+            return res;
         } else {
             return super.toString(verbosity);
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Mon May 11 17:56:16 2015 -0700
@@ -107,6 +107,12 @@
     }
 
     @Override
+    public void setStateAfter(FrameState x) {
+        assert hasSideEffect() || x == null;
+        super.setStateAfter(x);
+    }
+
+    @Override
     public FrameState stateDuring() {
         return stateDuring;
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Mon May 11 17:56:16 2015 -0700
@@ -468,14 +468,28 @@
         Kind invokeReturnKind = invoke.asNode().getKind();
 
         if (frameState.bci == BytecodeFrame.AFTER_BCI) {
+            FrameState stateAfterReturn = stateAtReturn;
+            if (frameState.method() == null) {
+                // This is a frame state for a side effect within an intrinsic
+                // that was parsed for post-parse intrinsification
+                for (Node usage : frameState.usages()) {
+                    if (usage instanceof ForeignCallNode) {
+                        // A foreign call inside an intrinsic needs to have
+                        // the BCI of the invoke being intrinsified
+                        ForeignCallNode foreign = (ForeignCallNode) usage;
+                        foreign.setBci(invoke.bci());
+                    }
+                }
+            }
+
             /*
              * pop return kind from invoke's stateAfter and replace with this frameState's return
              * value (top of stack)
              */
-            FrameState stateAfterReturn = stateAtReturn;
             if (invokeReturnKind != Kind.Void && (alwaysDuplicateStateAfter || (frameState.stackSize() > 0 && stateAfterReturn.stackAt(0) != frameState.stackAt(0)))) {
                 stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, frameState.stackAt(0));
             }
+
             frameState.replaceAndDelete(stateAfterReturn);
             return stateAfterReturn;
         } else if (stateAtExceptionEdge != null && isStateAfterException(frameState)) {
@@ -581,25 +595,26 @@
         ValueNode singleReturnValue = null;
         PhiNode returnValuePhi = null;
         for (ReturnNode returnNode : returnNodes) {
-            if (returnNode.result() != null) {
-                if (returnValuePhi == null && (singleReturnValue == null || singleReturnValue == returnNode.result())) {
+            ValueNode result = returnNode.result();
+            if (result != null) {
+                if (returnValuePhi == null && (singleReturnValue == null || singleReturnValue == result)) {
                     /* Only one return value, so no need yet for a phi node. */
-                    singleReturnValue = returnNode.result();
+                    singleReturnValue = result;
 
                 } else if (returnValuePhi == null) {
                     /* Found a second return value, so create phi node. */
-                    returnValuePhi = merge.graph().addWithoutUnique(new ValuePhiNode(returnNode.result().stamp().unrestricted(), merge));
+                    returnValuePhi = merge.graph().addWithoutUnique(new ValuePhiNode(result.stamp().unrestricted(), merge));
                     if (canonicalizedNodes != null) {
                         canonicalizedNodes.add(returnValuePhi);
                     }
                     for (int i = 0; i < merge.forwardEndCount(); i++) {
                         returnValuePhi.addInput(singleReturnValue);
                     }
-                    returnValuePhi.addInput(returnNode.result());
+                    returnValuePhi.addInput(result);
 
                 } else {
                     /* Multiple return values, just add to existing phi node. */
-                    returnValuePhi.addInput(returnNode.result());
+                    returnValuePhi.addInput(result);
                 }
             }
 
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DynamicNewArrayTest.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DynamicNewArrayTest.java	Mon May 11 17:56:16 2015 -0700
@@ -55,6 +55,7 @@
     @Test
     public void test4() {
         test("dynamic", Boolean.class, -7);
+        test("dynamicSynchronized", Boolean.class, -7);
     }
 
     @Test
@@ -95,4 +96,8 @@
     public static Object dynamic(Class<?> elementType, int length) {
         return Array.newInstance(elementType, length);
     }
+
+    public static synchronized Object dynamicSynchronized(Class<?> elementType, int length) {
+        return Array.newInstance(elementType, length);
+    }
 }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Mon May 11 17:56:16 2015 -0700
@@ -32,7 +32,6 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
 import com.oracle.graal.word.*;
 
 /**
@@ -50,7 +49,7 @@
 
     @Override
     protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
-        return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
+        return installer.makeGraph(m, null, null);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Mon May 11 17:56:16 2015 -0700
@@ -35,7 +35,6 @@
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
 import com.oracle.graal.word.*;
 import com.oracle.graal.word.nodes.*;
 
@@ -56,7 +55,7 @@
 
     @Override
     protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
-        return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
+        return installer.makeGraph(m, null, null);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Mon May 11 17:56:16 2015 -0700
@@ -29,7 +29,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
 import com.oracle.graal.word.*;
 
 /**
@@ -45,7 +44,7 @@
 
     @Override
     protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
-        return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
+        return installer.makeGraph(m, null, null);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java	Mon May 11 12:08:25 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,240 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.replacements;
-
-import static com.oracle.graal.api.code.BytecodeFrame.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.graph.*;
-import com.oracle.graal.phases.graph.ReentrantNodeIterator.LoopInfo;
-import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
-
-/**
- * This phase ensures that there's a single {@linkplain BytecodeFrame#AFTER_BCI collapsed frame
- * state} per path.
- *
- * Removes other frame states from {@linkplain StateSplit#hasSideEffect() non-side-effecting} nodes
- * in the graph, and replaces them with {@linkplain BytecodeFrame#INVALID_FRAMESTATE_BCI invalid
- * frame states}.
- *
- * The invalid frame states ensure that no deoptimization to a snippet frame state will happen.
- */
-public class CollapseFrameForSingleSideEffectPhase extends Phase {
-
-    private static class IterationState {
-        public final IterationState previous;
-        public final Node node;
-        public final Collection<IterationState> merge;
-        public final boolean invalid;
-
-        private IterationState(IterationState previous, Node node, Collection<IterationState> merge, boolean invalid) {
-            this.previous = previous;
-            this.node = node;
-            this.merge = merge;
-            this.invalid = invalid;
-        }
-
-        public IterationState() {
-            this(null, null, null, false);
-        }
-
-        public IterationState addSideEffect(StateSplit sideEffect) {
-            return new IterationState(this, sideEffect.asNode(), null, true);
-        }
-
-        public IterationState addBranch(AbstractBeginNode begin) {
-            return new IterationState(this, begin, null, this.invalid);
-        }
-
-        public static IterationState merge(AbstractMergeNode merge, Collection<IterationState> before, boolean invalid) {
-            return new IterationState(null, merge, before, invalid);
-        }
-
-        public void markAll(NodeBitMap set) {
-            IterationState state = this;
-            while (state != null && state.node != null && !set.contains(state.node)) {
-                set.mark(state.node);
-                if (state.merge != null) {
-                    for (IterationState branch : state.merge) {
-                        branch.markAll(set);
-                    }
-                }
-                state = state.previous;
-            }
-        }
-
-        public void markMasked(NodeBitMap unmasked, NodeBitMap masked) {
-            IterationState state = this;
-            while (state != null && state.node != null && !masked.contains(state.node)) {
-                if (state.node instanceof StateSplit) {
-                    unmasked.mark(state.node);
-                    StateSplit split = (StateSplit) state.node;
-                    if (split.hasSideEffect() && state.previous != null) {
-                        state.previous.markAll(masked);
-                        return;
-                    }
-                }
-
-                if (state.merge != null) {
-                    for (IterationState branch : state.merge) {
-                        branch.markMasked(unmasked, masked);
-                    }
-                }
-                state = state.previous;
-            }
-        }
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        CollapseFrameForSingleSideEffectClosure closure = new CollapseFrameForSingleSideEffectClosure();
-        ReentrantNodeIterator.apply(closure, graph.start(), new IterationState());
-        closure.finishProcessing(graph);
-    }
-
-    private static class CollapseFrameForSingleSideEffectClosure extends NodeIteratorClosure<IterationState> {
-
-        private List<IterationState> returnStates = new ArrayList<>();
-        private List<IterationState> unwindStates = new ArrayList<>();
-
-        @Override
-        protected IterationState processNode(FixedNode node, IterationState currentState) {
-            IterationState state = currentState;
-            if (node instanceof StateSplit) {
-                StateSplit stateSplit = (StateSplit) node;
-                FrameState frameState = stateSplit.stateAfter();
-                if (frameState != null) {
-                    if (stateSplit.hasSideEffect()) {
-                        setStateAfter(node.graph(), stateSplit, INVALID_FRAMESTATE_BCI, false);
-                        state = state.addSideEffect(stateSplit);
-                    } else if (currentState.invalid) {
-                        setStateAfter(node.graph(), stateSplit, INVALID_FRAMESTATE_BCI, false);
-                    } else if (stateSplit instanceof StartNode) {
-                        setStateAfter(node.graph(), stateSplit, BEFORE_BCI, false);
-                    } else {
-                        stateSplit.setStateAfter(null);
-                        if (frameState.hasNoUsages()) {
-                            GraphUtil.killWithUnusedFloatingInputs(frameState);
-                        }
-                    }
-                }
-            }
-            if (node instanceof ReturnNode) {
-                returnStates.add(currentState);
-            } else if (node instanceof UnwindNode) {
-                unwindStates.add(currentState);
-            }
-            return state;
-        }
-
-        @Override
-        protected IterationState merge(AbstractMergeNode merge, List<IterationState> states) {
-            boolean invalid = false;
-            for (IterationState state : states) {
-                if (state.invalid) {
-                    invalid = true;
-                    break;
-                }
-            }
-            return IterationState.merge(merge, states, invalid);
-        }
-
-        public void finishProcessing(StructuredGraph graph) {
-            NodeBitMap maskedSideEffects = new NodeBitMap(graph);
-            NodeBitMap returnSideEffects = new NodeBitMap(graph);
-            NodeBitMap unwindSideEffects = new NodeBitMap(graph);
-
-            for (IterationState returnState : returnStates) {
-                returnState.markMasked(returnSideEffects, maskedSideEffects);
-            }
-            for (IterationState unwindState : unwindStates) {
-                unwindState.markMasked(unwindSideEffects, maskedSideEffects);
-            }
-
-            for (Node returnSideEffect : returnSideEffects) {
-                if (!unwindSideEffects.contains(returnSideEffect) && !maskedSideEffects.contains(returnSideEffect)) {
-                    StateSplit split = (StateSplit) returnSideEffect;
-                    setStateAfter(graph, split, AFTER_BCI, true);
-                }
-            }
-
-            for (Node unwindSideEffect : unwindSideEffects) {
-                if (!returnSideEffects.contains(unwindSideEffect) && !maskedSideEffects.contains(unwindSideEffect)) {
-                    StateSplit split = (StateSplit) unwindSideEffect;
-                    setStateAfter(graph, split, AFTER_EXCEPTION_BCI, true);
-                }
-            }
-        }
-
-        @Override
-        protected IterationState afterSplit(AbstractBeginNode node, IterationState oldState) {
-            return oldState.addBranch(node);
-        }
-
-        @Override
-        protected Map<LoopExitNode, IterationState> processLoop(LoopBeginNode loop, IterationState initialState) {
-            LoopInfo<IterationState> info = ReentrantNodeIterator.processLoop(this, loop, initialState);
-
-            boolean isNowInvalid = initialState.invalid;
-            for (IterationState endState : info.endStates.values()) {
-                isNowInvalid |= endState.invalid;
-            }
-
-            if (isNowInvalid) {
-                setStateAfter(loop.graph(), loop, INVALID_FRAMESTATE_BCI, false);
-            }
-
-            IterationState endState = IterationState.merge(loop, info.endStates.values(), isNowInvalid);
-            return ReentrantNodeIterator.processLoop(this, loop, endState).exitStates;
-        }
-
-        /**
-         * Creates and sets a special frame state for a node. If the existing frame state is
-         * non-null and has no other usages, it is deleted via
-         * {@link GraphUtil#killWithUnusedFloatingInputs(Node)}.
-         *
-         * @param graph the graph context
-         * @param node the node whose frame state is updated
-         * @param bci {@link BytecodeFrame#BEFORE_BCI}, {@link BytecodeFrame#AFTER_EXCEPTION_BCI} or
-         *            {@link BytecodeFrame#INVALID_FRAMESTATE_BCI}
-         * @param replaceOnly only perform the update if the node currently has a non-null frame
-         *            state
-         */
-        private static void setStateAfter(StructuredGraph graph, StateSplit node, int bci, boolean replaceOnly) {
-            assert (bci == BEFORE_BCI && node instanceof StartNode) || bci == AFTER_BCI || bci == AFTER_EXCEPTION_BCI || bci == INVALID_FRAMESTATE_BCI;
-            FrameState currentStateAfter = node.stateAfter();
-            if (currentStateAfter != null || !replaceOnly) {
-                node.setStateAfter(graph.add(new FrameState(bci)));
-                if (currentStateAfter != null && currentStateAfter.hasNoUsages()) {
-                    GraphUtil.killWithUnusedFloatingInputs(currentStateAfter);
-                }
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Mon May 11 17:56:16 2015 -0700
@@ -145,12 +145,18 @@
             b.add(new UnsafeStoreNode(copy.destinationObject(), copy.destinationOffset(), value, copy.accessKind(), copy.getLocationIdentity()));
             return true;
         } else if (res instanceof ForeignCallNode) {
-            ForeignCallNode foreign = (ForeignCallNode) res;
-            foreign.setBci(b.bci());
+            /*
+             * 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 normal method as opposed to an intrinsic.
+             */
+            GraphBuilderContext ancestor = b.getNonReplacementAncestor();
+            if (ancestor != null) {
+                ForeignCallNode foreign = (ForeignCallNode) res;
+                foreign.setBci(ancestor.bci());
+            }
         }
 
-        res = b.add(res);
-
         boolean nonValueType = false;
         if (returnKind == Kind.Object && stamp instanceof ObjectStamp) {
             ResolvedJavaType type = ((ObjectStamp) stamp).type();
@@ -162,16 +168,10 @@
 
         if (returnKind != Kind.Void) {
             assert nonValueType || res.getKind().getStackKind() != Kind.Void;
-            b.push(returnKind.getStackKind(), res);
+            res = b.addPush(returnKind.getStackKind(), res);
         } else {
             assert res.getKind().getStackKind() == Kind.Void;
-        }
-
-        if (res instanceof StateSplit) {
-            StateSplit stateSplit = (StateSplit) res;
-            if (stateSplit.stateAfter() == null) {
-                stateSplit.setStateAfter(b.createStateAfter());
-            }
+            res = b.add(res);
         }
 
         return true;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Mon May 11 17:56:16 2015 -0700
@@ -152,7 +152,7 @@
             if (invoke.getKind() != Kind.Void) {
                 frameStateBuilder.push(returnType.getKind(), invoke);
             }
-            invoke.setStateAfter(frameStateBuilder.create(bci));
+            invoke.setStateAfter(frameStateBuilder.create(bci, invoke));
             if (invoke.getKind() != Kind.Void) {
                 frameStateBuilder.pop(returnType.getKind());
             }
@@ -219,7 +219,7 @@
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
 
         StructuredGraph calleeGraph = new StructuredGraph(method, AllowAssumptions.NO);
-        IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, null, IntrinsicContext.POST_PARSE_INLINE_BCI);
+        IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, IntrinsicContext.POST_PARSE_INLINE_BCI);
         new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(calleeGraph);
 
         // Remove all frame states from inlinee
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java	Mon May 11 17:56:16 2015 -0700
@@ -152,8 +152,10 @@
         return graph;
     }
 
-    public FrameState createStateAfter() {
-        return getGraph().add(new FrameState(BytecodeFrame.BEFORE_BCI));
+    public void setStateAfter(StateSplit sideEffect) {
+        assert sideEffect.hasSideEffect();
+        FrameState stateAfter = getGraph().add(new FrameState(BytecodeFrame.BEFORE_BCI));
+        sideEffect.setStateAfter(stateAfter);
     }
 
     public GraphBuilderContext getParent() {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java	Mon May 11 17:56:16 2015 -0700
@@ -178,7 +178,7 @@
         }
 
         @Override
-        public FrameState createStateAfter() {
+        public void setStateAfter(StateSplit stateSplit) {
             throw unimplemented();
         }
 
@@ -226,10 +226,11 @@
         }
 
         @Override
-        public FrameState createStateAfter() {
+        public void setStateAfter(StateSplit stateSplit) {
             Node stateAfter = decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId);
             getGraph().add(stateAfter);
-            return (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter);
+            FrameState fs = (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter);
+            stateSplit.setStateAfter(fs);
         }
 
         @Override
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Mon May 11 17:56:16 2015 -0700
@@ -25,6 +25,7 @@
 import static com.oracle.graal.api.meta.MetaUtil.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+import static com.oracle.graal.java.IntrinsicContext.*;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*;
 import static java.lang.String.*;
 
@@ -299,9 +300,7 @@
         StructuredGraph graph = UseSnippetGraphCache ? graphs.get(method) : null;
         if (graph == null) {
             try (DebugCloseable a = SnippetPreparationTime.start()) {
-                FrameStateProcessing frameStateProcessing = method.getAnnotation(Snippet.class).removeAllFrameStates() ? FrameStateProcessing.Removal
-                                : FrameStateProcessing.CollapseFrameForSingleSideEffect;
-                StructuredGraph newGraph = makeGraph(method, args, recursiveEntry, frameStateProcessing);
+                StructuredGraph newGraph = makeGraph(method, args, recursiveEntry);
                 Debug.metric("SnippetNodeCount[%#s]", method).add(newGraph.getNodeCount());
                 if (!UseSnippetGraphCache || args != null) {
                     return newGraph;
@@ -346,7 +345,7 @@
         }
         StructuredGraph graph = graphs.get(substitute);
         if (graph == null) {
-            graph = makeGraph(substitute, null, original, FrameStateProcessing.None);
+            graph = makeGraph(substitute, null, original);
             graph.freeze();
             graphs.putIfAbsent(substitute, graph);
             graph = graphs.get(substitute);
@@ -445,19 +444,18 @@
      * @param args
      * @param original the original method if {@code method} is a {@linkplain MethodSubstitution
      *            substitution} otherwise null
-     * @param frameStateProcessing controls how {@link FrameState FrameStates} should be handled.
      */
-    public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, FrameStateProcessing frameStateProcessing) {
+    public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original) {
         try (OverrideScope s = OptionValue.override(DeoptALot, false)) {
-            return createGraphMaker(method, original, frameStateProcessing).makeGraph(args);
+            return createGraphMaker(method, original).makeGraph(args);
         }
     }
 
     /**
      * Can be overridden to return an object that specializes various parts of graph preprocessing.
      */
-    protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original, FrameStateProcessing frameStateProcessing) {
-        return new GraphMaker(this, substitute, original, frameStateProcessing);
+    protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original) {
+        return new GraphMaker(this, substitute, original);
     }
 
     /**
@@ -465,18 +463,6 @@
      */
     final ConcurrentMap<ResolvedJavaMethod, StructuredGraph> graphCache = new ConcurrentHashMap<>();
 
-    public enum FrameStateProcessing {
-        None,
-        /**
-         * @see CollapseFrameForSingleSideEffectPhase
-         */
-        CollapseFrameForSingleSideEffect,
-        /**
-         * Removes frame states from all nodes in the graph.
-         */
-        Removal
-    }
-
     /**
      * Creates and preprocesses a graph for a replacement.
      */
@@ -496,16 +482,10 @@
          */
         protected final ResolvedJavaMethod substitutedMethod;
 
-        /**
-         * Controls how FrameStates are processed.
-         */
-        private FrameStateProcessing frameStateProcessing;
-
-        protected GraphMaker(ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod, FrameStateProcessing frameStateProcessing) {
+        protected GraphMaker(ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod) {
             this.replacements = replacements;
             this.method = substitute;
             this.substitutedMethod = substitutedMethod;
-            this.frameStateProcessing = frameStateProcessing;
         }
 
         public StructuredGraph makeGraph(Object[] args) {
@@ -536,18 +516,6 @@
             new ConvertDeoptimizeToGuardPhase().apply(graph, null);
             assert sideEffectCount == graph.getNodes().filter(e -> hasSideEffect(e)).count() : "deleted side effecting node";
 
-            switch (frameStateProcessing) {
-                case Removal:
-                    for (Node node : graph.getNodes()) {
-                        if (node instanceof StateSplit) {
-                            ((StateSplit) node).setStateAfter(null);
-                        }
-                    }
-                    break;
-                case CollapseFrameForSingleSideEffect:
-                    new CollapseFrameForSingleSideEffectPhase().apply(graph);
-                    break;
-            }
             new DeadCodeEliminationPhase(Required).apply(graph);
         }
 
@@ -629,12 +597,13 @@
                         OptimisticOptimizations optimisticOpts) {
             ReplacementContext initialReplacementContext = null;
             if (method.getAnnotation(Snippet.class) == null) {
-                // Late inlined intrinsic
-                initialReplacementContext = new IntrinsicContext(substitutedMethod, method, null, -1);
+                // Post-parse inlined intrinsic
+                initialReplacementContext = new IntrinsicContext(substitutedMethod, method, POST_PARSE_INLINE_BCI);
             } else {
                 // Snippet
                 ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method;
-                initialReplacementContext = new ReplacementContext(original, method);
+                // initialReplacementContext = new ReplacementContext(original, method);
+                initialReplacementContext = new IntrinsicContext(original, method, POST_PARSE_INLINE_BCI);
             }
             return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, initialReplacementContext);
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Mon May 11 17:56:16 2015 -0700
@@ -24,7 +24,6 @@
 
 import static com.oracle.graal.api.code.BytecodeFrame.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
@@ -114,13 +113,6 @@
         StructuredGraph methodSubstitution = tool.getReplacements().getSubstitution(getTargetMethod(), true, bci);
         if (methodSubstitution != null) {
             methodSubstitution = methodSubstitution.copy();
-            if (stateAfter() == null || stateAfter().bci == BytecodeFrame.AFTER_BCI) {
-                /*
-                 * handles the case of a MacroNode inside a snippet used for another MacroNode
-                 * lowering
-                 */
-                new CollapseFrameForSingleSideEffectPhase().apply(methodSubstitution);
-            }
             return lowerReplacement(methodSubstitution, tool);
         }
         return null;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Mon May 11 17:56:16 2015 -0700
@@ -34,8 +34,8 @@
     public static final NodeClass<NeverPartOfCompilationNode> TYPE = NodeClass.create(NeverPartOfCompilationNode.class);
     protected final String message;
 
-    public NeverPartOfCompilationNode(String message, FrameState stateAfter) {
-        super(TYPE, StampFactory.forVoid(), stateAfter);
+    public NeverPartOfCompilationNode(String message) {
+        super(TYPE, StampFactory.forVoid());
         this.message = message;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Mon May 11 17:56:16 2015 -0700
@@ -239,7 +239,7 @@
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode message) {
                 if (message.isConstant()) {
                     String messageString = message.asConstant().toValueString();
-                    b.add(new NeverPartOfCompilationNode(messageString, b.createStateAfter()));
+                    b.add(new NeverPartOfCompilationNode(messageString));
                     return true;
                 } else if (canDelayIntrinsification) {
                     return false;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Mon May 11 17:56:16 2015 -0700
@@ -182,7 +182,7 @@
 
     /**
      * Collects the effects of virtualizing the given node.
-     * 
+     *
      * @return {@code true} if the effects include removing the node, {@code false} otherwise.
      */
     protected abstract boolean processNode(Node node, BlockT state, GraphEffectList effects, FixedWithNextNode lastFixedNode);
@@ -210,6 +210,7 @@
 
         BlockT loopEntryState = initialState;
         BlockT lastMergedState = cloneState(initialState);
+        processInitialLoopState(loop, lastMergedState);
         MergeProcessor mergeProcessor = createMergeProcessor(loop.getHeader());
         for (int iteration = 0; iteration < 10; iteration++) {
             LoopInfo<BlockT> info = ReentrantBlockIterator.processLoop(this, loop, cloneState(lastMergedState));
@@ -245,6 +246,11 @@
         throw new GraalInternalError("too many iterations at %s", loop);
     }
 
+    @SuppressWarnings("unused")
+    protected void processInitialLoopState(Loop<Block> loop, BlockT initialState) {
+        // nothing to do
+    }
+
     private void doMergeWithoutDead(MergeProcessor mergeProcessor, List<BlockT> states) {
         int alive = 0;
         for (BlockT state : states) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Mon May 11 17:56:16 2015 -0700
@@ -115,7 +115,7 @@
         ValueNode cacheObject;
         ObjectState obj = closure.getObjectState(this, object);
         if (obj != null) {
-            assert !obj.isVirtual();
+            assert !obj.isVirtual() : object;
             cacheObject = obj.getMaterializedValue();
         } else {
             cacheObject = object;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Mon May 11 17:56:16 2015 -0700
@@ -27,6 +27,7 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
@@ -212,6 +213,23 @@
     }
 
     @Override
+    protected void processInitialLoopState(Loop<Block> loop, PEReadEliminationBlockState initialState) {
+        super.processInitialLoopState(loop, initialState);
+
+        for (PhiNode phi : ((LoopBeginNode) loop.getHeader().getBeginNode()).phis()) {
+            ValueNode firstValue = phi.valueAt(0);
+            if (firstValue != null) {
+                firstValue = GraphUtil.unproxify(firstValue);
+                for (Map.Entry<ReadCacheEntry, ValueNode> entry : new ArrayList<>(initialState.getReadCache().entrySet())) {
+                    if (entry.getKey().object == firstValue) {
+                        initialState.addReadCache(phi, entry.getKey().identity, entry.getKey().index, entry.getValue(), this);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
     protected void processLoopExit(LoopExitNode exitNode, PEReadEliminationBlockState initialState, PEReadEliminationBlockState exitState, GraphEffectList effects) {
         super.processLoopExit(exitNode, initialState, exitState, effects);
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Mon May 11 17:56:16 2015 -0700
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.util.*;
 import com.oracle.graal.debug.*;
@@ -359,6 +360,20 @@
     }
 
     @Override
+    protected void processInitialLoopState(Loop<Block> loop, BlockT initialState) {
+        super.processInitialLoopState(loop, initialState);
+
+        for (PhiNode phi : ((LoopBeginNode) loop.getHeader().getBeginNode()).phis()) {
+            if (phi.valueAt(0) != null) {
+                ObjectState state = getObjectState(initialState, phi.valueAt(0));
+                if (state != null && state.isVirtual()) {
+                    addAndMarkAlias(state.virtual, phi);
+                }
+            }
+        }
+    }
+
+    @Override
     protected void processLoopExit(LoopExitNode exitNode, BlockT initialState, BlockT exitState, GraphEffectList effects) {
         if (exitNode.graph().hasValueProxies()) {
             Map<VirtualObjectNode, ProxyNode> proxies = Node.newMap();
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java	Mon May 11 12:08:25 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java	Mon May 11 17:56:16 2015 -0700
@@ -61,6 +61,11 @@
  * (non-indexed) <em>Literal</em> . <br>
  * See {@link Source#fromReader(Reader, String)}</li>
  * <p>
+ * <li><strong>Sub-Source:</strong> A representation of the contents of a sub-range of another
+ * {@link Source}.<br>
+ * See @link {@link Source#subSource(Source, int, int)}<br>
+ * See @link {@link Source#subSource(Source, int)}</li>
+ * <p>
  * <li><strong>AppendableSource:</strong> Literal contents are provided by the client,
  * incrementally, after the instance is created.<br>
  * See {@link Source#fromAppendableText(String)}<br>
@@ -250,8 +255,8 @@
      * @param description a note about the origin, for error messages and debugging
      * @return a newly created, non-indexed, initially empty, appendable source representation
      */
-    public static AppendableSource fromAppendableText(String description) {
-        final AppendableSource source = new AppendableLiteralSource(description);
+    public static Source fromAppendableText(String description) {
+        final Source source = new AppendableLiteralSource(description);
         notifyNewSource(source).tagAs(Tags.FROM_LITERAL);
         return source;
     }
@@ -281,11 +286,39 @@
      * @param name string to use for indexing/lookup
      * @return a newly created, indexed, initially empty, appendable source representation
      */
-    public static AppendableSource fromNamedAppendableText(String name) {
+    public static Source fromNamedAppendableText(String name) {
         final Source source = new AppendableLiteralSource(name);
         nameToSource.put(name, new WeakReference<>(source));
         notifyNewSource(source).tagAs(Tags.FROM_LITERAL);
-        return (AppendableSource) source;
+        return source;
+    }
+
+    /**
+     * Creates a {@linkplain Source Source instance} that represents the contents of a sub-range of
+     * an existing {@link Source}.
+     *
+     * @param base an existing Source instance
+     * @param baseCharIndex 0-based index of the first character of the sub-range
+     * @param length the number of characters in the sub-range
+     * @return a new instance representing a sub-range of another Source
+     * @throws IllegalArgumentException if the specified sub-range is not contained in the base
+     */
+    public static Source subSource(Source base, int baseCharIndex, int length) {
+        final SubSource subSource = SubSource.create(base, baseCharIndex, length);
+        return subSource;
+    }
+
+    /**
+     * Creates a {@linkplain Source Source instance} that represents the contents of a sub-range at
+     * the end of an existing {@link Source}.
+     *
+     * @param base an existing Source instance
+     * @param baseCharIndex 0-based index of the first character of the sub-range
+     * @return a new instance representing a sub-range at the end of another Source
+     * @throws IllegalArgumentException if the index is out of range
+     */
+    public static Source subSource(Source base, int baseCharIndex) {
+        return subSource(base, baseCharIndex, base.getLength() - baseCharIndex);
     }
 
     /**
@@ -418,25 +451,6 @@
         return builder.toString();
     }
 
-    public abstract static class AppendableSource extends Source {
-
-        /**
-         * Sets the mark.
-         */
-        public void setMark() {
-        }
-
-        public abstract void appendCode(CharSequence chars);
-
-        /**
-         * Gets the code from the mark to the end.
-         */
-        public String getCodeFromMark() {
-            return getCode();
-        }
-
-    }
-
     private final ArrayList<SourceTag> tags = new ArrayList<>();
 
     private Source() {
@@ -515,7 +529,7 @@
      * Gets the number of characters in the source.
      */
     public final int getLength() {
-        return checkTextMap().length();
+        return getTextMap().length();
     }
 
     /**
@@ -534,9 +548,8 @@
      * Gets the text (not including a possible terminating newline) in a (1-based) numbered line.
      */
     public final String getCode(int lineNumber) {
-        checkTextMap();
-        final int offset = textMap.lineStartOffset(lineNumber);
-        final int length = textMap.lineLength(lineNumber);
+        final int offset = getTextMap().lineStartOffset(lineNumber);
+        final int length = getTextMap().lineLength(lineNumber);
         return getCode().substring(offset, offset + length);
     }
 
@@ -545,7 +558,7 @@
      * source without a terminating newline count as a line.
      */
     public final int getLineCount() {
-        return checkTextMap().lineCount();
+        return getTextMap().lineCount();
     }
 
     /**
@@ -555,7 +568,7 @@
      * @throws IllegalArgumentException if the offset is outside the text contents
      */
     public final int getLineNumber(int offset) throws IllegalArgumentException {
-        return checkTextMap().offsetToLine(offset);
+        return getTextMap().offsetToLine(offset);
     }
 
     /**
@@ -564,7 +577,7 @@
      * @throws IllegalArgumentException if the offset is outside the text contents
      */
     public final int getColumnNumber(int offset) throws IllegalArgumentException {
-        return checkTextMap().offsetToCol(offset);
+        return getTextMap().offsetToCol(offset);
     }
 
     /**
@@ -573,7 +586,7 @@
      * @throws IllegalArgumentException if there is no such line in the text
      */
     public final int getLineStartOffset(int lineNumber) throws IllegalArgumentException {
-        return checkTextMap().lineStartOffset(lineNumber);
+        return getTextMap().lineStartOffset(lineNumber);
     }
 
     /**
@@ -583,7 +596,17 @@
      * @throws IllegalArgumentException if there is no such line in the text
      */
     public final int getLineLength(int lineNumber) throws IllegalArgumentException {
-        return checkTextMap().lineLength(lineNumber);
+        return getTextMap().lineLength(lineNumber);
+    }
+
+    /**
+     * Append text to a Source explicitly created as <em>Appendable</em>.
+     *
+     * @param chars the text to append
+     * @throws UnsupportedOperationException by concrete subclasses that do not support appending
+     */
+    public void appendCode(CharSequence chars) {
+        throw new UnsupportedOperationException();
     }
 
     /**
@@ -623,9 +646,8 @@
      * @throws IllegalStateException if the source is one of the "null" instances
      */
     public final SourceSection createSection(String identifier, int startLine, int startColumn, int length) {
-        checkTextMap();
-        final int lineStartOffset = textMap.lineStartOffset(startLine);
-        if (startColumn > textMap.lineLength(startLine)) {
+        final int lineStartOffset = getTextMap().lineStartOffset(startLine);
+        if (startColumn > getTextMap().lineLength(startLine)) {
             throw new IllegalArgumentException("column out of range");
         }
         final int startOffset = lineStartOffset + startColumn - 1;
@@ -653,10 +675,8 @@
      */
     public final SourceSection createSection(String identifier, int charIndex, int length) throws IllegalArgumentException {
         checkRange(charIndex, length);
-        checkTextMap();
         final int startLine = getLineNumber(charIndex);
         final int startColumn = charIndex - getLineStartOffset(startLine) + 1;
-
         return new DefaultSourceSection(this, identifier, startLine, startColumn, charIndex, length);
     }
 
@@ -677,9 +697,8 @@
      * @throws IllegalStateException if the source is one of the "null" instances
      */
     public final SourceSection createSection(String identifier, int lineNumber) {
-        checkTextMap();
-        final int charIndex = textMap.lineStartOffset(lineNumber);
-        final int length = textMap.lineLength(lineNumber);
+        final int charIndex = getTextMap().lineStartOffset(lineNumber);
+        final int length = getTextMap().lineLength(lineNumber);
         return createSection(identifier, charIndex, length);
     }
 
@@ -702,7 +721,7 @@
         return getName();
     }
 
-    protected final TextMap checkTextMap() {
+    protected final TextMap getTextMap() {
         if (textMap == null) {
             textMap = createTextMap();
         }
@@ -786,9 +805,8 @@
         }
     }
 
-    private static final class AppendableLiteralSource extends AppendableSource {
+    private static final class AppendableLiteralSource extends Source {
         private String description;
-        private int mark = 0;
         final List<CharSequence> codeList = new ArrayList<>();
 
         public AppendableLiteralSource(String description) {
@@ -839,20 +857,11 @@
         }
 
         @Override
-        public String getCodeFromMark() {
-            return getCodeFromIndex(mark);
-        }
-
-        @Override
         public void appendCode(CharSequence chars) {
             codeList.add(chars);
             clearTextMap();
         }
 
-        @Override
-        public void setMark() {
-            mark = codeList.size();
-        }
     }
 
     private static final class FileSource extends Source {
@@ -1016,6 +1025,61 @@
         }
     }
 
+    private static final class SubSource extends Source {
+        private final Source base;
+        private final int baseIndex;
+        private final int subLength;
+
+        private static SubSource create(Source base, int baseIndex, int length) {
+            if (baseIndex < 0 || length < 0 || baseIndex + length > base.getLength()) {
+                throw new IllegalArgumentException("text positions out of range");
+            }
+            return new SubSource(base, baseIndex, length);
+        }
+
+        private SubSource(Source base, int baseIndex, int length) {
+            this.base = base;
+            this.baseIndex = baseIndex;
+            this.subLength = length;
+        }
+
+        @Override
+        protected void reset() {
+            assert false;
+        }
+
+        @Override
+        public String getName() {
+            return base.getName();
+        }
+
+        @Override
+        public String getShortName() {
+            return base.getShortName();
+        }
+
+        @Override
+        public String getPath() {
+            return base.getPath();
+        }
+
+        @Override
+        public URL getURL() {
+            return null;
+        }
+
+        @Override
+        public Reader getReader() {
+            assert false;
+            return null;
+        }
+
+        @Override
+        public String getCode() {
+            return base.getCode(baseIndex, subLength);
+        }
+    }
+
     private static final class BytesSource extends Source {
 
         private final String name;
--- a/mx/mx_graal.py	Mon May 11 12:08:25 2015 -0700
+++ b/mx/mx_graal.py	Mon May 11 17:56:16 2015 -0700
@@ -1606,7 +1606,6 @@
     parser = ArgumentParser(prog='mx ctw')
     parser.add_argument('--ctwopts', action='store', help='space separated Graal options used for CTW compilations (default: --ctwopts="' + defaultCtwopts + '")', default=defaultCtwopts, metavar='<options>')
     parser.add_argument('--jar', action='store', help='jar of classes to compiled instead of rt.jar', metavar='<path>')
-    parser.add_argument('vmargs', nargs=REMAINDER, metavar='VM options...')
 
     args, vmargs = parser.parse_known_args(args)
 
--- a/mxtool/mx.py	Mon May 11 12:08:25 2015 -0700
+++ b/mxtool/mx.py	Mon May 11 17:56:16 2015 -0700
@@ -4157,8 +4157,8 @@
     launchOut.open('launchConfiguration', {'type' : 'org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType'})
     launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.core.capture_output', 'value': consoleOn})
     launchOut.open('mapAttribute', {'key' : 'org.eclipse.debug.core.environmentVariables'})
-    launchOut.element('mapEntry', {'key' : 'JAVA_HOME', 'value' : _opts.java_home})
-    launchOut.element('mapEntry', {'key' : 'EXTRA_JAVA_HOMES', 'value' : _opts.extra_java_homes})
+    launchOut.element('mapEntry', {'key' : 'JAVA_HOME', 'value' : _default_java_home.jdk})
+    launchOut.element('mapEntry', {'key' : 'EXTRA_JAVA_HOMES', 'value' :  os.pathsep.join([extraJavaHome.jdk for extraJavaHome in _extra_java_homes])})
     launchOut.close('mapAttribute')
 
     if refresh: