changeset 19506:8c7536965c95

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Thu, 19 Feb 2015 15:44:05 +0100
parents 068256ee3b90 (current diff) 95aa11d4822d (diff)
children 1cde96b96673 387f86ea4d10
files graal/com.oracle.graal.java/src/com/oracle/graal/java/GraalDirectivePlugins.java graal/com.oracle.graal.java/src/com/oracle/graal/java/StandardGraphBuilderPlugins.java
diffstat 17 files changed, 607 insertions(+), 298 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Thu Feb 19 15:43:41 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Thu Feb 19 15:44:05 2015 +0100
@@ -33,6 +33,7 @@
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
 
 /**
  * Common functionality of HotSpot host backends.
@@ -73,7 +74,7 @@
         try (InitTimer st = timer("graphBuilderPlugins.initialize")) {
             GraphBuilderPhase phase = (GraphBuilderPhase) providers.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous();
             InvocationPlugins plugins = phase.getGraphBuilderConfig().getInvocationPlugins();
-            registerInvocationPlugins(providers.getMetaAccess(), plugins);
+            registerInvocationPlugins(providers, plugins);
         }
 
         try (InitTimer st = timer("foreignCalls.initialize")) {
@@ -105,8 +106,8 @@
         }
     }
 
-    protected void registerInvocationPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, plugins);
-        HotSpotGraphBuilderPlugins.registerInvocationPlugins(metaAccess, plugins);
+    protected void registerInvocationPlugins(HotSpotProviders providers, InvocationPlugins plugins) {
+        StandardGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), plugins);
+        HotSpotGraphBuilderPlugins.registerInvocationPlugins(providers, plugins);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Thu Feb 19 15:43:41 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Thu Feb 19 15:44:05 2015 +0100
@@ -22,28 +22,46 @@
  */
 package com.oracle.graal.hotspot.meta;
 
+import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.java.GraphBuilderContext.*;
+import static java.lang.Character.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.java.GraphBuilderPlugin.InvocationPlugin;
 import com.oracle.graal.java.InvocationPlugins.Registration;
 import com.oracle.graal.java.InvocationPlugins.Registration.Receiver;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.options.*;
+import com.oracle.graal.word.*;
+import com.oracle.graal.word.nodes.*;
 
 /**
  * Provides HotSpot specific {@link InvocationPlugin}s.
  */
 public class HotSpotGraphBuilderPlugins {
-    public static void registerInvocationPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        // Object.class
+    public static void registerInvocationPlugins(HotSpotProviders providers, InvocationPlugins plugins) {
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+        SnippetReflectionProvider snippetReflection = providers.getSnippetReflection();
+        Kind wordKind = providers.getCodeCache().getTarget().wordKind;
+
+        registerObjectPlugins(plugins, metaAccess);
+        registerClassPlugins(plugins, metaAccess);
+        registerStableOptionPlugins(plugins, metaAccess);
+        registerMetaspacePointerPlugins(plugins, metaAccess, snippetReflection, wordKind);
+    }
+
+    private static void registerObjectPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess) {
         Registration r = new Registration(plugins, metaAccess, Object.class);
         r.register1("getClass", Receiver.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext builder, ValueNode rcvr) {
@@ -60,9 +78,10 @@
                 return true;
             }
         });
+    }
 
-        // Class.class
-        r = new Registration(plugins, metaAccess, Class.class);
+    private static void registerClassPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess) {
+        Registration r = new Registration(plugins, metaAccess, Class.class);
         r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext builder, ValueNode rcvr, ValueNode object) {
                 if (rcvr.isConstant() && !rcvr.isNullConstant()) {
@@ -88,9 +107,10 @@
                 return false;
             }
         });
+    }
 
-        // StableOptionValue.class
-        r = new Registration(plugins, metaAccess, StableOptionValue.class);
+    private static void registerStableOptionPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess) {
+        Registration r = new Registration(plugins, metaAccess, StableOptionValue.class);
         r.register1("getValue", Receiver.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext builder, ValueNode rcvr) {
                 if (rcvr.isConstant() && !rcvr.isNullConstant()) {
@@ -104,4 +124,130 @@
             }
         });
     }
+
+    private static void registerMetaspacePointerPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, Kind wordKind) {
+        Registration r = new Registration(plugins, metaAccess, MetaspacePointer.class);
+        r.register1("isNull", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode pointer) {
+                assert pointer.stamp() instanceof MetaspacePointerStamp;
+                IsNullNode isNull = builder.append(new IsNullNode(pointer));
+                ConstantNode trueValue = builder.append(ConstantNode.forBoolean(true));
+                ConstantNode falseValue = builder.append(ConstantNode.forBoolean(false));
+                builder.push(Kind.Boolean.getStackKind(), builder.append(new ConditionalNode(isNull, trueValue, falseValue)));
+                return true;
+            }
+        });
+        r.register1("asWord", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode pointer) {
+                builder.append(new PointerCastNode(StampFactory.forKind(wordKind), pointer));
+                return true;
+            }
+        });
+        r.register2("readObject", Receiver.class, int.class, new ReadOp(snippetReflection, wordKind, Kind.Object, BarrierType.NONE, true));
+        r.register3("readObject", Receiver.class, int.class, LocationIdentity.class, new ReadOp(snippetReflection, wordKind, Kind.Object, BarrierType.NONE, true));
+        r.register3("readObject", Receiver.class, int.class, BarrierType.class, new ReadOp(snippetReflection, wordKind, Kind.Object, BarrierType.NONE, true));
+        r.register2("readObject", Receiver.class, WordBase.class, new ReadOp(snippetReflection, wordKind, Kind.Object, BarrierType.NONE, true));
+        r.register3("readObject", Receiver.class, WordBase.class, LocationIdentity.class, new ReadOp(snippetReflection, wordKind, Kind.Object, BarrierType.NONE, true));
+        r.register3("readObject", Receiver.class, WordBase.class, BarrierType.class, new ReadOp(snippetReflection, wordKind, Kind.Object, BarrierType.NONE, true));
+
+        registerWordOpPlugins(r, snippetReflection, wordKind, Kind.Byte, Kind.Short, Kind.Char, Kind.Int, Kind.Float, Kind.Long, Kind.Double);
+    }
+
+    private static void registerWordOpPlugins(Registration r, SnippetReflectionProvider snippetReflection, Kind wordKind, Kind... kinds) {
+        for (Kind kind : kinds) {
+            String kindName = kind.getJavaName();
+            kindName = toUpperCase(kindName.charAt(0)) + kindName.substring(1);
+            String getName = "read" + kindName;
+            // String putName = "write" + kindName;
+            r.register2(getName, Receiver.class, int.class, new ReadOp(snippetReflection, wordKind, kind));
+            r.register3(getName, Receiver.class, int.class, LocationIdentity.class, new ReadOp(snippetReflection, wordKind, kind));
+        }
+    }
+
+    static class ReadOp implements InvocationPlugin {
+        final SnippetReflectionProvider snippetReflection;
+        final Kind wordKind;
+        final Kind resultKind;
+        final BarrierType barrierType;
+        final boolean compressible;
+
+        public ReadOp(SnippetReflectionProvider snippetReflection, Kind wordKind, Kind resultKind, BarrierType barrierType, boolean compressible) {
+            this.snippetReflection = snippetReflection;
+            this.wordKind = wordKind;
+            this.resultKind = resultKind;
+            this.barrierType = barrierType;
+            this.compressible = compressible;
+        }
+
+        public ReadOp(SnippetReflectionProvider snippetReflection, Kind wordKind, Kind resultKind) {
+            this(snippetReflection, wordKind, resultKind, BarrierType.NONE, false);
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode pointer, ValueNode offset) {
+            LocationNode location = makeLocation(builder, offset, ANY_LOCATION, wordKind);
+            builder.push(resultKind, builder.append(readOp(builder, resultKind, pointer, location, barrierType, compressible)));
+            return true;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode pointer, ValueNode offset, ValueNode locationIdentityArg) {
+            assert locationIdentityArg.isConstant();
+            LocationIdentity locationIdentity = snippetReflection.asObject(LocationIdentity.class, locationIdentityArg.asJavaConstant());
+            LocationNode location = makeLocation(builder, offset, locationIdentity, wordKind);
+            builder.push(resultKind, builder.append(readOp(builder, resultKind, pointer, location, barrierType, compressible)));
+            return true;
+        }
+    }
+
+    public static ValueNode readOp(GraphBuilderContext builder, Kind readKind, ValueNode base, LocationNode location, BarrierType barrierType, boolean compressible) {
+        JavaReadNode read = builder.append(new JavaReadNode(readKind, base, location, barrierType, compressible));
+        /*
+         * The read must not float outside its block otherwise it may float above an explicit zero
+         * check on its base address.
+         */
+        read.setGuard(builder.getCurrentBlockGuard());
+        return read;
+    }
+
+    public static LocationNode makeLocation(GraphBuilderContext builder, ValueNode offset, LocationIdentity locationIdentity, Kind wordKind) {
+        return builder.append(new IndexedLocationNode(locationIdentity, 0, fromSigned(builder, offset, wordKind), 1));
+    }
+
+    public static LocationNode makeLocation(GraphBuilderContext builder, ValueNode offset, ValueNode locationIdentity, Kind wordKind) {
+        if (locationIdentity.isConstant()) {
+            return makeLocation(builder, offset, builder.getSnippetReflection().asObject(LocationIdentity.class, locationIdentity.asJavaConstant()), wordKind);
+        }
+        return builder.append(new SnippetLocationNode(builder.getSnippetReflection(), locationIdentity, builder.append(ConstantNode.forLong(0)), fromSigned(builder, offset, wordKind),
+                        builder.append(ConstantNode.forInt(1))));
+    }
+
+    public static ValueNode fromUnsigned(GraphBuilderContext builder, ValueNode value, Kind wordKind) {
+        return convert(builder, value, wordKind, true);
+    }
+
+    public static ValueNode fromSigned(GraphBuilderContext builder, ValueNode value, Kind wordKind) {
+        return convert(builder, value, wordKind, false);
+    }
+
+    public static ValueNode toUnsigned(GraphBuilderContext builder, ValueNode value, Kind toKind) {
+        return convert(builder, value, toKind, true);
+    }
+
+    public static ValueNode convert(GraphBuilderContext builder, ValueNode value, Kind toKind, boolean unsigned) {
+        if (value.getKind() == toKind) {
+            return value;
+        }
+
+        if (toKind == Kind.Int) {
+            assert value.getKind() == Kind.Long;
+            return builder.append(new NarrowNode(value, 32));
+        } else {
+            assert toKind == Kind.Long;
+            assert value.getKind().getStackKind() == Kind.Int;
+            if (unsigned) {
+                return builder.append(new ZeroExtendNode(value, 64));
+            } else {
+                return builder.append(new SignExtendNode(value, 64));
+            }
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Thu Feb 19 15:43:41 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Thu Feb 19 15:44:05 2015 +0100
@@ -22,14 +22,21 @@
  */
 package com.oracle.graal.hotspot.meta;
 
+import static com.oracle.graal.api.meta.MetaUtil.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.replacements.NodeIntrinsificationPhase.*;
+
+import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.java.GraphBuilderConfiguration.DebugInfoMode;
+import com.oracle.graal.java.GraphBuilderPlugin.AnnotatedInvocationPlugin;
 import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin;
 import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin;
 import com.oracle.graal.lir.phases.*;
@@ -39,6 +46,7 @@
 import com.oracle.graal.options.DerivedOptionValue.OptionSupplier;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.replacements.*;
 
 /**
  * HotSpot implementation of {@link SuitesProvider}.
@@ -104,6 +112,20 @@
         return ret;
     }
 
+    NodeIntrinsificationPhase intrinsifier;
+
+    NodeIntrinsificationPhase getIntrinsifier() {
+        if (intrinsifier == null) {
+            HotSpotProviders providers = runtime.getHostProviders();
+            intrinsifier = new NodeIntrinsificationPhase(providers, providers.getSnippetReflection());
+        }
+        return intrinsifier;
+    }
+
+    MetaAccessProvider getMetaAccess() {
+        return runtime.getHostProviders().getMetaAccess();
+    }
+
     protected PhaseSuite<HighTierContext> createGraphBuilderSuite(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, Replacements replacements) {
         PhaseSuite<HighTierContext> suite = new PhaseSuite<>();
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault();
@@ -127,12 +149,57 @@
                     if (subst != null) {
                         return subst;
                     }
+                    if (builder.parsingReplacement() && method.getAnnotation(NodeIntrinsic.class) == null) {
+                        return method;
+                    }
                     if (method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && depth < InlineDuringParsingMaxDepth.getValue()) {
                         return method;
                     }
                     return null;
                 }
             });
+            config.setAnnotatedInvocationPlugin(new AnnotatedInvocationPlugin() {
+                public boolean apply(GraphBuilderContext builder, ResolvedJavaMethod method, ValueNode[] args) {
+                    if (builder.parsingReplacement()) {
+                        @SuppressWarnings("hiding")
+                        NodeIntrinsificationPhase intrinsifier = getIntrinsifier();
+                        NodeIntrinsic intrinsic = intrinsifier.getIntrinsic(method);
+                        if (intrinsic != null) {
+                            Signature sig = method.getSignature();
+                            Kind returnKind = sig.getReturnKind();
+                            Stamp stamp = StampFactory.forKind(returnKind);
+                            if (returnKind == Kind.Object) {
+                                JavaType returnType = sig.getReturnType(method.getDeclaringClass());
+                                if (returnType instanceof ResolvedJavaType) {
+                                    stamp = StampFactory.declared((ResolvedJavaType) returnType);
+                                }
+                            }
+
+                            ValueNode res = intrinsifier.createIntrinsicNode(Arrays.asList(args), stamp, method, builder.getGraph(), intrinsic);
+                            res = builder.append(res);
+                            if (res.getKind().getStackKind() != Kind.Void) {
+                                builder.push(returnKind.getStackKind(), res);
+                            }
+                            return true;
+                        } else if (intrinsifier.isFoldable(method)) {
+                            ResolvedJavaType[] parameterTypes = resolveJavaTypes(method.toParameterTypes(), method.getDeclaringClass());
+                            JavaConstant constant = intrinsifier.tryFold(Arrays.asList(args), parameterTypes, method);
+                            if (!COULD_NOT_FOLD.equals(constant)) {
+                                if (constant != null) {
+                                    // Replace the invoke with the result of the call
+                                    ConstantNode res = builder.append(ConstantNode.forConstant(constant, getMetaAccess()));
+                                    builder.push(res.getKind().getStackKind(), builder.append(res));
+                                } else {
+                                    // This must be a void invoke
+                                    assert method.getSignature().getReturnKind() == Kind.Void;
+                                }
+                                return true;
+                            }
+                        }
+                    }
+                    return false;
+                }
+            });
         }
         suite.appendPhase(new GraphBuilderPhase(config));
         return suite;
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Thu Feb 19 15:43:41 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Thu Feb 19 15:44:05 2015 +0100
@@ -37,7 +37,6 @@
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
-import com.oracle.graal.java.GraphBuilderPlugin.InvocationPlugin;
 import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.options.*;
@@ -119,7 +118,7 @@
         if (kind == Kind.Object) {
             value = frameState.xpop();
             // astore and astore_<n> may be used to store a returnAddress (jsr)
-            assert value.getKind() == Kind.Object || value.getKind() == Kind.Int;
+            assert parsingReplacement || (value.getKind() == Kind.Object || value.getKind() == Kind.Int) : value + ":" + value.getKind();
         } else {
             value = frameState.pop(kind);
         }
@@ -573,7 +572,7 @@
     }
 
     private JavaTypeProfile getProfileForTypeCheck(ResolvedJavaType type) {
-        if (profilingInfo == null || !optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) {
+        if (parsingReplacement || profilingInfo == null || !optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) {
             return null;
         } else {
             return profilingInfo.getTypeProfile(bci());
@@ -757,7 +756,7 @@
     private void genGetStatic(JavaField field) {
         Kind kind = field.getKind();
         if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
-            InvocationPlugin.LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getLoadFieldPlugin();
+            LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getLoadFieldPlugin();
             if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field)) {
                 appendOptimizedLoadField(kind, genLoadField(null, (ResolvedJavaField) field));
             }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java	Thu Feb 19 15:43:41 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java	Thu Feb 19 15:44:05 2015 +0100
@@ -36,15 +36,21 @@
     protected T[] lockedObjects;
 
     /**
+     * Specifies if asserting type checks are enabled.
+     */
+    protected final boolean checkTypes;
+
+    /**
      * @see BytecodeFrame#rethrowException
      */
     protected boolean rethrowException;
 
-    public AbstractFrameStateBuilder(ResolvedJavaMethod method) {
+    public AbstractFrameStateBuilder(ResolvedJavaMethod method, boolean checkTypes) {
         this.method = method;
         this.locals = allocateArray(method.getMaxLocals());
         this.stack = allocateArray(Math.max(1, method.getMaxStackSize()));
         this.lockedObjects = allocateArray(0);
+        this.checkTypes = checkTypes;
     }
 
     protected AbstractFrameStateBuilder(S other) {
@@ -54,6 +60,7 @@
         this.stack = other.stack.clone();
         this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone();
         this.rethrowException = other.rethrowException;
+        this.checkTypes = other.checkTypes;
 
         assert locals.length == method.getMaxLocals();
         assert stack.length == Math.max(1, method.getMaxStackSize());
@@ -171,8 +178,8 @@
     public T loadLocal(int i) {
         T x = locals[i];
         assert x != null : i;
-        assert x.getKind().getSlotCount() == 1 || locals[i + 1] == null;
-        assert i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1;
+        assert !checkTypes || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null);
+        assert !checkTypes || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1);
         return x;
     }
 
@@ -184,7 +191,7 @@
      * @param x the instruction which produces the value for the local
      */
     public void storeLocal(int i, T x) {
-        assert x == null || x.getKind() != Kind.Void && x.getKind() != Kind.Illegal : "unexpected value: " + x;
+        assert x == null || !checkTypes || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x;
         locals[i] = x;
         if (x != null && x.getKind().needsTwoSlots()) {
             // if this is a double word, then kill i+1
@@ -211,7 +218,7 @@
      * @param x the instruction to push onto the stack
      */
     public void push(Kind kind, T x) {
-        assert x.getKind() != Kind.Void && x.getKind() != Kind.Illegal;
+        assert !checkTypes || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : x;
         xpush(assertKind(kind, x));
         if (kind.needsTwoSlots()) {
             xpush(null);
@@ -224,7 +231,7 @@
      * @param x the instruction to push onto the stack
      */
     public void xpush(T x) {
-        assert x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal);
+        assert !checkTypes || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal));
         stack[stackSize++] = x;
     }
 
@@ -368,7 +375,7 @@
                 newStackSize--;
                 assert stack[newStackSize].getKind().needsTwoSlots();
             } else {
-                assert stack[newStackSize].getKind().getSlotCount() == 1;
+                assert !checkTypes || (stack[newStackSize].getKind().getSlotCount() == 1);
             }
             result[i] = stack[newStackSize];
         }
@@ -404,7 +411,7 @@
     }
 
     private T assertKind(Kind kind, T x) {
-        assert x != null && x.getKind() == kind : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.getKind());
+        assert x != null && (!checkTypes || x.getKind() == kind) : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.getKind());
         return x;
     }
 
@@ -424,7 +431,7 @@
     }
 
     private T assertObject(T x) {
-        assert x != null && (x.getKind() == Kind.Object);
+        assert x != null && (!checkTypes || (x.getKind() == Kind.Object));
         return x;
     }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraalDirectivePlugins.java	Thu Feb 19 15:43:41 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.java;
-
-import com.oracle.graal.api.directives.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.java.GraphBuilderPlugin.InvocationPlugin;
-import com.oracle.graal.java.InvocationPlugins.Registration;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.debug.*;
-import com.oracle.graal.nodes.extended.*;
-
-public class GraalDirectivePlugins {
-
-    public static void registerInvocationPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, GraalDirectives.class);
-        r.register0("deoptimize", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder) {
-                builder.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
-                return true;
-            }
-        });
-
-        r.register0("deoptimizeAndInvalidate", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder) {
-                builder.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
-                return true;
-            }
-        });
-
-        r.register0("inCompiledCode", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder) {
-                builder.push(Kind.Int, builder.append(ConstantNode.forInt(1)));
-                return true;
-            }
-        });
-
-        r.register0("controlFlowAnchor", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder) {
-                builder.append(new ControlFlowAnchorNode());
-                return true;
-            }
-        });
-
-        r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode probability, ValueNode condition) {
-                builder.push(Kind.Int, builder.append(new BranchProbabilityNode(probability, condition)));
-                return true;
-            }
-        });
-
-        InvocationPlugin blackholePlugin = new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode value) {
-                builder.append(new BlackholeNode(value));
-                return true;
-            }
-        };
-
-        for (Kind kind : Kind.values()) {
-            Class<?> cls = null;
-            switch (kind) {
-                case Object:
-                    cls = Object.class;
-                    break;
-                case Void:
-                case Illegal:
-                    continue;
-                default:
-                    cls = kind.toJavaClass();
-            }
-
-            r.register1("blackhole", cls, blackholePlugin);
-
-            final Kind stackKind = kind.getStackKind();
-            r.register1("opaque", cls, new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext builder, ValueNode value) {
-                    builder.push(stackKind, builder.append(new OpaqueNode(value)));
-                    return true;
-                }
-            });
-        }
-    }
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Thu Feb 19 15:43:41 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Thu Feb 19 15:44:05 2015 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -56,6 +57,8 @@
 
     void push(Kind kind, ValueNode value);
 
+    StructuredGraph getGraph();
+
     /**
      * Determines if the graph builder is parsing a snippet or method substitution.
      */
@@ -71,4 +74,6 @@
         }
         return nonNullValue;
     }
+
+    GuardingNode getCurrentBlockGuard();
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Feb 19 15:43:41 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Feb 19 15:44:05 2015 +0100
@@ -26,6 +26,7 @@
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.bytecode.Bytecodes.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.graph.iterators.NodePredicates.*;
 import static com.oracle.graal.nodes.StructuredGraph.*;
 import static java.lang.String.*;
 
@@ -126,7 +127,7 @@
             int entryBCI = graph.getEntryBCI();
             assert method.getCode() != null : "method must contain bytecodes: " + method;
             this.currentGraph = graph;
-            HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(method, graph, null);
+            HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(method, graph, true, null);
             frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving(), this.graphBuilderConfig.getParameterPlugin());
             TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
             try {
@@ -889,7 +890,8 @@
                     Mark mark = needsNullCheck ? currentGraph.getMark() : null;
                     if (InvocationPlugin.execute(this, plugin, args)) {
                         assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize : "plugin manipulated the stack incorrectly " + targetMethod;
-                        assert !needsNullCheck || containsNullCheckOf(currentGraph.getNewNodes(mark), args[0]) : "plugin needs to null check the receiver of " + targetMethod + ": " + args[0];
+                        assert !needsNullCheck || args[0].usages().filter(isNotA(FrameState.class)).isEmpty() || containsNullCheckOf(currentGraph.getNewNodes(mark), args[0]) : "plugin needs to null check the receiver of " +
+                                        targetMethod + ": " + args[0];
                         return true;
                     }
                     assert nodeCount == currentGraph.getNodeCount() : "plugin that returns false must not create new nodes";
@@ -938,7 +940,13 @@
             private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, boolean isReplacement) {
                 BytecodeParser parser = new BytecodeParser(metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, isReplacement);
                 final FrameState[] lazyFrameState = new FrameState[1];
-                HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(targetMethod, currentGraph, () -> {
+
+                // Replacements often produce nodes with an illegal kind (e.g., pointer stamps)
+                // so the frame state builder should not check the types flowing through the frame
+                // since all such assertions are in terms of Java kinds.
+                boolean checkTypes = !isReplacement;
+
+                HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(targetMethod, currentGraph, checkTypes, () -> {
                     if (lazyFrameState[0] == null) {
                         lazyFrameState[0] = frameState.create(bci());
                     }
@@ -1924,6 +1932,19 @@
             public boolean parsingReplacement() {
                 return parsingReplacement;
             }
+
+            public StructuredGraph getGraph() {
+                return currentGraph;
+            }
+
+            public GuardingNode getCurrentBlockGuard() {
+                return (GuardingNode) getFirstInstruction(currentBlock, getCurrentDimension());
+            }
+
+            @Override
+            public String toString() {
+                return method.format("%H.%n(%p)@") + bci();
+            }
         }
     }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Thu Feb 19 15:43:41 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Thu Feb 19 15:44:05 2015 +0100
@@ -53,8 +53,8 @@
      * @param method the method whose frame is simulated
      * @param graph the target graph of Graal nodes created by the builder
      */
-    public HIRFrameStateBuilder(ResolvedJavaMethod method, StructuredGraph graph, Supplier<FrameState> outerFrameStateSupplier) {
-        super(method);
+    public HIRFrameStateBuilder(ResolvedJavaMethod method, StructuredGraph graph, boolean checkTypes, Supplier<FrameState> outerFrameStateSupplier) {
+        super(method, checkTypes);
 
         assert graph != null;
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/InvocationPlugins.java	Thu Feb 19 15:43:41 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/InvocationPlugins.java	Thu Feb 19 15:44:05 2015 +0100
@@ -222,28 +222,15 @@
         public static boolean check(ResolvedJavaMethod method, InvocationPlugin plugin) {
             int arguments = method.getSignature().getParameterCount(!method.isStatic());
             assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method.format("%H.%n(%p)"));
-            Method expected = null;
             for (Method m : plugin.getClass().getDeclaredMethods()) {
                 if (m.getName().equals("apply")) {
                     Class<?>[] parameterTypes = m.getParameterTypes();
-                    assert Arrays.equals(SIGS[arguments], parameterTypes) : format("graph builder plugin for %s has wrong signature%nexpected: (%s)%n  actual: (%s)", method.format("%H.%n(%p)"),
-                                    sigString(SIGS[arguments]), sigString(m.getParameterTypes()));
-                    expected = m;
+                    if (Arrays.equals(SIGS[arguments], parameterTypes)) {
+                        return true;
+                    }
                 }
             }
-            assert expected != null : format("graph builder plugin %s must define exactly one \"apply\" method, none found", plugin);
-            return true;
-        }
-
-        protected static String sigString(Class<?>... sig) {
-            StringBuilder sb = new StringBuilder();
-            for (Class<?> t : sig) {
-                if (sb.length() != 0) {
-                    sb.append(", ");
-                }
-                sb.append(t.getSimpleName());
-            }
-            return sb.toString();
+            throw new AssertionError(format("graph builder plugin for %s not found", method.format("%H.%n(%p)")));
         }
     }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/StandardGraphBuilderPlugins.java	Thu Feb 19 15:43:41 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.java;
-
-import static com.oracle.graal.java.GraphBuilderContext.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.java.GraphBuilderPlugin.InvocationPlugin;
-import com.oracle.graal.java.InvocationPlugins.Registration;
-import com.oracle.graal.java.InvocationPlugins.Registration.Receiver;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-
-/**
- * Provides non-runtime specific {@link InvocationPlugin}s.
- */
-public class StandardGraphBuilderPlugins {
-    public static void registerInvocationPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, Object.class);
-        r.register1("<init>", Receiver.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode object) {
-                if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) {
-                    builder.append(new RegisterFinalizerNode(object));
-                }
-                return true;
-            }
-        });
-
-        r = new Registration(plugins, metaAccess, Math.class);
-        r.register1("abs", Float.TYPE, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode value) {
-                builder.push(Kind.Float, builder.append(new AbsNode(value)));
-                return true;
-            }
-        });
-        r.register1("abs", Double.TYPE, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode value) {
-                builder.push(Kind.Double, builder.append(new AbsNode(value)));
-                return true;
-            }
-        });
-        r.register1("sqrt", Double.TYPE, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode value) {
-                builder.push(Kind.Double, builder.append(new SqrtNode(value)));
-                return true;
-            }
-        });
-
-        for (Kind kind : Kind.values()) {
-            if (kind.isPrimitive() && kind != Kind.Void) {
-                new BoxPlugin(kind).register(metaAccess, plugins);
-                new UnboxPlugin(kind).register(metaAccess, plugins);
-            }
-        }
-
-        GraalDirectivePlugins.registerInvocationPlugins(metaAccess, plugins);
-    }
-
-    static class BoxPlugin implements InvocationPlugin {
-
-        private final Kind kind;
-
-        BoxPlugin(Kind kind) {
-            this.kind = kind;
-        }
-
-        public boolean apply(GraphBuilderContext builder, ValueNode value) {
-            ResolvedJavaType resultType = builder.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass());
-            builder.push(Kind.Object, builder.append(new BoxNode(value, resultType, kind)));
-            return true;
-        }
-
-        void register(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass());
-            plugins.register(method, this);
-        }
-    }
-
-    static class UnboxPlugin implements InvocationPlugin {
-
-        private final Kind kind;
-
-        UnboxPlugin(Kind kind) {
-            this.kind = kind;
-        }
-
-        public boolean apply(GraphBuilderContext builder, ValueNode value) {
-            ValueNode valueNode = UnboxNode.create(builder.getMetaAccess(), builder.getConstantReflection(), nullCheckedValue(builder, value), kind);
-            builder.push(kind.getStackKind(), builder.append(valueNode));
-            return true;
-        }
-
-        void register(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
-            String name = kind.toJavaClass().getSimpleName() + "Value";
-            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), name);
-            plugins.register(method, this);
-        }
-    }
-}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Thu Feb 19 15:43:41 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Thu Feb 19 15:44:05 2015 +0100
@@ -114,7 +114,7 @@
         return true;
     }
 
-    @SuppressWarnings("serial") private static final JavaConstant COULD_NOT_FOLD = new PrimitiveConstant(Kind.Illegal, 100) {
+    @SuppressWarnings("serial") public static final JavaConstant COULD_NOT_FOLD = new PrimitiveConstant(Kind.Illegal, 100) {
         @Override
         public boolean equals(Object o) {
             return this == o;
@@ -183,14 +183,14 @@
     /**
      * Permits a subclass to override the default definition of "intrinsic".
      */
-    protected NodeIntrinsic getIntrinsic(ResolvedJavaMethod method) {
+    public NodeIntrinsic getIntrinsic(ResolvedJavaMethod method) {
         return method.getAnnotation(Node.NodeIntrinsic.class);
     }
 
     /**
      * Permits a subclass to override the default definition of "foldable".
      */
-    protected boolean isFoldable(ResolvedJavaMethod method) {
+    public boolean isFoldable(ResolvedJavaMethod method) {
         return method.getAnnotation(Fold.class) != null;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Thu Feb 19 15:44:05 2015 +0100
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements;
+
+import static com.oracle.graal.api.code.MemoryBarriers.*;
+import static com.oracle.graal.java.GraphBuilderContext.*;
+import static java.lang.Character.*;
+import sun.misc.*;
+
+import com.oracle.graal.api.directives.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugin.InvocationPlugin;
+import com.oracle.graal.java.InvocationPlugins.Registration;
+import com.oracle.graal.java.InvocationPlugins.Registration.Receiver;
+import com.oracle.graal.nodes.*;
+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.replacements.nodes.*;
+
+/**
+ * Provides non-runtime specific {@link InvocationPlugin}s.
+ */
+public class StandardGraphBuilderPlugins {
+
+    public static void registerInvocationPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        registerObjectPlugins(metaAccess, plugins);
+        registerMathPlugins(metaAccess, plugins);
+        registerUnsafePlugins(metaAccess, plugins);
+        registerGraalDirectivesPlugins(metaAccess, plugins);
+    }
+
+    public static void registerUnsafePlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, Unsafe.class);
+        for (Kind kind : Kind.values()) {
+            if ((kind.isPrimitive() && kind != Kind.Void) || kind == Kind.Object) {
+                String kindName = kind.getJavaName();
+                kindName = toUpperCase(kindName.charAt(0)) + kindName.substring(1);
+                String getName = "get" + kindName;
+                String putName = "put" + kindName;
+                r.register3(getName, Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, false));
+                r.register4(putName, Receiver.class, Object.class, long.class, kind == Kind.Object ? Object.class : kind.toJavaClass(), new UnsafePutPlugin(kind, false));
+                r.register3(getName + "Volatile", Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, true));
+                r.register4(putName + "Volatile", Receiver.class, Object.class, long.class, kind == Kind.Object ? Object.class : kind.toJavaClass(), new UnsafePutPlugin(kind, true));
+                if (kind != Kind.Boolean && kind != Kind.Object) {
+                    r.register2(getName, Receiver.class, long.class, new UnsafeGetPlugin(kind, false));
+                    r.register3(putName, Receiver.class, long.class, kind.toJavaClass(), new UnsafePutPlugin(kind, false));
+                }
+            }
+        }
+    }
+
+    public static void registerMathPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, Math.class);
+        r.register1("abs", Float.TYPE, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                builder.push(Kind.Float, builder.append(new AbsNode(value)));
+                return true;
+            }
+        });
+        r.register1("abs", Double.TYPE, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                builder.push(Kind.Double, builder.append(new AbsNode(value)));
+                return true;
+            }
+        });
+        r.register1("sqrt", Double.TYPE, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                builder.push(Kind.Double, builder.append(new SqrtNode(value)));
+                return true;
+            }
+        });
+
+        for (Kind kind : Kind.values()) {
+            if (kind.isPrimitive() && kind != Kind.Void) {
+                new BoxPlugin(kind).register(metaAccess, plugins);
+                new UnboxPlugin(kind).register(metaAccess, plugins);
+            }
+        }
+    }
+
+    public static void registerObjectPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, Object.class);
+        r.register1("<init>", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode object) {
+                if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) {
+                    builder.append(new RegisterFinalizerNode(object));
+                }
+                return true;
+            }
+        });
+    }
+
+    static class BoxPlugin implements InvocationPlugin {
+
+        private final Kind kind;
+
+        BoxPlugin(Kind kind) {
+            this.kind = kind;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode value) {
+            ResolvedJavaType resultType = builder.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass());
+            builder.push(Kind.Object, builder.append(new BoxNode(value, resultType, kind)));
+            return true;
+        }
+
+        void register(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass());
+            plugins.register(method, this);
+        }
+    }
+
+    static class UnboxPlugin implements InvocationPlugin {
+
+        private final Kind kind;
+
+        UnboxPlugin(Kind kind) {
+            this.kind = kind;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode value) {
+            ValueNode valueNode = UnboxNode.create(builder.getMetaAccess(), builder.getConstantReflection(), nullCheckedValue(builder, value), kind);
+            builder.push(kind.getStackKind(), builder.append(valueNode));
+            return true;
+        }
+
+        void register(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+            String name = kind.toJavaClass().getSimpleName() + "Value";
+            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), name);
+            plugins.register(method, this);
+        }
+    }
+
+    static class UnsafeGetPlugin implements InvocationPlugin {
+
+        private final Kind returnKind;
+        private final boolean isVolatile;
+
+        public UnsafeGetPlugin(Kind returnKind, boolean isVolatile) {
+            this.returnKind = returnKind;
+            this.isVolatile = isVolatile;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode ignoredUnsafe, ValueNode address) {
+            builder.push(returnKind.getStackKind(), builder.append(new DirectReadNode(address, returnKind)));
+            return true;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset) {
+            if (isVolatile) {
+                builder.append(new MembarNode(JMM_PRE_VOLATILE_READ));
+            }
+            builder.push(returnKind.getStackKind(), builder.append(new UnsafeLoadNode(object, offset, returnKind, LocationIdentity.ANY_LOCATION)));
+            if (isVolatile) {
+                builder.append(new MembarNode(JMM_POST_VOLATILE_READ));
+            }
+            return true;
+        }
+    }
+
+    static class UnsafePutPlugin implements InvocationPlugin {
+
+        private final Kind kind;
+        private final boolean isVolatile;
+
+        public UnsafePutPlugin(Kind kind, boolean isVolatile) {
+            this.kind = kind;
+            this.isVolatile = isVolatile;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode ignoredUnsafe, ValueNode address, ValueNode value) {
+            builder.append(new DirectStoreNode(address, value, kind));
+            return true;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode value) {
+            if (isVolatile) {
+                builder.append(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+            }
+            builder.append(new UnsafeStoreNode(object, offset, value, kind, LocationIdentity.ANY_LOCATION));
+            if (isVolatile) {
+                builder.append(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+            }
+            return true;
+        }
+    }
+
+    public static void registerGraalDirectivesPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, GraalDirectives.class);
+        r.register0("deoptimize", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
+                return true;
+            }
+        });
+
+        r.register0("deoptimizeAndInvalidate", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
+                return true;
+            }
+        });
+
+        r.register0("inCompiledCode", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.push(Kind.Int, builder.append(ConstantNode.forInt(1)));
+                return true;
+            }
+        });
+
+        r.register0("controlFlowAnchor", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.append(new ControlFlowAnchorNode());
+                return true;
+            }
+        });
+
+        r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode probability, ValueNode condition) {
+                builder.push(Kind.Int, builder.append(new BranchProbabilityNode(probability, condition)));
+                return true;
+            }
+        });
+
+        InvocationPlugin blackholePlugin = new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                builder.append(new BlackholeNode(value));
+                return true;
+            }
+        };
+
+        for (Kind kind : Kind.values()) {
+            Class<?> cls = null;
+            switch (kind) {
+                case Object:
+                    cls = Object.class;
+                    break;
+                case Void:
+                case Illegal:
+                    continue;
+                default:
+                    cls = kind.toJavaClass();
+            }
+
+            r.register1("blackhole", cls, blackholePlugin);
+
+            final Kind stackKind = kind.getStackKind();
+            r.register1("opaque", cls, new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                    builder.push(stackKind, builder.append(new OpaqueNode(value)));
+                    return true;
+                }
+            });
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Thu Feb 19 15:43:41 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Thu Feb 19 15:44:05 2015 +0100
@@ -53,7 +53,8 @@
 
     public ArrayEqualsNode(ValueNode array1, ValueNode array2, ValueNode length) {
         super(TYPE, StampFactory.forKind(Kind.Boolean));
-        assert array1.stamp().equals(array2.stamp());
+        // Ignore nullness in stamp equality test
+        assert array1.stamp().join(StampFactory.objectNonNull()).equals(array2.stamp().join(StampFactory.objectNonNull()));
         ObjectStamp array1Stamp = (ObjectStamp) array1.stamp();
         ResolvedJavaType componentType = array1Stamp.type().getComponentType();
         this.kind = componentType.getKind();
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Thu Feb 19 15:43:41 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Thu Feb 19 15:44:05 2015 +0100
@@ -54,9 +54,9 @@
     }
 
     /**
-     * If we are sub it sizes, we try to sign/zero extend the value to at least int as it is done in
-     * the {@link com.oracle.graal.replacements.DefaultJavaLoweringProvider#implicitLoadConvert} and
-     * {@link com.oracle.graal.replacements.DefaultJavaLoweringProvider#createUnsafeRead}.
+     * If we are sub int sizes, we try to sign/zero extend the value to at least int as it is done
+     * in the {@link com.oracle.graal.replacements.DefaultJavaLoweringProvider#implicitLoadConvert}
+     * and {@link com.oracle.graal.replacements.DefaultJavaLoweringProvider#createUnsafeRead}.
      *
      * @see com.oracle.graal.replacements.DefaultJavaLoweringProvider#implicitLoadConvert
      * @see com.oracle.graal.replacements.DefaultJavaLoweringProvider#createUnsafeRead
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Thu Feb 19 15:43:41 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Thu Feb 19 15:44:05 2015 +0100
@@ -52,7 +52,21 @@
 public class TruffleGraphBuilderPlugins {
     public static void registerInvocationPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
 
-        // OptimizedAssumption.class
+        registerOptimizedAssumptionPlugins(metaAccess, plugins);
+        registerExactMathPlugins(metaAccess, plugins);
+        registerCompilerDirectivesPlugins(metaAccess, plugins);
+        registerOptimizedCallTargetPlugins(metaAccess, plugins);
+        registerUnsafeAccessImplPlugins(metaAccess, plugins);
+
+        if (TruffleCompilerOptions.TruffleUseFrameWithoutBoxing.getValue()) {
+            registerFrameWithoutBoxingPlugins(metaAccess, plugins);
+        } else {
+            registerFrameWithBoxingPlugins(metaAccess, plugins);
+        }
+
+    }
+
+    public static void registerOptimizedAssumptionPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
         Registration r = new Registration(plugins, metaAccess, OptimizedAssumption.class);
         r.register1("isValid", Receiver.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext builder, ValueNode arg) {
@@ -69,9 +83,10 @@
                 return true;
             }
         });
+    }
 
-        // ExactMath.class
-        r = new Registration(plugins, metaAccess, ExactMath.class);
+    public static void registerExactMathPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, ExactMath.class);
         r.register2("addExact", Integer.TYPE, Integer.TYPE, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
                 builder.push(Kind.Int.getStackKind(), builder.append(new IntegerAddExactNode(x, y)));
@@ -108,9 +123,10 @@
                 return true;
             }
         });
+    }
 
-        // CompilerDirectives.class
-        r = new Registration(plugins, metaAccess, CompilerDirectives.class);
+    public static void registerCompilerDirectivesPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, CompilerDirectives.class);
         r.register0("inInterpreter", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext builder) {
                 builder.push(Kind.Boolean.getStackKind(), builder.append(ConstantNode.forBoolean(false)));
@@ -175,9 +191,10 @@
                 return true;
             }
         });
+    }
 
-        // OptimizedCallTarget.class
-        r = new Registration(plugins, metaAccess, OptimizedCallTarget.class);
+    public static void registerOptimizedCallTargetPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, OptimizedCallTarget.class);
         r.register2("createFrame", FrameDescriptor.class, Object[].class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2) {
                 Class<?> frameClass = TruffleCompilerOptions.TruffleUseFrameWithoutBoxing.getValue() ? FrameWithoutBoxing.class : FrameWithBoxing.class;
@@ -185,22 +202,23 @@
                 return true;
             }
         });
+    }
 
-        if (TruffleCompilerOptions.TruffleUseFrameWithoutBoxing.getValue()) {
-            // FrameWithoutBoxing.class
-            r = new Registration(plugins, metaAccess, FrameWithoutBoxing.class);
-            registerMaterialize(r);
-            registerUnsafeCast(r);
-            registerUnsafeLoadStorePlugins(r, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object);
-        } else {
-            // FrameWithBoxing.class
-            r = new Registration(plugins, metaAccess, FrameWithBoxing.class);
-            registerMaterialize(r);
-            registerUnsafeCast(r);
-        }
+    public static void registerFrameWithoutBoxingPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, FrameWithoutBoxing.class);
+        registerMaterialize(r);
+        registerUnsafeCast(r);
+        registerUnsafeLoadStorePlugins(r, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object);
+    }
 
-        // CompilerDirectives.class
-        r = new Registration(plugins, metaAccess, UnsafeAccessImpl.class);
+    public static void registerFrameWithBoxingPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, FrameWithBoxing.class);
+        registerMaterialize(r);
+        registerUnsafeCast(r);
+    }
+
+    public static void registerUnsafeAccessImplPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, UnsafeAccessImpl.class);
         registerUnsafeCast(r);
         registerUnsafeLoadStorePlugins(r, Kind.Boolean, Kind.Byte, Kind.Int, Kind.Short, Kind.Long, Kind.Float, Kind.Double, Kind.Object);
     }
--- a/mx/suite.py	Thu Feb 19 15:43:41 2015 +0100
+++ b/mx/suite.py	Thu Feb 19 15:44:05 2015 +0100
@@ -591,6 +591,7 @@
       "dependencies" : [
         "com.oracle.graal.compiler",
         "com.oracle.graal.java",
+        "com.oracle.graal.api.directives",
         "com.oracle.graal.word",
       ],
       "checkstyle" : "com.oracle.graal.graph",
@@ -801,7 +802,6 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
-        "com.oracle.graal.api.directives",
         "com.oracle.graal.phases",
       ],
       "checkstyle" : "com.oracle.graal.graph",
@@ -851,6 +851,7 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
+        "com.oracle.graal.api.directives",
         "com.oracle.graal.test",
         "com.oracle.graal.printer",
         "com.oracle.graal.runtime",