changeset 13088:514e809bd97d

Merge.
author Doug Simon <doug.simon@oracle.com>
date Wed, 20 Nov 2013 15:58:58 +0100
parents ec3e4f35e466 (current diff) 5341a7fca039 (diff)
children 77fbf02f701c
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostLoweringProvider.java
diffstat 37 files changed, 1067 insertions(+), 897 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Wed Nov 20 15:58:58 2013 +0100
@@ -1874,6 +1874,7 @@
                 printLir("After register number assignment", true);
                 EdgeMoveOptimizer.optimize(ir);
                 ControlFlowOptimizer.optimize(ir);
+                NullCheckOptimizer.optimize(ir, target.implicitNullCheckLimit);
                 printLir("After control flow optimization", false);
             }
         });
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Wed Nov 20 15:58:58 2013 +0100
@@ -52,12 +52,13 @@
         assert host == null;
         TargetDescription target = createTarget(runtime.getConfig());
 
+        HotSpotRegistersProvider registers = createRegisters();
         HotSpotMetaAccessProvider metaAccess = createMetaAccess(runtime);
         HotSpotCodeCacheProvider codeCache = createCodeCache(runtime, target);
         HotSpotConstantReflectionProvider constantReflection = createConstantReflection(runtime);
         Value[] nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(runtime.getConfig(), codeCache.getRegisterConfig());
         HotSpotHostForeignCallsProvider foreignCalls = createForeignCalls(runtime, metaAccess, codeCache, nativeABICallerSaveRegisters);
-        HotSpotHostLoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls);
+        HotSpotLoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers);
         // Replacements cannot have speculative optimizations since they have
         // to be valid for the entire run of the VM.
         Assumptions assumptions = new Assumptions(false);
@@ -65,7 +66,6 @@
         Replacements replacements = createReplacements(runtime, assumptions, p);
         HotSpotDisassemblerProvider disassembler = createDisassembler(runtime);
         HotSpotSuitesProvider suites = createSuites(runtime);
-        HotSpotRegisters registers = createRegisters();
         HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers);
 
         return createBackend(runtime, providers);
@@ -75,7 +75,7 @@
         return new AMD64HotSpotBackend(runtime, providers);
     }
 
-    protected HotSpotRegisters createRegisters() {
+    protected HotSpotRegistersProvider createRegisters() {
         return new HotSpotRegisters(AMD64.r15, AMD64.r12, AMD64.rsp);
     }
 
@@ -108,8 +108,8 @@
         return new HotSpotSuitesProvider(runtime);
     }
 
-    protected AMD64HotSpotLoweringProvider createLowerer(HotSpotGraalRuntime runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls) {
-        return new AMD64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls);
+    protected AMD64HotSpotLoweringProvider createLowerer(HotSpotGraalRuntime runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
+        return new AMD64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers);
     }
 
     protected Value[] createNativeABICallerSaveRegisters(HotSpotVMConfig config, RegisterConfig regConfig) {
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed Nov 20 15:58:58 2013 +0100
@@ -76,7 +76,7 @@
     }
 
     @Override
-    protected HotSpotProviders getProviders() {
+    public HotSpotProviders getProviders() {
         return (HotSpotProviders) super.getProviders();
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLoweringProvider.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLoweringProvider.java	Wed Nov 20 15:58:58 2013 +0100
@@ -31,12 +31,12 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.amd64.*;
 
-public class AMD64HotSpotLoweringProvider extends HotSpotHostLoweringProvider {
+public class AMD64HotSpotLoweringProvider extends HotSpotLoweringProvider {
 
     private AMD64ConvertSnippets.Templates convertSnippets;
 
-    public AMD64HotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls) {
-        super(runtime, metaAccess, foreignCalls);
+    public AMD64HotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
+        super(runtime, metaAccess, foreignCalls, registers);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java	Wed Nov 20 15:58:58 2013 +0100
@@ -64,6 +64,14 @@
         return true;
     }
 
+    @Override
+    public void completeInitialization() {
+        final HotSpotProviders providers = getProviders();
+        HotSpotVMConfig config = getRuntime().getConfig();
+        final HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer();
+        lowerer.initialize(providers, config);
+    }
+
     /**
      * Use the HSAIL register set when the compilation target is HSAIL.
      */
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java	Wed Nov 20 15:58:58 2013 +0100
@@ -38,11 +38,12 @@
     public HSAILHotSpotBackend createBackend(HotSpotGraalRuntime runtime, HotSpotBackend hostBackend) {
         HotSpotProviders host = hostBackend.getProviders();
 
+        HotSpotRegisters registers = new HotSpotRegisters(Register.None, Register.None, Register.None);
         HotSpotMetaAccessProvider metaAccess = host.getMetaAccess();
         HSAILHotSpotCodeCacheProvider codeCache = new HSAILHotSpotCodeCacheProvider(runtime, createTarget());
         ConstantReflectionProvider constantReflection = host.getConstantReflection();
         HotSpotForeignCallsProvider foreignCalls = new HSAILHotSpotForeignCallsProvider(runtime, metaAccess, codeCache);
-        LoweringProvider lowerer = new HSAILHotSpotLoweringProvider(host.getLowerer());
+        LoweringProvider lowerer = new HSAILHotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers);
         // Replacements cannot have speculative optimizations since they have
         // to be valid for the entire run of the VM.
         Assumptions assumptions = new Assumptions(false);
@@ -50,7 +51,6 @@
         Replacements replacements = new HSAILHotSpotReplacementsImpl(p, assumptions, host.getReplacements());
         HotSpotDisassemblerProvider disassembler = host.getDisassembler();
         HotSpotSuitesProvider suites = host.getSuites();
-        HotSpotRegisters registers = new HotSpotRegisters(Register.None, Register.None, Register.None);
         HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers);
 
         return new HSAILHotSpotBackend(runtime, providers);
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLoweringProvider.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLoweringProvider.java	Wed Nov 20 15:58:58 2013 +0100
@@ -22,30 +22,27 @@
  */
 package com.oracle.graal.hotspot.hsail;
 
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class HSAILHotSpotLoweringProvider implements LoweringProvider {
+public class HSAILHotSpotLoweringProvider extends HotSpotLoweringProvider {
 
-    private LoweringProvider host;
-
-    public HSAILHotSpotLoweringProvider(LoweringProvider host) {
-        this.host = host;
+    public HSAILHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
+        super(runtime, metaAccess, foreignCalls, registers);
     }
 
+    @Override
     public void lower(Node n, LoweringTool tool) {
         if (n instanceof ConvertNode) {
-            // TODO
             return;
         } else {
-            host.lower(n, tool);
+            super.lower(n, tool);
         }
     }
 
-    public ValueNode reconstructArrayIndex(LocationNode location) {
-        throw GraalInternalError.unimplemented();
-    }
 }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java	Wed Nov 20 15:58:58 2013 +0100
@@ -62,8 +62,8 @@
 
     @Override
     public StructuredGraph getSnippet(ResolvedJavaMethod method) {
-        // TODO must work in cooperation with HSAILHotSpotLoweringProvider
-        return null;
+        // Must work in cooperation with HSAILHotSpotLoweringProvider
+        return host.getSnippet(method);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Wed Nov 20 15:58:58 2013 +0100
@@ -50,12 +50,13 @@
         assert host == null;
         TargetDescription target = createTarget();
 
+        HotSpotRegistersProvider registers = new HotSpotRegisters(Register.None, Register.None, Register.None); // FIXME
         HotSpotMetaAccessProvider metaAccess = new HotSpotMetaAccessProvider(runtime);
         HotSpotCodeCacheProvider codeCache = new SPARCHotSpotCodeCacheProvider(runtime, target);
         HotSpotConstantReflectionProvider constantReflection = new HotSpotConstantReflectionProvider(runtime);
         Value[] nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(runtime.getConfig(), codeCache.getRegisterConfig());
         HotSpotForeignCallsProvider foreignCalls = new SPARCHotSpotForeignCallsProvider(runtime, metaAccess, codeCache, nativeABICallerSaveRegisters);
-        LoweringProvider lowerer = new SPARCHotSpotLoweringProvider(runtime, metaAccess, foreignCalls);
+        LoweringProvider lowerer = new SPARCHotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers);
         // Replacements cannot have speculative optimizations since they have
         // to be valid for the entire run of the VM.
         Assumptions assumptions = new Assumptions(false);
@@ -63,7 +64,6 @@
         HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, runtime.getConfig(), assumptions);
         HotSpotDisassemblerProvider disassembler = new HotSpotDisassemblerProvider(runtime);
         HotSpotSuitesProvider suites = new HotSpotSuitesProvider(runtime);
-        HotSpotRegisters registers = new HotSpotRegisters(Register.None, Register.None, Register.None); // FIXME
         HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers);
 
         return new SPARCHotSpotBackend(runtime, providers);
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Wed Nov 20 15:58:58 2013 +0100
@@ -57,7 +57,7 @@
     }
 
     @Override
-    protected HotSpotProviders getProviders() {
+    public HotSpotProviders getProviders() {
         return (HotSpotProviders) super.getProviders();
     }
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLoweringProvider.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLoweringProvider.java	Wed Nov 20 15:58:58 2013 +0100
@@ -30,10 +30,10 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
-public class SPARCHotSpotLoweringProvider extends HotSpotHostLoweringProvider {
+public class SPARCHotSpotLoweringProvider extends HotSpotLoweringProvider {
 
-    public SPARCHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls) {
-        super(runtime, metaAccess, foreignCalls);
+    public SPARCHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
+        super(runtime, metaAccess, foreignCalls, registers);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Wed Nov 20 15:58:58 2013 +0100
@@ -45,7 +45,7 @@
         final HotSpotProviders providers = getProviders();
         HotSpotVMConfig config = getRuntime().getConfig();
         HotSpotHostForeignCallsProvider foreignCalls = (HotSpotHostForeignCallsProvider) providers.getForeignCalls();
-        final HotSpotHostLoweringProvider lowerer = (HotSpotHostLoweringProvider) providers.getLowerer();
+        final HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer();
         foreignCalls.initialize(providers, config);
         lowerer.initialize(providers, config);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Wed Nov 20 15:58:58 2013 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -55,4 +56,6 @@
      * Gets a stack slot for a lock at a given lock nesting depth.
      */
     StackSlot getLockSlot(int lockDepth);
+
+    HotSpotProviders getProviders();
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Wed Nov 20 15:58:58 2013 +0100
@@ -39,12 +39,7 @@
      * Compiles a method to machine code. This method is called from the VM
      * (VMToCompiler::compileMethod).
      */
-    void compileMethod(long metaspaceMethod, HotSpotResolvedObjectType holder, int entryBCI, boolean blocking) throws Throwable;
-
-    /**
-     * Compiles a method to machine code.
-     */
-    void compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, boolean blocking) throws Throwable;
+    void compileMethod(long metaspaceMethod, HotSpotResolvedObjectType holder, int entryBCI, boolean blocking);
 
     /**
      * Notifies this object of statistics for a completed compilation.
@@ -60,7 +55,7 @@
      */
     void notifyCompilationDone(int id, HotSpotResolvedJavaMethod method, boolean osr, int processedBytecodes, long time, TimeUnit timeUnit, HotSpotInstalledCode installedCode);
 
-    void shutdownCompiler() throws Throwable;
+    void shutdownCompiler() throws Exception;
 
     void startCompiler(boolean bootstrapEnabled, long statsAddress) throws Throwable;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed Nov 20 15:58:58 2013 +0100
@@ -30,6 +30,7 @@
 
 import java.io.*;
 import java.lang.reflect.*;
+import java.security.*;
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.concurrent.atomic.*;
@@ -352,11 +353,18 @@
         }
     }
 
-    public void shutdownCompiler() throws Throwable {
+    public void shutdownCompiler() throws Exception {
         try {
             assert !CompilationTask.withinEnqueue.get();
             CompilationTask.withinEnqueue.set(Boolean.TRUE);
-            shutdownCompileQueue(compileQueue);
+            // We have to use a privileged action here because shutting down the compiler might be
+            // called from user code which very likely contains unprivileged frames.
+            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+                public Void run() throws Exception {
+                    shutdownCompileQueue(compileQueue);
+                    return null;
+                }
+            });
         } finally {
             CompilationTask.withinEnqueue.set(Boolean.FALSE);
         }
@@ -535,15 +543,22 @@
     }
 
     @Override
-    public void compileMethod(long metaspaceMethod, final HotSpotResolvedObjectType holder, final int entryBCI, boolean blocking) throws Throwable {
-        HotSpotResolvedJavaMethod method = holder.createMethod(metaspaceMethod);
-        compileMethod(method, entryBCI, blocking);
+    public void compileMethod(long metaspaceMethod, final HotSpotResolvedObjectType holder, final int entryBCI, final boolean blocking) {
+        final HotSpotResolvedJavaMethod method = holder.createMethod(metaspaceMethod);
+        // We have to use a privileged action here because compilations are enqueued from user code
+        // which very likely contains unprivileged frames.
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                compileMethod(method, entryBCI, blocking);
+                return null;
+            }
+        });
     }
 
     /**
      * Compiles a method to machine code.
      */
-    public void compileMethod(final HotSpotResolvedJavaMethod method, final int entryBCI, boolean blocking) throws Throwable {
+    public void compileMethod(final HotSpotResolvedJavaMethod method, final int entryBCI, final boolean blocking) {
         boolean osrCompilation = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
         if (osrCompilation && bootstrapRunning) {
             // no OSR compilations during bootstrap - the compiler is just too slow at this point,
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostLoweringProvider.java	Wed Nov 20 15:58:23 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,725 +0,0 @@
-/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.meta;
-
-import static com.oracle.graal.api.code.MemoryBarriers.*;
-import static com.oracle.graal.api.meta.DeoptimizationAction.*;
-import static com.oracle.graal.api.meta.DeoptimizationReason.*;
-import static com.oracle.graal.api.meta.LocationIdentity.*;
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.hotspot.meta.HotSpotHostForeignCallsProvider.*;
-import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
-import static com.oracle.graal.nodes.java.ArrayLengthNode.*;
-import static com.oracle.graal.phases.GraalOptions.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.debug.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.debug.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.virtual.*;
-import com.oracle.graal.replacements.*;
-
-/**
- * HotSpot implementation of {@link LoweringProvider}.
- */
-public class HotSpotHostLoweringProvider implements LoweringProvider {
-
-    protected final HotSpotGraalRuntime runtime;
-    protected final MetaAccessProvider metaAccess;
-    protected final ForeignCallsProvider foreignCalls;
-
-    private CheckCastDynamicSnippets.Templates checkcastDynamicSnippets;
-    private InstanceOfSnippets.Templates instanceofSnippets;
-    private NewObjectSnippets.Templates newObjectSnippets;
-    private MonitorSnippets.Templates monitorSnippets;
-    protected WriteBarrierSnippets.Templates writeBarrierSnippets;
-    private BoxingSnippets.Templates boxingSnippets;
-    private LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
-    private UnsafeLoadSnippets.Templates unsafeLoadSnippets;
-
-    public HotSpotHostLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls) {
-        this.runtime = runtime;
-        this.metaAccess = metaAccess;
-        this.foreignCalls = foreignCalls;
-    }
-
-    public void initialize(HotSpotProviders providers, HotSpotVMConfig config) {
-        TargetDescription target = providers.getCodeCache().getTarget();
-        checkcastDynamicSnippets = new CheckCastDynamicSnippets.Templates(providers, target);
-        instanceofSnippets = new InstanceOfSnippets.Templates(providers, target);
-        newObjectSnippets = new NewObjectSnippets.Templates(providers, target);
-        monitorSnippets = new MonitorSnippets.Templates(providers, target, config.useFastLocking);
-        writeBarrierSnippets = new WriteBarrierSnippets.Templates(providers, target);
-        boxingSnippets = new BoxingSnippets.Templates(providers, target);
-        exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target);
-        unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target);
-        providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target));
-    }
-
-    @Override
-    public void lower(Node n, LoweringTool tool) {
-        HotSpotVMConfig config = runtime.getConfig();
-        StructuredGraph graph = (StructuredGraph) n.graph();
-
-        Kind wordKind = runtime.getTarget().wordKind;
-        if (n instanceof ArrayLengthNode) {
-            ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n;
-            ValueNode array = arrayLengthNode.array();
-            ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt(),
-                            BarrierType.NONE, false));
-            tool.createNullCheckGuard(arrayLengthRead, array);
-            graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
-        } else if (n instanceof Invoke) {
-            Invoke invoke = (Invoke) n;
-            if (invoke.callTarget() instanceof MethodCallTargetNode) {
-
-                MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
-                NodeInputList<ValueNode> parameters = callTarget.arguments();
-                ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
-                GuardingNode receiverNullCheck = null;
-                if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !ObjectStamp.isObjectNonNull(receiver)) {
-                    receiverNullCheck = tool.createNullCheckGuard(invoke, receiver);
-                }
-                JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
-
-                LoweredCallTargetNode loweredCallTarget = null;
-                if (callTarget.invokeKind() == InvokeKind.Virtual && InlineVTableStubs.getValue() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
-
-                    HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
-                    if (!hsMethod.getDeclaringClass().isInterface()) {
-                        if (hsMethod.isInVirtualMethodTable()) {
-                            int vtableEntryOffset = hsMethod.vtableEntryOffset();
-                            assert vtableEntryOffset > 0;
-                            FloatingReadNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck);
-
-                            ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod);
-                            // We use LocationNode.ANY_LOCATION for the reads that access the
-                            // compiled code entry as HotSpot does not guarantee they are final
-                            // values.
-                            ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph),
-                                            StampFactory.forKind(wordKind), BarrierType.NONE, false));
-
-                            loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
-                                            CallingConvention.Type.JavaCall));
-
-                            graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
-                            graph.addAfterFixed(metaspaceMethod, compiledEntry);
-                        }
-                    }
-                }
-
-                if (loweredCallTarget == null) {
-                    loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall,
-                                    callTarget.invokeKind()));
-                }
-                callTarget.replaceAndDelete(loweredCallTarget);
-            }
-        } else if (n instanceof LoadFieldNode) {
-            LoadFieldNode loadField = (LoadFieldNode) n;
-            HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field();
-            ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : loadField.object();
-            assert loadField.kind() != Kind.Illegal;
-            BarrierType barrierType = getFieldLoadBarrierType(field);
-            ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object)));
-            graph.replaceFixedWithFixed(loadField, memoryRead);
-            tool.createNullCheckGuard(memoryRead, object);
-
-            if (loadField.isVolatile()) {
-                MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
-                graph.addBeforeFixed(memoryRead, preMembar);
-                MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
-                graph.addAfterFixed(memoryRead, postMembar);
-            }
-        } else if (n instanceof StoreFieldNode) {
-            StoreFieldNode storeField = (StoreFieldNode) n;
-            HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field();
-            ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : storeField.object();
-            BarrierType barrierType = getFieldStoreBarrierType(storeField);
-            WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field, false), barrierType, storeField.field().getKind() == Kind.Object));
-            tool.createNullCheckGuard(memoryWrite, object);
-            memoryWrite.setStateAfter(storeField.stateAfter());
-            graph.replaceFixedWithFixed(storeField, memoryWrite);
-            FixedWithNextNode last = memoryWrite;
-            FixedWithNextNode first = memoryWrite;
-
-            if (storeField.isVolatile()) {
-                MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
-                graph.addBeforeFixed(first, preMembar);
-                MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
-                graph.addAfterFixed(last, postMembar);
-            }
-        } else if (n instanceof CompareAndSwapNode) {
-            // Separate out GC barrier semantics
-            CompareAndSwapNode cas = (CompareAndSwapNode) n;
-            LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1);
-            LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, cas.expected(), cas.newValue(), getCompareAndSwapBarrier(cas),
-                            cas.expected().kind() == Kind.Object));
-            atomicNode.setStateAfter(cas.stateAfter());
-            graph.replaceFixedWithFixed(cas, atomicNode);
-        } else if (n instanceof LoadIndexedNode) {
-            LoadIndexedNode loadIndexed = (LoadIndexedNode) n;
-            GuardingNode boundsCheck = createBoundsCheck(loadIndexed, tool);
-            Kind elementKind = loadIndexed.elementKind();
-            LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false);
-            ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp(), BarrierType.NONE, elementKind == Kind.Object));
-            memoryRead.setGuard(boundsCheck);
-            graph.replaceFixedWithFixed(loadIndexed, memoryRead);
-        } else if (n instanceof StoreIndexedNode) {
-            StoreIndexedNode storeIndexed = (StoreIndexedNode) n;
-            GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool);
-            Kind elementKind = storeIndexed.elementKind();
-            LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index(), false);
-            ValueNode value = storeIndexed.value();
-            ValueNode array = storeIndexed.array();
-
-            CheckCastNode checkcastNode = null;
-            CheckCastDynamicNode checkcastDynamicNode = null;
-            if (elementKind == Kind.Object && !ObjectStamp.isObjectAlwaysNull(value)) {
-                // Store check!
-                ResolvedJavaType arrayType = ObjectStamp.typeOrNull(array);
-                if (arrayType != null && ObjectStamp.isExactType(array)) {
-                    ResolvedJavaType elementType = arrayType.getComponentType();
-                    if (!MetaUtil.isJavaLangObject(elementType)) {
-                        checkcastNode = graph.add(new CheckCastNode(elementType, value, null, true));
-                        graph.addBeforeFixed(storeIndexed, checkcastNode);
-                        value = checkcastNode;
-                    }
-                } else {
-                    FloatingReadNode arrayClass = createReadHub(graph, wordKind, array, boundsCheck);
-                    LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph);
-                    /*
-                     * Anchor the read of the element klass to the cfg, because it is only valid
-                     * when arrayClass is an object class, which might not be the case in other
-                     * parts of the compiled method.
-                     */
-                    FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind), BeginNode.prevBegin(storeIndexed)));
-                    checkcastDynamicNode = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true));
-                    graph.addBeforeFixed(storeIndexed, checkcastDynamicNode);
-                    value = checkcastDynamicNode;
-                }
-            }
-            BarrierType barrierType = getArrayStoreBarrierType(storeIndexed);
-            WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation, barrierType, elementKind == Kind.Object));
-            memoryWrite.setGuard(boundsCheck);
-            memoryWrite.setStateAfter(storeIndexed.stateAfter());
-            graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
-
-            // Lower the associated checkcast node.
-            if (checkcastNode != null) {
-                checkcastNode.lower(tool);
-            } else if (checkcastDynamicNode != null) {
-                checkcastDynamicSnippets.lower(checkcastDynamicNode);
-            }
-        } else if (n instanceof UnsafeLoadNode) {
-            UnsafeLoadNode load = (UnsafeLoadNode) n;
-            if (load.getGuardingCondition() != null) {
-                boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
-                ConditionAnchorNode valueAnchorNode = graph.add(new ConditionAnchorNode(load.getGuardingCondition()));
-                LocationNode location = createLocation(load);
-                ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), valueAnchorNode, BarrierType.NONE, compressible));
-                load.replaceAtUsages(memoryRead);
-                graph.replaceFixedWithFixed(load, valueAnchorNode);
-                graph.addAfterFixed(valueAnchorNode, memoryRead);
-            } else if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) {
-                assert load.kind() != Kind.Illegal;
-                boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
-                if (addReadBarrier(load)) {
-                    unsafeLoadSnippets.lower(load, tool);
-                } else {
-                    LocationNode location = createLocation(load);
-                    ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), BarrierType.NONE, compressible));
-                    // An unsafe read must not float outside its block otherwise
-                    // it may float above an explicit null check on its object.
-                    memoryRead.setGuard(AbstractBeginNode.prevBegin(load));
-                    graph.replaceFixedWithFixed(load, memoryRead);
-                }
-            }
-        } else if (n instanceof UnsafeStoreNode) {
-            UnsafeStoreNode store = (UnsafeStoreNode) n;
-            LocationNode location = createLocation(store);
-            ValueNode object = store.object();
-            BarrierType barrierType = getUnsafeStoreBarrierType(store);
-            WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType, store.value().kind() == Kind.Object));
-            write.setStateAfter(store.stateAfter());
-            graph.replaceFixedWithFixed(store, write);
-        } else if (n instanceof LoadHubNode) {
-            LoadHubNode loadHub = (LoadHubNode) n;
-            assert loadHub.kind() == wordKind;
-            ValueNode object = loadHub.object();
-            GuardingNode guard = loadHub.getGuard();
-            FloatingReadNode hub = createReadHub(graph, wordKind, object, guard);
-            graph.replaceFloating(loadHub, hub);
-        } else if (n instanceof LoadMethodNode) {
-            LoadMethodNode loadMethodNode = (LoadMethodNode) n;
-            ResolvedJavaMethod method = loadMethodNode.getMethod();
-            ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, loadMethodNode.getHub(), method);
-            graph.replaceFixed(loadMethodNode, metaspaceMethod);
-        } else if (n instanceof StoreHubNode) {
-            StoreHubNode storeHub = (StoreHubNode) n;
-            WriteNode hub = createWriteHub(graph, wordKind, storeHub.getObject(), storeHub.getValue());
-            graph.replaceFixed(storeHub, hub);
-        } else if (n instanceof CommitAllocationNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-                CommitAllocationNode commit = (CommitAllocationNode) n;
-                ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
-                BitSet omittedValues = new BitSet();
-                int valuePos = 0;
-                for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-                    VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
-                    int entryCount = virtual.entryCount();
-                    FixedWithNextNode newObject;
-                    if (virtual instanceof VirtualInstanceNode) {
-                        newObject = graph.add(new NewInstanceNode(virtual.type(), true));
-                        graph.addBeforeFixed(commit, newObject);
-                        allocations[objIndex] = newObject;
-                        for (int i = 0; i < entryCount; i++) {
-                            ValueNode value = commit.getValues().get(valuePos);
-                            if (value instanceof VirtualObjectNode) {
-                                value = allocations[commit.getVirtualObjects().indexOf(value)];
-                            }
-                            if (value == null) {
-                                omittedValues.set(valuePos);
-                            } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
-                                // Constant.illegal is always the defaultForKind, so it is skipped
-                                VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
-                                Kind accessKind;
-                                HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) virtualInstance.field(i);
-                                if (value.kind().getStackKind() != field.getKind().getStackKind()) {
-                                    assert value.kind() == Kind.Long || value.kind() == Kind.Double;
-                                    accessKind = value.kind();
-                                } else {
-                                    accessKind = field.getKind();
-                                }
-                                ConstantLocationNode location = ConstantLocationNode.create(INIT_LOCATION, accessKind, field.offset(), graph);
-                                BarrierType barrierType = (virtualInstance.field(i).getKind() == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE;
-                                WriteNode write = new WriteNode(newObject, value, location, barrierType, virtualInstance.field(i).getKind() == Kind.Object);
-                                graph.addAfterFixed(newObject, graph.add(write));
-                            }
-                            valuePos++;
-                        }
-                    } else {
-                        ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType();
-                        newObject = graph.add(new NewArrayNode(element, ConstantNode.forInt(entryCount, graph), true));
-                        graph.addBeforeFixed(commit, newObject);
-                        allocations[objIndex] = newObject;
-                        for (int i = 0; i < entryCount; i++) {
-                            ValueNode value = commit.getValues().get(valuePos);
-                            if (value instanceof VirtualObjectNode) {
-                                value = allocations[commit.getVirtualObjects().indexOf(value)];
-                            }
-                            if (value == null) {
-                                omittedValues.set(valuePos);
-                            } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
-                                // Constant.illegal is always the defaultForKind, so it is skipped
-                                Kind componentKind = element.getKind();
-                                Kind accessKind;
-                                Kind valueKind = value.kind();
-                                if (valueKind.getStackKind() != componentKind.getStackKind()) {
-                                    // Given how Truffle uses unsafe, it can happen that
-                                    // valueKind is Kind.Int
-                                    // assert valueKind == Kind.Long || valueKind == Kind.Double;
-                                    accessKind = valueKind;
-                                } else {
-                                    accessKind = componentKind;
-                                }
-
-                                int scale = getScalingFactor(componentKind);
-                                ConstantLocationNode location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(componentKind) + i * scale, graph);
-                                BarrierType barrierType = (componentKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE;
-                                WriteNode write = new WriteNode(newObject, value, location, barrierType, componentKind == Kind.Object);
-                                graph.addAfterFixed(newObject, graph.add(write));
-                            }
-                            valuePos++;
-                        }
-                    }
-                }
-                valuePos = 0;
-
-                for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-                    VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
-                    int entryCount = virtual.entryCount();
-                    ValueNode newObject = allocations[objIndex];
-                    if (virtual instanceof VirtualInstanceNode) {
-                        for (int i = 0; i < entryCount; i++) {
-                            if (omittedValues.get(valuePos)) {
-                                ValueNode value = commit.getValues().get(valuePos);
-                                assert value instanceof VirtualObjectNode;
-                                ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
-                                if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
-                                    VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
-                                    assert virtualInstance.field(i).getKind() == Kind.Object;
-                                    WriteNode write = new WriteNode(newObject, allocValue, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i), true),
-                                                    BarrierType.IMPRECISE, true);
-                                    graph.addBeforeFixed(commit, graph.add(write));
-                                }
-                            }
-                            valuePos++;
-                        }
-                    } else {
-                        ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType();
-                        for (int i = 0; i < entryCount; i++) {
-                            if (omittedValues.get(valuePos)) {
-                                ValueNode value = commit.getValues().get(valuePos);
-                                assert value instanceof VirtualObjectNode;
-                                ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
-                                if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
-                                    assert allocValue.kind() == Kind.Object;
-                                    WriteNode write = new WriteNode(newObject, allocValue, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph), true), BarrierType.PRECISE,
-                                                    true);
-                                    graph.addBeforeFixed(commit, graph.add(write));
-                                }
-                            }
-                            valuePos++;
-                        }
-                    }
-                }
-
-                for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-                    FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
-                    allocations[objIndex] = anchor;
-                    graph.addBeforeFixed(commit, anchor);
-                }
-                for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-                    for (int lockDepth : commit.getLocks().get(objIndex)) {
-                        MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], lockDepth));
-                        graph.addBeforeFixed(commit, enter);
-                        enter.lower(tool);
-                    }
-                }
-                for (Node usage : commit.usages().snapshot()) {
-                    AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
-                    int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
-                    graph.replaceFloating(addObject, allocations[index]);
-                }
-                graph.removeFixed(commit);
-            }
-        } else if (n instanceof OSRStartNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-                OSRStartNode osrStart = (OSRStartNode) n;
-                StartNode newStart = graph.add(new StartNode());
-                LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(wordKind)));
-                ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer));
-                migrationEnd.setStateAfter(osrStart.stateAfter());
-
-                newStart.setNext(migrationEnd);
-                FixedNode next = osrStart.next();
-                osrStart.setNext(null);
-                migrationEnd.setNext(next);
-                graph.setStart(newStart);
-
-                // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
-                int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
-                for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) {
-                    int size = FrameStateBuilder.stackSlots(osrLocal.kind());
-                    int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
-                    IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.kind(), offset, ConstantNode.forLong(0, graph), graph, 1);
-                    ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE, false));
-                    osrLocal.replaceAndDelete(load);
-                    graph.addBeforeFixed(migrationEnd, load);
-                }
-                osrStart.replaceAtUsages(newStart);
-                osrStart.safeDelete();
-            }
-        } else if (n instanceof DynamicCounterNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                BenchmarkCounters.lower((DynamicCounterNode) n, runtime.getHostProviders().getRegisters(), runtime.getConfig(), wordKind);
-            }
-        } else if (n instanceof CheckCastDynamicNode) {
-            checkcastDynamicSnippets.lower((CheckCastDynamicNode) n);
-        } else if (n instanceof InstanceOfNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-                instanceofSnippets.lower((InstanceOfNode) n, tool);
-            }
-        } else if (n instanceof InstanceOfDynamicNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-                instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
-            }
-        } else if (n instanceof NewInstanceNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((NewInstanceNode) n);
-            }
-        } else if (n instanceof NewArrayNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((NewArrayNode) n);
-            }
-        } else if (n instanceof DynamicNewArrayNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((DynamicNewArrayNode) n);
-            }
-        } else if (n instanceof MonitorEnterNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-                monitorSnippets.lower((MonitorEnterNode) n, tool);
-            }
-        } else if (n instanceof MonitorExitNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
-                monitorSnippets.lower((MonitorExitNode) n, tool);
-            }
-        } else if (n instanceof G1PreWriteBarrier) {
-            writeBarrierSnippets.lower((G1PreWriteBarrier) n, tool);
-        } else if (n instanceof G1PostWriteBarrier) {
-            writeBarrierSnippets.lower((G1PostWriteBarrier) n, tool);
-        } else if (n instanceof G1ReferentFieldReadBarrier) {
-            writeBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, tool);
-        } else if (n instanceof SerialWriteBarrier) {
-            writeBarrierSnippets.lower((SerialWriteBarrier) n, tool);
-        } else if (n instanceof SerialArrayRangeWriteBarrier) {
-            writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool);
-        } else if (n instanceof G1ArrayRangePreWriteBarrier) {
-            writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, tool);
-        } else if (n instanceof G1ArrayRangePostWriteBarrier) {
-            writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, tool);
-        } else if (n instanceof NewMultiArrayNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
-                newObjectSnippets.lower((NewMultiArrayNode) n);
-            }
-        } else if (n instanceof LoadExceptionObjectNode) {
-            exceptionObjectSnippets.lower((LoadExceptionObjectNode) n);
-        } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) {
-            // Nothing to do for division nodes. The HotSpot signal handler catches divisions by
-            // zero and the MIN_VALUE / -1 cases.
-        } else if (n instanceof BoxNode) {
-            boxingSnippets.lower((BoxNode) n, tool);
-        } else if (n instanceof UnboxNode) {
-            boxingSnippets.lower((UnboxNode) n, tool);
-        } else {
-            assert false : "Node implementing Lowerable not handled: " + n;
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    private static LocationNode createLocation(UnsafeAccessNode access) {
-        ValueNode offset = access.offset();
-        if (offset.isConstant()) {
-            long offsetValue = offset.asConstant().asLong();
-            return ConstantLocationNode.create(access.getLocationIdentity(), access.accessKind(), offsetValue, access.graph());
-        }
-
-        long displacement = 0;
-        int indexScaling = 1;
-        if (offset instanceof IntegerAddNode) {
-            IntegerAddNode integerAddNode = (IntegerAddNode) offset;
-            if (integerAddNode.y() instanceof ConstantNode) {
-                displacement = integerAddNode.y().asConstant().asLong();
-                offset = integerAddNode.x();
-            }
-        }
-
-        if (offset instanceof LeftShiftNode) {
-            LeftShiftNode leftShiftNode = (LeftShiftNode) offset;
-            if (leftShiftNode.y() instanceof ConstantNode) {
-                long shift = leftShiftNode.y().asConstant().asLong();
-                if (shift >= 1 && shift <= 3) {
-                    if (shift == 1) {
-                        indexScaling = 2;
-                    } else if (shift == 2) {
-                        indexScaling = 4;
-                    } else {
-                        indexScaling = 8;
-                    }
-                    offset = leftShiftNode.x();
-                }
-            }
-        }
-
-        return IndexedLocationNode.create(access.getLocationIdentity(), access.accessKind(), displacement, offset, access.graph(), indexScaling);
-    }
-
-    private static boolean addReadBarrier(UnsafeLoadNode load) {
-        if (useG1GC() && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().kind() == Kind.Object && load.accessKind() == Kind.Object &&
-                        !ObjectStamp.isObjectAlwaysNull(load.object())) {
-            ResolvedJavaType type = ObjectStamp.typeOrNull(load.object());
-            if (type != null && !type.isArray()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, ResolvedJavaMethod method) {
-        HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
-        assert !hsMethod.getDeclaringClass().isInterface();
-        assert hsMethod.isInVirtualMethodTable();
-
-        int vtableEntryOffset = hsMethod.vtableEntryOffset();
-        assert vtableEntryOffset > 0;
-        // We use LocationNode.ANY_LOCATION for the reads that access the vtable
-        // entry as HotSpot does not guarantee that this is a final value.
-        ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind), BarrierType.NONE, false));
-        return metaspaceMethod;
-    }
-
-    private FloatingReadNode createReadHub(StructuredGraph graph, Kind wordKind, ValueNode object, GuardingNode guard) {
-        HotSpotVMConfig config = runtime.getConfig();
-        LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.hubOffset, graph);
-        assert !object.isConstant() || object.asConstant().isNull();
-        return graph.unique(new FloatingReadNode(object, location, null, StampFactory.forKind(wordKind), guard, BarrierType.NONE, config.useCompressedClassPointers));
-    }
-
-    private WriteNode createWriteHub(StructuredGraph graph, Kind wordKind, ValueNode object, ValueNode value) {
-        HotSpotVMConfig config = runtime.getConfig();
-        LocationNode location = ConstantLocationNode.create(HUB_LOCATION, wordKind, config.hubOffset, graph);
-        assert !object.isConstant() || object.asConstant().isNull();
-        return graph.add(new WriteNode(object, value, location, BarrierType.NONE, config.useCompressedClassPointers));
-    }
-
-    private static BarrierType getFieldLoadBarrierType(HotSpotResolvedJavaField loadField) {
-        BarrierType barrierType = BarrierType.NONE;
-        if (config().useG1GC && loadField.getKind() == Kind.Object && loadField.getDeclaringClass().mirror() == java.lang.ref.Reference.class && loadField.getName().equals("referent")) {
-            barrierType = BarrierType.PRECISE;
-        }
-        return barrierType;
-    }
-
-    private static BarrierType getFieldStoreBarrierType(StoreFieldNode storeField) {
-        BarrierType barrierType = BarrierType.NONE;
-        if (storeField.field().getKind() == Kind.Object) {
-            barrierType = BarrierType.IMPRECISE;
-        }
-        return barrierType;
-    }
-
-    private static BarrierType getArrayStoreBarrierType(StoreIndexedNode store) {
-        BarrierType barrierType = BarrierType.NONE;
-        if (store.elementKind() == Kind.Object) {
-            barrierType = BarrierType.PRECISE;
-        }
-        return barrierType;
-    }
-
-    private static BarrierType getUnsafeStoreBarrierType(UnsafeStoreNode store) {
-        BarrierType barrierType = BarrierType.NONE;
-        if (store.value().kind() == Kind.Object) {
-            ResolvedJavaType type = ObjectStamp.typeOrNull(store.object());
-            if (type != null && !type.isArray()) {
-                barrierType = BarrierType.IMPRECISE;
-            } else {
-                barrierType = BarrierType.PRECISE;
-            }
-        }
-        return barrierType;
-    }
-
-    private static BarrierType getCompareAndSwapBarrier(CompareAndSwapNode cas) {
-        BarrierType barrierType = BarrierType.NONE;
-        if (cas.expected().kind() == Kind.Object) {
-            ResolvedJavaType type = ObjectStamp.typeOrNull(cas.object());
-            if (type != null && !type.isArray()) {
-                barrierType = BarrierType.IMPRECISE;
-            } else {
-                barrierType = BarrierType.PRECISE;
-            }
-        }
-        return barrierType;
-    }
-
-    protected static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field, boolean initialization) {
-        LocationIdentity loc = initialization ? INIT_LOCATION : field;
-        return ConstantLocationNode.create(loc, field.getKind(), field.offset(), graph);
-    }
-
-    public int getScalingFactor(Kind kind) {
-        if (useCompressedOops() && kind == Kind.Object) {
-            return this.runtime.getTarget().arch.getSizeInBytes(Kind.Int);
-        } else {
-            return this.runtime.getTarget().arch.getSizeInBytes(kind);
-        }
-    }
-
-    protected IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization) {
-        LocationIdentity loc = initialization ? INIT_LOCATION : NamedLocationIdentity.getArrayLocation(elementKind);
-        int scale = getScalingFactor(elementKind);
-        return IndexedLocationNode.create(loc, elementKind, getArrayBaseOffset(elementKind), index, graph, scale);
-    }
-
-    @Override
-    public ValueNode reconstructArrayIndex(LocationNode location) {
-        Kind elementKind = location.getValueKind();
-        assert location.getLocationIdentity().equals(NamedLocationIdentity.getArrayLocation(elementKind));
-
-        long base;
-        ValueNode index;
-        int scale = getScalingFactor(elementKind);
-
-        if (location instanceof ConstantLocationNode) {
-            base = ((ConstantLocationNode) location).getDisplacement();
-            index = null;
-        } else if (location instanceof IndexedLocationNode) {
-            IndexedLocationNode indexedLocation = (IndexedLocationNode) location;
-            assert indexedLocation.getIndexScaling() == scale;
-            base = indexedLocation.getDisplacement();
-            index = indexedLocation.getIndex();
-        } else {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-
-        base -= getArrayBaseOffset(elementKind);
-        assert base >= 0 && base % scale == 0;
-
-        base /= scale;
-        assert NumUtil.isInt(base);
-
-        StructuredGraph graph = location.graph();
-        if (index == null) {
-            return ConstantNode.forInt((int) base, graph);
-        } else {
-            if (base == 0) {
-                return index;
-            } else {
-                return IntegerArithmeticNode.add(graph, ConstantNode.forInt((int) base, graph), index);
-            }
-        }
-    }
-
-    private GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
-        StructuredGraph g = n.graph();
-        ValueNode array = n.array();
-        ValueNode arrayLength = readArrayLength(n.graph(), array, tool.getConstantReflection());
-        if (arrayLength == null) {
-            Stamp stamp = StampFactory.positiveInt();
-            ReadNode readArrayLength = g.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, g), stamp, BarrierType.NONE, false));
-            g.addBeforeFixed(n, readArrayLength);
-            tool.createNullCheckGuard(readArrayLength, array);
-            arrayLength = readArrayLength;
-        }
-
-        return tool.createGuard(g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java	Wed Nov 20 15:58:58 2013 +0100
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.meta;
+
+import static com.oracle.graal.api.code.MemoryBarriers.*;
+import static com.oracle.graal.api.meta.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.api.meta.LocationIdentity.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.meta.HotSpotHostForeignCallsProvider.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
+import static com.oracle.graal.nodes.java.ArrayLengthNode.*;
+import static com.oracle.graal.phases.GraalOptions.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.debug.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.HeapAccess.BarrierType;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.debug.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.virtual.*;
+import com.oracle.graal.replacements.*;
+
+/**
+ * HotSpot implementation of {@link LoweringProvider}.
+ */
+public class HotSpotLoweringProvider implements LoweringProvider {
+
+    protected final HotSpotGraalRuntime runtime;
+    protected final MetaAccessProvider metaAccess;
+    protected final ForeignCallsProvider foreignCalls;
+    protected final HotSpotRegistersProvider registers;
+
+    protected CheckCastDynamicSnippets.Templates checkcastDynamicSnippets;
+    protected InstanceOfSnippets.Templates instanceofSnippets;
+    protected NewObjectSnippets.Templates newObjectSnippets;
+    protected MonitorSnippets.Templates monitorSnippets;
+    protected WriteBarrierSnippets.Templates writeBarrierSnippets;
+    protected BoxingSnippets.Templates boxingSnippets;
+    protected LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
+    protected UnsafeLoadSnippets.Templates unsafeLoadSnippets;
+
+    public HotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) {
+        this.runtime = runtime;
+        this.metaAccess = metaAccess;
+        this.foreignCalls = foreignCalls;
+        this.registers = registers;
+    }
+
+    public void initialize(HotSpotProviders providers, HotSpotVMConfig config) {
+        TargetDescription target = providers.getCodeCache().getTarget();
+        checkcastDynamicSnippets = new CheckCastDynamicSnippets.Templates(providers, target);
+        instanceofSnippets = new InstanceOfSnippets.Templates(providers, target);
+        newObjectSnippets = new NewObjectSnippets.Templates(providers, target);
+        monitorSnippets = new MonitorSnippets.Templates(providers, target, config.useFastLocking);
+        writeBarrierSnippets = new WriteBarrierSnippets.Templates(providers, target);
+        boxingSnippets = new BoxingSnippets.Templates(providers, target);
+        exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target);
+        unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target);
+        providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target));
+    }
+
+    @Override
+    public void lower(Node n, LoweringTool tool) {
+        HotSpotVMConfig config = runtime.getConfig();
+        StructuredGraph graph = (StructuredGraph) n.graph();
+
+        Kind wordKind = runtime.getTarget().wordKind;
+        if (n instanceof ArrayLengthNode) {
+            ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n;
+            ValueNode array = arrayLengthNode.array();
+            ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt(),
+                            BarrierType.NONE, false));
+            tool.createNullCheckGuard(arrayLengthRead, array);
+            graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
+        } else if (n instanceof Invoke) {
+            Invoke invoke = (Invoke) n;
+            if (invoke.callTarget() instanceof MethodCallTargetNode) {
+
+                MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+                NodeInputList<ValueNode> parameters = callTarget.arguments();
+                ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
+                GuardingNode receiverNullCheck = null;
+                if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !ObjectStamp.isObjectNonNull(receiver)) {
+                    receiverNullCheck = tool.createNullCheckGuard(invoke, receiver);
+                }
+                JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
+
+                LoweredCallTargetNode loweredCallTarget = null;
+                if (callTarget.invokeKind() == InvokeKind.Virtual && InlineVTableStubs.getValue() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
+
+                    HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
+                    if (!hsMethod.getDeclaringClass().isInterface()) {
+                        if (hsMethod.isInVirtualMethodTable()) {
+                            int vtableEntryOffset = hsMethod.vtableEntryOffset();
+                            assert vtableEntryOffset > 0;
+                            FloatingReadNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck);
+
+                            ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod);
+                            // We use LocationNode.ANY_LOCATION for the reads that access the
+                            // compiled code entry as HotSpot does not guarantee they are final
+                            // values.
+                            ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph),
+                                            StampFactory.forKind(wordKind), BarrierType.NONE, false));
+
+                            loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
+                                            CallingConvention.Type.JavaCall));
+
+                            graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
+                            graph.addAfterFixed(metaspaceMethod, compiledEntry);
+                        }
+                    }
+                }
+
+                if (loweredCallTarget == null) {
+                    loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall,
+                                    callTarget.invokeKind()));
+                }
+                callTarget.replaceAndDelete(loweredCallTarget);
+            }
+        } else if (n instanceof LoadFieldNode) {
+            LoadFieldNode loadField = (LoadFieldNode) n;
+            HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field();
+            ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : loadField.object();
+            assert loadField.kind() != Kind.Illegal;
+            BarrierType barrierType = getFieldLoadBarrierType(field);
+            ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object)));
+            graph.replaceFixedWithFixed(loadField, memoryRead);
+            tool.createNullCheckGuard(memoryRead, object);
+
+            if (loadField.isVolatile()) {
+                MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
+                graph.addBeforeFixed(memoryRead, preMembar);
+                MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
+                graph.addAfterFixed(memoryRead, postMembar);
+            }
+        } else if (n instanceof StoreFieldNode) {
+            StoreFieldNode storeField = (StoreFieldNode) n;
+            HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field();
+            ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : storeField.object();
+            BarrierType barrierType = getFieldStoreBarrierType(storeField);
+            WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field, false), barrierType, storeField.field().getKind() == Kind.Object));
+            tool.createNullCheckGuard(memoryWrite, object);
+            memoryWrite.setStateAfter(storeField.stateAfter());
+            graph.replaceFixedWithFixed(storeField, memoryWrite);
+            FixedWithNextNode last = memoryWrite;
+            FixedWithNextNode first = memoryWrite;
+
+            if (storeField.isVolatile()) {
+                MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+                graph.addBeforeFixed(first, preMembar);
+                MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
+                graph.addAfterFixed(last, postMembar);
+            }
+        } else if (n instanceof CompareAndSwapNode) {
+            // Separate out GC barrier semantics
+            CompareAndSwapNode cas = (CompareAndSwapNode) n;
+            LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1);
+            LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, cas.expected(), cas.newValue(), getCompareAndSwapBarrier(cas),
+                            cas.expected().kind() == Kind.Object));
+            atomicNode.setStateAfter(cas.stateAfter());
+            graph.replaceFixedWithFixed(cas, atomicNode);
+        } else if (n instanceof LoadIndexedNode) {
+            LoadIndexedNode loadIndexed = (LoadIndexedNode) n;
+            GuardingNode boundsCheck = createBoundsCheck(loadIndexed, tool);
+            Kind elementKind = loadIndexed.elementKind();
+            LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false);
+            ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp(), BarrierType.NONE, elementKind == Kind.Object));
+            memoryRead.setGuard(boundsCheck);
+            graph.replaceFixedWithFixed(loadIndexed, memoryRead);
+        } else if (n instanceof StoreIndexedNode) {
+            StoreIndexedNode storeIndexed = (StoreIndexedNode) n;
+            GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool);
+            Kind elementKind = storeIndexed.elementKind();
+            LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index(), false);
+            ValueNode value = storeIndexed.value();
+            ValueNode array = storeIndexed.array();
+
+            CheckCastNode checkcastNode = null;
+            CheckCastDynamicNode checkcastDynamicNode = null;
+            if (elementKind == Kind.Object && !ObjectStamp.isObjectAlwaysNull(value)) {
+                // Store check!
+                ResolvedJavaType arrayType = ObjectStamp.typeOrNull(array);
+                if (arrayType != null && ObjectStamp.isExactType(array)) {
+                    ResolvedJavaType elementType = arrayType.getComponentType();
+                    if (!MetaUtil.isJavaLangObject(elementType)) {
+                        checkcastNode = graph.add(new CheckCastNode(elementType, value, null, true));
+                        graph.addBeforeFixed(storeIndexed, checkcastNode);
+                        value = checkcastNode;
+                    }
+                } else {
+                    FloatingReadNode arrayClass = createReadHub(graph, wordKind, array, boundsCheck);
+                    LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph);
+                    /*
+                     * Anchor the read of the element klass to the cfg, because it is only valid
+                     * when arrayClass is an object class, which might not be the case in other
+                     * parts of the compiled method.
+                     */
+                    FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind), BeginNode.prevBegin(storeIndexed)));
+                    checkcastDynamicNode = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true));
+                    graph.addBeforeFixed(storeIndexed, checkcastDynamicNode);
+                    value = checkcastDynamicNode;
+                }
+            }
+            BarrierType barrierType = getArrayStoreBarrierType(storeIndexed);
+            WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation, barrierType, elementKind == Kind.Object));
+            memoryWrite.setGuard(boundsCheck);
+            memoryWrite.setStateAfter(storeIndexed.stateAfter());
+            graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
+
+            // Lower the associated checkcast node.
+            if (checkcastNode != null) {
+                checkcastNode.lower(tool);
+            } else if (checkcastDynamicNode != null) {
+                checkcastDynamicSnippets.lower(checkcastDynamicNode);
+            }
+        } else if (n instanceof UnsafeLoadNode) {
+            UnsafeLoadNode load = (UnsafeLoadNode) n;
+            if (load.getGuardingCondition() != null) {
+                boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
+                ConditionAnchorNode valueAnchorNode = graph.add(new ConditionAnchorNode(load.getGuardingCondition()));
+                LocationNode location = createLocation(load);
+                ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), valueAnchorNode, BarrierType.NONE, compressible));
+                load.replaceAtUsages(memoryRead);
+                graph.replaceFixedWithFixed(load, valueAnchorNode);
+                graph.addAfterFixed(valueAnchorNode, memoryRead);
+            } else if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) {
+                assert load.kind() != Kind.Illegal;
+                boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
+                if (addReadBarrier(load)) {
+                    unsafeLoadSnippets.lower(load, tool);
+                } else {
+                    LocationNode location = createLocation(load);
+                    ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), BarrierType.NONE, compressible));
+                    // An unsafe read must not float outside its block otherwise
+                    // it may float above an explicit null check on its object.
+                    memoryRead.setGuard(AbstractBeginNode.prevBegin(load));
+                    graph.replaceFixedWithFixed(load, memoryRead);
+                }
+            }
+        } else if (n instanceof UnsafeStoreNode) {
+            UnsafeStoreNode store = (UnsafeStoreNode) n;
+            LocationNode location = createLocation(store);
+            ValueNode object = store.object();
+            BarrierType barrierType = getUnsafeStoreBarrierType(store);
+            WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType, store.value().kind() == Kind.Object));
+            write.setStateAfter(store.stateAfter());
+            graph.replaceFixedWithFixed(store, write);
+        } else if (n instanceof LoadHubNode) {
+            LoadHubNode loadHub = (LoadHubNode) n;
+            assert loadHub.kind() == wordKind;
+            ValueNode object = loadHub.object();
+            GuardingNode guard = loadHub.getGuard();
+            FloatingReadNode hub = createReadHub(graph, wordKind, object, guard);
+            graph.replaceFloating(loadHub, hub);
+        } else if (n instanceof LoadMethodNode) {
+            LoadMethodNode loadMethodNode = (LoadMethodNode) n;
+            ResolvedJavaMethod method = loadMethodNode.getMethod();
+            ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, loadMethodNode.getHub(), method);
+            graph.replaceFixed(loadMethodNode, metaspaceMethod);
+        } else if (n instanceof StoreHubNode) {
+            StoreHubNode storeHub = (StoreHubNode) n;
+            WriteNode hub = createWriteHub(graph, wordKind, storeHub.getObject(), storeHub.getValue());
+            graph.replaceFixed(storeHub, hub);
+        } else if (n instanceof CommitAllocationNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+                CommitAllocationNode commit = (CommitAllocationNode) n;
+                ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
+                BitSet omittedValues = new BitSet();
+                int valuePos = 0;
+                for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                    VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                    int entryCount = virtual.entryCount();
+                    FixedWithNextNode newObject;
+                    if (virtual instanceof VirtualInstanceNode) {
+                        newObject = graph.add(new NewInstanceNode(virtual.type(), true));
+                        graph.addBeforeFixed(commit, newObject);
+                        allocations[objIndex] = newObject;
+                        for (int i = 0; i < entryCount; i++) {
+                            ValueNode value = commit.getValues().get(valuePos);
+                            if (value instanceof VirtualObjectNode) {
+                                value = allocations[commit.getVirtualObjects().indexOf(value)];
+                            }
+                            if (value == null) {
+                                omittedValues.set(valuePos);
+                            } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
+                                // Constant.illegal is always the defaultForKind, so it is skipped
+                                VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
+                                Kind accessKind;
+                                HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) virtualInstance.field(i);
+                                if (value.kind().getStackKind() != field.getKind().getStackKind()) {
+                                    assert value.kind() == Kind.Long || value.kind() == Kind.Double;
+                                    accessKind = value.kind();
+                                } else {
+                                    accessKind = field.getKind();
+                                }
+                                ConstantLocationNode location = ConstantLocationNode.create(INIT_LOCATION, accessKind, field.offset(), graph);
+                                BarrierType barrierType = (virtualInstance.field(i).getKind() == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE;
+                                WriteNode write = new WriteNode(newObject, value, location, barrierType, virtualInstance.field(i).getKind() == Kind.Object);
+                                graph.addAfterFixed(newObject, graph.add(write));
+                            }
+                            valuePos++;
+                        }
+                    } else {
+                        ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType();
+                        newObject = graph.add(new NewArrayNode(element, ConstantNode.forInt(entryCount, graph), true));
+                        graph.addBeforeFixed(commit, newObject);
+                        allocations[objIndex] = newObject;
+                        for (int i = 0; i < entryCount; i++) {
+                            ValueNode value = commit.getValues().get(valuePos);
+                            if (value instanceof VirtualObjectNode) {
+                                value = allocations[commit.getVirtualObjects().indexOf(value)];
+                            }
+                            if (value == null) {
+                                omittedValues.set(valuePos);
+                            } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
+                                // Constant.illegal is always the defaultForKind, so it is skipped
+                                Kind componentKind = element.getKind();
+                                Kind accessKind;
+                                Kind valueKind = value.kind();
+                                if (valueKind.getStackKind() != componentKind.getStackKind()) {
+                                    // Given how Truffle uses unsafe, it can happen that
+                                    // valueKind is Kind.Int
+                                    // assert valueKind == Kind.Long || valueKind == Kind.Double;
+                                    accessKind = valueKind;
+                                } else {
+                                    accessKind = componentKind;
+                                }
+
+                                int scale = getScalingFactor(componentKind);
+                                ConstantLocationNode location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(componentKind) + i * scale, graph);
+                                BarrierType barrierType = (componentKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE;
+                                WriteNode write = new WriteNode(newObject, value, location, barrierType, componentKind == Kind.Object);
+                                graph.addAfterFixed(newObject, graph.add(write));
+                            }
+                            valuePos++;
+                        }
+                    }
+                }
+                valuePos = 0;
+
+                for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                    VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
+                    int entryCount = virtual.entryCount();
+                    ValueNode newObject = allocations[objIndex];
+                    if (virtual instanceof VirtualInstanceNode) {
+                        for (int i = 0; i < entryCount; i++) {
+                            if (omittedValues.get(valuePos)) {
+                                ValueNode value = commit.getValues().get(valuePos);
+                                assert value instanceof VirtualObjectNode;
+                                ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
+                                if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
+                                    VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
+                                    assert virtualInstance.field(i).getKind() == Kind.Object;
+                                    WriteNode write = new WriteNode(newObject, allocValue, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i), true),
+                                                    BarrierType.IMPRECISE, true);
+                                    graph.addBeforeFixed(commit, graph.add(write));
+                                }
+                            }
+                            valuePos++;
+                        }
+                    } else {
+                        ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType();
+                        for (int i = 0; i < entryCount; i++) {
+                            if (omittedValues.get(valuePos)) {
+                                ValueNode value = commit.getValues().get(valuePos);
+                                assert value instanceof VirtualObjectNode;
+                                ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
+                                if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
+                                    assert allocValue.kind() == Kind.Object;
+                                    WriteNode write = new WriteNode(newObject, allocValue, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph), true), BarrierType.PRECISE,
+                                                    true);
+                                    graph.addBeforeFixed(commit, graph.add(write));
+                                }
+                            }
+                            valuePos++;
+                        }
+                    }
+                }
+
+                for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                    FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
+                    allocations[objIndex] = anchor;
+                    graph.addBeforeFixed(commit, anchor);
+                }
+                for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
+                    for (int lockDepth : commit.getLocks().get(objIndex)) {
+                        MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], lockDepth));
+                        graph.addBeforeFixed(commit, enter);
+                        enter.lower(tool);
+                    }
+                }
+                for (Node usage : commit.usages().snapshot()) {
+                    AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
+                    int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
+                    graph.replaceFloating(addObject, allocations[index]);
+                }
+                graph.removeFixed(commit);
+            }
+        } else if (n instanceof OSRStartNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+                OSRStartNode osrStart = (OSRStartNode) n;
+                StartNode newStart = graph.add(new StartNode());
+                LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(wordKind)));
+                ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer));
+                migrationEnd.setStateAfter(osrStart.stateAfter());
+
+                newStart.setNext(migrationEnd);
+                FixedNode next = osrStart.next();
+                osrStart.setNext(null);
+                migrationEnd.setNext(next);
+                graph.setStart(newStart);
+
+                // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
+                int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
+                for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) {
+                    int size = FrameStateBuilder.stackSlots(osrLocal.kind());
+                    int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
+                    IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.kind(), offset, ConstantNode.forLong(0, graph), graph, 1);
+                    ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE, false));
+                    osrLocal.replaceAndDelete(load);
+                    graph.addBeforeFixed(migrationEnd, load);
+                }
+                osrStart.replaceAtUsages(newStart);
+                osrStart.safeDelete();
+            }
+        } else if (n instanceof DynamicCounterNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                BenchmarkCounters.lower((DynamicCounterNode) n, registers, runtime.getConfig(), wordKind);
+            }
+        } else if (n instanceof CheckCastDynamicNode) {
+            checkcastDynamicSnippets.lower((CheckCastDynamicNode) n);
+        } else if (n instanceof InstanceOfNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+                instanceofSnippets.lower((InstanceOfNode) n, tool);
+            }
+        } else if (n instanceof InstanceOfDynamicNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+                instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
+            }
+        } else if (n instanceof NewInstanceNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((NewInstanceNode) n, registers);
+            }
+        } else if (n instanceof NewArrayNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((NewArrayNode) n, registers);
+            }
+        } else if (n instanceof DynamicNewArrayNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((DynamicNewArrayNode) n, registers);
+            }
+        } else if (n instanceof MonitorEnterNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+                monitorSnippets.lower((MonitorEnterNode) n, registers);
+            }
+        } else if (n instanceof MonitorExitNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+                monitorSnippets.lower((MonitorExitNode) n, tool);
+            }
+        } else if (n instanceof G1PreWriteBarrier) {
+            writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers);
+        } else if (n instanceof G1PostWriteBarrier) {
+            writeBarrierSnippets.lower((G1PostWriteBarrier) n, registers);
+        } else if (n instanceof G1ReferentFieldReadBarrier) {
+            writeBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, registers);
+        } else if (n instanceof SerialWriteBarrier) {
+            writeBarrierSnippets.lower((SerialWriteBarrier) n);
+        } else if (n instanceof SerialArrayRangeWriteBarrier) {
+            writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n);
+        } else if (n instanceof G1ArrayRangePreWriteBarrier) {
+            writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, registers);
+        } else if (n instanceof G1ArrayRangePostWriteBarrier) {
+            writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, registers);
+        } else if (n instanceof NewMultiArrayNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                newObjectSnippets.lower((NewMultiArrayNode) n);
+            }
+        } else if (n instanceof LoadExceptionObjectNode) {
+            exceptionObjectSnippets.lower((LoadExceptionObjectNode) n, registers);
+        } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) {
+            // Nothing to do for division nodes. The HotSpot signal handler catches divisions by
+            // zero and the MIN_VALUE / -1 cases.
+        } else if (n instanceof BoxNode) {
+            boxingSnippets.lower((BoxNode) n, tool);
+        } else if (n instanceof UnboxNode) {
+            boxingSnippets.lower((UnboxNode) n, tool);
+        } else {
+            assert false : "Node implementing Lowerable not handled: " + n;
+            throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    private static LocationNode createLocation(UnsafeAccessNode access) {
+        ValueNode offset = access.offset();
+        if (offset.isConstant()) {
+            long offsetValue = offset.asConstant().asLong();
+            return ConstantLocationNode.create(access.getLocationIdentity(), access.accessKind(), offsetValue, access.graph());
+        }
+
+        long displacement = 0;
+        int indexScaling = 1;
+        if (offset instanceof IntegerAddNode) {
+            IntegerAddNode integerAddNode = (IntegerAddNode) offset;
+            if (integerAddNode.y() instanceof ConstantNode) {
+                displacement = integerAddNode.y().asConstant().asLong();
+                offset = integerAddNode.x();
+            }
+        }
+
+        if (offset instanceof LeftShiftNode) {
+            LeftShiftNode leftShiftNode = (LeftShiftNode) offset;
+            if (leftShiftNode.y() instanceof ConstantNode) {
+                long shift = leftShiftNode.y().asConstant().asLong();
+                if (shift >= 1 && shift <= 3) {
+                    if (shift == 1) {
+                        indexScaling = 2;
+                    } else if (shift == 2) {
+                        indexScaling = 4;
+                    } else {
+                        indexScaling = 8;
+                    }
+                    offset = leftShiftNode.x();
+                }
+            }
+        }
+
+        return IndexedLocationNode.create(access.getLocationIdentity(), access.accessKind(), displacement, offset, access.graph(), indexScaling);
+    }
+
+    private static boolean addReadBarrier(UnsafeLoadNode load) {
+        if (useG1GC() && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().kind() == Kind.Object && load.accessKind() == Kind.Object &&
+                        !ObjectStamp.isObjectAlwaysNull(load.object())) {
+            ResolvedJavaType type = ObjectStamp.typeOrNull(load.object());
+            if (type != null && !type.isArray()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, ResolvedJavaMethod method) {
+        HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
+        assert !hsMethod.getDeclaringClass().isInterface();
+        assert hsMethod.isInVirtualMethodTable();
+
+        int vtableEntryOffset = hsMethod.vtableEntryOffset();
+        assert vtableEntryOffset > 0;
+        // We use LocationNode.ANY_LOCATION for the reads that access the vtable
+        // entry as HotSpot does not guarantee that this is a final value.
+        ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind), BarrierType.NONE, false));
+        return metaspaceMethod;
+    }
+
+    private FloatingReadNode createReadHub(StructuredGraph graph, Kind wordKind, ValueNode object, GuardingNode guard) {
+        HotSpotVMConfig config = runtime.getConfig();
+        LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.hubOffset, graph);
+        assert !object.isConstant() || object.asConstant().isNull();
+        return graph.unique(new FloatingReadNode(object, location, null, StampFactory.forKind(wordKind), guard, BarrierType.NONE, config.useCompressedClassPointers));
+    }
+
+    private WriteNode createWriteHub(StructuredGraph graph, Kind wordKind, ValueNode object, ValueNode value) {
+        HotSpotVMConfig config = runtime.getConfig();
+        LocationNode location = ConstantLocationNode.create(HUB_LOCATION, wordKind, config.hubOffset, graph);
+        assert !object.isConstant() || object.asConstant().isNull();
+        return graph.add(new WriteNode(object, value, location, BarrierType.NONE, config.useCompressedClassPointers));
+    }
+
+    private static BarrierType getFieldLoadBarrierType(HotSpotResolvedJavaField loadField) {
+        BarrierType barrierType = BarrierType.NONE;
+        if (config().useG1GC && loadField.getKind() == Kind.Object && loadField.getDeclaringClass().mirror() == java.lang.ref.Reference.class && loadField.getName().equals("referent")) {
+            barrierType = BarrierType.PRECISE;
+        }
+        return barrierType;
+    }
+
+    private static BarrierType getFieldStoreBarrierType(StoreFieldNode storeField) {
+        BarrierType barrierType = BarrierType.NONE;
+        if (storeField.field().getKind() == Kind.Object) {
+            barrierType = BarrierType.IMPRECISE;
+        }
+        return barrierType;
+    }
+
+    private static BarrierType getArrayStoreBarrierType(StoreIndexedNode store) {
+        BarrierType barrierType = BarrierType.NONE;
+        if (store.elementKind() == Kind.Object) {
+            barrierType = BarrierType.PRECISE;
+        }
+        return barrierType;
+    }
+
+    private static BarrierType getUnsafeStoreBarrierType(UnsafeStoreNode store) {
+        BarrierType barrierType = BarrierType.NONE;
+        if (store.value().kind() == Kind.Object) {
+            ResolvedJavaType type = ObjectStamp.typeOrNull(store.object());
+            if (type != null && !type.isArray()) {
+                barrierType = BarrierType.IMPRECISE;
+            } else {
+                barrierType = BarrierType.PRECISE;
+            }
+        }
+        return barrierType;
+    }
+
+    private static BarrierType getCompareAndSwapBarrier(CompareAndSwapNode cas) {
+        BarrierType barrierType = BarrierType.NONE;
+        if (cas.expected().kind() == Kind.Object) {
+            ResolvedJavaType type = ObjectStamp.typeOrNull(cas.object());
+            if (type != null && !type.isArray()) {
+                barrierType = BarrierType.IMPRECISE;
+            } else {
+                barrierType = BarrierType.PRECISE;
+            }
+        }
+        return barrierType;
+    }
+
+    protected static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field, boolean initialization) {
+        LocationIdentity loc = initialization ? INIT_LOCATION : field;
+        return ConstantLocationNode.create(loc, field.getKind(), field.offset(), graph);
+    }
+
+    public int getScalingFactor(Kind kind) {
+        if (useCompressedOops() && kind == Kind.Object) {
+            return this.runtime.getTarget().arch.getSizeInBytes(Kind.Int);
+        } else {
+            return this.runtime.getTarget().arch.getSizeInBytes(kind);
+        }
+    }
+
+    protected IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization) {
+        LocationIdentity loc = initialization ? INIT_LOCATION : NamedLocationIdentity.getArrayLocation(elementKind);
+        int scale = getScalingFactor(elementKind);
+        return IndexedLocationNode.create(loc, elementKind, getArrayBaseOffset(elementKind), index, graph, scale);
+    }
+
+    @Override
+    public ValueNode reconstructArrayIndex(LocationNode location) {
+        Kind elementKind = location.getValueKind();
+        assert location.getLocationIdentity().equals(NamedLocationIdentity.getArrayLocation(elementKind));
+
+        long base;
+        ValueNode index;
+        int scale = getScalingFactor(elementKind);
+
+        if (location instanceof ConstantLocationNode) {
+            base = ((ConstantLocationNode) location).getDisplacement();
+            index = null;
+        } else if (location instanceof IndexedLocationNode) {
+            IndexedLocationNode indexedLocation = (IndexedLocationNode) location;
+            assert indexedLocation.getIndexScaling() == scale;
+            base = indexedLocation.getDisplacement();
+            index = indexedLocation.getIndex();
+        } else {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        base -= getArrayBaseOffset(elementKind);
+        assert base >= 0 && base % scale == 0;
+
+        base /= scale;
+        assert NumUtil.isInt(base);
+
+        StructuredGraph graph = location.graph();
+        if (index == null) {
+            return ConstantNode.forInt((int) base, graph);
+        } else {
+            if (base == 0) {
+                return index;
+            } else {
+                return IntegerArithmeticNode.add(graph, ConstantNode.forInt((int) base, graph), index);
+            }
+        }
+    }
+
+    private GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
+        StructuredGraph g = n.graph();
+        ValueNode array = n.array();
+        ValueNode arrayLength = readArrayLength(n.graph(), array, tool.getConstantReflection());
+        if (arrayLength == null) {
+            Stamp stamp = StampFactory.positiveInt();
+            ReadNode readArrayLength = g.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, g), stamp, BarrierType.NONE, false));
+            g.addBeforeFixed(n, readArrayLength);
+            tool.createNullCheckGuard(readArrayLength, array);
+            arrayLength = readArrayLength;
+        }
+
+        return tool.createGuard(g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Wed Nov 20 15:58:58 2013 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
@@ -41,7 +42,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        Register rawThread = runtime().getHostProviders().getRegisters().getThreadRegister();
+        Register rawThread = ((HotSpotLIRGenerator) gen).getProviders().getRegisters().getThreadRegister();
         gen.setResult(this, rawThread.asValue(this.kind()));
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Wed Nov 20 15:58:58 2013 +0100
@@ -202,16 +202,6 @@
     }
 
     @Fold
-    public static Register threadRegister() {
-        return runtime().getHostProviders().getRegisters().getThreadRegister();
-    }
-
-    @Fold
-    public static Register stackPointerRegister() {
-        return runtime().getHostProviders().getRegisters().getStackPointerRegister();
-    }
-
-    @Fold
     public static int wordSize() {
         return runtime().getTarget().wordSize;
     }
@@ -469,23 +459,19 @@
     @NodeIntrinsic(ForeignCallNode.class)
     private static native Object verifyOopStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object);
 
-    /**
-     * Gets the value of the stack pointer register as a Word.
-     */
-    public static Word stackPointer() {
-        return registerAsWord(stackPointerRegister(), true, false);
+    public static Word loadWordFromObject(Object object, int offset) {
+        assert offset != hubOffset() : "Use loadHubIntrinsic instead";
+        return loadWordFromObjectIntrinsic(object, offset, getWordKind(), LocationIdentity.ANY_LOCATION);
     }
 
     /**
-     * Gets the value of the thread register as a Word.
+     * Reads the value of a given register.
+     * 
+     * @param register a register which must not be available to the register allocator
+     * @return the value of {@code register} as a word
      */
-    public static Word thread() {
-        return registerAsWord(threadRegister(), true, false);
-    }
-
-    public static Word loadWordFromObject(Object object, int offset) {
-        assert offset != hubOffset() : "Use loadHubIntrinsic instead";
-        return loadWordFromObjectIntrinsic(object, offset, getWordKind(), LocationIdentity.ANY_LOCATION);
+    public static Word registerAsWord(@ConstantNodeParameter Register register) {
+        return registerAsWord(register, true, false);
     }
 
     @NodeIntrinsic(value = ReadRegisterNode.class, setStampFromReturnType = true)
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Wed Nov 20 15:58:58 2013 +0100
@@ -34,6 +34,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.Snippet.*;
 import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
 import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
@@ -51,8 +52,8 @@
     private static final boolean USE_C_RUNTIME = Boolean.getBoolean("graal.loadExceptionObject.useCRuntime");
 
     @Snippet
-    public static Object loadException() {
-        Word thread = thread();
+    public static Object loadException(@ConstantParameter Register threadRegister) {
+        Word thread = registerAsWord(threadRegister);
         Object exception = readExceptionOop(thread);
         writeExceptionOop(thread, null);
         writeExceptionPc(thread, Word.zero());
@@ -67,10 +68,9 @@
             super(providers, target);
         }
 
-        public void lower(LoadExceptionObjectNode loadExceptionObject) {
+        public void lower(LoadExceptionObjectNode loadExceptionObject, HotSpotRegistersProvider registers) {
             if (USE_C_RUNTIME) {
                 StructuredGraph graph = loadExceptionObject.graph();
-                HotSpotRegistersProvider registers = ((HotSpotProviders) providers).getRegisters();
                 ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), true, false));
                 graph.addBeforeFixed(loadExceptionObject, thread);
                 ForeignCallNode loadExceptionC = graph.add(new ForeignCallNode(providers.getForeignCalls(), LOAD_AND_CLEAR_EXCEPTION, thread));
@@ -78,6 +78,7 @@
                 graph.replaceFixedWithFixed(loadExceptionObject, loadExceptionC);
             } else {
                 Arguments args = new Arguments(loadException, loadExceptionObject.graph().getGuardsStage());
+                args.addConst("threadRegister", registers.getThreadRegister());
                 template(args).instantiate(providers.getMetaAccess(), loadExceptionObject, DEFAULT_REPLACER, args);
             }
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Wed Nov 20 15:58:58 2013 +0100
@@ -38,6 +38,7 @@
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.debug.*;
@@ -96,7 +97,8 @@
     public static final boolean CHECK_BALANCED_MONITORS = Boolean.getBoolean("graal.monitors.checkBalanced");
 
     @Snippet
-    public static void monitorenter(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) {
+    public static void monitorenter(Object object, @ConstantParameter int lockDepth, @ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister,
+                    @ConstantParameter boolean trace) {
         verifyOop(object);
 
         if (object == null) {
@@ -130,7 +132,7 @@
                 // whether the bias owner and the epoch are both still current.
                 Word hub = loadHubIntrinsic(object, getWordKind(), anchorNode);
                 final Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
-                final Word thread = thread();
+                final Word thread = registerAsWord(threadRegister);
                 final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace());
                 trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord);
                 trace(trace, "           thread: 0x%016lx\n", thread);
@@ -253,7 +255,7 @@
             // assuming both the stack pointer and page_size have their least
             // significant 2 bits cleared and page_size is a power of 2
             final Word alignedMask = Word.unsigned(wordSize() - 1);
-            final Word stackPointer = stackPointer();
+            final Word stackPointer = registerAsWord(stackPointerRegister);
             if (probability(VERY_SLOW_PATH_PROBABILITY, currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).notEqual(0))) {
                 // Most likely not a recursive lock, go into a slow runtime call
                 traceObject(trace, "+lock{stub:failed-cas}", object, true);
@@ -420,7 +422,7 @@
             this.useFastLocking = useFastLocking;
         }
 
-        public void lower(MonitorEnterNode monitorenterNode, @SuppressWarnings("unused") LoweringTool tool) {
+        public void lower(MonitorEnterNode monitorenterNode, HotSpotRegistersProvider registers) {
             StructuredGraph graph = monitorenterNode.graph();
             checkBalancedMonitors(graph);
             FrameState stateAfter = monitorenterNode.stateAfter();
@@ -434,6 +436,8 @@
             args.add("object", monitorenterNode.object());
             args.addConst("lockDepth", monitorenterNode.getLockDepth());
             boolean tracingEnabledForMethod = stateAfter != null && (isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method()));
+            args.addConst("threadRegister", registers.getThreadRegister());
+            args.addConst("stackPointerRegister", registers.getStackPointerRegister());
             args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || tracingEnabledForMethod);
 
             Map<Node, Node> nodes = template(args).instantiate(providers.getMetaAccess(), monitorenterNode, DEFAULT_REPLACER, args);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Wed Nov 20 15:58:58 2013 +0100
@@ -113,9 +113,10 @@
     }
 
     @Snippet
-    public static Object allocateInstance(@ConstantParameter int size, Word hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents, @ConstantParameter String typeContext) {
+    public static Object allocateInstance(@ConstantParameter int size, Word hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister,
+                    @ConstantParameter String typeContext) {
         Object result;
-        Word thread = thread();
+        Word thread = registerAsWord(threadRegister);
         Word top = readTlabTop(thread);
         Word end = readTlabEnd(thread);
         Word newTop = top.add(size);
@@ -137,19 +138,20 @@
 
     @Snippet
     public static Object allocateArray(Word hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize,
-                    @ConstantParameter boolean fillContents, @ConstantParameter String typeContext) {
+                    @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter String typeContext) {
         if (!belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) {
             // This handles both negative array sizes and very large array sizes
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
-        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, typeContext);
+        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, typeContext);
     }
 
-    private static Object allocateArrayImpl(Word hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents, String typeContext) {
+    private static Object allocateArrayImpl(Word hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents, @ConstantParameter Register threadRegister,
+                    String typeContext) {
         Object result;
         int alignment = wordSize();
         int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
-        Word thread = thread();
+        Word thread = registerAsWord(threadRegister);
         Word top = readTlabTop(thread);
         Word end = readTlabEnd(thread);
         Word newTop = top.add(allocationSize);
@@ -171,7 +173,7 @@
     public static native Object dynamicNewArrayStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType, int length);
 
     @Snippet
-    public static Object allocateArrayDynamic(Class<?> elementType, int length, @ConstantParameter boolean fillContents) {
+    public static Object allocateArrayDynamic(Class<?> elementType, int length, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister) {
         Word hub = loadWordFromObject(elementType, arrayKlassOffset());
         if (hub.equal(Word.zero()) || !belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) {
             return dynamicNewArrayStub(DYNAMIC_NEW_ARRAY, elementType, length);
@@ -195,7 +197,7 @@
         int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
         Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
 
-        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, "dynamic type");
+        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, "dynamic type");
     }
 
     /**
@@ -288,7 +290,7 @@
         /**
          * Lowers a {@link NewInstanceNode}.
          */
-        public void lower(NewInstanceNode newInstanceNode) {
+        public void lower(NewInstanceNode newInstanceNode, HotSpotRegistersProvider registers) {
             StructuredGraph graph = newInstanceNode.graph();
             HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newInstanceNode.instanceClass();
             assert !type.isArray();
@@ -300,6 +302,7 @@
             args.add("hub", hub);
             args.add("prototypeMarkWord", type.prototypeMarkWord());
             args.addConst("fillContents", newInstanceNode.fillContents());
+            args.addConst("threadRegister", registers.getThreadRegister());
             args.addConst("typeContext", ProfileAllocations.getValue() ? toJavaName(type, false) : "");
 
             SnippetTemplate template = template(args);
@@ -310,14 +313,14 @@
         /**
          * Lowers a {@link NewArrayNode}.
          */
-        public void lower(NewArrayNode newArrayNode) {
+        public void lower(NewArrayNode newArrayNode, HotSpotRegistersProvider registers) {
             StructuredGraph graph = newArrayNode.graph();
             ResolvedJavaType elementType = newArrayNode.elementType();
             HotSpotResolvedObjectType arrayType = (HotSpotResolvedObjectType) elementType.getArrayClass();
             Kind elementKind = elementType.getKind();
             ConstantNode hub = ConstantNode.forConstant(arrayType.klass(), providers.getMetaAccess(), graph);
             final int headerSize = HotSpotGraalRuntime.getArrayBaseOffset(elementKind);
-            HotSpotHostLoweringProvider lowerer = (HotSpotHostLoweringProvider) providers.getLowerer();
+            HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer();
             int log2ElementSize = CodeUtil.log2(lowerer.getScalingFactor(elementKind));
 
             Arguments args = new Arguments(allocateArray, graph.getGuardsStage());
@@ -327,6 +330,7 @@
             args.addConst("headerSize", headerSize);
             args.addConst("log2ElementSize", log2ElementSize);
             args.addConst("fillContents", newArrayNode.fillContents());
+            args.addConst("threadRegister", registers.getThreadRegister());
             args.addConst("typeContext", ProfileAllocations.getValue() ? toJavaName(arrayType, false) : "");
 
             SnippetTemplate template = template(args);
@@ -334,11 +338,12 @@
             template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args);
         }
 
-        public void lower(DynamicNewArrayNode newArrayNode) {
+        public void lower(DynamicNewArrayNode newArrayNode, HotSpotRegistersProvider registers) {
             Arguments args = new Arguments(allocateArrayDynamic, newArrayNode.graph().getGuardsStage());
             args.add("elementType", newArrayNode.getElementType());
             args.add("length", newArrayNode.length());
             args.addConst("fillContents", newArrayNode.fillContents());
+            args.addConst("threadRegister", registers.getThreadRegister());
 
             SnippetTemplate template = template(args);
             template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Wed Nov 20 15:58:58 2013 +0100
@@ -31,11 +31,11 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
@@ -106,11 +106,11 @@
 
     @Snippet
     public static void g1PreWriteBarrier(Object object, Object expectedObject, Object location, @ConstantParameter boolean doLoad, @ConstantParameter boolean nullCheck,
-                    @ConstantParameter boolean trace) {
+                    @ConstantParameter Register threadRegister, @ConstantParameter boolean trace) {
         if (nullCheck && object == null) {
             DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException);
         }
-        Word thread = thread();
+        Word thread = registerAsWord(threadRegister);
         Object fixedObject = FixedValueAnchorNode.getObject(object);
         verifyOop(fixedObject);
         Object fixedExpectedObject = FixedValueAnchorNode.getObject(expectedObject);
@@ -161,8 +161,9 @@
     }
 
     @Snippet
-    public static void g1PostWriteBarrier(Object object, Object value, Object location, @ConstantParameter boolean usePrecise, @ConstantParameter boolean trace) {
-        Word thread = thread();
+    public static void g1PostWriteBarrier(Object object, Object value, Object location, @ConstantParameter boolean usePrecise, @ConstantParameter Register threadRegister,
+                    @ConstantParameter boolean trace) {
+        Word thread = registerAsWord(threadRegister);
         Object fixedObject = FixedValueAnchorNode.getObject(object);
         Object fixedValue = FixedValueAnchorNode.getObject(value);
         verifyOop(fixedObject);
@@ -233,8 +234,8 @@
     }
 
     @Snippet
-    public static void g1ArrayRangePreWriteBarrier(Object object, int startIndex, int length) {
-        Word thread = thread();
+    public static void g1ArrayRangePreWriteBarrier(Object object, int startIndex, int length, @ConstantParameter Register threadRegister) {
+        Word thread = registerAsWord(threadRegister);
         byte markingValue = thread.readByte(g1SATBQueueMarkingOffset());
         // If the concurrent marker is not enabled or the vector length is zero, return.
         if (markingValue == (byte) 0 || length == 0) {
@@ -267,12 +268,12 @@
     }
 
     @Snippet
-    public static void g1ArrayRangePostWriteBarrier(Object object, int startIndex, int length) {
+    public static void g1ArrayRangePostWriteBarrier(Object object, int startIndex, int length, @ConstantParameter Register threadRegister) {
         if (length == 0) {
             return;
         }
         Object dest = FixedValueAnchorNode.getObject(object);
-        Word thread = thread();
+        Word thread = registerAsWord(threadRegister);
         Word bufferAddress = thread.readWord(g1CardQueueBufferOffset());
         Word indexAddress = thread.add(g1CardQueueIndexOffset());
         long indexValue = thread.readWord(g1CardQueueIndexOffset()).rawValue();
@@ -332,7 +333,7 @@
             super(providers, target);
         }
 
-        public void lower(SerialWriteBarrier writeBarrier, @SuppressWarnings("unused") LoweringTool tool) {
+        public void lower(SerialWriteBarrier writeBarrier) {
             if (writeBarrier.alwaysNull()) {
                 writeBarrier.graph().removeFixed(writeBarrier);
                 return;
@@ -344,7 +345,7 @@
             template(args).instantiate(providers.getMetaAccess(), writeBarrier, DEFAULT_REPLACER, args);
         }
 
-        public void lower(SerialArrayRangeWriteBarrier arrayRangeWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) {
+        public void lower(SerialArrayRangeWriteBarrier arrayRangeWriteBarrier) {
             Arguments args = new Arguments(serialArrayRangeWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage());
             args.add("object", arrayRangeWriteBarrier.getObject());
             args.add("startIndex", arrayRangeWriteBarrier.getStartIndex());
@@ -352,29 +353,31 @@
             template(args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
         }
 
-        public void lower(G1PreWriteBarrier writeBarrierPre, @SuppressWarnings("unused") LoweringTool tool) {
+        public void lower(G1PreWriteBarrier writeBarrierPre, HotSpotRegistersProvider registers) {
             Arguments args = new Arguments(g1PreWriteBarrier, writeBarrierPre.graph().getGuardsStage());
             args.add("object", writeBarrierPre.getObject());
             args.add("expectedObject", writeBarrierPre.getExpectedObject());
             args.add("location", writeBarrierPre.getLocation());
             args.addConst("doLoad", writeBarrierPre.doLoad());
             args.addConst("nullCheck", writeBarrierPre.getNullCheck());
+            args.addConst("threadRegister", registers.getThreadRegister());
             args.addConst("trace", traceBarrier());
             template(args).instantiate(providers.getMetaAccess(), writeBarrierPre, DEFAULT_REPLACER, args);
         }
 
-        public void lower(G1ReferentFieldReadBarrier readBarrier, @SuppressWarnings("unused") LoweringTool tool) {
+        public void lower(G1ReferentFieldReadBarrier readBarrier, HotSpotRegistersProvider registers) {
             Arguments args = new Arguments(g1ReferentReadBarrier, readBarrier.graph().getGuardsStage());
             args.add("object", readBarrier.getObject());
             args.add("expectedObject", readBarrier.getExpectedObject());
             args.add("location", readBarrier.getLocation());
             args.addConst("doLoad", readBarrier.doLoad());
             args.addConst("nullCheck", false);
+            args.addConst("threadRegister", registers.getThreadRegister());
             args.addConst("trace", traceBarrier());
             template(args).instantiate(providers.getMetaAccess(), readBarrier, DEFAULT_REPLACER, args);
         }
 
-        public void lower(G1PostWriteBarrier writeBarrierPost, @SuppressWarnings("unused") LoweringTool tool) {
+        public void lower(G1PostWriteBarrier writeBarrierPost, HotSpotRegistersProvider registers) {
             if (writeBarrierPost.alwaysNull()) {
                 writeBarrierPost.graph().removeFixed(writeBarrierPost);
                 return;
@@ -384,23 +387,26 @@
             args.add("value", writeBarrierPost.getValue());
             args.add("location", writeBarrierPost.getLocation());
             args.addConst("usePrecise", writeBarrierPost.usePrecise());
+            args.addConst("threadRegister", registers.getThreadRegister());
             args.addConst("trace", traceBarrier());
             template(args).instantiate(providers.getMetaAccess(), writeBarrierPost, DEFAULT_REPLACER, args);
         }
 
-        public void lower(G1ArrayRangePreWriteBarrier arrayRangeWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) {
+        public void lower(G1ArrayRangePreWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers) {
             Arguments args = new Arguments(g1ArrayRangePreWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage());
             args.add("object", arrayRangeWriteBarrier.getObject());
             args.add("startIndex", arrayRangeWriteBarrier.getStartIndex());
             args.add("length", arrayRangeWriteBarrier.getLength());
+            args.addConst("threadRegister", registers.getThreadRegister());
             template(args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
         }
 
-        public void lower(G1ArrayRangePostWriteBarrier arrayRangeWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) {
+        public void lower(G1ArrayRangePostWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers) {
             Arguments args = new Arguments(g1ArrayRangePostWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage());
             args.add("object", arrayRangeWriteBarrier.getObject());
             args.add("startIndex", arrayRangeWriteBarrier.getStartIndex());
             args.add("length", arrayRangeWriteBarrier.getLength());
+            args.addConst("threadRegister", registers.getThreadRegister());
             template(args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Wed Nov 20 15:58:58 2013 +0100
@@ -35,7 +35,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.Snippet.Fold;
+import com.oracle.graal.replacements.Snippet.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -62,12 +62,19 @@
         return false;
     }
 
+    @Override
+    protected Object getConstantParameterValue(int index, String name) {
+        assert index == 2;
+        return providers.getRegisters().getThreadRegister();
+    }
+
     @Snippet
-    private static void exceptionHandler(Object exception, Word exceptionPc) {
-        checkNoExceptionInThread(assertionsEnabled());
+    private static void exceptionHandler(Object exception, Word exceptionPc, @ConstantParameter Register threadRegister) {
+        Word thread = registerAsWord(threadRegister);
+        checkNoExceptionInThread(thread, assertionsEnabled());
         checkExceptionNotNull(assertionsEnabled(), exception);
-        writeExceptionOop(thread(), exception);
-        writeExceptionPc(thread(), exceptionPc);
+        writeExceptionOop(thread, exception);
+        writeExceptionPc(thread, exceptionPc);
         if (logging()) {
             printf("handling exception %p (", Word.fromObject(exception).rawValue());
             decipher(Word.fromObject(exception).rawValue());
@@ -79,7 +86,7 @@
         // patch throwing pc into return address so that deoptimization finds the right debug info
         patchReturnAddress(exceptionPc);
 
-        Word handlerPc = exceptionHandlerForPc(EXCEPTION_HANDLER_FOR_PC, thread());
+        Word handlerPc = exceptionHandlerForPc(EXCEPTION_HANDLER_FOR_PC, thread);
 
         if (logging()) {
             printf("handler for exception %p at %p is at %p (", Word.fromObject(exception).rawValue(), exceptionPc.rawValue(), handlerPc.rawValue());
@@ -91,16 +98,16 @@
         patchReturnAddress(handlerPc);
     }
 
-    static void checkNoExceptionInThread(boolean enabled) {
+    static void checkNoExceptionInThread(Word thread, boolean enabled) {
         if (enabled) {
-            Object currentException = readExceptionOop(thread());
+            Object currentException = readExceptionOop(thread);
             if (currentException != null) {
                 fatal("exception object in thread must be null, not %p", Word.fromObject(currentException).rawValue());
             }
             if (cAssertionsEnabled()) {
                 // This thread-local is only cleared in DEBUG builds of the VM
                 // (see OptoRuntime::generate_exception_blob)
-                Word currentExceptionPc = readExceptionPc(thread());
+                Word currentExceptionPc = readExceptionPc(thread);
                 if (currentExceptionPc.notEqual(Word.zero())) {
                     fatal("exception PC in thread must be zero, not %p", currentExceptionPc.rawValue());
                 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Wed Nov 20 15:58:58 2013 +0100
@@ -54,8 +54,8 @@
  * deoptimization while the call is in progress. And since these are foreign/runtime calls on slow
  * paths, we don't want to force the register allocator to spill around the call. As such, this stub
  * saves and restores all allocatable registers. It also
- * {@linkplain StubUtil#handlePendingException(boolean) handles} any exceptions raised during the
- * foreign call.
+ * {@linkplain StubUtil#handlePendingException(Word, boolean) handles} any exceptions raised during
+ * the foreign call.
  */
 public class ForeignCallStub extends Stub {
 
@@ -226,9 +226,9 @@
         LocalNode[] locals = createLocals(builder, args);
         List<InvokeNode> invokes = new ArrayList<>(3);
 
-        ReadRegisterNode thread = prependThread || isObjectResult ? builder.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), true, false)) : null;
+        ReadRegisterNode thread = builder.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), true, false));
         ValueNode result = createTargetCall(builder, locals, thread);
-        invokes.add(createInvoke(builder, StubUtil.class, "handlePendingException", ConstantNode.forBoolean(isObjectResult, builder.graph)));
+        invokes.add(createInvoke(builder, StubUtil.class, "handlePendingException", thread, ConstantNode.forBoolean(isObjectResult, builder.graph)));
         if (isObjectResult) {
             InvokeNode object = createInvoke(builder, HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread);
             result = createInvoke(builder, StubUtil.class, "verifyObject", object);
@@ -276,7 +276,7 @@
         return locals;
     }
 
-    private InvokeNode createInvoke(GraphBuilder builder, Class<?> declaringClass, String name, ValueNode... hpeArgs) {
+    private InvokeNode createInvoke(GraphBuilder builder, Class<?> declaringClass, String name, ValueNode... args) {
         ResolvedJavaMethod method = null;
         for (Method m : declaringClass.getDeclaredMethods()) {
             if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(name)) {
@@ -285,12 +285,25 @@
             }
         }
         assert method != null : "did not find method in " + declaringClass + " named " + name;
-        JavaType returnType = method.getSignature().getReturnType(null);
-        MethodCallTargetNode callTarget = builder.graph.add(new MethodCallTargetNode(InvokeKind.Static, method, hpeArgs, returnType));
+        Signature signature = method.getSignature();
+        JavaType returnType = signature.getReturnType(null);
+        assert checkArgs(method, args);
+        MethodCallTargetNode callTarget = builder.graph.add(new MethodCallTargetNode(InvokeKind.Static, method, args, returnType));
         InvokeNode invoke = builder.append(new InvokeNode(callTarget, FrameState.UNKNOWN_BCI));
         return invoke;
     }
 
+    private boolean checkArgs(ResolvedJavaMethod method, ValueNode... args) {
+        Signature signature = method.getSignature();
+        assert signature.getParameterCount(false) == args.length : target + ": wrong number of arguments to " + method;
+        for (int i = 0; i != args.length; i++) {
+            Kind expected = signature.getParameterKind(i).getStackKind();
+            Kind actual = args[i].stamp().kind();
+            assert expected == actual : target + ": wrong kind of value for argument " + i + " of calls to " + method + " [" + actual + " != " + expected + "]";
+        }
+        return true;
+    }
+
     private StubForeignCallNode createTargetCall(GraphBuilder builder, LocalNode[] locals, ReadRegisterNode thread) {
         if (prependThread) {
             ValueNode[] targetArguments = new ValueNode[1 + locals.length];
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Wed Nov 20 15:58:58 2013 +0100
@@ -70,6 +70,7 @@
         args.add("hub", null);
         args.add("length", null);
         args.addConst("intArrayHub", intArrayHub);
+        args.addConst("threadRegister", providers.getRegisters().getThreadRegister());
         return args;
     }
 
@@ -87,7 +88,7 @@
      * @param intArrayHub the hub for {@code int[].class}
      */
     @Snippet
-    private static Object newArray(Word hub, int length, @ConstantParameter Word intArrayHub) {
+    private static Object newArray(Word hub, int length, @ConstantParameter Word intArrayHub, @ConstantParameter Register threadRegister) {
         int layoutHelper = hub.readInt(layoutHelperOffset(), LocationIdentity.FINAL_LOCATION);
         int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
         int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask();
@@ -101,8 +102,9 @@
         }
 
         // check that array length is small enough for fast path.
+        Word thread = registerAsWord(threadRegister);
         if (length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) {
-            Word memory = refillAllocate(intArrayHub, sizeInBytes, logging());
+            Word memory = refillAllocate(thread, intArrayHub, sizeInBytes, logging());
             if (memory.notEqual(0)) {
                 if (logging()) {
                     printf("newArray: allocated new array at %p\n", memory.rawValue());
@@ -114,9 +116,9 @@
             printf("newArray: calling new_array_c\n");
         }
 
-        newArrayC(NEW_ARRAY_C, thread(), hub, length);
-        handlePendingException(true);
-        return verifyObject(getAndClearObjectResult(thread()));
+        newArrayC(NEW_ARRAY_C, thread, hub, length);
+        handlePendingException(thread, true);
+        return verifyObject(getAndClearObjectResult(thread));
     }
 
     public static final ForeignCallDescriptor NEW_ARRAY_C = descriptorFor(NewArrayStub.class, "newArrayC");
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Wed Nov 20 15:58:58 2013 +0100
@@ -70,11 +70,11 @@
         Arguments args = new Arguments(stub, GuardsStage.FLOATING_GUARDS);
         args.add("hub", null);
         args.addConst("intArrayHub", intArrayHub);
+        args.addConst("threadRegister", providers.getRegisters().getThreadRegister());
         return args;
     }
 
-    private static Word allocate(int size) {
-        Word thread = thread();
+    private static Word allocate(Word thread, int size) {
         Word top = readTlabTop(thread);
         Word end = readTlabEnd(thread);
         Word newTop = top.add(size);
@@ -102,11 +102,12 @@
      * @param intArrayHub the hub for {@code int[].class}
      */
     @Snippet
-    private static Object newInstance(Word hub, @ConstantParameter Word intArrayHub) {
+    private static Object newInstance(Word hub, @ConstantParameter Word intArrayHub, @ConstantParameter Register threadRegister) {
         int sizeInBytes = hub.readInt(klassInstanceSizeOffset(), LocationIdentity.FINAL_LOCATION);
+        Word thread = registerAsWord(threadRegister);
         if (!forceSlowPath() && inlineContiguousAllocationSupported()) {
             if (hub.readByte(klassStateOffset(), CLASS_STATE_LOCATION) == klassStateFullyInitialized()) {
-                Word memory = refillAllocate(intArrayHub, sizeInBytes, logging());
+                Word memory = refillAllocate(thread, intArrayHub, sizeInBytes, logging());
                 if (memory.notEqual(0)) {
                     Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
                     initializeObjectHeader(memory, prototypeMarkWord, hub);
@@ -122,9 +123,9 @@
             printf("newInstance: calling new_instance_c\n");
         }
 
-        newInstanceC(NEW_INSTANCE_C, thread(), hub);
-        handlePendingException(true);
-        return verifyObject(getAndClearObjectResult(thread()));
+        newInstanceC(NEW_INSTANCE_C, thread, hub);
+        handlePendingException(thread, true);
+        return verifyObject(getAndClearObjectResult(thread));
     }
 
     /**
@@ -133,10 +134,11 @@
      * @param intArrayHub the hub for {@code int[].class}
      * @param sizeInBytes the size of the allocation
      * @param log specifies if logging is enabled
+     * 
      * @return the newly allocated, uninitialized chunk of memory, or {@link Word#zero()} if the
      *         operation was unsuccessful
      */
-    static Word refillAllocate(Word intArrayHub, int sizeInBytes, boolean log) {
+    static Word refillAllocate(Word thread, Word intArrayHub, int sizeInBytes, boolean log) {
         // If G1 is enabled, the "eden" allocation space is not the same always
         // and therefore we have to go to slowpath to allocate a new TLAB.
         if (useG1GC()) {
@@ -148,7 +150,6 @@
         Word intArrayMarkWord = Word.unsigned(tlabIntArrayMarkWord());
         int alignmentReserveInBytes = tlabAlignmentReserveInHeapWords() * wordSize();
 
-        Word thread = thread();
         Word top = readTlabTop(thread);
         Word end = readTlabEnd(thread);
 
@@ -206,7 +207,7 @@
                 end = top.add(tlabRefillSizeInBytes.subtract(alignmentReserveInBytes));
                 initializeTlab(thread, top, end);
 
-                return NewInstanceStub.allocate(sizeInBytes);
+                return NewInstanceStub.allocate(thread, sizeInBytes);
             } else {
                 return Word.zero();
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Wed Nov 20 15:58:58 2013 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodes.*;
@@ -82,11 +83,21 @@
     protected Arguments makeArguments(SnippetInfo stub) {
         Arguments args = new Arguments(stub, GuardsStage.FLOATING_GUARDS);
         for (int i = 0; i < stub.getParameterCount(); i++) {
-            args.add(stub.getParameterName(i), null);
+            String name = stub.getParameterName(i);
+            if (stub.isConstantParameter(i)) {
+                args.addConst(name, getConstantParameterValue(i, name));
+            } else {
+                assert !stub.isVarargsParameter(i);
+                args.add(name, null);
+            }
         }
         return args;
     }
 
+    protected Object getConstantParameterValue(int index, String name) {
+        throw new GraalInternalError("%s must override getConstantParameterValue() to provide a value for parameter %d%s", getClass().getName(), index, name == null ? "" : " (" + name + ")");
+    }
+
     @Override
     protected Object debugScopeContext() {
         return getInstalledCodeOwner();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java	Wed Nov 20 15:58:58 2013 +0100
@@ -73,10 +73,10 @@
         return new ForeignCallDescriptor(name, found.getReturnType(), cCallTypes);
     }
 
-    public static void handlePendingException(boolean isObjectResult) {
-        if (clearPendingException(thread())) {
+    public static void handlePendingException(Word thread, boolean isObjectResult) {
+        if (clearPendingException(thread)) {
             if (isObjectResult) {
-                getAndClearObjectResult(thread());
+                getAndClearObjectResult(thread);
             }
             DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Wed Nov 20 15:58:58 2013 +0100
@@ -36,7 +36,7 @@
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.Snippet.Fold;
+import com.oracle.graal.replacements.Snippet.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -58,8 +58,14 @@
         return false;
     }
 
+    @Override
+    protected Object getConstantParameterValue(int index, String name) {
+        assert index == 2;
+        return providers.getRegisters().getThreadRegister();
+    }
+
     @Snippet
-    private static void unwindExceptionToCaller(Object exception, Word returnAddress) {
+    private static void unwindExceptionToCaller(Object exception, Word returnAddress, @ConstantParameter Register threadRegister) {
         Pointer exceptionOop = Word.fromObject(exception);
         if (logging()) {
             printf("unwinding exception %p (", exceptionOop.rawValue());
@@ -68,10 +74,11 @@
             decipher(returnAddress.rawValue());
             printf(")\n");
         }
-        checkNoExceptionInThread(assertionsEnabled());
+        Word thread = registerAsWord(threadRegister);
+        checkNoExceptionInThread(thread, assertionsEnabled());
         checkExceptionNotNull(assertionsEnabled(), exception);
 
-        Word handlerInCallerPc = exceptionHandlerForReturnAddress(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, thread(), returnAddress);
+        Word handlerInCallerPc = exceptionHandlerForReturnAddress(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, thread, returnAddress);
 
         if (logging()) {
             printf("handler for exception %p at return address %p is at %p (", exceptionOop.rawValue(), returnAddress.rawValue(), handlerInCallerPc.rawValue());
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Wed Nov 20 15:58:58 2013 +0100
@@ -34,7 +34,9 @@
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
 import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.StandardOp.NullCheck;
 import com.oracle.graal.lir.asm.*;
 
 public class AMD64Move {
@@ -93,7 +95,7 @@
         }
     }
 
-    public abstract static class MemOp extends AMD64LIRInstruction {
+    public abstract static class MemOp extends AMD64LIRInstruction implements ImplicitNullCheck {
 
         protected final Kind kind;
         @Use({COMPOSITE}) protected AMD64AddressValue address;
@@ -114,6 +116,14 @@
             }
             emitMemAccess(masm);
         }
+
+        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+            if (state == null && value.equals(address.base) && address.index == Value.ILLEGAL && address.displacement >= 0 && address.displacement < implicitNullCheckLimit) {
+                state = nullCheckState;
+                return true;
+            }
+            return false;
+        }
     }
 
     public static class LoadOp extends MemOp {
@@ -295,7 +305,7 @@
         }
     }
 
-    public static class NullCheckOp extends AMD64LIRInstruction {
+    public static class NullCheckOp extends AMD64LIRInstruction implements NullCheck {
 
         @Use({REG}) protected AllocatableValue input;
         @State protected LIRFrameState state;
@@ -310,6 +320,14 @@
             tasm.recordImplicitException(masm.codeBuffer.position(), state);
             masm.nullCheck(asRegister(input));
         }
+
+        public Value getCheckedValue() {
+            return input;
+        }
+
+        public LIRFrameState getState() {
+            return state;
+        }
     }
 
     @Opcode("CAS")
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Wed Nov 20 15:58:58 2013 +0100
@@ -32,7 +32,9 @@
 import com.oracle.graal.asm.sparc.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
 import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.StandardOp.NullCheck;
 import com.oracle.graal.lir.asm.*;
 
 public class SPARCMove {
@@ -91,7 +93,7 @@
         }
     }
 
-    public abstract static class MemOp extends SPARCLIRInstruction {
+    public abstract static class MemOp extends SPARCLIRInstruction implements ImplicitNullCheck {
 
         protected final Kind kind;
         @Use({COMPOSITE}) protected SPARCAddressValue address;
@@ -112,6 +114,14 @@
             }
             emitMemAccess(masm);
         }
+
+        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+            if (state == null && value.equals(address.base) && address.index == Value.ILLEGAL && address.displacement >= 0 && address.displacement < implicitNullCheckLimit) {
+                state = nullCheckState;
+                return true;
+            }
+            return false;
+        }
     }
 
     public static class LoadOp extends MemOp {
@@ -193,7 +203,7 @@
         }
     }
 
-    public static class NullCheckOp extends SPARCLIRInstruction {
+    public static class NullCheckOp extends SPARCLIRInstruction implements NullCheck {
 
         @Use({REG}) protected AllocatableValue input;
         @State protected LIRFrameState state;
@@ -208,6 +218,14 @@
             tasm.recordImplicitException(masm.codeBuffer.position(), state);
             new Ldx(new SPARCAddress(asRegister(input), 0), r0).emit(masm);
         }
+
+        public Value getCheckedValue() {
+            return input;
+        }
+
+        public LIRFrameState getState() {
+            return state;
+        }
     }
 
     @Opcode("CAS")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java	Wed Nov 20 15:58:58 2013 +0100
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir;
+
+import java.util.*;
+
+import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
+import com.oracle.graal.lir.StandardOp.NullCheck;
+import com.oracle.graal.nodes.cfg.*;
+
+public final class NullCheckOptimizer {
+
+    public static void optimize(LIR ir, int implicitNullCheckLimit) {
+        List<Block> blocks = ir.codeEmittingOrder();
+        NullCheckOptimizer.foldNullChecks(ir, blocks, implicitNullCheckLimit);
+    }
+
+    private NullCheckOptimizer() {
+    }
+
+    private static void foldNullChecks(LIR ir, List<Block> blocks, int implicitNullCheckLimit) {
+        for (Block block : blocks) {
+            List<LIRInstruction> list = ir.lir(block);
+
+            if (!list.isEmpty()) {
+
+                LIRInstruction lastInstruction = list.get(0);
+                for (int i = 0; i < list.size(); i++) {
+                    LIRInstruction instruction = list.get(i);
+
+                    if (instruction instanceof ImplicitNullCheck && lastInstruction instanceof NullCheck) {
+                        NullCheck nullCheck = (NullCheck) lastInstruction;
+                        ImplicitNullCheck implicitNullCheck = (ImplicitNullCheck) instruction;
+                        if (implicitNullCheck.makeNullCheckFor(nullCheck.getCheckedValue(), nullCheck.getState(), implicitNullCheckLimit)) {
+                            list.remove(i - 1);
+                            if (i < list.size()) {
+                                instruction = list.get(i);
+                            }
+                        }
+                    }
+                    lastInstruction = instruction;
+                }
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Wed Nov 20 15:58:58 2013 +0100
@@ -51,6 +51,16 @@
         void setFallThroughTarget(LabelRef target);
     }
 
+    public interface NullCheck {
+        Value getCheckedValue();
+
+        LIRFrameState getState();
+    }
+
+    public interface ImplicitNullCheck {
+        boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit);
+    }
+
     /**
      * LIR operation that defines the position of a label. The first operation of every block must
      * implement this interface.
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java	Wed Nov 20 15:58:23 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java	Wed Nov 20 15:58:58 2013 +0100
@@ -56,6 +56,7 @@
 
     public ReadRegisterNode(Register register, Kind kind, boolean directUse, boolean incoming) {
         super(StampFactory.forKind(kind));
+        assert register != null;
         this.register = register;
         this.directUse = directUse;
         this.incoming = incoming;
@@ -67,6 +68,7 @@
      */
     public ReadRegisterNode(Register register, boolean directUse, boolean incoming) {
         super(StampFactory.forNodeIntrinsic());
+        assert register != null;
         this.register = register;
         this.directUse = directUse;
         this.incoming = incoming;
--- a/src/gpu/hsail/vm/hsailKernelArguments.cpp	Wed Nov 20 15:58:23 2013 +0100
+++ b/src/gpu/hsail/vm/hsailKernelArguments.cpp	Wed Nov 20 15:58:58 2013 +0100
@@ -93,7 +93,7 @@
 void HSAILKernelArguments::do_int() {
   // The last int is the iteration variable in an IntStream, but we don't pass it
   // since we use the HSAIL workitemid in place of that int value
-  if (_index == _length) {
+  if (_parameter_index == _parameter_count - 1) {
     if (TraceGPUInteraction) {
       tty->print_cr("[HSAIL] HSAILKernelArguments::not pushing trailing int");
     }
@@ -136,17 +136,19 @@
 
 void HSAILKernelArguments::do_object() {
   if (TraceGPUInteraction) {
-    tty->print_cr("[HSAIL] HSAILKernelArguments::do_object.");
+    tty->print_cr("[HSAIL] HSAILKernelArguments::do_object, _parameter_index=%d", _parameter_index);
   }
-  if (_index == _length) {  
-    // last arg in object stream lambda is  the object stream source array
+  oop arg = _args->obj_at(_index++);
+
+  // check if this is last arg in signature
+  // an object as last parameter requires an object stream source array to be passed
+  if (_parameter_index == _parameter_count - 1) {
     if (TraceGPUInteraction) {
       tty->print_cr("[HSAIL] HSAILKernelArguments::trailing object ref should be object source array ref");
     }
+    assert(arg->is_objArray(), "arg type mismatch");
   }
 
-  oop arg = _args->obj_at(_index++);
-  assert(arg->is_array(), "arg type mismatch");
   if (TraceGPUInteraction) {
     tty->print_cr("[HSAIL] HSAILKernelArguments::do_object, 0x%08x is a %s", (address) arg, arg->klass()->external_name());
   }
@@ -157,24 +159,9 @@
 
 void HSAILKernelArguments::do_object(int begin, int end) {
   if (TraceGPUInteraction) {
-    tty->print_cr("[HSAIL] HSAILKernelArguments::do_object(int begin, int end).");
-  }
-
-  if ((!_is_static && (_index >=(_length-1))) || (_is_static && (_index >=(_length)))) {
-    // last arg in object stream lambda is  the object stream source array
-    if (TraceGPUInteraction) {
-      tty->print_cr("[HSAIL] HSAILKernelArguments::trailing object ref should be object source array ref");
-    }
+      tty->print_cr("[HSAIL] HSAILKernelArguments::do_object(int begin, int end), begin=%d, end=%d.", begin, end);
   }
-  
-  oop arg = _args->obj_at(_index++);
-  assert(arg->is_array(), "arg type mismatch");
-  if (TraceGPUInteraction) {
-    tty->print_cr("[HSAIL] HSAILKernelArguments::do_object(int, int), 0x%08x is a %s", (address) arg, arg->klass()->external_name());
-  }
-    
-  bool pushed = gpu::Hsail::_okra_push_object(_kernel, arg);
-  assert(pushed == true, "arg push failed");  
+  do_object();
 }
 
 void HSAILKernelArguments::do_void() {
--- a/src/gpu/hsail/vm/hsailKernelArguments.hpp	Wed Nov 20 15:58:23 2013 +0100
+++ b/src/gpu/hsail/vm/hsailKernelArguments.hpp	Wed Nov 20 15:58:58 2013 +0100
@@ -42,6 +42,8 @@
   int _index;
   // Kernel to push into
   address _kernel;
+  // number of parameters in the signature
+  int _parameter_count;
 
   bool _is_static;
   
@@ -55,8 +57,10 @@
     _args = args;
     _kernel = kernel;
     _is_static = is_static;
-    
+
     _length = args->length();
+    _parameter_count = ArgumentCount(signature).size();
+
     if (TraceGPUInteraction) {
       tty->print_cr("[HSAIL] sig:%s  args length=%d", signature->as_C_string(), _length);
     }