Merge
authordholmes
Thu, 01 Jun 2017 02:21:18 +0000
changeset 46511 4a5b7a2dd783
parent 46509 b32d3928ad6a (diff)
parent 46510 8cc204b35e39 (current diff)
child 46512 1ba5728eda0d
Merge
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCArithmeticLIRGenerator.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCArithmeticLIRGenerator.java	Thu Jun 01 02:21:18 2017 +0000
@@ -113,12 +113,7 @@
     @Override
     public Variable emitBitCount(Value operand) {
         Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD));
-        AllocatableValue usedOperand = getLIRGen().asAllocatable(operand);
-        if (operand.getPlatformKind() == SPARCKind.WORD) { // Zero extend
-            AllocatableValue intermediateOperand = getLIRGen().newVariable(operand.getValueKind());
-            getLIRGen().append(new SPARCOP3Op(Op3s.Srl, usedOperand, g0.asValue(), intermediateOperand));
-            usedOperand = intermediateOperand;
-        }
+        AllocatableValue usedOperand = getLIRGen().asAllocatable(emitZeroExtend(operand));
         getLIRGen().append(new SPARCOP3Op(Op3s.Popc, g0.asValue(), usedOperand, result));
         return result;
     }
@@ -275,7 +270,7 @@
                 }
                 return result;
             } else {
-                return emitBinary(resultKind, setFlags ? Op3s.Mulscc : Op3s.Mulx, a, b);
+                return emitBinary(resultKind, Op3s.Mulx, a, b);
             }
         } else {
             boolean isDouble = a.getPlatformKind().equals(DOUBLE);
@@ -303,9 +298,7 @@
     public Value emitUMulHigh(Value a, Value b) {
         switch (((SPARCKind) a.getPlatformKind())) {
             case WORD:
-                Value aExtended = emitBinary(LIRKind.combine(a), Srl, a, 0);
-                Value bExtended = emitBinary(LIRKind.combine(b), Srl, b, 0);
-                Value result = emitBinary(LIRKind.combine(a, b), Mulx, aExtended, bExtended);
+                Value result = emitBinary(LIRKind.combine(a, b), Mulx, emitZeroExtend(a), emitZeroExtend(b));
                 return emitBinary(LIRKind.combine(a, b), Srax, result, WORD.getSizeInBits());
             case XWORD:
                 return emitBinary(LIRKind.combine(a, b), UMulxhi, a, b);
@@ -324,17 +317,13 @@
     @Override
     public Value emitDiv(Value a, Value b, LIRFrameState state) {
         LIRKind resultKind = LIRKind.combine(a, b);
-        PlatformKind aKind = a.getPlatformKind();
-        PlatformKind bKind = b.getPlatformKind();
         if (isJavaConstant(b) && asJavaConstant(b).isDefaultForKind()) { // Div by zero
             Value zero = SPARC.g0.asValue(LIRKind.value(SPARCKind.WORD));
             return emitBinary(resultKind, Op3s.Sdivx, zero, zero, state);
-        } else if (isNumericInteger(aKind)) {
-            Value fixedA = emitSignExtend(a, aKind.getSizeInBytes() * 8, 64);
-            Value fixedB = emitSignExtend(b, bKind.getSizeInBytes() * 8, 64);
-            return emitBinary(resultKind, Op3s.Sdivx, fixedA, fixedB, state);
+        } else if (isNumericInteger(a.getPlatformKind())) {
+            return emitBinary(resultKind, Op3s.Sdivx, emitSignExtend(a), emitSignExtend(b), state);
         } else {
-            boolean isDouble = a.getPlatformKind().equals(DOUBLE);
+            boolean isDouble = a.getPlatformKind() == DOUBLE;
             return emitBinary(resultKind, isDouble ? Opfs.Fdivd : Opfs.Fdivs, a, b, state);
         }
     }
@@ -342,24 +331,21 @@
     @Override
     public Value emitRem(Value a, Value b, LIRFrameState state) {
         Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
-        Value aLoaded;
         Variable q1; // Intermediate values
         Variable q2;
-        SPARCKind aKind = (SPARCKind) a.getPlatformKind();
-        switch (aKind) {
+        switch ((SPARCKind) a.getPlatformKind()) {
             case WORD:
                 // Sign extend a and b
-                Variable as = emitBinary(result.getValueKind(), Sra, a, g0.asValue(LIRKind.value(WORD)));
-                Variable bs = emitBinary(result.getValueKind(), Sra, b, g0.asValue(LIRKind.value(WORD)));
+                Value as = emitSignExtend(a);
+                Value bs = emitSignExtend(b);
                 q1 = emitBinary(as.getValueKind(), Sdivx, as, bs, state);
-                q2 = emitBinary(q1.getValueKind(), Mulx, q1, bs);
+                q2 = emitBinary(as.getValueKind(), Mulx, q1, bs);
                 result = emitSub(as, q2, false);
                 break;
             case XWORD:
-                aLoaded = getLIRGen().load(a); // Reuse the loaded value
-                q1 = emitBinary(result.getValueKind(), Sdivx, aLoaded, b, state);
+                q1 = emitBinary(result.getValueKind(), Sdivx, a, b, state);
                 q2 = emitBinary(result.getValueKind(), Mulx, q1, b);
-                result = emitSub(aLoaded, q2, false);
+                result = emitSub(a, q2, false);
                 break;
             case SINGLE:
                 ForeignCallLinkage fremCall = getLIRGen().getForeignCalls().lookupForeignCall(ARITHMETIC_FREM);
@@ -391,26 +377,14 @@
             default:
                 throw GraalError.shouldNotReachHere();
         }
-        getLIRGen().append(new RemOp(opcode, result, getLIRGen().load(a), getLIRGen().load(b), scratch1, scratch2, state));
+        getLIRGen().append(new RemOp(opcode, result, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b), scratch1, scratch2, state));
         return result;
 
     }
 
     @Override
     public Value emitUDiv(Value a, Value b, LIRFrameState state) {
-        Value actualA = a;
-        Value actualB = b;
-        switch (((SPARCKind) a.getPlatformKind())) {
-            case WORD:
-                actualA = emitZeroExtend(actualA, 32, 64);
-                actualB = emitZeroExtend(actualB, 32, 64);
-                break;
-            case XWORD:
-                break;
-            default:
-                throw GraalError.shouldNotReachHere();
-        }
-        return emitBinary(LIRKind.combine(actualA, actualB), Udivx, actualA, actualB, state);
+        return emitBinary(LIRKind.combine(a, b), Udivx, emitZeroExtend(a), emitZeroExtend(b), state);
     }
 
     @Override
@@ -601,6 +575,11 @@
         }
     }
 
+    private Value emitSignExtend(Value inputValue) {
+        int inputBits = inputValue.getPlatformKind().getSizeInBytes() * 8;
+        return emitNarrow(emitSignExtend(inputValue, inputBits, XWORD.getSizeInBits()), inputBits);
+    }
+
     @Override
     public Value emitSignExtend(Value inputVal, int fromBits, int toBits) {
         assert fromBits <= toBits && toBits <= XWORD.getSizeInBits();
@@ -632,6 +611,11 @@
         }
     }
 
+    private Value emitZeroExtend(Value inputValue) {
+        int inputBits = inputValue.getPlatformKind().getSizeInBytes() * 8;
+        return emitNarrow(emitZeroExtend(inputValue, inputBits, XWORD.getSizeInBits()), inputBits);
+    }
+
     @Override
     public Value emitZeroExtend(Value inputValue, int fromBits, int toBits) {
         assert fromBits <= toBits && toBits <= 64;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashCodeTest.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashCodeTest.java	Thu Jun 01 02:21:18 2017 +0000
@@ -22,18 +22,18 @@
  */
 package org.graalvm.compiler.core.test;
 
-import org.junit.Assert;
-import org.junit.Test;
-
 import org.graalvm.compiler.core.phases.HighTier;
 import org.graalvm.compiler.core.phases.MidTier;
 import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.extended.LoadHubNode;
 import org.graalvm.compiler.nodes.extended.LoadMethodNode;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.tiers.MidTierContext;
+import org.junit.Assert;
+import org.junit.Test;
 
 public class HashCodeTest extends GraalCompilerTest {
 
@@ -144,7 +144,9 @@
 
     private void checkForGuardedIntrinsicPattern(String name) {
         StructuredGraph g = parseForCompile(getResolvedJavaMethod(name));
-        Assert.assertEquals(1, g.getNodes().filter(InvokeNode.class).count());
+        int invokeNodeCount = g.getNodes().filter(InvokeNode.class).count();
+        int invokeWithExceptionNodeCount = g.getNodes().filter(InvokeWithExceptionNode.class).count();
+        Assert.assertEquals(1, invokeNodeCount + invokeWithExceptionNodeCount);
         Assert.assertEquals(1, g.getNodes().filter(LoadHubNode.class).count());
         Assert.assertEquals(1, g.getNodes().filter(LoadMethodNode.class).count());
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/RethrowDeoptMaterializeTest.java	Thu Jun 01 02:21:18 2017 +0000
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017, 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 org.graalvm.compiler.core.test.deopt;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.FrameState;
+import org.junit.Test;
+
+public final class RethrowDeoptMaterializeTest extends GraalCompilerTest {
+
+    private static final Object RETURN_VALUE = "1 2 3";
+    private static final RuntimeException DUMMY_EXCEPTION = new RuntimeException();
+
+    static class MyException extends RuntimeException {
+        private static final long serialVersionUID = 0L;
+
+        MyException(Throwable cause) {
+            super(cause);
+        }
+
+        @SuppressWarnings("sync-override")
+        @Override
+        public final Throwable fillInStackTrace() {
+            return null;
+        }
+    }
+
+    public static Object executeDeoptRethrow(int action) {
+
+        try {
+            if (action != 0) {
+                throw new MyException(DUMMY_EXCEPTION);
+            } else if (action == 1) {
+                throw new MyException(null);
+            }
+        } catch (RuntimeException t) {
+            Throwable e = t.getCause();
+            GraalDirectives.deoptimize();
+            if (e != DUMMY_EXCEPTION) {
+                throw t;
+            }
+        }
+        return RETURN_VALUE;
+    }
+
+    /**
+     * This tests that a state with {@link FrameState#rethrowException()} set to true can properly
+     * throw an exception that must be rematerialized.
+     */
+    @Test
+    public void testDeoptRethrow() {
+        test("executeDeoptRethrow", 1);
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java	Thu Jun 01 02:21:18 2017 +0000
@@ -770,7 +770,7 @@
      * @param object object to verify
      * @param message description of verification context
      *
-     * @see DebugVerifyHandler#verify(Object, String)
+     * @see DebugVerifyHandler#verify(java.lang.Object, java.lang.String, java.lang.Object...)
      */
     public static void verify(Object object, String message) {
         if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) {
@@ -786,7 +786,7 @@
      * @param format a format string for the description of the verification context
      * @param arg the argument referenced by the format specifiers in {@code format}
      *
-     * @see DebugVerifyHandler#verify(Object, String)
+     * @see DebugVerifyHandler#verify(java.lang.Object, java.lang.String, java.lang.Object...)
      */
     public static void verify(Object object, String format, Object arg) {
         if (ENABLED && DebugScope.getInstance().isVerifyEnabled()) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugDumpHandler.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugDumpHandler.java	Thu Jun 01 02:21:18 2017 +0000
@@ -26,7 +26,7 @@
 
 public interface DebugDumpHandler extends Closeable {
 
-    void dump(Object object, String message);
+    void dump(Object object, String format, Object... arguments);
 
     /**
      * Add arbitrary capability for use by the handler.
@@ -38,8 +38,8 @@
 
     /**
      * Flushes and releases resources managed by this dump handler. A subsequent call to
-     * {@link #dump(Object, String)} will create and open new resources. That is, this method can be
-     * used to reset the handler.
+     * {@link #dump(java.lang.Object, java.lang.String, java.lang.Object...)} will create and open
+     * new resources. That is, this method can be used to reset the handler.
      */
     @Override
     void close();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugEnvironment.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugEnvironment.java	Thu Jun 01 02:21:18 2017 +0000
@@ -70,7 +70,7 @@
             return null;
         }
         GraalDebugConfig debugConfig = (GraalDebugConfig) DebugScope.getConfig();
-        if (debugConfig == null || forceInit) {
+        if (debugConfig == null || forceInit || options != debugConfig.getOptions()) {
             // Initialize JVMCI before loading class Debug
             JVMCI.initialize();
             List<DebugDumpHandler> dumpHandlers = new ArrayList<>();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugVerifyHandler.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugVerifyHandler.java	Thu Jun 01 02:21:18 2017 +0000
@@ -31,7 +31,8 @@
      * Verifies that a given object satisfies some invariants.
      *
      * @param object object to verify
-     * @param message description of verification context
+     * @param format description of verification context
+     * @param args arguments for the format
      */
-    void verify(Object object, String message);
+    void verify(Object object, String format, Object... args);
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Fingerprint.java	Wed May 31 09:19:28 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,162 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.debug;
-
-import static org.graalvm.compiler.debug.Debug.DEBUG_OPTIONS;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import org.graalvm.compiler.options.Option;
-import org.graalvm.compiler.options.OptionKey;
-
-/**
- * Facility for fingerprinting execution.
- */
-public class Fingerprint implements AutoCloseable {
-
-    public static class Options {
-        @Option(help = "Enables execution fingerprinting.")//
-        public static final OptionKey<Boolean> UseFingerprinting = new OptionKey<>(false);
-
-        @Option(help = "Limit number of events shown in fingerprinting error message.")//
-        public static final OptionKey<Integer> FingerprintErrorEventTailLength = new OptionKey<>(50);
-
-        @Option(help = "Fingerprinting event at which to execute breakpointable code.")//
-        public static final OptionKey<Integer> FingerprintingBreakpointEvent = new OptionKey<>(-1);
-    }
-
-    /**
-     * Determines whether fingerprinting is enabled.
-     */
-    public static final boolean ENABLED = Options.UseFingerprinting.getValue(DEBUG_OPTIONS);
-
-    private static final ThreadLocal<Fingerprint> current = ENABLED ? new ThreadLocal<>() : null;
-
-    private final List<String> events;
-    private int index;
-
-    /**
-     * Creates an object to record a fingerprint.
-     */
-    public Fingerprint() {
-        events = new ArrayList<>();
-        index = -1;
-    }
-
-    /**
-     * Creates an object to verify execution matches a given fingerprint.
-     *
-     * @param toVerifyAgainst the fingerprint events to verify against
-     */
-    public Fingerprint(List<String> toVerifyAgainst) {
-        this.events = toVerifyAgainst;
-        index = 0;
-    }
-
-    /**
-     * Creates an object to verify execution matches a given fingerprint.
-     *
-     * @param toVerifyAgainst the fingerprint to verify against
-     */
-    public Fingerprint(Fingerprint toVerifyAgainst) {
-        this(toVerifyAgainst.events);
-    }
-
-    public Collection<String> getEvents() {
-        return Collections.unmodifiableCollection(events);
-    }
-
-    /**
-     * Starts fingerprint recording or verification for the current thread. At most one fingerprint
-     * object can be active for any thread.
-     */
-    public Fingerprint open() {
-        if (ENABLED) {
-            assert current.get() == null;
-            current.set(this);
-            return this;
-        }
-        return null;
-    }
-
-    /**
-     * Finishes fingerprint recording or verification for the current thread.
-     */
-    @Override
-    public void close() {
-        if (ENABLED) {
-            assert current.get() == this;
-            current.set(null);
-        }
-    }
-
-    private static final int BREAKPOINT_EVENT = Options.FingerprintingBreakpointEvent.getValue(DEBUG_OPTIONS);
-
-    /**
-     * Submits an execution event for the purpose of recording or verifying a fingerprint. This must
-     * only be called if {@link #ENABLED} is {@code true}.
-     */
-    public static void submit(String format, Object... args) {
-        assert ENABLED : "fingerprinting must be enabled (-Dgraal." + Options.UseFingerprinting.getName() + "=true)";
-        Fingerprint fingerprint = current.get();
-        if (fingerprint != null) {
-            int eventId = fingerprint.nextEventId();
-            if (eventId == BREAKPOINT_EVENT) {
-                // Set IDE breakpoint on the following line and set the relevant
-                // system property to debug a fingerprint verification error.
-                System.console();
-            }
-            fingerprint.event(String.format(eventId + ": " + format, args));
-        }
-    }
-
-    private int nextEventId() {
-        return index == -1 ? events.size() : index;
-    }
-
-    private static final int MAX_EVENT_TAIL_IN_ERROR_MESSAGE = Options.FingerprintErrorEventTailLength.getValue(DEBUG_OPTIONS);
-
-    private String tail() {
-        int start = Math.max(index - MAX_EVENT_TAIL_IN_ERROR_MESSAGE, 0);
-        return events.subList(start, index).stream().collect(Collectors.joining(String.format("%n")));
-    }
-
-    private void event(String entry) {
-        if (index == -1) {
-            events.add(entry);
-        } else {
-            if (index > events.size()) {
-                throw new InternalError(String.format("%s%nOriginal fingerprint limit reached", tail()));
-            }
-            String l = events.get(index);
-            if (!l.equals(entry)) {
-                throw new InternalError(String.format("%s%nFingerprint differs at event %d%nexpected: %s%n  actual: %s", tail(), index, l, entry));
-            }
-            index++;
-        }
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugScope.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugScope.java	Thu Jun 01 02:21:18 2017 +0000
@@ -333,9 +333,8 @@
         if (isDumpEnabled(dumpLevel)) {
             DebugConfig config = getConfig();
             if (config != null) {
-                String message = String.format(formatString, args);
                 for (DebugDumpHandler dumpHandler : config.dumpHandlers()) {
-                    dumpHandler.dump(object, message);
+                    dumpHandler.dump(object, formatString, args);
                 }
             }
         }
@@ -347,9 +346,8 @@
     public static void forceDump(Object object, String format, Object... args) {
         DebugConfig config = getConfig();
         if (config != null) {
-            String message = String.format(format, args);
             for (DebugDumpHandler dumpHandler : config.dumpHandlers()) {
-                dumpHandler.dump(object, message);
+                dumpHandler.dump(object, format, args);
             }
         } else {
             TTY.println("Forced dump ignored because debugging is disabled - use -Dgraal.ForceDebugEnable=true");
@@ -363,9 +361,8 @@
         if (isVerifyEnabled()) {
             DebugConfig config = getConfig();
             if (config != null) {
-                String message = String.format(formatString, args);
                 for (DebugVerifyHandler handler : config.verifyHandlers()) {
-                    handler.verify(object, message);
+                    handler.verify(object, formatString, args);
                 }
             }
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/.checkstyle_checks.xml	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/.checkstyle_checks.xml	Thu Jun 01 02:21:18 2017 +0000
@@ -161,7 +161,8 @@
     </module>
   </module>
   <module name="RegexpHeader">
-    <property name="header" value="/\*\n \* Copyright \(c\) (20[0-9][0-9], )?20[0-9][0-9], Oracle and/or its affiliates. All rights reserved.\n \* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n \*\n \* This code is free software; you can redistribute it and/or modify it\n \* under the terms of the GNU General Public License version 2 only, as\n \* published by the Free Software Foundation.\n \*\n \* This code is distributed in the hope that it will be useful, but WITHOUT\n \* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n \* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n \* version 2 for more details \(a copy is included in the LICENSE file that\n \* accompanied this code\).\n \*\n \* You should have received a copy of the GNU General Public License version\n \* 2 along with this work; if not, write to the Free Software Foundation,\n \* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n \*\n \* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n \* or visit www.oracle.com if you need additional information or have any\n \* questions.\n \*/\n"/>
+    <property name="header" value="/\*\n \* Copyright \(c\) (20[0-9][0-9], )?20[0-9][0-9], Oracle and/or its affiliates\. All rights reserved\.\n \* Copyright \(c\) (20[0-9][0-9], )?20[0-9][0-9], .*\. All rights reserved\.\n \* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER\.\n \*\n \* This code is free software; you can redistribute it and/or modify it\n \* under the terms of the GNU General Public License version 2 only, as\n \* published by the Free Software Foundation\.\n \*\n \* This code is distributed in the hope that it will be useful, but WITHOUT\n \* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n \* FITNESS FOR A PARTICULAR PURPOSE\.  See the GNU General Public License\n \* version 2 for more details \(a copy is included in the LICENSE file that\n \* accompanied this code\)\.\n \*\n \* You should have received a copy of the GNU General Public License version\n \* 2 along with this work; if not, write to the Free Software Foundation,\n \* Inc\., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\.\n \*\n \* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n \* or visit www\.oracle\.com if you need additional information or have any\n \* questions\.\n \*/\n"/>
+    <property name="multiLines" value="3"/>
     <property name="fileExtensions" value="java"/>
   </module>
   <module name="FileTabCharacter">
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java	Thu Jun 01 02:21:18 2017 +0000
@@ -22,19 +22,10 @@
  */
 package org.graalvm.compiler.graph;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.function.Consumer;
-
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugCounter;
 import org.graalvm.compiler.debug.DebugTimer;
-import org.graalvm.compiler.debug.Fingerprint;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Node.ValueNumberable;
 import org.graalvm.compiler.graph.iterators.NodeIterable;
@@ -46,6 +37,14 @@
 import org.graalvm.util.Equivalence;
 import org.graalvm.util.UnmodifiableEconomicMap;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.function.Consumer;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
 /**
  * This class is a graph container, it contains the set of nodes that belong to this graph.
  */
@@ -982,9 +981,6 @@
         if (nodeEventListener != null) {
             nodeEventListener.nodeAdded(node);
         }
-        if (Fingerprint.ENABLED) {
-            Fingerprint.submit("%s: %s", NodeEvent.NODE_ADDED, node);
-        }
         afterRegister(node);
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java	Thu Jun 01 02:21:18 2017 +0000
@@ -43,8 +43,6 @@
 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.debug.DebugCloseable;
-import org.graalvm.compiler.debug.Fingerprint;
-import org.graalvm.compiler.graph.Graph.NodeEvent;
 import org.graalvm.compiler.graph.Graph.NodeEventListener;
 import org.graalvm.compiler.graph.Graph.Options;
 import org.graalvm.compiler.graph.iterators.NodeIterable;
@@ -738,9 +736,6 @@
             if (listener != null) {
                 listener.inputChanged(node);
             }
-            if (Fingerprint.ENABLED) {
-                Fingerprint.submit("%s: %s", NodeEvent.INPUT_CHANGED, node);
-            }
         }
     }
 
@@ -751,9 +746,6 @@
             if (listener != null && node.isAlive()) {
                 listener.usagesDroppedToZero(node);
             }
-            if (Fingerprint.ENABLED) {
-                Fingerprint.submit("%s: %s", NodeEvent.ZERO_USAGES, node);
-            }
         }
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java	Thu Jun 01 02:21:18 2017 +0000
@@ -49,7 +49,6 @@
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugCounter;
 import org.graalvm.compiler.debug.DebugTimer;
-import org.graalvm.compiler.debug.Fingerprint;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Edges.Type;
 import org.graalvm.compiler.graph.Graph.DuplicationReplacement;
@@ -810,10 +809,11 @@
 
     /**
      * The template used to build the {@link Verbosity#Name} version. Variable parts are specified
-     * using &#123;i#inputName&#125; or &#123;p#propertyName&#125;.
+     * using &#123;i#inputName&#125; or &#123;p#propertyName&#125;. Returns empty string if no
+     * special name template is specified.
      */
     public String getNameTemplate() {
-        return nameTemplate.isEmpty() ? shortName() : nameTemplate;
+        return nameTemplate;
     }
 
     interface InplaceUpdateClosure {
@@ -879,15 +879,9 @@
                     replacement = replacements.replacement(node);
                 }
                 if (replacement != node) {
-                    if (Fingerprint.ENABLED) {
-                        Fingerprint.submit("replacing %s with %s", node, replacement);
-                    }
                     assert replacement != null;
                     newNodes.put(node, replacement);
                 } else {
-                    if (Fingerprint.ENABLED) {
-                        Fingerprint.submit("duplicating %s", node);
-                    }
                     Node newNode = node.clone(graph, WithAllEdges);
                     assert newNode.getNodeClass().isLeafNode() || newNode.hasNoUsages();
                     assert newNode.getClass() == node.getClass();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalMBeanTest.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalMBeanTest.java	Thu Jun 01 02:21:18 2017 +0000
@@ -24,17 +24,21 @@
 
 import java.lang.management.ManagementFactory;
 import java.lang.reflect.Field;
+import javax.management.Attribute;
 import javax.management.MBeanAttributeInfo;
 import javax.management.MBeanInfo;
 import javax.management.MBeanServer;
 import javax.management.ObjectInstance;
 import javax.management.ObjectName;
 import org.graalvm.compiler.hotspot.HotSpotGraalMBean;
-import static org.junit.Assert.assertFalse;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.util.EconomicMap;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 import org.junit.Test;
 
 public class HotSpotGraalMBeanTest {
@@ -80,18 +84,73 @@
 
         HotSpotGraalMBean realBean = HotSpotGraalMBean.create();
         assertNotNull("Bean is registered", name = realBean.ensureRegistered(false));
+        final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
 
-        ObjectInstance bean = ManagementFactory.getPlatformMBeanServer().getObjectInstance(name);
+        ObjectInstance bean = server.getObjectInstance(name);
         assertNotNull("Bean is registered", bean);
-        MBeanInfo info = ManagementFactory.getPlatformMBeanServer().getMBeanInfo(name);
+        MBeanInfo info = server.getMBeanInfo(name);
         assertNotNull("Info is found", info);
+
+        MBeanAttributeInfo printCompilation = findAttributeInfo("PrintCompilation", info);
+        assertNotNull("PrintCompilation found", printCompilation);
+        assertEquals("true/false", Boolean.class.getName(), printCompilation.getType());
+
+        Attribute printOn = new Attribute(printCompilation.getName(), Boolean.TRUE);
+
+        Object before = server.getAttribute(name, printCompilation.getName());
+        server.setAttribute(name, printOn);
+        Object after = server.getAttribute(name, printCompilation.getName());
+
+        assertNull("Default value was not set", before);
+        assertEquals("Changed to on", Boolean.TRUE, after);
+    }
+
+    private static MBeanAttributeInfo findAttributeInfo(String attrName, MBeanInfo info) {
+        MBeanAttributeInfo printCompilation = null;
         for (MBeanAttributeInfo attr : info.getAttributes()) {
-            if (attr.getName().equals("Dump")) {
-                assertFalse("Read only now", attr.isWritable());
+            if (attr.getName().equals(attrName)) {
                 assertTrue("Readable", attr.isReadable());
-                return;
+                assertTrue("Writable", attr.isWritable());
+                printCompilation = attr;
+                break;
             }
         }
-        fail("No Dump attribute found");
+        return printCompilation;
     }
+
+    @Test
+    public void optionsAreCached() throws Exception {
+        ObjectName name;
+
+        assertNotNull("Server is started", ManagementFactory.getPlatformMBeanServer());
+
+        HotSpotGraalMBean realBean = HotSpotGraalMBean.create();
+
+        OptionValues original = new OptionValues(EconomicMap.create());
+
+        assertSame(original, realBean.optionsFor(original, null));
+
+        assertNotNull("Bean is registered", name = realBean.ensureRegistered(false));
+        final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+
+        ObjectInstance bean = server.getObjectInstance(name);
+        assertNotNull("Bean is registered", bean);
+        MBeanInfo info = server.getMBeanInfo(name);
+        assertNotNull("Info is found", info);
+
+        MBeanAttributeInfo dump = findAttributeInfo("Dump", info);
+
+        Attribute dumpTo1 = new Attribute(dump.getName(), 1);
+
+        server.setAttribute(name, dumpTo1);
+        Object after = server.getAttribute(name, dump.getName());
+        assertEquals(1, after);
+
+        final OptionValues modified1 = realBean.optionsFor(original, null);
+        assertNotSame(original, modified1);
+        final OptionValues modified2 = realBean.optionsFor(original, null);
+        assertSame("Options are cached", modified1, modified2);
+
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ObjectCloneTest.java	Thu Jun 01 02:21:18 2017 +0000
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2017, 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 org.graalvm.compiler.hotspot.test;
+
+import java.util.ArrayList;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.junit.Test;
+
+/**
+ * Exercise intrinsification of {@link Object#clone}.
+ */
+public class ObjectCloneTest extends GraalCompilerTest {
+
+    public static Object cloneArray(int[] array) {
+        return array.clone();
+    }
+
+    public static Object cloneList(ArrayList<?> list) {
+        return list.clone();
+    }
+
+    static class ObjectCloneable implements Cloneable {
+        int field;
+
+        @Override
+        protected Object clone() throws CloneNotSupportedException {
+            try {
+                return super.clone();
+            } catch (CloneNotSupportedException e) {
+                throw new AssertionError();
+            }
+        }
+    }
+
+    static class CloneableSubclass extends ObjectCloneable {
+
+    }
+
+    /*
+     * This test checks that the ObjectCloneNode doesn't accidentally inject non-nullness into the
+     * graph which is later removed.
+     */
+    public static Object notCloneable(ObjectCloneable cloneable) throws CloneNotSupportedException {
+        ObjectCloneable clone = (ObjectCloneable) cloneable.clone();
+        return clone.getClass();
+    }
+
+    @Test
+    public void testNotIntrinsified() throws Throwable {
+        test("notCloneable", new CloneableSubclass());
+    }
+
+    @Test
+    public void testArray() throws Throwable {
+        test("cloneArray", new int[]{1, 2, 4, 3});
+    }
+
+    @Test
+    public void testList() throws Throwable {
+        ArrayList<Object> list = new ArrayList<>();
+        for (int i = 0; i < 4; i++) {
+            list.add(i);
+        }
+        test("cloneList", list);
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/OptionsInFileTest.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/OptionsInFileTest.java	Thu Jun 01 02:21:18 2017 +0000
@@ -51,7 +51,7 @@
         File optionsFile = File.createTempFile("options", ".properties").getAbsoluteFile();
         try {
             Assert.assertFalse(methodFilterValue.equals(MethodFilter.getDefaultValue()));
-            Assert.assertFalse(debugFilterValue.equals(PrintGraph.getDefaultValue()));
+            Assert.assertFalse(debugFilterValue.equals(Dump.getDefaultValue()));
             Assert.assertTrue(PrintGraph.getDefaultValue());
 
             try (PrintStream out = new PrintStream(new FileOutputStream(optionsFile))) {
@@ -61,6 +61,7 @@
             }
 
             List<String> vmArgs = withoutDebuggerArguments(getVMCommandLine());
+            vmArgs.removeIf(a -> a.startsWith("-Dgraal."));
             vmArgs.add("-Dgraal.options.file=" + optionsFile);
             vmArgs.add("-XX:+JVMCIPrintProperties");
             Subprocess proc = SubprocessUtil.java(vmArgs);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/RetryableCompilationTest.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/RetryableCompilationTest.java	Thu Jun 01 02:21:18 2017 +0000
@@ -63,6 +63,9 @@
 
     private static void testHelper(List<String> extraVmArgs, String... mainClassAndArgs) throws IOException, InterruptedException {
         List<String> vmArgs = withoutDebuggerArguments(getVMCommandLine());
+        vmArgs.removeIf(a -> a.startsWith("-Dgraal."));
+        // Force output to a file even if there's a running IGV instance available.
+        vmArgs.add("-Dgraal.PrintGraphFile=true");
         vmArgs.addAll(extraVmArgs);
 
         Subprocess proc = SubprocessUtil.java(vmArgs, mainClassAndArgs);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDebugInfoBuilder.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDebugInfoBuilder.java	Thu Jun 01 02:21:18 2017 +0000
@@ -24,8 +24,14 @@
 
 import static jdk.vm.ci.code.BytecodeFrame.isPlaceholderBci;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.core.gen.DebugInfoBuilder;
-import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.GraalGraphError;
+import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.lir.VirtualStackSlot;
 import org.graalvm.compiler.nodes.FrameState;
 import org.graalvm.compiler.nodes.ValueNode;
@@ -36,6 +42,8 @@
 import jdk.vm.ci.code.VirtualObject;
 import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
 import jdk.vm.ci.meta.JavaValue;
+import jdk.vm.ci.meta.MetaUtil;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /**
  * Extends {@link DebugInfoBuilder} to allocate the extra debug information required for locks.
@@ -79,11 +87,40 @@
     @Override
     protected BytecodeFrame computeFrameForState(FrameState state) {
         if (isPlaceholderBci(state.bci) && state.bci != BytecodeFrame.BEFORE_BCI) {
-            // This is really a hard error since an incorrect state could crash hotspot
-            throw GraalError.shouldNotReachHere("Invalid state " + BytecodeFrame.getPlaceholderBciName(state.bci) + " " + state);
+            raiseInvalidFrameStateError(state);
         }
         BytecodeFrame result = super.computeFrameForState(state);
         maxInterpreterFrameSize = Math.max(maxInterpreterFrameSize, codeCacheProvider.interpreterFrameSize(result));
         return result;
     }
+
+    protected void raiseInvalidFrameStateError(FrameState state) throws GraalGraphError {
+        // This is a hard error since an incorrect state could crash hotspot
+        NodeSourcePosition sourcePosition = state.getNodeSourcePosition();
+        List<String> context = new ArrayList<>();
+        ResolvedJavaMethod replacementMethodWithProblematicSideEffect = null;
+        if (sourcePosition != null) {
+            NodeSourcePosition pos = sourcePosition;
+            while (pos != null) {
+                StringBuilder sb = new StringBuilder("parsing ");
+                ResolvedJavaMethod method = pos.getMethod();
+                MetaUtil.appendLocation(sb, method, pos.getBCI());
+                if (method.getAnnotation(MethodSubstitution.class) != null ||
+                                method.getAnnotation(Snippet.class) != null) {
+                    replacementMethodWithProblematicSideEffect = method;
+                }
+                context.add(sb.toString());
+                pos = pos.getCaller();
+            }
+        }
+        String message = "Invalid frame state " + state;
+        if (replacementMethodWithProblematicSideEffect != null) {
+            message += " associated with a side effect in " + replacementMethodWithProblematicSideEffect.format("%H.%n(%p)") + " at a position that cannot be deoptimized to";
+        }
+        GraalGraphError error = new GraalGraphError(message);
+        for (String c : context) {
+            error.addContext(c);
+        }
+        throw error;
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalMBean.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalMBean.java	Thu Jun 01 02:21:18 2017 +0000
@@ -25,14 +25,12 @@
 import java.lang.management.ManagementFactory;
 import java.lang.reflect.Field;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 import javax.management.Attribute;
 import javax.management.AttributeList;
 import javax.management.AttributeNotFoundException;
 import javax.management.DynamicMBean;
 import javax.management.InstanceAlreadyExistsException;
-import javax.management.InvalidAttributeValueException;
 import javax.management.MBeanAttributeInfo;
 import javax.management.MBeanException;
 import javax.management.MBeanInfo;
@@ -49,12 +47,14 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.options.OptionsParser;
 import org.graalvm.util.EconomicMap;
+import org.graalvm.util.UnmodifiableEconomicMap;
 
 public final class HotSpotGraalMBean implements DynamicMBean {
     private static Object mBeanServerField;
     private final OptionValues options;
     private final EconomicMap<OptionKey<?>, Object> changes;
     private ObjectName registered;
+    private OptionValues cachedOptions;
 
     private HotSpotGraalMBean(OptionValues options) {
         this.options = options;
@@ -112,27 +112,51 @@
     }
 
     @SuppressWarnings("unused")
-    OptionValues optionsFor(OptionValues values, ResolvedJavaMethod forMethod) {
+    public OptionValues optionsFor(OptionValues initialValues, ResolvedJavaMethod forMethod) {
         ensureRegistered(true);
+        return currentMap(initialValues);
+    }
+
+    private OptionValues currentMap(OptionValues initialValues) {
         if (changes.isEmpty()) {
-            return values;
+            return initialValues;
         }
-        return new OptionValues(values, changes);
+        OptionValues current = cachedOptions;
+        if (current == null) {
+            current = new OptionValues(initialValues, changes);
+            cachedOptions = current;
+        }
+        return current;
     }
 
     @Override
     public Object getAttribute(String attribute) {
-        for (OptionKey<?> k : options.getMap().getKeys()) {
+        UnmodifiableEconomicMap<OptionKey<?>, Object> map = currentMap(options).getMap();
+        for (OptionKey<?> k : map.getKeys()) {
             if (k.getName().equals(attribute)) {
-                return options.getMap().get(k);
+                return map.get(k);
             }
         }
         return null;
     }
 
     @Override
-    public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
-        throw new InvalidAttributeValueException();
+    public void setAttribute(Attribute attribute) throws AttributeNotFoundException {
+        Attribute newAttr = setImpl(attribute);
+        if (newAttr == null) {
+            throw new AttributeNotFoundException();
+        }
+    }
+
+    private Attribute setImpl(Attribute attribute) {
+        cachedOptions = null;
+        for (OptionDescriptor option : allOptionDescriptors()) {
+            if (option.getName().equals(attribute.getName())) {
+                changes.put(option.getOptionKey(), attribute.getValue());
+                return attribute;
+            }
+        }
+        return null;
     }
 
     @Override
@@ -149,7 +173,14 @@
 
     @Override
     public AttributeList setAttributes(AttributeList attributes) {
-        throw new IllegalStateException();
+        AttributeList setOk = new AttributeList();
+        for (Attribute attr : attributes.asList()) {
+            Attribute newAttr = setImpl(attr);
+            if (newAttr != null) {
+                setOk.add(newAttr);
+            }
+        }
+        return setOk;
     }
 
     @Override
@@ -161,10 +192,8 @@
     public MBeanInfo getMBeanInfo() {
         List<MBeanAttributeInfo> attrs = new ArrayList<>();
         if (registered != null) {
-            for (Iterator<OptionDescriptors> it = OptionsParser.getOptionsLoader().iterator(); it.hasNext();) {
-                for (OptionDescriptor descr : it.next()) {
-                    attrs.add(new MBeanAttributeInfo(descr.getName(), descr.getType().getName(), descr.getHelp(), true, false, false));
-                }
+            for (OptionDescriptor descr : allOptionDescriptors()) {
+                attrs.add(new MBeanAttributeInfo(descr.getName(), descr.getType().getName(), descr.getHelp(), true, true, false));
             }
         }
         return new MBeanInfo(
@@ -174,4 +203,14 @@
                         null, null, null);
     }
 
+    private static Iterable<OptionDescriptor> allOptionDescriptors() {
+        List<OptionDescriptor> arr = new ArrayList<>();
+        for (OptionDescriptors set : OptionsParser.getOptionsLoader()) {
+            for (OptionDescriptor descr : set) {
+                arr.add(descr);
+            }
+        }
+        return arr;
+    }
+
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java	Thu Jun 01 02:21:18 2017 +0000
@@ -88,7 +88,6 @@
 import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyFixedNode;
 import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode;
 import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
-import org.graalvm.compiler.hotspot.replacements.aot.ResolveConstantSnippets;
 import org.graalvm.compiler.hotspot.word.KlassPointer;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.DeoptimizeNode;
@@ -299,7 +298,7 @@
     public static Object allocateArrayPIC(KlassPointer hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize,
                     @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, @ConstantParameter String typeContext,
                     @ConstantParameter OptionValues options, @ConstantParameter Counters counters) {
-        KlassPointer picHub = ResolveConstantSnippets.resolveKlassConstant(hub);
+        KlassPointer picHub = LoadConstantIndirectlyFixedNode.loadKlass(hub);
         return allocateArrayImpl(picHub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, false, options, counters);
     }
 
@@ -415,8 +414,8 @@
 
     @Snippet
     public static Object newmultiarrayPIC(KlassPointer hub, @ConstantParameter int rank, @VarargsParameter int[] dimensions) {
-        KlassPointer hubPIC = ResolveConstantSnippets.resolveKlassConstant(hub);
-        return newmultiarray(hubPIC, rank, dimensions);
+        KlassPointer picHub = LoadConstantIndirectlyFixedNode.loadKlass(hub);
+        return newmultiarray(picHub, rank, dimensions);
     }
 
     @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true)
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneNode.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneNode.java	Thu Jun 01 02:21:18 2017 +0000
@@ -24,6 +24,8 @@
 
 import java.lang.reflect.Method;
 
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampPair;
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.Debug.Scope;
@@ -60,6 +62,18 @@
     }
 
     @Override
+    protected Stamp computeStamp(ValueNode object) {
+        if (getConcreteType(object.stamp()) != null) {
+            return AbstractPointerStamp.pointerNonNull(object.stamp());
+        }
+        /*
+         * If this call can't be intrinsified don't report a non-null stamp, otherwise the stamp
+         * would change when this is lowered back to an invoke and we might lose a null check.
+         */
+        return AbstractPointerStamp.pointerMaybeNull(object.stamp());
+    }
+
+    @Override
     @SuppressWarnings("try")
     protected StructuredGraph getLoweredSnippetGraph(LoweringTool tool) {
         ResolvedJavaType type = StampTool.typeOrNull(getObject());
@@ -77,6 +91,7 @@
                     }
 
                     assert snippetGraph != null : "ObjectCloneSnippets should be installed";
+                    assert getConcreteType(stamp()) != null;
                     return lowerReplacement((StructuredGraph) snippetGraph.copy(), tool);
                 }
                 assert false : "unhandled array type " + type.getComponentType().getJavaKind();
@@ -96,10 +111,12 @@
                         newGraph.addBeforeFixed(returnNode, load);
                         newGraph.addBeforeFixed(returnNode, newGraph.add(new StoreFieldNode(newInstance, field, load)));
                     }
+                    assert getConcreteType(stamp()) != null;
                     return lowerReplacement(newGraph, tool);
                 }
             }
         }
+        assert getConcreteType(stamp()) == null;
         return null;
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Thu Jun 01 02:21:18 2017 +0000
@@ -248,6 +248,7 @@
 import static org.graalvm.compiler.debug.GraalError.guarantee;
 import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere;
 import static org.graalvm.compiler.java.BytecodeParserOptions.DumpWithInfopoints;
+import static org.graalvm.compiler.java.BytecodeParserOptions.InlinePartialIntrinsicExitDuringParsing;
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceBytecodeParserLevel;
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceInlineDuringParsing;
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceParserPlugins;
@@ -264,6 +265,7 @@
 import java.util.List;
 
 import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.bytecode.BytecodeDisassembler;
 import org.graalvm.compiler.bytecode.BytecodeLookupSwitch;
@@ -463,6 +465,7 @@
         FrameState stateBefore;
         final Mark mark;
         final BytecodeParser parser;
+        List<ReturnToCallerData> returnDataList;
 
         /**
          * Creates a scope for root parsing an intrinsic.
@@ -504,46 +507,50 @@
          * added to the graph while parsing/inlining the intrinsic for which this object exists.
          */
         private void processPlaceholderFrameStates(IntrinsicContext intrinsic) {
-            FrameState stateAfterReturn = null;
             StructuredGraph graph = parser.getGraph();
             for (Node node : graph.getNewNodes(mark)) {
                 if (node instanceof FrameState) {
                     FrameState frameState = (FrameState) node;
                     if (BytecodeFrame.isPlaceholderBci(frameState.bci)) {
                         if (frameState.bci == BytecodeFrame.AFTER_BCI) {
-                            FrameStateBuilder frameStateBuilder = parser.frameState;
-                            if (frameState.stackSize() != 0) {
-                                assert frameState.usages().count() == 1;
-                                ValueNode returnVal = frameState.stackAt(0);
-                                assert returnVal == frameState.usages().first();
-
-                                if (parser.currentInvokeReturnType == null) {
-                                    assert intrinsic.isCompilationRoot();
-                                    FrameState newFrameState = graph.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI));
-                                    frameState.replaceAndDelete(newFrameState);
-                                } else {
-                                    /*
-                                     * Swap the top-of-stack value with the side-effect return value
-                                     * using the frame state.
-                                     */
-                                    JavaKind returnKind = parser.currentInvokeReturnType.getJavaKind();
+                            if (parser.getInvokeReturnType() == null) {
+                                // A frame state in a root compiled intrinsic.
+                                assert intrinsic.isCompilationRoot();
+                                FrameState newFrameState = graph.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI));
+                                frameState.replaceAndDelete(newFrameState);
+                            } else {
+                                JavaKind returnKind = parser.getInvokeReturnType().getJavaKind();
+                                FrameStateBuilder frameStateBuilder = parser.frameState;
+                                assert !frameState.rethrowException();
+                                if (frameState.stackSize() != 0) {
+                                    ValueNode returnVal = frameState.stackAt(0);
+                                    if (!ReturnToCallerData.containsReturnValue(returnDataList, returnVal)) {
+                                        throw new GraalError("AFTER_BCI frame state within an intrinsic has a non-return value on the stack: %s", returnVal);
+                                    }
+
+                                    // Swap the top-of-stack value with the return value
                                     ValueNode tos = frameStateBuilder.pop(returnKind);
                                     assert tos.getStackKind() == returnVal.getStackKind();
                                     FrameState newFrameState = frameStateBuilder.create(parser.stream.nextBCI(), parser.getNonIntrinsicAncestor(), false, new JavaKind[]{returnKind},
                                                     new ValueNode[]{returnVal});
                                     frameState.replaceAndDelete(newFrameState);
+                                    newFrameState.setNodeSourcePosition(frameState.getNodeSourcePosition());
                                     frameStateBuilder.push(returnKind, tos);
+                                } else if (returnKind != JavaKind.Void) {
+                                    // If the intrinsic returns a non-void value, then any frame
+                                    // state with an empty stack is invalid as it cannot
+                                    // be used to deoptimize to just after the call returns.
+                                    // These invalid frame states are expected to be removed
+                                    // by later compilation stages.
+                                    FrameState newFrameState = graph.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI));
+                                    newFrameState.setNodeSourcePosition(frameState.getNodeSourcePosition());
+                                    frameState.replaceAndDelete(newFrameState);
+                                } else {
+                                    // An intrinsic for a void method.
+                                    FrameState newFrameState = frameStateBuilder.create(parser.stream.nextBCI(), null);
+                                    newFrameState.setNodeSourcePosition(frameState.getNodeSourcePosition());
+                                    frameState.replaceAndDelete(newFrameState);
                                 }
-                            } else {
-                                if (stateAfterReturn == null) {
-                                    if (intrinsic != null) {
-                                        assert intrinsic.isCompilationRoot();
-                                        stateAfterReturn = graph.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI));
-                                    } else {
-                                        stateAfterReturn = frameStateBuilder.create(parser.stream.nextBCI(), null);
-                                    }
-                                }
-                                frameState.replaceAndDelete(stateAfterReturn);
                             }
                         } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) {
                             if (stateBefore == null) {
@@ -552,6 +559,24 @@
                             if (stateBefore != frameState) {
                                 frameState.replaceAndDelete(stateBefore);
                             }
+                        } else if (frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
+                            // This is a frame state for the entry point to an exception
+                            // dispatcher in an intrinsic. For example, the invoke denoting
+                            // a partial intrinsic exit will have an edge to such a
+                            // dispatcher if the profile for the original invoke being
+                            // intrinsified indicates an exception was seen. As per JVM
+                            // bytecode semantics, the interpreter expects a single
+                            // value on the stack on entry to an exception handler,
+                            // namely the exception object.
+                            assert frameState.rethrowException();
+                            ExceptionObjectNode exceptionObject = (ExceptionObjectNode) frameState.stackAt(0);
+                            FrameStateBuilder dispatchState = parser.frameState.copy();
+                            dispatchState.clearStack();
+                            dispatchState.push(JavaKind.Object, exceptionObject);
+                            dispatchState.setRethrowException(true);
+                            FrameState newFrameState = dispatchState.create(parser.bci(), exceptionObject);
+                            frameState.replaceAndDelete(newFrameState);
+                            newFrameState.setNodeSourcePosition(frameState.getNodeSourcePosition());
                         } else {
                             assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI;
                         }
@@ -591,6 +616,15 @@
             this.returnValue = returnValue;
             this.beforeReturnNode = beforeReturnNode;
         }
+
+        static boolean containsReturnValue(List<ReturnToCallerData> list, ValueNode value) {
+            for (ReturnToCallerData e : list) {
+                if (e.returnValue == value) {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 
     private final GraphBuilderPhase.Instance graphBuilderInstance;
@@ -1333,8 +1367,19 @@
         }
     }
 
-    private InvokeKind currentInvokeKind;
-    private JavaType currentInvokeReturnType;
+    static class CurrentInvoke {
+        final ValueNode[] args;
+        final InvokeKind kind;
+        final JavaType returnType;
+
+        CurrentInvoke(ValueNode[] args, InvokeKind kind, JavaType returnType) {
+            this.args = args;
+            this.kind = kind;
+            this.returnType = returnType;
+        }
+    }
+
+    private CurrentInvoke currentInvoke;
     protected FrameStateBuilder frameState;
     protected BciBlock currentBlock;
     protected final BytecodeStream stream;
@@ -1353,12 +1398,12 @@
 
     @Override
     public InvokeKind getInvokeKind() {
-        return currentInvokeKind;
+        return currentInvoke == null ? null : currentInvoke.kind;
     }
 
     @Override
     public JavaType getInvokeReturnType() {
-        return currentInvokeReturnType;
+        return currentInvoke == null ? null : currentInvoke.returnType;
     }
 
     private boolean forceInliningEverything;
@@ -1376,7 +1421,9 @@
 
     @Override
     public void handleReplacedInvoke(CallTargetNode callTarget, JavaKind resultType) {
-        createNonInlinedInvoke(bci(), callTarget, resultType, null);
+        BytecodeParser intrinsicCallSiteParser = getNonIntrinsicAncestor();
+        boolean withExceptionEdge = intrinsicCallSiteParser == null ? false : intrinsicCallSiteParser.omitInvokeExceptionEdge(null);
+        createNonInlinedInvoke(withExceptionEdge, bci(), callTarget, resultType);
     }
 
     private Invoke appendInvoke(InvokeKind initialInvokeKind, ResolvedJavaMethod initialTargetMethod, ValueNode[] args) {
@@ -1408,8 +1455,7 @@
 
         InlineInfo inlineInfo = null;
         try {
-            currentInvokeReturnType = returnType;
-            currentInvokeKind = invokeKind;
+            currentInvoke = new CurrentInvoke(args, invokeKind, returnType);
             if (tryNodePluginForInvocation(args, targetMethod)) {
                 if (TraceParserPlugins.getValue(options)) {
                     traceWithContext("used node plugin for %s", targetMethod.format("%h.%n(%p)"));
@@ -1438,15 +1484,35 @@
                 }
             }
         } finally {
-            currentInvokeReturnType = null;
-            currentInvokeKind = null;
+            currentInvoke = null;
         }
 
-        int bci = bci();
+        int invokeBci = bci();
+        JavaTypeProfile profile = getProfileForInvoke(invokeKind);
+        boolean withExceptionEdge = !omitInvokeExceptionEdge(inlineInfo);
         boolean partialIntrinsicExit = false;
         if (intrinsicContext != null && intrinsicContext.isCallToOriginal(targetMethod)) {
             partialIntrinsicExit = true;
             ResolvedJavaMethod originalMethod = intrinsicContext.getOriginalMethod();
+            BytecodeParser intrinsicCallSiteParser = getNonIntrinsicAncestor();
+            if (intrinsicCallSiteParser != null) {
+                // When exiting a partial intrinsic, the invoke to the original
+                // must use the same context as the call to the intrinsic.
+                invokeBci = intrinsicCallSiteParser.bci();
+                profile = intrinsicCallSiteParser.getProfileForInvoke(invokeKind);
+                withExceptionEdge = !intrinsicCallSiteParser.omitInvokeExceptionEdge(inlineInfo);
+            } else {
+                // We are parsing the intrinsic for the root compilation or for inlining,
+                // This call is a partial intrinsic exit, and we do not have profile information
+                // for this callsite. We also have to assume that the call needs an exception
+                // edge. Finally, we know that this intrinsic is parsed for late inlining,
+                // so the bci must be set to unknown, so that the inliner patches it later.
+                assert intrinsicContext.isPostParseInlined();
+                invokeBci = BytecodeFrame.UNKNOWN_BCI;
+                profile = null;
+                withExceptionEdge = graph.method().getAnnotation(Snippet.class) == null;
+            }
+
             if (originalMethod.isStatic()) {
                 invokeKind = InvokeKind.Static;
             } else {
@@ -1457,15 +1523,10 @@
             Signature sig = originalMethod.getSignature();
             returnType = sig.getReturnType(method.getDeclaringClass());
             resultType = sig.getReturnKind();
-            bci = intrinsicContext.bci();
-            assert checkPartialIntrinsicExit(args);
+            assert checkPartialIntrinsicExit(intrinsicCallSiteParser == null ? null : intrinsicCallSiteParser.currentInvoke.args, args);
             targetMethod = originalMethod;
         }
-        JavaTypeProfile profile = null;
-        if (invokeKind.isIndirect() && profilingInfo != null && this.optimisticOpts.useTypeCheckHints(getOptions())) {
-            profile = profilingInfo.getTypeProfile(bci());
-        }
-        Invoke invoke = createNonInlinedInvoke(args, bci, targetMethod, invokeKind, resultType, returnType, inlineInfo, profile);
+        Invoke invoke = createNonInlinedInvoke(withExceptionEdge, invokeBci, args, targetMethod, invokeKind, resultType, returnType, profile);
         if (partialIntrinsicExit) {
             // This invoke must never be later inlined as it might select the intrinsic graph.
             // Until there is a mechanism to guarantee that any late inlining will not select
@@ -1475,24 +1536,30 @@
         return invoke;
     }
 
+    protected JavaTypeProfile getProfileForInvoke(InvokeKind invokeKind) {
+        if (invokeKind.isIndirect() && profilingInfo != null && this.optimisticOpts.useTypeCheckHints(getOptions())) {
+            return profilingInfo.getTypeProfile(bci());
+        }
+        return null;
+    }
+
     /**
      * A partial intrinsic exits by (effectively) calling the intrinsified method. This call must
      * use exactly the arguments to the call being intrinsified.
      *
-     * @param args arguments of recursive call to intrinsified method
+     * @param originalArgs arguments of original call to intrinsified method
+     * @param recursiveArgs arguments of recursive call to intrinsified method
      */
-    private boolean checkPartialIntrinsicExit(ValueNode[] args) {
-        if (intrinsicContext.getArgs() != null) {
-            assert intrinsicContext.bci() >= 0;
-            ValueNode[] icArgs = intrinsicContext.getArgs();
-            for (int i = 0; i < icArgs.length; i++) {
-                ValueNode arg = GraphUtil.unproxify(args[i]);
-                ValueNode icArg = GraphUtil.unproxify(icArgs[i]);
+    private static boolean checkPartialIntrinsicExit(ValueNode[] originalArgs, ValueNode[] recursiveArgs) {
+        if (originalArgs != null) {
+            for (int i = 0; i < originalArgs.length; i++) {
+                ValueNode arg = GraphUtil.unproxify(recursiveArgs[i]);
+                ValueNode icArg = GraphUtil.unproxify(originalArgs[i]);
                 assert arg == icArg : String.format("argument %d of call denoting partial intrinsic exit should be %s, not %s", i, icArg, arg);
             }
         } else {
-            for (int i = 0; i < args.length; i++) {
-                ValueNode arg = GraphUtil.unproxify(args[i]);
+            for (int i = 0; i < recursiveArgs.length; i++) {
+                ValueNode arg = GraphUtil.unproxify(recursiveArgs[i]);
                 assert arg instanceof ParameterNode && ((ParameterNode) arg).index() == i : String.format("argument %d of call denoting partial intrinsic exit should be a %s with index %d, not %s", i,
                                 ParameterNode.class.getSimpleName(), i, arg);
             }
@@ -1500,8 +1567,8 @@
         return true;
     }
 
-    protected Invoke createNonInlinedInvoke(ValueNode[] invokeArgs, int invokeBci, ResolvedJavaMethod targetMethod,
-                    InvokeKind invokeKind, JavaKind resultType, JavaType returnType, InlineInfo inlineInfo, JavaTypeProfile profile) {
+    protected Invoke createNonInlinedInvoke(boolean withExceptionEdge, int invokeBci, ValueNode[] invokeArgs, ResolvedJavaMethod targetMethod,
+                    InvokeKind invokeKind, JavaKind resultType, JavaType returnType, JavaTypeProfile profile) {
 
         StampPair returnStamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, returnType, false);
         if (returnStamp == null) {
@@ -1509,7 +1576,7 @@
         }
 
         MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, targetMethod, invokeArgs, returnStamp, profile));
-        Invoke invoke = createNonInlinedInvoke(invokeBci, callTarget, resultType, inlineInfo);
+        Invoke invoke = createNonInlinedInvoke(withExceptionEdge, invokeBci, callTarget, resultType);
 
         for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
             plugin.notifyNotInlined(this, targetMethod, invoke);
@@ -1518,8 +1585,8 @@
         return invoke;
     }
 
-    protected Invoke createNonInlinedInvoke(int invokeBci, CallTargetNode callTarget, JavaKind resultType, InlineInfo inlineInfo) {
-        if (omitInvokeExceptionEdge(callTarget, inlineInfo)) {
+    protected Invoke createNonInlinedInvoke(boolean withExceptionEdge, int invokeBci, CallTargetNode callTarget, JavaKind resultType) {
+        if (!withExceptionEdge) {
             return createInvoke(invokeBci, callTarget, resultType);
         } else {
             Invoke invoke = createInvokeWithException(invokeBci, callTarget, resultType);
@@ -1533,10 +1600,8 @@
     /**
      * If the method returns true, the invocation of the given {@link MethodCallTargetNode call
      * target} does not need an exception edge.
-     *
-     * @param callTarget The call target.
      */
-    protected boolean omitInvokeExceptionEdge(CallTargetNode callTarget, InlineInfo lastInlineInfo) {
+    protected boolean omitInvokeExceptionEdge(InlineInfo lastInlineInfo) {
         if (lastInlineInfo == InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION) {
             return false;
         } else if (lastInlineInfo == InlineInfo.DO_NOT_INLINE_NO_EXCEPTION) {
@@ -1551,8 +1616,17 @@
             assert graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.Profile;
             // be conservative if information was not recorded (could result in endless
             // recompiles otherwise)
-            return (!StressInvokeWithExceptionNode.getValue(options) && optimisticOpts.useExceptionProbability(getOptions()) && profilingInfo != null &&
-                            profilingInfo.getExceptionSeen(bci()) == TriState.FALSE);
+            if (!StressInvokeWithExceptionNode.getValue(options)) {
+                if (optimisticOpts.useExceptionProbability(getOptions())) {
+                    if (profilingInfo != null) {
+                        TriState exceptionSeen = profilingInfo.getExceptionSeen(bci());
+                        if (exceptionSeen == TriState.FALSE) {
+                            return true;
+                        }
+                    }
+                }
+            }
+            return false;
         }
     }
 
@@ -1754,7 +1828,7 @@
                     }
 
                     lastInstr = intrinsicGuard.nonIntrinsicBranch;
-                    createNonInlinedInvoke(args, bci(), targetMethod, invokeKind, resultType, returnType, null, intrinsicGuard.profile);
+                    createNonInlinedInvoke(omitInvokeExceptionEdge(null), bci(), args, targetMethod, invokeKind, resultType, returnType, intrinsicGuard.profile);
 
                     EndNode nonIntrinsicEnd = append(new EndNode());
                     AbstractMergeNode mergeNode = graph.add(new MergeNode());
@@ -1851,6 +1925,7 @@
                     if (inline(targetMethod, inlineInfo.getMethodToInline(), inlineInfo.getIntrinsicBytecodeProvider(), args)) {
                         return SUCCESSFULLY_INLINED;
                     }
+                    inlineInfo = null;
                 }
                 /* Do not inline, and do not ask the remaining plugins. */
                 return inlineInfo;
@@ -1922,10 +1997,10 @@
                     printInlining(targetMethod, inlinedMethod, false, "native method (bytecode parsing)");
                     return false;
                 }
-                if (inlinePartialIntrinsicExit()) {
+                if (canInlinePartialIntrinsicExit() && InlinePartialIntrinsicExitDuringParsing.getValue(options)) {
                     // 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)).
+                    // intrinsic method (see FrameStateBuilder.create(int bci)).
                     notifyBeforeInline(inlinedMethod);
                     printInlining(targetMethod, inlinedMethod, true, "partial intrinsic exit (bytecode parsing)");
                     parseAndInlineCallee(intrinsic.getOriginalMethod(), args, null);
@@ -1940,7 +2015,7 @@
             boolean isIntrinsic = intrinsicBytecodeProvider != null;
             if (intrinsic == null && isIntrinsic) {
                 assert !inlinedMethod.equals(targetMethod);
-                intrinsic = new IntrinsicContext(targetMethod, inlinedMethod, intrinsicBytecodeProvider, INLINE_DURING_PARSING, args, bci());
+                intrinsic = new IntrinsicContext(targetMethod, inlinedMethod, intrinsicBytecodeProvider, INLINE_DURING_PARSING);
             }
             if (inlinedMethod.hasBytecodes()) {
                 notifyBeforeInline(inlinedMethod);
@@ -1969,9 +2044,9 @@
 
     /**
      * Determines if a partial intrinsic exit (i.e., a call to the original method within an
-     * intrinsic) should be inlined.
+     * intrinsic) can be inlined.
      */
-    protected boolean inlinePartialIntrinsicExit() {
+    protected boolean canInlinePartialIntrinsicExit() {
         return true;
     }
 
@@ -2031,7 +2106,6 @@
         return res;
     }
 
-    @SuppressWarnings("try")
     protected void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) {
         try (IntrinsicScope s = calleeIntrinsicContext != null && !parsingIntrinsic() ? new IntrinsicScope(this, targetMethod.getSignature().toParameterKinds(!targetMethod.isStatic()), args) : null) {
 
@@ -2049,6 +2123,9 @@
             } else {
                 ValueNode calleeReturnValue;
                 MergeNode returnMergeNode = null;
+                if (s != null) {
+                    s.returnDataList = parser.returnDataList;
+                }
                 if (parser.returnDataList.size() == 1) {
                     /* Callee has a single return, we can continue parsing at that point. */
                     ReturnToCallerData singleReturnData = parser.returnDataList.get(0);
@@ -2091,7 +2168,6 @@
     }
 
     protected InvokeWithExceptionNode createInvokeWithException(int invokeBci, CallTargetNode callTarget, JavaKind resultType) {
-        assert bci() == invokeBci;
         if (currentBlock != null && stream.nextBCI() > currentBlock.endBci) {
             /*
              * Clear non-live locals early so that the exception handler entry gets the cleared
@@ -2101,7 +2177,7 @@
         }
 
         AbstractBeginNode exceptionEdge = handleException(null, bci());
-        InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci()));
+        InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, invokeBci));
         frameState.pushReturn(resultType, invoke);
         invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke));
         return invoke;
@@ -3632,9 +3708,9 @@
         ResolvedJavaType resolvedType = (ResolvedJavaType) type;
 
         ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin();
-        if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType.getArrayClass())) {
+        if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType)) {
             FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
-            classInitializationPlugin.apply(this, resolvedType.getArrayClass(), stateBefore);
+            classInitializationPlugin.apply(this, resolvedType, stateBefore);
         }
 
         for (int i = rank - 1; i >= 0; i--) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java	Thu Jun 01 02:21:18 2017 +0000
@@ -40,6 +40,12 @@
     @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert)
     public static final OptionKey<Boolean> InlineDuringParsing = new OptionKey<>(true);
 
+    @Option(help = "Inlines partial intrinsic exits during bytecode parsing when possible. " +
+                   "A partial intrinsic exit is a call within an intrinsic to the method " +
+                   "being intrinsified and denotes semantics of the original method that " +
+                   "the intrinsic does not support.", type = OptionType.Expert)
+    public static final OptionKey<Boolean> InlinePartialIntrinsicExitDuringParsing = new OptionKey<>(true);
+
     @Option(help = "Inlines intrinsic methods during bytecode parsing.", type = OptionType.Expert)
     public static final OptionKey<Boolean> InlineIntrinsicsDuringParsing = new OptionKey<>(true);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java	Thu Jun 01 02:21:18 2017 +0000
@@ -42,8 +42,8 @@
 
 import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
+import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.PermanentBailoutException;
-import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.StampPair;
 import org.graalvm.compiler.debug.Debug;
@@ -307,7 +307,8 @@
 
     public FrameState create(int bci, StateSplit forStateSplit) {
         if (parser != null && parser.parsingIntrinsic()) {
-            return parser.intrinsicContext.createFrameState(parser.getGraph(), this, forStateSplit);
+            NodeSourcePosition sourcePosition = createBytecodePosition(bci, false);
+            return parser.intrinsicContext.createFrameState(parser.getGraph(), this, forStateSplit, sourcePosition);
         }
 
         // Skip intrinsic frames
@@ -350,8 +351,12 @@
     }
 
     public NodeSourcePosition createBytecodePosition(int bci) {
+        return createBytecodePosition(bci, HideSubstitutionStates.getValue(parser.graph.getOptions()));
+    }
+
+    private NodeSourcePosition createBytecodePosition(int bci, boolean hideSubstitutionStates) {
         BytecodeParser parent = parser.getParent();
-        if (HideSubstitutionStates.getValue(parser.graph.getOptions())) {
+        if (hideSubstitutionStates) {
             if (parser.parsingIntrinsic()) {
                 // Attribute to the method being replaced
                 return new NodeSourcePosition(constantReceiver, parent.getFrameStateBuilder().createBytecodePosition(parent.bci()), parser.intrinsicContext.getOriginalMethod(), -1);
@@ -359,13 +364,13 @@
             // Skip intrinsic frames
             parent = parser.getNonIntrinsicAncestor();
         }
-        return create(null, constantReceiver, bci, parent);
+        return create(null, constantReceiver, bci, parent, hideSubstitutionStates);
     }
 
-    private NodeSourcePosition create(NodeSourcePosition o, JavaConstant receiver, int bci, BytecodeParser parent) {
+    private NodeSourcePosition create(NodeSourcePosition o, JavaConstant receiver, int bci, BytecodeParser parent, boolean hideSubstitutionStates) {
         NodeSourcePosition outer = o;
         if (outer == null && parent != null) {
-            outer = parent.getFrameStateBuilder().createBytecodePosition(parent.bci());
+            outer = parent.getFrameStateBuilder().createBytecodePosition(parent.bci(), hideSubstitutionStates);
         }
         if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
             return FrameState.toSourcePosition(outerFrameState);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArithmetic.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArithmetic.java	Thu Jun 01 02:21:18 2017 +0000
@@ -170,7 +170,9 @@
                 assert !y.equals(scratch1);
                 switch (opcode) {
                     case LUREM:
-                        crb.recordImplicitException(masm.position(), state);
+                        if (state != null) {
+                            crb.recordImplicitException(masm.position(), state);
+                        }
                         masm.udivx(asRegister(x, XWORD), crb.asIntConst(y), asRegister(scratch1, XWORD));
                         masm.mulx(asRegister(scratch1, XWORD), crb.asIntConst(y), asRegister(scratch2, XWORD));
                         getDelayedControlTransfer().emitControlTransfer(crb, masm);
@@ -192,7 +194,9 @@
                         }
                         assert !asRegister(xLeft, XWORD).equals(asRegister(scratch1, XWORD));
                         assert !asRegister(y, XWORD).equals(asRegister(scratch1, XWORD));
-                        crb.recordImplicitException(masm.position(), state);
+                        if (state != null) {
+                            crb.recordImplicitException(masm.position(), state);
+                        }
                         masm.udivx(asRegister(xLeft, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD));
                         masm.mulx(asRegister(scratch1, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD));
                         getDelayedControlTransfer().emitControlTransfer(crb, masm);
@@ -203,7 +207,9 @@
                         assert !asRegister(result, WORD).equals(asRegister(scratch2, WORD));
                         masm.srl(asRegister(x, WORD), 0, asRegister(scratch1, WORD));
                         masm.srl(asRegister(y, WORD), 0, asRegister(result, WORD));
-                        crb.recordImplicitException(masm.position(), state);
+                        if (state != null) {
+                            crb.recordImplicitException(masm.position(), state);
+                        }
                         masm.udivx(asRegister(scratch1, WORD), asRegister(result, WORD), asRegister(scratch2, WORD));
                         masm.mulx(asRegister(scratch2, WORD), asRegister(result, WORD), asRegister(result, WORD));
                         getDelayedControlTransfer().emitControlTransfer(crb, masm);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/FixedInterval.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/FixedInterval.java	Thu Jun 01 02:21:18 2017 +0000
@@ -35,56 +35,6 @@
  */
 final class FixedInterval extends IntervalHint {
 
-    static final class FixedList {
-
-        public FixedInterval fixed;
-
-        FixedList(FixedInterval fixed) {
-            this.fixed = fixed;
-        }
-
-        /**
-         * Gets the fixed list.
-         */
-        public FixedInterval getFixed() {
-            return fixed;
-        }
-
-        /**
-         * Sets the fixed list.
-         */
-        public void setFixed(FixedInterval list) {
-            fixed = list;
-        }
-
-        /**
-         * Adds an interval to a list sorted by {@linkplain FixedInterval#currentFrom() current
-         * from} positions.
-         *
-         * @param interval the interval to add
-         */
-        public void addToListSortedByCurrentFromPositions(FixedInterval interval) {
-            FixedInterval list = getFixed();
-            FixedInterval prev = null;
-            FixedInterval cur = list;
-            while (cur.currentFrom() < interval.currentFrom()) {
-                prev = cur;
-                cur = cur.next;
-            }
-            FixedInterval result = list;
-            if (prev == null) {
-                // add to head of list
-                result = interval;
-            } else {
-                // add before 'cur'
-                prev.next = interval;
-            }
-            interval.next = cur;
-            setFixed(result);
-        }
-
-    }
-
     /**
      * The fixed operand of this interval.
      */
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/RegisterVerifier.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/RegisterVerifier.java	Thu Jun 01 02:21:18 2017 +0000
@@ -24,6 +24,7 @@
 
 import static jdk.vm.ci.code.ValueUtil.asRegister;
 import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
 import static org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.isVariableOrRegister;
 
 import java.util.ArrayList;
@@ -39,6 +40,7 @@
 import org.graalvm.compiler.lir.LIRInstruction;
 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.Variable;
 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
 
 import jdk.vm.ci.code.Register;
@@ -53,7 +55,7 @@
     BlockMap<TraceInterval[]> savedStates; // saved information of previous check
 
     // simplified access to methods of LinearScan
-    TraceInterval intervalAt(Value operand) {
+    TraceInterval intervalAt(Variable operand) {
         return allocator.intervalFor(operand);
     }
 
@@ -189,7 +191,7 @@
             Register reg = asRegister(location);
             int regNum = reg.number;
             if (interval != null) {
-                Debug.log("%s = %s", reg, interval.operand);
+                Debug.log("%s = v%d", reg, interval.operandNumber);
             } else if (inputState[regNum] != null) {
                 Debug.log("%s = null", reg);
             }
@@ -217,19 +219,19 @@
             public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
                 // we skip spill moves inserted by the spill position optimization
                 if (isVariableOrRegister(operand) && allocator.isProcessed(operand) && op.id() != TraceLinearScanPhase.DOMINATOR_SPILL_MOVE_ID) {
-                    TraceInterval interval = intervalAt(operand);
+                    TraceInterval interval = intervalAt(asVariable(operand));
                     if (op.id() != -1) {
                         interval = interval.getSplitChildAtOpId(op.id(), mode);
                     }
 
-                    assert checkState(block, op, inputState, interval.operand, interval.location(), interval.splitParent());
+                    assert checkState(block, op, inputState, allocator.getOperand(interval), interval.location(), interval.splitParent());
                 }
             }
         };
 
         InstructionValueConsumer defConsumer = (op, operand, mode, flags) -> {
             if (isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
-                TraceInterval interval = intervalAt(operand);
+                TraceInterval interval = intervalAt(asVariable(operand));
                 if (op.id() != -1) {
                     interval = interval.getSplitChildAtOpId(op.id(), mode);
                 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceInterval.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceInterval.java	Thu Jun 01 02:21:18 2017 +0000
@@ -57,102 +57,6 @@
  */
 final class TraceInterval extends IntervalHint {
 
-    static final class AnyList {
-
-        /**
-         * List of intervals whose binding is currently {@link RegisterBinding#Any}.
-         */
-        public TraceInterval any;
-
-        AnyList(TraceInterval any) {
-            this.any = any;
-        }
-
-        /**
-         * Gets the any list.
-         */
-        public TraceInterval getAny() {
-            return any;
-        }
-
-        /**
-         * Sets the any list.
-         */
-        public void setAny(TraceInterval list) {
-            any = list;
-        }
-
-        /**
-         * Adds an interval to a list sorted by {@linkplain TraceInterval#from() current from}
-         * positions.
-         *
-         * @param interval the interval to add
-         */
-        public void addToListSortedByFromPositions(TraceInterval interval) {
-            TraceInterval list = getAny();
-            TraceInterval prev = null;
-            TraceInterval cur = list;
-            while (cur.from() < interval.from()) {
-                prev = cur;
-                cur = cur.next;
-            }
-            TraceInterval result = list;
-            if (prev == null) {
-                // add to head of list
-                result = interval;
-            } else {
-                // add before 'cur'
-                prev.next = interval;
-            }
-            interval.next = cur;
-            setAny(result);
-        }
-
-        /**
-         * Adds an interval to a list sorted by {@linkplain TraceInterval#from() start} positions
-         * and {@linkplain TraceInterval#firstUsage(RegisterPriority) first usage} positions.
-         *
-         * @param interval the interval to add
-         */
-        public void addToListSortedByStartAndUsePositions(TraceInterval interval) {
-            TraceInterval list = getAny();
-            TraceInterval prev = null;
-            TraceInterval cur = list;
-            while (cur.from() < interval.from() || (cur.from() == interval.from() && cur.firstUsage(RegisterPriority.None) < interval.firstUsage(RegisterPriority.None))) {
-                prev = cur;
-                cur = cur.next;
-            }
-            if (prev == null) {
-                list = interval;
-            } else {
-                prev.next = interval;
-            }
-            interval.next = cur;
-            setAny(list);
-        }
-
-        /**
-         * Removes an interval from a list.
-         *
-         * @param i the interval to remove
-         */
-        public void removeAny(TraceInterval i) {
-            TraceInterval list = getAny();
-            TraceInterval prev = null;
-            TraceInterval cur = list;
-            while (cur != i) {
-                assert cur != null && cur != TraceInterval.EndMarker : "interval has not been found in list: " + i;
-                prev = cur;
-                cur = cur.next;
-            }
-            if (prev == null) {
-                setAny(cur.next);
-            } else {
-                prev.next = cur.next;
-            }
-        }
-    }
-
     /**
      * Constants denoting the register usage priority for an interval. The constants are declared in
      * increasing order of priority are are used to optimize spilling when multiple overlapping
@@ -290,7 +194,7 @@
      * The {@linkplain RegisterValue register} or {@linkplain Variable variable} for this interval
      * prior to register allocation.
      */
-    public final AllocatableValue operand;
+    public final Variable operand;
 
     /**
      * The operand number for this interval's {@linkplain #operand operand}.
@@ -375,11 +279,32 @@
     private JavaConstant materializedValue;
 
     /**
-     * The number of times {@link #addMaterializationValue(JavaConstant)} is called.
+     * Sentinel interval to denote the end of an interval list.
      */
-    private int numMaterializationValuesAdded;
+    static final TraceInterval EndMarker = new TraceInterval(new Variable(ValueKind.Illegal, Integer.MAX_VALUE), -1);
+
+    TraceInterval(Variable operand) {
+        this(operand, operand.index);
+    }
 
-    private final OptionValues options;
+    private TraceInterval(Variable operand, int operandNumber) {
+        assert operand != null;
+        this.operand = operand;
+        this.operandNumber = operandNumber;
+        if (isRegister(operand)) {
+            location = operand;
+        } else {
+            assert isIllegal(operand) || isVariable(operand);
+        }
+        this.intFrom = Integer.MAX_VALUE;
+        this.intTo = Integer.MAX_VALUE;
+        this.usePosListArray = new int[4 * 2];
+        this.next = EndMarker;
+        this.spillState = SpillState.NoDefinitionFound;
+        this.spillDefinitionPos = -1;
+        splitParent = this;
+        currentSplitChild = this;
+    }
 
     private boolean splitChildrenEmpty() {
         assert splitChildren == null || !splitChildren.isEmpty();
@@ -413,7 +338,7 @@
         return location;
     }
 
-    public ValueKind<?> kind() {
+    private ValueKind<?> kind() {
         return operand.getValueKind();
     }
 
@@ -551,41 +476,13 @@
     }
 
     /**
-     * Sentinel interval to denote the end of an interval list.
-     */
-    static final TraceInterval EndMarker = new TraceInterval(Value.ILLEGAL, -1, null);
-
-    TraceInterval(AllocatableValue operand, int operandNumber, OptionValues options) {
-        assert operand != null;
-        this.operand = operand;
-        this.operandNumber = operandNumber;
-        this.options = options;
-        if (isRegister(operand)) {
-            location = operand;
-        } else {
-            assert isIllegal(operand) || isVariable(operand);
-        }
-        this.intFrom = Integer.MAX_VALUE;
-        this.intTo = Integer.MAX_VALUE;
-        this.usePosListArray = new int[4 * 2];
-        this.next = EndMarker;
-        this.spillState = SpillState.NoDefinitionFound;
-        this.spillDefinitionPos = -1;
-        splitParent = this;
-        currentSplitChild = this;
-    }
-
-    /**
      * Sets the value which is used for re-materialization.
      */
     public void addMaterializationValue(JavaConstant value) {
-        if (numMaterializationValuesAdded == 0) {
-            materializedValue = value;
-        } else {
-            // Interval is defined on multiple places -> no materialization is possible.
-            materializedValue = null;
+        if (materializedValue != null) {
+            throw GraalError.shouldNotReachHere(String.format("Multiple materialization values for %s?", this));
         }
-        numMaterializationValuesAdded++;
+        materializedValue = value;
     }
 
     /**
@@ -618,7 +515,7 @@
                 for (int j = i + 1; j < splitChildren.size(); j++) {
                     TraceInterval i2 = splitChildren.get(j);
 
-                    assert !i1.operand.equals(i2.operand) : "same register number";
+                    assert i1.operandNumber != i2.operandNumber : "same register number";
 
                     if (i1.from() < i2.from()) {
                         assert i1.to() <= i2.from() && i1.to() < i2.to() : "intervals overlapping";
@@ -741,32 +638,6 @@
         return true;
     }
 
-    // returns the interval that covers the given opId or null if there is none
-    TraceInterval getIntervalCoveringOpId(int opId) {
-        assert opId >= 0 : "invalid opId";
-        assert opId < to() : "can only look into the past";
-
-        if (opId >= from()) {
-            return this;
-        }
-
-        TraceInterval parent = splitParent();
-        TraceInterval result = null;
-
-        assert !parent.splitChildrenEmpty() : "no split children available";
-        int len = parent.splitChildren.size();
-
-        for (int i = len - 1; i >= 0; i--) {
-            TraceInterval cur = parent.splitChildren.get(i);
-            if (cur.from() <= opId && opId < cur.to()) {
-                assert result == null : "covered by multiple split children " + result + " and " + cur;
-                result = cur;
-            }
-        }
-
-        return result;
-    }
-
     // returns the last split child that ends before the given opId
     TraceInterval getSplitChildBeforeOpId(int opId) {
         assert opId >= 0 : "invalid opId";
@@ -788,28 +659,6 @@
         return result;
     }
 
-    // checks if opId is covered by any split child
-    boolean splitChildCovers(int opId, LIRInstruction.OperandMode mode) {
-        assert isSplitParent() : "can only be called for split parents";
-        assert opId >= 0 : "invalid opId (method can not be called for spill moves)";
-
-        if (splitChildrenEmpty()) {
-            // simple case if interval was not split
-            return covers(opId, mode);
-
-        } else {
-            // extended case: check all split children
-            int len = splitChildren.size();
-            for (int i = 0; i < len; i++) {
-                TraceInterval cur = splitChildren.get(i);
-                if (cur.covers(opId, mode)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
-
     private RegisterPriority adaptPriority(RegisterPriority priority) {
         /*
          * In case of re-materialized values we require that use-operands are registers, because we
@@ -824,8 +673,6 @@
 
     // Note: use positions are sorted descending . first use has highest index
     int firstUsage(RegisterPriority minRegisterPriority) {
-        assert isVariable(operand) : "cannot access use positions for fixed intervals";
-
         for (int i = numUsePos() - 1; i >= 0; --i) {
             RegisterPriority registerPriority = adaptPriority(getUsePosRegisterPriority(i));
             if (registerPriority.greaterEqual(minRegisterPriority)) {
@@ -836,8 +683,6 @@
     }
 
     int nextUsage(RegisterPriority minRegisterPriority, int from) {
-        assert isVariable(operand) : "cannot access use positions for fixed intervals";
-
         for (int i = numUsePos() - 1; i >= 0; --i) {
             int usePos = getUsePos(i);
             if (usePos >= from && adaptPriority(getUsePosRegisterPriority(i)).greaterEqual(minRegisterPriority)) {
@@ -848,7 +693,6 @@
     }
 
     int nextUsageExact(RegisterPriority exactRegisterPriority, int from) {
-        assert isVariable(operand) : "cannot access use positions for fixed intervals";
 
         for (int i = numUsePos() - 1; i >= 0; --i) {
             int usePos = getUsePos(i);
@@ -860,8 +704,6 @@
     }
 
     int previousUsage(RegisterPriority minRegisterPriority, int from) {
-        assert isVariable(operand) : "cannot access use positions for fixed intervals";
-
         int prev = -1;
         for (int i = numUsePos() - 1; i >= 0; --i) {
             int usePos = getUsePos(i);
@@ -875,11 +717,11 @@
         return prev;
     }
 
-    public void addUsePos(int pos, RegisterPriority registerPriority) {
+    public void addUsePos(int pos, RegisterPriority registerPriority, OptionValues options) {
         assert isEmpty() || covers(pos, LIRInstruction.OperandMode.USE) : String.format("use position %d not covered by live range of interval %s", pos, this);
 
         // do not add use positions for precolored intervals because they are never used
-        if (registerPriority != RegisterPriority.None && isVariable(operand)) {
+        if (registerPriority != RegisterPriority.None) {
             if (DetailedAsserts.getValue(options)) {
                 for (int i = 0; i < numUsePos(); i++) {
                     assert pos <= getUsePos(i) : "already added a use-position with lower position";
@@ -948,7 +790,6 @@
      * @return the child interval split off from this interval
      */
     TraceInterval split(int splitPos, TraceLinearScan allocator) {
-        assert isVariable(operand) : "cannot split fixed intervals";
 
         // allocate new interval
         TraceInterval result = newSplitChild(allocator);
@@ -961,7 +802,7 @@
         // split list of use positions
         splitUsePosAt(result, splitPos);
 
-        if (DetailedAsserts.getValue(options)) {
+        if (DetailedAsserts.getValue(allocator.getOptions())) {
             for (int i = 0; i < numUsePos(); i++) {
                 assert getUsePos(i) < splitPos;
             }
@@ -1037,59 +878,6 @@
         return Collections.unmodifiableList(splitChildren);
     }
 
-    boolean isFixedInterval() {
-        return isRegister(operand);
-    }
-
-    private static boolean isDefinitionPosition(int usePos) {
-        return (usePos & 1) == 1;
-    }
-
-    int currentFrom(int currentPosition) {
-        assert isFixedInterval();
-        for (int i = 0; i < numUsePos(); i++) {
-            int usePos = getUsePos(i);
-            if (usePos <= currentPosition && isDefinitionPosition(usePos)) {
-                return usePos;
-            }
-
-        }
-        return Integer.MAX_VALUE;
-    }
-
-    int currentIntersectsAt(int currentPosition, TraceInterval current) {
-        assert isFixedInterval();
-        assert !current.isFixedInterval();
-        int from = Integer.MAX_VALUE;
-        int to = Integer.MIN_VALUE;
-
-        for (int i = 0; i < numUsePos(); i++) {
-            int usePos = getUsePos(i);
-            if (isDefinitionPosition(usePos)) {
-                if (usePos <= currentPosition) {
-                    from = usePos;
-                    break;
-                }
-                to = Integer.MIN_VALUE;
-            } else {
-                if (to < usePos) {
-                    to = usePos;
-                }
-            }
-        }
-        if (from < current.from()) {
-            if (to <= current.from()) {
-                return -1;
-            }
-            return current.from();
-        } else {
-            if (current.to() <= from) {
-                return -1;
-            }
-            return from;
-        }
-    }
-
     /*
      * UsePos
      *
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceIntervalWalker.java	Wed May 31 09:19:28 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,314 +0,0 @@
-/*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.lir.alloc.trace.lsra;
-
-import org.graalvm.compiler.debug.Debug;
-import org.graalvm.compiler.debug.Indent;
-import org.graalvm.compiler.lir.alloc.trace.lsra.FixedInterval.FixedList;
-import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.AnyList;
-import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.RegisterBinding;
-import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.State;
-import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
-
-/**
- */
-class TraceIntervalWalker {
-
-    protected final TraceLinearScan allocator;
-
-    /**
-     * Sorted list of intervals, not live before the current position.
-     */
-    protected AnyList unhandledAnyList;
-
-    /**
-     * Sorted list of intervals, live at the current position.
-     */
-    protected AnyList activeAnyList;
-    protected FixedList activeFixedList;
-
-    /**
-     * Sorted list of intervals in a life time hole at the current position.
-     */
-    protected FixedList inactiveFixedList;
-
-    /**
-     * The current position (intercept point through the intervals).
-     */
-    protected int currentPosition;
-
-    /**
-     * Processes the {@code currentInterval} interval in an attempt to allocate a physical register
-     * to it and thus allow it to be moved to a list of {@linkplain #activeAnyList active}
-     * intervals.
-     *
-     * @param currentInterval The interval to be activated.
-     *
-     * @return {@code true} if a register was allocated to the {@code currentInterval} interval
-     */
-    protected boolean activateCurrent(TraceInterval currentInterval) {
-        if (Debug.isLogEnabled()) {
-            logCurrentStatus();
-        }
-        return true;
-    }
-
-    @SuppressWarnings("try")
-    protected void logCurrentStatus() {
-        try (Indent i = Debug.logAndIndent("active:")) {
-            logList(activeFixedList.getFixed());
-            logList(activeAnyList.getAny());
-        }
-        try (Indent i = Debug.logAndIndent("inactive(fixed):")) {
-            logList(inactiveFixedList.getFixed());
-        }
-    }
-
-    private static void logList(FixedInterval i) {
-        for (FixedInterval interval = i; interval != FixedInterval.EndMarker; interval = interval.next) {
-            Debug.log("%s", interval.logString());
-        }
-    }
-
-    private static void logList(TraceInterval i) {
-        for (TraceInterval interval = i; interval != TraceInterval.EndMarker; interval = interval.next) {
-            Debug.log("%s", interval.logString());
-        }
-    }
-
-    void walkBefore(int lirOpId) {
-        walkTo(lirOpId - 1);
-    }
-
-    void walk() {
-        walkTo(Integer.MAX_VALUE);
-    }
-
-    /**
-     * Creates a new interval walker.
-     *
-     * @param allocator the register allocator context
-     * @param unhandledFixed the list of unhandled {@linkplain RegisterBinding#Fixed fixed}
-     *            intervals
-     * @param unhandledAny the list of unhandled {@linkplain RegisterBinding#Any non-fixed}
-     *            intervals
-     */
-    TraceIntervalWalker(TraceLinearScan allocator, FixedInterval unhandledFixed, TraceInterval unhandledAny) {
-        this.allocator = allocator;
-
-        unhandledAnyList = new AnyList(unhandledAny);
-        activeAnyList = new AnyList(TraceInterval.EndMarker);
-        activeFixedList = new FixedList(FixedInterval.EndMarker);
-        // we don't need a separate unhandled list for fixed.
-        inactiveFixedList = new FixedList(unhandledFixed);
-        currentPosition = -1;
-    }
-
-    protected void removeFromList(TraceInterval interval) {
-        activeAnyList.removeAny(interval);
-    }
-
-    /**
-     * Walks up to {@code from} and updates the state of {@link FixedInterval fixed intervals}.
-     *
-     * Fixed intervals can switch back and forth between the states {@link State#Active} and
-     * {@link State#Inactive} (and eventually to {@link State#Handled} but handled intervals are not
-     * managed).
-     */
-    @SuppressWarnings("try")
-    private void walkToFixed(State state, int from) {
-        assert state == State.Active || state == State.Inactive : "wrong state";
-        FixedInterval prevprev = null;
-        FixedInterval prev = (state == State.Active) ? activeFixedList.getFixed() : inactiveFixedList.getFixed();
-        FixedInterval next = prev;
-        if (Debug.isLogEnabled()) {
-            try (Indent i = Debug.logAndIndent("walkToFixed(%s, %d):", state, from)) {
-                logList(next);
-            }
-        }
-        while (next.currentFrom() <= from) {
-            FixedInterval cur = next;
-            next = cur.next;
-
-            boolean rangeHasChanged = false;
-            while (cur.currentTo() <= from) {
-                cur.nextRange();
-                rangeHasChanged = true;
-            }
-
-            // also handle move from inactive list to active list
-            rangeHasChanged = rangeHasChanged || (state == State.Inactive && cur.currentFrom() <= from);
-
-            if (rangeHasChanged) {
-                // remove cur from list
-                if (prevprev == null) {
-                    if (state == State.Active) {
-                        activeFixedList.setFixed(next);
-                    } else {
-                        inactiveFixedList.setFixed(next);
-                    }
-                } else {
-                    prevprev.next = next;
-                }
-                prev = next;
-                TraceInterval.State newState;
-                if (cur.currentAtEnd()) {
-                    // move to handled state (not maintained as a list)
-                    newState = State.Handled;
-                } else {
-                    if (cur.currentFrom() <= from) {
-                        // sort into active list
-                        activeFixedList.addToListSortedByCurrentFromPositions(cur);
-                        newState = State.Active;
-                    } else {
-                        // sort into inactive list
-                        inactiveFixedList.addToListSortedByCurrentFromPositions(cur);
-                        newState = State.Inactive;
-                    }
-                    if (prev == cur) {
-                        assert state == newState;
-                        prevprev = prev;
-                        prev = cur.next;
-                    }
-                }
-                intervalMoved(cur, state, newState);
-            } else {
-                prevprev = prev;
-                prev = cur.next;
-            }
-        }
-    }
-
-    /**
-     * Walks up to {@code from} and updates the state of {@link TraceInterval intervals}.
-     *
-     * Trace intervals can switch once from {@link State#Unhandled} to {@link State#Active} and then
-     * to {@link State#Handled} but handled intervals are not managed.
-     */
-    @SuppressWarnings("try")
-    private void walkToAny(int from) {
-        TraceInterval prevprev = null;
-        TraceInterval prev = activeAnyList.getAny();
-        TraceInterval next = prev;
-        if (Debug.isLogEnabled()) {
-            try (Indent i = Debug.logAndIndent("walkToAny(%d):", from)) {
-                logList(next);
-            }
-        }
-        while (next.from() <= from) {
-            TraceInterval cur = next;
-            next = cur.next;
-
-            if (cur.to() <= from) {
-                // remove cur from list
-                if (prevprev == null) {
-                    activeAnyList.setAny(next);
-                } else {
-                    prevprev.next = next;
-                }
-                intervalMoved(cur, State.Active, State.Handled);
-            } else {
-                prevprev = prev;
-            }
-            prev = next;
-        }
-    }
-
-    /**
-     * Get the next interval from {@linkplain #unhandledAnyList} which starts before or at
-     * {@code toOpId}. The returned interval is removed.
-     *
-     * @postcondition all intervals in {@linkplain #unhandledAnyList} start after {@code toOpId}.
-     *
-     * @return The next interval or null if there is no {@linkplain #unhandledAnyList unhandled}
-     *         interval at position {@code toOpId}.
-     */
-    private TraceInterval nextInterval(int toOpId) {
-        TraceInterval any = unhandledAnyList.getAny();
-
-        if (any != TraceInterval.EndMarker) {
-            TraceInterval currentInterval = unhandledAnyList.getAny();
-            if (toOpId < currentInterval.from()) {
-                return null;
-            }
-
-            unhandledAnyList.setAny(currentInterval.next);
-            currentInterval.next = TraceInterval.EndMarker;
-            return currentInterval;
-        }
-        return null;
-
-    }
-
-    /**
-     * Walk up to {@code toOpId}.
-     *
-     * @postcondition {@link #currentPosition} is set to {@code toOpId}, {@link #activeFixedList}
-     *                and {@link #inactiveFixedList} are populated.
-     */
-    @SuppressWarnings("try")
-    protected void walkTo(int toOpId) {
-        assert currentPosition <= toOpId : "can not walk backwards";
-        for (TraceInterval currentInterval = nextInterval(toOpId); currentInterval != null; currentInterval = nextInterval(toOpId)) {
-            int opId = currentInterval.from();
-
-            // set currentPosition prior to call of walkTo
-            currentPosition = opId;
-
-            // update unhandled stack intervals
-            // updateUnhandledStackIntervals(opId);
-
-            // call walkTo even if currentPosition == id
-            walkToFixed(State.Active, opId);
-            walkToFixed(State.Inactive, opId);
-            walkToAny(opId);
-
-            try (Indent indent = Debug.logAndIndent("walk to op %d", opId)) {
-                if (activateCurrent(currentInterval)) {
-                    activeAnyList.addToListSortedByFromPositions(currentInterval);
-                    intervalMoved(currentInterval, State.Unhandled, State.Active);
-                }
-            }
-        }
-        // set currentPosition prior to call of walkTo
-        currentPosition = toOpId;
-
-        if (currentPosition <= allocator.maxOpId()) {
-            // update unhandled stack intervals
-            // updateUnhandledStackIntervals(toOpId);
-
-            // call walkTo if still in range
-            walkToFixed(State.Active, toOpId);
-            walkToFixed(State.Inactive, toOpId);
-            walkToAny(toOpId);
-        }
-    }
-
-    private static void intervalMoved(IntervalHint interval, State from, State to) {
-        // intervalMoved() is called whenever an interval moves from one interval list to another.
-        // In the implementation of this method it is prohibited to move the interval to any list.
-        if (Debug.isLogEnabled()) {
-            Debug.log("interval moved from %s to %s: %s", from, to, interval.logString());
-        }
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanAssignLocationsPhase.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanAssignLocationsPhase.java	Thu Jun 01 02:21:18 2017 +0000
@@ -24,6 +24,7 @@
 
 import static jdk.vm.ci.code.ValueUtil.isIllegal;
 import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
 import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
 import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
@@ -108,7 +109,7 @@
             return getLocation(op, interval, mode);
         }
 
-        private static Value getLocation(LIRInstruction op, TraceInterval interval, OperandMode mode) {
+        private Value getLocation(LIRInstruction op, TraceInterval interval, OperandMode mode) {
             if (isIllegal(interval.location()) && interval.canMaterialize()) {
                 if (op instanceof LabelOp) {
                     /*
@@ -118,7 +119,7 @@
                     return Value.ILLEGAL;
                 }
                 assert mode != OperandMode.DEF;
-                return new ConstantValue(interval.kind(), interval.getMaterializedValue());
+                return new ConstantValue(allocator.getKind(interval), interval.getMaterializedValue());
             }
             return interval.location();
         }
@@ -226,7 +227,7 @@
             return values;
         }
 
-        private static Value valueAtBlockBoundary(LIRInstruction instruction, TraceInterval interval, OperandMode mode) {
+        private Value valueAtBlockBoundary(LIRInstruction instruction, TraceInterval interval, OperandMode mode) {
             if (mode == OperandMode.DEF && interval == null) {
                 // not needed in this trace
                 return Value.ILLEGAL;
@@ -275,7 +276,7 @@
             // remove useless moves
             if (MoveOp.isMoveOp(op)) {
                 AllocatableValue result = MoveOp.asMoveOp(op).getResult();
-                if (isVariable(result) && allocator.isMaterialized(result, op.id(), OperandMode.DEF)) {
+                if (isVariable(result) && allocator.isMaterialized(asVariable(result), op.id(), OperandMode.DEF)) {
                     /*
                      * This happens if a materializable interval is originally not spilled but then
                      * kicked out in LinearScanWalker.splitForSpilling(). When kicking out such an
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanEliminateSpillMovePhase.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanEliminateSpillMovePhase.java	Thu Jun 01 02:21:18 2017 +0000
@@ -24,6 +24,7 @@
 
 import static jdk.vm.ci.code.ValueUtil.isRegister;
 import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts;
+import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
 import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
 import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
 
@@ -121,11 +122,10 @@
                                     if (Debug.isLogEnabled()) {
                                         if (ValueMoveOp.isValueMoveOp(op)) {
                                             ValueMoveOp vmove = ValueMoveOp.asValueMoveOp(op);
-                                            Debug.log("eliminating move from interval %d (%s) to %d (%s) in block %s", allocator.operandNumber(vmove.getInput()), vmove.getInput(),
-                                                            allocator.operandNumber(vmove.getResult()), vmove.getResult(), block);
+                                            Debug.log("eliminating move from interval %s to %s in block %s", vmove.getInput(), vmove.getResult(), block);
                                         } else {
                                             LoadConstantOp load = LoadConstantOp.asLoadConstantOp(op);
-                                            Debug.log("eliminating constant load from %s to %d (%s) in block %s", load.getConstant(), allocator.operandNumber(load.getResult()), load.getResult(),
+                                            Debug.log("eliminating constant load from %s to %s in block %s", load.getConstant(), load.getResult(),
                                                             block);
                                         }
                                     }
@@ -200,7 +200,7 @@
         assert isVariable(move.getResult()) : "LinearScan inserts only moves to variables: " + move;
         assert lastOpId >= 0 : "Invalid lastOpId: " + lastOpId;
 
-        TraceInterval curInterval = allocator.intervalFor(move.getResult());
+        TraceInterval curInterval = allocator.intervalFor(asVariable(move.getResult()));
 
         if (!isRegister(curInterval.location()) && curInterval.inMemoryAt(lastOpId) && !isPhiResolutionMove(allocator, move)) {
             /* Phi resolution moves cannot be removed because they define the value. */
@@ -221,7 +221,7 @@
      */
     private static boolean isPhiResolutionMove(TraceLinearScan allocator, MoveOp move) {
         assert ((LIRInstruction) move).id() == -1 : "Not a spill move: " + move;
-        TraceInterval curInterval = allocator.intervalFor(move.getResult());
+        TraceInterval curInterval = allocator.intervalFor(asVariable(move.getResult()));
         return curInterval.isSplitParent();
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java	Thu Jun 01 02:21:18 2017 +0000
@@ -191,11 +191,11 @@
         };
 
         private void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority) {
-            if (!allocator.isProcessed(operand)) {
-                return;
-            }
             if (isRegister(operand)) {
-                addFixedUse(asRegisterValue(operand), from, to);
+                RegisterValue reg = asRegisterValue(operand);
+                if (allocator.isAllocatable(reg)) {
+                    addFixedUse(reg, from, to);
+                }
             } else {
                 assert isVariable(operand) : operand;
                 addVariableUse(asVariable(operand), from, to, registerPriority);
@@ -215,7 +215,7 @@
             interval.addRange(from, to);
 
             // Register use position at even instruction id.
-            interval.addUsePos(to & ~1, registerPriority);
+            interval.addUsePos(to & ~1, registerPriority, allocator.getOptions());
 
             if (Debug.isLogEnabled()) {
                 Debug.log("add use: %s, at %d (%s)", interval, to, registerPriority.name());
@@ -223,11 +223,11 @@
         }
 
         private void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority) {
-            if (!allocator.isProcessed(operand)) {
-                return;
-            }
             if (isRegister(operand)) {
-                addFixedDef(asRegisterValue(operand), op);
+                RegisterValue reg = asRegisterValue(operand);
+                if (allocator.isAllocatable(reg)) {
+                    addFixedDef(reg, op);
+                }
             } else {
                 assert isVariable(operand) : operand;
                 addVariableDef(asVariable(operand), op, registerPriority);
@@ -280,7 +280,7 @@
             }
             if (!(op instanceof LabelOp)) {
                 // no use positions for labels
-                interval.addUsePos(defPos, registerPriority);
+                interval.addUsePos(defPos, registerPriority, allocator.getOptions());
             }
 
             changeSpillDefinitionPos(op, operand, interval, defPos);
@@ -297,11 +297,11 @@
         }
 
         private void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority) {
-            if (!allocator.isProcessed(operand)) {
-                return;
-            }
             if (isRegister(operand)) {
-                addFixedTemp(asRegisterValue(operand), tempPos);
+                RegisterValue reg = asRegisterValue(operand);
+                if (allocator.isAllocatable(reg)) {
+                    addFixedTemp(reg, tempPos);
+                }
             } else {
                 assert isVariable(operand) : operand;
                 addVariableTemp(asVariable(operand), tempPos, registerPriority);
@@ -325,7 +325,7 @@
                 interval.setFrom(tempPos);
             }
 
-            interval.addUsePos(tempPos, registerPriority);
+            interval.addUsePos(tempPos, registerPriority, allocator.getOptions());
             interval.addMaterializationValue(null);
 
             if (Debug.isLogEnabled()) {
@@ -404,9 +404,9 @@
                                     return null;
                                 }
                                 from = getIntervalHint(toValue);
-                                to = allocator.getOrCreateInterval(fromValue);
+                                to = allocator.getOrCreateInterval(asVariable(fromValue));
                             } else {
-                                to = allocator.getOrCreateInterval(toValue);
+                                to = allocator.getOrCreateInterval(asVariable(toValue));
                                 from = getIntervalHint(fromValue);
                             }
 
@@ -699,7 +699,7 @@
             if (isRegister(from)) {
                 return allocator.getOrCreateFixedInterval(asRegisterValue(from));
             }
-            return allocator.getOrCreateInterval(from);
+            return allocator.getOrCreateInterval(asVariable(from));
         }
 
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java	Thu Jun 01 02:21:18 2017 +0000
@@ -24,7 +24,6 @@
 
 import static jdk.vm.ci.code.CodeUtil.isEven;
 import static jdk.vm.ci.code.ValueUtil.asRegister;
-import static jdk.vm.ci.code.ValueUtil.asRegisterValue;
 import static jdk.vm.ci.code.ValueUtil.isIllegal;
 import static jdk.vm.ci.code.ValueUtil.isLegal;
 import static jdk.vm.ci.code.ValueUtil.isRegister;
@@ -33,7 +32,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.EnumSet;
+import java.util.Comparator;
 
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
@@ -46,11 +45,8 @@
 import org.graalvm.compiler.debug.Indent;
 import org.graalvm.compiler.lir.LIR;
 import org.graalvm.compiler.lir.LIRInstruction;
-import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
-import org.graalvm.compiler.lir.LIRValueUtil;
 import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
-import org.graalvm.compiler.lir.ValueConsumer;
 import org.graalvm.compiler.lir.Variable;
 import org.graalvm.compiler.lir.VirtualStackSlot;
 import org.graalvm.compiler.lir.alloc.trace.GlobalLivenessInfo;
@@ -149,27 +145,26 @@
         abstract boolean apply(TraceInterval i);
     }
 
-    static final IntervalPredicate IS_PRECOLORED_INTERVAL = new IntervalPredicate() {
-
-        @Override
-        public boolean apply(TraceInterval i) {
-            return isRegister(i.operand);
-        }
-    };
-
     static final IntervalPredicate IS_VARIABLE_INTERVAL = new IntervalPredicate() {
 
         @Override
         public boolean apply(TraceInterval i) {
-            return isVariable(i.operand);
+            // all TraceIntervals are variable intervals
+            return true;
         }
     };
-
-    static final IntervalPredicate IS_STACK_INTERVAL = new IntervalPredicate() {
+    private static final Comparator<TraceInterval> SORT_BY_FROM_COMP = new Comparator<TraceInterval>() {
 
         @Override
-        public boolean apply(TraceInterval i) {
-            return !isRegister(i.operand);
+        public int compare(TraceInterval a, TraceInterval b) {
+            return a.from() - b.from();
+        }
+    };
+    private static final Comparator<TraceInterval> SORT_BY_SPILL_POS_COMP = new Comparator<TraceInterval>() {
+
+        @Override
+        public int compare(TraceInterval a, TraceInterval b) {
+            return a.spillDefinitionPos() - b.spillDefinitionPos();
         }
     };
 
@@ -185,7 +180,9 @@
     private static <T extends IntervalHint> boolean isSortedByFrom(T[] intervals) {
         int from = -1;
         for (T interval : intervals) {
-            assert interval != null;
+            if (interval == null) {
+                continue;
+            }
             assert from <= interval.from();
             from = interval.from();
         }
@@ -202,13 +199,13 @@
         return true;
     }
 
-    private static <T extends IntervalHint> T[] sortIntervalsBeforeAllocation(T[] intervals, T[] sortedList) {
+    private static TraceInterval[] sortIntervalsBeforeAllocation(TraceInterval[] intervals, TraceInterval[] sortedList) {
         int sortedIdx = 0;
         int sortedFromMax = -1;
 
         // special sorting algorithm: the original interval-list is almost sorted,
         // only some intervals are swapped. So this is much faster than a complete QuickSort
-        for (T interval : intervals) {
+        for (TraceInterval interval : intervals) {
             if (interval != null) {
                 int from = interval.from();
 
@@ -237,11 +234,6 @@
          */
         private TraceInterval[] sortedIntervals;
 
-        /**
-         * Fixed intervals sorted by {@link FixedInterval#from()}.
-         */
-        private FixedInterval[] sortedFixedIntervals;
-
         private final Trace trace;
 
         public TraceLinearScan(Trace trace) {
@@ -254,14 +246,10 @@
         }
 
         /**
-         * Converts an operand (variable or register) to an index in a flat address space covering
-         * all the {@linkplain Variable variables} and {@linkplain RegisterValue registers} being
-         * processed by this allocator.
+         * @return {@link Variable#index}
          */
-        int operandNumber(Value operand) {
-            assert !isRegister(operand) : "Register do not have operand numbers: " + operand;
-            assert isVariable(operand) : "Unsupported Value " + operand;
-            return ((Variable) operand).index;
+        int operandNumber(Variable operand) {
+            return operand.index;
         }
 
         OptionValues getOptions() {
@@ -303,6 +291,10 @@
             return registerAttributes[reg.number];
         }
 
+        public boolean isAllocatable(RegisterValue register) {
+            return attributes(register.getRegister()).isAllocatable();
+        }
+
         public MoveFactory getSpillMoveFactory() {
             return moveFactory;
         }
@@ -331,20 +323,20 @@
 
         /**
          * Returns a new spill slot or a cached entry if there is already one for the
-         * {@linkplain TraceInterval#operand variable}.
+         * {@linkplain TraceInterval variable}.
          */
         private AllocatableValue allocateSpillSlot(TraceInterval interval) {
-            int variableIndex = LIRValueUtil.asVariable(interval.splitParent().operand).index;
+            int variableIndex = interval.splitParent().operandNumber;
             OptionValues options = getOptions();
             if (TraceRegisterAllocationPhase.Options.TraceRACacheStackSlots.getValue(options)) {
                 AllocatableValue cachedStackSlot = cachedStackSlots[variableIndex];
                 if (cachedStackSlot != null) {
                     TraceRegisterAllocationPhase.globalStackSlots.increment();
-                    assert cachedStackSlot.getValueKind().equals(interval.kind()) : "CachedStackSlot: kind mismatch? " + interval.kind() + " vs. " + cachedStackSlot.getValueKind();
+                    assert cachedStackSlot.getValueKind().equals(getKind(interval)) : "CachedStackSlot: kind mismatch? " + getKind(interval) + " vs. " + cachedStackSlot.getValueKind();
                     return cachedStackSlot;
                 }
             }
-            VirtualStackSlot slot = frameMapBuilder.allocateSpillSlot(interval.kind());
+            VirtualStackSlot slot = frameMapBuilder.allocateSpillSlot(getKind(interval));
             if (TraceRegisterAllocationPhase.Options.TraceRACacheStackSlots.getValue(options)) {
                 cachedStackSlots[variableIndex] = slot;
             }
@@ -457,16 +449,13 @@
         }
 
         FixedInterval createFixedUnhandledList() {
-            assert isSortedByFrom(sortedFixedIntervals) : "interval list is not sorted";
+            assert isSortedByFrom(fixedIntervals) : "interval list is not sorted";
 
             FixedInterval list1 = FixedInterval.EndMarker;
 
             FixedInterval list1Prev = null;
-            FixedInterval v;
+            for (FixedInterval v : fixedIntervals) {
 
-            int n = sortedFixedIntervals.length;
-            for (int i = 0; i < n; i++) {
-                v = sortedFixedIntervals[i];
                 if (v == null) {
                     continue;
                 }
@@ -497,16 +486,6 @@
             sortedIntervals = TraceLinearScanPhase.sortIntervalsBeforeAllocation(intervals(), new TraceInterval[sortedLen]);
         }
 
-        protected void sortFixedIntervalsBeforeAllocation() {
-            int sortedLen = 0;
-            for (FixedInterval interval : fixedIntervals()) {
-                if (interval != null) {
-                    sortedLen++;
-                }
-            }
-            sortedFixedIntervals = TraceLinearScanPhase.sortIntervalsBeforeAllocation(fixedIntervals(), new FixedInterval[sortedLen]);
-        }
-
         void sortIntervalsAfterAllocation() {
             if (hasDerivedIntervals()) {
                 // no intervals have been added during allocation, so sorted list is already up to
@@ -520,7 +499,7 @@
             int newLen = newList.length;
 
             // conventional sort-algorithm for new intervals
-            Arrays.sort(newList, (TraceInterval a, TraceInterval b) -> a.from() - b.from());
+            Arrays.sort(newList, SORT_BY_FROM_COMP);
 
             // merge old and new list (both already sorted) into one combined list
             TraceInterval[] combinedList = new TraceInterval[oldLen + newLen];
@@ -543,7 +522,7 @@
         void sortIntervalsBySpillPos() {
             // TODO (JE): better algorithm?
             // conventional sort-algorithm for new intervals
-            Arrays.sort(sortedIntervals, (TraceInterval a, TraceInterval b) -> a.spillDefinitionPos() - b.spillDefinitionPos());
+            Arrays.sort(sortedIntervals, SORT_BY_SPILL_POS_COMP);
         }
 
         // wrapper for Interval.splitChildAtOpId that performs a bailout in product mode
@@ -565,7 +544,7 @@
             return interval.spillSlot();
         }
 
-        boolean isMaterialized(AllocatableValue operand, int opId, OperandMode mode) {
+        boolean isMaterialized(Variable operand, int opId, OperandMode mode) {
             TraceInterval interval = intervalFor(operand);
             assert interval != null : "interval must exist";
 
@@ -600,7 +579,6 @@
                     printIntervals("Before register allocation");
 
                     sortIntervalsBeforeAllocation();
-                    sortFixedIntervalsBeforeAllocation();
 
                     TRACE_LINEAR_SCAN_REGISTER_ALLOCATION_PHASE.apply(target, lirGenRes, trace, spillMoveFactory, registerAllocationConfig, traceBuilderResult, this, false);
                     printIntervals("After register allocation");
@@ -671,7 +649,7 @@
                         throw new GraalError("");
                     }
 
-                    if (isVariable(i1.operand) && i1.kind().equals(LIRKind.Illegal)) {
+                    if (getKind(i1).equals(LIRKind.Illegal)) {
                         Debug.log("Interval %d has no type assigned", i1.operandNumber);
                         Debug.log(i1.logString());
                         throw new GraalError("");
@@ -736,74 +714,6 @@
             }
         }
 
-        class CheckConsumer implements ValueConsumer {
-
-            boolean ok;
-            FixedInterval curInterval;
-
-            @Override
-            public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                if (isRegister(operand)) {
-                    if (fixedIntervalFor(asRegisterValue(operand)) == curInterval) {
-                        ok = true;
-                    }
-                }
-            }
-        }
-
-        @SuppressWarnings("try")
-        void verifyNoOopsInFixedIntervals() {
-            try (Indent indent = Debug.logAndIndent("verifying that no oops are in fixed intervals *")) {
-                CheckConsumer checkConsumer = new CheckConsumer();
-
-                TraceInterval otherIntervals;
-                FixedInterval fixedInts = createFixedUnhandledList();
-                // to ensure a walking until the last instruction id, add a dummy interval
-                // with a high operation id
-                otherIntervals = new TraceInterval(Value.ILLEGAL, -1, getOptions());
-                otherIntervals.addRange(Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1);
-                TraceIntervalWalker iw = new TraceIntervalWalker(this, fixedInts, otherIntervals);
-
-                for (AbstractBlockBase<?> block : sortedBlocks()) {
-                    ArrayList<LIRInstruction> instructions = getLIR().getLIRforBlock(block);
-
-                    for (int j = 0; j < instructions.size(); j++) {
-                        LIRInstruction op = instructions.get(j);
-
-                        if (op.hasState()) {
-                            iw.walkBefore(op.id());
-                            boolean checkLive = true;
-
-                            /*
-                             * Make sure none of the fixed registers is live across an oopmap since
-                             * we can't handle that correctly.
-                             */
-                            if (checkLive) {
-                                for (FixedInterval interval = iw.activeFixedList.getFixed(); interval != FixedInterval.EndMarker; interval = interval.next) {
-                                    if (interval.to() > op.id() + 1) {
-                                        /*
-                                         * This interval is live out of this op so make sure that
-                                         * this interval represents some value that's referenced by
-                                         * this op either as an input or output.
-                                         */
-                                        checkConsumer.curInterval = interval;
-                                        checkConsumer.ok = false;
-
-                                        op.visitEachInput(checkConsumer);
-                                        op.visitEachAlive(checkConsumer);
-                                        op.visitEachTemp(checkConsumer);
-                                        op.visitEachOutput(checkConsumer);
-
-                                        assert checkConsumer.ok : "fixed intervals should never be live across an oopmap point";
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
         public LIR getLIR() {
             return res.getLIR();
         }
@@ -872,14 +782,14 @@
         private AbstractBlockBase<?>[] opIdToBlockMap;
 
         /**
-         * Map from {@linkplain #operandNumber(Value) operand numbers} to intervals.
+         * Map from {@linkplain #operandNumber operand numbers} to intervals.
          */
         TraceInterval[] intervals() {
             return intervals;
         }
 
         /**
-         * Map from {@linkplain #operandNumber(Value) operand numbers} to intervals.
+         * Map from {@linkplain Register#number} to fixed intervals.
          */
         FixedInterval[] fixedIntervals() {
             return fixedIntervals;
@@ -910,10 +820,11 @@
          * @param operand the operand for the interval
          * @return the created interval
          */
-        private TraceInterval createInterval(AllocatableValue operand) {
+        private TraceInterval createInterval(Variable operand) {
             assert isLegal(operand);
             int operandNumber = operandNumber(operand);
-            TraceInterval interval = new TraceInterval(operand, operandNumber, getOptions());
+            assert operand.index == operandNumber;
+            TraceInterval interval = new TraceInterval(operand);
             assert operandNumber < intervalsSize;
             assert intervals[operandNumber] == null;
             intervals[operandNumber] = interval;
@@ -934,7 +845,7 @@
                 intervals = Arrays.copyOf(intervals, intervals.length + (intervals.length >> SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT) + 1);
             }
             // increments intervalsSize
-            Variable variable = createVariable(source.kind());
+            Variable variable = createVariable(getKind(source));
 
             assert intervalsSize <= intervals.length;
 
@@ -976,7 +887,7 @@
             }
         }
 
-        TraceInterval intervalFor(Value operand) {
+        TraceInterval intervalFor(Variable operand) {
             return intervalFor(operandNumber(operand));
         }
 
@@ -985,7 +896,7 @@
             return intervals[operandNumber];
         }
 
-        TraceInterval getOrCreateInterval(AllocatableValue operand) {
+        TraceInterval getOrCreateInterval(Variable operand) {
             TraceInterval ret = intervalFor(operand);
             if (ret == null) {
                 return createInterval(operand);
@@ -1095,6 +1006,34 @@
             return TraceUtil.hasInterTraceSuccessor(traceBuilderResult, trace, block);
         }
 
+        private void printInterval(TraceInterval interval, IntervalVisitor visitor) {
+            Value hint = interval.locationHint(false) != null ? interval.locationHint(false).location() : null;
+            AllocatableValue operand = getOperand(interval);
+            String type = getKind(interval).getPlatformKind().toString();
+            visitor.visitIntervalStart(getOperand(interval.splitParent()), operand, interval.location(), hint, type);
+
+            // print ranges
+            visitor.visitRange(interval.from(), interval.to());
+
+            // print use positions
+            int prev = -1;
+            for (int i = interval.numUsePos() - 1; i >= 0; --i) {
+                assert prev < interval.getUsePos(i) : "use positions not sorted";
+                visitor.visitUsePos(interval.getUsePos(i), interval.getUsePosRegisterPriority(i));
+                prev = interval.getUsePos(i);
+            }
+
+            visitor.visitIntervalEnd(interval.spillState());
+        }
+
+        AllocatableValue getOperand(TraceInterval interval) {
+            return interval.operand;
+        }
+
+        ValueKind<?> getKind(TraceInterval interval) {
+            return getOperand(interval).getValueKind();
+        }
+
     }
 
     public static boolean verifyEquals(TraceLinearScan a, TraceLinearScan b) {
@@ -1124,7 +1063,7 @@
             return;
         }
         assert b != null : "Second interval is null but forst is: " + a;
-        assert a.operand.equals(b.operand) : "Operand mismatch: " + a + " vs. " + b;
+        assert a.operandNumber == b.operandNumber : "Operand mismatch: " + a + " vs. " + b;
         assert a.from() == b.from() : "From mismatch: " + a + " vs. " + b;
         assert a.to() == b.to() : "To mismatch: " + a + " vs. " + b;
         assert verifyIntervalsEquals(a, b);
@@ -1209,23 +1148,4 @@
 
     }
 
-    private static void printInterval(TraceInterval interval, IntervalVisitor visitor) {
-        Value hint = interval.locationHint(false) != null ? interval.locationHint(false).location() : null;
-        AllocatableValue operand = interval.operand;
-        String type = isRegister(operand) ? "fixed" : operand.getValueKind().getPlatformKind().toString();
-        visitor.visitIntervalStart(interval.splitParent().operand, operand, interval.location(), hint, type);
-
-        // print ranges
-        visitor.visitRange(interval.from(), interval.to());
-
-        // print use positions
-        int prev = -1;
-        for (int i = interval.numUsePos() - 1; i >= 0; --i) {
-            assert prev < interval.getUsePos(i) : "use positions not sorted";
-            visitor.visitUsePos(interval.getUsePos(i), interval.getUsePosRegisterPriority(i));
-            prev = interval.getUsePos(i);
-        }
-
-        visitor.visitIntervalEnd(interval.spillState());
-    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanResolveDataFlowPhase.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanResolveDataFlowPhase.java	Thu Jun 01 02:21:18 2017 +0000
@@ -25,6 +25,7 @@
 import static jdk.vm.ci.code.ValueUtil.isRegister;
 import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts;
 import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
+import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
 import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
 import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
@@ -190,13 +191,13 @@
                 // no need to handle virtual stack slots
                 return;
             }
-            TraceInterval toParent = allocator.intervalFor(phiTo);
+            TraceInterval toParent = allocator.intervalFor(asVariable(phiTo));
             if (isConstantValue(phiFrom)) {
                 numResolutionMoves.increment();
                 TraceInterval toInterval = allocator.splitChildAtOpId(toParent, toId, LIRInstruction.OperandMode.DEF);
                 moveResolver.addMapping(asConstant(phiFrom), toInterval);
             } else {
-                addMapping(allocator.intervalFor(phiFrom), toParent, fromId, toId, moveResolver);
+                addMapping(allocator.intervalFor(asVariable(phiFrom)), toParent, fromId, toId, moveResolver);
             }
         }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java	Thu Jun 01 02:21:18 2017 +0000
@@ -39,12 +39,14 @@
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.debug.Indent;
 import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.LIRValueUtil;
 import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
 import org.graalvm.compiler.lir.StandardOp.LabelOp;
 import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
 import org.graalvm.compiler.lir.alloc.OutOfRegistersException;
 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.RegisterPriority;
 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.SpillState;
+import org.graalvm.compiler.lir.alloc.trace.lsra.TraceInterval.State;
 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase.TraceLinearScan;
 import org.graalvm.compiler.lir.ssa.SSAUtil;
 
@@ -53,7 +55,110 @@
 
 /**
  */
-final class TraceLinearScanWalker extends TraceIntervalWalker {
+final class TraceLinearScanWalker {
+
+    /**
+     * Adds an interval to a list sorted by {@linkplain FixedInterval#currentFrom() current from}
+     * positions.
+     *
+     * @param list the list
+     * @param interval the interval to add
+     * @return the new head of the list
+     */
+    private static FixedInterval addToListSortedByCurrentFromPositions(FixedInterval list, FixedInterval interval) {
+        FixedInterval prev = null;
+        FixedInterval cur = list;
+        while (cur.currentFrom() < interval.currentFrom()) {
+            prev = cur;
+            cur = cur.next;
+        }
+        FixedInterval result = list;
+        if (prev == null) {
+            // add to head of list
+            result = interval;
+        } else {
+            // add before 'cur'
+            prev.next = interval;
+        }
+        interval.next = cur;
+        return result;
+    }
+
+    /**
+     * Adds an interval to a list sorted by {@linkplain TraceInterval#from() current from}
+     * positions.
+     *
+     * @param list the list
+     * @param interval the interval to add
+     * @return the new head of the list
+     */
+    private static TraceInterval addToListSortedByFromPositions(TraceInterval list, TraceInterval interval) {
+        TraceInterval prev = null;
+        TraceInterval cur = list;
+        while (cur.from() < interval.from()) {
+            prev = cur;
+            cur = cur.next;
+        }
+        TraceInterval result = list;
+        if (prev == null) {
+            // add to head of list
+            result = interval;
+        } else {
+            // add before 'cur'
+            prev.next = interval;
+        }
+        interval.next = cur;
+        return result;
+    }
+
+    /**
+     * Adds an interval to a list sorted by {@linkplain TraceInterval#from() start} positions and
+     * {@linkplain TraceInterval#firstUsage(RegisterPriority) first usage} positions.
+     *
+     * @param list the list
+     * @param interval the interval to add
+     * @return the new head of the list
+     */
+    private static TraceInterval addToListSortedByStartAndUsePositions(TraceInterval list, TraceInterval interval) {
+        TraceInterval newHead = list;
+        TraceInterval prev = null;
+        TraceInterval cur = newHead;
+        while (cur.from() < interval.from() || (cur.from() == interval.from() && cur.firstUsage(RegisterPriority.None) < interval.firstUsage(RegisterPriority.None))) {
+            prev = cur;
+            cur = cur.next;
+        }
+        if (prev == null) {
+            newHead = interval;
+        } else {
+            prev.next = interval;
+        }
+        interval.next = cur;
+        return newHead;
+    }
+
+    /**
+     * Removes an interval from a list.
+     *
+     * @param list the list
+     * @param interval the interval to remove
+     * @return the new head of the list
+     */
+    private static TraceInterval removeAny(TraceInterval list, TraceInterval interval) {
+        TraceInterval newHead = list;
+        TraceInterval prev = null;
+        TraceInterval cur = newHead;
+        while (cur != interval) {
+            assert cur != null && cur != TraceInterval.EndMarker : "interval has not been found in list: " + interval;
+            prev = cur;
+            cur = cur.next;
+        }
+        if (prev == null) {
+            newHead = cur.next;
+        } else {
+            prev.next = cur.next;
+        }
+        return newHead;
+    }
 
     private Register[] availableRegs;
 
@@ -69,6 +174,30 @@
 
     private int maxReg;
 
+    private final TraceLinearScan allocator;
+
+    /**
+     * Sorted list of intervals, not live before the current position.
+     */
+    private TraceInterval unhandledAnyList;
+
+    /**
+     * Sorted list of intervals, live at the current position.
+     */
+    private TraceInterval activeAnyList;
+
+    private FixedInterval activeFixedList;
+
+    /**
+     * Sorted list of intervals in a life time hole at the current position.
+     */
+    private FixedInterval inactiveFixedList;
+
+    /**
+     * The current position (intercept point through the intervals).
+     */
+    private int currentPosition;
+
     /**
      * Only 10% of the lists in {@link #spillIntervals} are actually used. But when they are used,
      * they can grow quite long. The maximum length observed was 45 (all numbers taken from a
@@ -92,7 +221,14 @@
     }
 
     TraceLinearScanWalker(TraceLinearScan allocator, FixedInterval unhandledFixedFirst, TraceInterval unhandledAnyFirst) {
-        super(allocator, unhandledFixedFirst, unhandledAnyFirst);
+        this.allocator = allocator;
+
+        unhandledAnyList = unhandledAnyFirst;
+        activeAnyList = TraceInterval.EndMarker;
+        activeFixedList = FixedInterval.EndMarker;
+        // we don't need a separate unhandled list for fixed.
+        inactiveFixedList = unhandledFixedFirst;
+        currentPosition = -1;
 
         moveResolver = allocator.createMoveResolver();
         int numRegs = allocator.getRegisters().size();
@@ -190,7 +326,7 @@
     }
 
     private void freeExcludeActiveFixed() {
-        FixedInterval interval = activeFixedList.getFixed();
+        FixedInterval interval = activeFixedList;
         while (interval != FixedInterval.EndMarker) {
             assert isRegister(interval.location()) : "active interval must have a register assigned";
             excludeFromUse(interval);
@@ -199,7 +335,7 @@
     }
 
     private void freeExcludeActiveAny() {
-        TraceInterval interval = activeAnyList.getAny();
+        TraceInterval interval = activeAnyList;
         while (interval != TraceInterval.EndMarker) {
             assert isRegister(interval.location()) : "active interval must have a register assigned";
             excludeFromUse(interval);
@@ -208,7 +344,7 @@
     }
 
     private void freeCollectInactiveFixed(TraceInterval current) {
-        FixedInterval interval = inactiveFixedList.getFixed();
+        FixedInterval interval = inactiveFixedList;
         while (interval != FixedInterval.EndMarker) {
             if (current.to() <= interval.from()) {
                 assert interval.intersectsAt(current) == -1 : "must not intersect";
@@ -221,7 +357,7 @@
     }
 
     private void spillExcludeActiveFixed() {
-        FixedInterval interval = activeFixedList.getFixed();
+        FixedInterval interval = activeFixedList;
         while (interval != FixedInterval.EndMarker) {
             excludeFromUse(interval);
             interval = interval.next;
@@ -229,7 +365,7 @@
     }
 
     private void spillBlockInactiveFixed(TraceInterval current) {
-        FixedInterval interval = inactiveFixedList.getFixed();
+        FixedInterval interval = inactiveFixedList;
         while (interval != FixedInterval.EndMarker) {
             if (current.to() > interval.currentFrom()) {
                 setBlockPos(interval, interval.currentIntersectsAt(current));
@@ -242,7 +378,7 @@
     }
 
     private void spillCollectActiveAny(RegisterPriority registerPriority) {
-        TraceInterval interval = activeAnyList.getAny();
+        TraceInterval interval = activeAnyList;
         while (interval != TraceInterval.EndMarker) {
             setUsePos(interval, Math.min(interval.nextUsage(registerPriority, currentPosition), interval.to()), false);
             interval = interval.next;
@@ -441,7 +577,7 @@
             splitPart.setInsertMoveWhenActivated(moveNecessary);
 
             assert splitPart.from() >= currentPosition : "cannot append new interval before current walk position";
-            unhandledAnyList.addToListSortedByStartAndUsePositions(splitPart);
+            unhandledAnyList = TraceLinearScanWalker.addToListSortedByStartAndUsePositions(unhandledAnyList, splitPart);
 
             if (Debug.isLogEnabled()) {
                 Debug.log("left interval  %s: %s", moveNecessary ? "      " : "", interval.logString());
@@ -851,7 +987,7 @@
             }
 
             splitPos = usePos[reg.number];
-            interval.assignLocation(reg.asValue(interval.kind()));
+            interval.assignLocation(reg.asValue(allocator.getKind(interval)));
             if (Debug.isLogEnabled()) {
                 Debug.log("selected register %d (%s)", reg.number, reg);
             }
@@ -978,7 +1114,7 @@
             assert splitPos > 0 : "invalid splitPos";
             assert needSplit || splitPos > interval.from() : "splitting interval at from";
 
-            interval.assignLocation(reg.asValue(interval.kind()));
+            interval.assignLocation(reg.asValue(allocator.getKind(interval)));
             if (needSplit) {
                 // register not available for full interval : so split it
                 splitWhenPartialRegisterAvailable(interval, splitPos);
@@ -990,7 +1126,7 @@
         }
     }
 
-    protected void dumpLIRAndIntervals(String description) {
+    private void dumpLIRAndIntervals(String description) {
         Debug.dump(Debug.INFO_LEVEL, allocator.getLIR(), description);
         allocator.printIntervals(description);
     }
@@ -1035,7 +1171,7 @@
     }
 
     private void initVarsForAlloc(TraceInterval interval) {
-        AllocatableRegisters allocatableRegisters = allocator.getRegisterAllocationConfig().getAllocatableRegisters(interval.kind().getPlatformKind());
+        AllocatableRegisters allocatableRegisters = allocator.getRegisterAllocationConfig().getAllocatableRegisters(allocator.getKind(interval).getPlatformKind());
         availableRegs = allocatableRegisters.allocatableRegisters;
         minReg = allocatableRegisters.minRegisterNumber;
         maxReg = allocatableRegisters.maxRegisterNumber;
@@ -1045,7 +1181,8 @@
         if (ValueMoveOp.isValueMoveOp(op)) {
             ValueMoveOp move = ValueMoveOp.asValueMoveOp(op);
             if (isVariable(move.getInput()) && isVariable(move.getResult())) {
-                return move.getInput() != null && move.getInput().equals(from.operand) && move.getResult() != null && move.getResult().equals(to.operand);
+                return move.getInput() != null && LIRValueUtil.asVariable(move.getInput()).index == from.operandNumber && move.getResult() != null &&
+                                LIRValueUtil.asVariable(move.getResult()).index == to.operandNumber;
             }
         }
         return false;
@@ -1111,9 +1248,8 @@
     }
 
     // allocate a physical register or memory location to an interval
-    @Override
     @SuppressWarnings("try")
-    protected boolean activateCurrent(TraceInterval interval) {
+    private boolean activateCurrent(TraceInterval interval) {
         if (Debug.isLogEnabled()) {
             logCurrentStatus();
         }
@@ -1121,7 +1257,6 @@
 
         try (Indent indent = Debug.logAndIndent("activating interval %s,  splitParent: %d", interval, interval.splitParent().operandNumber)) {
 
-            final Value operand = interval.operand;
             if (interval.location() != null && isStackSlotValue(interval.location())) {
                 // activating an interval that has a stack slot assigned . split it at first use
                 // position
@@ -1161,7 +1296,7 @@
             if (interval.insertMoveWhenActivated()) {
                 assert interval.isSplitChild();
                 assert interval.currentSplitChild() != null;
-                assert !interval.currentSplitChild().operand.equals(operand) : "cannot insert move between same interval";
+                assert interval.currentSplitChild().operandNumber != interval.operandNumber : "cannot insert move between same interval";
                 if (Debug.isLogEnabled()) {
                     Debug.log("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber);
                 }
@@ -1179,4 +1314,219 @@
         // must be called when all intervals are allocated
         moveResolver.resolveAndAppendMoves();
     }
+
+    @SuppressWarnings("try")
+    private void logCurrentStatus() {
+        try (Indent i = Debug.logAndIndent("active:")) {
+            logList(activeFixedList);
+            logList(activeAnyList);
+        }
+        try (Indent i = Debug.logAndIndent("inactive(fixed):")) {
+            logList(inactiveFixedList);
+        }
+    }
+
+    void walk() {
+        walkTo(Integer.MAX_VALUE);
+    }
+
+    private void removeFromList(TraceInterval interval) {
+        activeAnyList = TraceLinearScanWalker.removeAny(activeAnyList, interval);
+    }
+
+    /**
+     * Walks up to {@code from} and updates the state of {@link FixedInterval fixed intervals}.
+     *
+     * Fixed intervals can switch back and forth between the states {@link State#Active} and
+     * {@link State#Inactive} (and eventually to {@link State#Handled} but handled intervals are not
+     * managed).
+     */
+    @SuppressWarnings("try")
+    private void walkToFixed(State state, int from) {
+        assert state == State.Active || state == State.Inactive : "wrong state";
+        FixedInterval prevprev = null;
+        FixedInterval prev = (state == State.Active) ? activeFixedList : inactiveFixedList;
+        FixedInterval next = prev;
+        if (Debug.isLogEnabled()) {
+            try (Indent i = Debug.logAndIndent("walkToFixed(%s, %d):", state, from)) {
+                logList(next);
+            }
+        }
+        while (next.currentFrom() <= from) {
+            FixedInterval cur = next;
+            next = cur.next;
+
+            boolean rangeHasChanged = false;
+            while (cur.currentTo() <= from) {
+                cur.nextRange();
+                rangeHasChanged = true;
+            }
+
+            // also handle move from inactive list to active list
+            rangeHasChanged = rangeHasChanged || (state == State.Inactive && cur.currentFrom() <= from);
+
+            if (rangeHasChanged) {
+                // remove cur from list
+                if (prevprev == null) {
+                    if (state == State.Active) {
+                        activeFixedList = next;
+                    } else {
+                        inactiveFixedList = next;
+                    }
+                } else {
+                    prevprev.next = next;
+                }
+                prev = next;
+                TraceInterval.State newState;
+                if (cur.currentAtEnd()) {
+                    // move to handled state (not maintained as a list)
+                    newState = State.Handled;
+                } else {
+                    if (cur.currentFrom() <= from) {
+                        // sort into active list
+                        activeFixedList = TraceLinearScanWalker.addToListSortedByCurrentFromPositions(activeFixedList, cur);
+                        newState = State.Active;
+                    } else {
+                        // sort into inactive list
+                        inactiveFixedList = TraceLinearScanWalker.addToListSortedByCurrentFromPositions(inactiveFixedList, cur);
+                        newState = State.Inactive;
+                    }
+                    if (prev == cur) {
+                        assert state == newState;
+                        prevprev = prev;
+                        prev = cur.next;
+                    }
+                }
+                intervalMoved(cur, state, newState);
+            } else {
+                prevprev = prev;
+                prev = cur.next;
+            }
+        }
+    }
+
+    /**
+     * Walks up to {@code from} and updates the state of {@link TraceInterval intervals}.
+     *
+     * Trace intervals can switch once from {@link State#Unhandled} to {@link State#Active} and then
+     * to {@link State#Handled} but handled intervals are not managed.
+     */
+    @SuppressWarnings("try")
+    private void walkToAny(int from) {
+        TraceInterval prevprev = null;
+        TraceInterval prev = activeAnyList;
+        TraceInterval next = prev;
+        if (Debug.isLogEnabled()) {
+            try (Indent i = Debug.logAndIndent("walkToAny(%d):", from)) {
+                logList(next);
+            }
+        }
+        while (next.from() <= from) {
+            TraceInterval cur = next;
+            next = cur.next;
+
+            if (cur.to() <= from) {
+                // remove cur from list
+                if (prevprev == null) {
+                    activeAnyList = next;
+                } else {
+                    prevprev.next = next;
+                }
+                intervalMoved(cur, State.Active, State.Handled);
+            } else {
+                prevprev = prev;
+            }
+            prev = next;
+        }
+    }
+
+    /**
+     * Get the next interval from {@linkplain #unhandledAnyList} which starts before or at
+     * {@code toOpId}. The returned interval is removed.
+     *
+     * @postcondition all intervals in {@linkplain #unhandledAnyList} start after {@code toOpId}.
+     *
+     * @return The next interval or null if there is no {@linkplain #unhandledAnyList unhandled}
+     *         interval at position {@code toOpId}.
+     */
+    private TraceInterval nextInterval(int toOpId) {
+        TraceInterval any = unhandledAnyList;
+
+        if (any != TraceInterval.EndMarker) {
+            TraceInterval currentInterval = unhandledAnyList;
+            if (toOpId < currentInterval.from()) {
+                return null;
+            }
+
+            unhandledAnyList = currentInterval.next;
+            currentInterval.next = TraceInterval.EndMarker;
+            return currentInterval;
+        }
+        return null;
+
+    }
+
+    /**
+     * Walk up to {@code toOpId}.
+     *
+     * @postcondition {@link #currentPosition} is set to {@code toOpId}, {@link #activeFixedList}
+     *                and {@link #inactiveFixedList} are populated.
+     */
+    @SuppressWarnings("try")
+    private void walkTo(int toOpId) {
+        assert currentPosition <= toOpId : "can not walk backwards";
+        for (TraceInterval currentInterval = nextInterval(toOpId); currentInterval != null; currentInterval = nextInterval(toOpId)) {
+            int opId = currentInterval.from();
+
+            // set currentPosition prior to call of walkTo
+            currentPosition = opId;
+
+            // update unhandled stack intervals
+            // updateUnhandledStackIntervals(opId);
+
+            // call walkTo even if currentPosition == id
+            walkToFixed(State.Active, opId);
+            walkToFixed(State.Inactive, opId);
+            walkToAny(opId);
+
+            try (Indent indent = Debug.logAndIndent("walk to op %d", opId)) {
+                if (activateCurrent(currentInterval)) {
+                    activeAnyList = TraceLinearScanWalker.addToListSortedByFromPositions(activeAnyList, currentInterval);
+                    intervalMoved(currentInterval, State.Unhandled, State.Active);
+                }
+            }
+        }
+        // set currentPosition prior to call of walkTo
+        currentPosition = toOpId;
+
+        if (currentPosition <= allocator.maxOpId()) {
+            // update unhandled stack intervals
+            // updateUnhandledStackIntervals(toOpId);
+
+            // call walkTo if still in range
+            walkToFixed(State.Active, toOpId);
+            walkToFixed(State.Inactive, toOpId);
+            walkToAny(toOpId);
+        }
+    }
+
+    private static void logList(FixedInterval i) {
+        for (FixedInterval interval = i; interval != FixedInterval.EndMarker; interval = interval.next) {
+            Debug.log("%s", interval.logString());
+        }
+    }
+
+    private static void logList(TraceInterval i) {
+        for (TraceInterval interval = i; interval != TraceInterval.EndMarker; interval = interval.next) {
+            Debug.log("%s", interval.logString());
+        }
+    }
+
+    private static void intervalMoved(IntervalHint interval, State from, State to) {
+        // intervalMoved() is called whenever an interval moves from one interval list to another.
+        // In the implementation of this method it is prohibited to move the interval to any list.
+        if (Debug.isLogEnabled()) {
+            Debug.log("interval moved from %s to %s: %s", from, to, interval.logString());
+        }
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLocalMoveResolver.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLocalMoveResolver.java	Thu Jun 01 02:21:18 2017 +0000
@@ -323,11 +323,11 @@
     }
 
     private void insertMove(TraceInterval fromInterval, TraceInterval toInterval) {
-        assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
-        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind(), allocator.getRegisterAllocationConfig()) : "move between different types";
+        assert fromInterval.operandNumber != toInterval.operandNumber : "from and to interval equal: " + fromInterval;
+        assert LIRKind.verifyMoveKinds(allocator.getKind(toInterval), allocator.getKind(fromInterval), allocator.getRegisterAllocationConfig()) : "move between different types";
         assert insertIdx != -1 : "must setup insert position first";
 
-        insertionBuffer.append(insertIdx, createMove(fromInterval.operand, toInterval.operand, fromInterval.location(), toInterval.location()));
+        insertionBuffer.append(insertIdx, createMove(allocator.getOperand(fromInterval), allocator.getOperand(toInterval), fromInterval.location(), toInterval.location()));
 
         if (Debug.isLogEnabled()) {
             Debug.log("insert move from %s to %s at %d", fromInterval, toInterval, insertIdx);
@@ -335,8 +335,8 @@
     }
 
     /**
-     * @param fromOpr {@link TraceInterval#operand operand} of the {@code from} interval
-     * @param toOpr {@link TraceInterval#operand operand} of the {@code to} interval
+     * @param fromOpr {@link TraceInterval operand} of the {@code from} interval
+     * @param toOpr {@link TraceInterval operand} of the {@code to} interval
      * @param fromLocation {@link TraceInterval#location() location} of the {@code to} interval
      * @param toLocation {@link TraceInterval#location() location} of the {@code to} interval
      */
@@ -350,7 +350,7 @@
     private void insertMove(Constant fromOpr, TraceInterval toInterval) {
         assert insertIdx != -1 : "must setup insert position first";
 
-        AllocatableValue toOpr = toInterval.operand;
+        AllocatableValue toOpr = allocator.getOperand(toInterval);
         LIRInstruction move = getAllocator().getSpillMoveFactory().createLoad(toOpr, fromOpr);
         insertionBuffer.append(insertIdx, move);
 
@@ -436,7 +436,7 @@
             // one stack slot to another can happen (not allowed by LIRAssembler
             AllocatableValue spillSlot1 = fromInterval1.spillSlot();
             if (spillSlot1 == null) {
-                spillSlot1 = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval1.kind());
+                spillSlot1 = getAllocator().getFrameMapBuilder().allocateSpillSlot(allocator.getKind(fromInterval1));
                 fromInterval1.setSpillSlot(spillSlot1);
                 cycleBreakingSlotsAllocated.increment();
             }
@@ -448,7 +448,7 @@
         int stackSpillCandidate = 0;
         TraceInterval fromInterval = getMappingFrom(stackSpillCandidate);
         // allocate new stack slot
-        VirtualStackSlot spillSlot = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval.kind());
+        VirtualStackSlot spillSlot = getAllocator().getFrameMapBuilder().allocateSpillSlot(allocator.getKind(fromInterval));
         spillInterval(stackSpillCandidate, fromInterval, spillSlot);
     }
 
@@ -535,9 +535,9 @@
             Debug.log("add move mapping from %s to %s", fromInterval, toInterval);
         }
 
-        assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
-        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind(), allocator.getRegisterAllocationConfig()) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", fromInterval.kind(),
-                        toInterval.kind(), fromInterval, toInterval);
+        assert fromInterval.operandNumber != toInterval.operandNumber : "from and to interval equal: " + fromInterval;
+        assert LIRKind.verifyMoveKinds(allocator.getKind(toInterval), allocator.getKind(fromInterval), allocator.getRegisterAllocationConfig()) : String.format(
+                        "Kind mismatch: %s vs. %s, from=%s, to=%s", allocator.getKind(fromInterval), allocator.getKind(toInterval), fromInterval, toInterval);
         mappingFrom.add(fromInterval);
         mappingFromOpr.add(null);
         mappingTo.add(toInterval);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java	Thu Jun 01 02:21:18 2017 +0000
@@ -52,6 +52,7 @@
 import org.graalvm.compiler.nodeinfo.InputType;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.java.ExceptionObjectNode;
 import org.graalvm.compiler.nodes.java.MonitorIdNode;
 import org.graalvm.compiler.nodes.virtual.EscapeObjectState;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
@@ -96,7 +97,7 @@
     /**
      * @see BytecodeFrame#rethrowException
      */
-    protected boolean rethrowException;
+    protected final boolean rethrowException;
 
     protected final boolean duringCall;
 
@@ -184,15 +185,17 @@
 
     /**
      * 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.
+     * value or thrown exception. This allows the parsing of an intrinsic to communicate the
+     * returned or thrown 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.getStackKind().getSlotCount(), 0, false, false, null, Collections.<EscapeObjectState> emptyList());
-        assert bci == BytecodeFrame.AFTER_BCI;
-        this.values.initialize(0, returnValue);
+    public FrameState(int bci, ValueNode returnValueOrExceptionObject) {
+        this(null, null, bci, 0, returnValueOrExceptionObject.getStackKind().getSlotCount(), 0, returnValueOrExceptionObject instanceof ExceptionObjectNode, false, null,
+                        Collections.<EscapeObjectState> emptyList());
+        assert (bci == BytecodeFrame.AFTER_BCI && !rethrowException()) || (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && rethrowException());
+        this.values.initialize(0, returnValueOrExceptionObject);
     }
 
     public FrameState(FrameState outerFrameState, Bytecode code, int bci, ValueNode[] locals, ValueNode[] stack, int stackSize, ValueNode[] locks, List<MonitorIdNode> monitorIds,
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java	Thu Jun 01 02:21:18 2017 +0000
@@ -22,20 +22,7 @@
  */
 package org.graalvm.compiler.nodes;
 
-import static org.graalvm.compiler.nodeinfo.InputType.Extension;
-import static org.graalvm.compiler.nodeinfo.InputType.Memory;
-import static org.graalvm.compiler.nodeinfo.InputType.State;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
-
-import java.util.Map;
-
+import jdk.vm.ci.meta.JavaKind;
 import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.Node;
@@ -55,7 +42,19 @@
 import org.graalvm.compiler.nodes.spi.UncheckedInterfaceProvider;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 
-import jdk.vm.ci.meta.JavaKind;
+import java.util.Map;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Extension;
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.InputType.State;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
 
 /**
  * The {@code InvokeNode} represents all kinds of method calls.
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java	Thu Jun 01 02:21:18 2017 +0000
@@ -22,14 +22,7 @@
  */
 package org.graalvm.compiler.nodes;
 
-import static org.graalvm.compiler.nodeinfo.InputType.Extension;
-import static org.graalvm.compiler.nodeinfo.InputType.Memory;
-import static org.graalvm.compiler.nodeinfo.InputType.State;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
-
-import java.util.Map;
-
+import jdk.vm.ci.meta.JavaKind;
 import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.Node;
@@ -45,7 +38,13 @@
 import org.graalvm.compiler.nodes.spi.UncheckedInterfaceProvider;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 
-import jdk.vm.ci.meta.JavaKind;
+import java.util.Map;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Extension;
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.InputType.State;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
 
 @NodeInfo(nameTemplate = "Invoke!#{p#targetMethod/s}", allowedUsageTypes = {Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
 public final class InvokeWithExceptionNode extends ControlSplitNode implements Invoke, MemoryCheckpoint.Single, LIRLowerable, UncheckedInterfaceProvider {
@@ -198,12 +197,30 @@
         GraphUtil.killCFG(edge);
     }
 
+    public void replaceWithNewBci(int newBci) {
+        AbstractBeginNode nextNode = next();
+        AbstractBeginNode exceptionObject = exceptionEdge;
+        setExceptionEdge(null);
+        setNext(null);
+        InvokeWithExceptionNode repl = graph().add(new InvokeWithExceptionNode(callTarget(), exceptionObject, newBci));
+        repl.setStateAfter(stateAfter);
+        this.setStateAfter(null);
+        this.replaceAtPredecessor(repl);
+        repl.setNext(nextNode);
+        boolean removed = this.callTarget().removeUsage(this);
+        assert removed;
+        this.replaceAtUsages(repl);
+        this.markDeleted();
+    }
+
     @Override
     public void intrinsify(Node node) {
         assert !(node instanceof ValueNode) || (((ValueNode) node).getStackKind() == JavaKind.Void) == (getStackKind() == JavaKind.Void);
         CallTargetNode call = callTarget;
         FrameState state = stateAfter();
-        killExceptionEdge();
+        if (exceptionEdge != null) {
+            killExceptionEdge();
+        }
         if (node instanceof StateSplit) {
             StateSplit stateSplit = (StateSplit) node;
             stateSplit.setStateAfter(state);
@@ -281,4 +298,16 @@
     public int getSuccessorCount() {
         return 2;
     }
+
+    /**
+     * Replaces this InvokeWithExceptionNode with a normal InvokeNode. Kills the exception dispatch
+     * code.
+     */
+    public InvokeNode replaceWithInvoke() {
+        InvokeNode invokeNode = graph().add(new InvokeNode(callTarget, bci));
+        AbstractBeginNode oldException = this.exceptionEdge;
+        graph().replaceSplitWithFixed(this, invokeNode, this.next());
+        GraphUtil.killCFG(oldException);
+        return invokeNode;
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java	Thu Jun 01 02:21:18 2017 +0000
@@ -96,7 +96,9 @@
                 SignedRemNode integerRemNode = (SignedRemNode) integerSubNode.getY();
                 if (integerSubNode.stamp().isCompatible(this.stamp()) && integerRemNode.stamp().isCompatible(this.stamp()) && integerSubNode.getX() == integerRemNode.getX() &&
                                 forY == integerRemNode.getY()) {
-                    return new SignedDivNode(integerSubNode.getX(), forY);
+                    SignedDivNode sd = new SignedDivNode(integerSubNode.getX(), forY);
+                    sd.stateBefore = this.stateBefore;
+                    return sd;
                 }
             }
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java	Thu Jun 01 02:21:18 2017 +0000
@@ -23,21 +23,21 @@
 package org.graalvm.compiler.nodes.graphbuilderconf;
 
 import static jdk.vm.ci.code.BytecodeFrame.AFTER_BCI;
+import static jdk.vm.ci.code.BytecodeFrame.AFTER_EXCEPTION_BCI;
 import static jdk.vm.ci.code.BytecodeFrame.BEFORE_BCI;
 import static jdk.vm.ci.code.BytecodeFrame.INVALID_FRAMESTATE_BCI;
-import static jdk.vm.ci.code.BytecodeFrame.UNKNOWN_BCI;
 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
 
 import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.nodes.AbstractMergeNode;
 import org.graalvm.compiler.nodes.FrameState;
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.nodes.StateSplit;
 import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.java.ExceptionObjectNode;
 
-import jdk.vm.ci.code.BytecodeFrame;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /**
@@ -98,41 +98,12 @@
 
     final CompilationContext compilationContext;
 
-    private final ValueNode[] args;
-
-    /**
-     * Gets the arguments to the intrinsic invocation (if available).
-     *
-     * @return {@code null} if the arguments to the intrinsic invocation are not available
-     */
-    public ValueNode[] getArgs() {
-        return args;
-    }
-
-    /**
-     * Gets the bytecode index of the intrinsic invocation (if available).
-     *
-     * @return {@value BytecodeFrame#UNKNOWN_BCI} if the bytecode index of the intrinsic invocation
-     *         is not available
-     */
-    public int bci() {
-        return bci;
-    }
-
-    private final int bci;
-
     public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, BytecodeProvider bytecodeProvider, CompilationContext compilationContext) {
-        this(method, intrinsic, bytecodeProvider, compilationContext, null, UNKNOWN_BCI);
-    }
-
-    public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, BytecodeProvider bytecodeProvider, CompilationContext compilationContext, ValueNode[] args, int bci) {
         this.method = method;
         this.intrinsic = intrinsic;
         this.bytecodeProvider = bytecodeProvider;
         assert bytecodeProvider != null;
         this.compilationContext = compilationContext;
-        this.args = args;
-        this.bci = bci;
         assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)");
     }
 
@@ -187,28 +158,40 @@
         void addSideEffect(StateSplit sideEffect);
     }
 
-    public FrameState createFrameState(StructuredGraph graph, SideEffectsState sideEffects, StateSplit forStateSplit) {
+    public FrameState createFrameState(StructuredGraph graph, SideEffectsState sideEffects, StateSplit forStateSplit, NodeSourcePosition sourcePosition) {
         assert forStateSplit != graph.start();
         if (forStateSplit.hasSideEffect()) {
             if (sideEffects.isAfterSideEffect()) {
                 // Only the last side effect on any execution path in a replacement
                 // can inherit the stateAfter of the replaced node
                 FrameState invalid = graph.add(new FrameState(INVALID_FRAMESTATE_BCI));
+                invalid.setNodeSourcePosition(sourcePosition);
                 for (StateSplit lastSideEffect : sideEffects.sideEffects()) {
                     lastSideEffect.setStateAfter(invalid);
                 }
             }
             sideEffects.addSideEffect(forStateSplit);
-            return graph.add(new FrameState(AFTER_BCI));
+            FrameState frameState;
+            if (forStateSplit instanceof ExceptionObjectNode) {
+                frameState = graph.add(new FrameState(AFTER_EXCEPTION_BCI, (ExceptionObjectNode) forStateSplit));
+            } else {
+                frameState = graph.add(new FrameState(AFTER_BCI));
+            }
+            frameState.setNodeSourcePosition(sourcePosition);
+            return frameState;
         } else {
             if (forStateSplit instanceof AbstractMergeNode) {
                 // Merge nodes always need a frame state
                 if (sideEffects.isAfterSideEffect()) {
                     // A merge after one or more side effects
-                    return graph.add(new FrameState(AFTER_BCI));
+                    FrameState frameState = graph.add(new FrameState(AFTER_BCI));
+                    frameState.setNodeSourcePosition(sourcePosition);
+                    return frameState;
                 } else {
                     // A merge before any side effects
-                    return graph.add(new FrameState(BEFORE_BCI));
+                    FrameState frameState = graph.add(new FrameState(BEFORE_BCI));
+                    frameState.setNodeSourcePosition(sourcePosition);
+                    return frameState;
                 }
             } else {
                 // Other non-side-effects do not need a state
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java	Thu Jun 01 02:21:18 2017 +0000
@@ -709,14 +709,42 @@
         return null;
     }
 
+    @SuppressWarnings("serial")
+    static class InvocationPlugRegistrationError extends GraalError {
+        InvocationPlugRegistrationError(Throwable cause) {
+            super(cause);
+        }
+    }
+
     private void flushDeferrables() {
         if (deferredRegistrations != null) {
             synchronized (this) {
                 if (deferredRegistrations != null) {
-                    for (Runnable deferrable : deferredRegistrations) {
-                        deferrable.run();
+                    try {
+                        for (Runnable deferrable : deferredRegistrations) {
+                            deferrable.run();
+                        }
+                        deferredRegistrations = null;
+                    } catch (InvocationPlugRegistrationError t) {
+                        throw t;
+                    } catch (Throwable t) {
+                        /*
+                         * Something went wrong during registration but it's possible we'll end up
+                         * coming back into this code. nulling out deferredRegistrations would just
+                         * cause other things to break and rerunning them would cause errors about
+                         * already registered plugins, so rethrow the original exception during
+                         * later invocations.
+                         */
+                        deferredRegistrations.clear();
+                        Runnable rethrow = new Runnable() {
+                            @Override
+                            public void run() {
+                                throw new InvocationPlugRegistrationError(t);
+                            }
+                        };
+                        deferredRegistrations.add(rethrow);
+                        rethrow.run();
                     }
-                    deferredRegistrations = null;
                 }
             }
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java	Thu Jun 01 02:21:18 2017 +0000
@@ -22,10 +22,8 @@
  */
 package org.graalvm.compiler.nodes.java;
 
-import static org.graalvm.compiler.nodeinfo.InputType.Memory;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
-
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
 import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.TypeReference;
@@ -41,7 +39,9 @@
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 
-import jdk.vm.ci.meta.MetaAccessProvider;
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
 /**
  * The entry to an exception handler with the exception coming from a call (as opposed to a local
@@ -60,6 +60,15 @@
         return LocationIdentity.any();
     }
 
+    /**
+     * An exception handler is an entry point to a method from the runtime and so represents an
+     * instruction that cannot be re-executed. It therefore needs a frame state.
+     */
+    @Override
+    public boolean hasSideEffect() {
+        return true;
+    }
+
     @Override
     public void lower(LoweringTool tool) {
         if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
@@ -83,6 +92,8 @@
     @Override
     public boolean verify() {
         assertTrue(stateAfter() != null, "an exception handler needs a frame state");
+        assertTrue(stateAfter().stackSize() == 1 && stateAfter().stackAt(0).stamp().getStackKind() == JavaKind.Object,
+                        "an exception handler's frame state must have only the exception on the stack");
         return super.verify();
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java	Thu Jun 01 02:21:18 2017 +0000
@@ -400,6 +400,14 @@
                 MapCursor<ValuePhiNode, PhiInfoElement> entries = mergeMap.getEntries();
                 while (entries.advance()) {
                     ValuePhiNode phi = entries.getKey();
+                    assert phi.isAlive() || phi.isDeleted();
+                    /*
+                     * Phi might have been killed already via a conditional elimination in another
+                     * branch.
+                     */
+                    if (phi.isDeleted()) {
+                        continue;
+                    }
                     PhiInfoElement phiInfoElements = entries.getValue();
                     Stamp bestPossibleStamp = null;
                     for (int i = 0; i < phi.valueCount(); ++i) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java	Thu Jun 01 02:21:18 2017 +0000
@@ -22,14 +22,14 @@
  */
 package org.graalvm.compiler.phases.common.inlining;
 
-import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
-import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
-import static org.graalvm.compiler.core.common.GraalOptions.HotSpotPrintInlining;
-
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.List;
-
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -38,7 +38,6 @@
 import org.graalvm.compiler.core.common.util.Util;
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.Debug.Scope;
-import org.graalvm.compiler.debug.Fingerprint;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.debug.internal.method.MethodMetricsImpl;
 import org.graalvm.compiler.debug.internal.method.MethodMetricsInlineeScopeInfo;
@@ -48,6 +47,7 @@
 import org.graalvm.compiler.graph.Graph.NodeEventScope;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.graph.NodeMap;
 import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.graph.NodeWorkList;
 import org.graalvm.compiler.nodeinfo.Verbosity;
@@ -58,6 +58,7 @@
 import org.graalvm.compiler.nodes.CallTargetNode;
 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
 import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.EndNode;
 import org.graalvm.compiler.nodes.FixedGuardNode;
 import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
@@ -69,6 +70,7 @@
 import org.graalvm.compiler.nodes.LogicNode;
 import org.graalvm.compiler.nodes.MergeNode;
 import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.PhiNode;
 import org.graalvm.compiler.nodes.PiNode;
 import org.graalvm.compiler.nodes.ReturnNode;
 import org.graalvm.compiler.nodes.StartNode;
@@ -95,14 +97,14 @@
 import org.graalvm.util.UnmodifiableEconomicMap;
 import org.graalvm.util.UnmodifiableMapCursor;
 
-import jdk.vm.ci.code.BytecodeFrame;
-import jdk.vm.ci.meta.Assumptions;
-import jdk.vm.ci.meta.DeoptimizationAction;
-import jdk.vm.ci.meta.DeoptimizationReason;
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaType;
+import java.lang.reflect.Constructor;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.List;
+
+import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
+import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
+import static org.graalvm.compiler.core.common.GraalOptions.HotSpotPrintInlining;
 
 public class InliningUtil extends ValueMergeUtil {
 
@@ -277,9 +279,6 @@
         StructuredGraph graph = invokeNode.graph();
         MethodMetricsInlineeScopeInfo m = MethodMetricsInlineeScopeInfo.create(graph.getOptions());
         try (Debug.Scope s = Debug.methodMetricsScope("InlineEnhancement", m, false)) {
-            if (Fingerprint.ENABLED) {
-                Fingerprint.submit("inlining %s into %s: %s", formatGraph(inlineGraph), formatGraph(invoke.asNode().graph()), inlineGraph.getNodes().snapshot());
-            }
             final NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
 
             assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal();
@@ -291,7 +290,7 @@
 
             ArrayList<Node> nodes = new ArrayList<>(inlineGraph.getNodes().count());
             ArrayList<ReturnNode> returnNodes = new ArrayList<>(4);
-            ArrayList<InvokeNode> partialIntrinsicExits = new ArrayList<>();
+            ArrayList<Invoke> partialIntrinsicExits = new ArrayList<>();
             UnwindNode unwindNode = null;
             final StartNode entryPointNode = inlineGraph.start();
             FixedNode firstCFGNode = entryPointNode.next();
@@ -305,10 +304,10 @@
                     nodes.add(node);
                     if (node instanceof ReturnNode) {
                         returnNodes.add((ReturnNode) node);
-                    } else if (node instanceof InvokeNode) {
-                        InvokeNode invokeInInlineGraph = (InvokeNode) node;
+                    } else if (node instanceof Invoke) {
+                        Invoke invokeInInlineGraph = (Invoke) node;
                         if (invokeInInlineGraph.bci() == BytecodeFrame.UNKNOWN_BCI) {
-                            ResolvedJavaMethod target1 = invoke.callTarget().targetMethod();
+                            ResolvedJavaMethod target1 = inlineeMethod;
                             ResolvedJavaMethod target2 = invokeInInlineGraph.callTarget().targetMethod();
                             assert target1.equals(target2) : String.format("invoke in inlined method expected to be partial intrinsic exit (i.e., call to %s), not a call to %s",
                                             target1.format("%H.%n(%p)"), target2.format("%H.%n(%p)"));
@@ -338,7 +337,7 @@
             assert invokeNode.successors().first() != null : invoke;
             assert invokeNode.predecessor() != null;
 
-            UnmodifiableEconomicMap<Node, Node> duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement);
+            EconomicMap<Node, Node> duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement);
 
             FrameState stateAfter = invoke.stateAfter();
             assert stateAfter == null || stateAfter.isAlive();
@@ -370,12 +369,16 @@
             for (int i = 0; i < returnNodes.size(); i++) {
                 returnNodes.set(i, (ReturnNode) duplicates.get(returnNodes.get(i)));
             }
-            for (InvokeNode exit : partialIntrinsicExits) {
+            for (Invoke exit : partialIntrinsicExits) {
                 // A partial intrinsic exit must be replaced with a call to
                 // the intrinsified method.
-                InvokeNode dup = (InvokeNode) duplicates.get(exit);
-                InvokeNode repl = graph.add(new InvokeNode(invoke.callTarget(), invoke.bci()));
-                dup.intrinsify(repl);
+                Invoke dup = (Invoke) duplicates.get(exit.asNode());
+                if (dup instanceof InvokeNode) {
+                    InvokeNode repl = graph.add(new InvokeNode(invoke.callTarget(), invoke.bci()));
+                    dup.intrinsify(repl.asNode());
+                } else {
+                    ((InvokeWithExceptionNode) dup).replaceWithNewBci(invoke.bci());
+                }
             }
             if (unwindNode != null) {
                 unwindNode = (UnwindNode) duplicates.get(unwindNode);
@@ -392,7 +395,7 @@
     }
 
     /**
-     * Inline {@code inlineGraph} into the current replacoing the node {@code Invoke} and return the
+     * Inline {@code inlineGraph} into the current replacing the node {@code Invoke} and return the
      * set of nodes which should be canonicalized. The set should only contain nodes which modified
      * by the inlining since the current graph and {@code inlineGraph} are expected to already be
      * canonical.
@@ -467,10 +470,13 @@
                 invokeNode.replaceAtUsages(returnValue);
                 returnNode.replaceAndDelete(n);
             } else {
-                AbstractMergeNode merge = graph.add(new MergeNode());
+                MergeNode merge = graph.add(new MergeNode());
                 merge.setStateAfter(stateAfter);
                 returnValue = mergeReturns(merge, returnNodes);
                 invokeNode.replaceAtUsages(returnValue);
+                if (merge.isPhiAtMerge(returnValue)) {
+                    fixFrameStates(graph, merge, (PhiNode) returnValue);
+                }
                 merge.setNext(n);
             }
         } else {
@@ -505,11 +511,56 @@
         return returnValue;
     }
 
-    private static String formatGraph(StructuredGraph graph) {
-        if (graph.method() == null) {
-            return graph.name;
+    private static void fixFrameStates(StructuredGraph graph, MergeNode originalMerge, PhiNode returnPhi) {
+        // It is possible that some of the frame states that came from AFTER_BCI reference a Phi
+        // node that was created to merge multiple returns. This can create cycles
+        // (see GR-3949 and GR-3957).
+        // To detect this, we follow the control paths starting from the merge node,
+        // split the Phi node inputs at merges and assign the proper input to each frame state.
+        NodeMap<Node> seen = new NodeMap<>(graph);
+        ArrayDeque<Node> workList = new ArrayDeque<>();
+        ArrayDeque<ValueNode> valueList = new ArrayDeque<>();
+        workList.push(originalMerge);
+        valueList.push(returnPhi);
+        while (!workList.isEmpty()) {
+            Node current = workList.pop();
+            ValueNode currentValue = valueList.pop();
+            if (seen.containsKey(current)) {
+                continue;
+            }
+            seen.put(current, current);
+            if (current instanceof StateSplit && current != originalMerge) {
+                StateSplit stateSplit = (StateSplit) current;
+                FrameState state = stateSplit.stateAfter();
+                if (state != null && state.values().contains(returnPhi)) {
+                    int index = 0;
+                    FrameState duplicate = state.duplicate();
+                    for (ValueNode value : state.values()) {
+                        if (value == returnPhi) {
+                            duplicate.values().set(index, currentValue);
+                        }
+                        index++;
+                    }
+                    stateSplit.setStateAfter(duplicate);
+                    GraphUtil.tryKillUnused(state);
+                }
+            }
+            if (current instanceof AbstractMergeNode) {
+                AbstractMergeNode currentMerge = (AbstractMergeNode) current;
+                for (EndNode pred : currentMerge.cfgPredecessors()) {
+                    ValueNode newValue = currentValue;
+                    if (currentMerge.isPhiAtMerge(currentValue)) {
+                        PhiNode currentPhi = (PhiNode) currentValue;
+                        newValue = currentPhi.valueAt(pred);
+                    }
+                    workList.push(pred);
+                    valueList.push(newValue);
+                }
+            } else if (current.predecessor() != null) {
+                workList.push(current.predecessor());
+                valueList.push(currentValue);
+            }
         }
-        return graph.method().format("%H.%n(%p)");
     }
 
     @SuppressWarnings("try")
@@ -546,58 +597,35 @@
         }
     }
 
-    protected static void processFrameStates(Invoke invoke, StructuredGraph inlineGraph, UnmodifiableEconomicMap<Node, Node> duplicates, FrameState stateAtExceptionEdge,
+    protected static void processFrameStates(Invoke invoke, StructuredGraph inlineGraph, EconomicMap<Node, Node> duplicates, FrameState stateAtExceptionEdge,
                     boolean alwaysDuplicateStateAfter) {
         FrameState stateAtReturn = invoke.stateAfter();
         FrameState outerFrameState = null;
         JavaKind invokeReturnKind = invoke.asNode().getStackKind();
+        EconomicMap<Node, Node> replacements = EconomicMap.create();
         for (FrameState original : inlineGraph.getNodes(FrameState.TYPE)) {
             FrameState frameState = (FrameState) duplicates.get(original);
             if (frameState != null && frameState.isAlive()) {
                 if (outerFrameState == null) {
                     outerFrameState = stateAtReturn.duplicateModifiedDuringCall(invoke.bci(), invokeReturnKind);
                 }
-                processFrameState(frameState, invoke, inlineGraph.method(), stateAtExceptionEdge, outerFrameState, alwaysDuplicateStateAfter, invoke.callTarget().targetMethod(),
+                processFrameState(frameState, invoke, replacements, inlineGraph.method(), stateAtExceptionEdge, outerFrameState, alwaysDuplicateStateAfter, invoke.callTarget().targetMethod(),
                                 invoke.callTarget().arguments());
             }
         }
+        // If processing the frame states replaced any nodes, update the duplicates map.
+        duplicates.replaceAll((key, value) -> replacements.containsKey(value) ? replacements.get(value) : value);
     }
 
-    public static FrameState processFrameState(FrameState frameState, Invoke invoke, ResolvedJavaMethod inlinedMethod, FrameState stateAtExceptionEdge, FrameState outerFrameState,
+    public static FrameState processFrameState(FrameState frameState, Invoke invoke, EconomicMap<Node, Node> replacements, ResolvedJavaMethod inlinedMethod, FrameState stateAtExceptionEdge,
+                    FrameState outerFrameState,
                     boolean alwaysDuplicateStateAfter, ResolvedJavaMethod invokeTargetMethod, List<ValueNode> invokeArgsList) {
-
         assert outerFrameState == null || !outerFrameState.isDeleted() : outerFrameState;
-        FrameState stateAtReturn = invoke.stateAfter();
+        final FrameState stateAtReturn = invoke.stateAfter();
         JavaKind invokeReturnKind = invoke.asNode().getStackKind();
 
         if (frameState.bci == BytecodeFrame.AFTER_BCI) {
-            FrameState stateAfterReturn = stateAtReturn;
-            if (frameState.getCode() == 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)
-            if (frameState.stackSize() > 0 && (alwaysDuplicateStateAfter || stateAfterReturn.stackAt(0) != frameState.stackAt(0))) {
-                stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, invokeReturnKind, frameState.stackAt(0));
-            }
-
-            // Return value does no longer need to be limited by the monitor exit.
-            for (MonitorExitNode n : frameState.usages().filter(MonitorExitNode.class)) {
-                n.clearEscapedReturnValue();
-            }
-
-            frameState.replaceAndDelete(stateAfterReturn);
-            return stateAfterReturn;
+            return handleAfterBciFrameState(frameState, invoke, alwaysDuplicateStateAfter);
         } else if (stateAtExceptionEdge != null && isStateAfterException(frameState)) {
             // pop exception object from invoke's stateAfter and replace with this frameState's
             // exception object (top of stack)
@@ -608,7 +636,8 @@
             frameState.replaceAndDelete(stateAfterException);
             return stateAfterException;
         } else if (frameState.bci == BytecodeFrame.UNWIND_BCI || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
-            return handleMissingAfterExceptionFrameState(frameState);
+            handleMissingAfterExceptionFrameState(frameState, invoke, replacements, alwaysDuplicateStateAfter);
+            return frameState;
         } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) {
             // This is an intrinsic. Deoptimizing within an intrinsic
             // must re-execute the intrinsified invocation
@@ -628,6 +657,44 @@
         }
     }
 
+    private static FrameState handleAfterBciFrameState(FrameState frameState, Invoke invoke, boolean alwaysDuplicateStateAfter) {
+        FrameState stateAtReturn = invoke.stateAfter();
+        JavaKind invokeReturnKind = invoke.asNode().getStackKind();
+        FrameState stateAfterReturn = stateAtReturn;
+        if (frameState.getCode() == 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)
+        assert !frameState.rethrowException() : frameState;
+        if (frameState.stackSize() > 0 && (alwaysDuplicateStateAfter || stateAfterReturn.stackAt(0) != frameState.stackAt(0))) {
+            // A non-void return value.
+            stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, invokeReturnKind, frameState.stackAt(0));
+        } else {
+            // A void return value.
+            stateAfterReturn = stateAtReturn.duplicate();
+        }
+        assert stateAfterReturn.bci != BytecodeFrame.UNKNOWN_BCI;
+
+        // Return value does no longer need to be limited by the monitor exit.
+        for (MonitorExitNode n : frameState.usages().filter(MonitorExitNode.class)) {
+            n.clearEscapedReturnValue();
+        }
+
+        frameState.replaceAndDelete(stateAfterReturn);
+        return stateAfterReturn;
+    }
+
     static boolean checkInlineeFrameState(Invoke invoke, ResolvedJavaMethod inlinedMethod, FrameState frameState) {
         assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI : frameState;
         assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState;
@@ -663,7 +730,7 @@
         return frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.getMethod().isSynchronized());
     }
 
-    public static FrameState handleMissingAfterExceptionFrameState(FrameState nonReplaceableFrameState) {
+    public static FrameState handleMissingAfterExceptionFrameState(FrameState nonReplaceableFrameState, Invoke invoke, EconomicMap<Node, Node> replacements, boolean alwaysDuplicateStateAfter) {
         Graph graph = nonReplaceableFrameState.graph();
         NodeWorkList workList = graph.createNodeWorkList();
         workList.add(nonReplaceableFrameState);
@@ -686,6 +753,20 @@
                             end.replaceAtPredecessor(deoptimizeNode);
                             GraphUtil.killCFG(end);
                         }
+                    } else if (fixedStateSplit instanceof ExceptionObjectNode) {
+                        // The target invoke does not have an exception edge. This means that the
+                        // bytecode parser made the wrong assumption of making an
+                        // InvokeWithExceptionNode for the partial intrinsic exit. We therefore
+                        // replace the InvokeWithExceptionNode with a normal
+                        // InvokeNode -- the deoptimization occurs when the invoke throws.
+                        InvokeWithExceptionNode oldInvoke = (InvokeWithExceptionNode) fixedStateSplit.predecessor();
+                        FrameState oldFrameState = oldInvoke.stateAfter();
+                        InvokeNode newInvoke = oldInvoke.replaceWithInvoke();
+                        newInvoke.setStateAfter(oldFrameState.duplicate());
+                        if (replacements != null) {
+                            replacements.put(oldInvoke, newInvoke);
+                        }
+                        handleAfterBciFrameState(newInvoke.stateAfter(), invoke, alwaysDuplicateStateAfter);
                     } else {
                         FixedNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
                         if (fixedStateSplit instanceof AbstractBeginNode) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java	Thu Jun 01 02:21:18 2017 +0000
@@ -30,7 +30,6 @@
 import org.graalvm.compiler.debug.DebugCounter;
 import org.graalvm.compiler.debug.DebugMemUseTracker;
 import org.graalvm.compiler.debug.DebugTimer;
-import org.graalvm.compiler.debug.Fingerprint;
 import org.graalvm.compiler.debug.GraalDebugConfig;
 import org.graalvm.compiler.graph.Graph;
 import org.graalvm.compiler.graph.Graph.Mark;
@@ -196,10 +195,6 @@
             if (dumpGraph && Debug.isEnabled()) {
                 dumpAfter(graph, isTopLevel, dumpedBefore);
             }
-            if (Fingerprint.ENABLED) {
-                String graphDesc = graph.method() == null ? graph.name : graph.method().format("%H.%n(%p)");
-                Fingerprint.submit("After phase %s nodes in %s are %s", getName(), graphDesc, graph.getNodes().snapshot());
-            }
             if (Debug.isVerifyEnabled()) {
                 Debug.verify(graph, "%s", getName());
             }
@@ -273,24 +268,14 @@
     }
 
     protected CharSequence getName() {
-        String className = BasePhase.this.getClass().getName();
-        String s = className.substring(className.lastIndexOf(".") + 1); // strip the package name
-        int innerClassPos = s.indexOf('$');
-        if (innerClassPos > 0) {
-            /* Remove inner class name. */
-            s = s.substring(0, innerClassPos);
-        }
-        if (s.endsWith("Phase")) {
-            s = s.substring(0, s.length() - "Phase".length());
-        }
-        return s;
+        return new ClassTypeSequence(BasePhase.this.getClass());
     }
 
     protected abstract void run(StructuredGraph graph, C context);
 
     @Override
     public String contractorName() {
-        return (String) getName();
+        return getName().toString();
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/ClassTypeSequence.java	Thu Jun 01 02:21:18 2017 +0000
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2011, 2017, 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 org.graalvm.compiler.phases;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+final class ClassTypeSequence implements JavaType, CharSequence {
+    private final Class<?> clazz;
+
+    ClassTypeSequence(Class<?> clazz) {
+        this.clazz = clazz;
+    }
+
+    @Override
+    public String getName() {
+        return "L" + clazz.getName().replace('.', '/') + ";";
+    }
+
+    @Override
+    public String toJavaName() {
+        return toJavaName(true);
+    }
+
+    @Override
+    public String toJavaName(boolean qualified) {
+        if (qualified) {
+            return clazz.getName();
+        } else {
+            int lastDot = clazz.getName().lastIndexOf('.');
+            return clazz.getName().substring(lastDot + 1);
+        }
+    }
+
+    @Override
+    public JavaType getComponentType() {
+        return null;
+    }
+
+    @Override
+    public JavaType getArrayClass() {
+        return null;
+    }
+
+    @Override
+    public JavaKind getJavaKind() {
+        return JavaKind.Object;
+    }
+
+    @Override
+    public ResolvedJavaType resolve(ResolvedJavaType accessingClass) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int length() {
+        return clazz.getName().length();
+    }
+
+    @Override
+    public char charAt(int index) {
+        return clazz.getName().charAt(index);
+    }
+
+    @Override
+    public CharSequence subSequence(int start, int end) {
+        return clazz.getName().subSequence(start, end);
+    }
+
+    @Override
+    public String toString() {
+        return clazz.getName();
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java	Thu Jun 01 02:21:18 2017 +0000
@@ -22,14 +22,6 @@
  */
 package org.graalvm.compiler.phases.schedule;
 
-import static org.graalvm.compiler.core.common.GraalOptions.OptScheduleOutOfLoops;
-import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.strictlyDominates;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Formatter;
-import java.util.List;
-
 import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.SuppressFBWarnings;
@@ -51,6 +43,7 @@
 import org.graalvm.compiler.nodes.ControlSplitNode;
 import org.graalvm.compiler.nodes.DeoptimizeNode;
 import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.GuardNode;
 import org.graalvm.compiler.nodes.IfNode;
 import org.graalvm.compiler.nodes.KillingBeginNode;
@@ -75,7 +68,14 @@
 import org.graalvm.compiler.nodes.spi.ValueProxy;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.Phase;
-import org.graalvm.compiler.nodes.FixedWithNextNode;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Formatter;
+import java.util.List;
+
+import static org.graalvm.compiler.core.common.GraalOptions.OptScheduleOutOfLoops;
+import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.strictlyDominates;
 
 public final class SchedulePhase extends Phase {
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java	Thu Jun 01 02:21:18 2017 +0000
@@ -39,6 +39,7 @@
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.DebugMethodMetrics;
 import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Graph;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeInputList;
 import org.graalvm.compiler.nodes.CallTargetNode;
@@ -243,7 +244,7 @@
     protected void verifyDumpObjectParameter(StructuredGraph callerGraph, MethodCallTargetNode debugCallTarget, List<? extends ValueNode> args, ResolvedJavaMethod verifiedCallee, Integer dumpLevel)
                     throws org.graalvm.compiler.phases.VerifyPhase.VerificationError {
         ResolvedJavaType arg1Type = ((ObjectStamp) args.get(1).stamp()).type();
-        if (metaAccess.lookupJavaType(StructuredGraph.class).isAssignableFrom(arg1Type)) {
+        if (metaAccess.lookupJavaType(Graph.class).isAssignableFrom(arg1Type)) {
             verifyStructuredGraphDumping(callerGraph, debugCallTarget, verifiedCallee, dumpLevel);
         }
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java	Thu Jun 01 02:21:18 2017 +0000
@@ -38,6 +38,7 @@
 import java.util.Map.Entry;
 
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.core.common.cfg.BlockMap;
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.GraalDebugConfig.Options;
@@ -170,10 +171,20 @@
         return snippetReflection;
     }
 
+    @SuppressWarnings("all")
     @Override
-    public void print(Graph graph, String title, Map<Object, Object> properties) throws IOException {
+    public void print(Graph graph, Map<Object, Object> properties, int id, String format, Object... args) throws IOException {
         writeByte(BEGIN_GRAPH);
-        writePoolObject(title);
+        if (CURRENT_MAJOR_VERSION == 3) {
+            writeInt(id);
+            writeString(format);
+            writeInt(args.length);
+            for (Object a : args) {
+                writePropertyObject(a);
+            }
+        } else {
+            writePoolObject(String.format(format, args));
+        }
         writeGraph(graph, properties);
         flush();
     }
@@ -324,7 +335,7 @@
                 writeByte(POOL_CLASS);
             } else if (object instanceof NodeClass) {
                 writeByte(POOL_NODE_CLASS);
-            } else if (object instanceof ResolvedJavaMethod) {
+            } else if (object instanceof ResolvedJavaMethod || object instanceof Bytecode) {
                 writeByte(POOL_METHOD);
             } else if (object instanceof ResolvedJavaField) {
                 writeByte(POOL_FIELD);
@@ -344,6 +355,7 @@
         return getClassName(klass.getComponentType()) + "[]";
     }
 
+    @SuppressWarnings("all")
     private void addPoolEntry(Object object) throws IOException {
         char index = constantPool.add(object);
         writeByte(POOL_NEW);
@@ -374,13 +386,22 @@
         } else if (object instanceof NodeClass) {
             NodeClass<?> nodeClass = (NodeClass<?>) object;
             writeByte(POOL_NODE_CLASS);
-            writeString(nodeClass.getJavaClass().getSimpleName());
+            if (CURRENT_MAJOR_VERSION == 3) {
+                writePoolObject(nodeClass.getJavaClass());
+            } else {
+                writeString(nodeClass.getJavaClass().getSimpleName());
+            }
             writeString(nodeClass.getNameTemplate());
             writeEdgesInfo(nodeClass, Inputs);
             writeEdgesInfo(nodeClass, Successors);
-        } else if (object instanceof ResolvedJavaMethod) {
+        } else if (object instanceof ResolvedJavaMethod || object instanceof Bytecode) {
             writeByte(POOL_METHOD);
-            ResolvedJavaMethod method = ((ResolvedJavaMethod) object);
+            ResolvedJavaMethod method;
+            if (object instanceof Bytecode) {
+                method = ((Bytecode) object).getMethod();
+            } else {
+                method = ((ResolvedJavaMethod) object);
+            }
             writePoolObject(method.getDeclaringClass());
             writePoolObject(method.getName());
             writePoolObject(method.getSignature());
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java	Thu Jun 01 02:21:18 2017 +0000
@@ -79,7 +79,8 @@
     }
 
     @Override
-    public void dump(Object object, String message) {
+    public void dump(Object object, String format, Object... arguments) {
+        String message = String.format(format, arguments);
         try {
             dumpSandboxed(object, message);
         } catch (Throwable ex) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CanonicalStringGraphPrinter.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CanonicalStringGraphPrinter.java	Thu Jun 01 02:21:18 2017 +0000
@@ -258,7 +258,7 @@
     }
 
     @Override
-    public void print(Graph graph, String title, Map<Object, Object> properties) throws IOException {
+    public void print(Graph graph, Map<Object, Object> properties, int id, String format, Object... args) throws IOException {
         if (graph instanceof StructuredGraph) {
             OptionValues options = graph.getOptions();
             StructuredGraph structuredGraph = (StructuredGraph) graph;
@@ -267,6 +267,7 @@
                 TTY.println("Dumping string graphs in %s", this.root);
                 this.root = null;
             }
+            String title = id + ": " + String.format(format, args);
             Path filePath = currentDirectory.resolve(escapeFileName(title));
             try (PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(filePath.toFile())))) {
                 switch (PrintCanonicalGraphStringFlavor.getValue(options)) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraalDebugConfigCustomizer.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraalDebugConfigCustomizer.java	Thu Jun 01 02:21:18 2017 +0000
@@ -80,7 +80,7 @@
 
     private static class NodeDumper implements DebugDumpHandler {
         @Override
-        public void dump(Object object, String message) {
+        public void dump(Object object, String format, Object... arguments) {
             if (object instanceof Node) {
                 String location = GraphUtil.approxSourceLocation((Node) object);
                 String node = ((Node) object).toString(Verbosity.Debugger);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java	Thu Jun 01 02:21:18 2017 +0000
@@ -53,7 +53,7 @@
      * Prints an entire {@link Graph} with the specified title, optionally using short names for
      * nodes.
      */
-    void print(Graph graph, String title, Map<Object, Object> properties) throws IOException;
+    void print(Graph graph, Map<Object, Object> properties, int id, String format, Object... args) throws IOException;
 
     SnippetReflectionProvider getSnippetReflectionProvider();
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java	Thu Jun 01 02:21:18 2017 +0000
@@ -120,7 +120,7 @@
 
     @Override
     @SuppressWarnings("try")
-    public void dump(Object object, final String message) {
+    public void dump(Object object, final String format, Object... arguments) {
         if (object instanceof Graph && Options.PrintGraph.getValue(DebugScope.getConfig().getOptions())) {
             ensureInitialized();
             if (printer == null) {
@@ -184,7 +184,7 @@
                     }
                 }
                 addCFGFileName(properties);
-                printer.print(graph, nextDumpId() + ":" + message, properties);
+                printer.print(graph, properties, nextDumpId(), format, arguments);
             } catch (IOException e) {
                 handleException(e);
             } catch (Throwable e) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/IdealGraphPrinter.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/IdealGraphPrinter.java	Thu Jun 01 02:21:18 2017 +0000
@@ -114,7 +114,8 @@
      * nodes.
      */
     @Override
-    public void print(Graph graph, String title, Map<Object, Object> properties) {
+    public void print(Graph graph, Map<Object, Object> properties, int id, String format, Object... args) {
+        String title = id + ": " + String.format(format, args);
         beginGraph(title);
         EconomicSet<Node> noBlockNodes = EconomicSet.create(Equivalence.IDENTITY);
         ScheduleResult schedule = null;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/NoDeadCodeVerifyHandler.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/NoDeadCodeVerifyHandler.java	Thu Jun 01 02:21:18 2017 +0000
@@ -63,7 +63,7 @@
     private static final Map<String, Boolean> discovered = new ConcurrentHashMap<>();
 
     @Override
-    public void verify(Object object, String message) {
+    public void verify(Object object, String format, Object... args) {
         OptionValues options = DebugScope.getConfig().getOptions();
         if (Options.NDCV.getValue(options) != OFF && object instanceof StructuredGraph) {
             StructuredGraph graph = (StructuredGraph) object;
@@ -72,9 +72,9 @@
             List<Node> after = graph.getNodes().snapshot();
             assert after.size() <= before.size();
             if (before.size() != after.size()) {
-                if (discovered.put(message, Boolean.TRUE) == null) {
+                if (discovered.put(format, Boolean.TRUE) == null) {
                     before.removeAll(after);
-                    String prefix = message == null ? "" : message + ": ";
+                    String prefix = format == null ? "" : format + ": ";
                     GraalError error = new GraalError("%sfound dead nodes in %s: %s", prefix, graph, before);
                     if (Options.NDCV.getValue(options) == INFO) {
                         System.out.println(error.getMessage());
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java	Thu Jun 01 02:21:18 2017 +0000
@@ -22,19 +22,33 @@
  */
 package org.graalvm.compiler.replacements.test;
 
+import static org.graalvm.compiler.java.BytecodeParserOptions.InlinePartialIntrinsicExitDuringParsing;
+
 import java.util.function.Function;
 
+import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugConfigScope;
+import org.graalvm.compiler.graph.GraalGraphError;
 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
 import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.options.OptionValues;
+import org.junit.Assert;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
+import jdk.vm.ci.code.InstalledCode;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /**
@@ -42,6 +56,26 @@
  */
 public class ReplacementsParseTest extends ReplacementsTest {
 
+    private static final String IN_COMPILED_HANDLER_MARKER = "*** in compiled handler ***";
+
+    /**
+     * Marker value to indicate an exception handler was interpreted. We cannot use a complex string
+     * expression in this context without risking non-deterministic behavior dependent on whether
+     * String intrinsics are applied or whether String expression evaluation hit an uncommon trap
+     * when executed by C1 or C2 (and thus potentially altering the profile such that the exception
+     * handler is *not* compiled by Graal even when we want it to be).
+     */
+    private static final String IN_INTERPRETED_HANDLER_MARKER = "*** in interpreted handler ***";
+
+    private InlineInvokePlugin.InlineInfo inlineInvokeDecision;
+
+    @SuppressWarnings("serial")
+    static class CustomError extends Error {
+        CustomError(String message) {
+            super(message);
+        }
+    }
+
     static final Object THROW_EXCEPTION_MARKER = new Object() {
         @Override
         public String toString() {
@@ -49,6 +83,24 @@
         }
     };
 
+    static int copyFirstBody(byte[] left, byte[] right, boolean left2right) {
+        if (left2right) {
+            byte e = left[0];
+            right[0] = e;
+            return e;
+        } else {
+            byte e = right[0];
+            left[0] = e;
+            return e;
+        }
+    }
+
+    static int copyFirstL2RBody(byte[] left, byte[] right) {
+        byte e = left[0];
+        right[0] = e;
+        return e;
+    }
+
     static class TestObject {
         static double next(double v) {
             return Math.nextAfter(v, 1.0);
@@ -73,26 +125,40 @@
         final Object id;
 
         String stringizeId() {
-            String res = String.valueOf(id);
-            if (res.equals(THROW_EXCEPTION_MARKER.toString())) {
+            Object res = id;
+            if (res == THROW_EXCEPTION_MARKER) {
                 // Tests exception throwing from partial intrinsification
-                throw new RuntimeException("ex: " + id);
+                throw new CustomError("ex");
             }
-            return res;
+            return String.valueOf(res);
         }
 
         static String stringize(Object obj) {
-            String res = String.valueOf(obj);
-            if (res.equals(THROW_EXCEPTION_MARKER.toString())) {
+            Object res = obj;
+            if (res == THROW_EXCEPTION_MARKER) {
                 // Tests exception throwing from partial intrinsification
-                throw new RuntimeException("ex: " + obj);
+                throw new CustomError("ex");
             }
-            return res;
+            return String.valueOf(res);
         }
 
         static String identity(String s) {
             return s;
         }
+
+        /**
+         * @see TestObjectSubstitutions#copyFirst(byte[], byte[], boolean)
+         */
+        static int copyFirst(byte[] left, byte[] right, boolean left2right) {
+            return copyFirstBody(left, right, left2right);
+        }
+
+        /**
+         * @see TestObjectSubstitutions#copyFirstL2R(byte[], byte[])
+         */
+        static int copyFirstL2R(byte[] left, byte[] right) {
+            return copyFirstL2RBody(left, right);
+        }
     }
 
     @ClassSubstitution(TestObject.class)
@@ -146,6 +212,25 @@
         private static native String asNonNullStringIntrinsic(Object object, @ConstantNodeParameter Class<?> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull);
 
         /**
+         * An valid intrinsic as the frame state associated with the merge should prevent the frame
+         * states associated with the array stores from being associated with subsequent
+         * deoptimizing nodes.
+         */
+        @MethodSubstitution
+        static int copyFirst(byte[] left, byte[] right, boolean left2right) {
+            return copyFirstBody(left, right, left2right);
+        }
+
+        /**
+         * An invalid intrinsic as the frame state associated with the array assignment can leak out
+         * to subsequent deoptimizing nodes.
+         */
+        @MethodSubstitution
+        static int copyFirstL2R(byte[] left, byte[] right) {
+            return copyFirstL2RBody(left, right);
+        }
+
+        /**
          * Tests that non-capturing lambdas are folded away.
          */
         @MethodSubstitution
@@ -166,6 +251,8 @@
         r.registerMethodSubstitution(TestObjectSubstitutions.class, "nextAfter", double.class, double.class);
         r.registerMethodSubstitution(TestObjectSubstitutions.class, "stringize", Object.class);
         r.registerMethodSubstitution(TestObjectSubstitutions.class, "stringizeId", Receiver.class);
+        r.registerMethodSubstitution(TestObjectSubstitutions.class, "copyFirst", byte[].class, byte[].class, boolean.class);
+        r.registerMethodSubstitution(TestObjectSubstitutions.class, "copyFirstL2R", byte[].class, byte[].class);
 
         if (replacementBytecodeProvider.supportsInvokedynamic()) {
             r.registerMethodSubstitution(TestObjectSubstitutions.class, "identity", String.class);
@@ -173,6 +260,14 @@
         super.registerInvocationPlugins(invocationPlugins);
     }
 
+    @BeforeClass
+    public static void warmupProfiles() {
+        for (int i = 0; i < 40000; i++) {
+            callCopyFirst(new byte[16], new byte[16], true);
+            callCopyFirstL2R(new byte[16], new byte[16]);
+        }
+    }
+
     /**
      * Ensure that calling the original method from the substitution binds correctly.
      */
@@ -219,31 +314,100 @@
         }
     }
 
+    private void testWithDifferentReturnValues(OptionValues options, String standardReturnValue, String compiledReturnValue, String name, Object... args) {
+        ResolvedJavaMethod method = getResolvedJavaMethod(name);
+        Object receiver = null;
+
+        Result expect = executeExpected(method, receiver, args);
+        Assert.assertEquals(standardReturnValue, expect.returnValue);
+        expect = new Result(compiledReturnValue, null);
+        testAgainstExpected(options, method, expect, receiver, args);
+    }
+
+    @Override
+    protected InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile, boolean installAsDefault, OptionValues options) {
+        return super.getCode(installedCodeOwner, graph, forceCompileOverride, installAsDefault, options);
+    }
+
+    boolean forceCompileOverride;
+
     @Test
     public void testCallStringize() {
         test("callStringize", "a string");
-        test("callStringize", THROW_EXCEPTION_MARKER);
         test("callStringize", Boolean.TRUE);
+        // Unset 'exception seen' bit if testCallStringizeWithoutInlinePartialIntrinsicExit
+        // is executed before this test
+        getResolvedJavaMethod("callStringize").reprofile();
+        forceCompileOverride = true;
+        String standardReturnValue = IN_INTERPRETED_HANDLER_MARKER;
+        String compiledReturnValue = IN_COMPILED_HANDLER_MARKER;
+        testWithDifferentReturnValues(getInitialOptions(), standardReturnValue, compiledReturnValue, "callStringize", THROW_EXCEPTION_MARKER);
+    }
+
+    @Test
+    public void testCallStringizeWithoutInlinePartialIntrinsicExit() {
+        OptionValues options = new OptionValues(getInitialOptions(), InlinePartialIntrinsicExitDuringParsing, false);
+        test(options, "callStringize", "a string");
+        test(options, "callStringize", Boolean.TRUE);
+        String standardReturnValue = IN_INTERPRETED_HANDLER_MARKER;
+        String compiledReturnValue = IN_COMPILED_HANDLER_MARKER;
+        for (int i = 0; i < 1000; i++) {
+            // Ensures 'exception seen' bit is set for call to stringize
+            callStringize(THROW_EXCEPTION_MARKER);
+        }
+        forceCompileOverride = true;
+        testWithDifferentReturnValues(options, standardReturnValue, compiledReturnValue, "callStringize", THROW_EXCEPTION_MARKER);
     }
 
     @Test
     public void testCallStringizeId() {
         test("callStringizeId", new TestObject("a string"));
-        test("callStringizeId", new TestObject(THROW_EXCEPTION_MARKER));
         test("callStringizeId", new TestObject(Boolean.TRUE));
+        // Unset 'exception seen' bit if testCallStringizeIdWithoutInlinePartialIntrinsicExit
+        // is executed before this test
+        getResolvedJavaMethod("callStringize").reprofile();
+        forceCompileOverride = true;
+        String standardReturnValue = IN_INTERPRETED_HANDLER_MARKER;
+        String compiledReturnValue = IN_COMPILED_HANDLER_MARKER;
+        testWithDifferentReturnValues(getInitialOptions(), standardReturnValue, compiledReturnValue, "callStringizeId", new TestObject(THROW_EXCEPTION_MARKER));
+    }
+
+    @Test
+    public void testCallStringizeIdWithoutInlinePartialIntrinsicExit() {
+        OptionValues options = new OptionValues(getInitialOptions(), InlinePartialIntrinsicExitDuringParsing, false);
+        test(options, "callStringizeId", new TestObject("a string"));
+        test(options, "callStringizeId", new TestObject(Boolean.TRUE));
+        TestObject exceptionTestObject = new TestObject(THROW_EXCEPTION_MARKER);
+        for (int i = 0; i < 1000; i++) {
+            // Ensures 'exception seen' bit is set for call to stringizeId
+            callStringizeId(exceptionTestObject);
+        }
+        String standardReturnValue = IN_INTERPRETED_HANDLER_MARKER;
+        String compiledReturnValue = IN_COMPILED_HANDLER_MARKER;
+        forceCompileOverride = true;
+        testWithDifferentReturnValues(options, standardReturnValue, compiledReturnValue, "callStringizeId", exceptionTestObject);
     }
 
     public static Object callStringize(Object obj) {
-        return TestObject.stringize(obj);
+        try {
+            return TestObject.stringize(obj);
+        } catch (CustomError e) {
+            if (GraalDirectives.inCompiledCode()) {
+                return IN_COMPILED_HANDLER_MARKER;
+            }
+            return IN_INTERPRETED_HANDLER_MARKER;
+        }
     }
 
     public static Object callStringizeId(TestObject testObj) {
-        return indirect(testObj);
-    }
-
-    @BytecodeParserNeverInline
-    private static String indirect(TestObject testObj) {
-        return testObj.stringizeId();
+        try {
+            return testObj.stringizeId();
+        } catch (CustomError e) {
+            if (GraalDirectives.inCompiledCode()) {
+                return IN_COMPILED_HANDLER_MARKER;
+            }
+            return IN_INTERPRETED_HANDLER_MARKER;
+        }
     }
 
     @Test
@@ -263,4 +427,67 @@
     public static String callLambda(String value) {
         return TestObject.identity(value);
     }
+
+    public static int callCopyFirst(byte[] in, byte[] out, boolean left2right) {
+        int res = TestObject.copyFirst(in, out, left2right);
+        if (res == 17) {
+            // A node after the intrinsic that needs a frame state.
+            GraalDirectives.deoptimize();
+        }
+        return res;
+    }
+
+    public static int callCopyFirstWrapper(byte[] in, byte[] out, boolean left2right) {
+        return callCopyFirst(in, out, left2right);
+    }
+
+    public static int callCopyFirstL2R(byte[] in, byte[] out) {
+        int res = TestObject.copyFirstL2R(in, out);
+        if (res == 17) {
+            // A node after the intrinsic that needs a frame state.
+            GraalDirectives.deoptimize();
+        }
+        return res;
+    }
+
+    @Test
+    public void testCallCopyFirst() {
+        byte[] in = {0, 1, 2, 3, 4};
+        byte[] out = new byte[in.length];
+        test("callCopyFirst", in, out, true);
+        test("callCopyFirst", in, out, false);
+    }
+
+    @SuppressWarnings("try")
+    @Test
+    public void testCallCopyFirstL2R() {
+        byte[] in = {0, 1, 2, 3, 4};
+        byte[] out = new byte[in.length];
+        try {
+            try (DebugConfigScope s = Debug.setConfig(Debug.silentConfig())) {
+                test("callCopyFirstL2R", in, out);
+            }
+        } catch (GraalGraphError e) {
+            assertTrue(e.getMessage().startsWith("Invalid frame state"));
+        }
+    }
+
+    @Override
+    protected InlineInvokePlugin.InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        return inlineInvokeDecision;
+    }
+
+    @Test
+    public void testCallCopyFirstWithoutInlinePartialIntrinsicExit() {
+        OptionValues options = new OptionValues(getInitialOptions(), InlinePartialIntrinsicExitDuringParsing, false);
+        inlineInvokeDecision = InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION;
+        try {
+            byte[] in = {0, 1, 2, 3, 4};
+            byte[] out = new byte[in.length];
+            test(options, "callCopyFirstWrapper", in, out, true);
+            test(options, "callCopyFirstWrapper", in, out, false);
+        } finally {
+            inlineInvokeDecision = null;
+        }
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java	Thu Jun 01 02:21:18 2017 +0000
@@ -29,6 +29,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.StampPair;
@@ -45,6 +46,8 @@
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.IfNode;
 import org.graalvm.compiler.nodes.InvokeNode;
+import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
+import org.graalvm.compiler.nodes.KillingBeginNode;
 import org.graalvm.compiler.nodes.LogicNode;
 import org.graalvm.compiler.nodes.MergeNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -54,6 +57,7 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool;
 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
+import org.graalvm.compiler.nodes.java.ExceptionObjectNode;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
 import org.graalvm.compiler.nodes.spi.StampProvider;
 import org.graalvm.compiler.nodes.type.StampTool;
@@ -364,7 +368,7 @@
         pushStructure(s);
     }
 
-    private IfStructure saveLastNode() {
+    private IfStructure saveLastIfNode() {
         IfStructure s = getTopStructure(IfStructure.class);
         switch (s.state) {
             case CONDITION:
@@ -385,19 +389,19 @@
     }
 
     public void thenPart() {
-        IfStructure s = saveLastNode();
+        IfStructure s = saveLastIfNode();
         lastFixedNode = (FixedWithNextNode) s.thenPart;
         s.state = IfState.THEN_PART;
     }
 
     public void elsePart() {
-        IfStructure s = saveLastNode();
+        IfStructure s = saveLastIfNode();
         lastFixedNode = (FixedWithNextNode) s.elsePart;
         s.state = IfState.ELSE_PART;
     }
 
     public void endIf() {
-        IfStructure s = saveLastNode();
+        IfStructure s = saveLastIfNode();
 
         FixedWithNextNode thenPart = s.thenPart instanceof FixedWithNextNode ? (FixedWithNextNode) s.thenPart : null;
         FixedWithNextNode elsePart = s.elsePart instanceof FixedWithNextNode ? (FixedWithNextNode) s.elsePart : null;
@@ -430,4 +434,131 @@
         s.state = IfState.FINISHED;
         popStructure();
     }
+
+    static class InvokeWithExceptionStructure extends Structure {
+        protected enum State {
+            INVOKE,
+            NO_EXCEPTION_EDGE,
+            EXCEPTION_EDGE,
+            FINISHED
+        }
+
+        protected State state;
+        protected ExceptionObjectNode exceptionObject;
+        protected FixedNode noExceptionEdge;
+        protected FixedNode exceptionEdge;
+    }
+
+    public InvokeWithExceptionNode startInvokeWithException(ResolvedJavaMethod method, InvokeKind invokeKind,
+                    FrameStateBuilder frameStateBuilder, int invokeBci, int exceptionEdgeBci, ValueNode... args) {
+
+        assert method.isStatic() == (invokeKind == InvokeKind.Static);
+        Signature signature = method.getSignature();
+        JavaType returnType = signature.getReturnType(null);
+        assert checkArgs(method, args);
+        StampPair returnStamp = graphBuilderPlugins.getOverridingStamp(this, returnType, false);
+        if (returnStamp == null) {
+            returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false);
+        }
+        ExceptionObjectNode exceptionObject = add(new ExceptionObjectNode(getMetaAccess()));
+        if (frameStateBuilder != null) {
+            FrameStateBuilder exceptionState = frameStateBuilder.copy();
+            exceptionState.clearStack();
+            exceptionState.push(JavaKind.Object, exceptionObject);
+            exceptionState.setRethrowException(false);
+            exceptionObject.setStateAfter(exceptionState.create(exceptionEdgeBci, exceptionObject));
+        }
+        MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, method, args, returnStamp, invokeBci));
+        InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionObject, invokeBci));
+        AbstractBeginNode noExceptionEdge = graph.add(KillingBeginNode.create(LocationIdentity.any()));
+        invoke.setNext(noExceptionEdge);
+        if (frameStateBuilder != null) {
+            if (invoke.getStackKind() != JavaKind.Void) {
+                frameStateBuilder.push(returnType.getJavaKind(), invoke);
+            }
+            invoke.setStateAfter(frameStateBuilder.create(invokeBci, invoke));
+            if (invoke.getStackKind() != JavaKind.Void) {
+                frameStateBuilder.pop(returnType.getJavaKind());
+            }
+        }
+        lastFixedNode = null;
+
+        InvokeWithExceptionStructure s = new InvokeWithExceptionStructure();
+        s.state = InvokeWithExceptionStructure.State.INVOKE;
+        s.noExceptionEdge = noExceptionEdge;
+        s.exceptionEdge = exceptionObject;
+        s.exceptionObject = exceptionObject;
+        pushStructure(s);
+
+        return invoke;
+    }
+
+    private InvokeWithExceptionStructure saveLastInvokeWithExceptionNode() {
+        InvokeWithExceptionStructure s = getTopStructure(InvokeWithExceptionStructure.class);
+        switch (s.state) {
+            case INVOKE:
+                assert lastFixedNode == null;
+                break;
+            case NO_EXCEPTION_EDGE:
+                s.noExceptionEdge = lastFixedNode;
+                break;
+            case EXCEPTION_EDGE:
+                s.exceptionEdge = lastFixedNode;
+                break;
+            case FINISHED:
+                assert false;
+                break;
+        }
+        lastFixedNode = null;
+        return s;
+    }
+
+    public void noExceptionPart() {
+        InvokeWithExceptionStructure s = saveLastInvokeWithExceptionNode();
+        lastFixedNode = (FixedWithNextNode) s.noExceptionEdge;
+        s.state = InvokeWithExceptionStructure.State.NO_EXCEPTION_EDGE;
+    }
+
+    public void exceptionPart() {
+        InvokeWithExceptionStructure s = saveLastInvokeWithExceptionNode();
+        lastFixedNode = (FixedWithNextNode) s.exceptionEdge;
+        s.state = InvokeWithExceptionStructure.State.EXCEPTION_EDGE;
+    }
+
+    public ExceptionObjectNode exceptionObject() {
+        InvokeWithExceptionStructure s = getTopStructure(InvokeWithExceptionStructure.class);
+        return s.exceptionObject;
+    }
+
+    /**
+     * Finishes a control flow started with {@link #startInvokeWithException}. If necessary, creates
+     * a merge of the non-exception and exception edges. The merge node is returned and the
+     * non-exception edge is the first forward end of the merge, the exception edge is the second
+     * forward end (relevant for phi nodes).
+     */
+    public AbstractMergeNode endInvokeWithException() {
+        InvokeWithExceptionStructure s = saveLastInvokeWithExceptionNode();
+        FixedWithNextNode noExceptionEdge = s.noExceptionEdge instanceof FixedWithNextNode ? (FixedWithNextNode) s.noExceptionEdge : null;
+        FixedWithNextNode exceptionEdge = s.exceptionEdge instanceof FixedWithNextNode ? (FixedWithNextNode) s.exceptionEdge : null;
+        AbstractMergeNode merge = null;
+        if (noExceptionEdge != null && exceptionEdge != null) {
+            EndNode noExceptionEnd = graph.add(new EndNode());
+            graph.addAfterFixed(noExceptionEdge, noExceptionEnd);
+            EndNode exceptionEnd = graph.add(new EndNode());
+            graph.addAfterFixed(exceptionEdge, exceptionEnd);
+            merge = graph.add(new MergeNode());
+            merge.addForwardEnd(noExceptionEnd);
+            merge.addForwardEnd(exceptionEnd);
+            lastFixedNode = merge;
+        } else if (noExceptionEdge != null) {
+            lastFixedNode = noExceptionEdge;
+        } else if (exceptionEdge != null) {
+            lastFixedNode = exceptionEdge;
+        } else {
+            assert lastFixedNode == null;
+        }
+        s.state = InvokeWithExceptionStructure.State.FINISHED;
+        popStructure();
+        return merge;
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java	Thu Jun 01 02:21:18 2017 +0000
@@ -521,7 +521,9 @@
                  * anything because the usages of the frameState are not available yet. So we need
                  * to call it again.
                  */
-                InliningUtil.handleMissingAfterExceptionFrameState(frameState);
+                PEMethodScope peMethodScope = (PEMethodScope) methodScope;
+                Invoke invoke = peMethodScope.invokeData != null ? peMethodScope.invokeData.invoke : null;
+                InliningUtil.handleMissingAfterExceptionFrameState(frameState, invoke, null, true);
 
                 /*
                  * The frameState must be gone now, because it is not a valid deoptimization point.
@@ -1168,8 +1170,8 @@
                      */
                     invokeArgsList = Arrays.asList(methodScope.arguments);
                 }
-                return InliningUtil.processFrameState(frameState, methodScope.invokeData.invoke, methodScope.method, methodScope.exceptionState, methodScope.outerState, true, methodScope.method,
-                                invokeArgsList);
+                return InliningUtil.processFrameState(frameState, methodScope.invokeData.invoke, null, methodScope.method, methodScope.exceptionState, methodScope.outerState, true,
+                                methodScope.method, invokeArgsList);
 
             } else if (node instanceof MonitorIdNode) {
                 ensureOuterStateDecoded(methodScope);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java	Thu Jun 01 02:21:18 2017 +0000
@@ -52,6 +52,7 @@
 import org.graalvm.compiler.nodes.virtual.VirtualArrayNode;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
 
+import jdk.vm.ci.code.BytecodeFrame;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
@@ -85,7 +86,7 @@
 
     public BasicArrayCopyNode(NodeClass<? extends AbstractMemoryCheckpoint> type, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind) {
         super(type, StampFactory.forKind(JavaKind.Void));
-        this.bci = -6;
+        this.bci = BytecodeFrame.INVALID_FRAMESTATE_BCI;
         args = new NodeInputList<>(this, new ValueNode[]{src, srcPos, dest, destPos, length});
         this.elementKind = elementKind != JavaKind.Illegal ? elementKind : null;
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java	Thu Jun 01 02:21:18 2017 +0000
@@ -64,7 +64,7 @@
         return updateStamp(computeStamp(getObject()));
     }
 
-    private static Stamp computeStamp(ValueNode object) {
+    protected Stamp computeStamp(ValueNode object) {
         Stamp objectStamp = object.stamp();
         if (objectStamp instanceof ObjectStamp) {
             objectStamp = objectStamp.join(StampFactory.objectNonNull());
@@ -82,15 +82,17 @@
      *
      * If yes, then the exact type is returned, otherwise it returns null.
      */
-    protected static ResolvedJavaType getConcreteType(Stamp stamp) {
-        if (!(stamp instanceof ObjectStamp)) {
+    protected ResolvedJavaType getConcreteType(Stamp forStamp) {
+        if (!(forStamp instanceof ObjectStamp)) {
             return null;
         }
-        ObjectStamp objectStamp = (ObjectStamp) stamp;
+        ObjectStamp objectStamp = (ObjectStamp) forStamp;
         if (objectStamp.type() == null) {
             return null;
         } else if (objectStamp.isExactType()) {
             return objectStamp.type().isCloneableWithAllocation() ? objectStamp.type() : null;
+        } else if (objectStamp.type().isArray()) {
+            return objectStamp.type();
         }
         return null;
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java	Thu Jun 01 02:21:18 2017 +0000
@@ -22,6 +22,8 @@
  */
 package org.graalvm.compiler.test;
 
+import org.graalvm.util.CollectionsUtil;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
@@ -31,11 +33,10 @@
 import java.util.Arrays;
 import java.util.Formatter;
 import java.util.List;
+import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.graalvm.util.CollectionsUtil;
-
 /**
  * Utility methods for spawning a VM in a subprocess during unit tests.
  */
@@ -184,9 +185,46 @@
      * @param mainClassAndArgs the main class and its arguments
      */
     public static Subprocess java(List<String> vmArgs, List<String> mainClassAndArgs) throws IOException, InterruptedException {
+        return javaHelper(vmArgs, null, mainClassAndArgs);
+    }
+
+    /**
+     * Executes a Java subprocess.
+     *
+     * @param vmArgs the VM arguments
+     * @param env the environment variables
+     * @param mainClassAndArgs the main class and its arguments
+     */
+    public static Subprocess java(List<String> vmArgs, Map<String, String> env, String... mainClassAndArgs) throws IOException, InterruptedException {
+        return java(vmArgs, env, Arrays.asList(mainClassAndArgs));
+    }
+
+    /**
+     * Executes a Java subprocess.
+     *
+     * @param vmArgs the VM arguments
+     * @param env the environment variables
+     * @param mainClassAndArgs the main class and its arguments
+     */
+    public static Subprocess java(List<String> vmArgs, Map<String, String> env, List<String> mainClassAndArgs) throws IOException, InterruptedException {
+        return javaHelper(vmArgs, env, mainClassAndArgs);
+    }
+
+    /**
+     * Executes a Java subprocess.
+     *
+     * @param vmArgs the VM arguments
+     * @param env the environment variables
+     * @param mainClassAndArgs the main class and its arguments
+     */
+    private static Subprocess javaHelper(List<String> vmArgs, Map<String, String> env, List<String> mainClassAndArgs) throws IOException, InterruptedException {
         List<String> command = new ArrayList<>(vmArgs);
         command.addAll(mainClassAndArgs);
         ProcessBuilder processBuilder = new ProcessBuilder(command);
+        if (env != null) {
+            Map<String, String> processBuilderEnv = processBuilder.environment();
+            processBuilderEnv.putAll(env);
+        }
         processBuilder.redirectErrorStream(true);
         Process process = processBuilder.start();
         BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java	Wed May 31 09:19:28 2017 -0400
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java	Thu Jun 01 02:21:18 2017 +0000
@@ -26,7 +26,7 @@
 import java.util.BitSet;
 import java.util.Iterator;
 import java.util.List;
-import java.util.function.IntFunction;
+import java.util.function.IntUnaryOperator;
 
 import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.cfg.Loop;
@@ -806,7 +806,7 @@
         private boolean mergeObjectStates(int resultObject, int[] sourceObjects, PartialEscapeBlockState<?>[] states) {
             boolean compatible = true;
             boolean ensureVirtual = true;
-            IntFunction<Integer> getObject = index -> sourceObjects == null ? resultObject : sourceObjects[index];
+            IntUnaryOperator getObject = index -> sourceObjects == null ? resultObject : sourceObjects[index];
 
             VirtualObjectNode virtual = virtualObjects.get(resultObject);
             int entryCount = virtual.entryCount();
@@ -814,7 +814,7 @@
             // determine all entries that have a two-slot value
             JavaKind[] twoSlotKinds = null;
             outer: for (int i = 0; i < states.length; i++) {
-                ObjectState objectState = states[i].getObjectState(getObject.apply(i));
+                ObjectState objectState = states[i].getObjectState(getObject.applyAsInt(i));
                 ValueNode[] entries = objectState.getEntries();
                 int valueIndex = 0;
                 ensureVirtual &= objectState.getEnsureVirtualized();
@@ -845,7 +845,7 @@
                     if (twoSlotKinds[valueIndex] != null) {
                         assert valueIndex < virtual.entryCount() - 1 && virtual.entryKind(valueIndex) == JavaKind.Int && virtual.entryKind(valueIndex + 1) == JavaKind.Int;
                         for (int i = 0; i < states.length; i++) {
-                            int object = getObject.apply(i);
+                            int object = getObject.applyAsInt(i);
                             ObjectState objectState = states[i].getObjectState(object);
                             ValueNode value = objectState.getEntry(valueIndex);
                             JavaKind valueKind = value.getStackKind();
@@ -867,13 +867,13 @@
 
             if (compatible) {
                 // virtual objects are compatible: create phis for all entries that need them
-                ValueNode[] values = states[0].getObjectState(getObject.apply(0)).getEntries().clone();
+                ValueNode[] values = states[0].getObjectState(getObject.applyAsInt(0)).getEntries().clone();
                 PhiNode[] phis = getValuePhis(virtual, virtual.entryCount());
                 int valueIndex = 0;
                 while (valueIndex < values.length) {
                     for (int i = 1; i < states.length; i++) {
                         if (phis[valueIndex] == null) {
-                            ValueNode field = states[i].getObjectState(getObject.apply(i)).getEntry(valueIndex);
+                            ValueNode field = states[i].getObjectState(getObject.applyAsInt(i)).getEntry(valueIndex);
                             if (values[valueIndex] != field) {
                                 phis[valueIndex] = createValuePhi(values[valueIndex].stamp().unrestricted());
                             }
@@ -900,7 +900,7 @@
                             materialized |= mergeObjectEntry(getObject, states, phi, i);
                         } else {
                             for (int i2 = 0; i2 < states.length; i2++) {
-                                ObjectState state = states[i2].getObjectState(getObject.apply(i2));
+                                ObjectState state = states[i2].getObjectState(getObject.applyAsInt(i2));
                                 if (!state.isVirtual()) {
                                     break;
                                 }
@@ -910,19 +910,19 @@
                         values[i] = phi;
                     }
                 }
-                newState.addObject(resultObject, new ObjectState(values, states[0].getObjectState(getObject.apply(0)).getLocks(), ensureVirtual));
+                newState.addObject(resultObject, new ObjectState(values, states[0].getObjectState(getObject.applyAsInt(0)).getLocks(), ensureVirtual));
                 return materialized;
             } else {
                 // not compatible: materialize in all predecessors
                 PhiNode materializedValuePhi = getPhi(resultObject, StampFactory.forKind(JavaKind.Object));
                 for (int i = 0; i < states.length; i++) {
                     Block predecessor = getPredecessor(i);
-                    if (!ensureVirtual && states[i].getObjectState(virtual).isVirtual()) {
+                    if (!ensureVirtual && states[i].getObjectState(getObject.applyAsInt(i)).isVirtual()) {
                         // we can materialize if not all inputs are "ensureVirtualized"
-                        states[i].getObjectState(virtual).setEnsureVirtualized(false);
+                        states[i].getObjectState(getObject.applyAsInt(i)).setEnsureVirtualized(false);
                     }
-                    ensureMaterialized(states[i], getObject.apply(i), predecessor.getEndNode(), blockEffects.get(predecessor), COUNTER_MATERIALIZATIONS_MERGE);
-                    setPhiInput(materializedValuePhi, i, states[i].getObjectState(getObject.apply(i)).getMaterializedValue());
+                    ensureMaterialized(states[i], getObject.applyAsInt(i), predecessor.getEndNode(), blockEffects.get(predecessor), COUNTER_MATERIALIZATIONS_MERGE);
+                    setPhiInput(materializedValuePhi, i, states[i].getObjectState(getObject.applyAsInt(i)).getMaterializedValue());
                 }
                 newState.addObject(resultObject, new ObjectState(materializedValuePhi, null, ensureVirtual));
                 return true;
@@ -935,10 +935,10 @@
          *
          * @return true if materialization happened during the merge, false otherwise
          */
-        private boolean mergeObjectEntry(IntFunction<Integer> objectIdFunc, PartialEscapeBlockState<?>[] states, PhiNode phi, int entryIndex) {
+        private boolean mergeObjectEntry(IntUnaryOperator objectIdFunc, PartialEscapeBlockState<?>[] states, PhiNode phi, int entryIndex) {
             boolean materialized = false;
             for (int i = 0; i < states.length; i++) {
-                int object = objectIdFunc.apply(i);
+                int object = objectIdFunc.applyAsInt(i);
                 ObjectState objectState = states[i].getObjectState(object);
                 if (!objectState.isVirtual()) {
                     break;