8186850: Update Graal
authoriveresov
Mon, 28 Aug 2017 14:43:32 -0700
changeset 47084 630d326a3d15
parent 46999 dd86717fe58b
child 47085 eb6459334399
8186850: Update Graal Reviewed-by: kvn
hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java
hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/ClassSubstitution.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/InvokeGraal.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeBitMapTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64RawNativeCallNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64RawNativeCallNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotUnsafeSubstitutionTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotUnsafeSubstitutions.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceInterval.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CompilationPrinter.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/ClassSubstitutionVerifier.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java
hotspot/src/share/vm/aot/aotCodeHeap.cpp
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java	Mon Aug 28 14:43:32 2017 -0700
@@ -187,10 +187,9 @@
         {"StubRoutines::_arrayof_oop_disjoint_arraycopy", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy"},
         {"StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit"},
 
-        {"StubRoutines::_checkcast_arraycopy", "_aot_stub_routines_checkcast_arraycopy"},
+        {"StubRoutines::_unsafe_arraycopy", "_aot_stub_routines_unsafe_arraycopy"},
 
-
-
+        {"StubRoutines::_checkcast_arraycopy", "_aot_stub_routines_checkcast_arraycopy"},
 
         {"StubRoutines::_aescrypt_encryptBlock", "_aot_stub_routines_aescrypt_encryptBlock"},
         {"StubRoutines::_aescrypt_decryptBlock", "_aot_stub_routines_aescrypt_decryptBlock"},
@@ -478,8 +477,8 @@
     }
 
     /**
-     * Creates a global symbol of the form {@code "A" + container name}.
-     * Note, linker on Windows does not allow names which start with '.'
+     * Creates a global symbol of the form {@code "A" + container name}. Note, linker on Windows
+     * does not allow names which start with '.'
      *
      * @param container container to create a symbol for
      */
@@ -685,7 +684,8 @@
     }
 
     /**
-     * Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to patch.
+     * Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to
+     * patch.
      *
      * @param oopName name of the oop symbol
      */
@@ -728,10 +728,9 @@
     }
 
     /**
-     * Add klass symbol by as follows.
-     *   - Adding the symbol name to the metaspace.names section
-     *   - Add the offset of the name in metaspace.names to metaspace.offsets
-     *   - Extend the klasses.got section with another slot for the VM to patch
+     * Add klass symbol by as follows. - Adding the symbol name to the metaspace.names section - Add
+     * the offset of the name in metaspace.names to metaspace.offsets - Extend the klasses.got
+     * section with another slot for the VM to patch
      *
      * @param klassName name of the metaspace symbol
      * @return the got offset in the klasses.got of the metaspace symbol
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java	Mon Aug 28 14:43:32 2017 -0700
@@ -27,6 +27,8 @@
 
 import org.graalvm.compiler.code.CompilationResult;
 import org.graalvm.compiler.core.GraalCompiler;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.CompilationIdentifier.Verbosity;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.hotspot.HotSpotBackend;
 import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
@@ -127,7 +129,13 @@
             ProfilingInfo profilingInfo = DefaultProfilingInfo.get(TriState.FALSE);
 
             final boolean isImmutablePIC = true;
-            CompilationResult compilationResult = new CompilationResult(resolvedMethod.getName(), isImmutablePIC);
+            CompilationIdentifier id = new CompilationIdentifier() {
+                @Override
+                public String toString(Verbosity verbosity) {
+                    return resolvedMethod.getName();
+                }
+            };
+            CompilationResult compilationResult = new CompilationResult(id, isImmutablePIC);
 
             return GraalCompiler.compileGraph(graph, resolvedMethod, providers, backend, graphBuilderSuite, OptimisticOptimizations.ALL, profilingInfo, getSuites(), getLirSuites(),
                             compilationResult, CompilationResultBuilderFactory.Default);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/ClassSubstitution.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/ClassSubstitution.java	Mon Aug 28 14:43:32 2017 -0700
@@ -57,7 +57,9 @@
 
     /**
      * Determines if the substitutions are for classes that may not be part of the runtime.
-     * Substitutions for such classes are omitted if the original classes cannot be found.
+     * Substitutions for such classes are omitted if the original classes cannot be found. If
+     * multiple classes are specified using {@link #className()} and {@link #optional()} is false,
+     * then at least one of the classes is required to be reachable.
      */
     boolean optional() default false;
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java	Mon Aug 28 14:43:32 2017 -0700
@@ -90,7 +90,7 @@
             StructuredGraph graph = new StructuredGraph.Builder(options, debug).method(method).compilationId(compilationId).build();
             CallingConvention cc = backend.newLIRGenerationResult(compilationId, null, null, graph, null).getCallingConvention();
 
-            CompilationResult compResult = new CompilationResult();
+            CompilationResult compResult = new CompilationResult(graph.compilationId());
             byte[] targetCode = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc);
             compResult.setTargetCode(targetCode, targetCode.length);
             compResult.setTotalFrameSize(0);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java	Mon Aug 28 14:43:32 2017 -0700
@@ -33,6 +33,7 @@
 import java.util.List;
 import java.util.Objects;
 
+import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.util.EconomicSet;
 
@@ -190,6 +191,8 @@
 
     private final String name;
 
+    private final CompilationIdentifier compilationId;
+
     /**
      * The buffer containing the emitted machine code.
      */
@@ -222,21 +225,26 @@
 
     private boolean isImmutablePIC;
 
-    public CompilationResult() {
-        this(null, false);
+    public CompilationResult(CompilationIdentifier compilationId) {
+        this(compilationId, compilationId.toString(CompilationIdentifier.Verbosity.NAME), false);
+    }
+
+    public CompilationResult(CompilationIdentifier compilationId, String name) {
+        this(compilationId, name, false);
+    }
+
+    public CompilationResult(CompilationIdentifier compilationId, boolean isImmutablePIC) {
+        this(compilationId, null, isImmutablePIC);
+    }
+
+    public CompilationResult(CompilationIdentifier compilationId, String name, boolean isImmutablePIC) {
+        this.compilationId = compilationId;
+        this.name = name;
+        this.isImmutablePIC = isImmutablePIC;
     }
 
     public CompilationResult(String name) {
-        this(name, false);
-    }
-
-    public CompilationResult(boolean isImmutablePIC) {
-        this(null, isImmutablePIC);
-    }
-
-    public CompilationResult(String name, boolean isImmutablePIC) {
-        this.name = name;
-        this.isImmutablePIC = isImmutablePIC;
+        this(null, name);
     }
 
     @Override
@@ -266,6 +274,7 @@
                 this.totalFrameSize == that.totalFrameSize &&
                 this.targetCodeSize == that.targetCodeSize &&
                 Objects.equals(this.name, that.name) &&
+                Objects.equals(this.compilationId, that.compilationId) &&
                 Objects.equals(this.annotations, that.annotations) &&
                 Objects.equals(this.dataSection, that.dataSection) &&
                 Objects.equals(this.exceptionHandlers, that.exceptionHandlers) &&
@@ -670,6 +679,10 @@
         return name;
     }
 
+    public CompilationIdentifier getCompilationId() {
+        return compilationId;
+    }
+
     public void setHasUnsafeAccess(boolean hasUnsafeAccess) {
         checkOpen();
         this.hasUnsafeAccess = hasUnsafeAccess;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Mon Aug 28 14:43:32 2017 -0700
@@ -949,7 +949,7 @@
 
             try (AllocSpy spy = AllocSpy.open(installedCodeOwner); DebugContext.Scope ds = debug.scope("Compiling", new DebugDumpScope(id.toString(CompilationIdentifier.Verbosity.ID), true))) {
                 CompilationPrinter printer = CompilationPrinter.begin(options, id, installedCodeOwner, INVOCATION_ENTRY_BCI);
-                CompilationResult compResult = compile(installedCodeOwner, graphToCompile, new CompilationResult(), id, options);
+                CompilationResult compResult = compile(installedCodeOwner, graphToCompile, new CompilationResult(graphToCompile.compilationId()), id, options);
                 printer.finish(compResult);
 
                 try (DebugContext.Scope s = debug.scope("CodeInstall", getCodeCache(), installedCodeOwner, compResult);
@@ -1019,17 +1019,19 @@
      */
     protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) {
         OptionValues options = graph == null ? getInitialOptions() : graph.getOptions();
-        return compile(installedCodeOwner, graph, new CompilationResult(), getOrCreateCompilationId(installedCodeOwner, graph), options);
+        CompilationIdentifier compilationId = getOrCreateCompilationId(installedCodeOwner, graph);
+        return compile(installedCodeOwner, graph, new CompilationResult(compilationId), compilationId, options);
     }
 
     protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, CompilationIdentifier compilationId) {
         OptionValues options = graph == null ? getInitialOptions() : graph.getOptions();
-        return compile(installedCodeOwner, graph, new CompilationResult(), compilationId, options);
+        return compile(installedCodeOwner, graph, new CompilationResult(compilationId), compilationId, options);
     }
 
     protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, OptionValues options) {
         assert graph == null || graph.getOptions() == options;
-        return compile(installedCodeOwner, graph, new CompilationResult(), getOrCreateCompilationId(installedCodeOwner, graph), options);
+        CompilationIdentifier compilationId = getOrCreateCompilationId(installedCodeOwner, graph);
+        return compile(installedCodeOwner, graph, new CompilationResult(compilationId), compilationId, options);
     }
 
     /**
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java	Mon Aug 28 14:43:32 2017 -0700
@@ -64,7 +64,7 @@
         final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
         final StructuredGraph graph = parseEager(method, AllowAssumptions.YES);
         final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, graph.getProfilingInfo(),
-                        createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(), CompilationResultBuilderFactory.Default);
+                        createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
         for (Infopoint sp : cr.getInfopoints()) {
             assertNotNull(sp.reason);
             if (sp instanceof Call) {
@@ -86,7 +86,7 @@
         assertTrue(graphLineSPs > 0);
         PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true));
         final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), graphBuilderSuite, OptimisticOptimizations.ALL, graph.getProfilingInfo(),
-                        createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(), CompilationResultBuilderFactory.Default);
+                        createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
         int lineSPs = 0;
         for (Infopoint sp : cr.getInfopoints()) {
             assertNotNull(sp.reason);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/InvokeGraal.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/InvokeGraal.java	Mon Aug 28 14:43:32 2017 -0700
@@ -123,7 +123,7 @@
             ProfilingInfo profilingInfo = graph.getProfilingInfo(method);
 
             /* The default class and configuration for compilation results. */
-            CompilationResult compilationResult = new CompilationResult();
+            CompilationResult compilationResult = new CompilationResult(graph.compilationId());
             CompilationResultBuilderFactory factory = CompilationResultBuilderFactory.Default;
 
             /* Invoke the whole Graal compilation pipeline. */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeBitMapTest.java	Mon Aug 28 14:43:32 2017 -0700
@@ -0,0 +1,203 @@
+/*
+ * 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.graph.test;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.options.OptionValues;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class NodeBitMapTest extends GraphTest {
+
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    static final class TestNode extends Node {
+        public static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class);
+
+        protected TestNode() {
+            super(TYPE);
+        }
+    }
+
+    private Graph graph;
+    private TestNode[] nodes = new TestNode[100];
+    private NodeBitMap map;
+
+    @Before
+    public void before() {
+        // Need to initialize HotSpotGraalRuntime before any Node class is initialized.
+        Graal.getRuntime();
+
+        OptionValues options = getOptions();
+        graph = new Graph(options, getDebug(options));
+        for (int i = 0; i < nodes.length; i++) {
+            nodes[i] = graph.add(new TestNode());
+        }
+        map = graph.createNodeBitMap();
+    }
+
+    @Test
+    public void iterateEmpty() {
+        for (Node n : map) {
+            Assert.fail("no elements expected: " + n);
+        }
+    }
+
+    @Test
+    public void iterateMarkedNodes() {
+        map.mark(nodes[99]);
+        map.mark(nodes[0]);
+        map.mark(nodes[7]);
+        map.mark(nodes[1]);
+        map.mark(nodes[53]);
+
+        Iterator<Node> iter = map.iterator();
+        Assert.assertTrue(iter.hasNext());
+        Assert.assertEquals(nodes[0], iter.next());
+        Assert.assertTrue(iter.hasNext());
+        Assert.assertEquals(nodes[1], iter.next());
+        Assert.assertTrue(iter.hasNext());
+        Assert.assertEquals(nodes[7], iter.next());
+        Assert.assertTrue(iter.hasNext());
+        Assert.assertEquals(nodes[53], iter.next());
+        Assert.assertTrue(iter.hasNext());
+        Assert.assertEquals(nodes[99], iter.next());
+        Assert.assertFalse(iter.hasNext());
+    }
+
+    @Test
+    public void deleteNodeWhileIterating() {
+        map.mark(nodes[99]);
+        map.mark(nodes[0]);
+        map.mark(nodes[7]);
+        map.mark(nodes[1]);
+        map.mark(nodes[53]);
+
+        Iterator<Node> iter = map.iterator();
+        Assert.assertTrue(iter.hasNext());
+        Assert.assertEquals(nodes[0], iter.next());
+        Assert.assertTrue(iter.hasNext());
+        Assert.assertEquals(nodes[1], iter.next());
+        nodes[7].markDeleted();
+        nodes[53].markDeleted();
+        Assert.assertTrue(iter.hasNext());
+        Assert.assertEquals(nodes[99], iter.next());
+        Assert.assertFalse(iter.hasNext());
+    }
+
+    @Test
+    public void deleteAllNodesBeforeIterating() {
+        for (int i = 0; i < nodes.length; i++) {
+            map.mark(nodes[i]);
+            nodes[i].markDeleted();
+        }
+
+        Iterator<Node> iter = map.iterator();
+        Assert.assertFalse(iter.hasNext());
+    }
+
+    @Test
+    public void multipleHasNextInvocations() {
+        map.mark(nodes[7]);
+
+        Iterator<Node> iter = map.iterator();
+        Assert.assertTrue(iter.hasNext());
+        Assert.assertTrue(iter.hasNext());
+        Assert.assertEquals(nodes[7], iter.next());
+        Assert.assertFalse(iter.hasNext());
+    }
+
+    @Test(expected = NoSuchElementException.class)
+    public void noSuchElement() {
+        map.iterator().next();
+    }
+
+    @Test(expected = ConcurrentModificationException.class)
+    public void concurrentModification() {
+        map.mark(nodes[7]);
+
+        map.mark(nodes[99]);
+        map.mark(nodes[0]);
+        map.mark(nodes[7]);
+        map.mark(nodes[1]);
+        map.mark(nodes[53]);
+
+        Iterator<Node> iter = map.iterator();
+        Assert.assertTrue(iter.hasNext());
+        Assert.assertEquals(nodes[0], iter.next());
+        Assert.assertTrue(iter.hasNext());
+        Assert.assertEquals(nodes[1], iter.next());
+        Assert.assertTrue(iter.hasNext());
+        nodes[7].markDeleted();
+        iter.next();
+    }
+
+    @Test
+    public void nextWithoutHasNext() {
+        map.mark(nodes[99]);
+        map.mark(nodes[0]);
+        map.mark(nodes[7]);
+        map.mark(nodes[1]);
+        map.mark(nodes[53]);
+
+        Iterator<Node> iter = map.iterator();
+        Assert.assertEquals(nodes[0], iter.next());
+        Assert.assertEquals(nodes[1], iter.next());
+        Assert.assertEquals(nodes[7], iter.next());
+        Assert.assertEquals(nodes[53], iter.next());
+        Assert.assertEquals(nodes[99], iter.next());
+        Assert.assertFalse(iter.hasNext());
+    }
+
+    @Test
+    public void markWhileIterating() {
+        map.mark(nodes[0]);
+
+        Iterator<Node> iter = map.iterator();
+        Assert.assertTrue(iter.hasNext());
+        Assert.assertEquals(nodes[0], iter.next());
+        map.mark(nodes[7]);
+        Assert.assertTrue(iter.hasNext());
+        map.mark(nodes[1]);
+        Assert.assertEquals(nodes[7], iter.next());
+        map.mark(nodes[99]);
+        map.mark(nodes[53]);
+        Assert.assertTrue(iter.hasNext());
+        Assert.assertEquals(nodes[53], iter.next());
+        Assert.assertTrue(iter.hasNext());
+        Assert.assertEquals(nodes[99], iter.next());
+        Assert.assertFalse(iter.hasNext());
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java	Mon Aug 28 14:43:32 2017 -0700
@@ -23,22 +23,23 @@
 package org.graalvm.compiler.graph;
 
 import java.util.Arrays;
+import java.util.ConcurrentModificationException;
 import java.util.Iterator;
+import java.util.NoSuchElementException;
 
 import org.graalvm.compiler.graph.iterators.NodeIterable;
 
-public final class NodeBitMap implements NodeIterable<Node> {
+public final class NodeBitMap extends NodeIdAccessor implements NodeIterable<Node> {
     private static final int SHIFT = 6;
 
     private long[] bits;
     private int nodeCount;
     private int counter;
-    private final Graph graph;
 
     public NodeBitMap(Graph graph) {
+        super(graph);
         this.nodeCount = graph.nodeIdCount();
         this.bits = new long[sizeForNodeCount(nodeCount)];
-        this.graph = graph;
     }
 
     private static int sizeForNodeCount(int nodeCount) {
@@ -50,9 +51,9 @@
     }
 
     private NodeBitMap(NodeBitMap other) {
+        super(other.graph);
         this.bits = other.bits.clone();
         this.nodeCount = other.nodeCount;
-        this.graph = other.graph;
     }
 
     public Graph graph() {
@@ -60,12 +61,12 @@
     }
 
     public boolean isNew(Node node) {
-        return node.id() >= nodeCount;
+        return getNodeId(node) >= nodeCount;
     }
 
     public boolean isMarked(Node node) {
         assert check(node, false);
-        return isMarked(node.id());
+        return isMarked(getNodeId(node));
     }
 
     public boolean checkAndMarkInc(Node node) {
@@ -84,33 +85,33 @@
 
     public boolean isMarkedAndGrow(Node node) {
         assert check(node, true);
-        int id = node.id();
+        int id = getNodeId(node);
         checkGrow(id);
         return isMarked(id);
     }
 
     public void mark(Node node) {
         assert check(node, false);
-        int id = node.id();
+        int id = getNodeId(node);
         bits[id >> SHIFT] |= (1L << id);
     }
 
     public void markAndGrow(Node node) {
         assert check(node, true);
-        int id = node.id();
+        int id = getNodeId(node);
         checkGrow(id);
         bits[id >> SHIFT] |= (1L << id);
     }
 
     public void clear(Node node) {
         assert check(node, false);
-        int id = node.id();
+        int id = getNodeId(node);
         bits[id >> SHIFT] &= ~(1L << id);
     }
 
     public void clearAndGrow(Node node) {
         assert check(node, true);
-        int id = node.id();
+        int id = getNodeId(node);
         checkGrow(id);
         bits[id >> SHIFT] &= ~(1L << id);
     }
@@ -181,15 +182,30 @@
         }
     }
 
-    protected int nextMarkedNodeId(int fromNodeId) {
+    protected Node nextMarkedNode(int fromNodeId) {
         assert fromNodeId >= 0;
         int wordIndex = fromNodeId >> SHIFT;
         int wordsInUse = bits.length;
         if (wordIndex < wordsInUse) {
-            long word = bits[wordIndex] & (0xFFFFFFFFFFFFFFFFL << fromNodeId);
+            long word = getPartOfWord(bits[wordIndex], fromNodeId);
             while (true) {
-                if (word != 0) {
-                    return wordIndex * Long.SIZE + Long.numberOfTrailingZeros(word);
+                while (word != 0) {
+                    int bitIndex = Long.numberOfTrailingZeros(word);
+                    int nodeId = wordIndex * Long.SIZE + bitIndex;
+                    Node result = graph.getNode(nodeId);
+                    if (result == null) {
+                        // node was deleted -> clear the bit and continue searching
+                        bits[wordIndex] = bits[wordIndex] & ~(1 << bitIndex);
+                        int nextNodeId = nodeId + 1;
+                        if ((nextNodeId & (Long.SIZE - 1)) == 0) {
+                            // we reached the end of this word
+                            break;
+                        } else {
+                            word = getPartOfWord(word, nextNodeId);
+                        }
+                    } else {
+                        return result;
+                    }
                 }
                 if (++wordIndex == wordsInUse) {
                     break;
@@ -197,30 +213,56 @@
                 word = bits[wordIndex];
             }
         }
-        return -2;
+        return null;
+    }
+
+    private static long getPartOfWord(long word, int firstNodeIdToInclude) {
+        return word & (0xFFFFFFFFFFFFFFFFL << firstNodeIdToInclude);
     }
 
+    /**
+     * This iterator only returns nodes that are marked in the {@link NodeBitMap} and are alive in
+     * the corresponding {@link Graph}.
+     */
     private class MarkedNodeIterator implements Iterator<Node> {
-        private int nextNodeId;
+        private int currentNodeId;
+        private Node currentNode;
 
         MarkedNodeIterator() {
-            nextNodeId = -1;
+            currentNodeId = -1;
             forward();
         }
 
         private void forward() {
-            nextNodeId = NodeBitMap.this.nextMarkedNodeId(nextNodeId + 1);
+            assert currentNode == null;
+            currentNode = NodeBitMap.this.nextMarkedNode(currentNodeId + 1);
+            if (currentNode != null) {
+                assert currentNode.isAlive();
+                currentNodeId = getNodeId(currentNode);
+            } else {
+                currentNodeId = -1;
+            }
         }
 
         @Override
         public boolean hasNext() {
-            return nextNodeId >= 0;
+            if (currentNode == null && currentNodeId >= 0) {
+                forward();
+            }
+            return currentNodeId >= 0;
         }
 
         @Override
         public Node next() {
-            Node result = graph.getNode(nextNodeId);
-            forward();
+            if (!hasNext()) {
+                throw new NoSuchElementException();
+            }
+            if (!currentNode.isAlive()) {
+                throw new ConcurrentModificationException("NodeBitMap was modified between the calls to hasNext() and next()");
+            }
+
+            Node result = currentNode;
+            currentNode = null;
             return result;
         }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64RawNativeCallNode.java	Mon Aug 28 16:40:01 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2014, 2016, 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.aarch64;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
-
-import org.graalvm.compiler.core.aarch64.AArch64NodeLIRBuilder;
-import org.graalvm.compiler.core.common.type.RawPointerStamp;
-import org.graalvm.compiler.core.common.type.Stamp;
-import org.graalvm.compiler.core.common.type.StampFactory;
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.graph.NodeInputList;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.FixedWithNextNode;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.spi.LIRLowerable;
-import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
-
-import jdk.vm.ci.code.CallingConvention;
-import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.JavaType;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.meta.Value;
-
-@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "Native call is a block hole", size = SIZE_UNKNOWN)
-public final class AArch64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
-    public static final NodeClass<AArch64RawNativeCallNode> TYPE = NodeClass.create(AArch64RawNativeCallNode.class);
-
-    protected final JavaConstant functionPointer;
-    @Input NodeInputList<ValueNode> args;
-
-    public AArch64RawNativeCallNode(JavaKind returnType, JavaConstant functionPointer, ValueNode[] args) {
-        super(TYPE, StampFactory.forKind(returnType));
-        this.functionPointer = functionPointer;
-        this.args = new NodeInputList<>(this, args);
-    }
-
-    private static class PointerType implements JavaType {
-
-        @Override
-        public String getName() {
-            return "void*";
-        }
-
-        @Override
-        public JavaType getComponentType() {
-            return null;
-        }
-
-        @Override
-        public JavaType getArrayClass() {
-            return null;
-        }
-
-        @Override
-        public JavaKind getJavaKind() {
-            // native pointers and java objects use the same registers in the calling convention
-            return JavaKind.Object;
-        }
-
-        @Override
-        public ResolvedJavaType resolve(ResolvedJavaType accessingClass) {
-            return null;
-        }
-    }
-
-    private static JavaType toJavaType(Stamp stamp, MetaAccessProvider metaAccess) {
-        if (stamp instanceof RawPointerStamp) {
-            return new PointerType();
-        } else {
-            return stamp.javaType(metaAccess);
-        }
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool generator) {
-        AArch64NodeLIRBuilder gen = (AArch64NodeLIRBuilder) generator;
-        Value[] parameter = new Value[args.count()];
-        JavaType[] parameterTypes = new JavaType[args.count()];
-        for (int i = 0; i < args.count(); i++) {
-            parameter[i] = generator.operand(args.get(i));
-            parameterTypes[i] = toJavaType(args.get(i).stamp(), gen.getLIRGeneratorTool().getMetaAccess());
-        }
-        JavaType returnType = toJavaType(stamp(), gen.getLIRGeneratorTool().getMetaAccess());
-        CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.NativeCall, returnType, parameterTypes,
-                        generator.getLIRGeneratorTool());
-        gen.getLIRGeneratorTool().emitCCall(functionPointer.asLong(), cc, parameter);
-        if (this.getStackKind() != JavaKind.Void) {
-            generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn()));
-        }
-    }
-
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64RawNativeCallNode.java	Mon Aug 28 16:40:01 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2014, 2016, 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.amd64;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-
-import org.graalvm.compiler.core.amd64.AMD64NodeLIRBuilder;
-import org.graalvm.compiler.core.common.type.RawPointerStamp;
-import org.graalvm.compiler.core.common.type.Stamp;
-import org.graalvm.compiler.core.common.type.StampFactory;
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.graph.NodeInputList;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodeinfo.NodeSize;
-import org.graalvm.compiler.nodes.FixedWithNextNode;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.spi.LIRLowerable;
-import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
-
-import jdk.vm.ci.code.CallingConvention;
-import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.JavaType;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.meta.Value;
-
-@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "Native call is a block hole", size = NodeSize.SIZE_UNKNOWN)
-public final class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
-    public static final NodeClass<AMD64RawNativeCallNode> TYPE = NodeClass.create(AMD64RawNativeCallNode.class);
-
-    protected final JavaConstant functionPointer;
-    @Input NodeInputList<ValueNode> args;
-
-    public AMD64RawNativeCallNode(JavaKind returnType, JavaConstant functionPointer, ValueNode[] args) {
-        super(TYPE, StampFactory.forKind(returnType));
-        this.functionPointer = functionPointer;
-        this.args = new NodeInputList<>(this, args);
-    }
-
-    private static class PointerType implements JavaType {
-
-        @Override
-        public String getName() {
-            return "void*";
-        }
-
-        @Override
-        public JavaType getComponentType() {
-            return null;
-        }
-
-        @Override
-        public JavaType getArrayClass() {
-            return null;
-        }
-
-        @Override
-        public JavaKind getJavaKind() {
-            // native pointers and java objects use the same registers in the calling convention
-            return JavaKind.Object;
-        }
-
-        @Override
-        public ResolvedJavaType resolve(ResolvedJavaType accessingClass) {
-            return null;
-        }
-    }
-
-    private static JavaType toJavaType(Stamp stamp, MetaAccessProvider metaAccess) {
-        if (stamp instanceof RawPointerStamp) {
-            return new PointerType();
-        } else {
-            return stamp.javaType(metaAccess);
-        }
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool generator) {
-        AMD64NodeLIRBuilder gen = (AMD64NodeLIRBuilder) generator;
-        Value[] parameter = new Value[args.count()];
-        JavaType[] parameterTypes = new JavaType[args.count()];
-        for (int i = 0; i < args.count(); i++) {
-            parameter[i] = generator.operand(args.get(i));
-            parameterTypes[i] = toJavaType(args.get(i).stamp(), gen.getLIRGeneratorTool().getMetaAccess());
-        }
-        JavaType returnType = toJavaType(stamp(), gen.getLIRGeneratorTool().getMetaAccess());
-        CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.NativeCall, returnType, parameterTypes,
-                        generator.getLIRGeneratorTool());
-        gen.getLIRGeneratorTool().emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args));
-        if (this.getStackKind() != JavaKind.Void) {
-            generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn()));
-        }
-    }
-
-    private static int countFloatingTypeArguments(NodeInputList<ValueNode> args) {
-        int count = 0;
-        for (ValueNode n : args) {
-            if (n.getStackKind() == JavaKind.Double || n.getStackKind() == JavaKind.Float) {
-                count++;
-            }
-        }
-        if (count > 8) {
-            return 8;
-        }
-        return count;
-    }
-
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java	Mon Aug 28 14:43:32 2017 -0700
@@ -207,7 +207,6 @@
                         "oracle/jrockit/jfr/Timing.counterTime()J",
                         "oracle/jrockit/jfr/VMJFR.classID0(Ljava/lang/Class;)J",
                         "oracle/jrockit/jfr/VMJFR.threadID()I",
-                        "sun/misc/Unsafe.copyMemory(Ljava/lang/Object;JLjava/lang/Object;JJ)V",
                         "sun/nio/cs/ISO_8859_1$Encoder.encodeISOArray([CI[BII)I",
                         "sun/security/provider/DigestBase.implCompressMultiBlock([BII)I",
                         "sun/security/provider/SHA.implCompress([BI)V",
@@ -273,7 +272,6 @@
                         "jdk/internal/misc/Unsafe.compareAndExchangeShortRelease(Ljava/lang/Object;JSS)S",
                         "jdk/internal/misc/Unsafe.compareAndSetByte(Ljava/lang/Object;JBB)Z",
                         "jdk/internal/misc/Unsafe.compareAndSetShort(Ljava/lang/Object;JSS)Z",
-                        "jdk/internal/misc/Unsafe.copyMemory0(Ljava/lang/Object;JLjava/lang/Object;JJ)V",
                         "jdk/internal/misc/Unsafe.getAndAddByte(Ljava/lang/Object;JB)B",
                         "jdk/internal/misc/Unsafe.getAndAddShort(Ljava/lang/Object;JS)S",
                         "jdk/internal/misc/Unsafe.getAndSetByte(Ljava/lang/Object;JB)B",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotUnsafeSubstitutionTest.java	Mon Aug 28 14:43:32 2017 -0700
@@ -0,0 +1,81 @@
+/*
+ * 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 org.graalvm.compiler.replacements.test.MethodSubstitutionTest;
+import org.junit.Test;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import sun.misc.Unsafe;
+
+/**
+ * Tests the VM independent intrinsification of {@link Unsafe} methods.
+ */
+public class HotSpotUnsafeSubstitutionTest extends MethodSubstitutionTest {
+
+    public void testSubstitution(String testMethodName, Class<?> holder, String methodName, Class<?>[] parameterTypes, Object receiver, Object[] args1, Object[] args2) {
+        ResolvedJavaMethod testMethod = getResolvedJavaMethod(testMethodName);
+        ResolvedJavaMethod originalMethod = getResolvedJavaMethod(holder, methodName, parameterTypes);
+
+        // Force compilation
+        InstalledCode code = getCode(testMethod);
+        assert code != null;
+
+        // Verify that the original method and the substitution produce the same value
+        Object expected = invokeSafe(originalMethod, receiver, args1);
+        Object actual = invokeSafe(testMethod, null, args2);
+        assertDeepEquals(expected, actual);
+
+        // Verify that the generated code and the original produce the same value
+        expected = invokeSafe(originalMethod, receiver, args1);
+        actual = executeVarargsSafe(code, args2);
+        assertDeepEquals(expected, actual);
+
+    }
+
+    @Test
+    public void testUnsafeSubstitutions() throws Exception {
+        testGraph("unsafeCopyMemory");
+    }
+
+    public void unsafeCopyMemory(Object srcBase, long srcOffset, Object dstBase, long dstOffset, long bytes) {
+        UNSAFE.copyMemory(srcBase, srcOffset, dstBase, dstOffset, bytes);
+    }
+
+    public byte[] testCopyMemorySnippet(long src, int bytes) {
+        byte[] result = new byte[bytes];
+        UNSAFE.copyMemory(null, src, result, Unsafe.ARRAY_BYTE_BASE_OFFSET, bytes);
+        return result;
+    }
+
+    @Test
+    public void testCopyMemory() {
+        int size = 128;
+        long src = UNSAFE.allocateMemory(size);
+        for (int i = 0; i < size; i++) {
+            UNSAFE.putByte(null, src + i, (byte) i);
+        }
+        test("testCopyMemorySnippet", src, size);
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java	Mon Aug 28 14:43:32 2017 -0700
@@ -64,9 +64,9 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.tiers.SuitesProvider;
 import org.graalvm.compiler.word.Word;
-import org.graalvm.util.Equivalence;
 import org.graalvm.util.EconomicMap;
 import org.graalvm.util.EconomicSet;
+import org.graalvm.util.Equivalence;
 import org.graalvm.util.MapCursor;
 import org.graalvm.word.Pointer;
 
@@ -258,6 +258,18 @@
     private static native void sha5ImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state);
 
     /**
+     * @see org.graalvm.compiler.hotspot.meta.HotSpotUnsafeSubstitutions#copyMemory
+     */
+    public static final ForeignCallDescriptor UNSAFE_ARRAYCOPY = new ForeignCallDescriptor("unsafe_arraycopy", void.class, Word.class, Word.class, Word.class);
+
+    public static void unsafeArraycopy(Word srcAddr, Word dstAddr, Word size) {
+        unsafeArraycopyStub(HotSpotBackend.UNSAFE_ARRAYCOPY, srcAddr, dstAddr, size);
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void unsafeArraycopyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word srcAddr, Word dstAddr, Word size);
+
+    /**
      * @see VMErrorNode
      */
     public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java	Mon Aug 28 14:43:32 2017 -0700
@@ -198,7 +198,7 @@
 
     public CompilationResult compile(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId, OptionValues options, DebugContext debug) {
         StructuredGraph graph = createGraph(method, entryBCI, useProfilingInfo, compilationId, options, debug);
-        CompilationResult result = new CompilationResult();
+        CompilationResult result = new CompilationResult(compilationId);
         return compileHelper(CompilationResultBuilderFactory.Default, result, graph, method, entryBCI, useProfilingInfo, options);
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Mon Aug 28 14:43:32 2017 -0700
@@ -111,6 +111,7 @@
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
+import sun.misc.Unsafe;
 
 /**
  * Defines the {@link Plugins} used when running on HotSpot.
@@ -202,6 +203,7 @@
                 registerCRC32Plugins(invocationPlugins, config, replacementBytecodeProvider);
                 registerBigIntegerPlugins(invocationPlugins, config, replacementBytecodeProvider);
                 registerSHAPlugins(invocationPlugins, config, replacementBytecodeProvider);
+                registerUnsafePlugins(invocationPlugins, replacementBytecodeProvider);
                 StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacementBytecodeProvider, true);
 
                 for (NodeIntrinsicPluginFactory factory : GraalServices.load(NodeIntrinsicPluginFactory.class)) {
@@ -313,6 +315,17 @@
         r.registerMethodSubstitution(ReflectionSubstitutions.class, "getClassAccessFlags", Class.class);
     }
 
+    private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider replacementBytecodeProvider) {
+        Registration r;
+        if (Java8OrEarlier) {
+            r = new Registration(plugins, Unsafe.class, replacementBytecodeProvider);
+        } else {
+            r = new Registration(plugins, "jdk.internal.misc.Unsafe", replacementBytecodeProvider);
+        }
+        r.registerMethodSubstitution(HotSpotUnsafeSubstitutions.class, HotSpotUnsafeSubstitutions.copyMemoryName, "copyMemory", Receiver.class, Object.class, long.class, Object.class, long.class,
+                        long.class);
+    }
+
     private static final LocationIdentity INSTANCE_KLASS_CONSTANTS = NamedLocationIdentity.immutable("InstanceKlass::_constants");
     private static final LocationIdentity CONSTANT_POOL_LENGTH = NamedLocationIdentity.immutable("ConstantPool::_length");
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java	Mon Aug 28 14:43:32 2017 -0700
@@ -51,6 +51,7 @@
 import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA5_IMPL_COMPRESS;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA_IMPL_COMPRESS;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.SQUARE_TO_LEN;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.UNSAFE_ARRAYCOPY;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.VM_ERROR;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.WRONG_METHOD_HANDLER;
@@ -330,6 +331,8 @@
         registerCheckcastArraycopyDescriptor(true, c.checkcastArraycopyUninit);
         registerCheckcastArraycopyDescriptor(false, c.checkcastArraycopy);
 
+        registerForeignCall(UNSAFE_ARRAYCOPY, c.unsafeArraycopy, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.any());
+
         if (c.useMultiplyToLenIntrinsic()) {
             registerForeignCall(MULTIPLY_TO_LEN, c.multiplyToLen, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int));
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotUnsafeSubstitutions.java	Mon Aug 28 14:43:32 2017 -0700
@@ -0,0 +1,47 @@
+/*
+ * 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 static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.word.WordFactory;
+
+@ClassSubstitution(className = {"jdk.internal.misc.Unsafe", "sun.misc.Unsafe"})
+public class HotSpotUnsafeSubstitutions {
+
+    public static final String copyMemoryName = Java8OrEarlier ? "copyMemory" : "copyMemory0";
+
+    @SuppressWarnings("unused")
+    @MethodSubstitution(isStatic = false)
+    static void copyMemory(Object receiver, Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes) {
+        Word srcAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(srcBase, srcOffset));
+        Word dstAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(destBase, destOffset));
+        Word size = Word.signed(bytes);
+        HotSpotBackend.unsafeArraycopy(srcAddr, dstAddr, size);
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java	Mon Aug 28 14:43:32 2017 -0700
@@ -216,8 +216,9 @@
 
     @SuppressWarnings("try")
     private CompilationResult buildCompilationResult(DebugContext debug, final Backend backend) {
-        CompilationResult compResult = new CompilationResult(toString(), GeneratePIC.getValue(options));
-        final StructuredGraph graph = getGraph(debug, getStubCompilationId());
+        CompilationIdentifier compilationId = getStubCompilationId();
+        final StructuredGraph graph = getGraph(debug, compilationId);
+        CompilationResult compResult = new CompilationResult(compilationId, toString(), GeneratePIC.getValue(options));
 
         // Stubs cannot be recompiled so they cannot be compiled with assumptions
         assert graph.getAssumptions() == null;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceInterval.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceInterval.java	Mon Aug 28 14:43:32 2017 -0700
@@ -365,10 +365,6 @@
         return intTo;
     }
 
-    int numUsePositions() {
-        return numUsePos();
-    }
-
     public void setLocationHint(IntervalHint interval) {
         locationHint = interval;
     }
@@ -452,6 +448,10 @@
         return spillSt == SpillState.StartInMemory || (spillSt == SpillState.SpillStore && opId > spillDefinitionPos() && !canMaterialize());
     }
 
+    public boolean preSpilledAllocated() {
+        return spillState() == SpillState.StartInMemory && numUsePos() == 0 && !hasHint();
+    }
+
     // test intersection
     boolean intersects(TraceInterval i) {
         return intersectsAt(i) != -1;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java	Mon Aug 28 14:43:32 2017 -0700
@@ -541,16 +541,23 @@
                 assert instructionIndex == 0 : "not at start?" + instructionIndex;
                 handleTraceBegin(blocks[0]);
 
-                // fix spill state for phi/incoming intervals
-                for (TraceInterval interval : allocator.intervals()) {
-                    if (interval != null && interval.spillState().equals(SpillState.NoDefinitionFound) && interval.spillDefinitionPos() != -1) {
-                        // there was a definition in a phi/incoming
-                        interval.setSpillState(SpillState.NoSpillStore);
-                    }
-                }
                 if (TraceRAuseInterTraceHints.getValue(allocator.getLIR().getOptions())) {
                     addInterTraceHints();
                 }
+                // fix spill state for phi/incoming intervals
+                for (TraceInterval interval : allocator.intervals()) {
+                    if (interval != null) {
+                        if (interval.spillState().equals(SpillState.NoDefinitionFound) && interval.spillDefinitionPos() != -1) {
+                            // there was a definition in a phi/incoming
+                            interval.setSpillState(SpillState.NoSpillStore);
+                        }
+                        if (interval.preSpilledAllocated()) {
+                            // pre-spill unused, start in memory intervals
+                            allocator.assignSpillSlot(interval);
+                        }
+                    }
+                }
+
                 for (FixedInterval interval1 : allocator.fixedIntervals()) {
                     if (interval1 != null) {
                         /* We use [-1, 0] to avoid intersection with incoming values. */
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java	Mon Aug 28 14:43:32 2017 -0700
@@ -153,7 +153,7 @@
         @Override
         public boolean apply(TraceInterval i) {
             // all TraceIntervals are variable intervals
-            return true;
+            return !i.preSpilledAllocated();
         }
     };
     private static final Comparator<TraceInterval> SORT_BY_FROM_COMP = new Comparator<TraceInterval>() {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java	Mon Aug 28 14:43:32 2017 -0700
@@ -319,7 +319,7 @@
         assert !graph.isFrozen();
         ResolvedJavaMethod installedCodeOwner = graph.method();
         request = new Request<>(graph, installedCodeOwner, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL,
-                        graph.getProfilingInfo(), createSuites(getOptions()), createLIRSuites(getOptions()), new CompilationResult(), CompilationResultBuilderFactory.Default);
+                        graph.getProfilingInfo(), createSuites(getOptions()), createLIRSuites(getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
     }
 
     /**
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java	Mon Aug 28 14:43:32 2017 -0700
@@ -209,7 +209,6 @@
         int nodeCount = nodeOrder.nextOrderId;
         assert nodeOrder.orderIds.get(graph.start()) == START_NODE_ORDER_ID;
         assert nodeOrder.orderIds.get(graph.start().next()) == FIRST_NODE_ORDER_ID;
-        assert nodeCount == graph.getNodeCount() + 1;
 
         long[] nodeStartOffsets = new long[nodeCount];
         UnmodifiableMapCursor<Node, Integer> cursor = nodeOrder.orderIds.getEntries();
@@ -218,6 +217,7 @@
             Integer orderId = cursor.getValue();
 
             assert !(node instanceof AbstractBeginNode) || nodeOrder.orderIds.get(((AbstractBeginNode) node).next()) == orderId + BEGIN_NEXT_ORDER_ID_OFFSET;
+            assert nodeStartOffsets[orderId] == 0;
             nodeStartOffsets[orderId] = writer.getBytesWritten();
 
             /* Write out the type, properties, and edges. */
@@ -284,7 +284,6 @@
         writer.putUV(nodeOrder.maxFixedNodeOrderId);
         writer.putUV(nodeCount);
         for (int i = 0; i < nodeCount; i++) {
-            assert i == NULL_ORDER_ID || i == START_NODE_ORDER_ID || nodeStartOffsets[i] > 0;
             writer.putUV(metadataStart - nodeStartOffsets[i]);
         }
 
@@ -344,8 +343,25 @@
             } while (current != null);
 
             maxFixedNodeOrderId = nextOrderId - 1;
+
+            /*
+             * Emit all parameters consecutively at a known location (after all fixed nodes). This
+             * allows substituting parameters when inlining during decoding by pre-initializing the
+             * decoded node list.
+             *
+             * Note that not all parameters must be present (unused parameters are deleted after
+             * parsing). This leads to holes in the orderId, i.e., unused orderIds.
+             */
+            int parameterCount = graph.method().getSignature().getParameterCount(!graph.method().isStatic());
+            for (ParameterNode node : graph.getNodes(ParameterNode.TYPE)) {
+                assert orderIds.get(node) == null : "Parameter node must not be ordered yet";
+                assert node.index() < parameterCount : "Parameter index out of range";
+                orderIds.set(node, nextOrderId + node.index());
+            }
+            nextOrderId += parameterCount;
+
             for (Node node : graph.getNodes()) {
-                assert (node instanceof FixedNode) == (orderIds.get(node) != null) : "all fixed nodes must be ordered: " + node;
+                assert (node instanceof FixedNode || node instanceof ParameterNode) == (orderIds.get(node) != null) : "all fixed nodes and ParameterNodes must be ordered: " + node;
                 add(node);
             }
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java	Mon Aug 28 14:43:32 2017 -0700
@@ -37,6 +37,7 @@
 import org.graalvm.compiler.bytecode.BytecodeDisassembler;
 import org.graalvm.compiler.code.CompilationResult;
 import org.graalvm.compiler.code.DisassemblerProvider;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.core.common.alloc.Trace;
 import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
@@ -72,6 +73,7 @@
     private CFGPrinter cfgPrinter;
     private File cfgFile;
     private JavaMethod curMethod;
+    private CompilationIdentifier curCompilation;
     private List<String> curDecorators = Collections.emptyList();
 
     @Override
@@ -92,6 +94,7 @@
      */
     private boolean checkMethodScope(DebugContext debug) {
         JavaMethod method = null;
+        CompilationIdentifier compilation = null;
         ArrayList<String> decorators = new ArrayList<>();
         for (Object o : debug.context()) {
             if (o instanceof JavaMethod) {
@@ -102,22 +105,33 @@
                 if (graph.method() != null) {
                     method = graph.method();
                     decorators.clear();
+                    compilation = graph.compilationId();
                 }
             } else if (o instanceof DebugDumpScope) {
                 DebugDumpScope debugDumpScope = (DebugDumpScope) o;
                 if (debugDumpScope.decorator) {
                     decorators.add(debugDumpScope.name);
                 }
+            } else if (o instanceof CompilationResult) {
+                CompilationResult compilationResult = (CompilationResult) o;
+                compilation = compilationResult.getCompilationId();
             }
         }
 
-        if (method == null) {
+        if (method == null && compilation == null) {
             return false;
         }
 
-        if (!method.equals(curMethod) || !curDecorators.equals(decorators)) {
-            cfgPrinter.printCompilation(method);
+        if (compilation != null) {
+            if (!compilation.equals(curCompilation) || !curDecorators.equals(decorators)) {
+                cfgPrinter.printCompilation(compilation);
+            }
+        } else {
+            if (!method.equals(curMethod) || !curDecorators.equals(decorators)) {
+                cfgPrinter.printCompilation(method);
+            }
         }
+        curCompilation = compilation;
         curMethod = method;
         curDecorators = decorators;
         return true;
@@ -277,6 +291,7 @@
             cfgPrinter = null;
             curDecorators = Collections.emptyList();
             curMethod = null;
+            curCompilation = null;
         }
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CompilationPrinter.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CompilationPrinter.java	Mon Aug 28 14:43:32 2017 -0700
@@ -31,6 +31,7 @@
 import java.util.List;
 import java.util.Map;
 
+import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.debug.LogStream;
 import org.graalvm.compiler.debug.TTY;
 import org.graalvm.compiler.lir.util.IndexedValueMap;
@@ -115,12 +116,25 @@
     /**
      * Prints a compilation timestamp for a given method.
      *
-     * @param method the method for which a timestamp will be printed
+     * @param javaMethod the method for which a timestamp will be printed
      */
-    public void printCompilation(JavaMethod method) {
+    public void printCompilation(JavaMethod javaMethod) {
+        printCompilation(javaMethod.format("%H::%n"), javaMethod.format("%f %r %H.%n(%p)"));
+    }
+
+    /**
+     * Prints a compilation id.
+     *
+     * @param compilationId the compilation method for which an id will be printed
+     */
+    public void printCompilation(CompilationIdentifier compilationId) {
+        printCompilation(compilationId.toString(CompilationIdentifier.Verbosity.DETAILED), compilationId.toString(CompilationIdentifier.Verbosity.DETAILED));
+    }
+
+    private void printCompilation(final String name, String method) {
         begin("compilation");
-        out.print("name \" ").print(method.format("%H::%n")).println('"');
-        out.print("method \"").print(method.format("%f %r %H.%n(%p)")).println('"');
+        out.print("name \" ").print(name).println('"');
+        out.print("method \"").print(method).println('"');
         out.print("date ").println(System.currentTimeMillis());
         end("compilation");
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/ClassSubstitutionVerifier.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/ClassSubstitutionVerifier.java	Mon Aug 28 14:43:32 2017 -0700
@@ -95,10 +95,13 @@
             TypeElement typeElement = null;
             for (String className : classNames) {
                 typeElement = env.getElementUtils().getTypeElement(className);
-                if (typeElement == null && !optional) {
-                    env.getMessager().printMessage(Kind.ERROR, String.format("The class '%s' was not found on the classpath.", stringValue), sourceElement, classSubstition, stringValue);
+                if (typeElement != null) {
+                    break;
                 }
             }
+            if (typeElement == null && !optional) {
+                env.getMessager().printMessage(Kind.ERROR, String.format("The class '%s' was not found on the classpath.", stringValue), sourceElement, classSubstition, stringValue);
+            }
 
             return typeElement;
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java	Mon Aug 28 14:43:32 2017 -0700
@@ -707,10 +707,22 @@
             }
         }
 
+        LoopScope inlineLoopScope = createInitialLoopScope(inlineScope, predecessor);
+
+        /*
+         * The GraphEncoder assigns parameters a nodeId immediately after the fixed nodes.
+         * Initializing createdNodes here avoid decoding and immediately replacing the
+         * ParameterNodes.
+         */
+        int firstArgumentNodeId = inlineScope.maxFixedNodeOrderId + 1;
+        for (int i = 0; i < arguments.length; i++) {
+            inlineLoopScope.createdNodes[firstArgumentNodeId + i] = arguments[i];
+        }
+
         /*
          * Do the actual inlining by returning the initial loop scope for the inlined method scope.
          */
-        return createInitialLoopScope(inlineScope, predecessor);
+        return inlineLoopScope;
     }
 
     @Override
@@ -1028,9 +1040,7 @@
         if (node instanceof ParameterNode) {
             ParameterNode param = (ParameterNode) node;
             if (methodScope.isInlinedMethod()) {
-                Node result = methodScope.arguments[param.index()];
-                assert result != null;
-                return result;
+                throw GraalError.shouldNotReachHere("Parameter nodes are already registered when the inlined scope is created");
 
             } else if (parameterPlugin != null) {
                 assert !methodScope.isInlinedMethod();
--- a/hotspot/src/share/vm/aot/aotCodeHeap.cpp	Mon Aug 28 16:40:01 2017 +0000
+++ b/hotspot/src/share/vm/aot/aotCodeHeap.cpp	Mon Aug 28 14:43:32 2017 -0700
@@ -478,6 +478,8 @@
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_disjoint_arraycopy", address, StubRoutines::_arrayof_oop_disjoint_arraycopy);
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit", address, StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit);
 
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_unsafe_arraycopy", address, StubRoutines::_unsafe_arraycopy);
+
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_checkcast_arraycopy", address, StubRoutines::_checkcast_arraycopy);
 
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_aescrypt_encryptBlock", address, StubRoutines::_aescrypt_encryptBlock);