changeset 47667:390896759aa2

8187438: Update Graal Reviewed-by: kvn
author dlong
date Wed, 11 Oct 2017 17:11:28 -0700
parents 19219ec3f176
children fc4cfca10556
files src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashMapGetTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OffHeapUnsafeAccessTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StableArrayReadFoldingTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/TrufflePEATest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HsErrLogTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvokeDynamicPlugin.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem4.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPrefetchOp.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvokeDynamicPlugin.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionKey.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionType.java
diffstat 61 files changed, 2198 insertions(+), 406 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java	Wed Oct 11 17:11:28 2017 -0700
@@ -253,13 +253,17 @@
      * Comparator for sorting blocks based on loop depth and probability.
      */
     private static class BlockOrderComparator<T extends AbstractBlockBase<T>> implements Comparator<T> {
+        private static final double EPSILON = 1E-6;
 
         @Override
         public int compare(T a, T b) {
-            // Loop blocks before any loop exit block.
-            int diff = b.getLoopDepth() - a.getLoopDepth();
-            if (diff != 0) {
-                return diff;
+            // Loop blocks before any loop exit block. The only exception are blocks that are
+            // (almost) impossible to reach.
+            if (a.probability() > EPSILON && b.probability() > EPSILON) {
+                int diff = b.getLoopDepth() - a.getLoopDepth();
+                if (diff != 0) {
+                    return diff;
+                }
             }
 
             // Blocks with high probability before blocks with low probability.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java	Wed Oct 11 17:11:28 2017 -0700
@@ -172,7 +172,7 @@
 
         PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
         Plugins plugins = new Plugins(new InvocationPlugins());
-        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
         graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
         HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Wed Oct 11 17:11:28 2017 -0700
@@ -1249,7 +1249,7 @@
     }
 
     protected PhaseSuite<HighTierContext> getEagerGraphBuilderSuite() {
-        return getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true));
+        return getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true).withUnresolvedIsError(true));
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashMapGetTest.java	Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017, 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;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.calc.ObjectEqualsNode;
+import org.junit.Test;
+
+import java.util.HashMap;
+
+public class HashMapGetTest extends GraalCompilerTest {
+
+    public static void mapGet(HashMap<Integer, Integer> map, Integer key) {
+        map.get(key);
+    }
+
+    @Test
+    public void hashMapTest() {
+        HashMap<Integer, Integer> map = new HashMap<>();
+        ResolvedJavaMethod get = getResolvedJavaMethod(HashMapGetTest.class, "mapGet");
+        for (int i = 0; i < 5000; i++) {
+            mapGet(map, i);
+            map.put(i, i);
+            mapGet(map, i);
+        }
+        test(get, null, map, new Integer(0));
+        for (IfNode ifNode : lastCompiledGraph.getNodes(IfNode.TYPE)) {
+            LogicNode condition = ifNode.condition();
+            if (ifNode.getTrueSuccessorProbability() < 0.4 && condition instanceof ObjectEqualsNode) {
+                assertTrue(ifNode.trueSuccessor().next() instanceof ReturnNode, "Expected return.", ifNode.trueSuccessor(), ifNode.trueSuccessor().next());
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OffHeapUnsafeAccessTest.java	Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,146 @@
+/*
+ * 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;
+
+import java.lang.reflect.Field;
+
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.JavaKind;
+import sun.misc.Unsafe;
+
+/**
+ * Tests that off-heap memory writes don't prevent optimization of on-heap accesses.
+ */
+public class OffHeapUnsafeAccessTest extends GraalCompilerTest {
+
+    static final Unsafe UNSAFE = initUnsafe();
+
+    private static Unsafe initUnsafe() {
+        try {
+            // Fast path when we are trusted.
+            return Unsafe.getUnsafe();
+        } catch (SecurityException se) {
+            // Slow path when we are not trusted.
+            try {
+                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+                theUnsafe.setAccessible(true);
+                return (Unsafe) theUnsafe.get(Unsafe.class);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to get Unsafe", e);
+            }
+        }
+    }
+
+    public byte unboxByteAndStore(long memory, byte[] box) {
+        byte val = box[0];
+        UNSAFE.putByte(memory, val);
+        UNSAFE.putByte(null, memory, val);
+        return box[0];
+    }
+
+    public char unboxCharAndStore(long memory, char[] box) {
+        char val = box[0];
+        UNSAFE.putChar(memory, val);
+        UNSAFE.putChar(null, memory, val);
+        return box[0];
+    }
+
+    public int unboxIntAndStore(long memory, int[] box) {
+        int val = box[0];
+        UNSAFE.putInt(memory, val);
+        UNSAFE.putInt(null, memory, val);
+        return box[0];
+    }
+
+    public long unboxLongAndStore(long memory, long[] box) {
+        long val = box[0];
+        UNSAFE.putLong(memory, val);
+        UNSAFE.putLong(null, memory, val);
+        UNSAFE.putAddress(memory, val);
+        return box[0];
+    }
+
+    public float unboxFloatAndStore(long memory, float[] box) {
+        float val = box[0];
+        UNSAFE.putFloat(memory, val);
+        UNSAFE.putFloat(null, memory, val);
+        return box[0];
+    }
+
+    public double unboxDoubleAndStore(long memory, double[] box) {
+        double val = box[0];
+        UNSAFE.putDouble(memory, val);
+        UNSAFE.putDouble(null, memory, val);
+        return box[0];
+    }
+
+    private void assertExactlyOneArrayLoad(JavaKind elementKind) {
+        int total = 0;
+        for (ReadNode read : lastCompiledGraph.getNodes().filter(ReadNode.class)) {
+            if (read.getLocationIdentity().equals(NamedLocationIdentity.getArrayLocation(elementKind))) {
+                total++;
+            }
+        }
+        Assert.assertEquals(1, total);
+    }
+
+    @Test
+    public void testGet() {
+        long buf = allocBuf();
+        if (buf != 0) {
+            try {
+                test("unboxByteAndStore", buf, new byte[]{40});
+                assertExactlyOneArrayLoad(JavaKind.Byte);
+
+                test("unboxCharAndStore", buf, new char[]{41});
+                assertExactlyOneArrayLoad(JavaKind.Char);
+
+                test("unboxIntAndStore", buf, new int[]{42});
+                assertExactlyOneArrayLoad(JavaKind.Int);
+
+                test("unboxLongAndStore", buf, new long[]{43});
+                assertExactlyOneArrayLoad(JavaKind.Long);
+
+                test("unboxFloatAndStore", buf, new float[]{44.0F});
+                assertExactlyOneArrayLoad(JavaKind.Float);
+
+                test("unboxDoubleAndStore", buf, new double[]{45.0D});
+                assertExactlyOneArrayLoad(JavaKind.Double);
+            } finally {
+                UNSAFE.freeMemory(buf);
+            }
+        }
+    }
+
+    protected long allocBuf() {
+        try {
+            return UNSAFE.allocateMemory(16);
+        } catch (OutOfMemoryError e) {
+            return 0L;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StableArrayReadFoldingTest.java	Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,122 @@
+/*
+ * 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;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.options.OptionValues;
+import org.junit.Assume;
+import org.junit.Test;
+
+public class StableArrayReadFoldingTest extends GraalCompilerTest {
+
+    static final boolean[] STABLE_BOOLEAN_ARRAY = new boolean[16];
+    static final int[] STABLE_INT_ARRAY = new int[16];
+
+    static final long BOOLEAN_ARRAY_BASE_OFFSET;
+    static final long INT_ARRAY_BASE_OFFSET;
+
+    static {
+        BOOLEAN_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(boolean[].class);
+        INT_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(int[].class);
+    }
+
+    @Override
+    protected StructuredGraph parseForCompile(ResolvedJavaMethod method, CompilationIdentifier compilationId, OptionValues options) {
+        StructuredGraph graph = super.parseForCompile(method, compilationId, options);
+        // Mimic @Stable array constants.
+        for (ConstantNode constantNode : graph.getNodes().filter(ConstantNode.class).snapshot()) {
+            if (getConstantReflection().readArrayLength(constantNode.asJavaConstant()) != null) {
+                ConstantNode newConstantNode = graph.unique(ConstantNode.forConstant(constantNode.asJavaConstant(), 1, true, getMetaAccess()));
+                constantNode.replaceAndDelete(newConstantNode);
+            }
+        }
+        return graph;
+    }
+
+    public static boolean killWithSameType() {
+        boolean beforeKill = UNSAFE.getBoolean(STABLE_BOOLEAN_ARRAY, BOOLEAN_ARRAY_BASE_OFFSET);
+        STABLE_BOOLEAN_ARRAY[0] = true;
+        boolean afterKill = UNSAFE.getBoolean(STABLE_BOOLEAN_ARRAY, BOOLEAN_ARRAY_BASE_OFFSET);
+
+        STABLE_BOOLEAN_ARRAY[0] = false;
+        return beforeKill == afterKill;
+    }
+
+    @Test
+    public void testKillWithSameType() {
+        ResolvedJavaMethod method = getResolvedJavaMethod("killWithSameType");
+        testAgainstExpected(method, new Result(true, null), null);
+    }
+
+    public static boolean killWithDifferentType() {
+        byte beforeKill = UNSAFE.getByte(STABLE_BOOLEAN_ARRAY, BOOLEAN_ARRAY_BASE_OFFSET);
+        STABLE_BOOLEAN_ARRAY[0] = true;
+        byte afterKill = UNSAFE.getByte(STABLE_BOOLEAN_ARRAY, BOOLEAN_ARRAY_BASE_OFFSET);
+
+        STABLE_BOOLEAN_ARRAY[0] = false;
+        return beforeKill == afterKill;
+    }
+
+    @Test
+    public void testKillWithDifferentType() {
+        ResolvedJavaMethod method = getResolvedJavaMethod("killWithDifferentType");
+        testAgainstExpected(method, new Result(true, null), null);
+    }
+
+    public static boolean killWithSameTypeUnaligned() {
+        int beforeKill = UNSAFE.getInt(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1);
+        STABLE_INT_ARRAY[0] = 0x01020304;
+        int afterKill = UNSAFE.getInt(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1);
+
+        STABLE_INT_ARRAY[0] = 0;
+        return beforeKill == afterKill;
+    }
+
+    @Test
+    public void testKillWithSameTypeUnaligned() {
+        Assume.assumeTrue("Only test unaligned access on AMD64", getTarget().arch instanceof AMD64);
+        ResolvedJavaMethod method = getResolvedJavaMethod("killWithSameTypeUnaligned");
+        testAgainstExpected(method, new Result(true, null), null);
+    }
+
+    public static boolean killWithDifferentTypeUnaligned() {
+        byte beforeKill = UNSAFE.getByte(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1);
+        STABLE_INT_ARRAY[0] = 0x01020304;
+        byte afterKill = UNSAFE.getByte(STABLE_INT_ARRAY, INT_ARRAY_BASE_OFFSET + 1);
+
+        STABLE_INT_ARRAY[0] = 0;
+        return beforeKill == afterKill;
+    }
+
+    @Test
+    public void testKillWithDifferentTypeUnaligned() {
+        Assume.assumeTrue("Only test unaligned access on AMD64", getTarget().arch instanceof AMD64);
+        ResolvedJavaMethod method = getResolvedJavaMethod("killWithDifferentTypeUnaligned");
+        testAgainstExpected(method, new Result(true, null), null);
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java	Wed Oct 11 17:11:28 2017 -0700
@@ -82,7 +82,7 @@
 
         PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
         Plugins plugins = new Plugins(new InvocationPlugins());
-        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
         graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
         HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java	Wed Oct 11 17:11:28 2017 -0700
@@ -89,7 +89,7 @@
             OptionValues options = getInitialOptions();
             StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options)).method(method).build();
             Plugins plugins = new Plugins(new InvocationPlugins());
-            GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+            GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
             OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE;
 
             GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), null, null, graphBuilderConfig, optimisticOpts, null);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java	Wed Oct 11 17:11:28 2017 -0700
@@ -46,11 +46,13 @@
     public static double SideEffectD;
     public static double SideEffectL;
 
+    private static final long booleanArrayBaseOffset;
     private static final long byteArrayBaseOffset;
     private static final long intArrayBaseOffset;
     private static final long longArrayBaseOffset;
 
     static {
+        booleanArrayBaseOffset = UNSAFE.arrayBaseOffset(boolean[].class);
         byteArrayBaseOffset = UNSAFE.arrayBaseOffset(byte[].class);
         intArrayBaseOffset = UNSAFE.arrayBaseOffset(int[].class);
         longArrayBaseOffset = UNSAFE.arrayBaseOffset(long[].class);
@@ -212,4 +214,77 @@
         test("testWriteFloatToIntArraySnippet");
     }
 
+    public static final byte[] FINAL_BYTE_ARRAY = new byte[16];
+
+    public static boolean alignedKill() {
+        int beforeKill = UNSAFE.getInt(FINAL_BYTE_ARRAY, byteArrayBaseOffset);
+        FINAL_BYTE_ARRAY[0] = 1;
+        int afterKill = UNSAFE.getInt(FINAL_BYTE_ARRAY, byteArrayBaseOffset);
+
+        FINAL_BYTE_ARRAY[0] = 0; // reset
+        return beforeKill == afterKill;
+    }
+
+    @Test
+    public void testAlignedKill() {
+        test("alignedKill");
+    }
+
+    public static boolean unalignedKill() {
+        int beforeKill = UNSAFE.getInt(FINAL_BYTE_ARRAY, byteArrayBaseOffset);
+        FINAL_BYTE_ARRAY[1] = 1;
+        int afterKill = UNSAFE.getInt(FINAL_BYTE_ARRAY, byteArrayBaseOffset);
+
+        FINAL_BYTE_ARRAY[1] = 0; // reset
+        return beforeKill == afterKill;
+    }
+
+    @Test
+    public void testUnalignedKill() {
+        test("unalignedKill");
+    }
+
+    public static final boolean[] FINAL_BOOLEAN_ARRAY = new boolean[16];
+
+    public static boolean killBooleanAccessToBooleanArrayViaBASTORE() {
+        boolean beforeKill = UNSAFE.getBoolean(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset);
+        FINAL_BOOLEAN_ARRAY[0] = true;
+        boolean afterKill = UNSAFE.getBoolean(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset);
+
+        FINAL_BOOLEAN_ARRAY[0] = false; // reset
+        return beforeKill == afterKill;
+    }
+
+    @Test
+    public void testKillBooleanAccessToBooleanArrayViaBASTORE() {
+        test("killBooleanAccessToBooleanArrayViaBASTORE");
+    }
+
+    public static boolean killByteAccessToBooleanArrayViaBASTORE() {
+        byte beforeKill = UNSAFE.getByte(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset);
+        FINAL_BOOLEAN_ARRAY[0] = true;
+        byte afterKill = UNSAFE.getByte(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset);
+
+        FINAL_BOOLEAN_ARRAY[0] = false; // reset
+        return beforeKill == afterKill;
+    }
+
+    @Test
+    public void testKillByteAccessToBooleanArrayViaBASTORE() {
+        test("killByteAccessToBooleanArrayViaBASTORE");
+    }
+
+    public static boolean unsafeWriteToBooleanArray() {
+        UNSAFE.putByte(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset, (byte) 2);
+        boolean result = UNSAFE.getBoolean(FINAL_BOOLEAN_ARRAY, booleanArrayBaseOffset);
+
+        FINAL_BOOLEAN_ARRAY[0] = false; // reset
+        return result;
+    }
+
+    @Test
+    public void testUnsafeWriteToBooleanArray() {
+        test("unsafeWriteToBooleanArray");
+    }
+
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java	Wed Oct 11 17:11:28 2017 -0700
@@ -123,7 +123,7 @@
         MetaAccessProvider metaAccess = providers.getMetaAccess();
         PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
         Plugins plugins = new Plugins(new InvocationPlugins());
-        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
         graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
         HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
         OptionValues options = getInitialOptions();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java	Wed Oct 11 17:11:28 2017 -0700
@@ -344,7 +344,7 @@
         MetaAccessProvider metaAccess = providers.getMetaAccess();
         PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
         Plugins plugins = new Plugins(new InvocationPlugins());
-        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
         graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
         HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
         OptionValues options = getInitialOptions();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java	Wed Oct 11 17:11:28 2017 -0700
@@ -268,7 +268,7 @@
         MetaAccessProvider metaAccess = providers.getMetaAccess();
         PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
         Plugins plugins = new Plugins(new InvocationPlugins());
-        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
         graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
         HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
         OptionValues options = getInitialOptions();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java	Wed Oct 11 17:11:28 2017 -0700
@@ -22,6 +22,7 @@
  */
 package org.graalvm.compiler.core.test.ea;
 
+import org.graalvm.compiler.core.test.GraalCompilerTest;
 import org.junit.Test;
 
 import sun.misc.Unsafe;
@@ -36,7 +37,7 @@
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
 
-public class PEAReadEliminationTest extends EarlyReadEliminationTest {
+public class PEAReadEliminationTest extends GraalCompilerTest {
 
     public static int testIndexed1Snippet(int[] array) {
         array[1] = 1;
@@ -50,7 +51,7 @@
 
     @Test
     public void testIndexed1() {
-        StructuredGraph graph = processMethod("testIndexed1Snippet", false);
+        StructuredGraph graph = processMethod("testIndexed1Snippet");
         assertDeepEquals(0, graph.getNodes().filter(LoadIndexedNode.class).count());
     }
 
@@ -70,7 +71,7 @@
 
     @Test
     public void testIndexed2() {
-        StructuredGraph graph = processMethod("testIndexed2Snippet", false);
+        StructuredGraph graph = processMethod("testIndexed2Snippet");
         assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count());
         assertDeepEquals(7, graph.getNodes().filter(StoreIndexedNode.class).count());
     }
@@ -94,7 +95,7 @@
 
     @Test
     public void testIndexed3() {
-        StructuredGraph graph = processMethod("testIndexed3Snippet", false);
+        StructuredGraph graph = processMethod("testIndexed3Snippet");
         assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count());
     }
 
@@ -113,7 +114,7 @@
 
     @Test
     public void testIndexed4() {
-        StructuredGraph graph = processMethod("testIndexed4Snippet", false);
+        StructuredGraph graph = processMethod("testIndexed4Snippet");
         assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count());
     }
 
@@ -129,7 +130,7 @@
 
     @Test
     public void testUnsafe1() {
-        StructuredGraph graph = processMethod("testUnsafe1Snippet", false);
+        StructuredGraph graph = processMethod("testUnsafe1Snippet");
         assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count());
     }
 
@@ -142,7 +143,7 @@
 
     @Test
     public void testUnsafe2() {
-        StructuredGraph graph = processMethod("testUnsafe2Snippet", false);
+        StructuredGraph graph = processMethod("testUnsafe2Snippet");
         assertDeepEquals(3, graph.getNodes().filter(RawLoadNode.class).count());
     }
 
@@ -158,7 +159,7 @@
 
     @Test
     public void testUnsafe3() {
-        StructuredGraph graph = processMethod("testUnsafe3Snippet", false);
+        StructuredGraph graph = processMethod("testUnsafe3Snippet");
         assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count());
     }
 
@@ -172,28 +173,11 @@
 
     @Test
     public void testUnsafe4() {
-        StructuredGraph graph = processMethod("testUnsafe4Snippet", false);
+        StructuredGraph graph = processMethod("testUnsafe4Snippet");
         assertDeepEquals(3, graph.getNodes().filter(RawLoadNode.class).count());
     }
 
-    private static final long offsetLong1 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 1;
-    private static final long offsetLong2 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 2;
-
-    public static int testUnsafe5Snippet(int v, long[] array) {
-        int s = UNSAFE.getInt(array, offsetLong1);
-        UNSAFE.putInt(array, offsetLong1, v);
-        UNSAFE.putInt(array, offsetLong2, v);
-        return s + UNSAFE.getInt(array, offsetLong1) + UNSAFE.getInt(array, offsetLong2);
-    }
-
-    @Test
-    public void testUnsafe5() {
-        StructuredGraph graph = processMethod("testUnsafe5Snippet", false);
-        assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count());
-    }
-
-    @Override
-    protected StructuredGraph processMethod(final String snippet, boolean doLowering) {
+    protected StructuredGraph processMethod(final String snippet) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         HighTierContext context = getDefaultHighTierContext();
         new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/TrufflePEATest.java	Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017, 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.ea;
+
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.extended.RawLoadNode;
+import org.graalvm.compiler.nodes.extended.RawStoreNode;
+import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
+import org.junit.Test;
+import sun.misc.Unsafe;
+
+import java.lang.reflect.Field;
+
+public class TrufflePEATest extends GraalCompilerTest {
+
+    /**
+     * This class mimics the behavior of {@code FrameWithoutBoxing}.
+     */
+    static class Frame {
+        long[] primitiveLocals;
+
+        Frame(int size) {
+            primitiveLocals = new long[size];
+        }
+    }
+
+    /**
+     * This class mimics the behavior of {@code DynamicObjectL6I6}.
+     */
+    static class DynamicObject {
+        int primitiveField0;
+        int primitiveField1;
+    }
+
+    private static final long offsetLong1 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 1;
+    private static final long offsetLong2 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 2;
+
+    private static final long primitiveField0Offset;
+
+    static {
+        try {
+            Field primitiveField0 = DynamicObject.class.getDeclaredField("primitiveField0");
+            primitiveField0Offset = UNSAFE.objectFieldOffset(primitiveField0);
+        } catch (NoSuchFieldException | SecurityException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    public static int unsafeAccessToLongArray(int v, Frame frame) {
+        long[] array = frame.primitiveLocals;
+        int s = UNSAFE.getInt(array, offsetLong1);
+        UNSAFE.putInt(array, offsetLong1, v);
+        UNSAFE.putInt(array, offsetLong2, v);
+        return s + UNSAFE.getInt(array, offsetLong1) + UNSAFE.getInt(array, offsetLong2);
+    }
+
+    @Test
+    public void testUnsafeAccessToLongArray() {
+        StructuredGraph graph = processMethod("unsafeAccessToLongArray");
+        assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count());
+    }
+
+    /**
+     * The following value should be less than the default value of
+     * {@link GraalOptions#MaximumEscapeAnalysisArrayLength}.
+     */
+    private static final int FRAME_SIZE = 16;
+
+    public static long newFrame(long v) {
+        Frame frame = new Frame(FRAME_SIZE);
+        // Testing unsafe accesses with other kinds requires special handling of the initialized
+        // entry kind.
+        UNSAFE.putLong(frame.primitiveLocals, offsetLong1, v);
+        return UNSAFE.getLong(frame.primitiveLocals, offsetLong1);
+    }
+
+    @Test
+    public void testNewFrame() {
+        StructuredGraph graph = processMethod("newFrame");
+        assertDeepEquals(0, graph.getNodes().filter(CommitAllocationNode.class).count());
+        assertDeepEquals(0, graph.getNodes().filter(RawLoadNode.class).count());
+        assertDeepEquals(0, graph.getNodes().filter(RawStoreNode.class).count());
+    }
+
+    protected StructuredGraph processMethod(final String snippet) {
+        StructuredGraph graph = parseEager(snippet, StructuredGraph.AllowAssumptions.NO);
+        HighTierContext context = getDefaultHighTierContext();
+        new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
+        new PartialEscapePhase(true, true, new CanonicalizerPhase(), null, graph.getOptions()).apply(graph, context);
+        return graph;
+    }
+
+    public static double accessDynamicObject(double v) {
+        DynamicObject obj = new DynamicObject();
+        UNSAFE.putDouble(obj, primitiveField0Offset, v);
+        return UNSAFE.getDouble(obj, primitiveField0Offset);
+    }
+
+    @Test
+    public void testAccessDynamicObject() {
+        StructuredGraph graph = processMethod("accessDynamicObject");
+        assertDeepEquals(0, graph.getNodes().filter(CommitAllocationNode.class).count());
+        assertDeepEquals(0, graph.getNodes().filter(RawLoadNode.class).count());
+        assertDeepEquals(0, graph.getNodes().filter(RawStoreNode.class).count());
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java	Wed Oct 11 17:11:28 2017 -0700
@@ -256,7 +256,7 @@
                      * yet and the bytecode parser would only create a graph.
                      */
                     Plugins plugins = new Plugins(new InvocationPlugins());
-                    GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
+                    GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
                     /*
                      * For simplicity, we ignore all exception handling during the static analysis.
                      * This is a constraint of this example code, a real static analysis needs to
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalError.java	Wed Oct 11 17:11:28 2017 -0700
@@ -181,6 +181,12 @@
     public String toString() {
         StringBuilder str = new StringBuilder();
         str.append(super.toString());
+        str.append(context());
+        return str.toString();
+    }
+
+    public String context() {
+        StringBuilder str = new StringBuilder();
         for (String s : context) {
             str.append("\n\tat ").append(s);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java	Wed Oct 11 17:11:28 2017 -0700
@@ -38,6 +38,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.function.Predicate;
+import java.util.function.Supplier;
 
 import org.graalvm.compiler.core.common.Fields;
 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
@@ -598,6 +599,15 @@
         }
     }
 
+    /**
+     * Update the source position only if it is null.
+     */
+    public void updateNodeSourcePosition(Supplier<NodeSourcePosition> sourcePositionSupp) {
+        if (this.sourcePosition == null) {
+            setNodeSourcePosition(sourcePositionSupp.get());
+        }
+    }
+
     public DebugCloseable withNodeSourcePosition() {
         return graph.withNodeSourcePosition(this);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java	Wed Oct 11 17:11:28 2017 -0700
@@ -195,7 +195,7 @@
                     Node result = graph.getNode(nodeId);
                     if (result == null) {
                         // node was deleted -> clear the bit and continue searching
-                        bits[wordIndex] = bits[wordIndex] & ~(1 << bitIndex);
+                        bits[wordIndex] = bits[wordIndex] & ~(1L << bitIndex);
                         int nextNodeId = nodeId + 1;
                         if ((nextNodeId & (Long.SIZE - 1)) == 0) {
                             // we reached the end of this word
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed Oct 11 17:11:28 2017 -0700
@@ -28,6 +28,10 @@
 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE;
+import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE;
+import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.INITIALIZE;
+import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -39,6 +43,7 @@
 import org.graalvm.compiler.core.amd64.AMD64MoveFactoryBase.BackupSlotProvider;
 import org.graalvm.compiler.core.common.CompressEncoding;
 import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
 import org.graalvm.compiler.core.common.spi.LIRKindTool;
 import org.graalvm.compiler.debug.DebugContext;
@@ -415,49 +420,49 @@
         return result;
     }
 
-    @Override
-    public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
-        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_STRING_BY_SYMBOL);
-        Constant[] constants = new Constant[]{constant};
-        AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
-        Object[] notes = new Object[]{HotSpotConstantLoadAction.RESOLVE};
+    private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, Object[] notes, Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(foreignCall);
         append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
         AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
         return emitMove(result);
     }
 
+    private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, AllocatableValue[] constantDescriptions, LIRFrameState frameState) {
+        Constant[] constants = new Constant[]{constant};
+        Object[] notes = new Object[]{action};
+        return emitConstantRetrieval(foreignCall, notes, constants, constantDescriptions, frameState);
+    }
+
+    private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, Value constantDescription, LIRFrameState frameState) {
+        AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
+        return emitConstantRetrieval(foreignCall, action, constant, constantDescriptions, frameState);
+    }
+
+    @Override
+    public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
+        return emitConstantRetrieval(RESOLVE_STRING_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState);
+    }
+
     @Override
     public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
-        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_KLASS_BY_SYMBOL);
-        Constant[] constants = new Constant[]{constant};
-        AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
-        Object[] notes = new Object[]{HotSpotConstantLoadAction.RESOLVE};
-        append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
-        AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
-        return emitMove(result);
+        return emitConstantRetrieval(RESOLVE_KLASS_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState);
+    }
+
+    @Override
+    public Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
+        return emitConstantRetrieval(INITIALIZE_KLASS_BY_SYMBOL, INITIALIZE, constant, constantDescription, frameState);
     }
 
     @Override
     public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) {
-        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS);
-        Constant[] constants = new Constant[]{method};
         AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)};
-        Object[] notes = new Object[]{HotSpotConstantLoadAction.LOAD_COUNTERS};
-        append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
-        AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
-        return emitMove(result);
-
+        return emitConstantRetrieval(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, LOAD_COUNTERS, method, constantDescriptions, frameState);
     }
 
     @Override
-    public Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
-        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(INITIALIZE_KLASS_BY_SYMBOL);
-        Constant[] constants = new Constant[]{constant};
-        AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
-        Object[] notes = new Object[]{HotSpotConstantLoadAction.INITIALIZE};
-        append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
-        AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
-        return emitMove(result);
+    public Value emitResolveDynamicInvoke(Constant appendix, LIRFrameState frameState) {
+        AllocatableValue[] constantDescriptions = new AllocatableValue[0];
+        return emitConstantRetrieval(RESOLVE_DYNAMIC_INVOKE, INITIALIZE, appendix, constantDescriptions, frameState);
     }
 
     @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Wed Oct 11 17:11:28 2017 -0700
@@ -27,6 +27,7 @@
 import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
 
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
 import org.graalvm.compiler.core.common.CompressEncoding;
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.calc.Condition;
@@ -255,7 +256,7 @@
     @Override
     public void emitPrefetchAllocate(Value address) {
         SPARCAddressValue addr = asAddressValue(address);
-        append(new SPARCPrefetchOp(addr, config.allocatePrefetchInstr));
+        append(new SPARCPrefetchOp(addr, SPARCAssembler.Fcn.SeveralWritesAndPossiblyReads));
     }
 
     public StackSlot getDeoptimizationRescueSlot() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java	Wed Oct 11 17:11:28 2017 -0700
@@ -52,8 +52,10 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.ServiceLoader;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
@@ -475,6 +477,7 @@
     private void compile(String classPath) throws IOException {
         final String[] entries = classPath.split(File.pathSeparator);
         long start = System.currentTimeMillis();
+        Map<Thread, StackTraceElement[]> initialThreads = Thread.getAllStackTraces();
 
         try {
             // compile dummy method to get compiler initialized outside of the
@@ -549,7 +552,13 @@
 
                     classFileCounter++;
 
-                    if (className.startsWith("jdk.management.") || className.startsWith("jdk.internal.cmm.*")) {
+                    if (className.startsWith("jdk.management.") ||
+                                    className.startsWith("jdk.internal.cmm.*") ||
+                                    // GR-5881: The class initializer for
+                                    // sun.tools.jconsole.OutputViewer
+                                    // spawns non-daemon threads for redirecting sysout and syserr.
+                                    // These threads tend to cause deadlock at VM exit
+                                    className.startsWith("sun.tools.jconsole.")) {
                         continue;
                     }
 
@@ -643,6 +652,33 @@
         } else {
             TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), compileTime.get(), memoryUsed.get());
         }
+
+        // Apart from the main thread, there should be only be daemon threads
+        // alive now. If not, then a class initializer has probably started
+        // a thread that could cause a deadlock while trying to exit the VM.
+        // One known example of this is sun.tools.jconsole.OutputViewer which
+        // spawns threads to redirect sysout and syserr. To help debug such
+        // scenarios, the stacks of potentially problematic threads are dumped.
+        Map<Thread, StackTraceElement[]> suspiciousThreads = new HashMap<>();
+        for (Map.Entry<Thread, StackTraceElement[]> e : Thread.getAllStackTraces().entrySet()) {
+            Thread thread = e.getKey();
+            if (thread != Thread.currentThread() && !initialThreads.containsKey(thread) && !thread.isDaemon() && thread.isAlive()) {
+                suspiciousThreads.put(thread, e.getValue());
+            }
+        }
+        if (!suspiciousThreads.isEmpty()) {
+            TTY.println("--- Non-daemon threads started during CTW ---");
+            for (Map.Entry<Thread, StackTraceElement[]> e : suspiciousThreads.entrySet()) {
+                Thread thread = e.getKey();
+                if (thread.isAlive()) {
+                    TTY.println(thread.toString() + " " + thread.getState());
+                    for (StackTraceElement ste : e.getValue()) {
+                        TTY.println("\tat " + ste);
+                    }
+                }
+            }
+            TTY.println("---------------------------------------------");
+        }
     }
 
     private synchronized void startThreads() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest.java	Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,145 @@
+/*
+ * 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.function.IntPredicate;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import java.security.PrivilegedAction;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.hotspot.meta.HotSpotClassInitializationPlugin;
+import org.graalvm.compiler.hotspot.meta.HotSpotInvokeDynamicPlugin;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicStubCall;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase;
+import org.graalvm.compiler.phases.common.GuardLoweringPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class HotSpotInvokeDynamicPluginTest extends HotSpotGraalCompilerTest {
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins plugins = super.getDefaultGraphBuilderPlugins();
+        plugins.setClassInitializationPlugin(new HotSpotClassInitializationPlugin());
+        plugins.setInvokeDynamicPlugin(new HotSpotInvokeDynamicPlugin() {
+            @Override
+            public boolean isResolvedDynamicInvoke(GraphBuilderContext builder, int index, int opcode) {
+                // Allow invokedynamic testing with older JVMCI
+                ResolvedJavaMethod m = builder.getMethod();
+                if (m.getName().startsWith("invokeDynamic") && m.getDeclaringClass().getName().equals("Lorg/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest;")) {
+                    return false;
+                }
+                return super.isResolvedDynamicInvoke(builder, index, opcode);
+            }
+
+            @Override
+            public boolean supportsDynamicInvoke(GraphBuilderContext builder, int index, int opcode) {
+                // Allow invokehandle testing with older JVMCI
+                ResolvedJavaMethod m = builder.getMethod();
+                if (m.getName().startsWith("invokeHandle") && m.getDeclaringClass().getName().equals("Lorg/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest;")) {
+                    return true;
+                }
+                return super.supportsDynamicInvoke(builder, index, opcode);
+            }
+        });
+        return plugins;
+    }
+
+    @Override
+    protected InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        return InlineInfo.DO_NOT_INLINE_NO_EXCEPTION;
+    }
+
+    private void test(String name, int expectedResolves, int expectedStubCalls) {
+        StructuredGraph graph = parseEager(name, AllowAssumptions.NO, new OptionValues(getInitialOptions(), GraalOptions.GeneratePIC, true));
+        MidTierContext midTierContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
+
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        Assert.assertEquals(expectedResolves, graph.getNodes().filter(ResolveDynamicConstantNode.class).count());
+        Assert.assertEquals(0, graph.getNodes().filter(ResolveDynamicStubCall.class).count());
+        PhaseContext context = new PhaseContext(getProviders());
+        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        new GuardLoweringPhase().apply(graph, midTierContext);
+        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context);
+        new FrameStateAssignmentPhase().apply(graph);
+        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER).apply(graph, context);
+        Assert.assertEquals(0, graph.getNodes().filter(ResolveDynamicConstantNode.class).count());
+        Assert.assertEquals(expectedStubCalls, graph.getNodes().filter(ResolveDynamicStubCall.class).count());
+    }
+
+    public static IntPredicate invokeDynamic1() {
+        IntPredicate i = (v) -> v > 1;
+        return i;
+    }
+
+    public static PrivilegedAction<Integer> invokeDynamic2(String s) {
+        return s::length;
+    }
+
+    static final MethodHandle objToStringMH;
+
+    static {
+        MethodHandle mh = null;
+        try {
+            mh = MethodHandles.lookup().findVirtual(Object.class, "toString", MethodType.methodType(String.class));
+        } catch (Exception e) {
+        }
+        objToStringMH = mh;
+    }
+
+    // invokehandle
+    public static String invokeHandle1(Object o) throws Throwable {
+        return (String) objToStringMH.invokeExact(o);
+    }
+
+    @Test
+    public void test1() {
+        test("invokeDynamic1", 1, 1);
+    }
+
+    @Test
+    public void test2() {
+        test("invokeDynamic2", 1, 1);
+    }
+
+    @Test
+    public void test3() {
+        test("invokeHandle1", 1, 1);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HsErrLogTest.java	Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,153 @@
+/*
+ * 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 static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine;
+import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.test.SubprocessUtil;
+import org.graalvm.compiler.test.SubprocessUtil.Subprocess;
+import org.junit.Assert;
+import org.junit.Test;
+
+import sun.misc.Unsafe;
+
+/**
+ * Tests that a hs_err crash log contains expected content.
+ */
+public class HsErrLogTest extends GraalCompilerTest {
+
+    @Test
+    public void test1() throws IOException, InterruptedException {
+        List<String> args = new ArrayList<>();
+        if (Java8OrEarlier) {
+            args.add("-XX:-UseJVMCIClassLoader");
+        }
+        args.add("-XX:+UseJVMCICompiler");
+        args.add("-XX:CompileOnly=" + Crasher.class.getName() + "::tryCrash");
+        args.add(Crasher.class.getName());
+        testHelper(args);
+    }
+
+    private static final boolean VERBOSE = Boolean.getBoolean(HsErrLogTest.class.getSimpleName() + ".verbose");
+
+    private static void testHelper(List<String> extraVmArgs, String... mainClassAndArgs) throws IOException, InterruptedException {
+        List<String> vmArgs = withoutDebuggerArguments(getVMCommandLine());
+        vmArgs.removeIf(a -> a.startsWith("-Dgraal."));
+        vmArgs.remove("-esa");
+        vmArgs.remove("-ea");
+        vmArgs.addAll(extraVmArgs);
+
+        Subprocess proc = SubprocessUtil.java(vmArgs, mainClassAndArgs);
+        if (VERBOSE) {
+            System.out.println(proc);
+        }
+
+        Pattern re = Pattern.compile("# +(.*hs_err_pid[\\d]+\\.log)");
+
+        for (String line : proc.output) {
+            Matcher m = re.matcher(line);
+            if (m.matches()) {
+                File path = new File(m.group(1));
+                Assert.assertTrue(path.toString(), path.exists());
+                checkHsErr(path);
+                return;
+            }
+        }
+
+        Assert.fail("Could not find " + re.pattern());
+    }
+
+    private static void checkHsErr(File hsErrPath) {
+        try (BufferedReader br = new BufferedReader(new FileReader(hsErrPath))) {
+            String line = br.readLine();
+            String sig = Crasher.class.getName() + ".tryCrash(JI)I";
+            List<String> lines = new ArrayList<>();
+            while (line != null) {
+                if (line.contains(sig)) {
+                    if (!VERBOSE) {
+                        hsErrPath.delete();
+                    }
+                    return;
+                }
+                lines.add(line);
+                line = br.readLine();
+            }
+            throw new AssertionError("Could not find line containing \"" + sig + "\" in " + hsErrPath +
+                            ":" + System.lineSeparator() + String.join(System.lineSeparator(), lines));
+        } catch (IOException e) {
+            throw new AssertionError(e);
+        }
+    }
+}
+
+class Crasher {
+    public static void main(String[] args) {
+        int iter = 0;
+        long mem = UNSAFE.allocateMemory(1000);
+        while (iter < Integer.MAX_VALUE) {
+            tryCrash(mem, iter);
+            iter++;
+        }
+    }
+
+    protected static int tryCrash(long mem, int iter) {
+        if (GraalDirectives.inCompiledCode()) {
+            UNSAFE.putInt(0, iter);
+            return 0;
+        } else {
+            UNSAFE.putInt(mem, iter);
+            return UNSAFE.getInt(mem);
+        }
+    }
+
+    static final Unsafe UNSAFE = initUnsafe();
+
+    private static Unsafe initUnsafe() {
+        try {
+            // Fast path when we are trusted.
+            return Unsafe.getUnsafe();
+        } catch (SecurityException se) {
+            // Slow path when we are not trusted.
+            try {
+                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+                theUnsafe.setAccessible(true);
+                return (Unsafe) theUnsafe.get(Unsafe.class);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to get Unsafe", e);
+            }
+        }
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java	Wed Oct 11 17:11:28 2017 -0700
@@ -240,7 +240,7 @@
     }
 
     /**
-     * @return the compilation id plus a trailing '%' is the compilation is an OSR to match
+     * @return the compilation id plus a trailing '%' if the compilation is an OSR to match
      *         PrintCompilation style output
      */
     public String getIdString() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java	Wed Oct 11 17:11:28 2017 -0700
@@ -29,7 +29,6 @@
 import java.util.List;
 import java.util.stream.Collectors;
 
-import org.graalvm.compiler.debug.Assertions;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
@@ -73,7 +72,6 @@
     protected CompilerConfigurationFactory(String name, int autoSelectionPriority) {
         this.name = name;
         this.autoSelectionPriority = autoSelectionPriority;
-        assert checkAndAddNewFactory(this);
     }
 
     public abstract CompilerConfiguration createCompilerConfiguration();
@@ -127,18 +125,18 @@
     }
 
     /**
-     * List used to assert uniqueness of {@link #name} and {@link #autoSelectionPriority} across all
-     * {@link CompilerConfigurationFactory} instances.
+     * Asserts uniqueness of {@link #name} and {@link #autoSelectionPriority} for {@code factory} in
+     * {@code factories}.
      */
-    private static final List<CompilerConfigurationFactory> factories = Assertions.assertionsEnabled() ? new ArrayList<>() : null;
-
-    private static boolean checkAndAddNewFactory(CompilerConfigurationFactory factory) {
+    private static boolean checkUnique(CompilerConfigurationFactory factory, List<CompilerConfigurationFactory> factories) {
         for (CompilerConfigurationFactory other : factories) {
-            assert !other.name.equals(factory.name) : factory.getClass().getName() + " cannot have the same selector as " + other.getClass().getName() + ": " + factory.name;
-            assert other.autoSelectionPriority != factory.autoSelectionPriority : factory.getClass().getName() + " cannot have the same auto-selection priority as " + other.getClass().getName() +
-                            ": " + factory.autoSelectionPriority;
+            if (other != factory) {
+                assert !other.name.equals(factory.name) : factory.getClass().getName() + " cannot have the same selector as " + other.getClass().getName() + ": " + factory.name;
+                assert other.autoSelectionPriority != factory.autoSelectionPriority : factory.getClass().getName() + " cannot have the same auto-selection priority as " +
+                                other.getClass().getName() +
+                                ": " + factory.autoSelectionPriority;
+            }
         }
-        factories.add(factory);
         return true;
     }
 
@@ -148,6 +146,7 @@
     private static List<CompilerConfigurationFactory> getAllCandidates() {
         List<CompilerConfigurationFactory> candidates = new ArrayList<>();
         for (CompilerConfigurationFactory candidate : GraalServices.load(CompilerConfigurationFactory.class)) {
+            assert checkUnique(candidate, candidates);
             candidates.add(candidate);
         }
         Collections.sort(candidates);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerRuntimeHotSpotVMConfig.java	Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -35,6 +35,7 @@
     }
 
     public final long resolveStringBySymbol = getAddress("CompilerRuntime::resolve_string_by_symbol");
+    public final long resolveDynamicInvoke = getAddress("CompilerRuntime::resolve_dynamic_invoke");
     public final long resolveKlassBySymbol = getAddress("CompilerRuntime::resolve_klass_by_symbol");
     public final long resolveMethodBySymbolAndLoadCounters = getAddress("CompilerRuntime::resolve_method_by_symbol_and_load_counters");
     public final long initializeKlassBySymbol = getAddress("CompilerRuntime::initialize_klass_by_symbol");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java	Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -297,6 +297,11 @@
     /**
      * @see ResolveConstantStubCall
      */
+    public static final ForeignCallDescriptor RESOLVE_DYNAMIC_INVOKE = new ForeignCallDescriptor("resolve_dynamic_invoke", Object.class, Word.class);
+
+    /**
+     * @see ResolveConstantStubCall
+     */
     public static final ForeignCallDescriptor RESOLVE_KLASS_BY_SYMBOL = new ForeignCallDescriptor("resolve_klass_by_symbol", Word.class, Word.class, Word.class);
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java	Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -68,7 +68,7 @@
      * @return value of loaded address in register
      */
     default Value emitLoadObjectAddress(Constant constant) {
-        throw GraalError.unimplemented();
+        throw new GraalError("Emitting code to load an object address is not currently supported on %s", target().arch);
     }
 
     /**
@@ -79,7 +79,7 @@
      * @return Value of loaded address in register
      */
     default Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) {
-        throw GraalError.unimplemented();
+        throw new GraalError("Emitting code to load a metaspace address is not currently supported on %s", target().arch);
     }
 
     /**
@@ -90,7 +90,7 @@
      * @return value of loaded global in register
      */
     default Value emitLoadConfigValue(int markId, LIRKind kind) {
-        throw GraalError.unimplemented();
+        throw new GraalError("Emitting code to load a config value is not currently supported on %s", target().arch);
     }
 
     /**
@@ -100,10 +100,21 @@
      * @param constantDescription a description of the string that need to be materialized (and
      *            interned) as java.lang.String, generated with {@link EncodedSymbolConstant}
      * @param frameState frame state for the runtime call
-     * @return Returns the address of the requested constant.
+     * @return the address of the requested constant.
      */
     default Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
-        throw GraalError.unimplemented();
+        throw new GraalError("Emitting code to resolve an object constant is not currently supported on %s", target().arch);
+    }
+
+    /**
+     * Emits code to resolve a dynamic constant.
+     *
+     * @param constant original constant
+     * @param frameState frame state for the runtime call
+     * @return the address of the requested constant.
+     */
+    default Value emitResolveDynamicInvoke(Constant constant, LIRFrameState frameState) {
+        throw new GraalError("Emitting code to resolve a dynamic constant is not currently supported on %s", target().arch);
     }
 
     /**
@@ -113,10 +124,10 @@
      * @param constantDescription a symbolic description of the {@link HotSpotMetaspaceConstant}
      *            generated by {@link EncodedSymbolConstant}
      * @param frameState frame state for the runtime call
-     * @return Returns the address of the requested constant.
+     * @return the address of the requested constant.
      */
     default Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
-        throw GraalError.unimplemented();
+        throw new GraalError("Emitting code to resolve a metaspace constant is not currently supported on %s", target().arch);
     }
 
     /**
@@ -129,10 +140,10 @@
      * @param methodDescription is symbolic description of the constant generated by
      *            {@link EncodedSymbolConstant}
      * @param frameState frame state for the runtime call
-     * @return Returns the address of the requested constant.
+     * @return the address of the requested constant.
      */
     default Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) {
-        throw GraalError.unimplemented();
+        throw new GraalError("Emitting code to resolve a method and load counters is not currently supported on %s", target().arch);
     }
 
     /**
@@ -144,10 +155,10 @@
      * @param constantDescription a symbolic description of the {@link HotSpotMetaspaceConstant}
      *            generated by {@link EncodedSymbolConstant}
      * @param frameState frame state for the runtime call
-     * @return Returns the address of the requested constant.
+     * @return the address of the requested constant.
      */
     default Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
-        throw GraalError.unimplemented();
+        throw new GraalError("Emitting code to initialize a class is not currently supported on %s", target().arch);
     }
 
     /**
@@ -156,7 +167,7 @@
      * @return value of the counter
      */
     default Value emitRandomSeed() {
-        throw GraalError.unimplemented();
+        throw new GraalError("Emitting code to return a random seed is not currently supported on %s", target().arch);
     }
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java	Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -24,7 +24,6 @@
 
 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
 import static org.graalvm.compiler.core.common.GraalOptions.AlwaysInlineVTableStubs;
-import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.core.common.GraalOptions.InlineVTableStubs;
 import static org.graalvm.compiler.core.common.GraalOptions.OmitHotExceptionStacktrace;
 import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.OSR_MIGRATION_END;
@@ -70,6 +69,7 @@
 import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
 import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
 import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode;
 import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode;
 import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode;
 import org.graalvm.compiler.hotspot.nodes.type.HotSpotNarrowOopStamp;
@@ -214,10 +214,8 @@
         arraycopySnippets = new ArrayCopySnippets.Templates(options, factories, runtime, providers, target);
         stringToBytesSnippets = new StringToBytesSnippets.Templates(options, factories, providers, target);
         hashCodeSnippets = new HashCodeSnippets.Templates(options, factories, providers, target);
-        if (GeneratePIC.getValue(options)) {
-            resolveConstantSnippets = new ResolveConstantSnippets.Templates(options, factories, providers, target);
-            profileSnippets = new ProfileSnippets.Templates(options, factories, providers, target);
-        }
+        resolveConstantSnippets = new ResolveConstantSnippets.Templates(options, factories, providers, target);
+        profileSnippets = new ProfileSnippets.Templates(options, factories, providers, target);
         providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(options, factories, providers, target));
     }
 
@@ -364,6 +362,10 @@
             }
         } else if (n instanceof IdentityHashCodeNode) {
             hashCodeSnippets.lower((IdentityHashCodeNode) n, tool);
+        } else if (n instanceof ResolveDynamicConstantNode) {
+            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+                resolveConstantSnippets.lower((ResolveDynamicConstantNode) n, tool);
+            }
         } else if (n instanceof ResolveConstantNode) {
             if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
                 resolveConstantSnippets.lower((ResolveConstantNode) n, tool);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -22,8 +22,6 @@
  */
 package org.graalvm.compiler.hotspot.meta;
 
-import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateRecompile;
-import static jdk.vm.ci.meta.DeoptimizationReason.Unresolved;
 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION;
@@ -63,7 +61,6 @@
 import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyNode;
 import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
 import org.graalvm.compiler.nodes.ConstantNode;
-import org.graalvm.compiler.nodes.DeoptimizeNode;
 import org.graalvm.compiler.nodes.DynamicPiNode;
 import org.graalvm.compiler.nodes.FixedGuardNode;
 import org.graalvm.compiler.nodes.LogicNode;
@@ -80,7 +77,6 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
-import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
 import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
@@ -101,13 +97,9 @@
 import org.graalvm.word.LocationIdentity;
 
 import jdk.vm.ci.code.CodeUtil;
-import jdk.vm.ci.hotspot.HotSpotObjectConstant;
-import jdk.vm.ci.hotspot.HotSpotResolvedJavaType;
-import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 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.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -139,42 +131,9 @@
         plugins.appendTypePlugin(nodePlugin);
         plugins.appendNodePlugin(nodePlugin);
         OptionValues options = replacements.getOptions();
-        if (GeneratePIC.getValue(options)) {
-            // AOT needs to filter out bad invokes
-            plugins.prependNodePlugin(new NodePlugin() {
-                @Override
-                public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
-                    if (b.parsingIntrinsic()) {
-                        return false;
-                    }
-                    // check if the holder has a valid fingerprint
-                    if (((HotSpotResolvedObjectType) method.getDeclaringClass()).getFingerprint() == 0) {
-                        // Deopt otherwise
-                        b.append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
-                        return true;
-                    }
-                    // the last argument that may come from appendix, check if it is a supported
-                    // constant type
-                    if (args.length > 0) {
-                        JavaConstant constant = args[args.length - 1].asJavaConstant();
-                        if (constant != null && constant instanceof HotSpotObjectConstant) {
-                            HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) ((HotSpotObjectConstant) constant).getType();
-                            Class<?> clazz = type.mirror();
-                            if (clazz.equals(String.class)) {
-                                return false;
-                            }
-                            if (Class.class.isAssignableFrom(clazz) && ((HotSpotResolvedObjectType) type).getFingerprint() != 0) {
-                                return false;
-                            }
-                            b.append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
-                            return true;
-                        }
-                    }
-                    return false;
-                }
-            });
+        if (!GeneratePIC.getValue(options)) {
+            plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), true));
         }
-        plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), true));
         plugins.appendInlineInvokePlugin(replacements);
         if (InlineDuringParsing.getValue(options)) {
             plugins.appendInlineInvokePlugin(new InlineDuringParsingPlugin());
@@ -196,7 +155,9 @@
                 registerClassPlugins(plugins, config, replacementBytecodeProvider);
                 registerSystemPlugins(invocationPlugins, foreignCalls);
                 registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config, replacementBytecodeProvider);
-                registerCallSitePlugins(invocationPlugins);
+                if (!GeneratePIC.getValue(options)) {
+                    registerCallSitePlugins(invocationPlugins);
+                }
                 registerReflectionPlugins(invocationPlugins, replacementBytecodeProvider);
                 registerConstantPoolPlugins(invocationPlugins, wordTypes, config, replacementBytecodeProvider);
                 registerAESPlugins(invocationPlugins, config, replacementBytecodeProvider);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java	Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -44,6 +44,7 @@
 import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_ARRAY;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_INSTANCE;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_MULTI_ARRAY;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL;
@@ -305,6 +306,7 @@
             registerForeignCall(WRONG_METHOD_HANDLER, c.handleWrongMethodStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
             CompilerRuntimeHotSpotVMConfig cr = new CompilerRuntimeHotSpotVMConfig(HotSpotJVMCIRuntime.runtime().getConfigStore());
             linkForeignCall(options, providers, RESOLVE_STRING_BY_SYMBOL, cr.resolveStringBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
+            linkForeignCall(options, providers, RESOLVE_DYNAMIC_INVOKE, cr.resolveDynamicInvoke, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any());
             linkForeignCall(options, providers, RESOLVE_KLASS_BY_SYMBOL, cr.resolveKlassBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any());
             linkForeignCall(options, providers, RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, cr.resolveMethodBySymbolAndLoadCounters, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, NO_LOCATIONS);
             linkForeignCall(options, providers, INITIALIZE_KLASS_BY_SYMBOL, cr.initializeKlassBySymbol, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, any());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvokeDynamicPlugin.java	Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,156 @@
+/*
+ * 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.meta;
+
+import org.graalvm.compiler.bytecode.Bytecodes;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvokeDynamicPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
+import jdk.vm.ci.meta.ConstantPool;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+public class HotSpotInvokeDynamicPlugin implements InvokeDynamicPlugin {
+
+    private static final Class<? extends ConstantPool> hscp;
+    private static final MethodHandle isResolvedDynamicInvokeMH;
+
+    static {
+        MethodHandle m = null;
+        Class<? extends ConstantPool> c = null;
+        try {
+            c = Class.forName("jdk.vm.ci.hotspot.HotSpotConstantPool").asSubclass(ConstantPool.class);
+            m = MethodHandles.lookup().findVirtual(c, "isResolvedDynamicInvoke", MethodType.methodType(boolean.class, int.class, int.class));
+        } catch (Exception e) {
+        }
+        isResolvedDynamicInvokeMH = m;
+        hscp = c;
+    }
+
+    private static boolean isResolvedDynamicInvoke(ConstantPool constantPool, int index, int opcode) {
+        if (isResolvedDynamicInvokeMH != null) {
+            if (!hscp.isInstance(constantPool)) {
+                return false;
+            }
+            try {
+                return (boolean) isResolvedDynamicInvokeMH.invoke(constantPool, index, opcode);
+            } catch (Throwable t) {
+                throw GraalError.shouldNotReachHere(t);
+            }
+        }
+        throw GraalError.shouldNotReachHere("isResolvedDynamicInvokeMH not set");
+    }
+
+    private final DynamicTypeStore dynoStore;
+    private final boolean treatAppendixAsConstant;
+
+    public HotSpotInvokeDynamicPlugin(DynamicTypeStore dynoStore, boolean treatAppendixAsConstant) {
+        this.dynoStore = dynoStore;
+        this.treatAppendixAsConstant = treatAppendixAsConstant;
+    }
+
+    public HotSpotInvokeDynamicPlugin(DynamicTypeStore dynoStore) {
+        this(dynoStore, true);
+    }
+
+    public HotSpotInvokeDynamicPlugin() {
+        this(null);
+    }
+
+    // invokehandle support
+    @Override
+    public boolean isResolvedDynamicInvoke(GraphBuilderContext builder, int index, int opcode) {
+        ConstantPool constantPool = builder.getCode().getConstantPool();
+        if (isResolvedDynamicInvokeMH == null) {
+            // If older JVMCI, but HotSpotInvokeDynamicPlugin is being
+            // used for testing, return true so that we continue along the
+            // plugin path.
+            return true;
+        }
+        return isResolvedDynamicInvoke(constantPool, index, opcode);
+    }
+
+    @Override
+    public boolean supportsDynamicInvoke(GraphBuilderContext builder, int index, int opcode) {
+        return opcode == Bytecodes.INVOKEDYNAMIC || isResolvedDynamicInvokeMH != null;
+    }
+
+    public DynamicTypeStore getDynamicTypeStore() {
+        return dynoStore;
+    }
+
+    @Override
+    public void recordDynamicMethod(GraphBuilderContext builder, int index, int opcode, ResolvedJavaMethod target) {
+        assert supportsDynamicInvoke(builder, index, opcode);
+        HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) builder.getMethod();
+        HotSpotResolvedObjectType methodHolder = method.getDeclaringClass();
+
+        HotSpotResolvedJavaMethod adapter = (HotSpotResolvedJavaMethod) target;
+        if (dynoStore != null) {
+            dynoStore.recordAdapter(opcode, methodHolder, index, adapter);
+        }
+    }
+
+    @Override
+    public ValueNode genAppendixNode(GraphBuilderContext builder, int index, int opcode, JavaConstant appendixConstant, FrameState frameState) {
+        JavaConstant appendix = appendixConstant;
+        assert supportsDynamicInvoke(builder, index, opcode);
+        HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) builder.getMethod();
+        HotSpotResolvedObjectType methodHolder = method.getDeclaringClass();
+
+        if (dynoStore != null) {
+            appendix = dynoStore.recordAppendix(opcode, methodHolder, index, appendix);
+        }
+
+        ConstantNode appendixNode = ConstantNode.forConstant(appendix, builder.getMetaAccess(), builder.getGraph());
+
+        Stamp appendixStamp = appendixNode.stamp();
+        Stamp resolveStamp = treatAppendixAsConstant ? appendixStamp : appendixStamp.unrestricted();
+        ResolveDynamicConstantNode resolveNode = new ResolveDynamicConstantNode(resolveStamp, appendixNode);
+        ResolveDynamicConstantNode added = builder.append(resolveNode);
+        assert added == resolveNode;
+        added.setStateBefore(frameState);
+        return resolveNode;
+    }
+
+    public interface DynamicTypeStore {
+
+        void recordAdapter(int opcode, HotSpotResolvedObjectType holder, int cpi, HotSpotResolvedJavaMethod adapter);
+
+        JavaConstant recordAppendix(int opcode, HotSpotResolvedObjectType holder, int cpi, JavaConstant appendix);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java	Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,68 @@
+/*
+ * 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.nodes.aot;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16;
+
+import org.graalvm.word.LocationIdentity;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+@NodeInfo(cycles = CYCLES_4, size = SIZE_16)
+public class ResolveDynamicConstantNode extends DeoptimizingFixedWithNextNode implements Lowerable, MemoryCheckpoint.Single {
+    public static final NodeClass<ResolveDynamicConstantNode> TYPE = NodeClass.create(ResolveDynamicConstantNode.class);
+
+    @Input ValueNode value;
+
+    public ResolveDynamicConstantNode(Stamp valueStamp, ValueNode value) {
+        super(TYPE, valueStamp);
+        this.value = value;
+    }
+
+    public ValueNode value() {
+        return value;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java	Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,113 @@
+/*
+ * 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.nodes.aot;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16;
+
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.word.LocationIdentity;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A call to the VM via a regular stub.
+ */
+@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_16)
+public class ResolveDynamicStubCall extends AbstractMemoryCheckpoint implements LIRLowerable, Canonicalizable, DeoptimizingNode.DeoptBefore, MemoryCheckpoint.Single {
+    public static final NodeClass<ResolveDynamicStubCall> TYPE = NodeClass.create(ResolveDynamicStubCall.class);
+
+    @OptionalInput protected ValueNode value;
+    @OptionalInput(InputType.State) protected FrameState stateBefore;
+    protected Constant constant;
+
+    public ResolveDynamicStubCall(ValueNode value) {
+        super(TYPE, value.stamp());
+        this.value = value;
+    }
+
+    @NodeIntrinsic
+    public static native Object resolveInvoke(Object value);
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (value != null) {
+            constant = GraphUtil.foldIfConstantAndRemove(this, value);
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        assert constant != null : "Expected the value to fold: " + value;
+        Value result;
+        LIRFrameState fs = gen.state(this);
+        assert fs != null : "The stateAfter is null";
+        result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitResolveDynamicInvoke(constant, fs);
+        gen.setResult(this, result);
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    @Override
+    public FrameState stateBefore() {
+        return stateBefore;
+    }
+
+    @Override
+    public void setStateBefore(FrameState f) {
+        updateUsages(stateBefore, f);
+        stateBefore = f;
+    }
+
+    @Override
+    public void markDeleted() {
+        throw GraalError.shouldNotReachHere("ResolveDynamicStubCall node deleted");
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java	Wed Oct 11 17:11:28 2017 -0700
@@ -42,6 +42,7 @@
 import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode;
 import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode;
 import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode;
 import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.AbstractMergeNode;
@@ -107,6 +108,7 @@
         // @formatter:off
         return n instanceof LoadConstantIndirectlyNode      ||
                n instanceof LoadConstantIndirectlyFixedNode ||
+               n instanceof ResolveDynamicConstantNode      ||
                n instanceof ResolveConstantNode             ||
                n instanceof InitializeKlassNode;
         // @formatter:on
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java	Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -36,7 +36,9 @@
 import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassStubCall;
 import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode;
 import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersIndirectlyNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicStubCall;
 import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode;
 import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall;
 import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode;
 import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersStubCall;
@@ -73,6 +75,15 @@
     }
 
     @Snippet
+    public static Object resolveDynamicConstant(Object constant) {
+        Object result = LoadConstantIndirectlyNode.loadObject(constant);
+        if (probability(VERY_SLOW_PATH_PROBABILITY, result == null)) {
+            result = ResolveDynamicStubCall.resolveInvoke(constant);
+        }
+        return result;
+    }
+
+    @Snippet
     public static KlassPointer resolveKlassConstant(KlassPointer constant) {
         KlassPointer result = LoadConstantIndirectlyNode.loadKlass(constant);
         if (probability(VERY_SLOW_PATH_PROBABILITY, result.isNull())) {
@@ -110,6 +121,7 @@
 
     public static class Templates extends AbstractTemplates {
         private final SnippetInfo resolveObjectConstant = snippet(ResolveConstantSnippets.class, "resolveObjectConstant");
+        private final SnippetInfo resolveDynamicConstant = snippet(ResolveConstantSnippets.class, "resolveDynamicConstant");
         private final SnippetInfo resolveKlassConstant = snippet(ResolveConstantSnippets.class, "resolveKlassConstant");
         private final SnippetInfo resolveMethodAndLoadCounters = snippet(ResolveConstantSnippets.class, "resolveMethodAndLoadCounters");
         private final SnippetInfo initializeKlass = snippet(ResolveConstantSnippets.class, "initializeKlass");
@@ -119,6 +131,25 @@
             super(options, factories, providers, providers.getSnippetReflection(), target);
         }
 
+        public void lower(ResolveDynamicConstantNode resolveConstantNode, LoweringTool tool) {
+            StructuredGraph graph = resolveConstantNode.graph();
+
+            ValueNode value = resolveConstantNode.value();
+            assert value.isConstant() : "Expected a constant: " + value;
+            SnippetInfo snippet = resolveDynamicConstant;
+
+            Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
+            args.add("constant", value);
+
+            SnippetTemplate template = template(graph.getDebug(), args);
+            template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args);
+
+            assert resolveConstantNode.hasNoUsages();
+            if (!resolveConstantNode.isDeleted()) {
+                GraphUtil.killWithUnusedFloatingInputs(resolveConstantNode);
+            }
+        }
+
         public void lower(ResolveConstantNode resolveConstantNode, LoweringTool tool) {
             StructuredGraph graph = resolveConstantNode.graph();
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -374,6 +374,7 @@
 import org.graalvm.compiler.nodes.extended.StateSplitProxyNode;
 import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.ClassInitializationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvokeDynamicPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
@@ -933,8 +934,13 @@
      * @param type the unresolved type of the constant
      */
     protected void handleUnresolvedLoadConstant(JavaType type) {
-        assert !graphBuilderConfig.eagerResolving();
-        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        assert !graphBuilderConfig.unresolvedIsError();
+        DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        /*
+         * Track source position for deopt nodes even if
+         * GraphBuilderConfiguration.trackNodeSourcePosition is not set.
+         */
+        deopt.updateNodeSourcePosition(() -> createBytecodePosition());
     }
 
     /**
@@ -942,7 +948,7 @@
      * @param object the object value whose type is being checked against {@code type}
      */
     protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) {
-        assert !graphBuilderConfig.eagerResolving();
+        assert !graphBuilderConfig.unresolvedIsError();
         append(new FixedGuardNode(graph.addOrUniqueWithInputs(IsNullNode.create(object)), Unresolved, InvalidateRecompile));
         frameState.push(JavaKind.Object, appendConstant(JavaConstant.NULL_POINTER));
     }
@@ -952,9 +958,10 @@
      * @param object the object value whose type is being checked against {@code type}
      */
     protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) {
-        assert !graphBuilderConfig.eagerResolving();
+        assert !graphBuilderConfig.unresolvedIsError();
         AbstractBeginNode successor = graph.add(new BeginNode());
         DeoptimizeNode deopt = graph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        deopt.updateNodeSourcePosition(() -> createBytecodePosition());
         append(new IfNode(graph.addOrUniqueWithInputs(IsNullNode.create(object)), successor, deopt, 1));
         lastInstr = successor;
         frameState.push(JavaKind.Int, appendConstant(JavaConstant.INT_0));
@@ -964,8 +971,9 @@
      * @param type the type being instantiated
      */
     protected void handleUnresolvedNewInstance(JavaType type) {
-        assert !graphBuilderConfig.eagerResolving();
-        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        assert !graphBuilderConfig.unresolvedIsError();
+        DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        deopt.updateNodeSourcePosition(() -> createBytecodePosition());
     }
 
     /**
@@ -973,8 +981,9 @@
      * @param length the length of the array
      */
     protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) {
-        assert !graphBuilderConfig.eagerResolving();
-        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        assert !graphBuilderConfig.unresolvedIsError();
+        DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        deopt.updateNodeSourcePosition(() -> createBytecodePosition());
     }
 
     /**
@@ -982,8 +991,9 @@
      * @param dims the dimensions for the multi-array
      */
     protected void handleUnresolvedNewMultiArray(JavaType type, ValueNode[] dims) {
-        assert !graphBuilderConfig.eagerResolving();
-        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        assert !graphBuilderConfig.unresolvedIsError();
+        DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        deopt.updateNodeSourcePosition(() -> createBytecodePosition());
     }
 
     /**
@@ -991,8 +1001,9 @@
      * @param receiver the object containing the field or {@code null} if {@code field} is static
      */
     protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) {
-        assert !graphBuilderConfig.eagerResolving();
-        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        assert !graphBuilderConfig.unresolvedIsError();
+        DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        deopt.updateNodeSourcePosition(() -> createBytecodePosition());
     }
 
     /**
@@ -1001,16 +1012,18 @@
      * @param receiver the object containing the field or {@code null} if {@code field} is static
      */
     protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) {
-        assert !graphBuilderConfig.eagerResolving();
-        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        assert !graphBuilderConfig.unresolvedIsError();
+        DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        deopt.updateNodeSourcePosition(() -> createBytecodePosition());
     }
 
     /**
      * @param type
      */
     protected void handleUnresolvedExceptionType(JavaType type) {
-        assert !graphBuilderConfig.eagerResolving();
-        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        assert !graphBuilderConfig.unresolvedIsError();
+        DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        deopt.updateNodeSourcePosition(() -> createBytecodePosition());
     }
 
     /**
@@ -1018,8 +1031,9 @@
      * @param invokeKind
      */
     protected void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind) {
-        assert !graphBuilderConfig.eagerResolving();
-        append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        assert !graphBuilderConfig.unresolvedIsError();
+        DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+        deopt.updateNodeSourcePosition(() -> createBytecodePosition());
     }
 
     private AbstractBeginNode handleException(ValueNode exceptionObject, int bci) {
@@ -1307,7 +1321,12 @@
         return false;
     }
 
-    protected void genInvokeStatic(JavaMethod target) {
+    protected void genInvokeStatic(int cpi, int opcode) {
+        JavaMethod target = lookupMethod(cpi, opcode);
+        genInvokeStatic(target);
+    }
+
+    void genInvokeStatic(JavaMethod target) {
         if (callTargetIsResolved(target)) {
             ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target;
             ResolvedJavaType holder = resolvedTarget.getDeclaringClass();
@@ -1332,6 +1351,11 @@
         }
     }
 
+    protected void genInvokeInterface(int cpi, int opcode) {
+        JavaMethod target = lookupMethod(cpi, opcode);
+        genInvokeInterface(target);
+    }
+
     protected void genInvokeInterface(JavaMethod target) {
         if (callTargetIsResolved(target)) {
             ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true));
@@ -1341,44 +1365,108 @@
         }
     }
 
-    protected void genInvokeDynamic(JavaMethod target) {
-        if (target instanceof ResolvedJavaMethod) {
-            JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI4(), Bytecodes.INVOKEDYNAMIC);
-            if (appendix != null) {
-                frameState.push(JavaKind.Object, ConstantNode.forConstant(appendix, metaAccess, graph));
-            }
-            ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(false));
-            appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args);
-        } else {
+    protected void genInvokeDynamic(int cpi, int opcode) {
+        JavaMethod target = lookupMethod(cpi, opcode);
+        genInvokeDynamic(target);
+    }
+
+    void genInvokeDynamic(JavaMethod target) {
+        if (!(target instanceof ResolvedJavaMethod) || !genDynamicInvokeHelper((ResolvedJavaMethod) target, stream.readCPI4(), INVOKEDYNAMIC)) {
             handleUnresolvedInvoke(target, InvokeKind.Static);
         }
     }
 
-    protected void genInvokeVirtual(JavaMethod target) {
-        if (callTargetIsResolved(target)) {
-            /*
-             * Special handling for runtimes that rewrite an invocation of MethodHandle.invoke(...)
-             * or MethodHandle.invokeExact(...) to a static adapter. HotSpot does this - see
-             * https://wikis.oracle.com/display/HotSpotInternals/Method+handles +and+invokedynamic
-             */
-            boolean hasReceiver = !((ResolvedJavaMethod) target).isStatic();
-            JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI(), Bytecodes.INVOKEVIRTUAL);
-            if (appendix != null) {
-                frameState.push(JavaKind.Object, ConstantNode.forConstant(appendix, metaAccess, graph));
+    protected void genInvokeVirtual(int cpi, int opcode) {
+        JavaMethod target = lookupMethod(cpi, opcode);
+        genInvokeVirtual(target);
+    }
+
+    private boolean genDynamicInvokeHelper(ResolvedJavaMethod target, int cpi, int opcode) {
+        assert opcode == INVOKEDYNAMIC || opcode == INVOKEVIRTUAL;
+
+        InvokeDynamicPlugin invokeDynamicPlugin = graphBuilderConfig.getPlugins().getInvokeDynamicPlugin();
+
+        if (opcode == INVOKEVIRTUAL && invokeDynamicPlugin != null && !invokeDynamicPlugin.isResolvedDynamicInvoke(this, cpi, opcode)) {
+            // regular invokevirtual, let caller handle it
+            return false;
+        }
+
+        if (GeneratePIC.getValue(options) && (invokeDynamicPlugin == null || !invokeDynamicPlugin.supportsDynamicInvoke(this, cpi, opcode))) {
+            // bail out if static compiler and no dynamic type support
+            append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+            return true;
+        }
+
+        JavaConstant appendix = constantPool.lookupAppendix(cpi, opcode);
+        ValueNode appendixNode = null;
+
+        if (appendix != null) {
+            if (invokeDynamicPlugin != null) {
+                invokeDynamicPlugin.recordDynamicMethod(this, cpi, opcode, target);
+
+                // Will perform runtime type checks and static initialization
+                FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
+                appendixNode = invokeDynamicPlugin.genAppendixNode(this, cpi, opcode, appendix, stateBefore);
+            } else {
+                appendixNode = ConstantNode.forConstant(appendix, metaAccess, graph);
             }
-            ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver));
-            if (hasReceiver) {
-                appendInvoke(InvokeKind.Virtual, (ResolvedJavaMethod) target, args);
-            } else {
-                appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args);
-            }
+
+            frameState.push(JavaKind.Object, appendixNode);
+
+        } else if (GeneratePIC.getValue(options)) {
+            // Need to emit runtime guard and perform static initialization.
+            // Not implemented yet.
+            append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
+            return true;
+        }
+
+        boolean hasReceiver = (opcode == INVOKEDYNAMIC) ? false : !target.isStatic();
+        ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver));
+        if (hasReceiver) {
+            appendInvoke(InvokeKind.Virtual, target, args);
         } else {
+            appendInvoke(InvokeKind.Static, target, args);
+        }
+
+        return true;
+    }
+
+    void genInvokeVirtual(JavaMethod target) {
+        if (!genInvokeVirtualHelper(target)) {
             handleUnresolvedInvoke(target, InvokeKind.Virtual);
         }
-
-    }
-
-    protected void genInvokeSpecial(JavaMethod target) {
+    }
+
+    private boolean genInvokeVirtualHelper(JavaMethod target) {
+        if (!callTargetIsResolved(target)) {
+            return false;
+        }
+
+        ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target;
+        int cpi = stream.readCPI();
+
+        /*
+         * Special handling for runtimes that rewrite an invocation of MethodHandle.invoke(...) or
+         * MethodHandle.invokeExact(...) to a static adapter. HotSpot does this - see
+         * https://wiki.openjdk.java.net/display/HotSpot/Method+handles+and+invokedynamic
+         */
+
+        if (genDynamicInvokeHelper(resolvedTarget, cpi, INVOKEVIRTUAL)) {
+            return true;
+        }
+
+        ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true));
+        appendInvoke(InvokeKind.Virtual, (ResolvedJavaMethod) target, args);
+
+        return true;
+    }
+
+    protected void genInvokeSpecial(int cpi, int opcode) {
+        JavaMethod target = lookupMethod(cpi, opcode);
+        genInvokeSpecial(target);
+    }
+
+    void genInvokeSpecial(JavaMethod target) {
         if (callTargetIsResolved(target)) {
             assert target != null;
             assert target.getSignature() != null;
@@ -2149,9 +2237,9 @@
         TTY.println(s);
     }
 
-    protected BytecodeParserError asParserError(Throwable e) {
+    protected RuntimeException throwParserError(Throwable e) {
         if (e instanceof BytecodeParserError) {
-            return (BytecodeParserError) e;
+            throw (BytecodeParserError) e;
         }
         BytecodeParser bp = this;
         BytecodeParserError res = new BytecodeParserError(e);
@@ -2159,7 +2247,7 @@
             res.addContext("parsing " + bp.code.asStackTraceElement(bp.bci()));
             bp = bp.parent;
         }
-        return res;
+        throw res;
     }
 
     protected void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) {
@@ -2837,7 +2925,7 @@
                 // Don't wrap bailouts as parser errors
                 throw e;
             } catch (Throwable e) {
-                throw asParserError(e);
+                throw throwParserError(e);
             }
 
             if (lastInstr == null || lastInstr.next() != null) {
@@ -3257,7 +3345,7 @@
         int nextBC = stream.readUByte(nextBCI);
         if (nextBCI <= currentBlock.endBci && nextBC == Bytecodes.GETFIELD) {
             stream.next();
-            genGetField(lookupField(stream.readCPI(), Bytecodes.GETFIELD), value);
+            genGetField(stream.readCPI(), Bytecodes.GETFIELD, value);
         } else {
             frameState.push(JavaKind.Object, value);
         }
@@ -3506,15 +3594,18 @@
         return result;
     }
 
-    private JavaField lookupField(int cpi, int opcode) {
+    protected JavaField lookupField(int cpi, int opcode) {
         maybeEagerlyResolve(cpi, opcode);
         JavaField result = constantPool.lookupField(cpi, method, opcode);
+
         if (graphBuilderConfig.eagerResolving()) {
-            assert result instanceof ResolvedJavaField : "Not resolved: " + result;
-            ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass();
-            if (!declaringClass.isInitialized()) {
-                assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass;
-                declaringClass.initialize();
+            assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaField : "Not resolved: " + result;
+            if (result instanceof ResolvedJavaField) {
+                ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass();
+                if (!declaringClass.isInitialized()) {
+                    assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass;
+                    declaringClass.initialize();
+                }
             }
         }
         assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result;
@@ -3524,11 +3615,11 @@
     private Object lookupConstant(int cpi, int opcode) {
         maybeEagerlyResolve(cpi, opcode);
         Object result = constantPool.lookupConstant(cpi);
-        assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result;
+        assert !graphBuilderConfig.unresolvedIsError() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result;
         return result;
     }
 
-    private void maybeEagerlyResolve(int cpi, int bytecode) {
+    protected void maybeEagerlyResolve(int cpi, int bytecode) {
         if (intrinsicContext != null) {
             constantPool.loadReferencedType(cpi, bytecode);
         } else if (graphBuilderConfig.eagerResolving()) {
@@ -3653,9 +3744,12 @@
         }
     }
 
-    void genNewInstance(int cpi) {
+    protected void genNewInstance(int cpi) {
         JavaType type = lookupType(cpi, NEW);
-
+        genNewInstance(type);
+    }
+
+    void genNewInstance(JavaType type) {
         if (!(type instanceof ResolvedJavaType) || !((ResolvedJavaType) type).isInitialized()) {
             handleUnresolvedNewInstance(type);
             return;
@@ -3790,8 +3884,13 @@
         frameState.push(JavaKind.Object, append(createNewMultiArray(resolvedType, dims)));
     }
 
-    private void genGetField(JavaField field) {
-        genGetField(field, frameState.pop(JavaKind.Object));
+    protected void genGetField(int cpi, int opcode) {
+        genGetField(cpi, opcode, frameState.pop(JavaKind.Object));
+    }
+
+    protected void genGetField(int cpi, int opcode, ValueNode receiverInput) {
+        JavaField field = lookupField(cpi, opcode);
+        genGetField(field, receiverInput);
     }
 
     private void genGetField(JavaField field, ValueNode receiverInput) {
@@ -3867,7 +3966,12 @@
         return false;
     }
 
-    private void genPutField(JavaField field) {
+    protected void genPutField(int cpi, int opcode) {
+        JavaField field = lookupField(cpi, opcode);
+        genPutField(field);
+    }
+
+    protected void genPutField(JavaField field) {
         genPutField(field, frameState.pop(field.getJavaKind()));
     }
 
@@ -3895,6 +3999,11 @@
         }
     }
 
+    protected void genGetStatic(int cpi, int opcode) {
+        JavaField field = lookupField(cpi, opcode);
+        genGetStatic(field);
+    }
+
     private void genGetStatic(JavaField field) {
         ResolvedJavaField resolvedField = resolveStaticFieldAccess(field, null);
         if (resolvedField == null) {
@@ -3956,7 +4065,12 @@
         return null;
     }
 
-    private void genPutStatic(JavaField field) {
+    protected void genPutStatic(int cpi, int opcode) {
+        JavaField field = lookupField(cpi, opcode);
+        genPutStatic(field);
+    }
+
+    protected void genPutStatic(JavaField field) {
         ValueNode value = frameState.pop(field.getJavaKind());
         ResolvedJavaField resolvedField = resolveStaticFieldAccess(field, value);
         if (resolvedField == null) {
@@ -4320,15 +4434,15 @@
             case DRETURN        : genReturn(frameState.pop(JavaKind.Double), JavaKind.Double); break;
             case ARETURN        : genReturn(frameState.pop(JavaKind.Object), JavaKind.Object); break;
             case RETURN         : genReturn(null, JavaKind.Void); break;
-            case GETSTATIC      : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break;
-            case PUTSTATIC      : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break;
-            case GETFIELD       : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break;
-            case PUTFIELD       : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break;
-            case INVOKEVIRTUAL  : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break;
-            case INVOKESPECIAL  : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break;
-            case INVOKESTATIC   : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break;
-            case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break;
-            case INVOKEDYNAMIC  : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break;
+            case GETSTATIC      : cpi = stream.readCPI(); genGetStatic(cpi, opcode); break;
+            case PUTSTATIC      : cpi = stream.readCPI(); genPutStatic(cpi, opcode); break;
+            case GETFIELD       : cpi = stream.readCPI(); genGetField(cpi, opcode); break;
+            case PUTFIELD       : cpi = stream.readCPI(); genPutField(cpi, opcode); break;
+            case INVOKEVIRTUAL  : cpi = stream.readCPI(); genInvokeVirtual(cpi, opcode); break;
+            case INVOKESPECIAL  : cpi = stream.readCPI(); genInvokeSpecial(cpi, opcode); break;
+            case INVOKESTATIC   : cpi = stream.readCPI(); genInvokeStatic(cpi, opcode); break;
+            case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(cpi, opcode); break;
+            case INVOKEDYNAMIC  : cpi = stream.readCPI4(); genInvokeDynamic(cpi, opcode); break;
             case NEW            : genNewInstance(stream.readCPI()); break;
             case NEWARRAY       : genNewPrimitiveArray(stream.readLocalIndex()); break;
             case ANEWARRAY      : genNewObjectArray(stream.readCPI()); break;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_irem4.java	Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,69 @@
+/*
+ * 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.jtt.bytecode;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+public class BC_irem4 extends JTTTest {
+
+    public static int test(int a) {
+        return a % 8;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", -2);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        runTest("test", -8);
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        runTest("test", 16);
+    }
+
+    @Test
+    public void run4() throws Throwable {
+        runTest("test", -16);
+    }
+
+    @Test
+    public void run5() throws Throwable {
+        runTest("test", -23);
+    }
+
+    @Test
+    public void run6() throws Throwable {
+        runTest("test", 23);
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPrefetchOp.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCPrefetchOp.java	Wed Oct 11 17:11:28 2017 -0700
@@ -34,18 +34,17 @@
     public static final LIRInstructionClass<SPARCPrefetchOp> TYPE = LIRInstructionClass.create(SPARCPrefetchOp.class);
     public static final SizeEstimate SIZE = SizeEstimate.create(1);
 
-    private final int instr;  // AllocatePrefetchInstr
+    private final SPARCAssembler.Fcn fcn;
     @Alive({COMPOSITE}) protected SPARCAddressValue address;
 
-    public SPARCPrefetchOp(SPARCAddressValue address, int instr) {
+    public SPARCPrefetchOp(SPARCAddressValue address, SPARCAssembler.Fcn fcn) {
         super(TYPE, SIZE);
         this.address = address;
-        this.instr = instr;
+        this.fcn = fcn;
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-        assert instr >= 0 && instr < SPARCAssembler.Fcn.values().length : instr;
-        masm.prefetch(address.toAddress(), SPARCAssembler.Fcn.values()[instr]);
+        masm.prefetch(address.toAddress(), fcn);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java	Wed Oct 11 17:11:28 2017 -0700
@@ -466,28 +466,6 @@
             AbstractMergeNode merge = (AbstractMergeNode) node;
             EndNode singleEnd = merge.forwardEndAt(0);
 
-            /*
-             * In some corner cases, the MergeNode already has PhiNodes. Since there is a single
-             * EndNode, each PhiNode can only have one input, and we can replace the PhiNode with
-             * this single input.
-             */
-            for (PhiNode phi : merge.phis()) {
-                assert phi.inputs().count() == 1 : "input count must match end count";
-                Node singlePhiInput = phi.inputs().first();
-
-                /*
-                 * We do not have the orderID of the PhiNode anymore, so we need to search through
-                 * the complete list of nodes to find a match.
-                 */
-                for (int i = 0; i < loopScope.createdNodes.length; i++) {
-                    if (loopScope.createdNodes[i] == phi) {
-                        loopScope.createdNodes[i] = singlePhiInput;
-                    }
-                }
-
-                phi.replaceAndDelete(singlePhiInput);
-            }
-
             /* Nodes that would use this merge as the guard need to use the previous block. */
             registerNode(loopScope, nodeOrderId, AbstractBeginNode.prevBegin(singleEnd), true, false);
 
@@ -973,8 +951,22 @@
             int phiNodeOrderId = readOrderId(methodScope);
 
             ValueNode phiInput = (ValueNode) ensureNodeCreated(methodScope, phiInputScope, phiInputOrderId);
+            ValueNode existing = (ValueNode) lookupNode(phiNodeScope, phiNodeOrderId);
 
-            ValueNode existing = (ValueNode) lookupNode(phiNodeScope, phiNodeOrderId);
+            if (existing != null && merge.phiPredecessorCount() == 1) {
+                /*
+                 * When exploding loops and the code after the loop (FULL_EXPLODE_UNTIL_RETURN),
+                 * then an existing value can already be registered: Parsing of the code before the
+                 * loop registers it when preparing for the later merge. The code after the loop,
+                 * which starts with a clone of the values that were created before the loop, sees
+                 * the stale value when processing the merge the first time. We can safely ignore
+                 * the stale value because it will never be needed to be merged (we are exploding
+                 * until we hit a return).
+                 */
+                assert methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN && phiNodeScope.loopIteration > 0;
+                existing = null;
+            }
+
             if (lazyPhi && (existing == null || existing == phiInput)) {
                 /* Phi function not yet necessary. */
                 registerNode(phiNodeScope, phiNodeOrderId, phiInput, true, false);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java	Wed Oct 11 17:11:28 2017 -0700
@@ -30,6 +30,8 @@
 import java.util.Iterator;
 import java.util.List;
 
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -52,7 +54,10 @@
 import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
 import org.graalvm.compiler.nodes.calc.IsNullNode;
 import org.graalvm.compiler.nodes.calc.NormalizeCompareNode;
+import org.graalvm.compiler.nodes.calc.ObjectEqualsNode;
+import org.graalvm.compiler.nodes.extended.UnboxNode;
 import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
 import org.graalvm.compiler.nodes.spi.LIRLowerable;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 import org.graalvm.compiler.nodes.util.GraphUtil;
@@ -256,6 +261,123 @@
                 }
             }
         }
+
+        if (tryEliminateBoxedReferenceEquals(tool)) {
+            return;
+        }
+    }
+
+    private boolean isUnboxedFrom(MetaAccessProvider meta, ValueNode x, ValueNode src) {
+        if (x == src) {
+            return true;
+        } else if (x instanceof UnboxNode) {
+            return isUnboxedFrom(meta, ((UnboxNode) x).getValue(), src);
+        } else if (x instanceof PiNode) {
+            PiNode pi = (PiNode) x;
+            return isUnboxedFrom(meta, pi.getOriginalNode(), src);
+        } else if (x instanceof LoadFieldNode) {
+            LoadFieldNode load = (LoadFieldNode) x;
+            ResolvedJavaType integerType = meta.lookupJavaType(Integer.class);
+            if (load.getValue().stamp().javaType(meta).equals(integerType)) {
+                return isUnboxedFrom(meta, load.getValue(), src);
+            } else {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Attempts to replace the following pattern:
+     *
+     * <pre>
+     * Integer x = ...;
+     * Integer y = ...;
+     * if ((x == y) || x.equals(y)) { ... }
+     * </pre>
+     *
+     * with:
+     *
+     * <pre>
+     * Integer x = ...;
+     * Integer y = ...;
+     * if (x.equals(y)) { ... }
+     * </pre>
+     *
+     * whenever the probability that the reference check will pass is relatively small.
+     *
+     * See GR-1315 for more information.
+     */
+    private boolean tryEliminateBoxedReferenceEquals(SimplifierTool tool) {
+        if (!(condition instanceof ObjectEqualsNode)) {
+            return false;
+        }
+
+        MetaAccessProvider meta = tool.getMetaAccess();
+        ObjectEqualsNode equalsCondition = (ObjectEqualsNode) condition;
+        ValueNode x = equalsCondition.getX();
+        ValueNode y = equalsCondition.getY();
+        ResolvedJavaType integerType = meta.lookupJavaType(Integer.class);
+
+        // At least one argument for reference equal must be a boxed primitive.
+        if (!x.stamp().javaType(meta).equals(integerType) && !y.stamp().javaType(meta).equals(integerType)) {
+            return false;
+        }
+
+        // The reference equality check is usually more efficient compared to a boxing check.
+        // The success of the reference equals must therefore be relatively rare, otherwise it makes
+        // no sense to eliminate it.
+        if (getTrueSuccessorProbability() > 0.4) {
+            return false;
+        }
+
+        // True branch must be empty.
+        if (trueSuccessor instanceof BeginNode || trueSuccessor instanceof LoopExitNode) {
+            if (trueSuccessor.next() instanceof EndNode) {
+                // Empty true branch.
+            } else {
+                return false;
+            }
+        } else {
+            return false;
+        }
+
+        // False branch must only check the unboxed values.
+        UnboxNode unbox = null;
+        FixedGuardNode unboxCheck = null;
+        for (FixedNode node : falseSuccessor.getBlockNodes()) {
+            if (!(node instanceof BeginNode || node instanceof UnboxNode || node instanceof FixedGuardNode || node instanceof EndNode ||
+                            node instanceof LoadFieldNode || node instanceof LoopExitNode)) {
+                return false;
+            }
+            if (node instanceof UnboxNode) {
+                if (unbox == null) {
+                    unbox = (UnboxNode) node;
+                } else {
+                    return false;
+                }
+            }
+            if (!(node instanceof FixedGuardNode)) {
+                continue;
+            }
+            FixedGuardNode fixed = (FixedGuardNode) node;
+            if (!(fixed.condition() instanceof IntegerEqualsNode)) {
+                continue;
+            }
+            IntegerEqualsNode equals = (IntegerEqualsNode) fixed.condition();
+            if ((isUnboxedFrom(meta, equals.getX(), x) && isUnboxedFrom(meta, equals.getY(), y)) || (isUnboxedFrom(meta, equals.getX(), y) && isUnboxedFrom(meta, equals.getY(), x))) {
+                unboxCheck = fixed;
+            }
+        }
+        if (unbox == null || unboxCheck == null) {
+            return false;
+        }
+
+        // Falsify the reference check.
+        setCondition(graph().addOrUnique(LogicConstantNode.contradiction()));
+
+        return true;
     }
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java	Wed Oct 11 17:11:28 2017 -0700
@@ -60,6 +60,11 @@
      */
     public static final LocationIdentity ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("[].length");
 
+    /**
+     * Denotes an off-heap address.
+     */
+    public static final LocationIdentity OFF_HEAP_LOCATION = NamedLocationIdentity.mutable("OFF_HEAP_LOCATION");
+
     private final String name;
     private final boolean immutable;
 
@@ -81,7 +86,7 @@
 
     /**
      * Creates a named unique location identity for read operations against immutable memory.
-     * Immutable memory will never have a visible write in the graph, which is more restictive than
+     * Immutable memory will never have a visible write in the graph, which is more restrictive than
      * Java final.
      *
      * @param name the name of the new location identity
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java	Wed Oct 11 17:11:28 2017 -0700
@@ -60,12 +60,26 @@
                 return this; // this will trap, can not canonicalize
             }
             return ConstantNode.forIntegerStamp(stamp(), forX.asJavaConstant().asLong() % y);
-        } else if (forY.isConstant()) {
-            long c = forY.asJavaConstant().asLong();
-            if (c == 1 || c == -1) {
+        } else if (forY.isConstant() && forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) {
+            long constY = forY.asJavaConstant().asLong();
+            IntegerStamp xStamp = (IntegerStamp) forX.stamp();
+            IntegerStamp yStamp = (IntegerStamp) forY.stamp();
+            if (constY < 0 && constY != CodeUtil.minValue(yStamp.getBits())) {
+                return new SignedRemNode(forX, ConstantNode.forIntegerStamp(yStamp, -constY)).canonical(tool);
+            }
+
+            if (constY == 1) {
                 return ConstantNode.forIntegerStamp(stamp(), 0);
-            } else if (c > 0 && CodeUtil.isPowerOf2(c) && forX.stamp() instanceof IntegerStamp && ((IntegerStamp) forX.stamp()).isPositive()) {
-                return new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), c - 1));
+            } else if (CodeUtil.isPowerOf2(constY)) {
+                if (xStamp.isPositive()) {
+                    return new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), constY - 1));
+                } else if (xStamp.isNegative()) {
+                    return new NegateNode(new AndNode(new NegateNode(forX), ConstantNode.forIntegerStamp(stamp(), constY - 1)));
+                } else {
+                    return new ConditionalNode(IntegerLessThanNode.create(forX, ConstantNode.forIntegerStamp(forX.stamp(), 0)),
+                                    new NegateNode(new AndNode(new NegateNode(forX), ConstantNode.forIntegerStamp(stamp(), constY - 1))),
+                                    new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), constY - 1)));
+                }
             }
         }
         return this;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java	Wed Oct 11 17:11:28 2017 -0700
@@ -30,7 +30,10 @@
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.ReinterpretNode;
 import org.graalvm.compiler.nodes.java.LoadFieldNode;
@@ -38,19 +41,23 @@
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.nodes.spi.Virtualizable;
 import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.type.StampTool;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
 import org.graalvm.word.LocationIdentity;
 
 import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaType;
 
 /**
  * Load of a value from a location specified as an offset relative to an object. No null check is
  * performed before the load.
  */
 @NodeInfo(cycles = CYCLES_2, size = SIZE_1)
-public class RawLoadNode extends UnsafeAccessNode implements Lowerable, Virtualizable {
+public class RawLoadNode extends UnsafeAccessNode implements Lowerable, Virtualizable, Canonicalizable {
     public static final NodeClass<RawLoadNode> TYPE = NodeClass.create(RawLoadNode.class);
 
     /**
@@ -123,6 +130,32 @@
     }
 
     @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (!isAnyLocationForced() && getLocationIdentity().isAny()) {
+            ValueNode targetObject = object();
+            if (offset().isConstant() && targetObject.isConstant() && !targetObject.isNullConstant()) {
+                ConstantNode objectConstant = (ConstantNode) targetObject;
+                ResolvedJavaType type = StampTool.typeOrNull(objectConstant);
+                if (type != null && type.isArray()) {
+                    JavaConstant arrayConstant = objectConstant.asJavaConstant();
+                    if (arrayConstant != null) {
+                        int stableDimension = objectConstant.getStableDimension();
+                        if (stableDimension > 0) {
+                            long constantOffset = offset().asJavaConstant().asLong();
+                            Constant constant = stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), arrayConstant, constantOffset);
+                            boolean isDefaultStable = objectConstant.isDefaultStable();
+                            if (constant != null && (isDefaultStable || !constant.isDefaultForKind())) {
+                                return ConstantNode.forConstant(stamp(), constant, stableDimension - 1, isDefaultStable, tool.getMetaAccess());
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return super.canonical(tool);
+    }
+
+    @Override
     protected ValueNode cloneAsFieldAccess(Assumptions assumptions, ResolvedJavaField field) {
         return LoadFieldNode.create(assumptions, object(), field);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java	Wed Oct 11 17:11:28 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -39,6 +39,7 @@
         private InlineInvokePlugin[] inlineInvokePlugins;
         private LoopExplosionPlugin loopExplosionPlugin;
         private ClassInitializationPlugin classInitializationPlugin;
+        private InvokeDynamicPlugin invokeDynamicPlugin;
         private ProfilingPlugin profilingPlugin;
 
         /**
@@ -54,6 +55,7 @@
             this.inlineInvokePlugins = copyFrom.inlineInvokePlugins;
             this.loopExplosionPlugin = copyFrom.loopExplosionPlugin;
             this.classInitializationPlugin = copyFrom.classInitializationPlugin;
+            this.invokeDynamicPlugin = copyFrom.invokeDynamicPlugin;
             this.profilingPlugin = copyFrom.profilingPlugin;
         }
 
@@ -167,6 +169,14 @@
             this.classInitializationPlugin = plugin;
         }
 
+        public InvokeDynamicPlugin getInvokeDynamicPlugin() {
+            return invokeDynamicPlugin;
+        }
+
+        public void setInvokeDynamicPlugin(InvokeDynamicPlugin plugin) {
+            this.invokeDynamicPlugin = plugin;
+        }
+
         public ProfilingPlugin getProfilingPlugin() {
             return profilingPlugin;
         }
@@ -189,6 +199,7 @@
     private static final ResolvedJavaType[] EMPTY = new ResolvedJavaType[]{};
 
     private final boolean eagerResolving;
+    private final boolean unresolvedIsError;
     private final BytecodeExceptionMode bytecodeExceptionMode;
     private final boolean omitAssertions;
     private final ResolvedJavaType[] skippedExceptionTypes;
@@ -216,10 +227,11 @@
         Profile
     }
 
-    protected GraphBuilderConfiguration(boolean eagerResolving, BytecodeExceptionMode bytecodeExceptionMode, boolean omitAssertions, boolean insertFullInfopoints,
+    protected GraphBuilderConfiguration(boolean eagerResolving, boolean unresolvedIsError, BytecodeExceptionMode bytecodeExceptionMode, boolean omitAssertions, boolean insertFullInfopoints,
                     boolean trackNodeSourcePosition, ResolvedJavaType[] skippedExceptionTypes,
                     Plugins plugins) {
         this.eagerResolving = eagerResolving;
+        this.unresolvedIsError = unresolvedIsError;
         this.bytecodeExceptionMode = bytecodeExceptionMode;
         this.omitAssertions = omitAssertions;
         this.insertFullInfopoints = insertFullInfopoints;
@@ -235,35 +247,52 @@
      */
     public GraphBuilderConfiguration copy() {
         Plugins newPlugins = new Plugins(plugins);
-        GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes,
-                        newPlugins);
+        GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition,
+                        skippedExceptionTypes, newPlugins);
         return result;
     }
 
+    /**
+     * Set the {@link #unresolvedIsError} flag. This flag can be set independently from
+     * {@link #eagerResolving}, i.e., even if eager resolving fails execution is assumed to be
+     * valid. This allows us for example to process unresolved types/methods/fields even when
+     * eagerly resolving elements.
+     */
+    public GraphBuilderConfiguration withUnresolvedIsError(boolean newUnresolvedIsError) {
+        return new GraphBuilderConfiguration(eagerResolving, newUnresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes,
+                        plugins);
+    }
+
     public GraphBuilderConfiguration withEagerResolving(boolean newEagerResolving) {
-        return new GraphBuilderConfiguration(newEagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, plugins);
+        return new GraphBuilderConfiguration(newEagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes,
+                        plugins);
     }
 
     public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
-        return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes, plugins);
+        return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes,
+                        plugins);
     }
 
     public GraphBuilderConfiguration withBytecodeExceptionMode(BytecodeExceptionMode newBytecodeExceptionMode) {
-        return new GraphBuilderConfiguration(eagerResolving, newBytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, plugins);
+        return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, newBytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes,
+                        plugins);
     }
 
     public GraphBuilderConfiguration withOmitAssertions(boolean newOmitAssertions) {
-        return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, newOmitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, plugins);
+        return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, newOmitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes,
+                        plugins);
     }
 
     public GraphBuilderConfiguration withFullInfopoints(boolean newInsertFullInfopoints) {
         ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length);
-        return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, newInsertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes, plugins);
+        return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, newInsertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes,
+                        plugins);
     }
 
     public GraphBuilderConfiguration withNodeSourcePosition(boolean newTrackNodeSourcePosition) {
         ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length);
-        return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, newTrackNodeSourcePosition, newSkippedExceptionTypes, plugins);
+        return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, newTrackNodeSourcePosition, newSkippedExceptionTypes,
+                        plugins);
     }
 
     public ResolvedJavaType[] getSkippedExceptionTypes() {
@@ -291,20 +320,16 @@
     }
 
     public static GraphBuilderConfiguration getDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(false, BytecodeExceptionMode.Profile, false, false, false, EMPTY, plugins);
+        return new GraphBuilderConfiguration(false, false, BytecodeExceptionMode.Profile, false, false, false, EMPTY, plugins);
     }
 
     public static GraphBuilderConfiguration getSnippetDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, BytecodeExceptionMode.OmitAll, false, false, false, EMPTY, plugins);
+        return new GraphBuilderConfiguration(true, true, BytecodeExceptionMode.OmitAll, false, false, false, EMPTY, plugins);
     }
 
-    /**
-     * Returns {@code true} if it is an error for a class/field/method resolution to fail. The
-     * default is the same result as returned by {@link #eagerResolving()}. However, it may be
-     * overridden to allow failure even when {@link #eagerResolving} is {@code true}.
-     */
+    /** Returns {@code true} if it is an error for a class/field/method resolution to fail. */
     public boolean unresolvedIsError() {
-        return eagerResolving;
+        return unresolvedIsError;
     }
 
     public Plugins getPlugins() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java	Wed Oct 11 17:11:28 2017 -0700
@@ -295,4 +295,20 @@
     default void notifyReplacedCall(ResolvedJavaMethod targetMethod, ConstantNode node) {
 
     }
+
+    /**
+     * Interface whose instances hold inlining information about the current context, in a wider
+     * sense. The wider sense in this case concerns graph building approaches that don't necessarily
+     * keep a chain of {@link GraphBuilderContext} instances normally available through
+     * {@linkplain #getParent()}. Examples of such approaches are partial evaluation and incremental
+     * inlining.
+     */
+    interface ExternalInliningContext {
+        int getInlinedDepth();
+    }
+
+    default ExternalInliningContext getExternalInliningContext() {
+        return null;
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvokeDynamicPlugin.java	Wed Oct 11 17:11:28 2017 -0700
@@ -0,0 +1,82 @@
+/*
+ * 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.nodes.graphbuilderconf;
+
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.JavaConstant;
+
+/**
+ * {@link GraphBuilderPlugin} interface for static compilation mode, allowing references to dynamic
+ * types.
+ */
+public interface InvokeDynamicPlugin extends GraphBuilderPlugin {
+
+    /**
+     * Checks for a resolved dynamic adapter method at the specified index, resulting from either a
+     * resolved invokedynamic or invokevirtual on a signature polymorphic MethodHandle method
+     * (HotSpot invokehandle).
+     *
+     * @param builder context for the invoke
+     * @param cpi the constant pool index
+     * @param opcode the opcode of the instruction for which the lookup is being performed
+     * @return {@code true} if a signature polymorphic method reference was found, otherwise
+     *         {@code false}
+     */
+    boolean isResolvedDynamicInvoke(GraphBuilderContext builder, int cpi, int opcode);
+
+    /**
+     * Checks if this plugin instance supports the specified dynamic invoke.
+     *
+     * @param builder context for the invoke
+     * @param cpi the constant pool index
+     * @param opcode the opcode of the invoke instruction
+     * @return {@code true} if this dynamic invoke is supported
+     */
+    boolean supportsDynamicInvoke(GraphBuilderContext builder, int cpi, int opcode);
+
+    /**
+     * Notifies this object of the value and context of the dynamic method target (e.g., A HotSpot
+     * adapter method) for a resolved dynamic invoke.
+     *
+     * @param builder context for the invoke
+     * @param cpi the constant pool index
+     * @param opcode the opcode of the instruction for which the lookup is being performed
+     * @param target dynamic target method to record
+     */
+    void recordDynamicMethod(GraphBuilderContext builder, int cpi, int opcode, ResolvedJavaMethod target);
+
+    /**
+     * Notifies this object of the value and context of the dynamic appendix object for a resolved
+     * dynamic invoke.
+     *
+     * @param builder context for the invoke
+     * @param cpi the constant pool index
+     * @param opcode the opcode of the instruction for which the lookup is being performed
+     * @return {@link ValueNode} for appendix constant
+     */
+    ValueNode genAppendixNode(GraphBuilderContext builder, int cpi, int opcode, JavaConstant appendix, FrameState frameState);
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java	Wed Oct 11 17:11:28 2017 -0700
@@ -137,8 +137,9 @@
         }
         long offset;
         if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && componentType.isPrimitive()) {
-            // On big endian, we do just get expect the type be right aligned in this memory slot
-            offset = constantOffset - (componentType.getJavaKind().getByteCount() - Math.min(componentType.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount()));
+            // On big endian, we expect the value to be correctly aligned in memory
+            int componentByteCount = componentType.getJavaKind().getByteCount();
+            offset = constantOffset - (componentByteCount - Math.min(componentByteCount, 4 + expectedEntryKind.getByteCount()));
         } else {
             offset = constantOffset;
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java	Wed Oct 11 17:11:28 2017 -0700
@@ -132,11 +132,11 @@
         StructuredGraph targetGraph = null;
         DebugContext debug = getDebugContext();
         try (DebugContext.Scope scope = debug.scope("GraphPETest", testMethod)) {
-            GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true);
+            GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true).withUnresolvedIsError(true);
             registerPlugins(graphBuilderConfig.getPlugins().getInvocationPlugins());
             targetGraph = new StructuredGraph.Builder(getInitialOptions(), debug, AllowAssumptions.YES).method(testMethod).build();
             CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getTarget().arch, targetGraph, getProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, AllowAssumptions.YES,
-                            null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null);
+                            null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null, null);
 
             decoder.decode(testMethod);
             debug.dump(DebugContext.BASIC_LEVEL, targetGraph, "Target Graph");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java	Wed Oct 11 17:11:28 2017 -0700
@@ -63,9 +63,9 @@
     public CachingPEGraphDecoder(Architecture architecture, StructuredGraph graph, Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
                     AllowAssumptions allowAssumptions, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins,
                     ParameterPlugin parameterPlugin,
-                    NodePlugin[] nodePlugins) {
+                    NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod) {
         super(architecture, graph, providers.getMetaAccess(), providers.getConstantReflection(), providers.getConstantFieldProvider(), providers.getStampProvider(), loopExplosionPlugin,
-                        invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins);
+                        invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins, callInlinedMethod);
 
         this.providers = providers;
         this.graphBuilderConfig = graphBuilderConfig;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java	Wed Oct 11 17:11:28 2017 -0700
@@ -238,11 +238,11 @@
 
         if (frameStateBuilder != null) {
             if (invoke.getStackKind() != JavaKind.Void) {
-                frameStateBuilder.push(returnType.getJavaKind(), invoke);
+                frameStateBuilder.push(invoke.getStackKind(), invoke);
             }
             invoke.setStateAfter(frameStateBuilder.create(bci, invoke));
             if (invoke.getStackKind() != JavaKind.Void) {
-                frameStateBuilder.pop(returnType.getJavaKind());
+                frameStateBuilder.pop(invoke.getStackKind());
             }
         }
         return invoke;
@@ -475,11 +475,11 @@
         invoke.setNext(noExceptionEdge);
         if (frameStateBuilder != null) {
             if (invoke.getStackKind() != JavaKind.Void) {
-                frameStateBuilder.push(returnType.getJavaKind(), invoke);
+                frameStateBuilder.push(invoke.getStackKind(), invoke);
             }
             invoke.setStateAfter(frameStateBuilder.create(invokeBci, invoke));
             if (invoke.getStackKind() != JavaKind.Void) {
-                frameStateBuilder.pop(returnType.getJavaKind());
+                frameStateBuilder.pop(invoke.getStackKind());
             }
         }
         lastFixedNode = null;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java	Wed Oct 11 17:11:28 2017 -0700
@@ -193,6 +193,24 @@
         protected final PEMethodScope methodScope;
         protected final Invoke invoke;
 
+        @Override
+        public ExternalInliningContext getExternalInliningContext() {
+            return new ExternalInliningContext() {
+                @Override
+                public int getInlinedDepth() {
+                    int count = 0;
+                    PEGraphDecoder.PEMethodScope scope = methodScope;
+                    while (scope != null) {
+                        if (scope.method.equals(callInlinedMethod)) {
+                            count++;
+                        }
+                        scope = scope.caller;
+                    }
+                    return count;
+                }
+            };
+        }
+
         public PENonAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke) {
             this.methodScope = methodScope;
             this.invoke = invoke;
@@ -420,11 +438,12 @@
     private final NodePlugin[] nodePlugins;
     private final EconomicMap<SpecialCallTargetCacheKey, Object> specialCallTargetCache;
     private final EconomicMap<ResolvedJavaMethod, Object> invocationPluginCache;
+    private final ResolvedJavaMethod callInlinedMethod;
 
     public PEGraphDecoder(Architecture architecture, StructuredGraph graph, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
                     StampProvider stampProvider, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins,
                     ParameterPlugin parameterPlugin,
-                    NodePlugin[] nodePlugins) {
+                    NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod) {
         super(architecture, graph, metaAccess, constantReflection, constantFieldProvider, stampProvider, true);
         this.loopExplosionPlugin = loopExplosionPlugin;
         this.invocationPlugins = invocationPlugins;
@@ -433,6 +452,7 @@
         this.nodePlugins = nodePlugins;
         this.specialCallTargetCache = EconomicMap.create(Equivalence.DEFAULT);
         this.invocationPluginCache = EconomicMap.create(Equivalence.DEFAULT);
+        this.callInlinedMethod = callInlinedMethod;
     }
 
     protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java	Wed Oct 11 17:11:28 2017 -0700
@@ -224,16 +224,12 @@
         }
 
         /**
-         * Times instantiations of all templates derived form this snippet.
-         *
-         * @see SnippetTemplate#instantiationTimer
+         * Times instantiations of all templates derived from this snippet.
          */
         private final TimerKey instantiationTimer;
 
         /**
          * Counts instantiations of all templates derived from this snippet.
-         *
-         * @see SnippetTemplate#instantiationCounter
          */
         private final CounterKey instantiationCounter;
 
@@ -706,8 +702,6 @@
 
         Object[] constantArgs = getConstantArgs(args);
         StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method, args.info.original, constantArgs);
-        instantiationTimer = DebugContext.timer("SnippetTemplateInstantiationTime[%#s]", args);
-        instantiationCounter = DebugContext.counter("SnippetTemplateInstantiationCount[%#s]", args);
 
         ResolvedJavaMethod method = snippetGraph.method();
         Signature signature = method.getSignature();
@@ -1078,20 +1072,6 @@
     private final ArrayList<Node> nodes;
 
     /**
-     * Times instantiations of this template.
-     *
-     * @see SnippetInfo#instantiationTimer
-     */
-    private final TimerKey instantiationTimer;
-
-    /**
-     * Counts instantiations of this template.
-     *
-     * @see SnippetInfo#instantiationCounter
-     */
-    private final CounterKey instantiationCounter;
-
-    /**
      * Gets the instantiation-time bindings to this template's parameters.
      *
      * @return the map that will be used to bind arguments to parameters when inlining this template
@@ -1406,9 +1386,8 @@
     public UnmodifiableEconomicMap<Node, Node> instantiate(MetaAccessProvider metaAccess, FixedNode replacee, UsageReplacer replacer, Arguments args, boolean killReplacee) {
         DebugContext debug = replacee.getDebug();
         assert assertSnippetKills(replacee);
-        try (DebugCloseable a = args.info.instantiationTimer.start(debug); DebugCloseable b = instantiationTimer.start(debug)) {
+        try (DebugCloseable a = args.info.instantiationTimer.start(debug)) {
             args.info.instantiationCounter.increment(debug);
-            instantiationCounter.increment(debug);
             // Inline the snippet nodes, replacing parameters with the given args in the process
             StartNode entryPointNode = snippet.start();
             FixedNode firstCFGNode = entryPointNode.next();
@@ -1561,7 +1540,6 @@
         assert assertSnippetKills(replacee);
         try (DebugCloseable a = args.info.instantiationTimer.start(debug)) {
             args.info.instantiationCounter.increment(debug);
-            instantiationCounter.increment(debug);
 
             // Inline the snippet nodes, replacing parameters with the given args in the process
             StartNode entryPointNode = snippet.start();
@@ -1614,7 +1592,6 @@
         assert assertSnippetKills(replacee);
         try (DebugCloseable a = args.info.instantiationTimer.start(debug)) {
             args.info.instantiationCounter.increment(debug);
-            instantiationCounter.increment(debug);
 
             // Inline the snippet nodes, replacing parameters with the given args in the process
             StartNode entryPointNode = snippet.start();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Wed Oct 11 17:11:28 2017 -0700
@@ -30,6 +30,7 @@
 import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE;
 import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
 import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE;
+import static org.graalvm.compiler.nodes.NamedLocationIdentity.OFF_HEAP_LOCATION;
 import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
 
 import java.lang.reflect.Array;
@@ -650,7 +651,7 @@
         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address) {
             // Emits a null-check for the otherwise unused receiver
             unsafe.get();
-            b.addPush(returnKind, new UnsafeMemoryLoadNode(address, returnKind, LocationIdentity.any()));
+            b.addPush(returnKind, new UnsafeMemoryLoadNode(address, returnKind, OFF_HEAP_LOCATION));
             b.getGraph().markUnsafeAccess();
             return true;
         }
@@ -662,7 +663,8 @@
             if (isVolatile) {
                 b.add(new MembarNode(JMM_PRE_VOLATILE_READ));
             }
-            b.addPush(returnKind, new RawLoadNode(object, offset, returnKind, LocationIdentity.any()));
+            LocationIdentity locationIdentity = object.isNullConstant() ? OFF_HEAP_LOCATION : LocationIdentity.any();
+            b.addPush(returnKind, new RawLoadNode(object, offset, returnKind, locationIdentity));
             if (isVolatile) {
                 b.add(new MembarNode(JMM_POST_VOLATILE_READ));
             }
@@ -685,7 +687,7 @@
         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address, ValueNode value) {
             // Emits a null-check for the otherwise unused receiver
             unsafe.get();
-            b.add(new UnsafeMemoryStoreNode(address, value, kind, LocationIdentity.any()));
+            b.add(new UnsafeMemoryStoreNode(address, value, kind, OFF_HEAP_LOCATION));
             b.getGraph().markUnsafeAccess();
             return true;
         }
@@ -697,7 +699,8 @@
             if (isVolatile) {
                 b.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
             }
-            b.add(new RawStoreNode(object, offset, value, kind, LocationIdentity.any()));
+            LocationIdentity locationIdentity = object.isNullConstant() ? OFF_HEAP_LOCATION : LocationIdentity.any();
+            b.add(new RawStoreNode(object, offset, value, kind, locationIdentity));
             if (isVolatile) {
                 b.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java	Wed Oct 11 17:11:28 2017 -0700
@@ -25,6 +25,8 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.nodes.FieldLocationIdentity;
 import org.graalvm.compiler.nodes.ValueNode;
@@ -49,11 +51,15 @@
         public final int index;
         public final JavaKind kind;
 
-        ReadCacheEntry(LocationIdentity identity, ValueNode object, int index, JavaKind kind) {
+        /* This flag does not affect hashCode or equals implementations. */
+        public final boolean overflowAccess;
+
+        ReadCacheEntry(LocationIdentity identity, ValueNode object, int index, JavaKind kind, boolean overflowAccess) {
             this.identity = identity;
             this.object = object;
             this.index = index;
             this.kind = kind;
+            this.overflowAccess = overflowAccess;
         }
 
         @Override
@@ -94,12 +100,38 @@
         return super.toString() + " " + readCache;
     }
 
+    private static JavaKind stampToJavaKind(Stamp stamp) {
+        if (stamp instanceof IntegerStamp) {
+            switch (((IntegerStamp) stamp).getBits()) {
+                case 1:
+                    return JavaKind.Boolean;
+                case 8:
+                    return JavaKind.Byte;
+                case 16:
+                    return ((IntegerStamp) stamp).isPositive() ? JavaKind.Char : JavaKind.Short;
+                case 32:
+                    return JavaKind.Int;
+                case 64:
+                    return JavaKind.Long;
+                default:
+                    throw new IllegalArgumentException("unexpected IntegerStamp " + stamp);
+            }
+        } else {
+            return stamp.getStackKind();
+        }
+    }
+
     @Override
     protected void objectMaterialized(VirtualObjectNode virtual, AllocatedObjectNode representation, List<ValueNode> values) {
         if (virtual instanceof VirtualInstanceNode) {
             VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
             for (int i = 0; i < instance.entryCount(); i++) {
-                readCache.put(new ReadCacheEntry(new FieldLocationIdentity(instance.field(i)), representation, -1, instance.field(i).getJavaKind()), values.get(i));
+                JavaKind declaredKind = instance.field(i).getJavaKind();
+                if (declaredKind == stampToJavaKind(values.get(i).stamp())) {
+                    // We won't cache unaligned field writes upon instantiation unless we add
+                    // support for non-array objects in PEReadEliminationClosure.processUnsafeLoad.
+                    readCache.put(new ReadCacheEntry(new FieldLocationIdentity(instance.field(i)), representation, -1, declaredKind, false), values.get(i));
+                }
             }
         }
     }
@@ -112,7 +144,7 @@
         return super.equivalentTo(other);
     }
 
-    public void addReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, ValueNode value, PartialEscapeClosure<?> closure) {
+    public void addReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, boolean overflowAccess, ValueNode value, PartialEscapeClosure<?> closure) {
         ValueNode cacheObject;
         ObjectState obj = closure.getObjectState(this, object);
         if (obj != null) {
@@ -121,7 +153,7 @@
         } else {
             cacheObject = object;
         }
-        readCache.put(new ReadCacheEntry(identity, cacheObject, index, kind), value);
+        readCache.put(new ReadCacheEntry(identity, cacheObject, index, kind, overflowAccess), value);
     }
 
     public ValueNode getReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, PartialEscapeClosure<?> closure) {
@@ -133,7 +165,7 @@
         } else {
             cacheObject = object;
         }
-        ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject, index, kind));
+        ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject, index, kind, false));
         obj = closure.getObjectState(this, cacheValue);
         if (obj != null) {
             assert !obj.isVirtual();
@@ -153,7 +185,7 @@
         Iterator<ReadCacheEntry> iter = readCache.getKeys().iterator();
         while (iter.hasNext()) {
             ReadCacheEntry entry = iter.next();
-            if (entry.identity.equals(identity) && (index == -1 || entry.index == -1 || index == entry.index)) {
+            if (entry.identity.equals(identity) && (index == -1 || entry.index == -1 || index == entry.index || entry.overflowAccess)) {
                 iter.remove();
             }
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java	Wed Oct 11 17:11:28 2017 -0700
@@ -31,7 +31,6 @@
 
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
-import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.FieldLocationIdentity;
@@ -131,9 +130,10 @@
         return false;
     }
 
-    private boolean processStore(FixedNode store, ValueNode object, LocationIdentity identity, int index, JavaKind kind, ValueNode value, PEReadEliminationBlockState state, GraphEffectList effects) {
+    private boolean processStore(FixedNode store, ValueNode object, LocationIdentity identity, int index, JavaKind accessKind, boolean overflowAccess, ValueNode value,
+                    PEReadEliminationBlockState state, GraphEffectList effects) {
         ValueNode unproxiedObject = GraphUtil.unproxify(object);
-        ValueNode cachedValue = state.getReadCache(object, identity, index, kind, this);
+        ValueNode cachedValue = state.getReadCache(object, identity, index, accessKind, this);
 
         ValueNode finalValue = getScalarAlias(value);
         boolean result = false;
@@ -142,7 +142,7 @@
             result = true;
         }
         state.killReadCache(identity, index);
-        state.addReadCache(unproxiedObject, identity, index, kind, finalValue, this);
+        state.addReadCache(unproxiedObject, identity, index, accessKind, overflowAccess, finalValue, this);
         return result;
     }
 
@@ -150,43 +150,52 @@
         ValueNode unproxiedObject = GraphUtil.unproxify(object);
         ValueNode cachedValue = state.getReadCache(unproxiedObject, identity, index, kind, this);
         if (cachedValue != null) {
-            Stamp loadStamp = load.stamp();
-            Stamp cachedValueStamp = cachedValue.stamp();
-            if (!loadStamp.isCompatible(cachedValueStamp)) {
-                /*
-                 * Can either be the first field of a two slot write to a one slot field which would
-                 * have a non compatible stamp or the second load which will see Illegal.
-                 */
-                assert load.stamp().getStackKind() == JavaKind.Int && (cachedValue.stamp().getStackKind() == JavaKind.Long || cachedValue.getStackKind() == JavaKind.Double ||
-                                cachedValue.getStackKind() == JavaKind.Illegal) : "Can only allow different stack kind two slot marker writes on one slot fields.";
-                return false;
-            } else {
-                // perform the read elimination
-                effects.replaceAtUsages(load, cachedValue, load);
-                addScalarAlias(load, cachedValue);
-                return true;
-            }
+            // perform the read elimination
+            effects.replaceAtUsages(load, cachedValue, load);
+            addScalarAlias(load, cachedValue);
+            return true;
         } else {
-            state.addReadCache(unproxiedObject, identity, index, kind, load, this);
+            state.addReadCache(unproxiedObject, identity, index, kind, false, load, this);
             return false;
         }
     }
 
+    private static boolean isOverflowAccess(JavaKind accessKind, JavaKind declaredKind) {
+        if (accessKind == declaredKind) {
+            return false;
+        }
+        if (accessKind == JavaKind.Object) {
+            switch (declaredKind) {
+                case Object:
+                case Double:
+                case Long:
+                    return false;
+                default:
+                    return true;
+            }
+        }
+        assert accessKind.isPrimitive() : "Illegal access kind";
+        return declaredKind.isPrimitive() ? accessKind.getBitCount() > declaredKind.getBitCount() : true;
+    }
+
     private boolean processUnsafeLoad(RawLoadNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
         if (load.offset().isConstant()) {
             ResolvedJavaType type = StampTool.typeOrNull(load.object());
             if (type != null && type.isArray()) {
+                JavaKind accessKind = load.accessKind();
+                JavaKind componentKind = type.getComponentType().getJavaKind();
                 long offset = load.offset().asJavaConstant().asLong();
-                int index = VirtualArrayNode.entryIndexForOffset(offset, load.accessKind(), type.getComponentType(), Integer.MAX_VALUE);
+                int index = VirtualArrayNode.entryIndexForOffset(offset, accessKind, type.getComponentType(), Integer.MAX_VALUE);
                 ValueNode object = GraphUtil.unproxify(load.object());
-                LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getJavaKind());
-                ValueNode cachedValue = state.getReadCache(object, location, index, load.accessKind(), this);
-                if (cachedValue != null && load.stamp().isCompatible(cachedValue.stamp())) {
+                LocationIdentity location = NamedLocationIdentity.getArrayLocation(componentKind);
+                ValueNode cachedValue = state.getReadCache(object, location, index, accessKind, this);
+                assert cachedValue == null || load.stamp().isCompatible(cachedValue.stamp()) : "The RawLoadNode's stamp is not compatible with the cached value.";
+                if (cachedValue != null) {
                     effects.replaceAtUsages(load, cachedValue, load);
                     addScalarAlias(load, cachedValue);
                     return true;
                 } else {
-                    state.addReadCache(object, location, index, load.accessKind(), load, this);
+                    state.addReadCache(object, location, index, accessKind, isOverflowAccess(accessKind, componentKind), load, this);
                 }
             }
         }
@@ -196,11 +205,14 @@
     private boolean processUnsafeStore(RawStoreNode store, PEReadEliminationBlockState state, GraphEffectList effects) {
         ResolvedJavaType type = StampTool.typeOrNull(store.object());
         if (type != null && type.isArray()) {
-            LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getJavaKind());
+            JavaKind accessKind = store.accessKind();
+            JavaKind componentKind = type.getComponentType().getJavaKind();
+            LocationIdentity location = NamedLocationIdentity.getArrayLocation(componentKind);
             if (store.offset().isConstant()) {
                 long offset = store.offset().asJavaConstant().asLong();
-                int index = VirtualArrayNode.entryIndexForOffset(offset, store.accessKind(), type.getComponentType(), Integer.MAX_VALUE);
-                return processStore(store, store.object(), location, index, store.accessKind(), store.value(), state, effects);
+                boolean overflowAccess = isOverflowAccess(accessKind, componentKind);
+                int index = overflowAccess ? -1 : VirtualArrayNode.entryIndexForOffset(offset, accessKind, type.getComponentType(), Integer.MAX_VALUE);
+                return processStore(store, store.object(), location, index, accessKind, overflowAccess, store.value(), state, effects);
             } else {
                 processIdentity(state, location);
             }
@@ -219,7 +231,8 @@
             state.killReadCache();
             return false;
         }
-        return processStore(store, store.object(), new FieldLocationIdentity(store.field()), -1, store.field().getJavaKind(), store.value(), state, effects);
+        JavaKind kind = store.field().getJavaKind();
+        return processStore(store, store.object(), new FieldLocationIdentity(store.field()), -1, kind, false, store.value(), state, effects);
     }
 
     private boolean processLoadField(LoadFieldNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
@@ -230,11 +243,32 @@
         return processLoad(load, load.object(), new FieldLocationIdentity(load.field()), -1, load.field().getJavaKind(), state, effects);
     }
 
+    private static JavaKind getElementKindFromStamp(ValueNode array) {
+        ResolvedJavaType type = StampTool.typeOrNull(array);
+        if (type != null && type.isArray()) {
+            return type.getComponentType().getJavaKind();
+        } else {
+            // It is likely an OSRLocal without valid stamp
+            return JavaKind.Illegal;
+        }
+    }
+
     private boolean processStoreIndexed(StoreIndexedNode store, PEReadEliminationBlockState state, GraphEffectList effects) {
-        LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(store.elementKind());
-        if (store.index().isConstant()) {
-            int index = ((JavaConstant) store.index().asConstant()).asInt();
-            return processStore(store, store.array(), arrayLocation, index, store.elementKind(), store.value(), state, effects);
+        int index = store.index().isConstant() ? ((JavaConstant) store.index().asConstant()).asInt() : -1;
+        // BASTORE (with elementKind being Byte) can be used to store values in boolean arrays.
+        JavaKind elementKind = store.elementKind();
+        if (elementKind == JavaKind.Byte) {
+            elementKind = getElementKindFromStamp(store.array());
+            if (elementKind == JavaKind.Illegal) {
+                // Could not determine the actual access kind from stamp. Hence kill both.
+                state.killReadCache(NamedLocationIdentity.getArrayLocation(JavaKind.Boolean), index);
+                state.killReadCache(NamedLocationIdentity.getArrayLocation(JavaKind.Byte), index);
+                return false;
+            }
+        }
+        LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(elementKind);
+        if (index != -1) {
+            return processStore(store, store.array(), arrayLocation, index, elementKind, false, store.value(), state, effects);
         } else {
             state.killReadCache(arrayLocation, -1);
         }
@@ -244,8 +278,17 @@
     private boolean processLoadIndexed(LoadIndexedNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
         if (load.index().isConstant()) {
             int index = ((JavaConstant) load.index().asConstant()).asInt();
-            LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(load.elementKind());
-            return processLoad(load, load.array(), arrayLocation, index, load.elementKind(), state, effects);
+            // BALOAD (with elementKind being Byte) can be used to retrieve values from boolean
+            // arrays.
+            JavaKind elementKind = load.elementKind();
+            if (elementKind == JavaKind.Byte) {
+                elementKind = getElementKindFromStamp(load.array());
+                if (elementKind == JavaKind.Illegal) {
+                    return false;
+                }
+            }
+            LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(elementKind);
+            return processLoad(load, load.array(), arrayLocation, index, elementKind, state, effects);
         }
         return false;
     }
@@ -293,7 +336,7 @@
                     if (object != null) {
                         Pair<ValueNode, Object> pair = firstValueSet.get(object);
                         while (pair != null) {
-                            initialState.addReadCache(pair.getLeft(), entry.identity, entry.index, entry.kind, initialState.getReadCache().get(entry), this);
+                            initialState.addReadCache(pair.getLeft(), entry.identity, entry.index, entry.kind, entry.overflowAccess, initialState.getReadCache().get(entry), this);
                             pair = (Pair<ValueNode, Object>) pair.getRight();
                         }
                     }
@@ -386,14 +429,14 @@
                 if (phi.getStackKind() == JavaKind.Object) {
                     for (ReadCacheEntry entry : states.get(0).readCache.getKeys()) {
                         if (entry.object == getPhiValueAt(phi, 0)) {
-                            mergeReadCachePhi(phi, entry.identity, entry.index, entry.kind, states);
+                            mergeReadCachePhi(phi, entry.identity, entry.index, entry.kind, entry.overflowAccess, states);
                         }
                     }
                 }
             }
         }
 
-        private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, JavaKind kind, List<PEReadEliminationBlockState> states) {
+        private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, JavaKind kind, boolean overflowAccess, List<PEReadEliminationBlockState> states) {
             ValueNode[] values = new ValueNode[states.size()];
             values[0] = states.get(0).getReadCache(getPhiValueAt(phi, 0), identity, index, kind, PEReadEliminationClosure.this);
             if (values[0] != null) {
@@ -407,12 +450,12 @@
                     values[i] = value;
                 }
 
-                PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi, index, kind), values[0].stamp().unrestricted());
+                PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi, index, kind, overflowAccess), values[0].stamp().unrestricted());
                 mergeEffects.addFloatingNode(phiNode, "mergeReadCachePhi");
                 for (int i = 0; i < values.length; i++) {
                     setPhiInput(phiNode, i, values[i]);
                 }
-                newState.readCache.put(new ReadCacheEntry(identity, phi, index, kind), phiNode);
+                newState.readCache.put(new ReadCacheEntry(identity, phi, index, kind, overflowAccess), phiNode);
             }
         }
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java	Wed Oct 11 17:11:28 2017 -0700
@@ -28,6 +28,7 @@
 import java.util.Iterator;
 import java.util.List;
 
+import jdk.vm.ci.meta.ResolvedJavaType;
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.Node;
@@ -52,6 +53,7 @@
 import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
 import org.graalvm.compiler.nodes.memory.ReadNode;
 import org.graalvm.compiler.nodes.memory.WriteNode;
+import org.graalvm.compiler.nodes.type.StampTool;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.virtual.phases.ea.ReadEliminationBlockState.CacheEntry;
@@ -146,38 +148,41 @@
                 processIdentity(state, write.getLocationIdentity());
             }
         } else if (node instanceof UnsafeAccessNode) {
-            if (node instanceof RawLoadNode) {
-                RawLoadNode load = (RawLoadNode) node;
-                if (load.getLocationIdentity().isSingle()) {
-                    ValueNode object = GraphUtil.unproxify(load.object());
-                    UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, load.offset(), load.getLocationIdentity());
-                    ValueNode cachedValue = state.getCacheEntry(identifier);
-                    if (cachedValue != null && areValuesReplaceable(load, cachedValue, considerGuards)) {
-                        effects.replaceAtUsages(load, cachedValue, load);
-                        addScalarAlias(load, cachedValue);
-                        deleted = true;
+            ResolvedJavaType type = StampTool.typeOrNull(((UnsafeAccessNode) node).object());
+            if (type != null && !type.isArray()) {
+                if (node instanceof RawLoadNode) {
+                    RawLoadNode load = (RawLoadNode) node;
+                    if (load.getLocationIdentity().isSingle()) {
+                        ValueNode object = GraphUtil.unproxify(load.object());
+                        UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, load.offset(), load.getLocationIdentity());
+                        ValueNode cachedValue = state.getCacheEntry(identifier);
+                        if (cachedValue != null && areValuesReplaceable(load, cachedValue, considerGuards)) {
+                            effects.replaceAtUsages(load, cachedValue, load);
+                            addScalarAlias(load, cachedValue);
+                            deleted = true;
+                        } else {
+                            state.addCacheEntry(identifier, load);
+                        }
+                    }
+                } else {
+                    assert node instanceof RawStoreNode;
+                    RawStoreNode write = (RawStoreNode) node;
+                    if (write.getLocationIdentity().isSingle()) {
+                        ValueNode object = GraphUtil.unproxify(write.object());
+                        UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, write.offset(), write.getLocationIdentity());
+                        ValueNode cachedValue = state.getCacheEntry(identifier);
+
+                        ValueNode value = getScalarAlias(write.value());
+                        if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
+                            effects.deleteNode(write);
+                            deleted = true;
+                        }
+                        processIdentity(state, write.getLocationIdentity());
+                        state.addCacheEntry(identifier, value);
                     } else {
-                        state.addCacheEntry(identifier, load);
+                        processIdentity(state, write.getLocationIdentity());
                     }
                 }
-            } else {
-                assert node instanceof RawStoreNode;
-                RawStoreNode write = (RawStoreNode) node;
-                if (write.getLocationIdentity().isSingle()) {
-                    ValueNode object = GraphUtil.unproxify(write.object());
-                    UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, write.offset(), write.getLocationIdentity());
-                    ValueNode cachedValue = state.getCacheEntry(identifier);
-
-                    ValueNode value = getScalarAlias(write.value());
-                    if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
-                        effects.deleteNode(write);
-                        deleted = true;
-                    }
-                    processIdentity(state, write.getLocationIdentity());
-                    state.addCacheEntry(identifier, value);
-                } else {
-                    processIdentity(state, write.getLocationIdentity());
-                }
             }
         } else if (node instanceof MemoryCheckpoint.Single) {
             LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java	Wed Oct 11 17:11:28 2017 -0700
@@ -268,6 +268,9 @@
         }
 
         Word.Operation operation = BridgeMethodUtils.getAnnotation(Word.Operation.class, wordMethod);
+        if (operation == null) {
+            throw bailout(b, "Cannot call method on a word value: " + wordMethod.format("%H.%n(%p)"));
+        }
         switch (operation.opcode()) {
             case NODE_CLASS:
                 assert args.length == 2;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java	Wed Oct 11 17:11:28 2017 -0700
@@ -527,7 +527,7 @@
             final int bci = findNodeSourcePositionBCI(pos);
             writeInt(bci);
             StackTraceElement ste = findMethodStackTraceElement(method, bci, pos);
-            if (ste != null) {
+            if (ste != null && ste.getFileName() != null) {
                 writePoolObject(ste.getFileName());
                 writeInt(ste.getLineNumber());
             } else {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionKey.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionKey.java	Wed Oct 11 17:11:28 2017 -0700
@@ -53,13 +53,11 @@
     }
 
     /**
-     * Constructs a new option key given a default value and option key. The default value and the
-     * type must not be <code>null</code>.
+     * Constructs a new option key given a default value and option key.
      *
      * @since 1.0
      */
     public OptionKey(T defaultValue, OptionType<T> type) {
-        Objects.requireNonNull(defaultValue);
         Objects.requireNonNull(type);
         this.defaultValue = defaultValue;
         this.type = type;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionType.java	Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.options/src/org/graalvm/options/OptionType.java	Wed Oct 11 17:11:28 2017 -0700
@@ -57,7 +57,6 @@
      */
     public OptionType(String name, T defaultValue, Function<String, T> stringConverter, Consumer<T> validator) {
         Objects.requireNonNull(name);
-        Objects.requireNonNull(defaultValue);
         Objects.requireNonNull(stringConverter);
         Objects.requireNonNull(validator);
         this.name = name;
@@ -133,7 +132,7 @@
         return "OptionType[name=" + name + ", defaultValue=" + defaultValue + "]";
     }
 
-    private static Map<Class<?>, OptionType<?>> DEFAULTTYPES = new HashMap<>();
+    private static final Map<Class<?>, OptionType<?>> DEFAULTTYPES = new HashMap<>();
     static {
         DEFAULTTYPES.put(Boolean.class, new OptionType<>("Boolean", false, new Function<String, Boolean>() {
             public Boolean apply(String t) {
@@ -200,13 +199,24 @@
 
     /**
      * Returns the default option type for a given value. Returns <code>null</code> if no default
-     * option type is available for this Java type.
+     * option type is available for the Java type of this value.
      *
      * @since 1.0
      */
     @SuppressWarnings("unchecked")
-    public static <T> OptionType<T> defaultType(Object value) {
-        return (OptionType<T>) DEFAULTTYPES.get(value.getClass());
+    public static <T> OptionType<T> defaultType(T value) {
+        return defaultType((Class<T>) value.getClass());
+    }
+
+    /**
+     * Returns the default option type for a class. Returns <code>null</code> if no default option
+     * type is available for this Java type.
+     *
+     * @since 1.0
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> OptionType<T> defaultType(Class<T> clazz) {
+        return (OptionType<T>) DEFAULTTYPES.get(clazz);
     }
 
 }