changeset 19807:4bc952439f2a

Merge
author Stefan Anzinger <stefan.anzinger@oracle.com>
date Thu, 12 Mar 2015 15:59:01 +0100
parents a67fe68c25c5 (current diff) ad32fd810c83 (diff)
children 7ee442766685 9f1404a45a6f
files graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/HotSpotWordTypeRewriterPhase.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BlackholeSubstitutions.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSubstitutions.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CharacterSubstitutions.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ClassSubstitutions.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DoubleSubstitutions.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/EdgesSubstitutions.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/FloatSubstitutions.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalDirectivesSubstitutions.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ShortSubstitutions.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsignedMathSubstitutions.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/ExactMathSubstitutions.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/FrameWithoutBoxingSubstitutions.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/UnsafeAccessSubstitutions.java graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java
diffstat 208 files changed, 4119 insertions(+), 4933 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,314 +0,0 @@
-/*
- * Copyright (c) 2011, 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.api.code;
-
-import java.io.*;
-import java.lang.invoke.*;
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-
-/**
- * Class for recording assumptions made during compilation.
- */
-public final class Assumptions implements Serializable, Iterable<Assumptions.Assumption> {
-
-    private static final long serialVersionUID = 5152062717588239131L;
-
-    /**
-     * Abstract base class for assumptions. An assumption assumes a property of the runtime that may
-     * be invalidated by subsequent execution (e.g., that a class has no subclasses implementing
-     * {@link NoFinalizableSubclass Object.finalize()}).
-     */
-    public abstract static class Assumption implements Serializable {
-
-        private static final long serialVersionUID = -1936652569665112915L;
-    }
-
-    /**
-     * An assumption that a given class has no subclasses implementing {@link Object#finalize()}).
-     */
-    public static final class NoFinalizableSubclass extends Assumption {
-
-        private static final long serialVersionUID = 6451169735564055081L;
-
-        private ResolvedJavaType receiverType;
-
-        public NoFinalizableSubclass(ResolvedJavaType receiverType) {
-            this.receiverType = receiverType;
-        }
-
-        @Override
-        public int hashCode() {
-            return 31 + receiverType.hashCode();
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof NoFinalizableSubclass) {
-                NoFinalizableSubclass other = (NoFinalizableSubclass) obj;
-                return other.receiverType.equals(receiverType);
-            }
-            return false;
-        }
-
-        @Override
-        public String toString() {
-            return "NoFinalizableSubclass[receiverType=" + receiverType.toJavaName() + "]";
-        }
-
-    }
-
-    /**
-     * An assumption that a given type has a given unique subtype.
-     */
-    public static final class ConcreteSubtype extends Assumption {
-
-        private static final long serialVersionUID = -1457173265437676252L;
-
-        /**
-         * Type the assumption is made about.
-         */
-        public final ResolvedJavaType context;
-
-        /**
-         * Assumed unique concrete sub-type of the context type.
-         */
-        public final ResolvedJavaType subtype;
-
-        public ConcreteSubtype(ResolvedJavaType context, ResolvedJavaType subtype) {
-            this.context = context;
-            this.subtype = subtype;
-            assert subtype.isConcrete() : subtype.toString() + " : " + context.toString();
-            assert !subtype.isArray() || subtype.getElementalType().isFinal() : subtype.toString() + " : " + context.toString();
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + context.hashCode();
-            result = prime * result + subtype.hashCode();
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof ConcreteSubtype) {
-                ConcreteSubtype other = (ConcreteSubtype) obj;
-                return other.context.equals(context) && other.subtype.equals(subtype);
-            }
-            return false;
-        }
-
-        @Override
-        public String toString() {
-            return "ConcreteSubtype[context=" + context.toJavaName() + ", subtype=" + subtype.toJavaName() + "]";
-        }
-    }
-
-    /**
-     * An assumption that a given virtual method has a given unique implementation.
-     */
-    public static final class ConcreteMethod extends Assumption {
-
-        private static final long serialVersionUID = -7636746737947390059L;
-
-        /**
-         * A virtual (or interface) method whose unique implementation for the receiver type in
-         * {@link #context} is {@link #impl}.
-         */
-        public final ResolvedJavaMethod method;
-
-        /**
-         * A receiver type.
-         */
-        public final ResolvedJavaType context;
-
-        /**
-         * The unique implementation of {@link #method} for {@link #context}.
-         */
-        public final ResolvedJavaMethod impl;
-
-        public ConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) {
-            this.method = method;
-            this.context = context;
-            this.impl = impl;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + method.hashCode();
-            result = prime * result + context.hashCode();
-            result = prime * result + impl.hashCode();
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof ConcreteMethod) {
-                ConcreteMethod other = (ConcreteMethod) obj;
-                return other.method.equals(method) && other.context.equals(context) && other.impl.equals(impl);
-            }
-            return false;
-        }
-
-        @Override
-        public String toString() {
-            return "ConcreteMethod[method=" + method.format("%H.%n(%p)%r") + ", context=" + context.toJavaName() + ", impl=" + impl.format("%H.%n(%p)%r") + "]";
-        }
-    }
-
-    /**
-     * An assumption that a given call site's method handle did not change.
-     */
-    public static final class CallSiteTargetValue extends Assumption {
-
-        private static final long serialVersionUID = 1732459941784550371L;
-
-        public final CallSite callSite;
-        public final MethodHandle methodHandle;
-
-        public CallSiteTargetValue(CallSite callSite, MethodHandle methodHandle) {
-            this.callSite = callSite;
-            this.methodHandle = methodHandle;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + callSite.hashCode();
-            result = prime * result + methodHandle.hashCode();
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof CallSiteTargetValue) {
-                CallSiteTargetValue other = (CallSiteTargetValue) obj;
-                return callSite.equals(other.callSite) && methodHandle.equals(other.methodHandle);
-            }
-            return false;
-        }
-
-        @Override
-        public String toString() {
-            return "CallSiteTargetValue[callSite=" + callSite + ", methodHandle=" + methodHandle + "]";
-        }
-    }
-
-    private final Set<Assumption> assumptions = new HashSet<>();
-
-    /**
-     * Returns whether any assumptions have been registered.
-     *
-     * @return {@code true} if at least one assumption has been registered, {@code false} otherwise.
-     */
-    public boolean isEmpty() {
-        return assumptions.isEmpty();
-    }
-
-    @Override
-    public int hashCode() {
-        throw new UnsupportedOperationException("hashCode");
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof Assumptions) {
-            Assumptions that = (Assumptions) obj;
-            if (!this.assumptions.equals(that.assumptions)) {
-                return false;
-            }
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public Iterator<Assumption> iterator() {
-        return assumptions.iterator();
-    }
-
-    /**
-     * Records an assumption that the specified type has no finalizable subclasses.
-     *
-     * @param receiverType the type that is assumed to have no finalizable subclasses
-     */
-    public void recordNoFinalizableSubclassAssumption(ResolvedJavaType receiverType) {
-        record(new NoFinalizableSubclass(receiverType));
-    }
-
-    /**
-     * Records that {@code subtype} is the only concrete subtype in the class hierarchy below
-     * {@code context}.
-     *
-     * @param context the root of the subtree of the class hierarchy that this assumptions is about
-     * @param subtype the one concrete subtype
-     */
-    public void recordConcreteSubtype(ResolvedJavaType context, ResolvedJavaType subtype) {
-        record(new ConcreteSubtype(context, subtype));
-    }
-
-    /**
-     * Records that {@code impl} is the only possible concrete target for a virtual call to
-     * {@code method} with a receiver of type {@code context}.
-     *
-     * @param method a method that is the target of a virtual call
-     * @param context the receiver type of a call to {@code method}
-     * @param impl the concrete method that is the only possible target for the virtual call
-     */
-    public void recordConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) {
-        record(new ConcreteMethod(method, context, impl));
-    }
-
-    public void record(Assumption assumption) {
-        assumptions.add(assumption);
-    }
-
-    /**
-     * Gets a copy of the assumptions recorded in this object as an array.
-     */
-    public Assumption[] toArray() {
-        return assumptions.toArray(new Assumption[assumptions.size()]);
-    }
-
-    /**
-     * Copies assumptions recorded by another {@link Assumptions} object into this object.
-     */
-    public void record(Assumptions other) {
-        assert other != this;
-        assumptions.addAll(other.assumptions);
-    }
-
-    @Override
-    public String toString() {
-        return "Assumptions[" + assumptions + "]";
-    }
-}
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java	Thu Mar 12 15:59:01 2015 +0100
@@ -85,7 +85,7 @@
 
     /**
      * True if this is a position inside an exception handler before the exception object has been
-     * consumed. In this case, {@link #numStack == 1} and {@link #getStackValue(int)
+     * consumed. In this case, {@link #numStack} {@code == 1} and {@link #getStackValue(int)
      * getStackValue(0)} is the location of the exception object. If deoptimization happens at this
      * position, the interpreter will rethrow the exception instead of executing the bytecode
      * instruction at this position.
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Thu Mar 12 15:59:01 2015 +0100
@@ -28,7 +28,7 @@
 import java.io.*;
 import java.util.*;
 
-import com.oracle.graal.api.code.Assumptions.Assumption;
+import com.oracle.graal.api.meta.Assumptions.Assumption;
 import com.oracle.graal.api.code.CodeUtil.RefMapFormatter;
 import com.oracle.graal.api.meta.*;
 
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java	Thu Mar 12 15:59:01 2015 +0100
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
 
 /**
@@ -95,11 +96,11 @@
         if (targetType != null && !canHaveSubtype(targetType)) {
             exact = targetType;
         } else {
-            ResolvedJavaType uniqueSubtype = targetType == null ? null : targetType.findUniqueConcreteSubtype();
-            if (uniqueSubtype != null) {
-                if (assumptions != null) {
-                    assumptions.recordConcreteSubtype(targetType, uniqueSubtype);
-                    exact = uniqueSubtype;
+            if (assumptions != null) {
+                AssumptionResult<ResolvedJavaType> leafConcreteSubtype = targetType == null ? null : targetType.findLeafConcreteSubtype();
+                if (leafConcreteSubtype != null) {
+                    assumptions.record(leafConcreteSubtype);
+                    exact = leafConcreteSubtype.getResult();
                 } else {
                     exact = null;
                 }
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java	Thu Mar 12 15:59:01 2015 +0100
@@ -35,6 +35,7 @@
 import sun.reflect.ConstantPool;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.compiler.common.*;
 
 /**
@@ -273,30 +274,30 @@
     }
 
     void checkConcreteSubtype(ResolvedJavaType type, ResolvedJavaType expected) {
-        ResolvedJavaType subtype = type.findUniqueConcreteSubtype();
-        if (subtype == null) {
-            // findUniqueConcreteSubtype() is conservative
+        AssumptionResult<ResolvedJavaType> leafConcreteSubtype = type.findLeafConcreteSubtype();
+        if (leafConcreteSubtype == null) {
+            // findLeafConcreteSubtype() is conservative
         } else {
             if (expected == null) {
-                assertNull(subtype);
+                assertNull(leafConcreteSubtype);
             } else {
-                assertTrue(subtype.equals(expected));
+                assertTrue(leafConcreteSubtype.getResult().equals(expected));
             }
         }
 
         if (!type.isArray()) {
             ResolvedJavaType arrayType = type.getArrayClass();
-            ResolvedJavaType arraySubtype = arrayType.findUniqueConcreteSubtype();
+            AssumptionResult<ResolvedJavaType> arraySubtype = arrayType.findLeafConcreteSubtype();
             if (arraySubtype != null) {
-                assertEquals(arraySubtype, arrayType);
+                assertEquals(arraySubtype.getResult(), arrayType);
             } else {
-                // findUniqueConcreteSubtype() method is conservative
+                // findLeafConcreteSubtype() method is conservative
             }
         }
     }
 
     @Test
-    public void findUniqueConcreteSubtypeTest() {
+    public void findLeafConcreteSubtypeTest() {
         ResolvedJavaType base = metaAccess.lookupJavaType(Base.class);
         checkConcreteSubtype(base, base);
 
@@ -617,7 +618,7 @@
     @Test
     public void findUniqueConcreteMethodTest() throws NoSuchMethodException {
         ResolvedJavaMethod thisMethod = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("findUniqueConcreteMethodTest"));
-        ResolvedJavaMethod ucm = metaAccess.lookupJavaType(getClass()).findUniqueConcreteMethod(thisMethod);
+        ResolvedJavaMethod ucm = metaAccess.lookupJavaType(getClass()).findUniqueConcreteMethod(thisMethod).getResult();
         assertEquals(thisMethod, ucm);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Assumptions.java	Thu Mar 12 15:59:01 2015 +0100
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2011, 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.api.meta;
+
+import java.io.*;
+import java.lang.invoke.*;
+import java.util.*;
+
+/**
+ * Class for recording assumptions made during compilation.
+ */
+public final class Assumptions implements Serializable, Iterable<Assumptions.Assumption> {
+
+    private static final long serialVersionUID = 5152062717588239131L;
+
+    /**
+     * Abstract base class for assumptions. An assumption assumes a property of the runtime that may
+     * be invalidated by subsequent execution (e.g., that a class has no subclasses implementing
+     * {@link NoFinalizableSubclass Object.finalize()}).
+     */
+    public abstract static class Assumption implements Serializable {
+
+        private static final long serialVersionUID = -1936652569665112915L;
+    }
+
+    /**
+     * A class for providing information that is only valid in association with a set of
+     * {@link Assumption}s.
+     *
+     * @param <T>
+     */
+    public static class AssumptionResult<T> {
+        Assumption[] assumptions;
+        final T result;
+
+        private static final Assumption[] EMPTY = new Assumption[0];
+
+        public AssumptionResult(T result, Assumption... assumptions) {
+            this.result = result;
+            this.assumptions = assumptions.clone();
+        }
+
+        public AssumptionResult(T result) {
+            this(result, EMPTY);
+        }
+
+        public T getResult() {
+            return result;
+        }
+
+        public void add(AssumptionResult<T> other) {
+            Assumption[] newAssumptions = Arrays.copyOf(this.assumptions, this.assumptions.length + other.assumptions.length);
+            System.arraycopy(other.assumptions, 0, newAssumptions, this.assumptions.length, other.assumptions.length);
+            this.assumptions = newAssumptions;
+        }
+    }
+
+    /**
+     * An assumption that a given class has no subclasses implementing {@link Object#finalize()}).
+     */
+    public static final class NoFinalizableSubclass extends Assumption {
+
+        private static final long serialVersionUID = 6451169735564055081L;
+
+        private ResolvedJavaType receiverType;
+
+        public NoFinalizableSubclass(ResolvedJavaType receiverType) {
+            this.receiverType = receiverType;
+        }
+
+        @Override
+        public int hashCode() {
+            return 31 + receiverType.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof NoFinalizableSubclass) {
+                NoFinalizableSubclass other = (NoFinalizableSubclass) obj;
+                return other.receiverType.equals(receiverType);
+            }
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return "NoFinalizableSubclass[receiverType=" + receiverType.toJavaName() + "]";
+        }
+
+    }
+
+    /**
+     * An assumption that a given abstract or interface type has one direct concrete subtype. There
+     * is no requirement that the subtype is a leaf type.
+     */
+    public static final class ConcreteSubtype extends Assumption {
+
+        private static final long serialVersionUID = -1457173265437676252L;
+
+        /**
+         * Type the assumption is made about.
+         */
+        public final ResolvedJavaType context;
+
+        /**
+         * Assumed concrete sub-type of the context type.
+         */
+        public final ResolvedJavaType subtype;
+
+        public ConcreteSubtype(ResolvedJavaType context, ResolvedJavaType subtype) {
+            this.context = context;
+            this.subtype = subtype;
+            assert context.isAbstract();
+            assert subtype.isConcrete() || context.isInterface() : subtype.toString() + " : " + context.toString();
+            assert !subtype.isArray() || subtype.getElementalType().isFinal() : subtype.toString() + " : " + context.toString();
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + context.hashCode();
+            result = prime * result + subtype.hashCode();
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof ConcreteSubtype) {
+                ConcreteSubtype other = (ConcreteSubtype) obj;
+                return other.context.equals(context) && other.subtype.equals(subtype);
+            }
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return "ConcreteSubtype[context=" + context.toJavaName() + ", subtype=" + subtype.toJavaName() + "]";
+        }
+    }
+
+    /**
+     * An assumption that a given type has no subtypes.
+     */
+    public static final class LeafType extends Assumption {
+
+        private static final long serialVersionUID = -1457173265437676252L;
+
+        /**
+         * Type the assumption is made about.
+         */
+        public final ResolvedJavaType context;
+
+        public LeafType(ResolvedJavaType context) {
+            this.context = context;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + context.hashCode();
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof LeafType) {
+                LeafType other = (LeafType) obj;
+                return other.context.equals(context);
+            }
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return "LeafSubtype[context=" + context.toJavaName() + "]";
+        }
+    }
+
+    /**
+     * An assumption that a given virtual method has a given unique implementation.
+     */
+    public static final class ConcreteMethod extends Assumption {
+
+        private static final long serialVersionUID = -7636746737947390059L;
+
+        /**
+         * A virtual (or interface) method whose unique implementation for the receiver type in
+         * {@link #context} is {@link #impl}.
+         */
+        public final ResolvedJavaMethod method;
+
+        /**
+         * A receiver type.
+         */
+        public final ResolvedJavaType context;
+
+        /**
+         * The unique implementation of {@link #method} for {@link #context}.
+         */
+        public final ResolvedJavaMethod impl;
+
+        public ConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) {
+            this.method = method;
+            this.context = context;
+            this.impl = impl;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + method.hashCode();
+            result = prime * result + context.hashCode();
+            result = prime * result + impl.hashCode();
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof ConcreteMethod) {
+                ConcreteMethod other = (ConcreteMethod) obj;
+                return other.method.equals(method) && other.context.equals(context) && other.impl.equals(impl);
+            }
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return "ConcreteMethod[method=" + method.format("%H.%n(%p)%r") + ", context=" + context.toJavaName() + ", impl=" + impl.format("%H.%n(%p)%r") + "]";
+        }
+    }
+
+    /**
+     * An assumption that a given call site's method handle did not change.
+     */
+    public static final class CallSiteTargetValue extends Assumption {
+
+        private static final long serialVersionUID = 1732459941784550371L;
+
+        public final CallSite callSite;
+        public final MethodHandle methodHandle;
+
+        public CallSiteTargetValue(CallSite callSite, MethodHandle methodHandle) {
+            this.callSite = callSite;
+            this.methodHandle = methodHandle;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + callSite.hashCode();
+            result = prime * result + methodHandle.hashCode();
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof CallSiteTargetValue) {
+                CallSiteTargetValue other = (CallSiteTargetValue) obj;
+                return callSite.equals(other.callSite) && methodHandle.equals(other.methodHandle);
+            }
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return "CallSiteTargetValue[callSite=" + callSite + ", methodHandle=" + methodHandle + "]";
+        }
+    }
+
+    private final Set<Assumption> assumptions = new HashSet<>();
+
+    /**
+     * Returns whether any assumptions have been registered.
+     *
+     * @return {@code true} if at least one assumption has been registered, {@code false} otherwise.
+     */
+    public boolean isEmpty() {
+        return assumptions.isEmpty();
+    }
+
+    @Override
+    public int hashCode() {
+        throw new UnsupportedOperationException("hashCode");
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof Assumptions) {
+            Assumptions that = (Assumptions) obj;
+            if (!this.assumptions.equals(that.assumptions)) {
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public Iterator<Assumption> iterator() {
+        return assumptions.iterator();
+    }
+
+    /**
+     * Records an assumption that the specified type has no finalizable subclasses.
+     *
+     * @param receiverType the type that is assumed to have no finalizable subclasses
+     */
+    public void recordNoFinalizableSubclassAssumption(ResolvedJavaType receiverType) {
+        record(new NoFinalizableSubclass(receiverType));
+    }
+
+    /**
+     * Records that {@code subtype} is the only concrete subtype in the class hierarchy below
+     * {@code context}.
+     *
+     * @param context the root of the subtree of the class hierarchy that this assumptions is about
+     * @param subtype the one concrete subtype
+     */
+    public void recordConcreteSubtype(ResolvedJavaType context, ResolvedJavaType subtype) {
+        record(new ConcreteSubtype(context, subtype));
+    }
+
+    /**
+     * Records that {@code impl} is the only possible concrete target for a virtual call to
+     * {@code method} with a receiver of type {@code context}.
+     *
+     * @param method a method that is the target of a virtual call
+     * @param context the receiver type of a call to {@code method}
+     * @param impl the concrete method that is the only possible target for the virtual call
+     */
+    public void recordConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) {
+        record(new ConcreteMethod(method, context, impl));
+    }
+
+    public void record(AssumptionResult<?> result) {
+        for (Assumption assumption : result.assumptions) {
+            record(assumption);
+        }
+    }
+
+    public void record(Assumption assumption) {
+        assumptions.add(assumption);
+    }
+
+    /**
+     * Gets a copy of the assumptions recorded in this object as an array.
+     */
+    public Assumption[] toArray() {
+        return assumptions.toArray(new Assumption[assumptions.size()]);
+    }
+
+    /**
+     * Copies assumptions recorded by another {@link Assumptions} object into this object.
+     */
+    public void record(Assumptions other) {
+        assert other != this;
+        assumptions.addAll(other.assumptions);
+    }
+
+    @Override
+    public String toString() {
+        return "Assumptions[" + assumptions + "]";
+    }
+}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Thu Mar 12 15:59:01 2015 +0100
@@ -25,6 +25,8 @@
 import java.lang.annotation.*;
 import java.net.*;
 
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
+
 /**
  * Represents a resolved Java type. Types include primitives, objects, {@code void}, and arrays
  * thereof. Types, like fields and methods, are resolved through {@link ConstantPool constant pools}
@@ -56,7 +58,7 @@
      *
      * @return {@code true} if this class has any subclasses with finalizers
      */
-    boolean hasFinalizableSubclass();
+    AssumptionResult<Boolean> hasFinalizableSubclass();
 
     /**
      * Checks whether this type is an interface.
@@ -184,25 +186,27 @@
     ResolvedJavaType findLeastCommonAncestor(ResolvedJavaType otherType);
 
     /**
-     * Attempts to get a unique concrete subclass of this type.
+     * Attempts to get a leaf concrete subclass of this type.
      * <p>
-     * For an {@linkplain #isArray() array} type A, the unique concrete subclass is A if the
+     * For an {@linkplain #isArray() array} type A, the leaf concrete subclass is A if the
      * {@linkplain #getElementalType() elemental} type of A is final (which includes primitive
      * types). Otherwise {@code null} is returned for A.
      * <p>
-     * For a non-array type T, the result is the unique concrete type in the current hierarchy of T.
+     * For a non-array type T, the result is the leaf concrete type in the current hierarchy of T.
      * <p>
      * A runtime may decide not to manage or walk a large hierarchy and so the result is
-     * conservative. That is, a non-null result is guaranteed to be the unique concrete class in T's
+     * conservative. That is, a non-null result is guaranteed to be the leaf concrete class in T's
      * hierarchy <b>at the current point in time</b> but a null result does not necessarily imply
-     * that there is no unique concrete class in T's hierarchy.
+     * that there is no leaf concrete class in T's hierarchy.
      * <p>
-     * If the compiler uses the result of this method for its compilation, it must register an
-     * assumption because dynamic class loading can invalidate the result of this method.
+     * If the compiler uses the result of this method for its compilation, it must register the
+     * {@link AssumptionResult} in its {@link Assumptions} because dynamic class loading can
+     * invalidate the result of this method.
      *
-     * @return the unique concrete subclass for this type as described above
+     * @return an {@link AssumptionResult} containing the leaf concrete subclass for this type as
+     *         described above
      */
-    ResolvedJavaType findUniqueConcreteSubtype();
+    AssumptionResult<ResolvedJavaType> findLeafConcreteSubtype();
 
     ResolvedJavaType getComponentType();
 
@@ -257,7 +261,7 @@
      * @return the unique concrete target or {@code null} if no such target exists or assumptions
      *         are not supported by this runtime
      */
-    ResolvedJavaMethod findUniqueConcreteMethod(ResolvedJavaMethod method);
+    AssumptionResult<ResolvedJavaMethod> findUniqueConcreteMethod(ResolvedJavaMethod method);
 
     /**
      * Returns the instance fields of this class, including
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/CollectionsFactory.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/CollectionsFactory.java	Thu Mar 12 15:59:01 2015 +0100
@@ -73,7 +73,7 @@
      * Updates the mode for the current thread.
      *
      * @return an object which when {@linkplain ModeScope#close() closed} will revert the mode of
-     *         the current thread to the stae before calling this method
+     *         the current thread to the state before calling this method
      */
     public static ModeScope changeMode(Mode mode) {
         Mode previousMode = tl.get();
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Thu Mar 12 15:59:01 2015 +0100
@@ -57,15 +57,6 @@
     @Option(help = "Graphs with less than this number of nodes are trivial and therefore always inlined.", type = OptionType.Expert)
     public static final OptionValue<Integer> TrivialInliningSize = new OptionValue<>(10);
 
-    @Option(help = "Inlines trivial methods during parsing of the bytecodes.", type = OptionType.Expert)
-    public static final StableOptionValue<Boolean> InlineDuringParsing = new StableOptionValue<>(false);
-
-    @Option(help = "Traces .", type = OptionType.Debug)
-    public static final StableOptionValue<Boolean> TraceInlineDuringParsing = new StableOptionValue<>(false);
-
-    @Option(help = "Maximum depth when inlining during parsing.", type = OptionType.Debug)
-    public static final StableOptionValue<Integer> InlineDuringParsingMaxDepth = new StableOptionValue<>(10);
-
     @Option(help = "Inlining is explored up to this number of nodes in the graph for each call site.", type = OptionType.Expert)
     public static final OptionValue<Integer> MaximumInliningSize = new OptionValue<>(300);
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConcreteSubtypeTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConcreteSubtypeTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -24,7 +24,7 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.Assumptions.*;
+import com.oracle.graal.api.meta.Assumptions.*;
 import com.oracle.graal.nodes.*;
 
 /**
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -28,9 +28,8 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.Assumptions.Assumption;
-import com.oracle.graal.api.code.Assumptions.NoFinalizableSubclass;
+import com.oracle.graal.api.meta.Assumptions.Assumption;
+import com.oracle.graal.api.meta.Assumptions.NoFinalizableSubclass;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.java.*;
@@ -68,7 +67,7 @@
         StructuredGraph graph = new StructuredGraph(javaMethod, allowAssumptions);
 
         GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault();
-        new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), conf, OptimisticOptimizations.ALL).apply(graph);
+        new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), conf, OptimisticOptimizations.ALL, null).apply(graph);
         HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
         new CanonicalizerPhase().apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FindUniqueConcreteMethodBugTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FindUniqueConcreteMethodBugTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -25,6 +25,7 @@
 import org.junit.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 
 public class FindUniqueConcreteMethodBugTest extends GraalCompilerTest {
 
@@ -59,8 +60,8 @@
         test("getLabelLength", tenant);
 
         ResolvedJavaMethod expected = null;
-        ResolvedJavaMethod actual = getMetaAccess().lookupJavaType(AbstractPerson.class).findUniqueConcreteMethod(ifaceMethod);
-        Assert.assertEquals(expected, actual);
+        AssumptionResult<ResolvedJavaMethod> actual = getMetaAccess().lookupJavaType(AbstractPerson.class).findUniqueConcreteMethod(ifaceMethod);
+        Assert.assertEquals(expected, actual.getResult());
 
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerAssumptionsTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerAssumptionsTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -23,7 +23,7 @@
 package com.oracle.graal.compiler.test;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.Assumptions.Assumption;
+import com.oracle.graal.api.meta.Assumptions.Assumption;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -30,6 +30,7 @@
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.atomic.*;
+import java.util.function.*;
 
 import org.junit.*;
 import org.junit.internal.*;
@@ -528,7 +529,7 @@
                 executeArgs[i + 1] = args[i];
             }
         }
-        return executeArgs;
+        return applyArgSuppliers(executeArgs);
     }
 
     protected void test(String name, Object... args) {
@@ -542,6 +543,22 @@
         }
     }
 
+    /**
+     * Type denoting a lambda that supplies a fresh value each time it is called. This is useful
+     * when supplying an argument to {@link GraalCompilerTest#test(String, Object...)} where the
+     * test modifies the state of the argument (e.g., updates a field).
+     */
+    @FunctionalInterface
+    public interface ArgSupplier extends Supplier<Object> {
+    }
+
+    /**
+     * Convenience method for using an {@link ArgSupplier} lambda in a varargs list.
+     */
+    public static Object supply(ArgSupplier supplier) {
+        return supplier;
+    }
+
     protected void test(ResolvedJavaMethod method, Object receiver, Object... args) {
         Result expect = executeExpected(method, receiver, args);
         if (getCodeCache() == null) {
@@ -550,6 +567,23 @@
         testAgainstExpected(method, expect, receiver, args);
     }
 
+    /**
+     * Process a given set of arguments, converting any {@link ArgSupplier} argument to the argument
+     * it supplies.
+     */
+    protected Object[] applyArgSuppliers(Object... args) {
+        Object[] res = args;
+        for (int i = 0; i < args.length; i++) {
+            if (args[i] instanceof ArgSupplier) {
+                if (res == args) {
+                    res = args.clone();
+                }
+                res[i] = ((ArgSupplier) args[i]).get();
+            }
+        }
+        return res;
+    }
+
     protected void testAgainstExpected(ResolvedJavaMethod method, Result expect, Object receiver, Object... args) {
         testAgainstExpected(method, expect, Collections.<DeoptimizationReason> emptySet(), receiver, args);
     }
@@ -736,7 +770,7 @@
         if (!method.isAccessible()) {
             method.setAccessible(true);
         }
-        return method.invoke(receiver, args);
+        return method.invoke(receiver, applyArgSuppliers(args));
     }
 
     /**
@@ -803,12 +837,23 @@
         PhaseSuite<HighTierContext> suite = getDefaultGraphBuilderSuite().copy();
         ListIterator<BasePhase<? super HighTierContext>> iterator = suite.findPhase(GraphBuilderPhase.class);
         GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) iterator.previous();
-        GraphBuilderConfiguration gbConfCopy = gbConf.copy().copyPluginsFrom(graphBuilderPhase.getGraphBuilderConfig());
+        GraphBuilderConfiguration gbConfCopy = editGraphBuilderConfiguration(gbConf.copy().copyPluginsFrom(graphBuilderPhase.getGraphBuilderConfig()));
         iterator.remove();
         iterator.add(new GraphBuilderPhase(gbConfCopy));
         return suite;
     }
 
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        editGraphBuilderPlugins(conf.getPlugins());
+        return conf;
+    }
+
+    /**
+     * @param plugins
+     */
+    protected void editGraphBuilderPlugins(GraphBuilderConfiguration.Plugins plugins) {
+    }
+
     protected Replacements getReplacements() {
         return getProviders().getReplacements();
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Thu Mar 12 15:59:01 2015 +0100
@@ -30,7 +30,6 @@
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
@@ -149,10 +148,8 @@
 
     protected void prepareGraph(String snippet, final boolean iterativeEscapeAnalysis) {
         ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
-        graph = new StructuredGraph(method, AllowAssumptions.NO);
-        try (Scope s = Debug.scope(getClass(), graph, method, getCodeCache())) {
-            new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(),
-                            OptimisticOptimizations.ALL).apply(graph);
+        try (Scope s = Debug.scope(getClass(), method, getCodeCache())) {
+            graph = parseEager(method, AllowAssumptions.YES);
             context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
             new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
             new DeadCodeEliminationPhase().apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Thu Mar 12 15:59:01 2015 +0100
@@ -237,7 +237,7 @@
                      */
                     OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE;
 
-                    GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, null, graphBuilderConfig, optimisticOpts);
+                    GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, null, graphBuilderConfig, optimisticOpts, null);
                     graphBuilder.apply(graph);
                 } catch (Throwable ex) {
                     Debug.handle(ex);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Thu Mar 12 15:59:01 2015 +0100
@@ -153,6 +153,7 @@
                 lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, target);
             }
             Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null, new HotSpotStampProvider());
+
             try (InitTimer rt = timer("create SnippetReflection provider")) {
                 snippetReflection = createSnippetReflection(runtime);
             }
@@ -163,7 +164,7 @@
                 disassembler = createDisassembler(runtime);
             }
             try (InitTimer rt = timer("create Suites provider")) {
-                suites = createSuites(runtime, metaAccess, constantReflection, replacements);
+                suites = createSuites(runtime);
             }
             providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection);
         }
@@ -209,8 +210,8 @@
         return new HotSpotMetaAccessProvider(runtime);
     }
 
-    protected HotSpotSuitesProvider createSuites(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, Replacements replacements) {
-        return new HotSpotSuitesProvider(runtime, metaAccess, constantReflection, replacements);
+    protected HotSpotSuitesProvider createSuites(HotSpotGraalRuntimeProvider runtime) {
+        return new HotSpotSuitesProvider(runtime);
     }
 
     protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime) {
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Thu Mar 12 15:59:01 2015 +0100
@@ -32,7 +32,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.sparc.*;
-import com.oracle.graal.sparc.SPARC.*;
+import com.oracle.graal.sparc.SPARC.CPUFeature;
 
 @ServiceProvider(HotSpotBackendFactory.class)
 public class SPARCHotSpotBackendFactory implements HotSpotBackendFactory {
@@ -64,14 +64,14 @@
         HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime);
         HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, snippetReflection, runtime.getConfig(), target);
         HotSpotDisassemblerProvider disassembler = new HotSpotDisassemblerProvider(runtime);
-        HotSpotSuitesProvider suites = createSuites(runtime, metaAccess, constantReflection, replacements);
+        HotSpotSuitesProvider suites = createSuites(runtime);
         HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection);
 
         return createBackend(runtime, providers);
     }
 
-    protected HotSpotSuitesProvider createSuites(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, Replacements replacements) {
-        return new HotSpotSuitesProvider(runtime, metaAccess, constantReflection, replacements);
+    protected HotSpotSuitesProvider createSuites(HotSpotGraalRuntimeProvider runtime) {
+        return new HotSpotSuitesProvider(runtime);
     }
 
     protected HotSpotCodeCacheProvider createCodeCache(HotSpotGraalRuntimeProvider runtime, TargetDescription target, RegisterConfig regConfig) {
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -72,7 +72,7 @@
         StructuredGraph result = compile("getStaticFinalObject", true);
         assertDeepEquals(1, getConstantNodes(result).count());
         Stamp constantStamp = getConstantNodes(result).first().stamp();
-        Assert.assertTrue(constantStamp instanceof KlassPointerStamp);
+        Assert.assertTrue(constantStamp.toString(), constantStamp instanceof KlassPointerStamp);
         assertDeepEquals(2, result.getNodes().filter(FloatingReadNode.class).count());
         assertDeepEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMethodSubstitutionTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMethodSubstitutionTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -25,7 +25,6 @@
 import org.junit.*;
 
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.replacements.test.*;
 
 /**
@@ -37,8 +36,8 @@
     public void testObjectSubstitutions() {
         TestClassA obj = new TestClassA();
 
-        test("getClass0");
-        test("objectHashCode");
+        testGraph("getClass0");
+        testGraph("objectHashCode");
 
         test("getClass0", "a string");
         test("objectHashCode", obj);
@@ -56,12 +55,12 @@
 
     @Test
     public void testClassSubstitutions() {
-        test("getModifiers");
-        test("isInterface");
-        test("isArray");
-        test("isPrimitive");
-        test("getSuperClass");
-        test("getComponentType");
+        testGraph("getModifiers");
+        testGraph("isInterface");
+        testGraph("isArray");
+        testGraph("isPrimitive");
+        testGraph("getSuperClass");
+        testGraph("getComponentType");
 
         for (Class<?> c : new Class[]{getClass(), Cloneable.class, int[].class, String[][].class}) {
             test("getModifiers", c);
@@ -105,9 +104,9 @@
 
     @Test
     public void testThreadSubstitutions() {
-        test("currentThread");
-        test("threadIsInterrupted");
-        test("threadInterrupted");
+        testGraph("currentThread");
+        testGraph("threadIsInterrupted");
+        testGraph("threadInterrupted");
 
         Thread currentThread = Thread.currentThread();
         test("currentThread", currentThread);
@@ -131,11 +130,9 @@
 
     @Test
     public void testSystemSubstitutions() {
-        test("systemTime");
-        test("systemIdentityHashCode");
+        testGraph("systemTime");
+        testGraph("systemIdentityHashCode");
 
-        SystemSubstitutions.currentTimeMillis();
-        SystemSubstitutions.nanoTime();
         for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) {
             test("systemIdentityHashCode", o);
         }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,12 +22,15 @@
  */
 package com.oracle.graal.hotspot.test;
 
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
+
 import java.lang.ref.*;
 
 import org.junit.*;
 
+import sun.misc.*;
+
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
@@ -157,7 +160,7 @@
     }
 
     public static Object test5Snippet() throws Exception {
-        return UnsafeAccess.unsafe.getObject(wr, config.useCompressedOops ? 12L : 16L);
+        return unsafe.getObject(wr, config.useCompressedOops ? 12L : 16L);
     }
 
     /**
@@ -166,7 +169,7 @@
      */
     @Test
     public void test6() throws Exception {
-        test2("testUnsafeLoad", wr, new Long(referentOffset), null);
+        test2("testUnsafeLoad", unsafe, wr, new Long(referentOffset), null);
     }
 
     /**
@@ -175,7 +178,7 @@
      */
     @Test
     public void test7() throws Exception {
-        test2("testUnsafeLoad", con, new Long(referentOffset), null);
+        test2("testUnsafeLoad", unsafe, con, new Long(referentOffset), null);
     }
 
     /**
@@ -185,7 +188,7 @@
      */
     @Test
     public void test8() throws Exception {
-        test2("testUnsafeLoad", wr, new Long(config.useCompressedOops ? 20 : 32), null);
+        test2("testUnsafeLoad", unsafe, wr, new Long(config.useCompressedOops ? 20 : 32), null);
     }
 
     /**
@@ -195,7 +198,7 @@
      */
     @Test
     public void test10() throws Exception {
-        test2("testUnsafeLoad", wr, new Long(config.useCompressedOops ? 6 : 8), new Integer(config.useCompressedOops ? 6 : 8));
+        test2("testUnsafeLoad", unsafe, wr, new Long(config.useCompressedOops ? 6 : 8), new Integer(config.useCompressedOops ? 6 : 8));
     }
 
     /**
@@ -205,7 +208,7 @@
      */
     @Test
     public void test9() throws Exception {
-        test2("testUnsafeLoad", wr, new Long(config.useCompressedOops ? 10 : 16), new Integer(config.useCompressedOops ? 10 : 16));
+        test2("testUnsafeLoad", unsafe, wr, new Long(config.useCompressedOops ? 10 : 16), new Integer(config.useCompressedOops ? 10 : 16));
     }
 
     static Object[] src = new Object[1];
@@ -229,16 +232,17 @@
         test2("testArrayCopy", src, dst, dst.length);
     }
 
-    public static Object testUnsafeLoad(Object a, Object b, Object c) throws Exception {
+    public static Object testUnsafeLoad(Unsafe theUnsafe, Object a, Object b, Object c) throws Exception {
         final int offset = (c == null ? 0 : ((Integer) c).intValue());
         final long displacement = (b == null ? 0 : ((Long) b).longValue());
-        return UnsafeLoadNode.load(a, offset + displacement, Kind.Object, LocationIdentity.ANY_LOCATION);
+        return theUnsafe.getObject(a, offset + displacement);
     }
 
-    private HotSpotInstalledCode getInstalledCode(String name) throws Exception {
-        final ResolvedJavaMethod javaMethod = getResolvedJavaMethod(WriteBarrierAdditionTest.class, name, Object.class, Object.class, Object.class);
-        final HotSpotInstalledCode installedBenchmarkCode = (HotSpotInstalledCode) getCode(javaMethod);
-        return installedBenchmarkCode;
+    private HotSpotInstalledCode getInstalledCode(String name, boolean withUnsafePrefix) throws Exception {
+        final ResolvedJavaMethod javaMethod = withUnsafePrefix ? getResolvedJavaMethod(WriteBarrierAdditionTest.class, name, Unsafe.class, Object.class, Object.class, Object.class)
+                        : getResolvedJavaMethod(WriteBarrierAdditionTest.class, name, Object.class, Object.class, Object.class);
+        final HotSpotInstalledCode installedCode = (HotSpotInstalledCode) getCode(javaMethod);
+        return installedCode;
     }
 
     private void testHelper(final String snippetName, final int expectedBarriers) throws Exception, SecurityException {
@@ -294,8 +298,8 @@
         }
     }
 
-    private void test2(final String snippet, Object a, Object b, Object c) throws Exception {
-        HotSpotInstalledCode code = getInstalledCode(snippet);
-        code.executeVarargs(a, b, c);
+    private void test2(final String snippet, Object... args) throws Exception {
+        HotSpotInstalledCode code = getInstalledCode(snippet, args[0] instanceof Unsafe);
+        code.executeVarargs(args);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Thu Mar 12 15:59:01 2015 +0100
@@ -55,7 +55,7 @@
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.OptimisticOptimizations.Optimization;
 import com.oracle.graal.phases.tiers.*;
@@ -203,16 +203,9 @@
                 boolean recordEvolMethodDeps = graalEnv == 0 || unsafe.getByte(graalEnv + config.graalEnvJvmtiCanHotswapOrPostBreakpointOffset) != 0;
 
                 HotSpotProviders providers = backend.getProviders();
-                Replacements replacements = providers.getReplacements();
-                graph = replacements.getMethodSubstitution(method);
-                if (graph == null || entryBCI != INVOCATION_ENTRY_BCI) {
-                    graph = new StructuredGraph(method, entryBCI, AllowAssumptions.from(OptAssumptions.getValue()));
-                    if (!recordEvolMethodDeps) {
-                        graph.disableInlinedMethodRecording();
-                    }
-                } else {
-                    // Compiling method substitution - must clone the graph
-                    graph = graph.copy(graph.name, method, AllowAssumptions.from(OptAssumptions.getValue()), recordEvolMethodDeps);
+                graph = new StructuredGraph(method, entryBCI, AllowAssumptions.from(OptAssumptions.getValue()));
+                if (!recordEvolMethodDeps) {
+                    graph.disableInlinedMethodRecording();
                 }
                 InlinedBytecodes.add(method.getCodeSize());
                 CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Thu Mar 12 15:59:01 2015 +0100
@@ -31,9 +31,9 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.java.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.replacements.*;
 
 /**
  * Common functionality of HotSpot host backends.
@@ -70,11 +70,14 @@
         HotSpotVMConfig config = getRuntime().getConfig();
         HotSpotHostForeignCallsProvider foreignCalls = (HotSpotHostForeignCallsProvider) providers.getForeignCalls();
         final HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer();
+        HotSpotReplacementsImpl replacements = (HotSpotReplacementsImpl) providers.getReplacements();
 
         try (InitTimer st = timer("graphBuilderPlugins.initialize")) {
+            Plugins plugins = HotSpotGraphBuilderPlugins.create(config, providers);
+            providers.setGraphBuilderPlugins(plugins);
             GraphBuilderPhase phase = (GraphBuilderPhase) providers.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous();
-            InvocationPlugins plugins = phase.getGraphBuilderConfig().getInvocationPlugins();
-            registerInvocationPlugins(providers, plugins);
+            phase.getGraphBuilderConfig().setPlugins(plugins);
+            replacements.completeInitialization(plugins);
         }
 
         try (InitTimer st = timer("foreignCalls.initialize")) {
@@ -83,7 +86,6 @@
         try (InitTimer st = timer("lowerer.initialize")) {
             lowerer.initialize(providers, config);
         }
-        HotSpotReplacementsImpl replacements = (HotSpotReplacementsImpl) providers.getReplacements();
 
         // Install intrinsics.
         if (Intrinsify.getValue()) {
@@ -105,9 +107,4 @@
             }
         }
     }
-
-    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/HotSpotReplacementsImpl.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Thu Mar 12 15:59:01 2015 +0100
@@ -30,11 +30,9 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.word.phases.*;
 
 /**
  * Filters certain method substitutions based on whether there is underlying hardware support for
@@ -52,16 +50,8 @@
     @Override
     protected ResolvedJavaMethod registerMethodSubstitution(ClassReplacements cr, Executable originalMethod, Method substituteMethod) {
         final Class<?> substituteClass = substituteMethod.getDeclaringClass();
-        if (substituteClass.getDeclaringClass() == BoxingSubstitutions.class) {
-            if (config.useHeapProfiler) {
-                return null;
-            }
-        } else if (substituteClass == IntegerSubstitutions.class || substituteClass == LongSubstitutions.class) {
-            if (substituteMethod.getName().equals("bitCount")) {
-                if (!config.usePopCountInstruction) {
-                    return null;
-                }
-            } else if (substituteMethod.getName().equals("numberOfLeadingZeros")) {
+        if (substituteClass == IntegerSubstitutions.class || substituteClass == LongSubstitutions.class) {
+            if (substituteMethod.getName().equals("numberOfLeadingZeros")) {
                 if (config.useCountLeadingZerosInstruction) {
                     return null;
                 }
@@ -102,23 +92,4 @@
         }
         return super.getMacroSubstitution(method);
     }
-
-    @Override
-    protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original, FrameStateProcessing frameStateProcessing) {
-        return new HotSpotGraphMaker(this, substitute, original, frameStateProcessing);
-    }
-
-    public static class HotSpotGraphMaker extends ReplacementsImpl.GraphMaker {
-
-        public HotSpotGraphMaker(ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod, FrameStateProcessing frameStateProcessing) {
-            super(replacements, substitute, substitutedMethod, frameStateProcessing);
-        }
-
-        @Override
-        protected void afterParsing(StructuredGraph graph) {
-            MetaAccessProvider metaAccess = replacements.providers.getMetaAccess();
-            new WordTypeVerificationPhase(metaAccess, replacements.snippetReflection, replacements.providers.getConstantReflection(), replacements.target.wordKind).apply(graph);
-            new HotSpotWordTypeRewriterPhase(metaAccess, replacements.snippetReflection, replacements.providers.getConstantReflection(), replacements.target.wordKind).apply(graph);
-        }
-    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Thu Mar 12 15:59:01 2015 +0100
@@ -24,6 +24,7 @@
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.hotspot.stubs.SnippetStub.*;
 
 import java.lang.reflect.*;
 import java.util.*;
@@ -32,6 +33,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
@@ -41,6 +43,7 @@
 /**
  * HotSpot implementation of {@link ConstantReflectionProvider}.
  */
+@SuppressWarnings("unused")
 public class HotSpotConstantReflectionProvider implements ConstantReflectionProvider, HotSpotProxified {
     private static final String SystemClassName = "Ljava/lang/System;";
 
@@ -195,7 +198,7 @@
      * {@code receiver} is (assignable to) {@link StableOptionValue}.
      */
     public JavaConstant readConstantFieldValue(JavaField field, JavaConstant receiver) {
-        assert !ImmutableCode.getValue() || isCalledForSnippets() : receiver;
+        assert !ImmutableCode.getValue() || isCalledForSnippets() || SnippetGraphUnderConstruction.get() != null || HotSpotLoadFieldPlugin.FieldReadEnabledInImmutableCode.get() == Boolean.TRUE : receiver;
         HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field;
 
         if (receiver == null) {
@@ -314,7 +317,7 @@
         ResolvedJavaMethod initMethod = null;
         try {
             Class<?> rjm = ResolvedJavaMethod.class;
-            makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, rjm, SnippetInliningPolicy.class, FrameStateProcessing.class));
+            makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm, SnippetInliningPolicy.class, FrameStateProcessing.class));
             initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class));
         } catch (NoSuchMethodException | SecurityException e) {
             throw new GraalInternalError(e);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,89 +22,109 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.api.meta.LocationIdentity.*;
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.java.GraphBuilderContext.*;
-import static java.lang.Character.*;
 
+import com.oracle.graal.api.code.*;
 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.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.hotspot.word.*;
+import com.oracle.graal.java.GraphBuilderConfiguration.Plugins;
 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.replacements.*;
 import com.oracle.graal.word.*;
-import com.oracle.graal.word.nodes.*;
 
 /**
- * Provides HotSpot specific {@link InvocationPlugin}s.
+ * Defines the {@link Plugins} used when running on HotSpot.
  */
 public class HotSpotGraphBuilderPlugins {
-    public static void registerInvocationPlugins(HotSpotProviders providers, InvocationPlugins plugins) {
+
+    /**
+     * Creates a {@link Plugins} object that should be used when running on HotSpot.
+     */
+    public static Plugins create(HotSpotVMConfig config, HotSpotProviders providers) {
+
         MetaAccessProvider metaAccess = providers.getMetaAccess();
-        SnippetReflectionProvider snippetReflection = providers.getSnippetReflection();
-        Kind wordKind = providers.getCodeCache().getTarget().wordKind;
+        HotSpotWordTypes wordTypes = providers.getWordTypes();
+        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess);
 
-        registerObjectPlugins(plugins, metaAccess);
-        registerClassPlugins(plugins, metaAccess);
-        registerStableOptionPlugins(plugins, metaAccess);
-        registerMetaspacePointerPlugins(plugins, metaAccess, snippetReflection, wordKind);
+        Plugins plugins = new Plugins(invocationPlugins);
+        NodeIntrinsificationPhase nodeIntrinsification = new NodeIntrinsificationPhase(providers, providers.getSnippetReflection());
+        ConstantReflectionProvider constantReflection = providers.getConstantReflection();
+        HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(providers.getSnippetReflection(), wordTypes);
+
+        plugins.setParameterPlugin(new HotSpotParameterPlugin(wordTypes));
+        plugins.setLoadFieldPlugin(new HotSpotLoadFieldPlugin(metaAccess, constantReflection));
+        plugins.setLoadIndexedPlugin(new HotSpotLoadIndexedPlugin(wordTypes));
+        plugins.setInlineInvokePlugin(new HotSpotInlineInvokePlugin(nodeIntrinsification, (ReplacementsImpl) providers.getReplacements()));
+        plugins.setGenericInvocationPlugin(new DefaultGenericInvocationPlugin(nodeIntrinsification, wordOperationPlugin));
+
+        registerObjectPlugins(invocationPlugins, metaAccess);
+        registerSystemPlugins(invocationPlugins, metaAccess, providers.getForeignCalls());
+        registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config);
+        registerStableOptionPlugins(invocationPlugins, metaAccess);
+        StandardGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), providers.getCodeCache().target.arch, invocationPlugins, !config.useHeapProfiler);
+        return plugins;
     }
 
     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) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode rcvr) {
                 ObjectStamp objectStamp = (ObjectStamp) rcvr.stamp();
                 ValueNode mirror;
                 if (objectStamp.isExactType() && objectStamp.nonNull()) {
-                    mirror = builder.append(ConstantNode.forConstant(objectStamp.type().getJavaClass(), builder.getMetaAccess()));
+                    mirror = b.append(ConstantNode.forConstant(objectStamp.type().getJavaClass(), b.getMetaAccess()));
                 } else {
-                    StampProvider stampProvider = builder.getStampProvider();
-                    LoadHubNode hub = builder.append(new LoadHubNode(stampProvider, nullCheckedValue(builder, rcvr)));
-                    mirror = builder.append(new HubGetClassNode(builder.getMetaAccess(), hub));
+                    StampProvider stampProvider = b.getStampProvider();
+                    LoadHubNode hub = b.append(new LoadHubNode(stampProvider, nullCheckedValue(b, rcvr)));
+                    mirror = b.append(new HubGetClassNode(b.getMetaAccess(), hub));
                 }
-                builder.push(Kind.Object, mirror);
+                b.push(Kind.Object, mirror);
                 return true;
             }
         });
     }
 
-    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()) {
-                    ResolvedJavaType type = builder.getConstantReflection().asJavaType(rcvr.asConstant());
-                    if (type != null && !type.isPrimitive()) {
-                        builder.push(Kind.Object, builder.append(CheckCastNode.create(type, object, null, false, builder.getAssumptions())));
-                        return true;
-                    }
-                }
-                return false;
+    private static void registerSystemPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls) {
+        Registration r = new Registration(plugins, metaAccess, System.class);
+        r.register0("currentTimeMillis", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+                b.push(Kind.Long, b.append(new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_MILLIS, StampFactory.forKind(Kind.Long))));
+                return true;
+            }
+        });
+        r.register0("nanoTime", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+                b.push(Kind.Long, b.append(new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_NANOS, StampFactory.forKind(Kind.Long))));
+                return true;
             }
         });
-        r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode rcvr, ValueNode object) {
-                if (rcvr.isConstant() && !rcvr.isNullConstant()) {
-                    ResolvedJavaType type = builder.getConstantReflection().asJavaType(rcvr.asConstant());
-                    if (type != null && !type.isPrimitive()) {
-                        LogicNode node = builder.append(InstanceOfNode.create(type, object, null));
-                        builder.push(Kind.Boolean.getStackKind(), builder.append(ConditionalNode.create(node)));
-                        return true;
-                    }
-                }
-                return false;
+    }
+
+    private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, HotSpotVMConfig config) {
+        Registration r = new Registration(plugins, metaAccess, Thread.class);
+        r.register0("currentThread", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+                CurrentJavaThreadNode thread = b.append(new CurrentJavaThreadNode(wordTypes.getWordKind()));
+                ConstantLocationNode location = b.append(new ConstantLocationNode(JAVA_THREAD_THREAD_OBJECT_LOCATION, config.threadObjectOffset));
+                boolean compressible = false;
+                ValueNode javaThread = WordOperationPlugin.readOp(b, Kind.Object, thread, location, BarrierType.NONE, compressible);
+                boolean exactType = compressible;
+                boolean nonNull = true;
+                b.push(Kind.Object, b.append(new PiNode(javaThread, metaAccess.lookupJavaType(Thread.class), exactType, nonNull)));
+                return true;
             }
         });
     }
@@ -112,142 +132,16 @@
     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) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode rcvr) {
                 if (rcvr.isConstant() && !rcvr.isNullConstant()) {
                     Object object = ((HotSpotObjectConstantImpl) rcvr.asConstant()).object();
                     StableOptionValue<?> option = (StableOptionValue<?>) object;
-                    ConstantNode value = builder.append(ConstantNode.forConstant(HotSpotObjectConstantImpl.forObject(option.getValue()), builder.getMetaAccess()));
-                    builder.push(Kind.Object, value);
+                    ConstantNode value = b.append(ConstantNode.forConstant(HotSpotObjectConstantImpl.forObject(option.getValue()), b.getMetaAccess()));
+                    b.push(Kind.Object, value);
                     return true;
                 }
                 return false;
             }
         });
     }
-
-    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/HotSpotHostForeignCallsProvider.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Thu Mar 12 15:59:01 2015 +0100
@@ -138,7 +138,6 @@
     }
 
     public void initialize(HotSpotProviders providers, HotSpotVMConfig c) {
-        TargetDescription target = providers.getCodeCache().getTarget();
 
         if (!PreferGraalStubs.getValue()) {
             registerForeignCall(DEOPTIMIZATION_HANDLER, c.handleDeoptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
@@ -174,11 +173,11 @@
         registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(ASSERTION_VM_MESSAGE_C, c.vmMessageAddress, NativeCall, PRESERVES_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
 
-        link(new NewInstanceStub(providers, target, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
-        link(new NewArrayStub(providers, target, registerStubCall(NEW_ARRAY, REEXECUTABLE, NOT_LEAF, INIT_LOCATION)));
-        link(new ExceptionHandlerStub(providers, target, foreignCalls.get(EXCEPTION_HANDLER)));
-        link(new UnwindExceptionToCallerStub(providers, target, registerStubCall(UNWIND_EXCEPTION_TO_CALLER, NOT_REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
-        link(new VerifyOopStub(providers, target, registerStubCall(VERIFY_OOP, REEXECUTABLE, LEAF_NOFP, NO_LOCATIONS)));
+        link(new NewInstanceStub(providers, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
+        link(new NewArrayStub(providers, registerStubCall(NEW_ARRAY, REEXECUTABLE, NOT_LEAF, INIT_LOCATION)));
+        link(new ExceptionHandlerStub(providers, foreignCalls.get(EXCEPTION_HANDLER)));
+        link(new UnwindExceptionToCallerStub(providers, registerStubCall(UNWIND_EXCEPTION_TO_CALLER, NOT_REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
+        link(new VerifyOopStub(providers, registerStubCall(VERIFY_OOP, REEXECUTABLE, LEAF_NOFP, NO_LOCATIONS)));
 
         linkForeignCall(providers, IDENTITY_HASHCODE, c.identityHashCodeAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, MARK_WORD_LOCATION);
         linkForeignCall(providers, REGISTER_FINALIZER, c.registerFinalizerAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java	Thu Mar 12 15:59:01 2015 +0100
@@ -0,0 +1,76 @@
+/*
+ * 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.hotspot.meta;
+
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+import static java.lang.String.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.word.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+
+public final class HotSpotInlineInvokePlugin implements InlineInvokePlugin {
+    private final ReplacementsImpl replacements;
+    private final NodeIntrinsificationPhase nodeIntrinsification;
+
+    public HotSpotInlineInvokePlugin(NodeIntrinsificationPhase nodeIntrinsification, ReplacementsImpl replacements) {
+        this.nodeIntrinsification = nodeIntrinsification;
+        this.replacements = replacements;
+    }
+
+    public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
+        ResolvedJavaMethod subst = replacements.getMethodSubstitutionMethod(method);
+        if (subst != null) {
+            // Forced inlining of intrinsics
+            return new InlineInfo(subst, true);
+        }
+        if (b.parsingReplacement()) {
+            assert nodeIntrinsification.getIntrinsic(method) == null && method.getAnnotation(Word.Operation.class) == null && method.getAnnotation(HotSpotOperation.class) == null &&
+                            !nodeIntrinsification.isFoldable(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), DefaultGenericInvocationPlugin.class.getName());
+
+            // Force inlining when parsing replacements
+            return new InlineInfo(method, true);
+        } else {
+            assert nodeIntrinsification.getIntrinsic(method) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(),
+                            method.format("%h.%n"), b);
+            if (InlineDuringParsing.getValue() && method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && b.getDepth() < InlineDuringParsingMaxDepth.getValue()) {
+                return new InlineInfo(method, false);
+            }
+        }
+        return null;
+    }
+
+    public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
+        if (b.parsingReplacement()) {
+            boolean compilingSnippet = b.getRootMethod().getAnnotation(MethodSubstitution.class) == null;
+            assert compilingSnippet : format("All calls in the replacement %s must be inlined or intrinsified: found call to %s", b.getRootMethod().format("%H.%n(%p)"), method.format("%h.%n(%p)"));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Thu Mar 12 15:59:01 2015 +0100
@@ -0,0 +1,72 @@
+/*
+ * 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.hotspot.meta;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugin.*;
+import com.oracle.graal.replacements.StandardGraphBuilderPlugins.*;
+
+/**
+ * Extension of {@link InvocationPlugins} that disables plugins based on runtime configuration.
+ */
+final class HotSpotInvocationPlugins extends InvocationPlugins {
+    final HotSpotVMConfig config;
+    final MetaAccessProvider metaAccess;
+
+    public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess) {
+        this.config = config;
+        this.metaAccess = metaAccess;
+    }
+
+    @Override
+    public void register(ResolvedJavaMethod method, InvocationPlugin plugin) {
+        if (!config.usePopCountInstruction) {
+            if (method.getName().equals("bitCount")) {
+                assert method.getDeclaringClass().equals(metaAccess.lookupJavaType(Integer.class)) || method.getDeclaringClass().equals(metaAccess.lookupJavaType(Long.class));
+                return;
+            }
+        }
+        if (!config.useCountLeadingZerosInstruction) {
+            if (method.getName().equals("numberOfLeadingZeros")) {
+                assert method.getDeclaringClass().equals(metaAccess.lookupJavaType(Integer.class)) || method.getDeclaringClass().equals(metaAccess.lookupJavaType(Long.class));
+                return;
+            }
+        }
+        if (!config.useCountTrailingZerosInstruction) {
+            if (method.getName().equals("numberOfTrailingZeros")) {
+                assert method.getDeclaringClass().equals(metaAccess.lookupJavaType(Integer.class));
+                return;
+            }
+        }
+
+        if (config.useHeapProfiler) {
+            if (plugin instanceof BoxPlugin) {
+                // The heap profiler wants to see all allocations related to boxing
+                return;
+            }
+        }
+        super.register(method, plugin);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java	Thu Mar 12 15:59:01 2015 +0100
@@ -0,0 +1,87 @@
+/*
+ * 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.hotspot.meta;
+
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin;
+import com.oracle.graal.nodes.*;
+
+public final class HotSpotLoadFieldPlugin implements LoadFieldPlugin {
+    private final MetaAccessProvider metaAccess;
+    private final ConstantReflectionProvider constantReflection;
+
+    public HotSpotLoadFieldPlugin(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+        this.metaAccess = metaAccess;
+        this.constantReflection = constantReflection;
+    }
+
+    static final ThreadLocal<Boolean> FieldReadEnabledInImmutableCode = new ThreadLocal<>();
+
+    public boolean apply(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) {
+        if ((InlineDuringParsing.getValue() && !ImmutableCode.getValue()) || b.parsingReplacement()) {
+            if (receiver.isConstant()) {
+                JavaConstant asJavaConstant = receiver.asJavaConstant();
+                return tryReadField(b, field, asJavaConstant);
+            }
+        }
+        return false;
+    }
+
+    private boolean tryReadField(GraphBuilderContext b, ResolvedJavaField field, JavaConstant receiver) {
+        if (ImmutableCode.getValue()) {
+            FieldReadEnabledInImmutableCode.set(Boolean.TRUE);
+        }
+        try {
+            return tryConstantFold(b, metaAccess, constantReflection, field, receiver);
+        } finally {
+            if (ImmutableCode.getValue()) {
+                FieldReadEnabledInImmutableCode.set(null);
+            }
+        }
+    }
+
+    public boolean apply(GraphBuilderContext b, ResolvedJavaField staticField) {
+        if ((InlineDuringParsing.getValue() && !ImmutableCode.getValue()) || b.parsingReplacement()) {
+            // Javac does not allow use of "$assertionsDisabled" for a field name but
+            // Eclipse does in which case a suffix is added to the generated field.
+            if (b.parsingReplacement() && staticField.isSynthetic() && staticField.getName().startsWith("$assertionsDisabled")) {
+                // For methods called indirectly from intrinsics, we (silently) disable
+                // assertions so that the parser won't see calls to the AssertionError
+                // constructor (all Invokes must be removed from intrinsics - see
+                // HotSpotInlineInvokePlugin.notifyOfNoninlinedInvoke). Direct use of
+                // assertions in intrinsics is forbidden.
+                assert b.getMethod().getAnnotation(MethodSubstitution.class) == null : "cannot use assertions in " + b.getMethod().format("%H.%n(%p)");
+                ConstantNode trueNode = b.append(ConstantNode.forBoolean(true));
+                b.push(trueNode.getKind().getStackKind(), trueNode);
+                return true;
+            }
+            return tryReadField(b, staticField, null);
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadIndexedPlugin.java	Thu Mar 12 15:59:01 2015 +0100
@@ -0,0 +1,67 @@
+/*
+ * 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.hotspot.meta;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.nodes.type.*;
+import com.oracle.graal.hotspot.word.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugin.LoadIndexedPlugin;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.type.*;
+
+public final class HotSpotLoadIndexedPlugin implements LoadIndexedPlugin {
+    private final HotSpotWordTypes wordTypes;
+
+    public HotSpotLoadIndexedPlugin(HotSpotWordTypes wordTypes) {
+        this.wordTypes = wordTypes;
+    }
+
+    public boolean apply(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind) {
+        if (b.parsingReplacement()) {
+            ResolvedJavaType arrayType = StampTool.typeOrNull(array);
+            /*
+             * There are cases where the array does not have a known type yet, i.e., the type is
+             * null. In that case we assume it is not a word type.
+             */
+            if (arrayType != null && wordTypes.isWord(arrayType.getComponentType()) && elementKind != wordTypes.getWordKind()) {
+                /*
+                 * The elementKind of the node is a final field, and other information such as the
+                 * stamp depends on elementKind. Therefore, just create a new node and replace the
+                 * old one.
+                 */
+                Stamp componentStamp = wordTypes.getWordStamp(arrayType.getComponentType());
+                if (componentStamp instanceof MetaspacePointerStamp) {
+                    b.push(elementKind, b.append(new LoadIndexedPointerNode(componentStamp, array, index)));
+                } else {
+                    b.push(elementKind, b.append(new LoadIndexedNode(array, index, wordTypes.getWordKind())));
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMemoryAccessProviderImpl.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMemoryAccessProviderImpl.java	Thu Mar 12 15:59:01 2015 +0100
@@ -48,6 +48,24 @@
         }
     }
 
+    private boolean isValidObjectFieldDisplacement(Constant base, long displacement) {
+        if (base instanceof HotSpotMetaspaceConstant) {
+            Object metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base);
+            if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) {
+                if (displacement == runtime.getConfig().classMirrorOffset) {
+                    // Klass::_java_mirror is valid for all Klass* values
+                    return true;
+                } else if (displacement == runtime.getConfig().arrayKlassComponentMirrorOffset) {
+                    // ArrayKlass::_component_mirror is only valid for all ArrayKlass* values
+                    return ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror().isArray();
+                }
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+        return false;
+    }
+
     private static long asRawPointer(Constant base) {
         if (base instanceof HotSpotMetaspaceConstant) {
             return ((HotSpotMetaspaceConstant) base).rawValue();
@@ -119,7 +137,6 @@
         if (base == null) {
             displacement += asRawPointer(baseConstant);
         }
-
         Object ret = runtime.getCompilerToVM().readUnsafeOop(base, displacement, compressed);
         assert verifyReadRawObject(ret, baseConstant, initialDisplacement, compressed);
 
@@ -167,6 +184,9 @@
 
     @Override
     public JavaConstant readObjectConstant(Constant base, long displacement) {
+        if (!isValidObjectFieldDisplacement(base, displacement)) {
+            return null;
+        }
         return HotSpotObjectConstantImpl.forObject(readRawObject(base, displacement, false));
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java	Thu Mar 12 15:59:01 2015 +0100
@@ -25,7 +25,6 @@
 import java.lang.invoke.*;
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.lir.*;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Thu Mar 12 15:59:01 2015 +0100
@@ -26,7 +26,6 @@
 
 import java.lang.invoke.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotParameterPlugin.java	Thu Mar 12 15:59:01 2015 +0100
@@ -0,0 +1,50 @@
+/*
+ * 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.hotspot.meta;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugin.ParameterPlugin;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.word.*;
+
+public final class HotSpotParameterPlugin implements ParameterPlugin {
+    private final WordTypes wordTypes;
+
+    public HotSpotParameterPlugin(WordTypes wordTypes) {
+        this.wordTypes = wordTypes;
+    }
+
+    public FloatingNode interceptParameter(GraphBuilderContext b, int index, Stamp stamp) {
+        if (b.parsingReplacement()) {
+            ResolvedJavaType type = StampTool.typeOrNull(stamp);
+            if (wordTypes.isWord(type)) {
+                return new ParameterNode(index, wordTypes.getWordStamp(type));
+            }
+        }
+        return null;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProviders.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProviders.java	Thu Mar 12 15:59:01 2015 +0100
@@ -24,6 +24,8 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.hotspot.word.*;
+import com.oracle.graal.java.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
@@ -38,6 +40,8 @@
     private final SuitesProvider suites;
     private final HotSpotRegistersProvider registers;
     private final SnippetReflectionProvider snippetReflection;
+    private final HotSpotWordTypes wordTypes;
+    private Plugins graphBuilderPlugins;
 
     public HotSpotProviders(MetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, HotSpotForeignCallsProvider foreignCalls,
                     LoweringProvider lowerer, Replacements replacements, HotSpotDisassemblerProvider disassembler, SuitesProvider suites, HotSpotRegistersProvider registers,
@@ -47,6 +51,7 @@
         this.suites = suites;
         this.registers = registers;
         this.snippetReflection = snippetReflection;
+        this.wordTypes = new HotSpotWordTypes(metaAccess, codeCache.getTarget().wordKind);
     }
 
     @Override
@@ -74,4 +79,17 @@
     public SnippetReflectionProvider getSnippetReflection() {
         return snippetReflection;
     }
+
+    public void setGraphBuilderPlugins(Plugins plugins) {
+        graphBuilderPlugins = plugins;
+    }
+
+    public Plugins getGraphBuilderPlugins() {
+        assert graphBuilderPlugins != null;
+        return graphBuilderPlugins;
+    }
+
+    public HotSpotWordTypes getWordTypes() {
+        return wordTypes;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Thu Mar 12 15:59:01 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.meta;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.hotspot.*;
 
 /**
@@ -34,7 +35,7 @@
 
     ResolvedJavaType getComponentType();
 
-    HotSpotResolvedObjectType findUniqueConcreteSubtype();
+    AssumptionResult<ResolvedJavaType> findLeafConcreteSubtype();
 
     HotSpotResolvedObjectType getSuperclass();
 
@@ -66,7 +67,7 @@
     int getVtableLength();
 
     @Override
-    ResolvedJavaMethod findUniqueConcreteMethod(ResolvedJavaMethod method);
+    AssumptionResult<ResolvedJavaMethod> findUniqueConcreteMethod(ResolvedJavaMethod method);
 
     /**
      * Performs a fast-path check that this type is resolved in the context of a given accessing
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectTypeImpl.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectTypeImpl.java	Thu Mar 12 15:59:01 2015 +0100
@@ -33,6 +33,7 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.hotspot.*;
 
@@ -139,25 +140,33 @@
     }
 
     @Override
-    public HotSpotResolvedObjectType findUniqueConcreteSubtype() {
+    public AssumptionResult<ResolvedJavaType> findLeafConcreteSubtype() {
         HotSpotVMConfig config = runtime().getConfig();
         if (isArray()) {
-            return getElementalType().isFinal() ? this : null;
+            return getElementalType().isFinal() ? new AssumptionResult<>(this) : null;
         } else if (isInterface()) {
-            HotSpotResolvedObjectTypeImpl type = getSingleImplementor();
-            if (type == null) {
+            HotSpotResolvedObjectTypeImpl implementor = getSingleImplementor();
+            /*
+             * If the implementor field contains itself that indicates that the interface has more
+             * than one implementors (see: InstanceKlass::add_implementor).
+             */
+            if (implementor == null || implementor.equals(this)) {
                 return null;
             }
 
-            /*
-             * If the implementor field contains itself that indicates that the interface has more
-             * than one implementors (see: InstanceKlass::add_implementor). The isInterface check
-             * takes care of this fact since this class is an interface.
-             */
-            if (type.isAbstract() || type.isInterface() || !type.isLeafClass()) {
+            assert !implementor.isInterface();
+            if (implementor.isAbstract() || !implementor.isLeafClass()) {
+                AssumptionResult<ResolvedJavaType> leafConcreteSubtype = implementor.findLeafConcreteSubtype();
+                if (leafConcreteSubtype != null) {
+                    assert !leafConcreteSubtype.getResult().equals(implementor);
+                    AssumptionResult<ResolvedJavaType> newResult = new AssumptionResult<>(leafConcreteSubtype.getResult(), new ConcreteSubtype(this, implementor));
+                    newResult.add(leafConcreteSubtype);
+                    return leafConcreteSubtype;
+                }
                 return null;
             }
-            return type;
+
+            return new AssumptionResult<>(implementor, new LeafType(implementor), new ConcreteSubtype(this, implementor));
         } else {
             HotSpotResolvedObjectTypeImpl type = this;
             while (type.isAbstract()) {
@@ -170,7 +179,12 @@
             if (type.isAbstract() || type.isInterface() || !type.isLeafClass()) {
                 return null;
             }
-            return type;
+            if (this.isAbstract()) {
+                return new AssumptionResult<>(type, new LeafType(type), new ConcreteSubtype(this, type));
+            } else {
+                assert this.equals(type);
+                return new AssumptionResult<>(type, new LeafType(type));
+            }
         }
     }
 
@@ -281,9 +295,12 @@
     }
 
     @Override
-    public boolean hasFinalizableSubclass() {
+    public AssumptionResult<Boolean> hasFinalizableSubclass() {
         assert !isArray();
-        return runtime().getCompilerToVM().hasFinalizableSubclass(getMetaspaceKlass());
+        if (!runtime().getCompilerToVM().hasFinalizableSubclass(getMetaspaceKlass())) {
+            return new AssumptionResult<>(false, new NoFinalizableSubclass(this));
+        }
+        return new AssumptionResult<>(true);
     }
 
     @Override
@@ -492,7 +509,7 @@
     }
 
     @Override
-    public ResolvedJavaMethod findUniqueConcreteMethod(ResolvedJavaMethod method) {
+    public AssumptionResult<ResolvedJavaMethod> findUniqueConcreteMethod(ResolvedJavaMethod method) {
         HotSpotResolvedJavaMethod hmethod = (HotSpotResolvedJavaMethod) method;
         HotSpotResolvedObjectType declaredHolder = hmethod.getDeclaringClass();
         /*
@@ -503,7 +520,11 @@
          * a deopt instead since they can't really be used if they aren't linked yet.
          */
         if (!declaredHolder.isAssignableFrom(this) || this.isArray() || this.equals(declaredHolder) || !isLinked() || isInterface()) {
-            return hmethod.uniqueConcreteMethod(declaredHolder);
+            ResolvedJavaMethod result = hmethod.uniqueConcreteMethod(declaredHolder);
+            if (result != null) {
+                return new AssumptionResult<>(result, new ConcreteMethod(method, declaredHolder, result));
+            }
+            return null;
         }
         /*
          * The holder may be a subtype of the declaredHolder so make sure to resolve the method to
@@ -515,7 +536,11 @@
             return null;
         }
 
-        return resolvedMethod.uniqueConcreteMethod(this);
+        ResolvedJavaMethod result = resolvedMethod.uniqueConcreteMethod(this);
+        if (result != null) {
+            return new AssumptionResult<>(result, new ConcreteMethod(method, this, result));
+        }
+        return null;
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java	Thu Mar 12 15:59:01 2015 +0100
@@ -29,6 +29,7 @@
 import java.net.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.hotspot.*;
 
@@ -115,8 +116,8 @@
     }
 
     @Override
-    public boolean hasFinalizableSubclass() {
-        return false;
+    public AssumptionResult<Boolean> hasFinalizableSubclass() {
+        return new AssumptionResult<>(false);
     }
 
     @Override
@@ -190,12 +191,12 @@
     }
 
     @Override
-    public ResolvedJavaType findUniqueConcreteSubtype() {
-        return this;
+    public AssumptionResult<ResolvedJavaType> findLeafConcreteSubtype() {
+        return new AssumptionResult<>(this);
     }
 
     @Override
-    public ResolvedJavaMethod findUniqueConcreteMethod(ResolvedJavaMethod method) {
+    public AssumptionResult<ResolvedJavaMethod> findUniqueConcreteMethod(ResolvedJavaMethod method) {
         return null;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSnippetReflectionProvider.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSnippetReflectionProvider.java	Thu Mar 12 15:59:01 2015 +0100
@@ -73,6 +73,9 @@
     }
 
     public Object getInjectedNodeIntrinsicParameter(ResolvedJavaType type) {
+        if (type.isInstance(forObject(runtime.getHostProviders().getWordTypes()))) {
+            return runtime.getHostProviders().getWordTypes();
+        }
         if (type.isInstance(forObject(runtime))) {
             return runtime;
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Thu Mar 12 15:59:01 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -22,31 +22,18 @@
  */
 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.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.options.*;
 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}.
@@ -78,9 +65,9 @@
 
     }
 
-    public HotSpotSuitesProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, Replacements replacements) {
+    public HotSpotSuitesProvider(HotSpotGraalRuntimeProvider runtime) {
         this.runtime = runtime;
-        this.defaultGraphBuilderSuite = createGraphBuilderSuite(metaAccess, constantReflection, replacements);
+        this.defaultGraphBuilderSuite = createGraphBuilderSuite();
         this.defaultSuites = new DerivedOptionValue<>(new SuitesSupplier());
         this.defaultLIRSuites = new DerivedOptionValue<>(new LIRSuitesSupplier());
     }
@@ -112,95 +99,9 @@
         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) {
+    protected PhaseSuite<HighTierContext> createGraphBuilderSuite() {
         PhaseSuite<HighTierContext> suite = new PhaseSuite<>();
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault();
-        if (InlineDuringParsing.getValue()) {
-            config.setLoadFieldPlugin(new LoadFieldPlugin() {
-                public boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field) {
-                    if (receiver.isConstant()) {
-                        JavaConstant asJavaConstant = receiver.asJavaConstant();
-                        return tryConstantFold(builder, metaAccess, constantReflection, field, asJavaConstant);
-                    }
-                    return false;
-                }
-
-                public boolean apply(GraphBuilderContext builder, ResolvedJavaField staticField) {
-                    return tryConstantFold(builder, metaAccess, constantReflection, staticField, null);
-                }
-            });
-            config.setInlineInvokePlugin(new InlineInvokePlugin() {
-                public ResolvedJavaMethod getInlinedMethod(GraphBuilderContext builder, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType, int depth) {
-                    ResolvedJavaMethod subst = replacements.getMethodSubstitutionMethod(method);
-                    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;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java	Thu Mar 12 15:59:01 2015 +0100
@@ -0,0 +1,134 @@
+/*
+ * 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.hotspot.meta;
+
+import static com.oracle.graal.api.meta.LocationIdentity.*;
+import static com.oracle.graal.hotspot.word.HotSpotOperation.HotspotOpcode.*;
+import static com.oracle.graal.nodes.ConstantNode.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.hotspot.nodes.type.*;
+import com.oracle.graal.hotspot.word.*;
+import com.oracle.graal.hotspot.word.HotSpotOperation.HotspotOpcode;
+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.extended.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Extends {@link WordOperationPlugin} to handle {@linkplain HotSpotOperation HotSpot word
+ * operations}.
+ */
+class HotSpotWordOperationPlugin extends WordOperationPlugin {
+    public HotSpotWordOperationPlugin(SnippetReflectionProvider snippetReflection, WordTypes wordTypes) {
+        super(snippetReflection, wordTypes);
+    }
+
+    @Override
+    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        if (!wordTypes.isWordOperation(method)) {
+            return false;
+        }
+
+        HotSpotOperation operation = method.getAnnotation(HotSpotOperation.class);
+        if (operation == null) {
+            processWordOperation(b, args, wordTypes.getWordOperation(method, b.getMethod().getDeclaringClass()));
+            return true;
+        }
+        processHotSpotWordOperation(b, method, args, operation);
+        return true;
+    }
+
+    public void processHotSpotWordOperation(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, HotSpotOperation operation) {
+        Kind returnKind = method.getSignature().getReturnKind();
+        Kind returnStackKind = returnKind.getStackKind();
+        switch (operation.opcode()) {
+            case POINTER_EQ:
+            case POINTER_NE:
+                assert args.length == 2;
+                HotspotOpcode opcode = operation.opcode();
+                ValueNode left = args[0];
+                ValueNode right = args[1];
+                assert left.stamp() instanceof MetaspacePointerStamp : left + " " + left.stamp();
+                assert right.stamp() instanceof MetaspacePointerStamp : right + " " + right.stamp();
+                assert opcode == POINTER_EQ || opcode == POINTER_NE;
+
+                PointerEqualsNode comparison = b.append(new PointerEqualsNode(left, right));
+                ValueNode eqValue = b.append(forBoolean(opcode == POINTER_EQ));
+                ValueNode neValue = b.append(forBoolean(opcode == POINTER_NE));
+                b.push(returnStackKind, b.append(new ConditionalNode(comparison, eqValue, neValue)));
+                break;
+
+            case IS_NULL:
+                assert args.length == 1;
+                ValueNode pointer = args[0];
+                assert pointer.stamp() instanceof MetaspacePointerStamp;
+
+                IsNullNode isNull = b.append(new IsNullNode(pointer));
+                b.push(returnStackKind, b.append(new ConditionalNode(isNull, b.append(forBoolean(true)), b.append(forBoolean(false)))));
+                break;
+
+            case FROM_POINTER:
+                assert args.length == 1;
+                b.push(returnStackKind, b.append(new PointerCastNode(StampFactory.forKind(wordKind), args[0])));
+                break;
+
+            case TO_KLASS_POINTER:
+                assert args.length == 1;
+                b.push(returnStackKind, b.append(new PointerCastNode(KlassPointerStamp.klass(), args[0])));
+                break;
+
+            case TO_METHOD_POINTER:
+                assert args.length == 1;
+                b.push(returnStackKind, b.append(new PointerCastNode(MethodPointerStamp.method(), args[0])));
+                break;
+
+            case READ_KLASS_POINTER:
+                assert args.length == 2 || args.length == 3;
+                Stamp readStamp = KlassPointerStamp.klass();
+                LocationNode location;
+                if (args.length == 2) {
+                    location = makeLocation(b, args[1], ANY_LOCATION);
+                } else {
+                    location = makeLocation(b, args[1], args[2]);
+                }
+                ReadNode read = b.append(new ReadNode(args[0], location, readStamp, BarrierType.NONE));
+                /*
+                 * The read must not float outside its block otherwise it may float above an
+                 * explicit zero check on its base address.
+                 */
+                read.setGuard(AbstractBeginNode.prevBegin(read));
+                b.push(returnStackKind, read);
+                break;
+
+            default:
+                throw GraalInternalError.shouldNotReachHere("unknown operation: " + operation.opcode());
+        }
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java	Thu Mar 12 15:59:01 2015 +0100
@@ -30,7 +30,6 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.extended.*;
@@ -91,7 +90,6 @@
 
             ReturnNode returnNode = g.add(new ReturnNode(boxedResult));
             callNode.setNext(returnNode);
-            (new HotSpotWordTypeRewriterPhase(providers.getMetaAccess(), providers.getSnippetReflection(), providers.getConstantReflection(), Kind.Long)).apply(g);
             return g;
         } catch (NoSuchMethodException e) {
             throw GraalInternalError.shouldNotReachHere("Call Stub method not found");
@@ -121,7 +119,7 @@
                 ConstantNode index = ConstantNode.forInt(0, g);
                 int indexScaling = runtime().getArrayIndexScale(arrayElementKind);
                 IndexedLocationNode locationNode = g.unique(new IndexedLocationNode(locationIdentity, displacement, index, indexScaling));
-                Stamp wordStamp = StampFactory.forKind(providers.getCodeCache().getTarget().wordKind);
+                Stamp wordStamp = StampFactory.forKind(providers.getWordTypes().getWordKind());
                 ComputeAddressNode arrayAddress = g.unique(new ComputeAddressNode(boxedElement, locationNode, wordStamp));
                 args.add(arrayAddress);
             } else {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodeinfo.*;
@@ -44,8 +45,8 @@
     public static final NodeClass<BeginLockScopeNode> TYPE = NodeClass.create(BeginLockScopeNode.class);
     protected int lockDepth;
 
-    public BeginLockScopeNode(int lockDepth) {
-        super(TYPE, null);
+    public BeginLockScopeNode(@InjectedNodeParameter WordTypes wordTypes, int lockDepth) {
+        super(TYPE, StampFactory.forKind(wordTypes.getWordKind()));
         this.lockDepth = lockDepth;
     }
 
@@ -68,6 +69,6 @@
         gen.setResult(this, result);
     }
 
-    @NodeIntrinsic(setStampFromReturnType = true)
+    @NodeIntrinsic
     public static native Word beginLockScope(@ConstantNodeParameter int lockDepth);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.calc.*;
@@ -38,8 +39,8 @@
     public static final NodeClass<CStringNode> TYPE = NodeClass.create(CStringNode.class);
     protected final String string;
 
-    public CStringNode(String string) {
-        super(TYPE, null);
+    public CStringNode(@InjectedNodeParameter WordTypes wordTypes, String string) {
+        super(TYPE, StampFactory.forKind(wordTypes.getWordKind()));
         this.string = string;
     }
 
@@ -68,6 +69,6 @@
         return bytes;
     }
 
-    @NodeIntrinsic(setStampFromReturnType = true)
+    @NodeIntrinsic
     public static native Word cstring(@ConstantNodeParameter String string);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
-import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
@@ -44,9 +42,13 @@
 
     protected LIRKind wordKind;
 
-    public CurrentJavaThreadNode(Kind kind) {
-        super(TYPE, StampFactory.forKind(kind));
-        this.wordKind = LIRKind.value(kind);
+    public CurrentJavaThreadNode(@InjectedNodeParameter WordTypes wordTypes) {
+        this(wordTypes.getWordKind());
+    }
+
+    public CurrentJavaThreadNode(Kind wordKind) {
+        super(TYPE, StampFactory.forKind(wordKind));
+        this.wordKind = LIRKind.value(wordKind);
     }
 
     @Override
@@ -63,8 +65,6 @@
         }
     }
 
-    @NodeIntrinsic(setStampFromReturnType = true)
-    public static Word get(@SuppressWarnings("unused") @ConstantNodeParameter Kind kind) {
-        return Word.unsigned(unsafeReadWord(Thread.currentThread(), eetopOffset()));
-    }
+    @NodeIntrinsic
+    public static native Word get();
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodeinfo.*;
@@ -40,8 +41,8 @@
 
     protected int lockDepth;
 
-    public CurrentLockNode(int lockDepth) {
-        super(TYPE, null);
+    public CurrentLockNode(@InjectedNodeParameter WordTypes wordTypes, int lockDepth) {
+        super(TYPE, StampFactory.forKind(wordTypes.getWordKind()));
         this.lockDepth = lockDepth;
     }
 
@@ -55,6 +56,6 @@
         gen.setResult(this, result);
     }
 
-    @NodeIntrinsic(setStampFromReturnType = true)
+    @NodeIntrinsic
     public static native Word currentLock(@ConstantNodeParameter int lockDepth);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -28,6 +28,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -45,8 +46,8 @@
     public static final NodeClass<DimensionsNode> TYPE = NodeClass.create(DimensionsNode.class);
     protected final int rank;
 
-    public DimensionsNode(int rank) {
-        super(TYPE, null);
+    public DimensionsNode(@InjectedNodeParameter WordTypes wordTypes, int rank) {
+        super(TYPE, StampFactory.forKind(wordTypes.getWordKind()));
         this.rank = rank;
     }
 
@@ -61,6 +62,6 @@
         gen.setResult(this, result);
     }
 
-    @NodeIntrinsic(setStampFromReturnType = true)
+    @NodeIntrinsic
     public static native Word allocaDimsArray(@ConstantNodeParameter int rank);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.calc.*;
@@ -39,8 +40,8 @@
 public final class MonitorCounterNode extends FloatingNode implements LIRLowerable {
     public static final NodeClass<MonitorCounterNode> TYPE = NodeClass.create(MonitorCounterNode.class);
 
-    public MonitorCounterNode() {
-        super(TYPE, null);
+    public MonitorCounterNode(@InjectedNodeParameter WordTypes wordTypes) {
+        super(TYPE, StampFactory.forKind(wordTypes.getWordKind()));
     }
 
     @Override
@@ -51,6 +52,6 @@
         gen.setResult(this, result);
     }
 
-    @NodeIntrinsic(setStampFromReturnType = true)
+    @NodeIntrinsic
     public static native Word counter();
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Thu Mar 12 15:59:01 2015 +0100
@@ -24,6 +24,7 @@
 
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+import static com.oracle.graal.word.Word.*;
 import sun.misc.*;
 
 import com.oracle.graal.api.meta.*;
@@ -89,7 +90,7 @@
     private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt) {
         Object realReceiver = PiNode.piCastNonNull(rcvr, AESCryptClass);
         Object kObject = UnsafeLoadNode.load(realReceiver, kOffset, Kind.Object, LocationIdentity.ANY_LOCATION);
-        Word kAddr = (Word) Word.fromObject(kObject).add(arrayBaseOffset(Kind.Byte));
+        Word kAddr = fromWordBase(Word.fromObject(kObject).add(arrayBaseOffset(Kind.Byte)));
         Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset);
         Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset);
         if (encrypt) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Thu Mar 12 15:59:01 2015 +0100
@@ -97,8 +97,8 @@
         Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
         Object kObject = UnsafeLoadNode.load(embeddedCipher, AESCryptSubstitutions.kOffset, Kind.Object, LocationIdentity.ANY_LOCATION);
         Object rObject = UnsafeLoadNode.load(realReceiver, rOffset, Kind.Object, LocationIdentity.ANY_LOCATION);
-        Word kAddr = (Word) Word.fromObject(kObject).add(arrayBaseOffset(Kind.Byte));
-        Word rAddr = (Word) Word.fromObject(rObject).add(arrayBaseOffset(Kind.Byte));
+        Word kAddr = Word.fromWordBase(Word.fromObject(kObject).add(arrayBaseOffset(Kind.Byte)));
+        Word rAddr = Word.fromWordBase(Word.fromObject(rObject).add(arrayBaseOffset(Kind.Byte)));
         Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset);
         Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset);
         if (encrypt) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java	Thu Mar 12 15:59:01 2015 +0100
@@ -23,13 +23,13 @@
 package com.oracle.graal.hotspot.replacements;
 
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.nodes.PiNode.*;
 
 import java.lang.reflect.*;
 
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.word.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
 
@@ -110,7 +110,7 @@
     }
 
     public static Class<?> readJavaMirror(Word klass) {
-        return piCastExactNonNull(klass.readObject(classMirrorOffset(), CLASS_MIRROR_LOCATION), Class.class);
+        return PiNode.asNonNullClass(klass.readObject(classMirrorOffset(), CLASS_MIRROR_LOCATION));
     }
 
     @MacroSubstitution(macro = ClassGetComponentTypeNode.class, isStatic = false)
@@ -119,7 +119,7 @@
         KlassPointer klass = ClassGetHubNode.readClass(thisObj);
         if (!klass.isNull()) {
             if (klassIsArray(klass)) {
-                return piCastExactNonNull(klass.readObject(arrayKlassComponentMirrorOffset(), ARRAY_KLASS_COMPONENT_MIRROR), Class.class);
+                return PiNode.asNonNullClass(klass.readObject(arrayKlassComponentMirrorOffset(), ARRAY_KLASS_COMPONENT_MIRROR));
             }
         }
         return null;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Thu Mar 12 15:59:01 2015 +0100
@@ -593,22 +593,14 @@
     @NodeIntrinsic(value = WriteRegisterNode.class, setStampFromReturnType = true)
     public static native void writeRegisterAsWord(@ConstantNodeParameter Register register, Word value);
 
-    @SuppressWarnings("unused")
     @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true)
-    private static Word loadWordFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter Kind wordKind, @ConstantNodeParameter LocationIdentity locationIdentity) {
-        return Word.unsigned(unsafeReadWord(object, offset));
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic(value = LoadHubNode.class)
-    public static KlassPointer loadHubIntrinsic(Object object, GuardingNode anchor) {
-        return KlassPointer.fromWord(Word.unsigned(unsafeReadKlassPointer(object)));
-    }
+    private static native Word loadWordFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter Kind wordKind, @ConstantNodeParameter LocationIdentity locationIdentity);
 
     @NodeIntrinsic(value = LoadHubNode.class)
-    public static KlassPointer loadHubIntrinsic(Object object) {
-        return KlassPointer.fromWord(Word.unsigned(unsafeReadKlassPointer(object)));
-    }
+    public static native KlassPointer loadHubIntrinsic(Object object, GuardingNode anchor);
+
+    @NodeIntrinsic(value = LoadHubNode.class)
+    public static native KlassPointer loadHubIntrinsic(Object object);
 
     @Fold
     public static int log2WordSize() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Thu Mar 12 15:59:01 2015 +0100
@@ -59,7 +59,7 @@
     private static final boolean USE_C_RUNTIME = Boolean.getBoolean("graal.loadExceptionObject.useCRuntime");
 
     @Snippet
-    public static Throwable loadException(@ConstantParameter Register threadRegister) {
+    public static Object loadException(@ConstantParameter Register threadRegister) {
         Word thread = registerAsWord(threadRegister);
         Object exception = readExceptionOop(thread);
         writeExceptionOop(thread, null);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -26,6 +26,7 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -183,9 +184,9 @@
         if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
             ResolvedJavaType receiverType = StampTool.typeOrNull(getReceiver().stamp());
             if (receiverType != null) {
-                ResolvedJavaMethod concreteMethod = receiverType.findUniqueConcreteMethod(target);
+                AssumptionResult<ResolvedJavaMethod> concreteMethod = receiverType.findUniqueConcreteMethod(target);
                 if (concreteMethod != null) {
-                    return createTargetInvokeNode(concreteMethod, intrinsicMethod);
+                    return createTargetInvokeNode(concreteMethod.getResult(), intrinsicMethod);
                 }
             }
         }
@@ -194,9 +195,9 @@
             return createTargetInvokeNode(target, intrinsicMethod);
         }
 
-        ResolvedJavaMethod concreteMethod = target.getDeclaringClass().findUniqueConcreteMethod(target);
+        AssumptionResult<ResolvedJavaMethod> concreteMethod = target.getDeclaringClass().findUniqueConcreteMethod(target);
         if (concreteMethod != null) {
-            return createTargetInvokeNode(concreteMethod, intrinsicMethod);
+            return createTargetInvokeNode(concreteMethod.getResult(), intrinsicMethod);
         }
 
         return null;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Thu Mar 12 15:59:01 2015 +0100
@@ -501,7 +501,7 @@
                     invoke.setStateAfter(graph.start().stateAfter());
                     graph.addAfterFixed(graph.start(), invoke);
 
-                    StructuredGraph inlineeGraph = providers.getReplacements().getSnippet(initCounter.getMethod());
+                    StructuredGraph inlineeGraph = providers.getReplacements().getSnippet(initCounter.getMethod(), null);
                     InliningUtil.inline(invoke, inlineeGraph, false, null);
 
                     List<ReturnNode> rets = graph.getNodes(ReturnNode.TYPE).snapshot();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -26,7 +26,6 @@
 
 import java.lang.reflect.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
@@ -63,7 +62,7 @@
                     final Replacements replacements = tool.getReplacements();
                     StructuredGraph snippetGraph = null;
                     try (Scope s = Debug.scope("ArrayCopySnippet", snippetMethod)) {
-                        snippetGraph = replacements.getSnippet(snippetMethod);
+                        snippetGraph = replacements.getSnippet(snippetMethod, null);
                     } catch (Throwable e) {
                         throw Debug.handle(e);
                     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Thu Mar 12 15:59:01 2015 +0100
@@ -114,7 +114,7 @@
 
     @Snippet(removeAllFrameStates = true)
     public static Object[] objectArrayClone(Object[] src) {
-        Object[] result = (Object[]) DynamicNewArrayNode.newUninitializedArray(GuardingPiNode.guardingNonNull(src.getClass().getComponentType()), src.length, Kind.Object);
+        Object[] result = (Object[]) DynamicNewArrayNode.newUninitializedArray(GuardingPiNode.asNonNullClass(src.getClass().getComponentType()), src.length, Kind.Object);
         ArrayCopyCallNode.disjointUninitializedArraycopy(src, 0, result, 0, src.length, Kind.Object);
         return result;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionSubstitutions.java	Thu Mar 12 15:59:01 2015 +0100
@@ -42,7 +42,7 @@
 
     @MethodSubstitution
     public static int getClassAccessFlags(Class<?> aClass) {
-        KlassPointer klass = ClassGetHubNode.readClass(GuardingPiNode.guardingNonNull(aClass));
+        KlassPointer klass = ClassGetHubNode.readClass(GuardingPiNode.asNonNullClass(aClass));
         if (klass.isNull()) {
             // Class for primitive type
             return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java	Thu Mar 12 15:59:01 2015 +0100
@@ -27,10 +27,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.graph.Node.ConstantNodeParameter;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.replacements.arraycopy.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -45,16 +42,6 @@
     @MacroSubstitution(macro = ArrayCopyNode.class)
     public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
 
-    @MethodSubstitution
-    public static long currentTimeMillis() {
-        return callLong(JAVA_TIME_MILLIS);
-    }
-
-    @MethodSubstitution
-    public static long nanoTime() {
-        return callLong(JAVA_TIME_NANOS);
-    }
-
     @MacroSubstitution(macro = SystemIdentityHashCodeNode.class)
     @MethodSubstitution
     public static int identityHashCode(Object x) {
@@ -64,13 +51,4 @@
 
         return computeHashCode(x);
     }
-
-    @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true)
-    public static long callLong(@ConstantNodeParameter ForeignCallDescriptor descriptor) {
-        if (descriptor == JAVA_TIME_MILLIS) {
-            return System.currentTimeMillis();
-        }
-        assert descriptor == JAVA_TIME_NANOS;
-        return System.nanoTime();
-    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java	Thu Mar 12 15:59:01 2015 +0100
@@ -25,15 +25,11 @@
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.word.*;
 
@@ -43,14 +39,9 @@
 @ClassSubstitution(java.lang.Thread.class)
 public class ThreadSubstitutions {
 
-    @MethodSubstitution
-    public static Thread currentThread() {
-        return PiNode.piCastNonNull(CurrentJavaThreadNode.get(getWordKind()).readObject(threadObjectOffset(), JAVA_THREAD_THREAD_OBJECT_LOCATION), Thread.class);
-    }
-
     @MethodSubstitution(isStatic = false)
     public static boolean isInterrupted(final Thread thisObject, boolean clearInterrupted) {
-        Word javaThread = CurrentJavaThreadNode.get(getWordKind());
+        Word javaThread = CurrentJavaThreadNode.get();
         Object thread = javaThread.readObject(threadObjectOffset(), JAVA_THREAD_THREAD_OBJECT_LOCATION);
         if (thisObject == thread) {
             Word osThread = javaThread.readWord(osThreadOffset(), JAVA_THREAD_OSTHREAD_LOCATION);
@@ -65,17 +56,6 @@
 
     public static final ForeignCallDescriptor THREAD_IS_INTERRUPTED = new ForeignCallDescriptor("thread_is_interrupted", boolean.class, Object.class, boolean.class);
 
-    /**
-     * @param descriptor
-     */
     @NodeIntrinsic(ForeignCallNode.class)
-    private static boolean threadIsInterruptedStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Thread thread, boolean clearIsInterrupted) {
-        try {
-            Method isInterrupted = Thread.class.getDeclaredMethod("isInterrupted", boolean.class);
-            isInterrupted.setAccessible(true);
-            return (Boolean) isInterrupted.invoke(thread, clearIsInterrupted);
-        } catch (Exception e) {
-            throw new GraalInternalError(e);
-        }
-    }
+    private static native boolean threadIsInterruptedStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Thread thread, boolean clearIsInterrupted);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Thu Mar 12 15:59:01 2015 +0100
@@ -79,7 +79,7 @@
         serialWriteBarrierCounter.inc();
         int cardTableShift = (isImmutableCode() && generatePIC()) ? CardTableShiftNode.cardTableShift() : cardTableShift();
         long cardTableAddress = (isImmutableCode() && generatePIC()) ? CardTableAddressNode.cardTableAddress() : cardTableStart();
-        Word base = (Word) oop.unsignedShiftRight(cardTableShift);
+        Word base = Word.fromWordBase(oop.unsignedShiftRight(cardTableShift));
         long startAddress = cardTableAddress;
         int displacement = 0;
         if (((int) startAddress) == startAddress) {
@@ -105,7 +105,7 @@
         long end = (dstAddr + header + ((long) startIndex + length - 1) * scale) >>> cardShift;
         long count = end - start + 1;
         while (count-- > 0) {
-            DirectStoreNode.store((start + cardStart) + count, false, Kind.Boolean);
+            DirectStoreNode.storeBoolean((start + cardStart) + count, false, Kind.Boolean);
         }
     }
 
@@ -119,8 +119,8 @@
         Object fixedObject = FixedValueAnchorNode.getObject(object);
         verifyOop(fixedObject);
         Object fixedExpectedObject = FixedValueAnchorNode.getObject(expectedObject);
-        Word field = (Word) Word.fromArray(fixedObject, SnippetLocationProxyNode.location(location));
-        Word previousOop = (Word) Word.fromObject(fixedExpectedObject);
+        Word field = Word.fromWordBase(Word.fromArray(fixedObject, SnippetLocationProxyNode.location(location)));
+        Word previousOop = Word.fromWordBase(Word.fromObject(fixedExpectedObject));
         byte markingValue = thread.readByte(g1SATBQueueMarkingOffset());
         Word bufferAddress = thread.readWord(g1SATBQueueBufferOffset());
         Word indexAddress = thread.add(g1SATBQueueIndexOffset());
@@ -140,7 +140,7 @@
             // If the previous value has to be loaded (before the write), the load is issued.
             // The load is always issued except the cases of CAS and referent field.
             if (probability(LIKELY_PROBABILITY, doLoad)) {
-                previousOop = (Word) Word.fromObject(field.readObject(0, BarrierType.NONE));
+                previousOop = Word.fromWordBase(Word.fromObject(field.readObject(0, BarrierType.NONE)));
                 if (trace) {
                     log(trace, "[%d] G1-Pre Thread %p Previous Object %p\n ", gcCycle, thread.rawValue(), previousOop.rawValue());
                     verifyOop(previousOop.toObject());
@@ -176,9 +176,9 @@
         validateObject(fixedObject, fixedValue);
         Word oop;
         if (usePrecise) {
-            oop = (Word) Word.fromArray(fixedObject, SnippetLocationProxyNode.location(location));
+            oop = Word.fromWordBase(Word.fromArray(fixedObject, SnippetLocationProxyNode.location(location)));
         } else {
-            oop = (Word) Word.fromObject(fixedObject);
+            oop = Word.fromWordBase(Word.fromObject(fixedObject));
         }
         int gcCycle = 0;
         if (trace) {
@@ -186,7 +186,7 @@
             log(trace, "[%d] G1-Post Thread: %p Object: %p\n", gcCycle, thread.rawValue(), Word.fromObject(fixedObject).rawValue());
             log(trace, "[%d] G1-Post Thread: %p Field: %p\n", gcCycle, thread.rawValue(), oop.rawValue());
         }
-        Word writtenValue = (Word) Word.fromObject(fixedValue);
+        Word writtenValue = Word.fromWordBase(Word.fromObject(fixedValue));
         Word bufferAddress = thread.readWord(g1CardQueueBufferOffset());
         Word indexAddress = thread.add(g1CardQueueIndexOffset());
         Word indexValue = thread.readWord(g1CardQueueIndexOffset());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -63,7 +63,7 @@
         Kind componentKind = srcType.getComponentType().getKind();
         final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind, shouldUnroll(), isExact()));
         try (Scope s = Debug.scope("ArrayCopySnippet", snippetMethod)) {
-            return replacements.getSnippet(snippetMethod);
+            return replacements.getSnippet(snippetMethod, null, null);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
@@ -103,7 +103,7 @@
             }
             snippetGraph = null;
             try (Scope s = Debug.scope("ArrayCopySnippet", snippetMethod)) {
-                snippetGraph = replacements.getSnippet(snippetMethod, getTargetMethod()).copy();
+                snippetGraph = replacements.getSnippet(snippetMethod, getTargetMethod(), null).copy();
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java	Thu Mar 12 15:59:01 2015 +0100
@@ -91,42 +91,36 @@
             for (long i = 0; i < postLoopBytes; i += elementSize) {
                 srcOffset -= elementSize;
                 destOffset -= elementSize;
-                Object a = UnsafeLoadNode.load(src, arrayBaseOffset + srcOffset, baseKind, locationIdentity);
-                UnsafeStoreNode.store(dest, arrayBaseOffset + destOffset, a, baseKind, locationIdentity);
+                UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity);
             }
             // Main-loop
             for (long i = 0; i < mainLoopBytes; i += VECTOR_SIZE) {
                 srcOffset -= VECTOR_SIZE;
                 destOffset -= VECTOR_SIZE;
-                Long a = UnsafeLoadNode.load(src, arrayBaseOffset + srcOffset, VECTOR_KIND, locationIdentity);
-                UnsafeStoreNode.store(dest, arrayBaseOffset + destOffset, a, VECTOR_KIND, locationIdentity);
+                UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, VECTOR_KIND, locationIdentity);
             }
             // Pre-loop
             for (long i = 0; i < preLoopBytes; i += elementSize) {
                 srcOffset -= elementSize;
                 destOffset -= elementSize;
-                Object a = UnsafeLoadNode.load(src, arrayBaseOffset + srcOffset, baseKind, locationIdentity);
-                UnsafeStoreNode.store(dest, arrayBaseOffset + destOffset, a, baseKind, locationIdentity);
+                UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity);
             }
         } else {
             // Pre-loop
             for (long i = 0; i < preLoopBytes; i += elementSize) {
-                Object a = UnsafeLoadNode.load(src, arrayBaseOffset + srcOffset, baseKind, locationIdentity);
-                UnsafeStoreNode.store(dest, arrayBaseOffset + destOffset, a, baseKind, locationIdentity);
+                UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity);
                 srcOffset += elementSize;
                 destOffset += elementSize;
             }
             // Main-loop
             for (long i = 0; i < mainLoopBytes; i += VECTOR_SIZE) {
-                Long a = UnsafeLoadNode.load(src, arrayBaseOffset + srcOffset, VECTOR_KIND, locationIdentity);
-                UnsafeStoreNode.store(dest, arrayBaseOffset + destOffset, a, VECTOR_KIND, locationIdentity);
+                UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, VECTOR_KIND, locationIdentity);
                 srcOffset += VECTOR_SIZE;
                 destOffset += VECTOR_SIZE;
             }
             // Post-loop
             for (long i = 0; i < postLoopBytes; i += elementSize) {
-                Object a = UnsafeLoadNode.load(src, arrayBaseOffset + srcOffset, baseKind, locationIdentity);
-                UnsafeStoreNode.store(dest, arrayBaseOffset + destOffset, a, baseKind, locationIdentity);
+                UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity);
                 srcOffset += elementSize;
                 destOffset += elementSize;
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Thu Mar 12 15:59:01 2015 +0100
@@ -84,7 +84,7 @@
     private final TargetDescription target;
 
     public DeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super(DeoptimizationStub.class, "deoptimizationHandler", providers, target, linkage);
+        super(DeoptimizationStub.class, "deoptimizationHandler", providers, linkage);
         this.target = target;
         assert PreferGraalStubs.getValue();
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java	Thu Mar 12 15:59:01 2015 +0100
@@ -49,8 +49,8 @@
  */
 public class ExceptionHandlerStub extends SnippetStub {
 
-    public ExceptionHandlerStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super("exceptionHandler", providers, target, linkage);
+    public ExceptionHandlerStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super("exceptionHandler", providers, linkage);
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Thu Mar 12 15:59:01 2015 +0100
@@ -26,7 +26,6 @@
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.*;
@@ -34,10 +33,8 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
-import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.word.*;
@@ -188,16 +185,17 @@
      */
     @Override
     protected StructuredGraph getGraph() {
+        WordTypes wordTypes = providers.getWordTypes();
         Class<?>[] args = linkage.getDescriptor().getArgumentTypes();
         boolean isObjectResult = linkage.getOutgoingCallingConvention().getReturn().getKind() == Kind.Object;
 
         StructuredGraph graph = new StructuredGraph(toString(), null, AllowAssumptions.NO);
         graph.disableInlinedMethodRecording();
 
-        GraphKit kit = new HotSpotGraphKit(graph, providers);
+        GraphKit kit = new GraphKit(graph, providers, wordTypes);
         ParameterNode[] params = createParameters(kit, args);
 
-        ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), true, false));
+        ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false));
         ValueNode result = createTargetCall(kit, params, thread);
         kit.createInvoke(StubUtil.class, "handlePendingException", thread, ConstantNode.forBoolean(isObjectResult, graph));
         if (isObjectResult) {
@@ -210,8 +208,7 @@
             Debug.dump(graph, "Initial stub graph");
         }
 
-        kit.rewriteWordTypes(providers.getSnippetReflection());
-        kit.inlineInvokes(providers.getSnippetReflection());
+        kit.inlineInvokes();
 
         if (Debug.isDumpEnabled()) {
             Debug.dump(graph, "Stub graph before compilation");
@@ -220,26 +217,13 @@
         return graph;
     }
 
-    private static class HotSpotGraphKit extends GraphKit {
-
-        public HotSpotGraphKit(StructuredGraph graph, Providers providers) {
-            super(graph, providers);
-        }
-
-        @Override
-        public void rewriteWordTypes(SnippetReflectionProvider snippetReflection) {
-            new HotSpotWordTypeRewriterPhase(providers.getMetaAccess(), snippetReflection, providers.getConstantReflection(), providers.getCodeCache().getTarget().wordKind).apply(graph);
-        }
-    }
-
     private ParameterNode[] createParameters(GraphKit kit, Class<?>[] args) {
         ParameterNode[] params = new ParameterNode[args.length];
         ResolvedJavaType accessingClass = providers.getMetaAccess().lookupJavaType(getClass());
         for (int i = 0; i < args.length; i++) {
             ResolvedJavaType type = providers.getMetaAccess().lookupJavaType(args[i]).resolve(accessingClass);
-            Kind kind = type.getKind().getStackKind();
             Stamp stamp;
-            if (kind == Kind.Object) {
+            if (type.getKind().getStackKind() == Kind.Object) {
                 stamp = StampFactory.declared(type);
             } else {
                 stamp = StampFactory.forKind(type.getKind());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java	Thu Mar 12 15:59:01 2015 +0100
@@ -38,12 +38,9 @@
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.hotspot.word.*;
-import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
-import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
-import com.oracle.graal.replacements.SnippetTemplate.Arguments;
-import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
 import com.oracle.graal.word.*;
 
 /**
@@ -54,19 +51,19 @@
  */
 public class NewArrayStub extends SnippetStub {
 
-    public NewArrayStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super("newArray", providers, target, linkage);
+    public NewArrayStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super("newArray", providers, linkage);
     }
 
     @Override
-    protected Arguments makeArguments(SnippetInfo stub) {
+    protected Object[] makeConstArgs() {
         HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) providers.getMetaAccess().lookupJavaType(int[].class);
-
-        Arguments args = new Arguments(stub, GuardsStage.FLOATING_GUARDS, LoweringTool.StandardLoweringStage.HIGH_TIER);
-        args.add("hub", null);
-        args.add("length", null);
-        args.addConst("intArrayHub", intArrayType.klass(), KlassPointerStamp.klassNonNull());
-        args.addConst("threadRegister", providers.getRegisters().getThreadRegister());
+        int count = method.getSignature().getParameterCount(false);
+        Object[] args = new Object[count];
+        assert checkConstArg(2, "intArrayHub");
+        assert checkConstArg(3, "threadRegister");
+        args[2] = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), intArrayType.klass(), null);
+        args[3] = providers.getRegisters().getThreadRegister();
         return args;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Thu Mar 12 15:59:01 2015 +0100
@@ -38,12 +38,9 @@
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.hotspot.word.*;
-import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
-import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
-import com.oracle.graal.replacements.SnippetTemplate.Arguments;
-import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
 import com.oracle.graal.word.*;
 
 /**
@@ -54,18 +51,19 @@
  */
 public class NewInstanceStub extends SnippetStub {
 
-    public NewInstanceStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super("newInstance", providers, target, linkage);
+    public NewInstanceStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super("newInstance", providers, linkage);
     }
 
     @Override
-    protected Arguments makeArguments(SnippetInfo stub) {
+    protected Object[] makeConstArgs() {
         HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) providers.getMetaAccess().lookupJavaType(int[].class);
-
-        Arguments args = new Arguments(stub, GuardsStage.FLOATING_GUARDS, LoweringTool.StandardLoweringStage.HIGH_TIER);
-        args.add("hub", null);
-        args.addConst("intArrayHub", intArrayType.klass(), KlassPointerStamp.klassNonNull());
-        args.addConst("threadRegister", providers.getRegisters().getThreadRegister());
+        int count = method.getSignature().getParameterCount(false);
+        Object[] args = new Object[count];
+        assert checkConstArg(1, "intArrayHub");
+        assert checkConstArg(2, "threadRegister");
+        args[1] = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), intArrayType.klass(), null);
+        args[2] = providers.getRegisters().getThreadRegister();
         return args;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,43 +22,32 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
-import com.oracle.graal.api.code.*;
+import java.lang.reflect.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
-import com.oracle.graal.replacements.SnippetTemplate.Arguments;
-import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
+import com.oracle.graal.replacements.Snippet.ConstantParameter;
 
 /**
  * Base class for a stub defined by a snippet.
  */
 public abstract class SnippetStub extends Stub implements Snippets {
 
-    static class Template extends AbstractTemplates {
-
-        Template(HotSpotProviders providers, TargetDescription target, Class<? extends Snippets> declaringClass, String snippetMethodName) {
-            super(providers, providers.getSnippetReflection(), target);
-            this.info = snippet(declaringClass, snippetMethodName);
-        }
-
-        /**
-         * Info for the method implementing the stub.
-         */
-        protected final SnippetInfo info;
-
-        protected StructuredGraph getGraph(Arguments args) {
-            SnippetTemplate template = template(args);
-            return template.copySpecializedGraph();
-        }
-    }
-
-    protected final Template snippet;
+    protected final ResolvedJavaMethod method;
 
     /**
      * Creates a new snippet stub.
@@ -67,8 +56,8 @@
      *            this object
      * @param linkage linkage details for a call to the stub
      */
-    public SnippetStub(String snippetMethodName, HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        this(null, snippetMethodName, providers, target, linkage);
+    public SnippetStub(String snippetMethodName, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        this(null, snippetMethodName, providers, linkage);
     }
 
     /**
@@ -80,28 +69,61 @@
      *            {@code snippetDeclaringClass}
      * @param linkage linkage details for a call to the stub
      */
-    public SnippetStub(Class<? extends Snippets> snippetDeclaringClass, String snippetMethodName, HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+    public SnippetStub(Class<? extends Snippets> snippetDeclaringClass, String snippetMethodName, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
         super(providers, linkage);
-        this.snippet = new Template(providers, target, snippetDeclaringClass == null ? getClass() : snippetDeclaringClass, snippetMethodName);
+        Method javaMethod = SnippetTemplate.AbstractTemplates.findMethod(snippetDeclaringClass == null ? getClass() : snippetDeclaringClass, snippetMethodName, null);
+        this.method = providers.getMetaAccess().lookupJavaMethod(javaMethod);
     }
 
+    public static final ThreadLocal<StructuredGraph> SnippetGraphUnderConstruction = new ThreadLocal<>();
+
     @Override
     protected StructuredGraph getGraph() {
-        return snippet.getGraph(makeArguments(snippet.info));
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault();
+        Plugins defaultPlugins = providers.getGraphBuilderPlugins();
+        Plugins plugins = config.getPlugins().updateFrom(defaultPlugins, false);
+        plugins.getInvocationPlugins().setDefaults(defaultPlugins.getInvocationPlugins());
+        plugins.setParameterPlugin(new ConstantBindingParameterPlugin(makeConstArgs(), plugins.getParameterPlugin(), providers.getMetaAccess(), providers.getSnippetReflection()));
+
+        // Stubs cannot have optimistic assumptions since they have
+        // to be valid for the entire run of the VM. Nor can they be
+        // evolved or have breakpoints.
+        final StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO);
+        graph.disableInlinedMethodRecording();
+
+        assert SnippetGraphUnderConstruction.get() == null;
+        SnippetGraphUnderConstruction.set(graph);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, method).apply(graph);
+        SnippetGraphUnderConstruction.set(null);
+
+        graph.setGuardsStage(GuardsStage.FLOATING_GUARDS);
+        try (Scope s = Debug.scope("LoweringStub", graph)) {
+            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, new PhaseContext(providers));
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+
+        return graph;
     }
 
-    /**
-     * Adds the arguments to this snippet stub.
-     */
-    protected Arguments makeArguments(SnippetInfo stub) {
-        Arguments args = new Arguments(stub, GuardsStage.FLOATING_GUARDS, LoweringTool.StandardLoweringStage.HIGH_TIER);
-        for (int i = 0; i < stub.getParameterCount(); i++) {
-            String name = stub.getParameterName(i);
-            if (stub.isConstantParameter(i)) {
-                args.addConst(name, getConstantParameterValue(i, name));
-            } else {
-                assert !stub.isVarargsParameter(i);
-                args.add(name, null);
+    protected boolean checkConstArg(int index, String expectedName) {
+        assert method.getParameterAnnotation(ConstantParameter.class, index) != null : String.format("parameter %d of %s is expected to be constant", index, method.format("%H.%n(%p)"));
+        LocalVariableTable lvt = method.getLocalVariableTable();
+        if (lvt != null) {
+            Local local = lvt.getLocal(index, 0);
+            assert local != null;
+            String actualName = local.getName();
+            assert actualName.equals(expectedName) : String.format("parameter %d of %s is expected to be named %s, not %s", index, method.format("%H.%n(%p)"), expectedName, actualName);
+        }
+        return true;
+    }
+
+    protected Object[] makeConstArgs() {
+        int count = method.getSignature().getParameterCount(false);
+        Object[] args = new Object[count];
+        for (int i = 0; i < args.length; i++) {
+            if (method.getParameterAnnotation(ConstantParameter.class, i) != null) {
+                args[i] = getConstantParameterValue(i, null);
             }
         }
         return args;
@@ -118,7 +140,7 @@
 
     @Override
     public ResolvedJavaMethod getInstalledCodeOwner() {
-        return snippet.info.getMethod();
+        return method;
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java	Thu Mar 12 15:59:01 2015 +0100
@@ -84,7 +84,7 @@
     private final TargetDescription target;
 
     public UncommonTrapStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super(UncommonTrapStub.class, "uncommonTrapHandler", providers, target, linkage);
+        super(UncommonTrapStub.class, "uncommonTrapHandler", providers, linkage);
         this.target = target;
         assert PreferGraalStubs.getValue();
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java	Thu Mar 12 15:59:01 2015 +0100
@@ -46,8 +46,8 @@
  */
 public class UnwindExceptionToCallerStub extends SnippetStub {
 
-    public UnwindExceptionToCallerStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super("unwindExceptionToCaller", providers, target, linkage);
+    public UnwindExceptionToCallerStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super("unwindExceptionToCaller", providers, linkage);
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VerifyOopStub.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VerifyOopStub.java	Thu Mar 12 15:59:01 2015 +0100
@@ -24,7 +24,6 @@
 
 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.replacements.*;
@@ -34,8 +33,8 @@
  */
 public class VerifyOopStub extends SnippetStub {
 
-    public VerifyOopStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
-        super("verifyOop", providers, target, linkage);
+    public VerifyOopStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super("verifyOop", providers, linkage);
     }
 
     @Snippet
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/HotSpotWordTypeRewriterPhase.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,179 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, 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.word;
-
-import static com.oracle.graal.api.meta.LocationIdentity.*;
-import static com.oracle.graal.hotspot.word.HotSpotOperation.HotspotOpcode.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.hotspot.nodes.type.*;
-import com.oracle.graal.hotspot.word.HotSpotOperation.HotspotOpcode;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.word.*;
-import com.oracle.graal.word.Word.*;
-import com.oracle.graal.word.phases.*;
-
-public class HotSpotWordTypeRewriterPhase extends WordTypeRewriterPhase {
-
-    private final ResolvedJavaType klassPointerType;
-    private final ResolvedJavaType methodPointerType;
-
-    public HotSpotWordTypeRewriterPhase(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ConstantReflectionProvider constantReflection, Kind wordKind) {
-        super(metaAccess, snippetReflection, constantReflection, wordKind);
-        this.klassPointerType = metaAccess.lookupJavaType(KlassPointer.class);
-        this.methodPointerType = metaAccess.lookupJavaType(MethodPointer.class);
-    }
-
-    @Override
-    protected void changeToWord(StructuredGraph graph, ValueNode node) {
-        ResolvedJavaType baseType = StampTool.typeOrNull(node);
-        if (baseType != null && baseType.equals(klassPointerType)) {
-            node.setStamp(KlassPointerStamp.klass());
-        } else if (baseType != null && baseType.equals(methodPointerType)) {
-            node.setStamp(MethodPointerStamp.method());
-        } else {
-            super.changeToWord(graph, node);
-        }
-    }
-
-    @Override
-    protected Kind asKind(JavaType type) {
-        if (type.equals(klassPointerType) || type.equals(methodPointerType)) {
-            return wordKind;
-        }
-        return super.asKind(type);
-    }
-
-    @Override
-    protected void rewriteAccessIndexed(StructuredGraph graph, AccessIndexedNode node) {
-        if (node.stamp() instanceof MetaspacePointerStamp && node instanceof LoadIndexedNode && node.elementKind() != Kind.Illegal) {
-            /*
-             * Prevent rewriting of the MetaspacePointerStamp in the CanonicalizerPhase.
-             */
-            graph.replaceFixedWithFixed(node, graph.add(new LoadIndexedPointerNode(node.stamp(), node.array(), node.index())));
-        } else {
-            super.rewriteAccessIndexed(graph, node);
-        }
-    }
-
-    @Override
-    protected void rewriteInvoke(StructuredGraph graph, MethodCallTargetNode callTargetNode) {
-        ResolvedJavaMethod targetMethod = callTargetNode.targetMethod();
-        HotSpotOperation operation = targetMethod.getAnnotation(HotSpotOperation.class);
-        if (operation == null) {
-            Operation wordOperation = targetMethod.getAnnotation(Word.Operation.class);
-            if (wordOperation != null) {
-                super.rewriteWordOperation(graph, callTargetNode, targetMethod);
-            } else {
-                super.rewriteInvoke(graph, callTargetNode);
-            }
-        } else {
-            Invoke invoke = callTargetNode.invoke();
-            NodeInputList<ValueNode> arguments = callTargetNode.arguments();
-
-            switch (operation.opcode()) {
-                case POINTER_EQ:
-                case POINTER_NE:
-                    assert arguments.size() == 2;
-                    replace(invoke, pointerComparisonOp(graph, operation.opcode(), arguments.get(0), arguments.get(1)));
-                    break;
-
-                case IS_NULL:
-                    assert arguments.size() == 1;
-                    replace(invoke, pointerIsNullOp(graph, arguments.get(0)));
-                    break;
-
-                case FROM_POINTER:
-                    assert arguments.size() == 1;
-                    replace(invoke, graph.unique(new PointerCastNode(StampFactory.forKind(wordKind), arguments.get(0))));
-                    break;
-
-                case TO_KLASS_POINTER:
-                    assert arguments.size() == 1;
-                    replace(invoke, graph.unique(new PointerCastNode(KlassPointerStamp.klass(), arguments.get(0))));
-                    break;
-
-                case TO_METHOD_POINTER:
-                    assert arguments.size() == 1;
-                    replace(invoke, graph.unique(new PointerCastNode(MethodPointerStamp.method(), arguments.get(0))));
-                    break;
-
-                case READ_KLASS_POINTER:
-                    assert arguments.size() == 2 || arguments.size() == 3;
-                    Stamp readStamp = KlassPointerStamp.klass();
-                    LocationNode location;
-                    if (arguments.size() == 2) {
-                        location = makeLocation(graph, arguments.get(1), ANY_LOCATION);
-                    } else {
-                        location = makeLocation(graph, arguments.get(1), arguments.get(2));
-                    }
-                    replace(invoke, readKlassOp(graph, arguments.get(0), invoke, location, readStamp, operation.opcode()));
-                    break;
-
-                default:
-                    throw GraalInternalError.shouldNotReachHere("unknown operation: " + operation.opcode());
-            }
-        }
-    }
-
-    protected ValueNode readKlassOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location, Stamp readStamp, HotspotOpcode op) {
-        assert op == READ_KLASS_POINTER;
-        final BarrierType barrier = BarrierType.NONE;
-
-        ReadNode read = graph.add(new ReadNode(base, location, readStamp, barrier));
-        graph.addBeforeFixed(invoke.asNode(), read);
-        /*
-         * The read must not float outside its block otherwise it may float above an explicit zero
-         * check on its base address.
-         */
-        read.setGuard(AbstractBeginNode.prevBegin(invoke.asNode()));
-        return read;
-    }
-
-    private static ValueNode pointerComparisonOp(StructuredGraph graph, HotspotOpcode opcode, ValueNode left, ValueNode right) {
-        assert left.stamp() instanceof MetaspacePointerStamp && right.stamp() instanceof MetaspacePointerStamp;
-        assert opcode == POINTER_EQ || opcode == POINTER_NE;
-
-        PointerEqualsNode comparison = graph.unique(new PointerEqualsNode(left, right));
-        ValueNode eqValue = ConstantNode.forBoolean(opcode == POINTER_EQ, graph);
-        ValueNode neValue = ConstantNode.forBoolean(opcode == POINTER_NE, graph);
-        return graph.unique(new ConditionalNode(comparison, eqValue, neValue));
-    }
-
-    private static ValueNode pointerIsNullOp(StructuredGraph graph, ValueNode pointer) {
-        assert pointer.stamp() instanceof MetaspacePointerStamp;
-
-        IsNullNode isNull = graph.unique(new IsNullNode(pointer));
-        return graph.unique(new ConditionalNode(isNull, ConstantNode.forBoolean(true, graph), ConstantNode.forBoolean(false, graph)));
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/HotSpotWordTypes.java	Thu Mar 12 15:59:01 2015 +0100
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012, 2014, 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.word;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.hotspot.nodes.type.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Extends {@link WordTypes} with information about HotSpot metaspace pointer types.
+ */
+public class HotSpotWordTypes extends WordTypes {
+
+    /**
+     * Resolved type for {@link MetaspacePointer}.
+     */
+    private final ResolvedJavaType metaspacePointerType;
+
+    /**
+     * Resolved type for {@link KlassPointer}.
+     */
+    private final ResolvedJavaType klassPointerType;
+
+    /**
+     * Resolved type for {@link MethodPointer}.
+     */
+    private final ResolvedJavaType methodPointerType;
+
+    public HotSpotWordTypes(MetaAccessProvider metaAccess, Kind wordKind) {
+        super(metaAccess, wordKind);
+        this.metaspacePointerType = metaAccess.lookupJavaType(MetaspacePointer.class);
+        this.klassPointerType = metaAccess.lookupJavaType(KlassPointer.class);
+        this.methodPointerType = metaAccess.lookupJavaType(MethodPointer.class);
+    }
+
+    @Override
+    public boolean isWord(ResolvedJavaType type) {
+        if (type != null && metaspacePointerType.isAssignableFrom(type)) {
+            return true;
+        }
+        return super.isWord(type);
+    }
+
+    @Override
+    public Kind asKind(JavaType type) {
+        if (klassPointerType.equals(type) || methodPointerType.equals(type)) {
+            return getWordKind();
+        }
+        return super.asKind(type);
+    }
+
+    @Override
+    public Stamp getWordStamp(ResolvedJavaType type) {
+        if (type.equals(klassPointerType)) {
+            return KlassPointerStamp.klass();
+        } else if (type.equals(methodPointerType)) {
+            return MethodPointerStamp.method();
+        }
+        return super.getWordStamp(type);
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/PointerCastNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/PointerCastNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -25,14 +25,15 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.word.HotSpotOperation.HotspotOpcode;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
- * Cast between Word and metaspace pointers that is introduced by the
- * {@link HotSpotWordTypeRewriterPhase}.
+ * Cast between Word and metaspace pointers exposed by the {@link HotspotOpcode#FROM_POINTER} and
+ * {@link HotspotOpcode#TO_KLASS_POINTER} operations.
  */
 @NodeInfo
 public final class PointerCastNode extends FloatingNode implements LIRLowerable {
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Thu Mar 12 15:59:01 2015 +0100
@@ -26,31 +26,138 @@
 import static com.oracle.graal.api.code.TypeCheckHints.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.bytecode.Bytecodes.*;
-
+import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.bytecode.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
+import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
 import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.LoadIndexedPlugin;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 
 public abstract class AbstractBytecodeParser {
 
-    static class Options {
+    public static class Options {
         // @formatter:off
         @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode", type = OptionType.Debug)
         public static final OptionValue<Integer> TraceBytecodeParserLevel = new OptionValue<>(0);
+
+        @Option(help = "Inlines trivial methods during parsing of the bytecodes.", type = OptionType.Expert)
+        public static final StableOptionValue<Boolean> InlineDuringParsing = new StableOptionValue<>(false);
+
+        @Option(help = "Traces inlining eagerly performed during bytecode parsing", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> TraceInlineDuringParsing = new StableOptionValue<>(false);
+
+        @Option(help = "Traces use of bytecode parser plugins", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> TraceParserPlugins = new StableOptionValue<>(false);
+
+        @Option(help = "Maximum depth when inlining during parsing.", type = OptionType.Debug)
+        public static final StableOptionValue<Integer> InlineDuringParsingMaxDepth = new StableOptionValue<>(10);
+
         // @formatter:on
     }
 
     /**
+     * Information about a substitute method being parsed in lieu of an original method. This can
+     * happen when a call to a {@link MethodSubstitution} is encountered or the root of compilation
+     * is a {@link MethodSubstitution} or a snippet.
+     */
+    static class ReplacementContext {
+        /**
+         * The method being replaced.
+         */
+        final ResolvedJavaMethod method;
+
+        /**
+         * The replacement method.
+         */
+        final ResolvedJavaMethod replacement;
+
+        public ReplacementContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute) {
+            this.method = method;
+            this.replacement = substitute;
+        }
+
+        /**
+         * Determines if a call within the compilation scope of a replacement represents a call to
+         * the original method.
+         */
+        public boolean isCallToOriginal(ResolvedJavaMethod targetMethod) {
+            return method.equals(targetMethod) || replacement.equals(targetMethod);
+        }
+
+        IntrinsicContext asIntrinsic() {
+            return null;
+        }
+    }
+
+    /**
+     * Context for a replacement being inlined as a compiler intrinsic. Deoptimization within a
+     * compiler intrinic must replay the intrinsified call. This context object retains the
+     * information required to build a frame state denoting the JVM state just before the
+     * intrinsified call.
+     */
+    static class IntrinsicContext extends ReplacementContext {
+
+        /**
+         * The arguments to the intrinsified invocation.
+         */
+        private final ValueNode[] invokeArgs;
+
+        /**
+         * The BCI of the intrinsified invocation.
+         */
+        private final int invokeBci;
+
+        private FrameState invokeStateBefore;
+        private FrameState invokeStateDuring;
+
+        public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute, ValueNode[] invokeArgs, int invokeBci) {
+            super(method, substitute);
+            this.invokeArgs = invokeArgs;
+            this.invokeBci = invokeBci;
+        }
+
+        /**
+         * Gets the frame state that will restart the interpreter just before the intrinsified
+         * invocation.
+         */
+        public FrameState getInvokeStateBefore(BytecodeParser parent) {
+            assert !parent.parsingReplacement() || parent.replacementContext instanceof IntrinsicContext;
+            if (invokeStateDuring == null) {
+                assert invokeStateBefore == null;
+                // Find the ancestor calling the replaced method
+                BytecodeParser ancestor = parent;
+                while (ancestor.parsingReplacement()) {
+                    ancestor = ancestor.getParent();
+                }
+                invokeStateDuring = ancestor.getFrameState().create(ancestor.bci(), ancestor.getParent(), true);
+                invokeStateBefore = invokeStateDuring.duplicateModifiedBeforeCall(invokeBci, Kind.Void, invokeArgs);
+            }
+            return invokeStateBefore;
+        }
+
+        public FrameState getInvokeStateDuring() {
+            assert invokeStateDuring != null : "must only be called after getInvokeStateBefore()";
+            return invokeStateDuring;
+        }
+
+        @Override
+        IntrinsicContext asIntrinsic() {
+            return this;
+        }
+    }
+
+    /**
      * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the
      * bytecode instructions as they are parsed.
      */
@@ -73,18 +180,15 @@
     protected final ConstantPool constantPool;
     protected final MetaAccessProvider metaAccess;
 
-    /**
-     * Specifies if the {@linkplain #getMethod() method} being parsed implements the semantics of
-     * another method (i.e., an intrinsic) or bytecode instruction (i.e., a snippet). substitution.
-     */
-    protected final boolean parsingReplacement;
+    protected final ReplacementContext replacementContext;
 
     /**
      * Meters the number of actual bytecodes parsed.
      */
     public static final DebugMetric BytecodesParsed = Debug.metric("BytecodesParsed");
 
-    public AbstractBytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, boolean isReplacement) {
+    public AbstractBytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
+                    ReplacementContext replacementContext) {
         this.graphBuilderConfig = graphBuilderConfig;
         this.optimisticOpts = optimisticOpts;
         this.metaAccess = metaAccess;
@@ -92,7 +196,7 @@
         this.profilingInfo = (graphBuilderConfig.getUseProfiling() ? method.getProfilingInfo() : null);
         this.constantPool = method.getConstantPool();
         this.method = method;
-        this.parsingReplacement = isReplacement;
+        this.replacementContext = replacementContext;
         assert metaAccess != null;
     }
 
@@ -104,7 +208,7 @@
         return stream;
     }
 
-    protected int bci() {
+    public int bci() {
         return stream.currentBCI();
     }
 
@@ -117,11 +221,11 @@
         if (kind == Kind.Object) {
             value = frameState.xpop();
             // astore and astore_<n> may be used to store a returnAddress (jsr)
-            assert parsingReplacement || (value.getKind() == Kind.Object || value.getKind() == Kind.Int) : value + ":" + value.getKind();
+            assert parsingReplacement() || (value.getKind() == Kind.Object || value.getKind() == Kind.Int) : value + ":" + value.getKind();
         } else {
             value = frameState.pop(kind);
         }
-        frameState.storeLocal(index, value);
+        frameState.storeLocal(index, value, kind);
     }
 
     /**
@@ -202,11 +306,28 @@
     protected abstract ValueNode genLoadIndexed(ValueNode index, ValueNode array, Kind kind);
 
     private void genLoadIndexed(Kind kind) {
+
         emitExplicitExceptions(frameState.peek(1), frameState.peek(0));
 
         ValueNode index = frameState.ipop();
         ValueNode array = frameState.apop();
-        frameState.push(kind.getStackKind(), append(genLoadIndexed(array, index, kind)));
+        if (!tryLoadIndexedPlugin(kind, index, array)) {
+            frameState.push(kind.getStackKind(), append(genLoadIndexed(array, index, kind)));
+        }
+    }
+
+    protected abstract void traceWithContext(String format, Object... args);
+
+    protected boolean tryLoadIndexedPlugin(Kind kind, ValueNode index, ValueNode array) {
+        LoadIndexedPlugin loadIndexedPlugin = graphBuilderConfig.getPlugins().getLoadIndexedPlugin();
+        if (loadIndexedPlugin != null && loadIndexedPlugin.apply((GraphBuilderContext) this, array, index, kind)) {
+            if (TraceParserPlugins.getValue()) {
+                traceWithContext("used load indexed plugin");
+            }
+            return true;
+        } else {
+            return false;
+        }
     }
 
     protected abstract ValueNode genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value);
@@ -515,14 +636,14 @@
     protected abstract void genThrow();
 
     protected JavaType lookupType(int cpi, int bytecode) {
-        eagerResolvingForSnippets(cpi, bytecode);
+        maybeEagerlyResolve(cpi, bytecode);
         JavaType result = constantPool.lookupType(cpi, bytecode);
         assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaType;
         return result;
     }
 
     private JavaMethod lookupMethod(int cpi, int opcode) {
-        eagerResolvingForSnippets(cpi, opcode);
+        maybeEagerlyResolve(cpi, opcode);
         JavaMethod result = constantPool.lookupMethod(cpi, opcode);
         /*
          * In general, one cannot assume that the declaring class being initialized is useful, since
@@ -535,27 +656,27 @@
     }
 
     private JavaField lookupField(int cpi, int opcode) {
-        eagerResolvingForSnippets(cpi, opcode);
+        maybeEagerlyResolve(cpi, opcode);
         JavaField result = constantPool.lookupField(cpi, opcode);
         assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result;
         return result;
     }
 
     private Object lookupConstant(int cpi, int opcode) {
-        eagerResolvingForSnippets(cpi, opcode);
+        maybeEagerlyResolve(cpi, opcode);
         Object result = constantPool.lookupConstant(cpi);
         assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result;
         return result;
     }
 
-    private void eagerResolvingForSnippets(int cpi, int bytecode) {
-        if (graphBuilderConfig.eagerResolving()) {
+    private void maybeEagerlyResolve(int cpi, int bytecode) {
+        if (graphBuilderConfig.eagerResolving() || parsingReplacement()) {
             constantPool.loadReferencedType(cpi, bytecode);
         }
     }
 
     private JavaTypeProfile getProfileForTypeCheck(ResolvedJavaType type) {
-        if (parsingReplacement || profilingInfo == null || !optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) {
+        if (parsingReplacement() || profilingInfo == null || !optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) {
             return null;
         } else {
             return profilingInfo.getTypeProfile(bci());
@@ -689,7 +810,7 @@
         Kind kind = field.getKind();
         ValueNode receiver = frameState.apop();
         if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
-            LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getLoadFieldPlugin();
+            LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin();
             if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, receiver, (ResolvedJavaField) field)) {
                 appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field));
             }
@@ -738,7 +859,7 @@
     private void genGetStatic(JavaField field) {
         Kind kind = field.getKind();
         if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
-            LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getLoadFieldPlugin();
+            LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin();
             if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field)) {
                 appendOptimizedLoadField(kind, genLoadField(null, (ResolvedJavaField) field));
             }
@@ -747,6 +868,10 @@
         }
     }
 
+    public boolean tryLoadFieldPlugin(JavaField field, LoadFieldPlugin loadFieldPlugin) {
+        return loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field);
+    }
+
     private void genPutStatic(JavaField field) {
         ValueNode value = frameState.pop(field.getKind().getStackKind());
         if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
@@ -776,7 +901,7 @@
 
     protected abstract void genInvokeSpecial(JavaMethod target);
 
-    protected abstract void genReturn(ValueNode x);
+    protected abstract void genReturn(ValueNode x, Kind kind);
 
     protected abstract ValueNode genMonitorEnter(ValueNode x);
 
@@ -1118,12 +1243,12 @@
         case RET            : genRet(stream.readLocalIndex()); break;
         case TABLESWITCH    : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break;
         case LOOKUPSWITCH   : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break;
-        case IRETURN        : genReturn(frameState.ipop()); break;
-        case LRETURN        : genReturn(frameState.lpop()); break;
-        case FRETURN        : genReturn(frameState.fpop()); break;
-        case DRETURN        : genReturn(frameState.dpop()); break;
-        case ARETURN        : genReturn(frameState.apop()); break;
-        case RETURN         : genReturn(null); break;
+        case IRETURN        : genReturn(frameState.ipop(), Kind.Int); break;
+        case LRETURN        : genReturn(frameState.lpop(), Kind.Long); break;
+        case FRETURN        : genReturn(frameState.fpop(), Kind.Float); break;
+        case DRETURN        : genReturn(frameState.dpop(), Kind.Double); break;
+        case ARETURN        : genReturn(frameState.apop(), Kind.Object); break;
+        case RETURN         : genReturn(null, Kind.Void); break;
         case GETSTATIC      : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break;
         case PUTSTATIC      : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break;
         case GETFIELD       : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break;
@@ -1192,4 +1317,8 @@
         }
         Debug.log("%s", sb);
     }
+
+    public boolean parsingReplacement() {
+        return replacementContext != null;
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java	Thu Mar 12 15:59:01 2015 +0100
@@ -26,6 +26,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
+import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
 
 public abstract class AbstractFrameStateBuilder<T extends KindProvider, S extends AbstractFrameStateBuilder<T, S>> {
 
@@ -35,32 +36,29 @@
     protected final T[] stack;
     protected T[] lockedObjects;
 
-    /**
-     * Specifies if asserting type checks are enabled.
-     */
-    protected final boolean checkTypes;
+    protected final BytecodeParser parser;
 
     /**
      * @see BytecodeFrame#rethrowException
      */
     protected boolean rethrowException;
 
-    public AbstractFrameStateBuilder(ResolvedJavaMethod method, boolean checkTypes) {
+    public AbstractFrameStateBuilder(ResolvedJavaMethod method, BytecodeParser parser) {
         this.method = method;
+        this.parser = parser;
         this.locals = allocateArray(method.getMaxLocals());
         this.stack = allocateArray(Math.max(1, method.getMaxStackSize()));
         this.lockedObjects = allocateArray(0);
-        this.checkTypes = checkTypes;
     }
 
     protected AbstractFrameStateBuilder(S other) {
         this.method = other.method;
+        this.parser = other.parser;
         this.stackSize = other.stackSize;
         this.locals = other.locals.clone();
         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());
@@ -178,11 +176,15 @@
     public T loadLocal(int i) {
         T x = locals[i];
         assert x != null : i;
-        assert !checkTypes || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null);
-        assert !checkTypes || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1);
+        assert parser.parsingReplacement() || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null);
+        assert parser.parsingReplacement() || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1);
         return x;
     }
 
+    public void storeLocal(int i, T x) {
+        storeLocal(i, x, x == null ? null : x.getKind());
+    }
+
     /**
      * Stores a given local variable at the specified index. If the value occupies two slots, then
      * the next local variable index is also overwritten.
@@ -190,18 +192,20 @@
      * @param i the index at which to store
      * @param x the instruction which produces the value for the local
      */
-    public void storeLocal(int i, T x) {
-        assert x == null || !checkTypes || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x;
+    public void storeLocal(int i, T x, Kind kind) {
+        assert x == null || parser.parsingReplacement() || (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
-            locals[i + 1] = null;
-        }
-        if (x != null && i > 0) {
-            T p = locals[i - 1];
-            if (p != null && p.getKind().needsTwoSlots()) {
-                // if there was a double word at i - 1, then kill it
-                locals[i - 1] = null;
+        if (x != null) {
+            if (kind.needsTwoSlots() && !parser.parsingReplacement()) {
+                // if this is a double word, then kill i+1
+                locals[i + 1] = null;
+            }
+            if (i > 0 && !parser.parsingReplacement()) {
+                T p = locals[i - 1];
+                if (p != null && p.getKind().needsTwoSlots()) {
+                    // if there was a double word at i - 1, then kill it
+                    locals[i - 1] = null;
+                }
             }
         }
     }
@@ -218,7 +222,7 @@
      * @param x the instruction to push onto the stack
      */
     public void push(Kind kind, T x) {
-        assert !checkTypes || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : x;
+        assert kind != Kind.Void && kind != Kind.Illegal : kind + ":" + x;
         xpush(assertKind(kind, x));
         if (kind.needsTwoSlots()) {
             xpush(null);
@@ -231,7 +235,7 @@
      * @param x the instruction to push onto the stack
      */
     public void xpush(T x) {
-        assert !checkTypes || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal));
+        assert parser.parsingReplacement() || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal));
         stack[stackSize++] = x;
     }
 
@@ -375,7 +379,7 @@
                 newStackSize--;
                 assert stack[newStackSize].getKind().needsTwoSlots();
             } else {
-                assert !checkTypes || (stack[newStackSize].getKind().getSlotCount() == 1);
+                assert parser.parsingReplacement() || (stack[newStackSize].getKind().getSlotCount() == 1);
             }
             result[i] = stack[newStackSize];
         }
@@ -411,7 +415,7 @@
     }
 
     private T assertKind(Kind kind, T x) {
-        assert x != null && (!checkTypes || x.getKind() == kind) : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.getKind());
+        assert x != null && (parser.parsingReplacement() || x.getKind() == kind) : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.getKind());
         return x;
     }
 
@@ -431,7 +435,7 @@
     }
 
     private T assertObject(T x) {
-        assert x != null && (!checkTypes || (x.getKind() == Kind.Object));
+        assert x != null && (parser.parsingReplacement() || (x.getKind() == Kind.Object));
         return x;
     }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Thu Mar 12 15:59:01 2015 +0100
@@ -26,14 +26,99 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.java.GraphBuilderPlugin.AnnotatedInvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.GenericInvocationPlugin;
 import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin;
 import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.LoadIndexedPlugin;
 import com.oracle.graal.java.GraphBuilderPlugin.LoopExplosionPlugin;
 import com.oracle.graal.java.GraphBuilderPlugin.ParameterPlugin;
 import com.oracle.graal.nodes.*;
 
 public class GraphBuilderConfiguration {
+
+    public static class Plugins {
+        private InvocationPlugins invocationPlugins;
+        private LoadFieldPlugin loadFieldPlugin;
+        private LoadIndexedPlugin loadIndexedPlugin;
+        private ParameterPlugin parameterPlugin;
+        private InlineInvokePlugin inlineInvokePlugin;
+        private GenericInvocationPlugin genericInvocationPlugin;
+        private LoopExplosionPlugin loopExplosionPlugin;
+
+        public Plugins() {
+            invocationPlugins = new InvocationPlugins();
+        }
+
+        public Plugins(InvocationPlugins invocationPlugins) {
+            this.invocationPlugins = invocationPlugins;
+        }
+
+        public InvocationPlugins getInvocationPlugins() {
+            return invocationPlugins;
+        }
+
+        public GenericInvocationPlugin getGenericInvocationPlugin() {
+            return genericInvocationPlugin;
+        }
+
+        public void setGenericInvocationPlugin(GenericInvocationPlugin plugin) {
+            this.genericInvocationPlugin = plugin;
+        }
+
+        public LoadFieldPlugin getLoadFieldPlugin() {
+            return loadFieldPlugin;
+        }
+
+        public void setLoadFieldPlugin(LoadFieldPlugin plugin) {
+            this.loadFieldPlugin = plugin;
+        }
+
+        public LoadIndexedPlugin getLoadIndexedPlugin() {
+            return loadIndexedPlugin;
+        }
+
+        public void setLoadIndexedPlugin(LoadIndexedPlugin plugin) {
+            this.loadIndexedPlugin = plugin;
+        }
+
+        public ParameterPlugin getParameterPlugin() {
+            return parameterPlugin;
+        }
+
+        public void setParameterPlugin(ParameterPlugin plugin) {
+            this.parameterPlugin = plugin;
+        }
+
+        public InlineInvokePlugin getInlineInvokePlugin() {
+            return inlineInvokePlugin;
+        }
+
+        public void setInlineInvokePlugin(InlineInvokePlugin plugin) {
+            this.inlineInvokePlugin = plugin;
+        }
+
+        public LoopExplosionPlugin getLoopExplosionPlugin() {
+            return loopExplosionPlugin;
+        }
+
+        public void setLoopExplosionPlugin(LoopExplosionPlugin plugin) {
+            this.loopExplosionPlugin = plugin;
+        }
+
+        public Plugins updateFrom(Plugins other, boolean includeInvocationPlugins) {
+            if (includeInvocationPlugins) {
+                this.invocationPlugins.updateFrom(other.getInvocationPlugins());
+            }
+            this.parameterPlugin = other.parameterPlugin;
+            this.loadFieldPlugin = other.loadFieldPlugin;
+            this.loadIndexedPlugin = other.loadIndexedPlugin;
+            this.inlineInvokePlugin = other.inlineInvokePlugin;
+            this.loopExplosionPlugin = other.loopExplosionPlugin;
+            this.genericInvocationPlugin = other.genericInvocationPlugin;
+            return this;
+        }
+    }
+
     private static final ResolvedJavaType[] EMPTY = new ResolvedJavaType[]{};
 
     private final boolean eagerResolving;
@@ -41,13 +126,8 @@
     private final ResolvedJavaType[] skippedExceptionTypes;
     private final DebugInfoMode debugInfoMode;
     private final boolean doLivenessAnalysis;
-    private InvocationPlugins invocationPlugins = new InvocationPlugins();
-    private LoadFieldPlugin loadFieldPlugin;
-    private ParameterPlugin parameterPlugin;
-    private InlineInvokePlugin inlineInvokePlugin;
-    private AnnotatedInvocationPlugin annotatedInvocationPlugin;
-    private LoopExplosionPlugin loopExplosionPlugin;
     private boolean useProfiling;
+    private Plugins plugins = new Plugins();
 
     public static enum DebugInfoMode {
         SafePointsOnly,
@@ -114,26 +194,6 @@
         return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, newLivenessAnalysis);
     }
 
-    public InvocationPlugins getInvocationPlugins() {
-        return invocationPlugins;
-    }
-
-    public AnnotatedInvocationPlugin getAnnotatedInvocationPlugin() {
-        return annotatedInvocationPlugin;
-    }
-
-    public void setAnnotatedInvocationPlugin(AnnotatedInvocationPlugin plugin) {
-        this.annotatedInvocationPlugin = plugin;
-    }
-
-    public LoadFieldPlugin getLoadFieldPlugin() {
-        return loadFieldPlugin;
-    }
-
-    public void setLoadFieldPlugin(LoadFieldPlugin plugin) {
-        this.loadFieldPlugin = plugin;
-    }
-
     public ResolvedJavaType[] getSkippedExceptionTypes() {
         return skippedExceptionTypes;
     }
@@ -183,37 +243,16 @@
         return eagerResolving;
     }
 
-    public ParameterPlugin getParameterPlugin() {
-        return parameterPlugin;
-    }
-
-    public void setParameterPlugin(ParameterPlugin plugin) {
-        this.parameterPlugin = plugin;
+    public Plugins getPlugins() {
+        return plugins;
     }
 
-    public InlineInvokePlugin getInlineInvokePlugin() {
-        return inlineInvokePlugin;
-    }
-
-    public void setInlineInvokePlugin(InlineInvokePlugin plugin) {
-        this.inlineInvokePlugin = plugin;
-    }
-
-    public LoopExplosionPlugin getLoopExplosionPlugin() {
-        return loopExplosionPlugin;
-    }
-
-    public void setLoopExplosionPlugin(LoopExplosionPlugin plugin) {
-        this.loopExplosionPlugin = plugin;
+    public void setPlugins(Plugins plugins) {
+        this.plugins = plugins;
     }
 
     public GraphBuilderConfiguration copyPluginsFrom(GraphBuilderConfiguration other) {
-        this.invocationPlugins.updateFrom(other.getInvocationPlugins());
-        this.parameterPlugin = other.parameterPlugin;
-        this.loadFieldPlugin = other.loadFieldPlugin;
-        this.inlineInvokePlugin = other.inlineInvokePlugin;
-        this.loopExplosionPlugin = other.loopExplosionPlugin;
-        this.annotatedInvocationPlugin = other.annotatedInvocationPlugin;
+        this.plugins.updateFrom(other.plugins, true);
         return this;
     }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Thu Mar 12 15:59:01 2015 +0100
@@ -27,7 +27,6 @@
 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.*;
 
 /**
@@ -60,7 +59,33 @@
     StructuredGraph getGraph();
 
     /**
-     * Determines if the graph builder is parsing a snippet or method substitution.
+     * Gets the parsing context for the method that inlines the method being parsed by this context.
+     */
+    GraphBuilderContext getParent();
+
+    /**
+     * Gets the root method for the graph building process.
+     */
+    ResolvedJavaMethod getRootMethod();
+
+    /**
+     * Gets the method currently being parsed.
+     */
+    ResolvedJavaMethod getMethod();
+
+    /**
+     * Gets the index of the bytecode instruction currently being parsed.
+     */
+    int bci();
+
+    /**
+     * Gets the inline depth of this context. 0 implies this is the context for the
+     * {@linkplain #getRootMethod() root method}.
+     */
+    int getDepth();
+
+    /**
+     * Determines if the current parsing context is a snippet or method substitution.
      */
     boolean parsingReplacement();
 
@@ -75,7 +100,7 @@
         return nonNullValue;
     }
 
-    GuardingNode getCurrentBlockGuard();
+    boolean eagerResolving();
 
     BailoutException bailout(String string);
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Mar 12 15:59:01 2015 +0100
@@ -27,6 +27,7 @@
 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.java.AbstractBytecodeParser.Options.*;
 import static com.oracle.graal.nodes.StructuredGraph.*;
 import static java.lang.String.*;
 
@@ -40,17 +41,20 @@
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ValueNumberable;
 import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.java.AbstractBytecodeParser.ReplacementContext;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock;
-import com.oracle.graal.java.GraphBuilderPlugin.AnnotatedInvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.GenericInvocationPlugin;
 import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin.InlineInfo;
 import com.oracle.graal.java.GraphBuilderPlugin.InvocationPlugin;
 import com.oracle.graal.java.GraphBuilderPlugin.LoopExplosionPlugin;
+import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.calc.*;
@@ -75,14 +79,15 @@
 
     @Override
     protected void run(StructuredGraph graph, HighTierContext context) {
-        new Instance(context.getMetaAccess(), context.getStampProvider(), null, context.getConstantReflection(), graphBuilderConfig, context.getOptimisticOptimizations()).run(graph);
+        new Instance(context.getMetaAccess(), context.getStampProvider(), null, context.getConstantReflection(), graphBuilderConfig, context.getOptimisticOptimizations(), null).run(graph);
     }
 
     public GraphBuilderConfiguration getGraphBuilderConfig() {
         return graphBuilderConfig;
     }
 
-    public static class Instance extends Phase {
+    // Fully qualified name is a workaround for JDK-8056066
+    public static class Instance extends com.oracle.graal.phases.Phase {
 
         protected StructuredGraph currentGraph;
 
@@ -90,33 +95,34 @@
 
         private ResolvedJavaMethod rootMethod;
 
+        /**
+         * If not null, then this indicates {@link #rootMethod} is a replacement or a snippet.
+         * Furthermore, if it is non-null and not equal to {@link #rootMethod} then this is the
+         * original method for which a snippet exists (e.g., System.arraycopy()).
+         */
+        private final ResolvedJavaMethod rootMethodIsReplacement;
+
         private final GraphBuilderConfiguration graphBuilderConfig;
         private final OptimisticOptimizations optimisticOpts;
         private final StampProvider stampProvider;
         private final ConstantReflectionProvider constantReflection;
         private final SnippetReflectionProvider snippetReflectionProvider;
 
-        /**
-         * Gets the graph being processed by this builder.
-         */
-        protected StructuredGraph getGraph() {
-            return currentGraph;
-        }
-
         public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflection,
-                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
+                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod rootMethodIsReplacement) {
             this.graphBuilderConfig = graphBuilderConfig;
             this.optimisticOpts = optimisticOpts;
             this.metaAccess = metaAccess;
             this.stampProvider = stampProvider;
             this.constantReflection = constantReflection;
             this.snippetReflectionProvider = snippetReflectionProvider;
+            this.rootMethodIsReplacement = rootMethodIsReplacement;
             assert metaAccess != null;
         }
 
         public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig,
-                        OptimisticOptimizations optimisticOpts) {
-            this(metaAccess, stampProvider, null, constantReflection, graphBuilderConfig, optimisticOpts);
+                        OptimisticOptimizations optimisticOpts, ResolvedJavaMethod rootMethodIsReplacement) {
+            this(metaAccess, stampProvider, null, constantReflection, graphBuilderConfig, optimisticOpts, rootMethodIsReplacement);
         }
 
         @Override
@@ -126,12 +132,13 @@
             int entryBCI = graph.getEntryBCI();
             assert method.getCode() != null : "method must contain bytecodes: " + method;
             this.currentGraph = graph;
-            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 {
-                BytecodeParser parser = new BytecodeParser(metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI, false);
-                parser.build(0, graph.start(), frameState);
+                ReplacementContext replacementContext = rootMethodIsReplacement != null ? new ReplacementContext(rootMethodIsReplacement, rootMethod) : null;
+                BytecodeParser parser = new BytecodeParser(null, metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI, replacementContext);
+                HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(parser, method, graph);
+                frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || rootMethodIsReplacement != null, graphBuilderConfig.getPlugins().getParameterPlugin());
+                parser.build(graph.start(), frameState);
 
                 parser.connectLoopEndToBegin();
 
@@ -144,11 +151,15 @@
                 }
 
                 // Remove redundant begin nodes.
+                Debug.dump(graph, "Before removing redundant begins");
                 for (BeginNode beginNode : currentGraph.getNodes(BeginNode.TYPE)) {
                     Node predecessor = beginNode.predecessor();
                     if (predecessor instanceof ControlSplitNode) {
                         // The begin node is necessary.
                     } else {
+                        if (beginNode.hasUsages()) {
+                            reanchorGuardedNodes(beginNode);
+                        }
                         GraphUtil.unlinkFixedNode(beginNode);
                         beginNode.safeDelete();
                     }
@@ -160,6 +171,36 @@
             ComputeLoopFrequenciesClosure.compute(graph);
         }
 
+        /**
+         * Removes {@link GuardedNode}s from {@code beginNode}'s usages and re-attaches them to an
+         * appropriate preceeding {@link GuardingNode}.
+         */
+        protected void reanchorGuardedNodes(BeginNode beginNode) {
+            // Find the new guarding node
+            GuardingNode guarding = null;
+            Node pred = beginNode.predecessor();
+            while (pred != null) {
+                if (pred instanceof BeginNode) {
+                    if (pred.predecessor() instanceof ControlSplitNode) {
+                        guarding = (GuardingNode) pred;
+                        break;
+                    }
+                } else if (pred.getNodeClass().getAllowedUsageTypes().contains(InputType.Guard)) {
+                    guarding = (GuardingNode) pred;
+                    break;
+                }
+                pred = pred.predecessor();
+            }
+
+            // Reset the guard for all of beginNode's usages
+            for (Node usage : beginNode.usages().snapshot()) {
+                GuardedNode guarded = (GuardedNode) usage;
+                assert guarded.getGuard() == beginNode;
+                guarded.setGuard(guarding);
+            }
+            assert beginNode.hasNoUsages() : beginNode;
+        }
+
         @Override
         protected String getDetailedName() {
             return getName() + " " + rootMethod.format("%H.%n(%p):%r");
@@ -182,12 +223,24 @@
             private int peelIteration;
         }
 
+        @SuppressWarnings("serial")
+        public class BytecodeParserError extends GraalInternalError {
+
+            public BytecodeParserError(Throwable cause) {
+                super(cause);
+            }
+
+            public BytecodeParserError(String msg, Object... args) {
+                super(msg, args);
+            }
+        }
+
         public class BytecodeParser extends AbstractBytecodeParser implements GraphBuilderContext {
 
             private BciBlockMapping blockMap;
             private LocalLiveness liveness;
             protected final int entryBCI;
-            private int currentDepth;
+            private final BytecodeParser parent;
 
             private LineNumberTable lnt;
             private int previousLineNumber;
@@ -213,22 +266,18 @@
             private FixedWithNextNode[][] firstInstructionMatrix;
             private HIRFrameStateBuilder[][] entryStateMatrix;
 
-            /**
-             * @param isReplacement specifies if this object is being used to parse a method that
-             *            implements the semantics of another method (i.e., an intrinsic) or
-             *            bytecode instruction (i.e., a snippet)
-             */
-            public BytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, int entryBCI,
-                            boolean isReplacement) {
-                super(metaAccess, method, graphBuilderConfig, optimisticOpts, isReplacement);
+            public BytecodeParser(BytecodeParser parent, MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig,
+                            OptimisticOptimizations optimisticOpts, int entryBCI, ReplacementContext replacementContext) {
+                super(metaAccess, method, graphBuilderConfig, optimisticOpts, replacementContext);
                 this.entryBCI = entryBCI;
+                this.parent = parent;
 
                 if (graphBuilderConfig.insertNonSafepointDebugInfo()) {
                     lnt = method.getLineNumberTable();
                     previousLineNumber = -1;
                 }
 
-                LoopExplosionPlugin loopExplosionPlugin = graphBuilderConfig.getLoopExplosionPlugin();
+                LoopExplosionPlugin loopExplosionPlugin = graphBuilderConfig.getPlugins().getLoopExplosionPlugin();
                 if (loopExplosionPlugin != null) {
                     explodeLoops = loopExplosionPlugin.shouldExplodeLoops(method);
                     if (explodeLoops) {
@@ -261,8 +310,7 @@
                 return this.beforeUnwindNode;
             }
 
-            protected void build(int depth, FixedWithNextNode startInstruction, HIRFrameStateBuilder startFrameState) {
-                this.currentDepth = depth;
+            protected void build(FixedWithNextNode startInstruction, HIRFrameStateBuilder startFrameState) {
                 if (PrintProfilingInformation.getValue() && profilingInfo != null) {
                     TTY.println("Profiling info for " + method.format("%H.%n(%p)"));
                     TTY.println(MetaUtil.indent(profilingInfo.toString(method, CodeUtil.NEW_LINE), "  "));
@@ -526,7 +574,6 @@
                 if (Debug.isDumpEnabled() && DumpDuringGraphBuilding.getValue()) {
                     Debug.dump(currentGraph, "before loop explosion dimension " + context.peelIteration);
                 }
-
                 peelIteration(blocks, header, context);
                 explodeLoopsContext.pop();
                 return header.loopEnd + 1;
@@ -538,6 +585,9 @@
 
             private void peelIteration(BciBlock[] blocks, BciBlock header, ExplodedLoopContext context) {
                 while (true) {
+                    if (TraceParserPlugins.getValue()) {
+                        traceWithContext("exploding loop, iteration %d", context.peelIteration);
+                    }
                     processBlock(this, header);
                     int j = header.getId() + 1;
                     while (j <= header.loopEnd) {
@@ -1047,7 +1097,7 @@
                 }
 
                 JavaType returnType = targetMethod.getSignature().getReturnType(method.getDeclaringClass());
-                if (graphBuilderConfig.eagerResolving()) {
+                if (graphBuilderConfig.eagerResolving() || parsingReplacement()) {
                     returnType = returnType.resolve(targetMethod.getDeclaringClass());
                 }
                 if (invokeKind.hasReceiver()) {
@@ -1058,16 +1108,16 @@
                     }
                 }
 
-                if (tryInvocationPlugin(args, targetMethod, resultType)) {
-                    if (GraalOptions.TraceInlineDuringParsing.getValue()) {
-                        TTY.println(format("%sUsed invocation plugin for %s", nSpaces(currentDepth), targetMethod));
+                if (tryGenericInvocationPlugin(args, targetMethod)) {
+                    if (TraceParserPlugins.getValue()) {
+                        traceWithContext("used generic invocation plugin for %s", targetMethod.format("%h.%n(%p)"));
                     }
                     return;
                 }
 
-                if (tryAnnotatedInvocationPlugin(args, targetMethod)) {
-                    if (GraalOptions.TraceInlineDuringParsing.getValue()) {
-                        TTY.println(format("%sUsed annotated invocation plugin for %s", nSpaces(currentDepth), targetMethod));
+                if (tryInvocationPlugin(args, targetMethod, resultType)) {
+                    if (TraceParserPlugins.getValue()) {
+                        traceWithContext("used invocation plugin for %s", targetMethod.format("%h.%n(%p)"));
                     }
                     return;
                 }
@@ -1080,27 +1130,37 @@
 
                 // be conservative if information was not recorded (could result in endless
                 // recompiles otherwise)
+                Invoke invoke;
                 if (graphBuilderConfig.omitAllExceptionEdges() || (optimisticOpts.useExceptionProbability() && profilingInfo != null && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE)) {
-                    createInvoke(callTarget, resultType);
+                    invoke = createInvoke(callTarget, resultType);
                 } else {
-                    InvokeWithExceptionNode invoke = createInvokeWithException(callTarget, resultType);
+                    invoke = createInvokeWithException(callTarget, resultType);
                     AbstractBeginNode beginNode = currentGraph.add(new KillingBeginNode(LocationIdentity.ANY_LOCATION));
                     invoke.setNext(beginNode);
                     lastInstr = beginNode;
                 }
+
+                InlineInvokePlugin plugin = graphBuilderConfig.getPlugins().getInlineInvokePlugin();
+                if (plugin != null) {
+                    if (TraceParserPlugins.getValue()) {
+                        traceWithContext("did not inline %s", targetMethod.format("%h.%n(%p)"));
+                    }
+                    plugin.notifyOfNoninlinedInvoke(this, targetMethod, invoke);
+                }
             }
 
             private boolean tryInvocationPlugin(ValueNode[] args, ResolvedJavaMethod targetMethod, Kind resultType) {
-                InvocationPlugin plugin = graphBuilderConfig.getInvocationPlugins().lookupInvocation(targetMethod);
+                InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod);
                 if (plugin != null) {
                     int beforeStackSize = frameState.stackSize;
                     boolean needsNullCheck = !targetMethod.isStatic() && args[0].getKind() == Kind.Object && !StampTool.isPointerNonNull(args[0].stamp());
                     int nodeCount = currentGraph.getNodeCount();
                     Mark mark = needsNullCheck ? currentGraph.getMark() : null;
-                    if (InvocationPlugin.execute(this, plugin, args)) {
+                    if (InvocationPlugin.execute(this, targetMethod, plugin, args)) {
                         assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize : "plugin manipulated the stack incorrectly " + targetMethod;
-                        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];
+                        assert !needsNullCheck || args[0].usages().filter(isNotA(FrameState.class)).isEmpty() || containsNullCheckOf(currentGraph.getNewNodes(mark), args[0]) : format(
+                                        "plugin needs to null check the receiver of %s: receiver=%s%n\tplugin at %s", targetMethod.format("%H.%n(%p)"), args[0],
+                                        plugin.getApplySourceLocation(metaAccess));
                         return true;
                     }
                     assert nodeCount == currentGraph.getNodeCount() : "plugin that returns false must not create new nodes";
@@ -1109,8 +1169,8 @@
                 return false;
             }
 
-            private boolean tryAnnotatedInvocationPlugin(ValueNode[] args, ResolvedJavaMethod targetMethod) {
-                AnnotatedInvocationPlugin plugin = graphBuilderConfig.getAnnotatedInvocationPlugin();
+            private boolean tryGenericInvocationPlugin(ValueNode[] args, ResolvedJavaMethod targetMethod) {
+                GenericInvocationPlugin plugin = graphBuilderConfig.getPlugins().getGenericInvocationPlugin();
                 return plugin != null && plugin.apply(this, targetMethod, args);
             }
 
@@ -1127,49 +1187,97 @@
             }
 
             private boolean tryInline(ValueNode[] args, ResolvedJavaMethod targetMethod, InvokeKind invokeKind, JavaType returnType) {
-                InlineInvokePlugin plugin = graphBuilderConfig.getInlineInvokePlugin();
+                InlineInvokePlugin plugin = graphBuilderConfig.getPlugins().getInlineInvokePlugin();
                 if (plugin == null || !invokeKind.isDirect() || !targetMethod.canBeInlined()) {
                     return false;
                 }
-                ResolvedJavaMethod inlinedMethod = plugin.getInlinedMethod(this, targetMethod, args, returnType, currentDepth);
-                if (inlinedMethod != null && inlinedMethod.hasBytecodes()) {
-                    if (TraceInlineDuringParsing.getValue()) {
-                        int bci = this.bci();
-                        StackTraceElement ste = this.method.asStackTraceElement(bci);
-                        TTY.println(format("%s%s (%s:%d) inlining call to %s", nSpaces(currentDepth), method.getName(), ste.getFileName(), ste.getLineNumber(), inlinedMethod.format("%h.%n(%p)")));
-                    }
-                    parseAndInlineCallee(inlinedMethod, args, parsingReplacement || !inlinedMethod.equals(targetMethod));
-                    plugin.postInline(inlinedMethod);
-                    return true;
+                InlineInfo inlineInfo = plugin.getInlineInfo(this, targetMethod, args, returnType);
+                if (inlineInfo != null) {
+                    return inline(plugin, targetMethod, inlineInfo, args);
                 }
-
                 return false;
             }
 
-            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];
-
-                // 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;
+            boolean inline(InlineInvokePlugin plugin, ResolvedJavaMethod targetMethod, InlineInfo inlineInfo, ValueNode[] args) {
+                int bci = bci();
+                ResolvedJavaMethod inlinedMethod = inlineInfo.methodToInline;
+                if (TraceInlineDuringParsing.getValue() || TraceParserPlugins.getValue()) {
+                    if (targetMethod.equals(inlinedMethod)) {
+                        traceWithContext("inlining call to %s", inlinedMethod.format("%h.%n(%p)"));
+                    } else {
+                        traceWithContext("inlining call to %s as replacement for %s", inlinedMethod.format("%h.%n(%p)"), targetMethod.format("%h.%n(%p)"));
+                    }
+                }
+                ReplacementContext context = this.replacementContext;
+                if (context != null && context.isCallToOriginal(targetMethod)) {
+                    // Self recursive replacement means the original
+                    // method should be called.
+                    if (targetMethod.hasBytecodes()) {
+                        parseAndInlineCallee(context.method, args, null);
+                    } else {
+                        return false;
+                    }
+                } else {
+                    if (context == null && !inlinedMethod.equals(targetMethod)) {
+                        if (inlineInfo.adoptBeforeCallFrameState) {
+                            context = new IntrinsicContext(targetMethod, inlinedMethod, args, bci);
+                        } else {
+                            context = new ReplacementContext(targetMethod, inlinedMethod);
+                        }
+                    }
+                    parseAndInlineCallee(inlinedMethod, args, context);
+                    if (plugin != null) {
+                        plugin.postInline(inlinedMethod);
+                    }
+                }
+                return true;
+            }
 
-                HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(targetMethod, currentGraph, checkTypes, () -> {
-                    if (lazyFrameState[0] == null) {
-                        lazyFrameState[0] = createFrameState(bci());
-                    }
-                    return lazyFrameState[0];
-                });
+            /**
+             * Prints a line to {@link TTY} with a prefix indicating the current parse context. The
+             * prefix is of the form:
+             *
+             * <pre>
+             * {SPACE * n} {name of method being parsed} "(" {file name} ":" {line number} ")"
+             * </pre>
+             *
+             * where {@code n} is the current inlining depth.
+             *
+             * @param format a format string
+             * @param args arguments to the format string
+             */
+            @Override
+            protected void traceWithContext(String format, Object... args) {
+                StackTraceElement where = method.asStackTraceElement(bci());
+                TTY.println(format("%s%s (%s:%d) %s", nSpaces(getDepth()), method.isConstructor() ? method.format("%h.%n") : method.getName(), where.getFileName(), where.getLineNumber(),
+                                format(format, args)));
+            }
+
+            protected BytecodeParserError asParserError(Throwable e) {
+                if (e instanceof BytecodeParserError) {
+                    return (BytecodeParserError) e;
+                }
+                BytecodeParser bp = this;
+                BytecodeParserError res = new BytecodeParserError(e);
+                while (bp != null) {
+                    res.addContext("parsing " + bp.method.asStackTraceElement(bp.bci()));
+                    bp = bp.parent;
+                }
+                return res;
+            }
+
+            private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, ReplacementContext calleeReplacementContext) {
+                BytecodeParser parser = new BytecodeParser(this, metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, calleeReplacementContext);
+                HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(parser, targetMethod, currentGraph);
                 startFrameState.initializeFromArgumentsArray(args);
-                parser.build(currentDepth + 1, this.lastInstr, startFrameState);
+                parser.build(this.lastInstr, startFrameState);
 
                 FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode();
                 this.lastInstr = calleeBeforeReturnNode;
                 if (calleeBeforeReturnNode != null) {
                     ValueNode calleeReturnValue = parser.getReturnValue();
                     if (calleeReturnValue != null) {
-                        frameState.push(calleeReturnValue.getKind().getStackKind(), calleeReturnValue);
+                        frameState.push(targetMethod.getSignature().getReturnKind().getStackKind(), calleeReturnValue);
                     }
                 }
 
@@ -1205,25 +1313,25 @@
             }
 
             @Override
-            protected void genReturn(ValueNode x) {
+            protected void genReturn(ValueNode returnVal, Kind returnKind) {
 
-                if (this.currentDepth == 0) {
+                if (parent == null) {
                     frameState.setRethrowException(false);
                     frameState.clearStack();
-                    beforeReturn(x);
-                    append(new ReturnNode(x));
+                    beforeReturn(returnVal, returnKind);
+                    append(new ReturnNode(returnVal));
                 } else {
                     if (blockMap.getReturnCount() == 1 || !controlFlowSplit) {
                         // There is only a single return.
-                        beforeReturn(x);
-                        this.returnValue = x;
+                        beforeReturn(returnVal, returnKind);
+                        this.returnValue = returnVal;
                         this.beforeReturnNode = this.lastInstr;
                         this.lastInstr = null;
                     } else {
                         frameState.setRethrowException(false);
                         frameState.clearStack();
-                        if (x != null) {
-                            frameState.push(x.getKind(), x);
+                        if (returnVal != null) {
+                            frameState.push(returnKind, returnVal);
                         }
                         assert blockMap.getReturnCount() > 1;
                         appendGoto(blockMap.getReturnBlock());
@@ -1231,12 +1339,12 @@
                 }
             }
 
-            private void beforeReturn(ValueNode x) {
+            private void beforeReturn(ValueNode x, Kind kind) {
                 if (graphBuilderConfig.insertNonSafepointDebugInfo()) {
                     append(createInfoPointNode(InfopointReason.METHOD_END));
                 }
 
-                synchronizedEpilogue(BytecodeFrame.AFTER_BCI, x);
+                synchronizedEpilogue(BytecodeFrame.AFTER_BCI, x, kind);
                 if (frameState.lockDepth() != 0) {
                     throw bailout("unbalanced monitors");
                 }
@@ -1587,7 +1695,11 @@
                      * the loop begin node created before.
                      */
                     LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(block, operatingDimension);
-                    Target target = checkLoopExit(currentGraph.add(new LoopEndNode(loopBegin)), block, state);
+                    LoopEndNode loopEnd = currentGraph.add(new LoopEndNode(loopBegin));
+                    if (parsingReplacement()) {
+                        loopEnd.disableSafepoint();
+                    }
+                    Target target = checkLoopExit(loopEnd, block, state);
                     FixedNode result = target.fixed;
                     getEntryState(block, operatingDimension).merge(loopBegin, target.state);
 
@@ -1672,7 +1784,7 @@
                         }
                         context.targetPeelIteration[context.targetPeelIteration.length - 1] = nextPeelIteration++;
                         if (nextPeelIteration > MaximumLoopExplosionCount.getValue()) {
-                            String message = "too many loop explosion interations - does the explosion not terminate for method " + method + "?";
+                            String message = "too many loop explosion iterations - does the explosion not terminate for method " + method + "?";
                             if (FailedLoopExplosionIsFatal.getValue()) {
                                 throw new RuntimeException(message);
                             } else {
@@ -1746,7 +1858,7 @@
             }
 
             private void handleUnwindBlock() {
-                if (currentDepth == 0) {
+                if (parent == null) {
                     frameState.setRethrowException(false);
                     createUnwind();
                 } else {
@@ -1760,7 +1872,7 @@
                 Kind returnKind = method.getSignature().getReturnKind().getStackKind();
                 ValueNode x = returnKind == Kind.Void ? null : frameState.pop(returnKind);
                 assert frameState.stackSize() == 0;
-                beforeReturn(x);
+                beforeReturn(x, returnKind);
                 this.returnValue = x;
                 this.beforeReturnNode = this.lastInstr;
             }
@@ -1803,15 +1915,15 @@
             private void createUnwind() {
                 assert frameState.stackSize() == 1 : frameState;
                 ValueNode exception = frameState.apop();
-                synchronizedEpilogue(BytecodeFrame.AFTER_EXCEPTION_BCI, null);
+                synchronizedEpilogue(BytecodeFrame.AFTER_EXCEPTION_BCI, null, null);
                 append(new UnwindNode(exception));
             }
 
-            private void synchronizedEpilogue(int bci, ValueNode currentReturnValue) {
+            private void synchronizedEpilogue(int bci, ValueNode currentReturnValue, Kind currentReturnValueKind) {
                 if (method.isSynchronized()) {
                     MonitorExitNode monitorExit = genMonitorExit(methodSynchronizedObject, currentReturnValue);
                     if (currentReturnValue != null) {
-                        frameState.push(currentReturnValue.getKind(), currentReturnValue);
+                        frameState.push(currentReturnValueKind, currentReturnValue);
                     }
                     monitorExit.setStateAfter(createFrameState(bci));
                     assert !frameState.rethrowException();
@@ -1926,7 +2038,7 @@
                     int opcode = stream.currentBC();
                     assert traceState();
                     assert traceInstruction(bci, opcode, bci == block.startBci);
-                    if (currentDepth == 0 && bci == entryBCI) {
+                    if (parent == null && bci == entryBCI) {
                         if (block.getJsrScope() != JsrScope.EMPTY_SCOPE) {
                             throw new BailoutException("OSR into a JSR scope is not supported");
                         }
@@ -1934,7 +2046,12 @@
                         frameState.insertProxies(x);
                         x.setStateAfter(createFrameState(bci));
                     }
-                    processBytecode(bci, opcode);
+
+                    try {
+                        processBytecode(bci, opcode);
+                    } catch (Throwable e) {
+                        throw asParserError(e);
+                    }
 
                     if (lastInstr == null || isBlockEnd(lastInstr) || lastInstr.next() != null) {
                         break;
@@ -2092,6 +2209,13 @@
                     FixedNode falseSuccessor = createTarget(falseBlock, frameState, false, true);
                     ValueNode ifNode = genIfNode(condition, trueSuccessor, falseSuccessor, probability);
                     append(ifNode);
+                    if (parsingReplacement()) {
+                        if (x instanceof BranchProbabilityNode) {
+                            ((BranchProbabilityNode) x).simplify(null);
+                        } else if (y instanceof BranchProbabilityNode) {
+                            ((BranchProbabilityNode) y).simplify(null);
+                        }
+                    }
                 }
             }
 
@@ -2099,7 +2223,7 @@
                 if (gotoOrFallThroughAfterConstant(trueBlock) && gotoOrFallThroughAfterConstant(falseBlock) && trueBlock.getSuccessor(0) == falseBlock.getSuccessor(0)) {
                     genConditionalForIf(trueBlock, condition, oldBci, trueBlockInt, falseBlockInt, false);
                     return true;
-                } else if (this.currentDepth != 0 && returnAfterConstant(trueBlock) && returnAfterConstant(falseBlock)) {
+                } else if (this.parent != null && returnAfterConstant(trueBlock) && returnAfterConstant(falseBlock)) {
                     genConditionalForIf(trueBlock, condition, oldBci, trueBlockInt, falseBlockInt, true);
                     return true;
                 }
@@ -2114,7 +2238,8 @@
                     conditionalNode = currentGraph.addOrUnique(conditionalNode);
                 }
                 if (genReturn) {
-                    this.genReturn(conditionalNode);
+                    Kind returnKind = method.getSignature().getReturnKind().getStackKind();
+                    this.genReturn(conditionalNode, returnKind);
                 } else {
                     frameState.push(Kind.Int, conditionalNode);
                     appendGoto(trueBlock.getSuccessor(0));
@@ -2210,21 +2335,43 @@
                 return snippetReflectionProvider;
             }
 
-            public boolean parsingReplacement() {
-                return parsingReplacement;
-            }
-
+            /**
+             * Gets the graph being processed by this builder.
+             */
             public StructuredGraph getGraph() {
                 return currentGraph;
             }
 
-            public GuardingNode getCurrentBlockGuard() {
-                return (GuardingNode) getFirstInstruction(currentBlock, getCurrentDimension());
+            public BytecodeParser getParent() {
+                return parent;
+            }
+
+            public int getDepth() {
+                return parent == null ? 0 : 1 + parent.getDepth();
+            }
+
+            public ResolvedJavaMethod getRootMethod() {
+                return rootMethod;
+            }
+
+            public boolean eagerResolving() {
+                return graphBuilderConfig.eagerResolving();
             }
 
             @Override
             public String toString() {
-                return method.format("%H.%n(%p)@") + bci();
+                Formatter fmt = new Formatter();
+                BytecodeParser bp = this;
+                String indent = "";
+                while (bp != null) {
+                    if (bp != this) {
+                        fmt.format("%n%s", indent);
+                    }
+                    fmt.format("%s [bci: %d, replacement: %s]", bp.method.asStackTraceElement(bp.bci()), bci(), bp.parsingReplacement());
+                    bp = bp.parent;
+                    indent += " ";
+                }
+                return fmt.toString();
             }
 
             public BailoutException bailout(String string) {
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,8 +22,13 @@
  */
 package com.oracle.graal.java;
 
+import java.lang.reflect.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
+import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin.InlineInfo;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 
@@ -34,7 +39,7 @@
 
     public interface LoadFieldPlugin extends GraphBuilderPlugin {
         @SuppressWarnings("unused")
-        default boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field) {
+        default boolean apply(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) {
             return false;
         }
 
@@ -43,32 +48,78 @@
             return false;
         }
 
-        default boolean tryConstantFold(GraphBuilderContext builder, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ResolvedJavaField field, JavaConstant asJavaConstant) {
-            JavaConstant result = constantReflection.readConstantFieldValue(field, asJavaConstant);
+        default boolean tryConstantFold(GraphBuilderContext b, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ResolvedJavaField field, JavaConstant receiver) {
+            JavaConstant result = constantReflection.readConstantFieldValue(field, receiver);
             if (result != null) {
-                ConstantNode constantNode = builder.append(ConstantNode.forConstant(result, metaAccess));
-                builder.push(constantNode.getKind().getStackKind(), constantNode);
+                ConstantNode constantNode = b.append(ConstantNode.forConstant(result, metaAccess));
+                b.push(constantNode.getKind().getStackKind(), constantNode);
                 return true;
             }
             return false;
         }
     }
 
-    /**
-     * Plugin for customizing how the graph builder handles a CHECKCAST instruction in the context
-     * of the instruction that consumes it from the stack.
-     */
-    public interface CheckCastPlugin extends GraphBuilderPlugin {
-        boolean apply(GraphBuilderContext builder, ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck);
+    public interface LoadIndexedPlugin extends GraphBuilderPlugin {
+        @SuppressWarnings("unused")
+        default boolean apply(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind) {
+            return false;
+        }
     }
 
+    /**
+     * Plugin for specifying what is inlined during graph parsing or for post-processing non-inlined
+     * invocations that result in {@link Invoke} nodes.
+     */
     public interface InlineInvokePlugin extends GraphBuilderPlugin {
 
-        default void postInline(@SuppressWarnings("unused") ResolvedJavaMethod inlinedTargetMethod) {
+        public static class InlineInfo {
+
+            /**
+             * The method to be inlined. If this is not equal to the {@code method} argument passed
+             * to {@link InlineInvokePlugin#getClass()}, the graph builder context interprets it as
+             * a {@linkplain GraphBuilderContext#parsingReplacement() replacement}.
+             */
+            public final ResolvedJavaMethod methodToInline;
 
+            /**
+             * Specifies if {@link #methodToInline} is an intrinsic for the original method. If so,
+             * any {@link StateSplit} node created in the (recursive) inlining scope will be given a
+             * frame state that restarts the interpreter just before the intrinsified invocation.
+             */
+            public final boolean adoptBeforeCallFrameState;
+
+            public InlineInfo(ResolvedJavaMethod methodToInline, boolean adoptBeforeCallFrameState) {
+                this.methodToInline = methodToInline;
+                this.adoptBeforeCallFrameState = adoptBeforeCallFrameState;
+            }
         }
 
-        ResolvedJavaMethod getInlinedMethod(GraphBuilderContext builder, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType, int depth);
+        /**
+         * Determines whether a call to a given method is to be inlined.
+         *
+         * @param method the target method of an invoke
+         * @param args the arguments to the invoke
+         * @param returnType the return type derived from {@code method}'s signature
+         */
+        default InlineInfo getInlineInfo(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
+            return null;
+        }
+
+        /**
+         * @param inlinedTargetMethod
+         */
+        default void postInline(ResolvedJavaMethod inlinedTargetMethod) {
+        }
+
+        /**
+         * Notifies this plugin of the {@link Invoke} node created for a method that was not inlined
+         * per {@link #getInlineInfo}.
+         *
+         * @param method the method that was not inlined
+         * @param invoke the invoke node created for the call to {@code method}
+         */
+        default void notifyOfNoninlinedInvoke(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
+        }
     }
 
     public interface LoopExplosionPlugin extends GraphBuilderPlugin {
@@ -78,19 +129,20 @@
     }
 
     public interface ParameterPlugin extends GraphBuilderPlugin {
-        FloatingNode interceptParameter(int index);
+        FloatingNode interceptParameter(GraphBuilderContext b, int index, Stamp stamp);
     }
 
     /**
-     * Plugin for handling an invocation based on the annotations of the invoked method.
+     * Plugin for handling an invocation based on some property of the method being invoked such as
+     * any annotations it may have.
      */
-    public interface AnnotatedInvocationPlugin extends GraphBuilderPlugin {
+    public interface GenericInvocationPlugin extends GraphBuilderPlugin {
         /**
          * Executes this plugin for an invocation of a given method with a given set of arguments.
          *
          * @return {@code true} if this plugin handled the invocation, {@code false} if not
          */
-        boolean apply(GraphBuilderContext builder, ResolvedJavaMethod method, ValueNode[] args);
+        boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args);
     }
 
     /**
@@ -98,67 +150,99 @@
      */
     public interface InvocationPlugin extends GraphBuilderPlugin {
         /**
-         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
+         * @see #execute
          */
-        default boolean apply(GraphBuilderContext builder) {
-            throw invalidHandler(builder);
+        default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+            throw invalidHandler(b, targetMethod);
+        }
+
+        /**
+         * @see #execute
+         */
+        default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) {
+            throw invalidHandler(b, targetMethod, arg);
         }
 
         /**
-         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
+         * @see #execute
          */
-        default boolean apply(GraphBuilderContext builder, ValueNode arg) {
-            throw invalidHandler(builder, arg);
+        default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2) {
+            throw invalidHandler(b, targetMethod, arg1, arg2);
         }
 
         /**
-         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
+         * @see #execute
          */
-        default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2) {
-            throw invalidHandler(builder, arg1, arg2);
+        default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
+            throw invalidHandler(b, targetMethod, arg1, arg2, arg3);
         }
 
         /**
-         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
+         * @see #execute
          */
-        default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
-            throw invalidHandler(builder, arg1, arg2, arg3);
+        default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) {
+            throw invalidHandler(b, targetMethod, arg1, arg2, arg3, arg4);
         }
 
         /**
-         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
+         * @see #execute
          */
-        default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) {
-            throw invalidHandler(builder, arg1, arg2, arg3, arg4);
+        default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) {
+            throw invalidHandler(b, targetMethod, arg1, arg2, arg3, arg4, arg5);
         }
 
+        default ResolvedJavaMethod getSubstitute() {
+            return null;
+        }
+
+        boolean ALLOW_INVOCATION_PLUGIN_TO_DO_INLINING = false;
+
         /**
          * Executes a given plugin against a set of invocation arguments by dispatching to the
-         * plugin's {@code apply(...)} method that matches the number of arguments.
+         * {@code apply(...)} method that matches the number of arguments.
          *
-         * @return {@code true} if the plugin handled the invocation, {@code false} if the graph
-         *         builder should process the invoke further (e.g., by inlining it or creating an
-         *         {@link Invoke} node). A plugin that does not handle an invocation must not modify
-         *         the graph being constructed.
+         * @param targetMethod the method for which plugin is being applied
+         * @return {@code true} if the plugin handled the invocation of {@code targetMethod}
+         *         {@code false} if the graph builder should process the invoke further (e.g., by
+         *         inlining it or creating an {@link Invoke} node). A plugin that does not handle an
+         *         invocation must not modify the graph being constructed.
          */
-        static boolean execute(GraphBuilderContext builder, InvocationPlugin plugin, ValueNode[] args) {
+        static boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin plugin, ValueNode[] args) {
+            if (ALLOW_INVOCATION_PLUGIN_TO_DO_INLINING) {
+                ResolvedJavaMethod subst = plugin.getSubstitute();
+                if (subst != null) {
+                    return ((BytecodeParser) b).inline(null, targetMethod, new InlineInfo(subst, false), args);
+                }
+            }
             if (args.length == 0) {
-                return plugin.apply(builder);
+                return plugin.apply(b, targetMethod);
             } else if (args.length == 1) {
-                return plugin.apply(builder, args[0]);
+                return plugin.apply(b, targetMethod, args[0]);
             } else if (args.length == 2) {
-                return plugin.apply(builder, args[0], args[1]);
+                return plugin.apply(b, targetMethod, args[0], args[1]);
             } else if (args.length == 3) {
-                return plugin.apply(builder, args[0], args[1], args[2]);
+                return plugin.apply(b, targetMethod, args[0], args[1], args[2]);
             } else if (args.length == 4) {
-                return plugin.apply(builder, args[0], args[1], args[2], args[3]);
+                return plugin.apply(b, targetMethod, args[0], args[1], args[2], args[3]);
+            } else if (args.length == 5) {
+                return plugin.apply(b, targetMethod, args[0], args[1], args[2], args[3], args[4]);
             } else {
-                throw plugin.invalidHandler(builder, args);
+                throw plugin.invalidHandler(b, targetMethod, args);
             }
         }
 
-        default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext builder, ValueNode... args) {
-            return new GraalInternalError("Invocation plugin %s does not handle invocations with %d arguments", getClass().getSimpleName(), args.length);
+        default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode... args) {
+            return new GraalInternalError("Invocation plugin for %s does not handle invocations with %d arguments", targetMethod.format("%H.%n(%p)"), args.length);
+        }
+
+        default StackTraceElement getApplySourceLocation(MetaAccessProvider metaAccess) {
+            Class<?> c = getClass();
+            for (Method m : c.getDeclaredMethods()) {
+                if (m.getName().equals("apply")) {
+                    return metaAccess.lookupJavaMethod(m).asStackTraceElement(0);
+                }
+            }
+            throw new GraalInternalError("could not find method named \"apply\" in " + c.getName());
         }
     }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Thu Mar 12 15:59:01 2015 +0100
@@ -25,13 +25,15 @@
 import static com.oracle.graal.graph.iterators.NodePredicates.*;
 
 import java.util.*;
-import java.util.function.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.java.BciBlockMapping.*;
+import com.oracle.graal.java.AbstractBytecodeParser.IntrinsicContext;
+import com.oracle.graal.java.BciBlockMapping.BciBlock;
+import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
 import com.oracle.graal.java.GraphBuilderPlugin.ParameterPlugin;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -44,6 +46,7 @@
     private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
     private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
 
+    protected final BytecodeParser parser;
     protected final ResolvedJavaMethod method;
     protected int stackSize;
     protected final ValueNode[] locals;
@@ -51,18 +54,13 @@
     protected ValueNode[] lockedObjects;
 
     /**
-     * Specifies if asserting type checks are enabled.
-     */
-    protected final boolean checkTypes;
-
-    /**
      * @see BytecodeFrame#rethrowException
      */
     protected boolean rethrowException;
 
     private MonitorIdNode[] monitorIds;
     private final StructuredGraph graph;
-    private final Supplier<FrameState> outerFrameStateSupplier;
+    private FrameState outerFrameState;
 
     /**
      * Creates a new frame state builder for the given method and the given target graph.
@@ -70,18 +68,17 @@
      * @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, boolean checkTypes, Supplier<FrameState> outerFrameStateSupplier) {
+    public HIRFrameStateBuilder(BytecodeParser parser, ResolvedJavaMethod method, StructuredGraph graph) {
+        this.parser = parser;
         this.method = method;
         this.locals = allocateArray(method.getMaxLocals());
         this.stack = allocateArray(Math.max(1, method.getMaxStackSize()));
         this.lockedObjects = allocateArray(0);
-        this.checkTypes = checkTypes;
 
         assert graph != null;
 
         this.monitorIds = EMPTY_MONITOR_ARRAY;
         this.graph = graph;
-        this.outerFrameStateSupplier = outerFrameStateSupplier;
     }
 
     public void initializeFromArgumentsArray(ValueNode[] arguments) {
@@ -97,8 +94,9 @@
         Signature sig = method.getSignature();
         int max = sig.getParameterCount(false);
         for (int i = 0; i < max; i++) {
+            Kind kind = sig.getParameterKind(i);
             locals[javaIndex] = arguments[index];
-            javaIndex += arguments[index].getKind().getSlotCount();
+            javaIndex += kind.getSlotCount();
             index++;
         }
     }
@@ -110,11 +108,12 @@
         if (!method.isStatic()) {
             // add the receiver
             FloatingNode receiver = null;
+            Stamp receiverStamp = StampFactory.declaredNonNull(method.getDeclaringClass());
             if (parameterPlugin != null) {
-                receiver = parameterPlugin.interceptParameter(index);
+                receiver = parameterPlugin.interceptParameter(parser, index, receiverStamp);
             }
             if (receiver == null) {
-                receiver = new ParameterNode(javaIndex, StampFactory.declaredNonNull(method.getDeclaringClass()));
+                receiver = new ParameterNode(javaIndex, receiverStamp);
             }
             locals[javaIndex] = graph.unique(receiver);
             javaIndex = 1;
@@ -137,7 +136,7 @@
             }
             FloatingNode param = null;
             if (parameterPlugin != null) {
-                param = parameterPlugin.interceptParameter(index);
+                param = parameterPlugin.interceptParameter(parser, index, stamp);
             }
             if (param == null) {
                 param = new ParameterNode(index, stamp);
@@ -149,13 +148,13 @@
     }
 
     private HIRFrameStateBuilder(HIRFrameStateBuilder other) {
+        this.parser = other.parser;
         this.method = other.method;
         this.stackSize = other.stackSize;
         this.locals = other.locals.clone();
         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());
@@ -163,7 +162,6 @@
         assert other.graph != null;
         graph = other.graph;
         monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone();
-        this.outerFrameStateSupplier = other.outerFrameStateSupplier;
 
         assert locals.length == method.getMaxLocals();
         assert stack.length == Math.max(1, method.getMaxStackSize());
@@ -198,15 +196,42 @@
     }
 
     public FrameState create(int bci) {
-        FrameState outerFrameState = null;
-        if (outerFrameStateSupplier != null) {
-            outerFrameState = outerFrameStateSupplier.get();
-            if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
-                FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0));
-                return newFrameState;
+        BytecodeParser parent = parser.getParent();
+        if (parser.parsingReplacement()) {
+            IntrinsicContext intrinsic = parser.replacementContext.asIntrinsic();
+            if (intrinsic != null) {
+                assert parent != null : "intrinsics can only be processed in context of a caller";
+
+                // We're somewhere in an intrinsic. In this case, we want a frame state
+                // that will restart the interpreter just before the intrinsified
+                // invocation.
+                return intrinsic.getInvokeStateBefore(parent);
             }
         }
-        return graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, false));
+        return create(bci, parent, false);
+    }
+
+    public FrameState create(int bci, BytecodeParser parent, boolean duringCall) {
+        if (outerFrameState == null && parent != null) {
+            outerFrameState = parent.getFrameState().create(parent.bci());
+            if (parser.parsingReplacement()) {
+                IntrinsicContext intrinsic = parser.replacementContext.asIntrinsic();
+                if (intrinsic != null) {
+                    // A side-effect of creating the frame state in a replacing
+                    // parent is that the 'during' frame state is created as well
+                    outerFrameState = intrinsic.getInvokeStateDuring();
+                }
+            }
+        }
+        if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
+            FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0));
+            return newFrameState;
+        }
+        if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
+            throw GraalInternalError.shouldNotReachHere();
+            // return graph.add(new FrameState(bci));
+        }
+        return graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall));
     }
 
     public HIRFrameStateBuilder copy() {
@@ -549,11 +574,15 @@
 
     private boolean assertLoadLocal(int i, ValueNode x) {
         assert x != null : i;
-        assert !checkTypes || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null);
-        assert !checkTypes || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1);
+        assert parser.parsingReplacement() || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null);
+        assert parser.parsingReplacement() || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1);
         return true;
     }
 
+    public void storeLocal(int i, ValueNode x) {
+        storeLocal(i, x, x == null ? null : x.getKind());
+    }
+
     /**
      * Stores a given local variable at the specified index. If the value occupies two slots, then
      * the next local variable index is also overwritten.
@@ -561,24 +590,26 @@
      * @param i the index at which to store
      * @param x the instruction which produces the value for the local
      */
-    public void storeLocal(int i, ValueNode x) {
+    public void storeLocal(int i, ValueNode x, Kind kind) {
         assert assertStoreLocal(x);
         locals[i] = x;
-        if (x != null && x.getKind().needsTwoSlots()) {
-            // if this is a double word, then kill i+1
-            locals[i + 1] = null;
-        }
-        if (x != null && i > 0) {
-            ValueNode p = locals[i - 1];
-            if (p != null && p.getKind().needsTwoSlots()) {
-                // if there was a double word at i - 1, then kill it
-                locals[i - 1] = null;
+        if (x != null) {
+            if (kind.needsTwoSlots() && !parser.parsingReplacement()) {
+                // if this is a double word, then kill i+1
+                locals[i + 1] = null;
+            }
+            if (i > 0 && !parser.parsingReplacement()) {
+                ValueNode p = locals[i - 1];
+                if (p != null && p.getKind().needsTwoSlots()) {
+                    // if there was a double word at i - 1, then kill it
+                    locals[i - 1] = null;
+                }
             }
         }
     }
 
     private boolean assertStoreLocal(ValueNode x) {
-        assert x == null || !checkTypes || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x;
+        assert x == null || parser.parsingReplacement() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x;
         return true;
     }
 
@@ -607,8 +638,8 @@
     }
 
     private boolean assertPush(Kind kind, ValueNode x) {
-        assert !checkTypes || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal);
-        assert x != null && (!checkTypes || x.getKind() == kind);
+        assert parser.parsingReplacement() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal);
+        assert x != null && (parser.parsingReplacement() || x.getKind() == kind);
         return true;
     }
 
@@ -623,7 +654,7 @@
     }
 
     private boolean assertXpush(ValueNode x) {
-        assert !checkTypes || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal));
+        assert parser.parsingReplacement() || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal));
         return true;
     }
 
@@ -702,7 +733,7 @@
     private boolean assertPop(Kind kind) {
         assert kind != Kind.Void;
         ValueNode x = xpeek();
-        assert x != null && (!checkTypes || x.getKind() == kind);
+        assert x != null && (parser.parsingReplacement() || x.getKind() == kind);
         return true;
     }
 
@@ -789,7 +820,7 @@
                 newStackSize--;
                 assert stack[newStackSize].getKind().needsTwoSlots();
             } else {
-                assert !checkTypes || (stack[newStackSize].getKind().getSlotCount() == 1);
+                assert parser.parsingReplacement() || (stack[newStackSize].getKind().getSlotCount() == 1);
             }
             result[i] = stack[newStackSize];
         }
@@ -856,7 +887,7 @@
     }
 
     private boolean assertObject(ValueNode x) {
-        assert x != null && (!checkTypes || (x.getKind() == Kind.Object));
+        assert x != null && (parser.parsingReplacement() || (x.getKind() == Kind.Object));
         return true;
     }
 
@@ -910,7 +941,7 @@
             if (other.stackSize != stackSize) {
                 return false;
             }
-            if (other.checkTypes != checkTypes) {
+            if (other.parser != parser) {
                 return false;
             }
             if (other.rethrowException != rethrowException) {
@@ -919,9 +950,6 @@
             if (other.graph != graph) {
                 return false;
             }
-            if (other.outerFrameStateSupplier != outerFrameStateSupplier) {
-                return false;
-            }
             if (other.locals.length != locals.length) {
                 return false;
             }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/InvocationPlugins.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/InvocationPlugins.java	Thu Mar 12 15:59:01 2015 +0100
@@ -90,8 +90,7 @@
          * @param plugin the plugin to be registered
          */
         public void register1(String name, Class<?> arg, InvocationPlugin plugin) {
-            ResolvedJavaMethod method = arg == Receiver.class ? resolve(metaAccess, declaringClass, name) : resolve(metaAccess, declaringClass, name, arg);
-            plugins.register(method, plugin);
+            plugins.register(arg == Receiver.class ? resolve(metaAccess, declaringClass, name) : resolve(metaAccess, declaringClass, name, arg), plugin);
         }
 
         /**
@@ -101,8 +100,7 @@
          * @param plugin the plugin to be registered
          */
         public void register2(String name, Class<?> arg1, Class<?> arg2, InvocationPlugin plugin) {
-            ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2) : resolve(metaAccess, declaringClass, name, arg1, arg2);
-            plugins.register(method, plugin);
+            plugins.register(arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2) : resolve(metaAccess, declaringClass, name, arg1, arg2), plugin);
         }
 
         /**
@@ -112,8 +110,7 @@
          * @param plugin the plugin to be registered
          */
         public void register3(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, InvocationPlugin plugin) {
-            ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2, arg3) : resolve(metaAccess, declaringClass, name, arg1, arg2, arg3);
-            plugins.register(method, plugin);
+            plugins.register(arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2, arg3) : resolve(metaAccess, declaringClass, name, arg1, arg2, arg3), plugin);
         }
 
         /**
@@ -123,8 +120,18 @@
          * @param plugin the plugin to be registered
          */
         public void register4(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, InvocationPlugin plugin) {
-            ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2, arg3, arg4) : resolve(metaAccess, declaringClass, name, arg1, arg2, arg3, arg4);
-            plugins.register(method, plugin);
+            plugins.register(arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2, arg3, arg4) : resolve(metaAccess, declaringClass, name, arg1, arg2, arg3, arg4), plugin);
+        }
+
+        /**
+         * Registers a plugin for a method with 5 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register5(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, Class<?> arg5, InvocationPlugin plugin) {
+            plugins.register(arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2, arg3, arg4, arg5) : resolve(metaAccess, declaringClass, name, arg1, arg2, arg3, arg4, arg5),
+                            plugin);
         }
 
         /**
@@ -197,21 +204,23 @@
     }
 
     private static class Checker {
+        private static final int MAX_ARITY = 5;
         /**
          * The set of all {@link InvocationPlugin#apply} method signatures.
          */
         static final Class<?>[][] SIGS;
         static {
-            ArrayList<Class<?>[]> sigs = new ArrayList<>(5);
+            ArrayList<Class<?>[]> sigs = new ArrayList<>(MAX_ARITY);
             for (Method method : InvocationPlugin.class.getDeclaredMethods()) {
                 if (!Modifier.isStatic(method.getModifiers()) && method.getName().equals("apply")) {
                     Class<?>[] sig = method.getParameterTypes();
                     assert sig[0] == GraphBuilderContext.class;
-                    assert Arrays.asList(Arrays.copyOfRange(sig, 1, sig.length)).stream().allMatch(c -> c == ValueNode.class);
-                    while (sigs.size() < sig.length) {
+                    assert sig[1] == ResolvedJavaMethod.class;
+                    assert Arrays.asList(Arrays.copyOfRange(sig, 2, sig.length)).stream().allMatch(c -> c == ValueNode.class);
+                    while (sigs.size() < sig.length - 1) {
                         sigs.add(null);
                     }
-                    sigs.set(sig.length - 1, sig);
+                    sigs.set(sig.length - 2, sig);
                 }
             }
             assert sigs.indexOf(null) == -1 : format("need to add an apply() method to %s that takes %d %s arguments ", InvocationPlugin.class.getName(), sigs.indexOf(null),
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Thu Mar 12 15:59:01 2015 +0100
@@ -223,14 +223,23 @@
     }
 
     /**
-     * Creates a copy of this frame state with one stack element of type popKind popped from the
-     * stack and the values in pushedValues pushed on the stack. The pushedValues will be formatted
-     * correctly in slot encoding: a long or double will be followed by a null slot.
+     * Creates a copy of this frame state with one stack element of type {@code popKind} popped from
+     * the stack.
      */
     public FrameState duplicateModifiedDuringCall(int newBci, Kind popKind) {
         return duplicateModified(newBci, rethrowException, true, popKind);
     }
 
+    public FrameState duplicateModifiedBeforeCall(int newBci, Kind popKind, ValueNode... pushedValues) {
+        return duplicateModified(newBci, rethrowException, false, popKind, pushedValues);
+    }
+
+    /**
+     * Creates a copy of this frame state with one stack element of type {@code popKind} popped from
+     * the stack and the values in {@code pushedValues} pushed on the stack. The
+     * {@code pushedValues} will be formatted correctly in slot encoding: a long or double will be
+     * followed by a null slot.
+     */
     public FrameState duplicateModified(int newBci, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) {
         return duplicateModified(newBci, newRethrowException, duringCall, popKind, pushedValues);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -147,19 +147,17 @@
     }
 
     @NodeIntrinsic
-    public static <T> T guardingNonNull(T object) {
-        if (object == null) {
-            throw new NullPointerException();
-        }
-        return object;
-    }
-
-    @NodeIntrinsic
-    public static native Object guardingPi(Object object, LogicNode condition, @ConstantNodeParameter boolean negateCondition, @ConstantNodeParameter DeoptimizationReason reason,
-                    @ConstantNodeParameter DeoptimizationAction action, @ConstantNodeParameter Stamp stamp);
+    public static native Object guardingNonNull(Object object);
 
     @Override
     public ValueNode getOriginalNode() {
         return object;
     }
+
+    /**
+     * Casts a value to have an exact, non-null stamp representing {@link Class} that is guarded by
+     * a null check.
+     */
+    @NodeIntrinsic(GuardingPiNode.class)
+    public static native Class<?> asNonNullClass(Class<?> c);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiArrayNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiArrayNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -59,5 +59,5 @@
     }
 
     @NodeIntrinsic
-    public static native <T> T piArrayCast(Object object, int length, @ConstantNodeParameter Stamp stamp);
+    public static native Object piArrayCast(Object object, int length, @ConstantNodeParameter Stamp stamp);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -34,12 +34,12 @@
 import com.oracle.graal.nodes.type.*;
 
 /**
- * A node that changes the type of its input, usually narrowing it. For example, a PiNode refines
- * the type of a receiver during type-guarded inlining to be the type tested by the guard.
+ * A node that changes the type of its input, usually narrowing it. For example, a {@link PiNode}
+ * refines the type of a receiver during type-guarded inlining to be the type tested by the guard.
  *
- * In contrast to a {@link GuardedValueNode}, a PiNode is useless as soon as the type of its input
- * is as narrow or narrower than the PiNode's type. The PiNode, and therefore also the scheduling
- * restriction enforced by the anchor, will go away.
+ * In contrast to a {@link GuardedValueNode}, a {@link PiNode} is useless as soon as the type of its
+ * input is as narrow or narrower than the {@link PiNode}'s type. The {@link PiNode}, and therefore
+ * also the scheduling restriction enforced by the anchor, will go away.
  */
 @NodeInfo
 public class PiNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, IterableNodeType, Canonicalizable, ValueProxy {
@@ -116,31 +116,37 @@
         return object;
     }
 
-    @NodeIntrinsic
-    public static native <T> T piCast(Object object, @ConstantNodeParameter Stamp stamp);
-
-    @NodeIntrinsic
-    public static native <T> T piCast(Object object, @ConstantNodeParameter Stamp stamp, GuardingNode anchor);
-
-    public static <T> T piCastExactNonNull(Object object, @ConstantNodeParameter Class<T> toType) {
-        return piCast(object, toType, true, true);
+    /**
+     * Casts an object to have an exact, non-null stamp representing {@link Class}.
+     */
+    public static Class<?> asNonNullClass(Object object) {
+        return asNonNullClassIntrinsic(object, Class.class, true, true);
     }
 
-    public static <T> T piCastExact(Object object, @ConstantNodeParameter Class<T> toType) {
-        return piCast(object, toType, true, false);
-    }
+    @NodeIntrinsic(PiNode.class)
+    private static native Class<?> asNonNullClassIntrinsic(Object object, @ConstantNodeParameter Class<?> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull);
+
+    /**
+     * Changes the stamp of an object.
+     */
+    @NodeIntrinsic
+    public static native Object piCast(Object object, @ConstantNodeParameter Stamp stamp);
 
-    public static <T> T piCast(Object object, @ConstantNodeParameter Class<T> toType) {
-        return piCast(object, toType, false, false);
-    }
+    /**
+     * Changes the stamp of an object and ensures the newly stamped value does float above a given
+     * anchor.
+     */
+    @NodeIntrinsic
+    public static native Object piCast(Object object, @ConstantNodeParameter Stamp stamp, GuardingNode anchor);
 
-    public static <T> T piCastNonNull(Object object, @ConstantNodeParameter Class<T> toType) {
+    /**
+     * Changes the stamp of an object to represent a given type and to indicate that the object is
+     * not null.
+     */
+    public static Object piCastNonNull(Object object, @ConstantNodeParameter Class<?> toType) {
         return piCast(object, toType, false, true);
     }
 
-    @SuppressWarnings("unused")
     @NodeIntrinsic
-    private static <T> T piCast(Object object, @ConstantNodeParameter Class<T> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull) {
-        return toType.cast(object);
-    }
+    public static native Object piCast(Object object, @ConstantNodeParameter Class<?> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Thu Mar 12 15:59:01 2015 +0100
@@ -25,8 +25,7 @@
 import java.util.*;
 import java.util.concurrent.atomic.*;
 
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.Assumptions.Assumption;
+import com.oracle.graal.api.meta.Assumptions.Assumption;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -98,8 +99,8 @@
             }
         } else if (StampTool.typeOrNull(forValue) != null) {
             ResolvedJavaType type = StampTool.typeOrNull(forValue);
-            ResolvedJavaType uniqueConcrete = type.findUniqueConcreteSubtype();
-            if (uniqueConcrete != null) {
+            AssumptionResult<ResolvedJavaType> leafConcreteSubtype = type.findLeafConcreteSubtype();
+            if (leafConcreteSubtype != null) {
                 // Profile is useless => remove.
                 Debug.log("Profile useless, there is enough static type information available.");
                 return forValue;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AbsNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AbsNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -58,14 +58,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitMathAbs(builder.operand(getValue())));
     }
-
-    @NodeIntrinsic
-    public static float abs(float n) {
-        return Math.abs(n);
-    }
-
-    @NodeIntrinsic
-    public static double abs(double n) {
-        return Math.abs(n);
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -31,7 +31,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -141,42 +140,7 @@
         generator.emitConditional(this);
     }
 
-    public ConditionalNode(@InjectedNodeParameter StructuredGraph graph, Condition condition, ValueNode x, ValueNode y) {
+    public ConditionalNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y) {
         this(createCompareNode(graph, condition, x, y, null));
     }
-
-    public ConditionalNode(ValueNode type, ValueNode object) {
-        this(type.graph().unique(new InstanceOfDynamicNode(type, object)));
-    }
-
-    @NodeIntrinsic
-    public static native boolean materializeCondition(@ConstantNodeParameter Condition condition, int x, int y);
-
-    @NodeIntrinsic
-    public static native boolean materializeCondition(@ConstantNodeParameter Condition condition, long x, long y);
-
-    @NodeIntrinsic
-    public static boolean materializeIsInstance(Class<?> mirror, Object object) {
-        return mirror.isInstance(object);
-    }
-
-    /**
-     * @param thisClass
-     * @param otherClass
-     * @param dummy a marker to make this constructor unique for the
-     *            {@link #materializeIsAssignableFrom(Class, Class, int)} NodeIntrinsic
-     */
-    public ConditionalNode(ValueNode thisClass, ValueNode otherClass, int dummy) {
-        this(thisClass.graph().unique(new ClassIsAssignableFromNode(thisClass, otherClass)));
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    private static boolean materializeIsAssignableFrom(Class<?> thisClass, Class<?> otherClass, @ConstantNodeParameter int dummy) {
-        return thisClass.isAssignableFrom(otherClass);
-    }
-
-    public static boolean materializeIsAssignableFrom(Class<?> thisClass, Class<?> otherClass) {
-        return materializeIsAssignableFrom(thisClass, otherClass, 0);
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -51,7 +51,7 @@
     @Override
     public boolean verify() {
         assertTrue(getValue() != null, "is null input must not be null");
-        assertTrue(getValue().stamp() instanceof AbstractPointerStamp, "is null input must be a pointer");
+        assertTrue(getValue().stamp() instanceof AbstractPointerStamp, "input must be a pointer not %s", getValue().stamp());
         return super.verify();
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SqrtNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SqrtNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -46,9 +46,4 @@
     public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
         builder.setResult(this, gen.emitMathSqrt(builder.operand(getValue())));
     }
-
-    @NodeIntrinsic
-    public static double sqrt(double n) {
-        return Math.sqrt(n);
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/BlackholeNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/BlackholeNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -43,31 +43,4 @@
     public void generate(NodeLIRBuilderTool gen) {
         gen.getLIRGeneratorTool().emitBlackhole(gen.operand(value));
     }
-
-    @NodeIntrinsic
-    public static native void consume(boolean v);
-
-    @NodeIntrinsic
-    public static native void consume(byte v);
-
-    @NodeIntrinsic
-    public static native void consume(short v);
-
-    @NodeIntrinsic
-    public static native void consume(char v);
-
-    @NodeIntrinsic
-    public static native void consume(int v);
-
-    @NodeIntrinsic
-    public static native void consume(long v);
-
-    @NodeIntrinsic
-    public static native void consume(float v);
-
-    @NodeIntrinsic
-    public static native void consume(double v);
-
-    @NodeIntrinsic
-    public static native void consume(Object v);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/OpaqueNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/OpaqueNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -47,31 +47,4 @@
     public void generate(NodeLIRBuilderTool gen) {
         gen.setResult(this, gen.operand(value));
     }
-
-    @NodeIntrinsic
-    public static native boolean opaque(boolean v);
-
-    @NodeIntrinsic
-    public static native byte opaque(byte v);
-
-    @NodeIntrinsic
-    public static native short opaque(short v);
-
-    @NodeIntrinsic
-    public static native char opaque(char v);
-
-    @NodeIntrinsic
-    public static native int opaque(int v);
-
-    @NodeIntrinsic
-    public static native long opaque(long v);
-
-    @NodeIntrinsic
-    public static native float opaque(float v);
-
-    @NodeIntrinsic
-    public static native double opaque(double v);
-
-    @NodeIntrinsic
-    public static native <T> T opaque(T v);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -80,28 +80,4 @@
         tool.createVirtualObject(newVirtual, new ValueNode[]{v}, Collections.<MonitorIdNode> emptyList());
         tool.replaceWithVirtual(newVirtual);
     }
-
-    @NodeIntrinsic
-    public static native Boolean box(boolean value, @ConstantNodeParameter Class<?> clazz, @ConstantNodeParameter Kind kind);
-
-    @NodeIntrinsic
-    public static native Byte box(byte value, @ConstantNodeParameter Class<?> clazz, @ConstantNodeParameter Kind kind);
-
-    @NodeIntrinsic
-    public static native Character box(char value, @ConstantNodeParameter Class<?> clazz, @ConstantNodeParameter Kind kind);
-
-    @NodeIntrinsic
-    public static native Double box(double value, @ConstantNodeParameter Class<?> clazz, @ConstantNodeParameter Kind kind);
-
-    @NodeIntrinsic
-    public static native Float box(float value, @ConstantNodeParameter Class<?> clazz, @ConstantNodeParameter Kind kind);
-
-    @NodeIntrinsic
-    public static native Integer box(int value, @ConstantNodeParameter Class<?> clazz, @ConstantNodeParameter Kind kind);
-
-    @NodeIntrinsic
-    public static native Long box(long value, @ConstantNodeParameter Class<?> clazz, @ConstantNodeParameter Kind kind);
-
-    @NodeIntrinsic
-    public static native Short box(short value, @ConstantNodeParameter Class<?> clazz, @ConstantNodeParameter Kind kind);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BranchProbabilityNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BranchProbabilityNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -110,7 +110,9 @@
             if (couldSet) {
                 ValueNode currentCondition = condition;
                 replaceAndDelete(currentCondition);
-                tool.addToWorkList(currentCondition.usages());
+                if (tool != null) {
+                    tool.addToWorkList(currentCondition.usages());
+                }
             } else {
                 if (!isSubstitutionGraph()) {
                     throw new GraalInternalError("Wrong usage of branch probability injection!");
@@ -135,10 +137,7 @@
      * @return the condition
      */
     @NodeIntrinsic
-    public static boolean probability(double probability, boolean condition) {
-        assert probability >= 0.0 && probability <= 1.0;
-        return condition;
-    }
+    public static native boolean probability(double probability, boolean condition);
 
     @Override
     public void lower(LoweringTool tool) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedValueAnchorNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedValueAnchorNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -49,7 +49,7 @@
     }
 
     @NodeIntrinsic
-    public static native <T> T getObject(Object object);
+    public static native Object getObject(Object object);
 
     @Override
     public void generate(NodeLIRBuilderTool generator) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -135,7 +135,7 @@
         if ((currentStateAfter.stackSize() > 0 && currentStateAfter.stackAt(currentStateAfter.stackSize() - 1) == this) ||
                         (currentStateAfter.stackSize() > 1 && currentStateAfter.stackAt(currentStateAfter.stackSize() - 2) == this)) {
             // The result of this call is on the top of stack, so roll back to the previous bci.
-            assert bci != BytecodeFrame.UNKNOWN_BCI;
+            assert bci != BytecodeFrame.UNKNOWN_BCI : this;
             newStateDuring = currentStateAfter.duplicateModifiedDuringCall(bci, this.getKind());
         } else {
             newStateDuring = currentStateAfter;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -72,16 +73,15 @@
         if (metaAccess != null && getValue().stamp() instanceof ObjectStamp) {
             ObjectStamp objectStamp = (ObjectStamp) getValue().stamp();
 
-            ResolvedJavaType exactType;
+            ResolvedJavaType exactType = null;
             if (objectStamp.isExactType()) {
                 exactType = objectStamp.type();
             } else if (objectStamp.type() != null && graph().getAssumptions() != null) {
-                exactType = objectStamp.type().findUniqueConcreteSubtype();
-                if (exactType != null) {
-                    graph().getAssumptions().recordConcreteSubtype(objectStamp.type(), exactType);
+                AssumptionResult<ResolvedJavaType> leafConcreteSubtype = objectStamp.type().findLeafConcreteSubtype();
+                if (leafConcreteSubtype != null) {
+                    exactType = leafConcreteSubtype.getResult();
+                    graph().getAssumptions().record(leafConcreteSubtype);
                 }
-            } else {
-                exactType = null;
             }
 
             if (exactType != null) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,8 +22,8 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -72,10 +72,10 @@
             }
             Assumptions assumptions = graph().getAssumptions();
             if (type != null && assumptions != null) {
-                ResolvedJavaMethod resolvedMethod = type.findUniqueConcreteMethod(method);
+                AssumptionResult<ResolvedJavaMethod> resolvedMethod = type.findUniqueConcreteMethod(method);
                 if (resolvedMethod != null && !type.isInterface() && method.getDeclaringClass().isAssignableFrom(type)) {
-                    assumptions.recordConcreteMethod(method, type, resolvedMethod);
-                    return ConstantNode.forConstant(stamp(), resolvedMethod.getEncoding(), tool.getMetaAccess());
+                    assumptions.record(resolvedMethod);
+                    return ConstantNode.forConstant(stamp(), resolvedMethod.getResult().getEncoding(), tool.getMetaAccess());
                 }
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,14 +22,7 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import static com.oracle.graal.compiler.common.UnsafeAccess.*;
-
-import java.lang.reflect.*;
-
-import sun.misc.*;
-
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
@@ -60,28 +53,6 @@
         generator.getLIRGeneratorTool().emitMembar(barriers);
     }
 
-    @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static void memoryBarrier(@ConstantNodeParameter int barriers) {
-        // Overly conservative but it doesn't matter in the interpreter
-        unsafe.putIntVolatile(dummyBase, dummyOffset, 0);
-        unsafe.getIntVolatile(dummyBase, dummyOffset);
-    }
-
-    /**
-     * An unused field that it used to exercise barriers in the interpreter. This can be replaced
-     * with direct support for barriers in {@link Unsafe} if/when they become available.
-     */
-    @SuppressWarnings("unused") private static int dummy;
-    private static Object dummyBase;
-    private static long dummyOffset;
-    static {
-        try {
-            Field dummyField = MembarNode.class.getDeclaredField("dummy");
-            dummyBase = unsafe.staticFieldBase(dummyField);
-            dummyOffset = unsafe.staticFieldOffset(dummyField);
-        } catch (Exception e) {
-            throw new GraalInternalError(e);
-        }
-    }
+    public static native void memoryBarrier(@ConstantNodeParameter int barriers);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -95,28 +95,4 @@
         }
         return null;
     }
-
-    @NodeIntrinsic
-    public static native boolean unbox(Boolean value, @ConstantNodeParameter Kind kind);
-
-    @NodeIntrinsic
-    public static native byte unbox(Byte value, @ConstantNodeParameter Kind kind);
-
-    @NodeIntrinsic
-    public static native char unbox(Character value, @ConstantNodeParameter Kind kind);
-
-    @NodeIntrinsic
-    public static native double unbox(Double value, @ConstantNodeParameter Kind kind);
-
-    @NodeIntrinsic
-    public static native float unbox(Float value, @ConstantNodeParameter Kind kind);
-
-    @NodeIntrinsic
-    public static native int unbox(Integer value, @ConstantNodeParameter Kind kind);
-
-    @NodeIntrinsic
-    public static native long unbox(Long value, @ConstantNodeParameter Kind kind);
-
-    @NodeIntrinsic
-    public static native short unbox(Short value, @ConstantNodeParameter Kind kind);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCopyNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2011, 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.nodes.extended;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Copy a value at a location specified as an offset relative to a source object to another location
+ * specified as an offset relative to destination object. No null checks are performed.
+ *
+ * This node must be replaced during processing of node intrinsics with an {@link UnsafeLoadNode}
+ * and {@link UnsafeStoreNode} pair.
+ */
+@NodeInfo
+public final class UnsafeCopyNode extends FixedWithNextNode implements StateSplit {
+
+    public static final NodeClass<UnsafeCopyNode> TYPE = NodeClass.create(UnsafeCopyNode.class);
+    @Input ValueNode sourceObject;
+    @Input ValueNode destinationObject;
+    @Input ValueNode sourceOffset;
+    @Input ValueNode destinationOffset;
+    protected final Kind accessKind;
+    protected final LocationIdentity locationIdentity;
+    @OptionalInput(InputType.State) FrameState stateAfter;
+
+    public UnsafeCopyNode(ValueNode sourceObject, ValueNode sourceOffset, ValueNode destinationObject, ValueNode destinationOffset, Kind accessKind, LocationIdentity locationIdentity) {
+        this(sourceObject, sourceOffset, destinationObject, destinationOffset, accessKind, locationIdentity, null);
+    }
+
+    public UnsafeCopyNode(ValueNode sourceObject, ValueNode sourceOffset, ValueNode destinationObject, ValueNode destinationOffset, Kind accessKind, LocationIdentity locationIdentity,
+                    FrameState stateAfter) {
+        super(TYPE, StampFactory.forVoid());
+        this.sourceObject = sourceObject;
+        this.sourceOffset = sourceOffset;
+        this.destinationObject = destinationObject;
+        this.destinationOffset = destinationOffset;
+        this.accessKind = accessKind;
+        this.locationIdentity = locationIdentity;
+        this.stateAfter = stateAfter;
+        assert accessKind != Kind.Void && accessKind != Kind.Illegal;
+    }
+
+    public ValueNode sourceObject() {
+        return sourceObject;
+    }
+
+    public ValueNode destinationObject() {
+        return destinationObject;
+    }
+
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
+
+    public ValueNode sourceOffset() {
+        return sourceOffset;
+    }
+
+    public ValueNode destinationOffset() {
+        return destinationOffset;
+    }
+
+    public Kind accessKind() {
+        return accessKind;
+    }
+
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    public boolean hasSideEffect() {
+        return true;
+    }
+
+    public FrameState getState() {
+        return stateAfter;
+    }
+
+    @NodeIntrinsic
+    public static native void copy(Object srcObject, long srcOffset, Object destObject, long destOffset, @ConstantNodeParameter Kind kind, @ConstantNodeParameter LocationIdentity locationIdentity);
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import static com.oracle.graal.compiler.common.UnsafeAccess.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -89,34 +87,6 @@
         return new UnsafeLoadNode(object(), location, accessKind(), identity, guardingCondition);
     }
 
-    @SuppressWarnings({"unchecked", "unused"})
     @NodeIntrinsic
-    public static <T> T load(Object object, long offset, @ConstantNodeParameter Kind kind, @ConstantNodeParameter LocationIdentity locationIdentity) {
-        if (kind == Kind.Boolean) {
-            return (T) (Boolean) unsafe.getBoolean(object, offset);
-        }
-        if (kind == Kind.Byte) {
-            return (T) (Byte) unsafe.getByte(object, offset);
-        }
-        if (kind == Kind.Short) {
-            return (T) (Short) unsafe.getShort(object, offset);
-        }
-        if (kind == Kind.Char) {
-            return (T) (Character) unsafe.getChar(object, offset);
-        }
-        if (kind == Kind.Int) {
-            return (T) (Integer) unsafe.getInt(object, offset);
-        }
-        if (kind == Kind.Float) {
-            return (T) (Float) unsafe.getFloat(object, offset);
-        }
-        if (kind == Kind.Long) {
-            return (T) (Long) unsafe.getLong(object, offset);
-        }
-        if (kind == Kind.Double) {
-            return (T) (Double) unsafe.getDouble(object, offset);
-        }
-        assert kind == Kind.Object;
-        return (T) unsafe.getObject(object, offset);
-    }
+    public static native Object load(Object object, long offset, @ConstantNodeParameter Kind kind, @ConstantNodeParameter LocationIdentity locationIdentity);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import static com.oracle.graal.compiler.common.UnsafeAccess.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -122,60 +120,4 @@
     public FrameState getState() {
         return stateAfter;
     }
-
-    // specialized on value type until boxing/unboxing is sorted out in intrinsification
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, Object value, @ConstantNodeParameter Kind kind, @ConstantNodeParameter LocationIdentity locationIdentity) {
-        unsafe.putObject(object, offset, value);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, boolean value, @ConstantNodeParameter Kind kind, @ConstantNodeParameter LocationIdentity locationIdentity) {
-        unsafe.putBoolean(object, offset, value);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, byte value, @ConstantNodeParameter Kind kind, @ConstantNodeParameter LocationIdentity locationIdentity) {
-        unsafe.putByte(object, offset, value);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, char value, @ConstantNodeParameter Kind kind, @ConstantNodeParameter LocationIdentity locationIdentity) {
-        unsafe.putChar(object, offset, value);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, double value, @ConstantNodeParameter Kind kind, @ConstantNodeParameter LocationIdentity locationIdentity) {
-        unsafe.putDouble(object, offset, value);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, float value, @ConstantNodeParameter Kind kind, @ConstantNodeParameter LocationIdentity locationIdentity) {
-        unsafe.putFloat(object, offset, value);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, int value, @ConstantNodeParameter Kind kind, @ConstantNodeParameter LocationIdentity locationIdentity) {
-        unsafe.putInt(object, offset, value);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, long value, @ConstantNodeParameter Kind kind, @ConstantNodeParameter LocationIdentity locationIdentity) {
-        unsafe.putLong(object, offset, value);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(Object object, long offset, short value, @ConstantNodeParameter Kind kind, @ConstantNodeParameter LocationIdentity locationIdentity) {
-        unsafe.putShort(object, offset, value);
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndAddNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndAddNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodes.java;
 
-import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import sun.misc.*;
 
 import com.oracle.graal.api.meta.*;
@@ -76,14 +75,4 @@
         Value result = gen.getLIRGeneratorTool().emitAtomicReadAndAdd(address, gen.operand(delta));
         gen.setResult(this, result);
     }
-
-    @NodeIntrinsic
-    public static int getAndAddInt(Object object, long offset, int delta, @ConstantNodeParameter @SuppressWarnings("unused") LocationIdentity locationIdentity) {
-        return unsafe.getAndAddInt(object, offset, delta);
-    }
-
-    @NodeIntrinsic
-    public static long getAndAddLong(Object object, long offset, long delta, @ConstantNodeParameter @SuppressWarnings("unused") LocationIdentity locationIdentity) {
-        return unsafe.getAndAddLong(object, offset, delta);
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndWriteNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndWriteNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodes.java;
 
-import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import sun.misc.*;
 
 import com.oracle.graal.api.meta.*;
@@ -80,23 +79,4 @@
     public void lower(LoweringTool tool) {
         tool.getLowerer().lower(this, tool);
     }
-
-    @NodeIntrinsic
-    public static int getAndSetInt(Object object, long offset, int newValue, @SuppressWarnings("unused") @ConstantNodeParameter Kind valueKind,
-                    @ConstantNodeParameter @SuppressWarnings("unused") LocationIdentity locationIdentity) {
-        return unsafe.getAndSetInt(object, offset, newValue);
-    }
-
-    @NodeIntrinsic
-    public static long getAndSetLong(Object object, long offset, long newValue, @SuppressWarnings("unused") @ConstantNodeParameter Kind valueKind,
-                    @ConstantNodeParameter @SuppressWarnings("unused") LocationIdentity locationIdentity) {
-        return unsafe.getAndSetLong(object, offset, newValue);
-    }
-
-    @NodeIntrinsic
-    public static Object getAndSetObject(Object object, long offset, Object newValue, @SuppressWarnings("unused") @ConstantNodeParameter Kind valueKind,
-                    @ConstantNodeParameter @SuppressWarnings("unused") LocationIdentity locationIdentity) {
-        return unsafe.getAndSetObject(object, offset, newValue);
-    }
-
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -100,7 +100,4 @@
         }
         return this;
     }
-
-    @NodeIntrinsic
-    public static native <T> T checkCastDynamic(Class<T> type, Object object, @ConstantNodeParameter boolean forStoreCheck);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -26,8 +26,8 @@
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -56,6 +56,7 @@
 
     public CheckCastNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile, boolean forStoreCheck) {
         super(TYPE, StampFactory.declaredTrusted(type));
+        assert object.stamp() instanceof ObjectStamp : object + ":" + object.stamp();
         assert type != null;
         this.type = type;
         this.object = object;
@@ -69,11 +70,12 @@
         if (synonym != null) {
             return synonym;
         }
+        assert object.stamp() instanceof ObjectStamp : object + ":" + object.stamp();
         if (assumptions != null) {
-            ResolvedJavaType uniqueConcreteType = type.findUniqueConcreteSubtype();
-            if (uniqueConcreteType != null && !uniqueConcreteType.equals(type)) {
-                assumptions.recordConcreteSubtype(type, uniqueConcreteType);
-                type = uniqueConcreteType;
+            AssumptionResult<ResolvedJavaType> leafConcreteSubtype = type.findLeafConcreteSubtype();
+            if (leafConcreteSubtype != null && !leafConcreteSubtype.getResult().equals(type)) {
+                assumptions.record(leafConcreteSubtype);
+                type = leafConcreteSubtype.getResult();
             }
         }
         return new CheckCastNode(type, object, profile, forStoreCheck);
@@ -168,11 +170,11 @@
 
         Assumptions assumptions = graph().getAssumptions();
         if (assumptions != null) {
-            ResolvedJavaType exactType = type.findUniqueConcreteSubtype();
-            if (exactType != null && !exactType.equals(type)) {
+            AssumptionResult<ResolvedJavaType> leafConcreteSubtype = type.findLeafConcreteSubtype();
+            if (leafConcreteSubtype != null && !leafConcreteSubtype.getResult().equals(type)) {
                 // Propagate more precise type information to usages of the checkcast.
-                assumptions.recordConcreteSubtype(type, exactType);
-                return new CheckCastNode(exactType, object, profile, forStoreCheck);
+                assumptions.record(leafConcreteSubtype);
+                return new CheckCastNode(leafConcreteSubtype.getResult(), object, profile, forStoreCheck);
             }
         }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.java;
 
-import static com.oracle.graal.compiler.common.UnsafeAccess.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -88,23 +86,4 @@
     public void lower(LoweringTool tool) {
         tool.getLowerer().lower(this, tool);
     }
-
-    // specialized on value type until boxing/unboxing is sorted out in intrinsification
-    @NodeIntrinsic
-    public static boolean compareAndSwap(Object object, long offset, Object expected, Object newValue, @SuppressWarnings("unused") @ConstantNodeParameter Kind valueKind,
-                    @SuppressWarnings("unused") @ConstantNodeParameter LocationIdentity locationIdentity) {
-        return unsafe.compareAndSwapObject(object, offset, expected, newValue);
-    }
-
-    @NodeIntrinsic
-    public static boolean compareAndSwap(Object object, long offset, long expected, long newValue, @SuppressWarnings("unused") @ConstantNodeParameter Kind valueKind,
-                    @SuppressWarnings("unused") @ConstantNodeParameter LocationIdentity locationIdentity) {
-        return unsafe.compareAndSwapLong(object, offset, expected, newValue);
-    }
-
-    @NodeIntrinsic
-    public static boolean compareAndSwap(Object object, long offset, int expected, int newValue, @SuppressWarnings("unused") @ConstantNodeParameter Kind valueKind,
-                    @SuppressWarnings("unused") @ConstantNodeParameter LocationIdentity locationIdentity) {
-        return unsafe.compareAndSwapInt(object, offset, expected, newValue);
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -23,7 +23,6 @@
 //JaCoCo Exclude
 package com.oracle.graal.nodes.java;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -97,9 +96,7 @@
     }
 
     @NodeIntrinsic
-    public static Object newArray(Class<?> componentType, int length) {
-        return Array.newInstance(componentType, length);
-    }
+    public static native Object newArray(Class<?> componentType, int length);
 
     @NodeIntrinsic
     private static native Object newArray(Class<?> componentType, int length, @ConstantNodeParameter boolean fillContents, @ConstantNodeParameter Kind knownElementKind);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -56,7 +56,7 @@
         tool.getLowerer().lower(this, tool);
     }
 
-    public ValueNode canonical(CanonicalizerTool tool, ValueNode forObject, ValueNode forMirror) {
+    public LogicNode canonical(CanonicalizerTool tool, ValueNode forObject, ValueNode forMirror) {
         if (forMirror.isConstant()) {
             ResolvedJavaType t = tool.getConstantReflection().asJavaType(forMirror.asConstant());
             if (t != null) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,8 +22,8 @@
  */
 package com.oracle.graal.nodes.java;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -82,11 +82,11 @@
             }
             Assumptions assumptions = graph().getAssumptions();
             if (assumptions != null) {
-                ResolvedJavaType exact = stampType.findUniqueConcreteSubtype();
-                if (exact != null) {
-                    result = checkInstanceOf(forValue, exact, objectStamp.nonNull(), true);
+                AssumptionResult<ResolvedJavaType> leafConcreteSubtype = stampType.findLeafConcreteSubtype();
+                if (leafConcreteSubtype != null) {
+                    result = checkInstanceOf(forValue, leafConcreteSubtype.getResult(), objectStamp.nonNull(), true);
                     if (result != null) {
-                        assumptions.recordConcreteSubtype(stampType, exact);
+                        assumptions.record(leafConcreteSubtype);
                         return result;
                     }
                 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,8 +22,8 @@
  */
 package com.oracle.graal.nodes.java;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -126,19 +126,19 @@
             }
             Assumptions assumptions = receiver.graph().getAssumptions();
             if (assumptions != null) {
-                ResolvedJavaType uniqueConcreteType = type.findUniqueConcreteSubtype();
-                if (uniqueConcreteType != null) {
-                    ResolvedJavaMethod methodFromUniqueType = uniqueConcreteType.resolveConcreteMethod(targetMethod, contextType);
+                AssumptionResult<ResolvedJavaType> leafConcreteSubtype = type.findLeafConcreteSubtype();
+                if (leafConcreteSubtype != null) {
+                    ResolvedJavaMethod methodFromUniqueType = leafConcreteSubtype.getResult().resolveConcreteMethod(targetMethod, contextType);
                     if (methodFromUniqueType != null) {
-                        assumptions.recordConcreteSubtype(type, uniqueConcreteType);
+                        assumptions.record(leafConcreteSubtype);
                         return methodFromUniqueType;
                     }
                 }
 
-                ResolvedJavaMethod uniqueConcreteMethod = type.findUniqueConcreteMethod(targetMethod);
+                AssumptionResult<ResolvedJavaMethod> uniqueConcreteMethod = type.findUniqueConcreteMethod(targetMethod);
                 if (uniqueConcreteMethod != null) {
-                    assumptions.recordConcreteMethod(targetMethod, type, uniqueConcreteMethod);
-                    return uniqueConcreteMethod;
+                    assumptions.record(uniqueConcreteMethod);
+                    return uniqueConcreteMethod.getResult();
                 }
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -25,6 +25,8 @@
 import static com.oracle.graal.nodes.java.ForeignCallDescriptors.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -66,13 +68,10 @@
         ObjectStamp objectStamp = (ObjectStamp) object.stamp();
         if (objectStamp.isExactType()) {
             return objectStamp.type().hasFinalizer();
-        } else if (objectStamp.type() != null && !objectStamp.type().hasFinalizableSubclass()) {
-            // if either the declared type of receiver or the holder
-            // can be assumed to have no finalizers
-            if (assumptions != null) {
-                assumptions.recordNoFinalizableSubclassAssumption(objectStamp.type());
-                return false;
-            }
+        } else if (objectStamp.type() != null && assumptions != null) {
+            AssumptionResult<Boolean> result = objectStamp.type().hasFinalizableSubclass();
+            assumptions.record(result);
+            return result.getResult();
         }
         return true;
     }
@@ -102,8 +101,6 @@
         return true;
     }
 
-    @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static void register(Object thisObj) {
-    }
+    public static native void register(Object thisObj);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Thu Mar 12 15:59:01 2015 +0100
@@ -37,9 +37,10 @@
     /**
      * Gets the snippet graph derived from a given method.
      *
+     * @param args arguments to the snippet if available, otherwise {@code null}
      * @return the snippet graph, if any, that is derived from {@code method}
      */
-    StructuredGraph getSnippet(ResolvedJavaMethod method);
+    StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args);
 
     /**
      * Gets the snippet graph derived from a given method.
@@ -47,9 +48,10 @@
      * @param recursiveEntry if the snippet contains a call to this method, it's considered as
      *            recursive call and won't be processed for {@linkplain MethodSubstitution
      *            substitutions} or {@linkplain MacroSubstitution macro nodes}.
+     * @param args arguments to the snippet if available, otherwise {@code null}
      * @return the snippet graph, if any, that is derived from {@code method}
      */
-    StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry);
+    StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args);
 
     /**
      * Registers a method as snippet.
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/OptimizeGuardAnchorsPhase.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/OptimizeGuardAnchorsPhase.java	Thu Mar 12 15:59:01 2015 +0100
@@ -94,21 +94,26 @@
     private static void optimizeAtControlSplit(ControlSplitNode controlSplit, LazyCFG cfg) {
         AbstractBeginNode successor = findMinimumUsagesSuccessor(controlSplit);
         int successorCount = controlSplit.successors().count();
-        List<GuardNode> otherGuards = new ArrayList<>(successorCount - 1);
         for (GuardNode guard : successor.guards().snapshot()) {
             if (guard.isDeleted() || guard.condition().getUsageCount() < successorCount) {
                 continue;
             }
+            List<GuardNode> otherGuards = new ArrayList<>(successorCount - 1);
+            HashSet<Node> successorsWithoutGuards = new HashSet<>(controlSplit.successors().count());
+            controlSplit.successors().snapshotTo(successorsWithoutGuards);
+            successorsWithoutGuards.remove(guard.getAnchor());
             for (GuardNode conditonGuard : guard.condition().usages().filter(GuardNode.class)) {
                 if (conditonGuard != guard) {
-                    AnchoringNode conditonGuardAnchor = conditonGuard.getAnchor();
-                    if (conditonGuardAnchor.asNode().predecessor() == controlSplit && compatibleGuards(guard, conditonGuard)) {
+                    AnchoringNode conditionGuardAnchor = conditonGuard.getAnchor();
+                    if (conditionGuardAnchor.asNode().predecessor() == controlSplit && compatibleGuards(guard, conditonGuard)) {
                         otherGuards.add(conditonGuard);
+                        successorsWithoutGuards.remove(conditionGuardAnchor);
                     }
                 }
             }
 
-            if (otherGuards.size() == successorCount - 1) {
+            if (successorsWithoutGuards.isEmpty()) {
+                assert otherGuards.size() >= successorCount - 1;
                 AbstractBeginNode anchor = computeOptimalAnchor(cfg.get(), AbstractBeginNode.prevBegin(controlSplit));
                 GuardNode newGuard = controlSplit.graph().unique(new GuardNode(guard.condition(), anchor, guard.reason(), guard.action(), guard.isNegated(), guard.getSpeculation()));
                 for (GuardNode otherGuard : otherGuards) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AssumptionInlineInfo.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AssumptionInlineInfo.java	Thu Mar 12 15:59:01 2015 +0100
@@ -24,7 +24,7 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.Assumptions.Assumption;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
@@ -38,9 +38,9 @@
  */
 public class AssumptionInlineInfo extends ExactInlineInfo {
 
-    private final Assumption takenAssumption;
+    private final AssumptionResult<?> takenAssumption;
 
-    public AssumptionInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, Assumption takenAssumption) {
+    public AssumptionInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, AssumptionResult<?> takenAssumption) {
         super(invoke, concrete);
         this.takenAssumption = takenAssumption;
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Thu Mar 12 15:59:01 2015 +0100
@@ -29,6 +29,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
@@ -194,17 +195,17 @@
         }
 
         if (callTarget.graph().getAssumptions() != null) {
-            ResolvedJavaType uniqueSubtype = holder.findUniqueConcreteSubtype();
-            if (uniqueSubtype != null) {
-                ResolvedJavaMethod resolvedMethod = uniqueSubtype.resolveConcreteMethod(targetMethod, contextType);
+            AssumptionResult<ResolvedJavaType> leafConcreteSubtype = holder.findLeafConcreteSubtype();
+            if (leafConcreteSubtype != null) {
+                ResolvedJavaMethod resolvedMethod = leafConcreteSubtype.getResult().resolveConcreteMethod(targetMethod, contextType);
                 if (resolvedMethod != null) {
-                    return getAssumptionInlineInfo(invoke, resolvedMethod, new Assumptions.ConcreteSubtype(holder, uniqueSubtype));
+                    return getAssumptionInlineInfo(invoke, resolvedMethod, leafConcreteSubtype);
                 }
             }
 
-            ResolvedJavaMethod concrete = holder.findUniqueConcreteMethod(targetMethod);
+            AssumptionResult<ResolvedJavaMethod> concrete = holder.findUniqueConcreteMethod(targetMethod);
             if (concrete != null) {
-                return getAssumptionInlineInfo(invoke, concrete, new Assumptions.ConcreteMethod(targetMethod, holder, concrete));
+                return getAssumptionInlineInfo(invoke, concrete.getResult(), concrete);
             }
         }
 
@@ -337,7 +338,7 @@
         }
     }
 
-    private InlineInfo getAssumptionInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, Assumptions.Assumption takenAssumption) {
+    private InlineInfo getAssumptionInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, AssumptionResult<?> takenAssumption) {
         assert concrete.isConcrete();
         if (checkTargetConditions(invoke, concrete)) {
             return new AssumptionInlineInfo(invoke, concrete, takenAssumption);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Thu Mar 12 15:59:01 2015 +0100
@@ -377,19 +377,34 @@
         processStack(blockToNodes, nodeToBlock, visited, stack);
 
         // Visit back input edges of loop phis.
-        for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.TYPE)) {
-            for (PhiNode phi : loopBegin.phis()) {
-                if (visited.isMarked(phi)) {
-                    for (int i = 0; i < loopBegin.getLoopEndCount(); ++i) {
-                        Node node = phi.valueAt(i + loopBegin.forwardEndCount());
-                        if (node != null && !visited.isMarked(node)) {
-                            stack.push(node);
-                            processStack(blockToNodes, nodeToBlock, visited, stack);
+
+        boolean changed;
+        boolean unmarkedPhi;
+        do {
+            changed = false;
+            unmarkedPhi = false;
+            for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.TYPE)) {
+                for (PhiNode phi : loopBegin.phis()) {
+                    if (visited.isMarked(phi)) {
+                        for (int i = 0; i < loopBegin.getLoopEndCount(); ++i) {
+                            Node node = phi.valueAt(i + loopBegin.forwardEndCount());
+                            if (node != null && !visited.isMarked(node)) {
+                                changed = true;
+                                stack.push(node);
+                                processStack(blockToNodes, nodeToBlock, visited, stack);
+                            }
                         }
+                    } else {
+                        unmarkedPhi = true;
                     }
                 }
             }
-        }
+
+            /*
+             * the processing of one loop phi could have marked a previously checked loop phi,
+             * therefore this needs to be iterative.
+             */
+        } while (unmarkedPhi && changed);
 
         // Check for dead nodes.
         if (visited.getCounter() < graph.getNodeCount()) {
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -313,7 +313,7 @@
 
     @Test
     public void testConstants() {
-        test("testConstantsSnippet");
+        testGraph("testConstantsSnippet");
     }
 
     public static final int[] constantArray1 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -45,7 +45,7 @@
  */
 public abstract class MethodSubstitutionTest extends GraalCompilerTest {
 
-    protected StructuredGraph test(final String snippet) {
+    protected StructuredGraph testGraph(final String snippet) {
         try (Scope s = Debug.scope("MethodSubstitutionTest", getResolvedJavaMethod(snippet))) {
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
             HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
@@ -74,7 +74,7 @@
     protected void testSubstitution(String testMethodName, Class<?> intrinsicClass, Class<?> holder, String methodName, Class<?>[] parameterTypes, boolean optional, Object[] args1, Object[] args2) {
         ResolvedJavaMethod realMethod = getResolvedJavaMethod(holder, methodName, parameterTypes);
         ResolvedJavaMethod testMethod = getResolvedJavaMethod(testMethodName);
-        StructuredGraph graph = test(testMethodName);
+        StructuredGraph graph = testGraph(testMethodName);
 
         // Check to see if the resulting graph contains the expected node
         StructuredGraph replacement = getReplacements().getMethodSubstitution(realMethod);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -33,7 +33,6 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
-import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
 import com.oracle.graal.word.*;
 
 /**
@@ -46,14 +45,12 @@
     private final ReplacementsImpl installer;
 
     public ObjectAccessTest() {
-        installer = new ReplacementsImpl(getProviders(), getSnippetReflection(), getTarget());
+        installer = (ReplacementsImpl) getReplacements();
     }
 
-    private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
-
     @Override
     protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
-        return installer.makeGraph(m, null, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect);
+        return installer.makeGraph(m, null, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -52,14 +52,14 @@
 
     public PointerTest() {
         target = getCodeCache().getTarget();
-        installer = new ReplacementsImpl(getProviders(), getSnippetReflection(), getTarget());
+        installer = (ReplacementsImpl) getProviders().getReplacements();
     }
 
     private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
 
     @Override
     protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
-        return installer.makeGraph(m, null, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect);
+        return installer.makeGraph(m, null, null, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -63,7 +63,6 @@
         @MethodSubstitution(isStatic = true)
         static double nextAfter(double x, double d) {
             double xx = (x == -0.0 ? 0.0 : x);
-            assert !Double.isNaN(xx);
             return Math.nextAfter(xx, d);
         }
     }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -29,7 +29,6 @@
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.nodes.*;
 
 /**
@@ -39,16 +38,23 @@
 
     @Test
     public void testMathSubstitutions() {
-        assertInGraph(assertNotInGraph(test("mathAbs"), IfNode.class), AbsNode.class);     // Java
-        test("math");
-
+        assertInGraph(assertNotInGraph(testGraph("mathAbs"), IfNode.class), AbsNode.class);     // Java
         double value = 34567.891D;
-        assertDeepEquals(Math.sqrt(value), MathSubstitutionsX86.sqrt(value));
-        assertDeepEquals(Math.log(value), MathSubstitutionsX86.log(value));
-        assertDeepEquals(Math.log10(value), MathSubstitutionsX86.log10(value));
-        assertDeepEquals(Math.sin(value), MathSubstitutionsX86.sin(value));
-        assertDeepEquals(Math.cos(value), MathSubstitutionsX86.cos(value));
-        assertDeepEquals(Math.tan(value), MathSubstitutionsX86.tan(value));
+        testGraph("mathCos");
+        testGraph("mathLog");
+        testGraph("mathLog10");
+        testGraph("mathSin");
+        testGraph("mathSqrt");
+        testGraph("mathTan");
+        testGraph("mathAll");
+
+        test("mathCos", value);
+        test("mathLog", value);
+        test("mathLog10", value);
+        test("mathSin", value);
+        test("mathSqrt", value);
+        test("mathTan", value);
+        test("mathAll", value);
     }
 
     @SuppressWarnings("all")
@@ -57,16 +63,44 @@
     }
 
     @SuppressWarnings("all")
-    public static double math(double value) {
+    public static double mathSqrt(double value) {
+        return Math.sqrt(value);
+    }
+
+    @SuppressWarnings("all")
+    public static double mathLog(double value) {
+        return Math.log(value);
+    }
+
+    @SuppressWarnings("all")
+    public static double mathLog10(double value) {
+        return Math.log10(value);
+    }
+
+    @SuppressWarnings("all")
+    public static double mathSin(double value) {
+        return Math.sin(value);
+    }
+
+    @SuppressWarnings("all")
+    public static double mathCos(double value) {
+        return Math.cos(value);
+    }
+
+    @SuppressWarnings("all")
+    public static double mathTan(double value) {
+        return Math.tan(value);
+    }
+
+    @SuppressWarnings("all")
+    public static double mathAll(double value) {
         return Math.sqrt(value) + Math.log(value) + Math.log10(value) + Math.sin(value) + Math.cos(value) + Math.tan(value);
-        // Math.exp(value) +
-        // Math.pow(value, 13);
     }
 
     public void testSubstitution(String testMethodName, Class<?> intrinsicClass, Class<?> holder, String methodName, boolean optional, Object... args) {
         ResolvedJavaMethod realJavaMethod = getResolvedJavaMethod(holder, methodName);
         ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod(testMethodName);
-        StructuredGraph graph = test(testMethodName);
+        StructuredGraph graph = testGraph(testMethodName);
 
         // Check to see if the resulting graph contains the expected node
         StructuredGraph replacement = getReplacements().getMethodSubstitution(realJavaMethod);
@@ -148,8 +182,8 @@
 
     @Test
     public void testFloatSubstitutions() {
-        assertInGraph(test("floatToIntBits"), ReinterpretNode.class); // Java
-        test("intBitsToFloat");
+        assertInGraph(testGraph("floatToIntBits"), ReinterpretNode.class); // Java
+        testGraph("intBitsToFloat");
     }
 
     @SuppressWarnings("all")
@@ -164,8 +198,8 @@
 
     @Test
     public void testDoubleSubstitutions() {
-        assertInGraph(test("doubleToLongBits"), ReinterpretNode.class); // Java
-        test("longBitsToDouble");
+        assertInGraph(testGraph("doubleToLongBits"), ReinterpretNode.class); // Java
+        testGraph("longBitsToDouble");
     }
 
     @SuppressWarnings("all")
@@ -179,22 +213,23 @@
     }
 
     @SuppressWarnings("all")
-    public static boolean isInstance(Class<?> clazz) {
-        return clazz.isInstance(Number.class);
+    public static boolean isInstance(Class<?> clazz, Object object) {
+        return clazz.isInstance(object);
     }
 
     @SuppressWarnings("all")
-    public static boolean isAssignableFrom(Class<?> clazz) {
-        return clazz.isInstance(Number.class);
+    public static boolean isAssignableFrom(Class<?> clazz, Class<?> other) {
+        return clazz.isAssignableFrom(other);
     }
 
     @Test
     public void testClassSubstitutions() {
-        test("isInstance");
+        testGraph("isInstance");
+        testGraph("isAssignableFrom");
         for (Class<?> c : new Class[]{getClass(), Cloneable.class, int[].class, String[][].class}) {
             for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) {
-                assertDeepEquals(c.isInstance(o), ClassSubstitutions.isInstance(c, o));
-                assertDeepEquals(c.isAssignableFrom(o.getClass()), ClassSubstitutions.isAssignableFrom(c, o.getClass()));
+                test("isInstance", c, o);
+                test("isAssignableFrom", c, o.getClass());
             }
         }
     }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StringSubstitutionsTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StringSubstitutionsTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -38,7 +38,7 @@
     public void testSubstitution(String testMethodName, Class<?> intrinsicClass, Class<?> holder, String methodName, boolean optional, Object[] args1, Object[] args2) {
         ResolvedJavaMethod realMethod = getResolvedJavaMethod(holder, methodName);
         ResolvedJavaMethod testMethod = getResolvedJavaMethod(testMethodName);
-        StructuredGraph graph = test(testMethodName);
+        StructuredGraph graph = testGraph(testMethodName);
 
         // Check to see if the resulting graph contains the expected node
         StructuredGraph replacement = getReplacements().getMethodSubstitution(realMethod);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -23,10 +23,6 @@
 package com.oracle.graal.replacements.test;
 
 import static com.oracle.graal.compiler.common.UnsafeAccess.*;
-import static com.oracle.graal.replacements.UnsafeSubstitutions.*;
-
-import java.lang.reflect.*;
-import java.util.concurrent.atomic.*;
 
 import org.junit.*;
 
@@ -71,7 +67,6 @@
     }
 
     static class Foo {
-
         boolean z;
         byte b;
         short s;
@@ -81,130 +76,73 @@
         float f;
         double d;
         Object o;
-
-        void testGet(Field field, long offset, String getName, Object value) throws Exception {
-            field.set(this, value);
-            Method m1 = Unsafe.class.getDeclaredMethod(getName, Object.class, long.class);
-            Method m2 = UnsafeSubstitutions.class.getDeclaredMethod(getName, Object.class, Object.class, long.class);
-            Object expected = m1.invoke(unsafe, this, offset);
-            Object actual = m2.invoke(null, unsafe, this, offset);
-            Assert.assertEquals(expected, actual);
-        }
-
-        void testDirect(Field field, long offset, String type, Object value) throws Exception {
-            if (type.equals("Boolean") || type.equals("Object")) {
-                // No direct memory access for these types
-                return;
-            }
-
-            long address = unsafe.allocateMemory(offset + 16);
-
-            String getName = "get" + type;
-            String putName = "put" + type;
-            Method m1 = Unsafe.class.getDeclaredMethod(putName, long.class, field.getType());
-            Method m2 = Unsafe.class.getDeclaredMethod(getName, long.class);
-
-            Method m3 = UnsafeSubstitutions.class.getDeclaredMethod(putName, Object.class, long.class, field.getType());
-            Method m4 = UnsafeSubstitutions.class.getDeclaredMethod(getName, Object.class, long.class);
-
-            m1.invoke(unsafe, address + offset, value);
-            Object expected = m2.invoke(unsafe, address + offset);
-
-            m3.invoke(null, unsafe, address + offset, value);
-            Object actual = m4.invoke(null, unsafe, address + offset);
-
-            unsafe.freeMemory(address);
-            Assert.assertEquals(expected, actual);
-        }
-
-        void testPut(Field field, long offset, String putName, Object value) throws Exception {
-            Object initialValue = field.get(new Foo());
-            field.set(this, initialValue);
-
-            try {
-                Method m1 = Unsafe.class.getDeclaredMethod(putName, Object.class, long.class, field.getType());
-                Method m2 = UnsafeSubstitutions.class.getDeclaredMethod(putName, Object.class, Object.class, long.class, field.getType());
-                m1.invoke(unsafe, this, offset, value);
-                Object expected = field.get(this);
-                m2.invoke(null, unsafe, this, offset, value);
-                Object actual = field.get(this);
-                Assert.assertEquals(expected, actual);
-            } catch (NoSuchMethodException e) {
-                if (!putName.startsWith("putOrdered")) {
-                    throw e;
-                }
-            }
-        }
-
-        void test(String fieldName, String typeSuffix, Object value) {
-            try {
-                Field field = Foo.class.getDeclaredField(fieldName);
-                long offset = unsafe.objectFieldOffset(field);
-                testGet(field, offset, "get" + typeSuffix, value);
-                testGet(field, offset, "get" + typeSuffix + "Volatile", value);
-                testPut(field, offset, "put" + typeSuffix, value);
-                testPut(field, offset, "put" + typeSuffix + "Volatile", value);
-                testPut(field, offset, "putOrdered" + typeSuffix, value);
-                testDirect(field, offset, typeSuffix, value);
-            } catch (Exception e) {
-                throw new AssertionError(e);
-            }
-        }
     }
 
     @Test
     public void testUnsafeSubstitutions() throws Exception {
-        test("unsafeCompareAndSwapInt");
-        test("unsafeCompareAndSwapLong");
-        test("unsafeCompareAndSwapObject");
+        test("unsafeCompareAndSwapInt", unsafe, supply(() -> new Foo()), fooOffset("i"));
+
+        testGraph("unsafeCompareAndSwapInt");
+        testGraph("unsafeCompareAndSwapLong");
+        testGraph("unsafeCompareAndSwapObject");
+
+        testGraph("unsafeGetBoolean");
+        testGraph("unsafeGetByte");
+        testGraph("unsafeGetShort");
+        testGraph("unsafeGetChar");
+        testGraph("unsafeGetInt");
+        testGraph("unsafeGetLong");
+        testGraph("unsafeGetFloat");
+        testGraph("unsafeGetDouble");
+        testGraph("unsafeGetObject");
 
-        test("unsafeGetBoolean");
-        test("unsafeGetByte");
-        test("unsafeGetShort");
-        test("unsafeGetChar");
-        test("unsafeGetInt");
-        test("unsafeGetLong");
-        test("unsafeGetFloat");
-        test("unsafeGetDouble");
-        test("unsafeGetObject");
+        testGraph("unsafePutBoolean");
+        testGraph("unsafePutByte");
+        testGraph("unsafePutShort");
+        testGraph("unsafePutChar");
+        testGraph("unsafePutInt");
+        testGraph("unsafePutFloat");
+        testGraph("unsafePutDouble");
+        testGraph("unsafePutObject");
 
-        test("unsafePutBoolean");
-        test("unsafePutByte");
-        test("unsafePutShort");
-        test("unsafePutChar");
-        test("unsafePutInt");
-        test("unsafePutFloat");
-        test("unsafePutDouble");
-        test("unsafePutObject");
+        testGraph("unsafeDirectMemoryRead");
+        testGraph("unsafeDirectMemoryWrite");
 
-        test("unsafeDirectMemoryRead");
-        test("unsafeDirectMemoryWrite");
+        test("unsafeCompareAndSwapInt", unsafe, supply(() -> new Foo()), fooOffset("i"));
+        test("unsafeCompareAndSwapLong", unsafe, supply(() -> new Foo()), fooOffset("l"));
+        test("unsafeCompareAndSwapObject", unsafe, supply(() -> new Foo()), fooOffset("o"));
 
-        AtomicInteger a1 = new AtomicInteger(42);
-        AtomicInteger a2 = new AtomicInteger(42);
-        assertDeepEquals(unsafe.compareAndSwapInt(a1, off(a1, "value"), 42, 53), compareAndSwapInt(unsafe, a2, off(a2, "value"), 42, 53));
-        assertDeepEquals(a1.get(), a2.get());
-
-        AtomicLong l1 = new AtomicLong(42);
-        AtomicLong l2 = new AtomicLong(42);
-        assertDeepEquals(unsafe.compareAndSwapLong(l1, off(l1, "value"), 42, 53), compareAndSwapLong(unsafe, l2, off(l2, "value"), 42, 53));
-        assertDeepEquals(l1.get(), l2.get());
+        test("unsafeGetBoolean", unsafe, supply(() -> new Foo()), fooOffset("z"));
+        test("unsafeGetByte", unsafe, supply(() -> new Foo()), fooOffset("b"));
+        test("unsafeGetShort", unsafe, supply(() -> new Foo()), fooOffset("s"));
+        test("unsafeGetChar", unsafe, supply(() -> new Foo()), fooOffset("c"));
+        test("unsafeGetInt", unsafe, supply(() -> new Foo()), fooOffset("i"));
+        test("unsafeGetLong", unsafe, supply(() -> new Foo()), fooOffset("l"));
+        test("unsafeGetFloat", unsafe, supply(() -> new Foo()), fooOffset("f"));
+        test("unsafeGetDouble", unsafe, supply(() -> new Foo()), fooOffset("d"));
+        test("unsafeGetObject", unsafe, supply(() -> new Foo()), fooOffset("o"));
 
-        AtomicReference<String> o1 = new AtomicReference<>("42");
-        AtomicReference<String> o2 = new AtomicReference<>("42");
-        assertDeepEquals(unsafe.compareAndSwapObject(o1, off(o1, "value"), "42", "53"), compareAndSwapObject(unsafe, o2, off(o2, "value"), "42", "53"));
-        assertDeepEquals(o1.get(), o2.get());
+        test("unsafePutBoolean", unsafe, supply(() -> new Foo()), fooOffset("z"), true);
+        test("unsafePutByte", unsafe, supply(() -> new Foo()), fooOffset("b"), (byte) 87);
+        test("unsafePutShort", unsafe, supply(() -> new Foo()), fooOffset("s"), (short) -93);
+        test("unsafePutChar", unsafe, supply(() -> new Foo()), fooOffset("c"), 'A');
+        test("unsafePutInt", unsafe, supply(() -> new Foo()), fooOffset("i"), 42);
+        test("unsafePutFloat", unsafe, supply(() -> new Foo()), fooOffset("f"), 58.0F);
+        test("unsafePutDouble", unsafe, supply(() -> new Foo()), fooOffset("d"), -28736.243465D);
+        test("unsafePutObject", unsafe, supply(() -> new Foo()), fooOffset("i"), "value1", "value2", "value3");
 
-        Foo f1 = new Foo();
-        f1.test("z", "Boolean", Boolean.TRUE);
-        f1.test("b", "Byte", Byte.MIN_VALUE);
-        f1.test("s", "Short", Short.MAX_VALUE);
-        f1.test("c", "Char", '!');
-        f1.test("i", "Int", 1010010);
-        f1.test("f", "Float", -34.5F);
-        f1.test("l", "Long", 99999L);
-        f1.test("d", "Double", 1234.5678D);
-        f1.test("o", "Object", "object");
+        long address = unsafe.allocateMemory(8 * Kind.values().length);
+        test("unsafeDirectMemoryRead", unsafe, address);
+        test("unsafeDirectMemoryWrite", unsafe, address, 0xCAFEBABEDEADBABEL);
+        unsafe.freeMemory(address);
+    }
+
+    private static long fooOffset(String name) {
+        try {
+            return unsafe.objectFieldOffset(Foo.class.getDeclaredField(name));
+        } catch (NoSuchFieldException | SecurityException e) {
+            throw new AssertionError(e);
+        }
     }
 
     @SuppressWarnings("all")
@@ -268,78 +206,126 @@
     }
 
     @SuppressWarnings("all")
-    public static void unsafePutBoolean(Unsafe unsafe, Object obj, long offset, boolean value) {
+    public static int unsafePutBoolean(Unsafe unsafe, Object obj, long offset, boolean value) {
+        int res = 1;
         unsafe.putBoolean(obj, offset, value);
+        res += unsafe.getBoolean(obj, offset) ? 3 : 5;
         unsafe.putBooleanVolatile(obj, offset, value);
+        res += unsafe.getBoolean(obj, offset) ? 7 : 11;
+        return res;
     }
 
     @SuppressWarnings("all")
-    public static void unsafePutByte(Unsafe unsafe, Object obj, long offset, byte value) {
-        unsafe.putByte(obj, offset, value);
-        unsafe.putByteVolatile(obj, offset, value);
+    public static int unsafePutByte(Unsafe unsafe, Object obj, long offset, byte value) {
+        int res = 1;
+        unsafe.putByte(obj, offset, (byte) (value + 1));
+        res += unsafe.getByte(obj, offset);
+        unsafe.putByteVolatile(obj, offset, (byte) (value + 2));
+        res += unsafe.getByte(obj, offset);
+        return res;
     }
 
     @SuppressWarnings("all")
-    public static void unsafePutShort(Unsafe unsafe, Object obj, long offset, short value) {
-        unsafe.putShort(obj, offset, value);
-        unsafe.putShortVolatile(obj, offset, value);
+    public static int unsafePutShort(Unsafe unsafe, Object obj, long offset, short value) {
+        int res = 1;
+        unsafe.putShort(obj, offset, (short) (value + 1));
+        res += unsafe.getShort(obj, offset);
+        unsafe.putShortVolatile(obj, offset, (short) (value + 2));
+        res += unsafe.getShort(obj, offset);
+        return res;
     }
 
     @SuppressWarnings("all")
-    public static void unsafePutChar(Unsafe unsafe, Object obj, long offset, char value) {
-        unsafe.putChar(obj, offset, value);
-        unsafe.putCharVolatile(obj, offset, value);
+    public static int unsafePutChar(Unsafe unsafe, Object obj, long offset, char value) {
+        int res = 1;
+        unsafe.putChar(obj, offset, (char) (value + 1));
+        res += unsafe.getChar(obj, offset);
+        unsafe.putCharVolatile(obj, offset, (char) (value + 2));
+        res += unsafe.getChar(obj, offset);
+        return res;
     }
 
     @SuppressWarnings("all")
-    public static void unsafePutInt(Unsafe unsafe, Object obj, long offset, int value) {
+    public static int unsafePutInt(Unsafe unsafe, Object obj, long offset, int value) {
+        int res = 1;
         unsafe.putInt(obj, offset, value);
-        unsafe.putIntVolatile(obj, offset, value);
-        unsafe.putOrderedInt(obj, offset, value);
+        res += unsafe.getInt(obj, offset);
+        unsafe.putIntVolatile(obj, offset, value + 1);
+        res += unsafe.getInt(obj, offset);
+        unsafe.putOrderedInt(obj, offset, value + 2);
+        res += unsafe.getInt(obj, offset);
+        return res;
     }
 
     @SuppressWarnings("all")
-    public static void unsafePutLong(Unsafe unsafe, Object obj, long offset, long value) {
-        unsafe.putLong(obj, offset, value);
-        unsafe.putLongVolatile(obj, offset, value);
-        unsafe.putOrderedLong(obj, offset, value);
+    public static long unsafePutLong(Unsafe unsafe, Object obj, long offset, long value) {
+        long res = 1;
+        unsafe.putLong(obj, offset, value + 1);
+        res += unsafe.getLong(obj, offset);
+        unsafe.putLongVolatile(obj, offset, value + 2);
+        res += unsafe.getLong(obj, offset);
+        unsafe.putOrderedLong(obj, offset, value + 3);
+        res += unsafe.getLong(obj, offset);
+        return res;
     }
 
     @SuppressWarnings("all")
-    public static void unsafePutFloat(Unsafe unsafe, Object obj, long offset, float value) {
-        unsafe.putFloat(obj, offset, value);
-        unsafe.putFloatVolatile(obj, offset, value);
+    public static float unsafePutFloat(Unsafe unsafe, Object obj, long offset, float value) {
+        float res = 1;
+        unsafe.putFloat(obj, offset, value + 1.0F);
+        res += unsafe.getFloat(obj, offset);
+        unsafe.putFloatVolatile(obj, offset, value + 2.0F);
+        res += unsafe.getFloat(obj, offset);
+        return res;
     }
 
     @SuppressWarnings("all")
-    public static void unsafePutDouble(Unsafe unsafe, Object obj, long offset, double value) {
+    public static double unsafePutDouble(Unsafe unsafe, Object obj, long offset, double value) {
+        double res = 1;
         unsafe.putDouble(obj, offset, value);
+        res += unsafe.getDouble(obj, offset);
         unsafe.putDoubleVolatile(obj, offset, value);
+        res += unsafe.getDouble(obj, offset);
+        return res;
     }
 
     @SuppressWarnings("all")
-    public static void unsafePutObject(Unsafe unsafe, Object obj, long offset, Object value) {
-        unsafe.putObject(obj, offset, value);
-        unsafe.putObjectVolatile(obj, offset, value);
-        unsafe.putOrderedObject(obj, offset, value);
+    public static Object[] unsafePutObject(Unsafe unsafe, Object obj, long offset, Object value1, Object value2, Object value3) {
+        Object[] res = new Object[3];
+        unsafe.putObject(obj, offset, value1);
+        res[0] = unsafe.getObject(obj, offset);
+        unsafe.putObjectVolatile(obj, offset, value2);
+        res[1] = unsafe.getObject(obj, offset);
+        unsafe.putOrderedObject(obj, offset, value3);
+        res[2] = unsafe.getObject(obj, offset);
+        return res;
     }
 
     @SuppressWarnings("all")
     public static double unsafeDirectMemoryRead(Unsafe unsafe, long address) {
         // Unsafe.getBoolean(long) and Unsafe.getObject(long) do not exist
-        return unsafe.getByte(address) + unsafe.getShort(address) + unsafe.getChar(address) + unsafe.getInt(address) + unsafe.getLong(address) + unsafe.getFloat(address) + unsafe.getDouble(address);
+        // @formatter:off
+        return unsafe.getByte(address) +
+               unsafe.getShort(address + 8) +
+               unsafe.getChar(address + 16) +
+               unsafe.getInt(address + 24) +
+               unsafe.getLong(address + 32) +
+               unsafe.getFloat(address + 40) +
+               unsafe.getDouble(address + 48);
+        // @formatter:on
     }
 
     @SuppressWarnings("all")
-    public static void unsafeDirectMemoryWrite(Unsafe unsafe, long address, byte value) {
+    public static double unsafeDirectMemoryWrite(Unsafe unsafe, long address, long value) {
         // Unsafe.putBoolean(long) and Unsafe.putObject(long) do not exist
-        unsafe.putByte(address, value);
-        unsafe.putShort(address, value);
-        unsafe.putChar(address, (char) value);
-        unsafe.putInt(address, value);
-        unsafe.putLong(address, value);
-        unsafe.putFloat(address, value);
-        unsafe.putDouble(address, value);
+        unsafe.putByte(address + 0, (byte) value);
+        unsafe.putShort(address + 8, (short) value);
+        unsafe.putChar(address + 16, (char) value);
+        unsafe.putInt(address + 24, (int) value);
+        unsafe.putLong(address + 32, value);
+        unsafe.putFloat(address + 40, value);
+        unsafe.putDouble(address + 48, value);
+        return unsafeDirectMemoryRead(unsafe, address);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -30,7 +30,6 @@
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
-import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
 import com.oracle.graal.word.*;
 
 /**
@@ -41,14 +40,12 @@
     private final ReplacementsImpl installer;
 
     public WordTest() {
-        installer = new ReplacementsImpl(getProviders(), getSnippetReflection(), getTarget());
+        installer = (ReplacementsImpl) getReplacements();
     }
 
-    private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
-
     @Override
     protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
-        return installer.makeGraph(m, null, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect);
+        return installer.makeGraph(m, null, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/NodeIntrinsicVerifier.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/NodeIntrinsicVerifier.java	Thu Mar 12 15:59:01 2015 +0100
@@ -75,6 +75,9 @@
         if (!intrinsicMethod.getModifiers().contains(Modifier.STATIC)) {
             env.getMessager().printMessage(Kind.ERROR, String.format("A @%s method must be static.", NodeIntrinsic.class.getSimpleName()), element, annotation);
         }
+        if (!intrinsicMethod.getModifiers().contains(Modifier.NATIVE)) {
+            env.getMessager().printMessage(Kind.ERROR, String.format("A @%s method must be native.", NodeIntrinsic.class.getSimpleName()), element, annotation);
+        }
 
         TypeMirror nodeClassMirror = resolveAnnotationValue(TypeMirror.class, findAnnotationValue(annotation, NODE_CLASS_NAME));
         TypeElement nodeClass = (TypeElement) env.getTypeUtils().asElement(nodeClassMirror);
@@ -89,6 +92,10 @@
             }
         }
 
+        if (intrinsicMethod.getReturnType() instanceof TypeVariable) {
+            env.getMessager().printMessage(Kind.ERROR, "@NodeIntrinsic cannot have a generic return type.", element, annotation);
+        }
+
         if (isNodeType(nodeClass)) {
             if (nodeClass.getModifiers().contains(Modifier.ABSTRACT)) {
                 env.getMessager().printMessage(Kind.ERROR, String.format("Cannot make @NodeIntrinsic for abstract node class %s.", nodeClass.getSimpleName()), element, annotation);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraySubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraySubstitutions.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,6 +22,9 @@
  */
 package com.oracle.graal.replacements;
 
+import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
+
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
@@ -36,19 +39,19 @@
     public static Object newInstance(Class<?> componentType, int length) throws NegativeArraySizeException {
         // The error cases must be handled here since DynamicNewArrayNode can only deoptimize the
         // caller in response to exceptions.
-        if (length < 0) {
-            throw new NegativeArraySizeException();
+        if (probability(SLOW_PATH_PROBABILITY, length < 0)) {
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
-        if (componentType == void.class) {
-            throw new IllegalArgumentException();
+        if (probability(SLOW_PATH_PROBABILITY, componentType == void.class)) {
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
-        return DynamicNewArrayNode.newArray(GuardingPiNode.guardingNonNull(componentType), length);
+        return DynamicNewArrayNode.newArray(GuardingPiNode.asNonNullClass(componentType), length);
     }
 
     @MethodSubstitution
     public static int getLength(Object array) {
         if (!array.getClass().isArray()) {
-            throw new IllegalArgumentException("Argument is not an array");
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
         return ArrayLengthNode.arrayLength(array);
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BlackholeSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +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.replacements;
-
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.debug.*;
-
-/**
- * Substitutions for both the old and new versions of JMH Blackhole helper classes.
- */
-@ClassSubstitution(className = {"org.openjdk.jmh.infra.Blackhole", "org.openjdk.jmh.logic.BlackHole"}, optional = true)
-public class BlackholeSubstitutions {
-
-    @SuppressWarnings("unused")
-    @MethodSubstitution(isStatic = false, forced = true)
-    public static void consume(final Object thisObj, Object v) {
-        BlackholeNode.consume(v);
-    }
-
-    @SuppressWarnings("unused")
-    @MethodSubstitution(isStatic = false, forced = true)
-    public static void consume(final Object thisObj, Object[] v) {
-        BlackholeNode.consume(v);
-    }
-
-    @SuppressWarnings("unused")
-    @MethodSubstitution(isStatic = false, forced = true)
-    public static void consume(final Object thisObj, byte v) {
-        BlackholeNode.consume(v);
-    }
-
-    @SuppressWarnings("unused")
-    @MethodSubstitution(isStatic = false, forced = true)
-    public static void consume(final Object thisObj, boolean v) {
-        BlackholeNode.consume(v);
-    }
-
-    @SuppressWarnings("unused")
-    @MethodSubstitution(isStatic = false, forced = true)
-    public static void consume(final Object thisObj, char v) {
-        BlackholeNode.consume(v);
-    }
-
-    @SuppressWarnings("unused")
-    @MethodSubstitution(isStatic = false, forced = true)
-    public static void consume(final Object thisObj, short v) {
-        BlackholeNode.consume(v);
-    }
-
-    @SuppressWarnings("unused")
-    @MethodSubstitution(isStatic = false, forced = true)
-    public static void consume(final Object thisObj, int v) {
-        BlackholeNode.consume(v);
-    }
-
-    @SuppressWarnings("unused")
-    @MethodSubstitution(isStatic = false, forced = true)
-    public static void consume(final Object thisObj, long v) {
-        BlackholeNode.consume(v);
-    }
-
-    @SuppressWarnings("unused")
-    @MethodSubstitution(isStatic = false, forced = true)
-    public static void consume(final Object thisObj, float v) {
-        BlackholeNode.consume(v);
-    }
-
-    @SuppressWarnings("unused")
-    @MethodSubstitution(isStatic = false, forced = true)
-    public static void consume(final Object thisObj, double v) {
-        BlackholeNode.consume(v);
-    }
-}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Thu Mar 12 15:59:01 2015 +0100
@@ -77,49 +77,49 @@
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
-    public static Boolean booleanValueOf(boolean value) {
+    public static Object booleanValueOf(boolean value) {
         valueOfCounter.inc();
         return PiNode.piCast(Boolean.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
-    public static Byte byteValueOf(byte value) {
+    public static Object byteValueOf(byte value) {
         valueOfCounter.inc();
         return PiNode.piCast(Byte.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
-    public static Character charValueOf(char value) {
+    public static Object charValueOf(char value) {
         valueOfCounter.inc();
         return PiNode.piCast(Character.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
-    public static Double doubleValueOf(double value) {
+    public static Object doubleValueOf(double value) {
         valueOfCounter.inc();
         return PiNode.piCast(Double.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
-    public static Float floatValueOf(float value) {
+    public static Object floatValueOf(float value) {
         valueOfCounter.inc();
         return PiNode.piCast(Float.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
-    public static Integer intValueOf(int value) {
+    public static Object intValueOf(int value) {
         valueOfCounter.inc();
         return PiNode.piCast(Integer.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
-    public static Long longValueOf(long value) {
+    public static Object longValueOf(long value) {
         valueOfCounter.inc();
         return PiNode.piCast(Long.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
-    public static Short shortValueOf(short value) {
+    public static Object shortValueOf(short value) {
         valueOfCounter.inc();
         return PiNode.piCast(Short.valueOf(value), StampFactory.forNodeIntrinsic());
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-/*
- * Copyright (c) 2012, 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.replacements;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-
-public class BoxingSubstitutions {
-
-    @ClassSubstitution(Boolean.class)
-    private static class BooleanSubstitutions {
-
-        @MethodSubstitution(forced = true)
-        public static Boolean valueOf(boolean value) {
-            return BoxNode.box(value, Boolean.class, Kind.Boolean);
-        }
-
-        @MethodSubstitution(isStatic = false, forced = true)
-        public static boolean booleanValue(Boolean value) {
-            return UnboxNode.unbox(value, Kind.Boolean);
-        }
-    }
-
-    @ClassSubstitution(Byte.class)
-    private static class ByteSubstitutions {
-
-        @MethodSubstitution(forced = true)
-        public static Byte valueOf(byte value) {
-            return BoxNode.box(value, Byte.class, Kind.Byte);
-        }
-
-        @MethodSubstitution(isStatic = false, forced = true)
-        public static byte byteValue(Byte value) {
-            return UnboxNode.unbox(value, Kind.Byte);
-        }
-    }
-
-    @ClassSubstitution(Character.class)
-    private static class CharacterSubstitutions {
-
-        @MethodSubstitution(forced = true)
-        public static Character valueOf(char value) {
-            return BoxNode.box(value, Character.class, Kind.Char);
-        }
-
-        @MethodSubstitution(isStatic = false, forced = true)
-        public static char charValue(Character value) {
-            return UnboxNode.unbox(value, Kind.Char);
-        }
-    }
-
-    @ClassSubstitution(Double.class)
-    private static class DoubleSubstitutions {
-
-        @MethodSubstitution(forced = true)
-        public static Double valueOf(double value) {
-            return BoxNode.box(value, Double.class, Kind.Double);
-        }
-
-        @MethodSubstitution(isStatic = false, forced = true)
-        public static double doubleValue(Double value) {
-            return UnboxNode.unbox(value, Kind.Double);
-        }
-    }
-
-    @ClassSubstitution(Float.class)
-    private static class FloatSubstitutions {
-
-        @MethodSubstitution(forced = true)
-        public static Float valueOf(float value) {
-            return BoxNode.box(value, Float.class, Kind.Float);
-        }
-
-        @MethodSubstitution(isStatic = false, forced = true)
-        public static float floatValue(Float value) {
-            return UnboxNode.unbox(value, Kind.Float);
-        }
-    }
-
-    @ClassSubstitution(Integer.class)
-    private static class IntegerSubstitutions {
-
-        @MethodSubstitution(forced = true)
-        public static Integer valueOf(int value) {
-            return BoxNode.box(value, Integer.class, Kind.Int);
-        }
-
-        @MethodSubstitution(isStatic = false, forced = true)
-        public static int intValue(Integer value) {
-            return UnboxNode.unbox(value, Kind.Int);
-        }
-    }
-
-    @ClassSubstitution(Long.class)
-    private static class LongSubstitutions {
-
-        @MethodSubstitution(forced = true)
-        public static Long valueOf(long value) {
-            return BoxNode.box(value, Long.class, Kind.Long);
-        }
-
-        @MethodSubstitution(isStatic = false, forced = true)
-        public static long longValue(Long value) {
-            return UnboxNode.unbox(value, Kind.Long);
-        }
-    }
-
-    @ClassSubstitution(Short.class)
-    private static class ShortSubstitutions {
-
-        @MethodSubstitution(forced = true)
-        public static Short valueOf(short value) {
-            return BoxNode.box(value, Short.class, Kind.Short);
-        }
-
-        @MethodSubstitution(isStatic = false, forced = true)
-        public static short shortValue(Short value) {
-            return UnboxNode.unbox(value, Kind.Short);
-        }
-    }
-
-    public static void registerReplacements(Replacements replacements) {
-        replacements.registerSubstitutions(Boolean.class, BooleanSubstitutions.class);
-        replacements.registerSubstitutions(Character.class, CharacterSubstitutions.class);
-        replacements.registerSubstitutions(Double.class, DoubleSubstitutions.class);
-        replacements.registerSubstitutions(Byte.class, ByteSubstitutions.class);
-        replacements.registerSubstitutions(Float.class, FloatSubstitutions.class);
-        replacements.registerSubstitutions(Integer.class, IntegerSubstitutions.class);
-        replacements.registerSubstitutions(Short.class, ShortSubstitutions.class);
-        replacements.registerSubstitutions(Long.class, LongSubstitutions.class);
-    }
-}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CharacterSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2014, 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 com.oracle.graal.api.replacements.*;
-import com.oracle.graal.replacements.nodes.*;
-
-@ClassSubstitution(Character.class)
-public class CharacterSubstitutions {
-    @MethodSubstitution
-    public static char reverseBytes(char i) {
-        return (char) (ReverseBytesNode.reverse(i) >> 16);
-    }
-}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ClassSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +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.replacements;
-
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.calc.*;
-
-/**
- * Substitutions for {@link java.lang.Class} methods.
- */
-@ClassSubstitution(java.lang.Class.class)
-public class ClassSubstitutions {
-
-    @MethodSubstitution(isStatic = false)
-    public static boolean isInstance(Class<?> thisObj, Object obj) {
-        return ConditionalNode.materializeIsInstance(thisObj, obj);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static boolean isAssignableFrom(Class<?> thisClass, Class<?> otherClass) {
-        return ConditionalNode.materializeIsAssignableFrom(thisClass, otherClass);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ConstantBindingParameterPlugin.java	Thu Mar 12 15:59:01 2015 +0100
@@ -0,0 +1,73 @@
+/*
+ * 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 com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugin.ParameterPlugin;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+
+/**
+ * A {@link ParameterPlugin} that binds constant values to some parameters.
+ */
+public class ConstantBindingParameterPlugin implements ParameterPlugin {
+    private final Object[] constantArgs;
+    private final ParameterPlugin delegate;
+    private final MetaAccessProvider metaAccess;
+    private final SnippetReflectionProvider snippetReflection;
+
+    /**
+     * Creates a plugin that will create {@link ConstantNode}s for each parameter with an index
+     * equal to that of a non-null object in {@code constantArgs} (from which the
+     * {@link ConstantNode} is created if it isn't already a {@link ConstantNode}). For all other
+     * parameter indexes, {@code delegate} is applied if it is non-null.
+     */
+    public ConstantBindingParameterPlugin(Object[] constantArgs, ParameterPlugin delegate, MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection) {
+        this.constantArgs = constantArgs;
+        this.delegate = delegate;
+        this.metaAccess = metaAccess;
+        this.snippetReflection = snippetReflection;
+    }
+
+    public FloatingNode interceptParameter(GraphBuilderContext b, int index, Stamp stamp) {
+        Object arg = constantArgs[index];
+        if (arg != null) {
+            ConstantNode constantNode;
+            if (arg instanceof ConstantNode) {
+                constantNode = (ConstantNode) arg;
+            } else if (arg instanceof Constant) {
+                constantNode = ConstantNode.forConstant(stamp, (Constant) arg, metaAccess);
+            } else {
+                constantNode = ConstantNode.forConstant(snippetReflection.forBoxed(stamp.getStackKind(), arg), metaAccess);
+            }
+            return constantNode;
+        }
+        if (delegate != null) {
+            return delegate.interceptParameter(b, index, stamp);
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Thu Mar 12 15:59:01 2015 +0100
@@ -0,0 +1,127 @@
+/*
+ * 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.meta.MetaUtil.*;
+import static com.oracle.graal.replacements.NodeIntrinsificationPhase.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugin.GenericInvocationPlugin;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.word.*;
+
+/**
+ * An {@link GenericInvocationPlugin} that handles methods annotated by {@link Fold},
+ * {@link NodeIntrinsic} and all annotations supported by a given {@link WordOperationPlugin}.
+ */
+public class DefaultGenericInvocationPlugin implements GenericInvocationPlugin {
+    protected final NodeIntrinsificationPhase nodeIntrinsification;
+    protected final WordOperationPlugin wordOperationPlugin;
+
+    public DefaultGenericInvocationPlugin(NodeIntrinsificationPhase nodeIntrinsification, WordOperationPlugin wordOperationPlugin) {
+        this.nodeIntrinsification = nodeIntrinsification;
+        this.wordOperationPlugin = wordOperationPlugin;
+    }
+
+    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        if (wordOperationPlugin.apply(b, method, args)) {
+            return true;
+        } else if (b.parsingReplacement() || b.eagerResolving()) {
+            NodeIntrinsic intrinsic = nodeIntrinsification.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) {
+                        ResolvedJavaType resolvedReturnType = (ResolvedJavaType) returnType;
+                        WordTypes wordTypes = wordOperationPlugin.getWordTypes();
+                        if (wordTypes.isWord(resolvedReturnType)) {
+                            stamp = wordTypes.getWordStamp(resolvedReturnType);
+                        } else {
+                            stamp = StampFactory.declared(resolvedReturnType);
+                        }
+                    }
+                }
+
+                return processNodeIntrinsic(b, method, intrinsic, Arrays.asList(args), returnKind, stamp);
+            } else if (nodeIntrinsification.isFoldable(method)) {
+                ResolvedJavaType[] parameterTypes = resolveJavaTypes(method.toParameterTypes(), method.getDeclaringClass());
+                JavaConstant constant = nodeIntrinsification.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 = b.append(ConstantNode.forConstant(constant, b.getMetaAccess()));
+                        b.push(res.getKind().getStackKind(), b.append(res));
+                    } else {
+                        // This must be a void invoke
+                        assert method.getSignature().getReturnKind() == Kind.Void;
+                    }
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    protected boolean processNodeIntrinsic(GraphBuilderContext b, ResolvedJavaMethod method, NodeIntrinsic intrinsic, List<ValueNode> args, Kind returnKind, Stamp stamp) {
+        ValueNode res = createNodeIntrinsic(b, method, intrinsic, args, stamp);
+        if (res == null) {
+            return false;
+        }
+        if (res instanceof UnsafeCopyNode) {
+            UnsafeCopyNode copy = (UnsafeCopyNode) res;
+            UnsafeLoadNode value = b.append(new UnsafeLoadNode(copy.sourceObject(), copy.sourceOffset(), copy.accessKind(), copy.getLocationIdentity()));
+            b.append(new UnsafeStoreNode(copy.destinationObject(), copy.destinationOffset(), value, copy.accessKind(), copy.getLocationIdentity()));
+            return true;
+        } else if (res instanceof ForeignCallNode) {
+            ForeignCallNode foreign = (ForeignCallNode) res;
+            foreign.setBci(b.bci());
+        }
+
+        res = b.append(res);
+        if (returnKind != Kind.Void) {
+            assert res.getKind().getStackKind() != Kind.Void;
+            b.push(returnKind.getStackKind(), res);
+        } else {
+            assert res.getKind().getStackKind() == Kind.Void;
+        }
+
+        return true;
+    }
+
+    protected ValueNode createNodeIntrinsic(GraphBuilderContext b, ResolvedJavaMethod method, NodeIntrinsic intrinsic, List<ValueNode> args, Stamp stamp) {
+        ValueNode res = nodeIntrinsification.createIntrinsicNode(args, stamp, method, b.getGraph(), intrinsic);
+        assert res != null || b.getRootMethod().getAnnotation(Snippet.class) != null : String.format(
+                        "Could not create node intrinsic for call to %s as one of the arguments expected to be constant isn't: arguments=%s", method.format("%H.%n(%p)"), args);
+        return res;
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DoubleSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.calc.*;
-
-/**
- * Substitutions for {@link java.lang.Double} methods.
- */
-@ClassSubstitution(java.lang.Double.class)
-public class DoubleSubstitutions {
-
-    private static final long NAN_RAW_LONG_BITS = Double.doubleToRawLongBits(Double.NaN);
-
-    @MethodSubstitution
-    public static long doubleToRawLongBits(double value) {
-        return ReinterpretNode.reinterpret(Kind.Long, value);
-    }
-
-    // TODO This method is not necessary, since the JDK method does exactly this
-    @MethodSubstitution
-    public static long doubleToLongBits(double value) {
-        if (value != value) {
-            return NAN_RAW_LONG_BITS;
-        } else {
-            return doubleToRawLongBits(value);
-        }
-    }
-
-    @MethodSubstitution
-    public static double longBitsToDouble(long bits) {
-        return ReinterpretNode.reinterpret(Kind.Double, bits);
-    }
-}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/EdgesSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * Substitutions for improving the performance of some critical methods in {@link Edges}. These
- * substitutions improve the performance by forcing the relevant methods to be inlined
- * (intrinsification being a special form of inlining) and removing a checked cast. The latter
- * cannot be done directly in Java code as {@link DeferredPiNode} is not available to the project
- * containing {@link Edges}.
- */
-@ClassSubstitution(Edges.class)
-public class EdgesSubstitutions {
-
-    @MethodSubstitution
-    private static Node getNodeUnsafe(Node node, long offset) {
-        return PiNode.piCast(UnsafeLoadNode.load(node, offset, Kind.Object, LocationIdentity.ANY_LOCATION), Node.class);
-    }
-
-    @MethodSubstitution
-    private static NodeList<?> getNodeListUnsafe(Node node, long offset) {
-        return PiNode.piCast(UnsafeLoadNode.load(node, offset, Kind.Object, LocationIdentity.ANY_LOCATION), NodeList.class);
-    }
-}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/FloatSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.calc.*;
-
-/**
- * Substitutions for {@link java.lang.Float} methods.
- */
-@ClassSubstitution(java.lang.Float.class)
-public class FloatSubstitutions {
-
-    private static final int NAN_RAW_INT_BITS = Float.floatToRawIntBits(Float.NaN);
-
-    @MethodSubstitution
-    public static int floatToRawIntBits(float value) {
-        return ReinterpretNode.reinterpret(Kind.Int, value);
-    }
-
-    // TODO This method is not necessary, since the JDK method does exactly this
-    @MethodSubstitution
-    public static int floatToIntBits(float value) {
-        if (value != value) {
-            return NAN_RAW_INT_BITS;
-        } else {
-            return floatToRawIntBits(value);
-        }
-    }
-
-    @MethodSubstitution
-    public static float intBitsToFloat(int bits) {
-        return ReinterpretNode.reinterpret(Kind.Float, bits);
-    }
-}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalDirectivesSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,153 +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.replacements;
-
-import com.oracle.graal.api.directives.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.debug.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-
-@ClassSubstitution(GraalDirectives.class)
-public class GraalDirectivesSubstitutions {
-
-    @MethodSubstitution(forced = true)
-    public static void deoptimize() {
-        DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static void deoptimizeAndInvalidate() {
-        DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static boolean inCompiledCode() {
-        return true;
-    }
-
-    /*
-     * This needs to be a @MacroSubstitution, not a @MethodSubstitution, because we want to get a
-     * unique ControlFlowAnchorNode for each occurrence of this call. With @MethodSubstitution, we
-     * would get a clone of a single cached node.
-     */
-    @MacroSubstitution(forced = true, macro = ControlFlowAnchorNode.class)
-    public static native void controlFlowAnchor();
-
-    @MethodSubstitution(forced = true)
-    public static boolean injectBranchProbability(double probability, boolean condition) {
-        return BranchProbabilityNode.probability(probability, condition);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static void blackhole(boolean value) {
-        BlackholeNode.consume(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static void blackhole(byte value) {
-        BlackholeNode.consume(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static void blackhole(short value) {
-        BlackholeNode.consume(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static void blackhole(char value) {
-        BlackholeNode.consume(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static void blackhole(int value) {
-        BlackholeNode.consume(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static void blackhole(long value) {
-        BlackholeNode.consume(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static void blackhole(float value) {
-        BlackholeNode.consume(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static void blackhole(double value) {
-        BlackholeNode.consume(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static void blackhole(Object value) {
-        BlackholeNode.consume(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static boolean opaque(boolean value) {
-        return OpaqueNode.opaque(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static byte opaque(byte value) {
-        return OpaqueNode.opaque(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static short opaque(short value) {
-        return OpaqueNode.opaque(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static char opaque(char value) {
-        return OpaqueNode.opaque(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static int opaque(int value) {
-        return OpaqueNode.opaque(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static long opaque(long value) {
-        return OpaqueNode.opaque(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static float opaque(float value) {
-        return OpaqueNode.opaque(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static double opaque(double value) {
-        return OpaqueNode.opaque(value);
-    }
-
-    @MethodSubstitution(forced = true)
-    public static <T> T opaque(T value) {
-        return OpaqueNode.opaque(value);
-    }
-}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Thu Mar 12 15:59:01 2015 +0100
@@ -28,13 +28,10 @@
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.directives.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.options.*;
 
 /**
  * Method substitutions that are VM-independent.
@@ -42,39 +39,14 @@
 @ServiceProvider(ReplacementsProvider.class)
 public class GraalMethodSubstitutions implements ReplacementsProvider {
 
-    static class Options {
-        @Option(help = "") public static final OptionValue<Boolean> UseBlackholeSubstitution = new OptionValue<>(true);
-    }
-
     public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
-        BoxingSubstitutions.registerReplacements(replacements);
-        replacements.registerSubstitutions(GraalDirectives.class, GraalDirectivesSubstitutions.class);
         if (Intrinsify.getValue()) {
             replacements.registerSubstitutions(Arrays.class, ArraysSubstitutions.class);
             replacements.registerSubstitutions(Array.class, ArraySubstitutions.class);
             replacements.registerSubstitutions(String.class, StringSubstitutions.class);
             replacements.registerSubstitutions(Math.class, MathSubstitutionsX86.class);
-            replacements.registerSubstitutions(Double.class, DoubleSubstitutions.class);
-            replacements.registerSubstitutions(Float.class, FloatSubstitutions.class);
             replacements.registerSubstitutions(Long.class, LongSubstitutions.class);
             replacements.registerSubstitutions(Integer.class, IntegerSubstitutions.class);
-            replacements.registerSubstitutions(Character.class, CharacterSubstitutions.class);
-            replacements.registerSubstitutions(Short.class, ShortSubstitutions.class);
-            replacements.registerSubstitutions(UnsignedMath.class, UnsignedMathSubstitutions.class);
-            replacements.registerSubstitutions(Edges.class, EdgesSubstitutions.class);
-            replacements.registerSubstitutions(Class.class, ClassSubstitutions.class);
-        }
-        if (Options.UseBlackholeSubstitution.getValue()) {
-            replacements.registerSubstitutions(new Type() {
-                public String getTypeName() {
-                    return "org.openjdk.jmh.infra.Blackhole";
-                }
-            }, BlackholeSubstitutions.class);
-            replacements.registerSubstitutions(new Type() {
-                public String getTypeName() {
-                    return "org.openjdk.jmh.logic.BlackHole";
-                }
-            }, BlackholeSubstitutions.class);
         }
     }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Thu Mar 12 15:59:01 2015 +0100
@@ -27,18 +27,18 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
-import com.oracle.graal.word.phases.*;
+import com.oracle.graal.word.*;
 
 /**
  * A utility for manually creating a graph. This will be expanded as necessary to support all
@@ -49,6 +49,7 @@
 
     protected final Providers providers;
     protected final StructuredGraph graph;
+    protected final WordTypes wordTypes;
     protected FixedWithNextNode lastFixedNode;
 
     private final List<Structure> structures;
@@ -56,9 +57,10 @@
     abstract static class Structure {
     }
 
-    public GraphKit(StructuredGraph graph, Providers providers) {
+    public GraphKit(StructuredGraph graph, Providers providers, WordTypes wordTypes) {
         this.providers = providers;
         this.graph = graph;
+        this.wordTypes = wordTypes;
         this.lastFixedNode = graph.start();
 
         structures = new ArrayList<>();
@@ -77,14 +79,21 @@
      * @return a node similar to {@code node} if one exists, otherwise {@code node}
      */
     public <T extends FloatingNode> T unique(T node) {
-        return graph.unique(node);
+        return graph.unique(changeToWord(node));
+    }
+
+    public <T extends ValueNode> T changeToWord(T node) {
+        if (wordTypes.isWord(node)) {
+            node.setStamp(wordTypes.getWordStamp(StampTool.typeOrNull(node)));
+        }
+        return node;
     }
 
     /**
      * Appends a fixed node to the graph.
      */
     public <T extends FixedNode> T append(T node) {
-        T result = graph.add(node);
+        T result = graph.add(changeToWord(node));
         assert lastFixedNode != null;
         assert result.predecessor() == null;
         graph.addAfterFixed(lastFixedNode, result);
@@ -135,11 +144,11 @@
 
         if (frameStateBuilder != null) {
             if (invoke.getKind() != Kind.Void) {
-                frameStateBuilder.push(invoke.getKind(), invoke);
+                frameStateBuilder.push(returnType.getKind(), invoke);
             }
             invoke.setStateAfter(frameStateBuilder.create(bci));
             if (invoke.getKind() != Kind.Void) {
-                frameStateBuilder.pop(invoke.getKind());
+                frameStateBuilder.pop(returnType.getKind());
             }
         }
         return invoke;
@@ -162,15 +171,15 @@
         if (signature.getParameterCount(!isStatic) != args.length) {
             throw new AssertionError(graph + ": wrong number of arguments to " + method);
         }
-        int paramNum = 0;
-        for (int i = 0; i != args.length; i++) {
-            Kind expected;
-            if (i == 0 && !isStatic) {
-                expected = Kind.Object;
-            } else {
-                expected = signature.getParameterKind(paramNum++).getStackKind();
-            }
-            Kind actual = args[i].stamp().getStackKind();
+        int argIndex = 0;
+        if (!isStatic) {
+            Kind expected = wordTypes.asKind(method.getDeclaringClass());
+            Kind actual = args[argIndex++].stamp().getStackKind();
+            assert expected == actual : graph + ": wrong kind of value for receiver argument of call to " + method + " [" + actual + " != " + expected + "]";
+        }
+        for (int i = 0; i != signature.getParameterCount(false); i++) {
+            Kind expected = wordTypes.asKind(signature.getParameterType(i, method.getDeclaringClass())).getStackKind();
+            Kind actual = args[argIndex++].stamp().getStackKind();
             if (expected != actual) {
                 throw new AssertionError(graph + ": wrong kind of value for argument " + i + " of call to " + method + " [" + actual + " != " + expected + "]");
             }
@@ -179,19 +188,12 @@
     }
 
     /**
-     * Rewrite all word types in the graph.
-     */
-    public void rewriteWordTypes(SnippetReflectionProvider snippetReflection) {
-        new WordTypeRewriterPhase(providers.getMetaAccess(), snippetReflection, providers.getConstantReflection(), providers.getCodeCache().getTarget().wordKind).apply(graph);
-    }
-
-    /**
      * Recursively {@linkplain #inline inlines} all invocations currently in the graph.
      */
-    public void inlineInvokes(SnippetReflectionProvider snippetReflection) {
+    public void inlineInvokes() {
         while (!graph.getNodes().filter(InvokeNode.class).isEmpty()) {
             for (InvokeNode invoke : graph.getNodes().filter(InvokeNode.class).snapshot()) {
-                inline(invoke, snippetReflection);
+                inline(invoke);
             }
         }
 
@@ -204,10 +206,10 @@
      * {@linkplain ReplacementsImpl#makeGraph processed} in the same manner as for snippets and
      * method substitutions.
      */
-    public void inline(InvokeNode invoke, SnippetReflectionProvider snippetReflection) {
+    public void inline(InvokeNode invoke) {
         ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
-        ReplacementsImpl repl = new ReplacementsImpl(providers, snippetReflection, providers.getCodeCache().getTarget());
-        StructuredGraph calleeGraph = repl.makeGraph(method, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
+        ReplacementsImpl replacements = (ReplacementsImpl) providers.getReplacements();
+        StructuredGraph calleeGraph = replacements.makeGraph(method, null, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
         InliningUtil.inline(invoke, calleeGraph, false, null);
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntegerSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntegerSubstitutions.java	Thu Mar 12 15:59:01 2015 +0100
@@ -23,18 +23,12 @@
 package com.oracle.graal.replacements;
 
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.replacements.nodes.*;
 
 @ClassSubstitution(Integer.class)
 public class IntegerSubstitutions {
 
     @MethodSubstitution
-    public static int reverseBytes(int i) {
-        return ReverseBytesNode.reverse(i);
-    }
-
-    @MethodSubstitution
     public static int numberOfLeadingZeros(int i) {
         if (i == 0) {
             return 32;
@@ -49,19 +43,4 @@
         }
         return BitScanForwardNode.unsafeScan(i);
     }
-
-    @MethodSubstitution
-    public static int bitCount(int i) {
-        return BitCountNode.bitCount(i);
-    }
-
-    @MethodSubstitution
-    public static int divideUnsigned(int dividend, int divisor) {
-        return UnsignedDivNode.unsignedDivide(dividend, divisor);
-    }
-
-    @MethodSubstitution
-    public static int remainderUnsigned(int dividend, int divisor) {
-        return UnsignedRemNode.unsignedRemainder(dividend, divisor);
-    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/LongSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/LongSubstitutions.java	Thu Mar 12 15:59:01 2015 +0100
@@ -23,18 +23,12 @@
 package com.oracle.graal.replacements;
 
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.replacements.nodes.*;
 
 @ClassSubstitution(Long.class)
 public class LongSubstitutions {
 
     @MethodSubstitution
-    public static long reverseBytes(long i) {
-        return ReverseBytesNode.reverse(i);
-    }
-
-    @MethodSubstitution
     public static int numberOfLeadingZeros(long i) {
         if (i == 0) {
             return 64;
@@ -49,19 +43,4 @@
         }
         return BitScanForwardNode.unsafeScan(i);
     }
-
-    @MethodSubstitution
-    public static int bitCount(long i) {
-        return BitCountNode.bitCount(i);
-    }
-
-    @MethodSubstitution
-    public static long divideUnsigned(long dividend, long divisor) {
-        return UnsignedDivNode.unsignedDivide(dividend, divisor);
-    }
-
-    @MethodSubstitution
-    public static long remainderUnsigned(long dividend, long divisor) {
-        return UnsignedRemNode.unsignedRemainder(dividend, divisor);
-    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java	Thu Mar 12 15:59:01 2015 +0100
@@ -26,7 +26,6 @@
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.nodes.*;
@@ -40,36 +39,11 @@
 
     private static final double PI_4 = Math.PI / 4;
 
-    @MethodSubstitution
-    public static float abs(float x) {
-        return AbsNode.abs(x);
-    }
-
-    @MethodSubstitution
-    public static double abs(double x) {
-        return AbsNode.abs(x);
-    }
-
-    @MethodSubstitution
-    public static double sqrt(double x) {
-        return SqrtNode.sqrt(x);
-    }
-
-    @MethodSubstitution(guard = UnsafeSubstitutions.GetAndSetGuard.class)
-    public static double log(double x) {
-        return MathIntrinsicNode.compute(x, Operation.LOG);
-    }
-
-    @MethodSubstitution(guard = UnsafeSubstitutions.GetAndSetGuard.class)
-    public static double log10(double x) {
-        return MathIntrinsicNode.compute(x, Operation.LOG10);
-    }
-
     /**
      * Special cases from {@link Math#pow} and __ieee754_pow (in sharedRuntimeTrans.cpp).
      */
     @MacroSubstitution(macro = MathPowNode.class)
-    @MethodSubstitution(guard = UnsafeSubstitutions.GetAndSetGuard.class)
+    @MethodSubstitution(guard = MathGuard.class)
     public static double pow(double x, double y) {
         // If the second argument is positive or negative zero, then the result is 1.0.
         if (y == 0) {
@@ -103,7 +77,7 @@
 
         // x**0.5 = sqrt(x)
         if (y == 0.5 && x >= 0) {
-            return sqrt(x);
+            return Math.sqrt(x);
         }
 
         return pow(x, y);
@@ -115,46 +89,45 @@
     // accurate within [-pi/4, pi/4]. Examine the passed value and provide
     // a slow path for inputs outside of that interval.
 
-    @MethodSubstitution(guard = UnsafeSubstitutions.GetAndSetGuard.class)
+    @MethodSubstitution(guard = MathGuard.class)
     public static double sin(double x) {
-        if (abs(x) < PI_4) {
+        if (Math.abs(x) < PI_4) {
             return MathIntrinsicNode.compute(x, Operation.SIN);
         } else {
             return callDouble(ARITHMETIC_SIN, x);
         }
     }
 
-    @MethodSubstitution(guard = UnsafeSubstitutions.GetAndSetGuard.class)
+    @MethodSubstitution(guard = MathGuard.class)
     public static double cos(double x) {
-        if (abs(x) < PI_4) {
+        if (Math.abs(x) < PI_4) {
             return MathIntrinsicNode.compute(x, Operation.COS);
         } else {
             return callDouble(ARITHMETIC_COS, x);
         }
     }
 
-    @MethodSubstitution(guard = UnsafeSubstitutions.GetAndSetGuard.class)
+    @MethodSubstitution(guard = MathGuard.class)
     public static double tan(double x) {
-        if (abs(x) < PI_4) {
+        if (Math.abs(x) < PI_4) {
             return MathIntrinsicNode.compute(x, Operation.TAN);
         } else {
             return callDouble(ARITHMETIC_TAN, x);
         }
     }
 
+    public static class MathGuard implements SubstitutionGuard {
+        public boolean execute() {
+            // FIXME should return whether the current compilation target supports these
+            String arch = System.getProperty("os.arch");
+            return arch.equals("amd64") || arch.equals("x86_64");
+        }
+    }
+
     public static final ForeignCallDescriptor ARITHMETIC_SIN = new ForeignCallDescriptor("arithmeticSin", double.class, double.class);
     public static final ForeignCallDescriptor ARITHMETIC_COS = new ForeignCallDescriptor("arithmeticCos", double.class, double.class);
     public static final ForeignCallDescriptor ARITHMETIC_TAN = new ForeignCallDescriptor("arithmeticTan", double.class, double.class);
 
     @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true)
-    public static double callDouble(@ConstantNodeParameter ForeignCallDescriptor descriptor, double value) {
-        if (descriptor == ARITHMETIC_SIN) {
-            return Math.sin(value);
-        }
-        if (descriptor == ARITHMETIC_COS) {
-            return Math.cos(value);
-        }
-        assert descriptor == ARITHMETIC_TAN;
-        return Math.tan(value);
-    }
+    public static native double callDouble(@ConstantNodeParameter ForeignCallDescriptor descriptor, double value);
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Thu Mar 12 15:59:01 2015 +0100
@@ -259,7 +259,7 @@
         return reflectionCallArguments;
     }
 
-    private ResolvedJavaType getNodeClass(ResolvedJavaMethod target, NodeIntrinsic intrinsic) {
+    public ResolvedJavaType getNodeClass(ResolvedJavaMethod target, NodeIntrinsic intrinsic) {
         ResolvedJavaType result;
         if (intrinsic.value() == NodeIntrinsic.class) {
             result = target.getDeclaringClass();
@@ -283,6 +283,10 @@
                 if (constructor == null) {
                     constructor = c;
                     arguments = match;
+                    if (!Debug.isEnabled()) {
+                        // Don't verify there's a unique match in non-debug mode
+                        break;
+                    }
                 } else {
                     throw new GraalInternalError("Found multiple constructors in %s compatible with signature %s: %s, %s", nodeClass.toJavaName(), sigString(parameterTypes), constructor, c);
                 }
@@ -358,14 +362,14 @@
                     throw new GraalInternalError("Cannot handle injected argument of type %s in %s", signature[i].toJavaName(), c.format("%H.%n(%p)"));
                 }
             } else {
-                if (i > 0) {
-                    // Chop injected arguments from signature
-                    signature = Arrays.copyOfRange(signature, i, signature.length);
-                }
                 assert checkNoMoreInjected(c, i);
                 break;
             }
         }
+        if (injected != null) {
+            // Chop injected arguments from signature
+            signature = Arrays.copyOfRange(signature, injected.length, signature.length);
+        }
 
         if (Arrays.equals(parameterTypes, signature)) {
             // Exact match
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Thu Mar 12 15:59:01 2015 +0100
@@ -44,6 +44,7 @@
 import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.java.GraphBuilderPhase.Instance;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
@@ -56,7 +57,6 @@
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.Snippet.DefaultSnippetInliningPolicy;
 import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
-import com.oracle.graal.word.phases.*;
 
 public class ReplacementsImpl implements Replacements {
 
@@ -64,12 +64,17 @@
     public final SnippetReflectionProvider snippetReflection;
     public final TargetDescription target;
     public final NodeIntrinsificationPhase nodeIntrinsificationPhase;
+    private GraphBuilderConfiguration.Plugins graphBuilderPlugins;
 
     /**
      * The preprocessed replacement graphs.
      */
     protected final ConcurrentMap<ResolvedJavaMethod, StructuredGraph> graphs;
 
+    public void completeInitialization(GraphBuilderConfiguration.Plugins plugins) {
+        this.graphBuilderPlugins = plugins;
+    }
+
     /**
      * Encapsulates method and macro substitutions for a single class.
      */
@@ -113,12 +118,14 @@
                         }
                         String originalName = originalName(substituteMethod, methodSubstitution.value());
                         JavaSignature originalSignature = originalSignature(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic());
-                        Executable[] originalMethods = originalMethods(classSubstitution, methodSubstitution.optional(), originalName, originalSignature);
-                        for (Executable originalMethod : originalMethods) {
-                            if (originalMethod != null && (guard == null || guard.execute())) {
-                                ResolvedJavaMethod original = registerMethodSubstitution(this, originalMethod, substituteMethod);
-                                if (original != null && methodSubstitution.forced() && shouldIntrinsify(original)) {
-                                    forcedSubstitutions.add(original);
+                        Executable[] originalMethods = originalMethods(classSubstitution, classSubstitution.optional(), originalName, originalSignature);
+                        if (originalMethods != null) {
+                            for (Executable originalMethod : originalMethods) {
+                                if (originalMethod != null && (guard == null || guard.execute())) {
+                                    ResolvedJavaMethod original = registerMethodSubstitution(this, originalMethod, substituteMethod);
+                                    if (original != null && methodSubstitution.forced() && shouldIntrinsify(original)) {
+                                        forcedSubstitutions.add(original);
+                                    }
                                 }
                             }
                         }
@@ -250,12 +257,12 @@
         return null;
     }
 
-    public StructuredGraph getSnippet(ResolvedJavaMethod method) {
-        return getSnippet(method, null);
+    public StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args) {
+        return getSnippet(method, null, args);
     }
 
     @Override
-    public StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry) {
+    public StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args) {
         assert method.getAnnotation(Snippet.class) != null : "Snippet must be annotated with @" + Snippet.class.getSimpleName();
         assert method.hasBytecodes() : "Snippet must not be abstract or native";
 
@@ -264,9 +271,9 @@
             try (DebugCloseable a = SnippetPreparationTime.start()) {
                 FrameStateProcessing frameStateProcessing = method.getAnnotation(Snippet.class).removeAllFrameStates() ? FrameStateProcessing.Removal
                                 : FrameStateProcessing.CollapseFrameForSingleSideEffect;
-                StructuredGraph newGraph = makeGraph(method, recursiveEntry, inliningPolicy(method), frameStateProcessing);
+                StructuredGraph newGraph = makeGraph(method, args, recursiveEntry, inliningPolicy(method), frameStateProcessing);
                 Debug.metric("SnippetNodeCount[%#s]", method).add(newGraph.getNodeCount());
-                if (!UseSnippetGraphCache) {
+                if (!UseSnippetGraphCache || args != null) {
                     return newGraph;
                 }
                 graphs.putIfAbsent(method, newGraph);
@@ -304,7 +311,7 @@
         }
         StructuredGraph graph = graphs.get(substitute);
         if (graph == null) {
-            graph = makeGraph(substitute, original, inliningPolicy(substitute), FrameStateProcessing.None);
+            graph = makeGraph(substitute, null, original, inliningPolicy(substitute), FrameStateProcessing.None);
             graph.freeze();
             graphs.putIfAbsent(substitute, graph);
             graph = graphs.get(substitute);
@@ -423,7 +430,7 @@
         }
     }
 
-    protected SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) {
+    public SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) {
         Class<? extends SnippetInliningPolicy> policyClass = SnippetInliningPolicy.class;
         Snippet snippet = method.getAnnotation(Snippet.class);
         if (snippet != null) {
@@ -439,13 +446,14 @@
      * Creates a preprocessed graph for a snippet or method substitution.
      *
      * @param method the snippet or method substitution for which a graph will be created
+     * @param args
      * @param original the original method if {@code method} is a {@linkplain MethodSubstitution
      *            substitution} otherwise null
      * @param policy the inlining policy to use during preprocessing
      * @param frameStateProcessing controls how {@link FrameState FrameStates} should be handled.
      */
-    public StructuredGraph makeGraph(ResolvedJavaMethod method, ResolvedJavaMethod original, SnippetInliningPolicy policy, FrameStateProcessing frameStateProcessing) {
-        return createGraphMaker(method, original, frameStateProcessing).makeGraph(policy);
+    public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, SnippetInliningPolicy policy, FrameStateProcessing frameStateProcessing) {
+        return createGraphMaker(method, original, frameStateProcessing).makeGraph(args, policy);
     }
 
     /**
@@ -462,7 +470,13 @@
 
     public enum FrameStateProcessing {
         None,
+        /**
+         * @see CollapseFrameForSingleSideEffectPhase
+         */
         CollapseFrameForSingleSideEffect,
+        /**
+         * Removes frame states from all nodes in the graph.
+         */
         Removal
     }
 
@@ -511,12 +525,14 @@
             this.frameStateProcessing = frameStateProcessing;
         }
 
-        public StructuredGraph makeGraph(final SnippetInliningPolicy policy) {
+        public StructuredGraph makeGraph(Object[] args, final SnippetInliningPolicy policy) {
             try (Scope s = Debug.scope("BuildSnippetGraph", method)) {
-                StructuredGraph graph = parseGraph(method, policy, 0);
+                StructuredGraph graph = parseGraph(method, args, policy, 0);
 
-                // Cannot have a finalized version of a graph in the cache
-                graph = graph.copy();
+                if (args == null) {
+                    // Cannot have a finalized version of a graph in the cache
+                    graph = graph.copy();
+                }
 
                 finalizeGraph(graph);
 
@@ -587,18 +603,21 @@
 
         private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough
 
-        private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy, int inliningDepth) {
-            StructuredGraph graph = replacements.graphCache.get(methodToParse);
+        private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, Object[] args, final SnippetInliningPolicy policy, int inliningDepth) {
+            StructuredGraph graph = args == null ? replacements.graphCache.get(methodToParse) : null;
             if (graph == null) {
                 StructuredGraph newGraph = null;
                 try (Scope s = Debug.scope("ParseGraph", methodToParse)) {
-                    newGraph = buildGraph(methodToParse, policy == null ? replacements.inliningPolicy(methodToParse) : policy, inliningDepth);
+                    newGraph = buildGraph(methodToParse, args, policy == null ? replacements.inliningPolicy(methodToParse) : policy, inliningDepth);
                 } catch (Throwable e) {
                     throw Debug.handle(e);
                 }
-
-                replacements.graphCache.putIfAbsent(methodToParse, newGraph);
-                graph = replacements.graphCache.get(methodToParse);
+                if (args == null) {
+                    replacements.graphCache.putIfAbsent(methodToParse, newGraph);
+                    graph = replacements.graphCache.get(methodToParse);
+                } else {
+                    graph = newGraph;
+                }
                 assert graph != null;
             }
             return graph;
@@ -607,7 +626,7 @@
         /**
          * Builds the initial graph for a snippet.
          */
-        protected StructuredGraph buildInitialGraph(final ResolvedJavaMethod methodToParse) {
+        protected StructuredGraph buildInitialGraph(final ResolvedJavaMethod methodToParse, Object[] args) {
             // Replacements cannot have optimistic assumptions since they have
             // to be valid for the entire run of the VM.
             final StructuredGraph graph = new StructuredGraph(methodToParse, AllowAssumptions.NO);
@@ -621,8 +640,13 @@
                 if (MethodsElidedInSnippets != null && methodToParse.getSignature().getReturnKind() == Kind.Void && MethodFilter.matches(MethodsElidedInSnippets, methodToParse)) {
                     graph.addAfterFixed(graph.start(), graph.add(new ReturnNode(null)));
                 } else {
-                    createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.providers.getConstantReflection(), GraphBuilderConfiguration.getSnippetDefault(),
-                                    OptimisticOptimizations.NONE).apply(graph);
+                    GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault();
+                    Plugins plugins = config.getPlugins().updateFrom(replacements.graphBuilderPlugins, false);
+                    plugins.getInvocationPlugins().setDefaults(replacements.graphBuilderPlugins.getInvocationPlugins());
+                    if (args != null) {
+                        plugins.setParameterPlugin(new ConstantBindingParameterPlugin(args, plugins.getParameterPlugin(), metaAccess, replacements.snippetReflection));
+                    }
+                    createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.providers.getConstantReflection(), config, OptimisticOptimizations.NONE).apply(graph);
                 }
                 afterParsing(graph);
 
@@ -637,13 +661,14 @@
 
         protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig,
                         OptimisticOptimizations optimisticOpts) {
-            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts);
+            ResolvedJavaMethod rootMethodIsReplacement = substitutedMethod == null ? method : substitutedMethod;
+            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, rootMethodIsReplacement);
         }
 
+        /**
+         * @param graph
+         */
         protected void afterParsing(StructuredGraph graph) {
-            MetaAccessProvider metaAccess = replacements.providers.getMetaAccess();
-            new WordTypeVerificationPhase(metaAccess, replacements.snippetReflection, replacements.providers.getConstantReflection(), replacements.target.wordKind).apply(graph);
-            new WordTypeRewriterPhase(metaAccess, replacements.snippetReflection, replacements.providers.getConstantReflection(), replacements.target.wordKind).apply(graph);
         }
 
         protected Object beforeInline(@SuppressWarnings("unused") MethodCallTargetNode callTarget, @SuppressWarnings("unused") StructuredGraph callee) {
@@ -674,10 +699,10 @@
             }
         }
 
-        private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy, int inliningDepth) {
+        private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, Object[] args, final SnippetInliningPolicy policy, int inliningDepth) {
             assert inliningDepth < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded";
             assert methodToParse.hasBytecodes() : methodToParse;
-            final StructuredGraph graph = buildInitialGraph(methodToParse);
+            final StructuredGraph graph = buildInitialGraph(methodToParse, args);
             try (Scope s = Debug.scope("buildGraph", graph)) {
                 Set<MethodCallTargetNode> doNotInline = null;
                 for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.TYPE)) {
@@ -691,7 +716,7 @@
                          * calling it instead of the Graal substitution.
                          */
                         if (substitutedMethod.hasBytecodes()) {
-                            final StructuredGraph originalGraph = buildInitialGraph(substitutedMethod);
+                            final StructuredGraph originalGraph = buildInitialGraph(substitutedMethod, null);
                             Mark mark = graph.getMark();
                             InliningUtil.inline(callTarget.invoke(), originalGraph, true, null);
                             for (MethodCallTargetNode inlinedCallTarget : graph.getNewNodes(mark).filter(MethodCallTargetNode.class)) {
@@ -723,7 +748,7 @@
                                                         " while preparing replacement " + method.format("%H.%n(%p)") + ". Placing \"//JaCoCo Exclude\" anywhere in " +
                                                         methodToParse.getDeclaringClass().getSourceFileName() + " should fix this.");
                                     }
-                                    targetGraph = parseGraph(callee, policy, inliningDepth + 1);
+                                    targetGraph = parseGraph(callee, null, policy, inliningDepth + 1);
                                 }
                                 Object beforeInlineData = beforeInline(callTarget, targetGraph);
                                 InliningUtil.inline(callTarget.invoke(), targetGraph, true, null);
@@ -763,7 +788,7 @@
      * @param optional if true, resolution failure returns null
      * @return the resolved class or null if resolution fails and {@code optional} is true
      */
-    static Class<?> resolveClass(String className, boolean optional) {
+    public static Class<?> resolveClass(String className, boolean optional) {
         try {
             // Need to use launcher class path to handle classes
             // that are not on the boot class path
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ShortSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2014, 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 com.oracle.graal.api.replacements.*;
-import com.oracle.graal.replacements.nodes.*;
-
-@ClassSubstitution(Short.class)
-public class ShortSubstitutions {
-    @MethodSubstitution
-    public static short reverseBytes(short i) {
-        return (short) (ReverseBytesNode.reverse(i) >> 16);
-    }
-}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Thu Mar 12 15:59:01 2015 +0100
@@ -483,7 +483,7 @@
             }
         }
 
-        private static Method findMethod(Class<? extends Snippets> declaringClass, String methodName, Method except) {
+        public static Method findMethod(Class<? extends Snippets> declaringClass, String methodName, Method except) {
             for (Method m : declaringClass.getDeclaredMethods()) {
                 if (m.getName().equals(methodName) && !m.equals(except)) {
                     return m;
@@ -555,8 +555,8 @@
      */
     protected SnippetTemplate(final Providers providers, SnippetReflectionProvider snippetReflection, Arguments args) {
         this.snippetReflection = snippetReflection;
-
-        StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method);
+        Object[] constantArgs = getConstantArgs(args);
+        StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method, constantArgs);
         instantiationTimer = Debug.timer("SnippetTemplateInstantiationTime[%#s]", args);
         instantiationCounter = Debug.metric("SnippetTemplateInstantiationCount[%#s]", args);
 
@@ -691,8 +691,6 @@
             throw Debug.handle(e);
         }
 
-        // Remove all frame states from snippet graph. Snippets must be atomic (i.e. free
-        // of side-effects that prevent deoptimizing to a point before the snippet).
         ArrayList<StateSplit> curSideEffectNodes = new ArrayList<>();
         ArrayList<DeoptimizingNode> curDeoptNodes = new ArrayList<>();
         ArrayList<ValueNode> curStampNodes = new ArrayList<>();
@@ -775,6 +773,16 @@
         Debug.dump(snippet, "SnippetTemplate final state");
     }
 
+    protected Object[] getConstantArgs(Arguments args) {
+        Object[] constantArgs = args.values.clone();
+        for (int i = 0; i < args.info.getParameterCount(); i++) {
+            if (!args.info.isConstantParameter(i)) {
+                constantArgs[i] = null;
+            }
+        }
+        return constantArgs;
+    }
+
     private static boolean checkAllVarargPlaceholdersAreDeleted(int parameterCount, VarargsPlaceholderNode[] placeholders) {
         for (int i = 0; i < parameterCount; i++) {
             if (placeholders[i] != null) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Thu Mar 12 15:59:01 2015 +0100
@@ -24,11 +24,14 @@
 
 import static com.oracle.graal.api.code.MemoryBarriers.*;
 import static com.oracle.graal.java.GraphBuilderContext.*;
-import static java.lang.Character.*;
+import static com.oracle.graal.replacements.nodes.MathIntrinsicNode.Operation.*;
 import sun.misc.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.directives.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.java.GraphBuilderPlugin.InvocationPlugin;
 import com.oracle.graal.java.InvocationPlugins.Registration;
@@ -38,6 +41,7 @@
 import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.options.*;
 import com.oracle.graal.replacements.nodes.*;
 
 /**
@@ -45,54 +49,291 @@
  */
 public class StandardGraphBuilderPlugins {
 
-    public static void registerInvocationPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+    // @formatter:off
+    static class Options {
+        @Option(help = "Enable use of intrinsics for the JMH Blackhole class")
+        public static final OptionValue<Boolean> UseBlackholeSubstitution = new OptionValue<>(true);
+    }
+    // @formatter:on
+
+    public static void registerInvocationPlugins(MetaAccessProvider metaAccess, Architecture arch, InvocationPlugins plugins, boolean useBoxingPlugins) {
         registerObjectPlugins(metaAccess, plugins);
-        registerMathPlugins(metaAccess, plugins);
-        registerUnsafePlugins(metaAccess, plugins);
+        registerClassPlugins(metaAccess, plugins);
+        registerMathPlugins(metaAccess, arch, plugins);
+        registerUnsignedMathPlugins(metaAccess, plugins);
+        registerCharacterPlugins(metaAccess, plugins);
+        registerShortPlugins(metaAccess, plugins);
+        registerIntegerLongPlugins(metaAccess, plugins, Kind.Int);
+        registerIntegerLongPlugins(metaAccess, plugins, Kind.Long);
+        registerFloatPlugins(metaAccess, plugins);
+        registerDoublePlugins(metaAccess, plugins);
+        registerUnsafePlugins(metaAccess, arch, plugins);
+        registerEdgesPlugins(metaAccess, plugins);
         registerGraalDirectivesPlugins(metaAccess, plugins);
+        if (useBoxingPlugins) {
+            registerBoxingPlugins(metaAccess, plugins);
+        }
+        if (Options.UseBlackholeSubstitution.getValue()) {
+            registerJMHBlackholePlugins(metaAccess, plugins);
+        }
     }
 
-    public static void registerUnsafePlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+    private static void registerUnsafePlugins(MetaAccessProvider metaAccess, Architecture arch, 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);
+                Class<?> javaClass = kind == Kind.Object ? Object.class : kind.toJavaClass();
+                String kindName = kind.name();
                 String getName = "get" + kindName;
                 String putName = "put" + kindName;
+                // Object-based accesses
                 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.register4(putName, Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, false));
+                // Volatile object-based accesses
                 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));
+                r.register4(putName + "Volatile", Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, true));
+                // Ordered object-based accesses
+                if (kind == Kind.Int || kind == Kind.Long || kind == Kind.Object) {
+                    r.register4("putOrdered" + kindName, Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, true));
+                }
                 if (kind != Kind.Boolean && kind != Kind.Object) {
+                    // Raw accesses to memory addresses
                     r.register2(getName, Receiver.class, long.class, new UnsafeGetPlugin(kind, false));
                     r.register3(putName, Receiver.class, long.class, kind.toJavaClass(), new UnsafePutPlugin(kind, false));
                 }
             }
         }
+
+        for (Kind kind : new Kind[]{Kind.Int, Kind.Long, Kind.Object}) {
+            Class<?> javaClass = kind == Kind.Object ? Object.class : kind.toJavaClass();
+            r.register5("compareAndSwap" + kind.name(), Receiver.class, Object.class, long.class, javaClass, javaClass, new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) {
+                    b.push(Kind.Boolean.getStackKind(), b.append(new CompareAndSwapNode(object, offset, expected, x, kind, LocationIdentity.ANY_LOCATION)));
+                    return true;
+                }
+            });
+
+            if (getAndSetEnabled(arch)) {
+                r.register4("getAndSet" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() {
+                    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode value) {
+                        b.push(kind.getStackKind(), b.append(new AtomicReadAndWriteNode(object, offset, value, kind, LocationIdentity.ANY_LOCATION)));
+                        return true;
+                    }
+                });
+                if (kind != Kind.Object) {
+                    r.register4("getAndAdd" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() {
+                        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode delta) {
+                            b.push(kind.getStackKind(), b.append(new AtomicReadAndAddNode(object, offset, delta, LocationIdentity.ANY_LOCATION)));
+                            return true;
+                        }
+                    });
+                }
+            }
+        }
+    }
+
+    /**
+     * Determines if the platform includes such for intrinsifying the {@link Unsafe#getAndSetInt}
+     * method family.
+     */
+    public static boolean getAndSetEnabled(Architecture arch) {
+        // FIXME should return whether the current compilation target supports these
+        return arch.getName().equals("AMD64");
     }
 
-    public static void registerMathPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+    private static void registerIntegerLongPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins, Kind kind) {
+        Class<?> declaringClass = kind.toBoxedJavaClass();
+        Class<?> type = kind.toJavaClass();
+        Registration r = new Registration(plugins, metaAccess, declaringClass);
+        r.register1("reverseBytes", type, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                b.push(kind, b.append(new ReverseBytesNode(value).canonical(null, value)));
+                return true;
+            }
+        });
+        r.register1("bitCount", type, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                b.push(Kind.Int, b.append(new BitCountNode(value).canonical(null, value)));
+                return true;
+            }
+        });
+        r.register2("divideUnsigned", type, type, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode dividend, ValueNode divisor) {
+                b.push(kind, b.append(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor)));
+                return true;
+            }
+        });
+        r.register2("remainderUnsigned", type, type, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode dividend, ValueNode divisor) {
+                b.push(kind, b.append(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor)));
+                return true;
+            }
+        });
+    }
+
+    private static void registerCharacterPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, Character.class);
+        r.register1("reverseBytes", char.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                // return (char) (Integer.reverse(i) >> 16);
+                ReverseBytesNode reverse = b.append(new ReverseBytesNode(value));
+                RightShiftNode rightShift = b.append(new RightShiftNode(reverse, b.append(ConstantNode.forInt(16))));
+                ZeroExtendNode charCast = b.append(new ZeroExtendNode(b.append(new NarrowNode(rightShift, 16)), 32));
+                b.push(Kind.Char.getStackKind(), b.append(charCast.canonical(null, value)));
+                return true;
+            }
+        });
+    }
+
+    private static void registerShortPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, Short.class);
+        r.register1("reverseBytes", short.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                // return (short) (Integer.reverse(i) >> 16);
+                ReverseBytesNode reverse = b.append(new ReverseBytesNode(value));
+                RightShiftNode rightShift = b.append(new RightShiftNode(reverse, b.append(ConstantNode.forInt(16))));
+                SignExtendNode charCast = b.append(new SignExtendNode(b.append(new NarrowNode(rightShift, 16)), 32));
+                b.push(Kind.Short.getStackKind(), b.append(charCast.canonical(null, value)));
+                return true;
+            }
+        });
+    }
+
+    private static void registerFloatPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, Float.class);
+        r.register1("floatToRawIntBits", float.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                b.push(Kind.Int, b.append(new ReinterpretNode(Kind.Int, value).canonical(null, value)));
+                return true;
+            }
+        });
+        r.register1("intBitsToFloat", int.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                b.push(Kind.Float, b.append(new ReinterpretNode(Kind.Float, value).canonical(null, value)));
+                return true;
+            }
+        });
+    }
+
+    private static void registerDoublePlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, Double.class);
+        r.register1("doubleToRawLongBits", double.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                b.push(Kind.Long, b.append(new ReinterpretNode(Kind.Long, value).canonical(null, value)));
+                return true;
+            }
+        });
+        r.register1("longBitsToDouble", long.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                b.push(Kind.Double, b.append(new ReinterpretNode(Kind.Double, value).canonical(null, value)));
+                return true;
+            }
+        });
+    }
+
+    private static void registerMathPlugins(MetaAccessProvider metaAccess, Architecture arch, 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)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                b.push(Kind.Float, b.append(new AbsNode(value).canonical(null, 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)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                b.push(Kind.Double, b.append(new AbsNode(value).canonical(null, 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)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                b.push(Kind.Double, b.append(new SqrtNode(value).canonical(null, value)));
                 return true;
             }
         });
+        if (getAndSetEnabled(arch)) {
+            r.register1("log", Double.TYPE, new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                    b.push(Kind.Double, b.append(MathIntrinsicNode.create(value, LOG)));
+                    return true;
+                }
+            });
+            r.register1("log10", Double.TYPE, new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                    b.push(Kind.Double, b.append(MathIntrinsicNode.create(value, LOG10)));
+                    return true;
+                }
+            });
+        }
+    }
 
+    public static class UnsignedMathPlugin implements InvocationPlugin {
+        private final Condition condition;
+
+        public UnsignedMathPlugin(Condition condition) {
+            this.condition = condition;
+        }
+
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
+            // the mirroring and negation operations get the condition into canonical form
+            boolean mirror = condition.canonicalMirror();
+            boolean negate = condition.canonicalNegate();
+            StructuredGraph graph = b.getGraph();
+
+            ValueNode lhs = mirror ? y : x;
+            ValueNode rhs = mirror ? x : y;
+
+            ValueNode trueValue = ConstantNode.forBoolean(!negate, graph);
+            ValueNode falseValue = ConstantNode.forBoolean(negate, graph);
+
+            Condition cond = mirror ? condition.mirror() : condition;
+            if (negate) {
+                cond = cond.negate();
+            }
+
+            LogicNode compare = CompareNode.createCompareNode(graph, cond, lhs, rhs, b.getConstantReflection());
+            b.push(Kind.Boolean.getStackKind(), b.append(new ConditionalNode(compare, trueValue, falseValue)));
+            return true;
+        }
+    }
+
+    private static void registerUnsignedMathPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, UnsignedMath.class);
+        r.register2("aboveThan", int.class, int.class, new UnsignedMathPlugin(Condition.AT));
+        r.register2("aboveThan", long.class, long.class, new UnsignedMathPlugin(Condition.AT));
+        r.register2("belowThan", int.class, int.class, new UnsignedMathPlugin(Condition.BT));
+        r.register2("belowThan", long.class, long.class, new UnsignedMathPlugin(Condition.BT));
+        r.register2("aboveOrEqual", int.class, int.class, new UnsignedMathPlugin(Condition.AE));
+        r.register2("aboveOrEqual", long.class, long.class, new UnsignedMathPlugin(Condition.AE));
+        r.register2("belowOrEqual", int.class, int.class, new UnsignedMathPlugin(Condition.BE));
+        r.register2("belowOrEqual", long.class, long.class, new UnsignedMathPlugin(Condition.BE));
+        r.register2("divide", int.class, int.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
+                b.push(Kind.Int, b.append(new UnsignedDivNode(x, y).canonical(null, x, y)));
+                return true;
+            }
+        });
+        r.register2("divide", long.class, long.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
+                b.push(Kind.Long, b.append(new UnsignedDivNode(x, y).canonical(null, x, y)));
+                return true;
+            }
+        });
+        r.register2("remainder", int.class, int.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
+                b.push(Kind.Int, b.append(new UnsignedRemNode(x, y).canonical(null, x, y)));
+                return true;
+            }
+        });
+        r.register2("remainder", long.class, long.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
+                b.push(Kind.Long, b.append(new UnsignedRemNode(x, y).canonical(null, x, y)));
+                return true;
+            }
+        });
+    }
+
+    protected static void registerBoxingPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
         for (Kind kind : Kind.values()) {
             if (kind.isPrimitive() && kind != Kind.Void) {
                 new BoxPlugin(kind).register(metaAccess, plugins);
@@ -101,19 +342,78 @@
         }
     }
 
-    public static void registerObjectPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+    private 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));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object) {
+                if (RegisterFinalizerNode.mayHaveFinalizer(object, b.getAssumptions())) {
+                    b.append(new RegisterFinalizerNode(object));
                 }
                 return true;
             }
         });
     }
 
-    static class BoxPlugin implements InvocationPlugin {
+    private static void registerClassPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, Class.class);
+        r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode type, ValueNode object) {
+                ValueNode nullCheckedType = nullCheckedValue(b, type);
+                LogicNode condition = b.append(new InstanceOfDynamicNode(nullCheckedType, object).canonical(null, nullCheckedType, object));
+                b.push(Kind.Boolean.getStackKind(), b.append(new ConditionalNode(condition).canonical(null)));
+                return true;
+            }
+        });
+        r.register2("isAssignableFrom", Receiver.class, Class.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode type, ValueNode otherType) {
+                ClassIsAssignableFromNode condition = b.append(new ClassIsAssignableFromNode(nullCheckedValue(b, type), otherType));
+                b.push(Kind.Boolean.getStackKind(), b.append(new ConditionalNode(condition).canonical(null)));
+                return true;
+            }
+        });
+        r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode rcvr, ValueNode object) {
+                if (rcvr.isConstant() && !rcvr.isNullConstant()) {
+                    ResolvedJavaType type = b.getConstantReflection().asJavaType(rcvr.asConstant());
+                    if (type != null && !type.isPrimitive()) {
+                        b.push(Kind.Object, b.append(CheckCastNode.create(type, object, null, false, b.getAssumptions())));
+                        return true;
+                    }
+                }
+                return false;
+            }
+        });
+    }
+
+    /**
+     * Substitutions for improving the performance of some critical methods in {@link Edges}. These
+     * substitutions improve the performance by forcing the relevant methods to be inlined
+     * (intrinsification being a special form of inlining) and removing a checked cast. The latter
+     * cannot be done directly in Java code as {@link DeferredPiNode} is not available to the
+     * project containing {@link Edges}.
+     */
+    private static void registerEdgesPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, Edges.class);
+        for (Class<?> c : new Class<?>[]{Node.class, NodeList.class}) {
+            r.register2("get" + c.getSimpleName() + "Unsafe", Node.class, long.class, new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode node, ValueNode offset) {
+                    ValueNode value = b.append(new UnsafeLoadNode(node, offset, Kind.Object, LocationIdentity.ANY_LOCATION));
+                    boolean exactType = false;
+                    boolean nonNull = false;
+                    b.push(Kind.Object, b.append(new PiNode(value, metaAccess.lookupJavaType(c), exactType, nonNull)));
+                    return true;
+                }
+            });
+            r.register3("put" + c.getSimpleName() + "Unsafe", Node.class, long.class, c, new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode node, ValueNode offset, ValueNode value) {
+                    b.append(new UnsafeStoreNode(node, offset, value, Kind.Object, LocationIdentity.ANY_LOCATION));
+                    return true;
+                }
+            });
+        }
+    }
+
+    public static class BoxPlugin implements InvocationPlugin {
 
         private final Kind kind;
 
@@ -121,9 +421,17 @@
             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)));
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+            if (b.parsingReplacement()) {
+                ResolvedJavaMethod rootMethod = b.getRootMethod();
+                if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) {
+                    // Disable invocation plugins for boxing snippets so that the
+                    // original JDK methods are inlined
+                    return false;
+                }
+            }
+            ResolvedJavaType resultType = b.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass());
+            b.push(Kind.Object, b.append(new BoxNode(value, resultType, kind)));
             return true;
         }
 
@@ -133,7 +441,7 @@
         }
     }
 
-    static class UnboxPlugin implements InvocationPlugin {
+    public static class UnboxPlugin implements InvocationPlugin {
 
         private final Kind kind;
 
@@ -141,9 +449,17 @@
             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));
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+            if (b.parsingReplacement()) {
+                ResolvedJavaMethod rootMethod = b.getRootMethod();
+                if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) {
+                    // Disable invocation plugins for unboxing snippets so that the
+                    // original JDK methods are inlined
+                    return false;
+                }
+            }
+            ValueNode valueNode = UnboxNode.create(b.getMetaAccess(), b.getConstantReflection(), nullCheckedValue(b, value), kind);
+            b.push(kind.getStackKind(), b.append(valueNode));
             return true;
         }
 
@@ -154,7 +470,7 @@
         }
     }
 
-    static class UnsafeGetPlugin implements InvocationPlugin {
+    public static class UnsafeGetPlugin implements InvocationPlugin {
 
         private final Kind returnKind;
         private final boolean isVolatile;
@@ -164,18 +480,18 @@
             this.isVolatile = isVolatile;
         }
 
-        public boolean apply(GraphBuilderContext builder, ValueNode ignoredUnsafe, ValueNode address) {
-            builder.push(returnKind.getStackKind(), builder.append(new DirectReadNode(address, returnKind)));
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode address) {
+            b.push(returnKind.getStackKind(), b.append(new DirectReadNode(address, returnKind)));
             return true;
         }
 
-        public boolean apply(GraphBuilderContext builder, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset) {
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset) {
             if (isVolatile) {
-                builder.append(new MembarNode(JMM_PRE_VOLATILE_READ));
+                b.append(new MembarNode(JMM_PRE_VOLATILE_READ));
             }
-            builder.push(returnKind.getStackKind(), builder.append(new UnsafeLoadNode(object, offset, returnKind, LocationIdentity.ANY_LOCATION)));
+            b.push(returnKind.getStackKind(), b.append(new UnsafeLoadNode(object, offset, returnKind, LocationIdentity.ANY_LOCATION)));
             if (isVolatile) {
-                builder.append(new MembarNode(JMM_POST_VOLATILE_READ));
+                b.append(new MembarNode(JMM_POST_VOLATILE_READ));
             }
             return true;
         }
@@ -191,90 +507,104 @@
             this.isVolatile = isVolatile;
         }
 
-        public boolean apply(GraphBuilderContext builder, ValueNode ignoredUnsafe, ValueNode address, ValueNode value) {
-            builder.append(new DirectStoreNode(address, value, kind));
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode address, ValueNode value) {
+            b.append(new DirectStoreNode(address, value, kind));
             return true;
         }
 
-        public boolean apply(GraphBuilderContext builder, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode value) {
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode value) {
             if (isVolatile) {
-                builder.append(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+                b.append(new MembarNode(JMM_PRE_VOLATILE_WRITE));
             }
-            builder.append(new UnsafeStoreNode(object, offset, value, kind, LocationIdentity.ANY_LOCATION));
+            b.append(new UnsafeStoreNode(object, offset, value, kind, LocationIdentity.ANY_LOCATION));
             if (isVolatile) {
-                builder.append(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+                b.append(new MembarNode(JMM_PRE_VOLATILE_WRITE));
             }
             return true;
         }
     }
 
-    public static void registerGraalDirectivesPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+    private 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));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+                b.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));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+                b.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)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+                b.push(Kind.Int, b.append(ConstantNode.forInt(1)));
                 return true;
             }
         });
 
         r.register0("controlFlowAnchor", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder) {
-                builder.append(new ControlFlowAnchorNode());
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+                b.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)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode probability, ValueNode condition) {
+                b.push(Kind.Int, b.append(new BranchProbabilityNode(probability, condition)));
                 return true;
             }
         });
 
         InvocationPlugin blackholePlugin = new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode value) {
-                builder.append(new BlackholeNode(value));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                b.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();
+            if ((kind.isPrimitive() && kind != Kind.Void) || kind == Kind.Object) {
+                Class<?> javaClass = kind == Kind.Object ? Object.class : kind.toJavaClass();
+                r.register1("blackhole", javaClass, blackholePlugin);
+
+                final Kind stackKind = kind.getStackKind();
+                r.register1("opaque", javaClass, new InvocationPlugin() {
+                    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                        b.push(stackKind, b.append(new OpaqueNode(value)));
+                        return true;
+                    }
+                });
             }
-
-            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;
-                }
-            });
         }
     }
 
+    private static void registerJMHBlackholePlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        InvocationPlugin blackholePlugin = new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode blackhole, ValueNode value) {
+                b.append(new BlackholeNode(value));
+                return true;
+            }
+        };
+        String[] names = {"org.openjdk.jmh.infra.Blackhole", "org.openjdk.jmh.logic.BlackHole"};
+        for (String name : names) {
+            Class<?> blackholeClass;
+            blackholeClass = ReplacementsImpl.resolveClass(name, true);
+            if (blackholeClass != null) {
+                Registration r = new Registration(plugins, metaAccess, blackholeClass);
+                for (Kind kind : Kind.values()) {
+                    if ((kind.isPrimitive() && kind != Kind.Void) || kind == Kind.Object) {
+                        Class<?> javaClass = kind == Kind.Object ? Object.class : kind.toJavaClass();
+                        r.register2("consume", Receiver.class, javaClass, blackholePlugin);
+                    }
+                }
+                r.register2("consume", Receiver.class, Object[].class, blackholePlugin);
+            }
+        }
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsafeSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsafeSubstitutions.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.replacements;
 
-import static com.oracle.graal.api.code.MemoryBarriers.*;
+import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
 
 import java.lang.reflect.*;
 
@@ -30,9 +30,8 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.replacements.nodes.*;
 
 /**
  * Substitutions for {@link sun.misc.Unsafe} methods.
@@ -41,405 +40,16 @@
 public class UnsafeSubstitutions {
 
     @MethodSubstitution(isStatic = false)
-    public static boolean compareAndSwapObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object expected, Object x) {
-        return CompareAndSwapNode.compareAndSwap(o, offset, expected, x, Kind.Object, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static boolean compareAndSwapInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int expected, int x) {
-        return CompareAndSwapNode.compareAndSwap(o, offset, expected, x, Kind.Int, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static boolean compareAndSwapLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long expected, long x) {
-        return CompareAndSwapNode.compareAndSwap(o, offset, expected, x, Kind.Long, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static Object getObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        return UnsafeLoadNode.load(o, offset, Kind.Object, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static Object getObjectVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_READ);
-        Object result = getObject(thisObj, o, offset);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object x) {
-        UnsafeStoreNode.store(o, offset, x, Kind.Object, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putObjectVolatile(final Object thisObj, Object o, long offset, Object x) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_WRITE);
-        putObject(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putOrderedObject(final Object thisObj, Object o, long offset, Object x) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_WRITE);
-        putObject(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static int getInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        Integer value = UnsafeLoadNode.load(o, offset, Kind.Int, LocationIdentity.ANY_LOCATION);
-        return value;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static int getIntVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_READ);
-        int result = getInt(thisObj, o, offset);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int x) {
-        UnsafeStoreNode.store(o, offset, x, Kind.Int, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putIntVolatile(final Object thisObj, Object o, long offset, int x) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_WRITE);
-        putInt(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putOrderedInt(final Object thisObj, Object o, long offset, int x) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_WRITE);
-        putInt(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static boolean getBoolean(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        @JavacBug(id = 6995200)
-        Boolean result = UnsafeLoadNode.load(o, offset, Kind.Boolean, LocationIdentity.ANY_LOCATION);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static boolean getBooleanVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_READ);
-        boolean result = getBoolean(thisObj, o, offset);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putBoolean(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, boolean x) {
-        UnsafeStoreNode.store(o, offset, x, Kind.Boolean, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putBooleanVolatile(final Object thisObj, Object o, long offset, boolean x) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_WRITE);
-        putBoolean(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static byte getByte(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        @JavacBug(id = 6995200)
-        Byte result = UnsafeLoadNode.load(o, offset, Kind.Byte, LocationIdentity.ANY_LOCATION);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static byte getByteVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_READ);
-        byte result = getByte(thisObj, o, offset);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putByte(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, byte x) {
-        UnsafeStoreNode.store(o, offset, x, Kind.Byte, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putByteVolatile(final Object thisObj, Object o, long offset, byte x) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_WRITE);
-        putByte(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static short getShort(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        @JavacBug(id = 6995200)
-        Short result = UnsafeLoadNode.load(o, offset, Kind.Short, LocationIdentity.ANY_LOCATION);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static short getShortVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_READ);
-        short result = getShort(thisObj, o, offset);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putShort(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, short x) {
-        UnsafeStoreNode.store(o, offset, x, Kind.Short, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putShortVolatile(final Object thisObj, Object o, long offset, short x) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_WRITE);
-        putShort(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static char getChar(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        @JavacBug(id = 6995200)
-        Character result = UnsafeLoadNode.load(o, offset, Kind.Char, LocationIdentity.ANY_LOCATION);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static char getCharVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_READ);
-        char result = getChar(thisObj, o, offset);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putChar(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, char x) {
-        UnsafeStoreNode.store(o, offset, x, Kind.Char, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putCharVolatile(final Object thisObj, Object o, long offset, char x) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_WRITE);
-        putChar(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static long getLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        @JavacBug(id = 6995200)
-        Long result = UnsafeLoadNode.load(o, offset, Kind.Long, LocationIdentity.ANY_LOCATION);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static long getLongVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_READ);
-        long result = getLong(thisObj, o, offset);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long x) {
-        UnsafeStoreNode.store(o, offset, x, Kind.Long, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putLongVolatile(final Object thisObj, Object o, long offset, long x) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_WRITE);
-        putLong(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putOrderedLong(final Object thisObj, Object o, long offset, long x) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_WRITE);
-        putLong(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static float getFloat(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        @JavacBug(id = 6995200)
-        Float result = UnsafeLoadNode.load(o, offset, Kind.Float, LocationIdentity.ANY_LOCATION);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static float getFloatVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_READ);
-        float result = getFloat(thisObj, o, offset);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putFloat(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, float x) {
-        UnsafeStoreNode.store(o, offset, x, Kind.Float, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putFloatVolatile(final Object thisObj, Object o, long offset, float x) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_WRITE);
-        putFloat(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static double getDouble(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) {
-        @JavacBug(id = 6995200)
-        Double result = UnsafeLoadNode.load(o, offset, Kind.Double, LocationIdentity.ANY_LOCATION);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static double getDoubleVolatile(final Object thisObj, Object o, long offset) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_READ);
-        double result = getDouble(thisObj, o, offset);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_READ);
-        return result;
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putDouble(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, double x) {
-        UnsafeStoreNode.store(o, offset, x, Kind.Double, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putDoubleVolatile(final Object thisObj, Object o, long offset, double x) {
-        MembarNode.memoryBarrier(JMM_PRE_VOLATILE_WRITE);
-        putDouble(thisObj, o, offset, x);
-        MembarNode.memoryBarrier(JMM_POST_VOLATILE_WRITE);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putByte(@SuppressWarnings("unused") final Object thisObj, long address, byte value) {
-        DirectStoreNode.store(address, value, Kind.Byte);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putShort(@SuppressWarnings("unused") final Object thisObj, long address, short value) {
-        DirectStoreNode.store(address, value, Kind.Short);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putChar(@SuppressWarnings("unused") final Object thisObj, long address, char value) {
-        DirectStoreNode.store(address, value, Kind.Char);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putInt(@SuppressWarnings("unused") final Object thisObj, long address, int value) {
-        DirectStoreNode.store(address, value, Kind.Int);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putLong(@SuppressWarnings("unused") final Object thisObj, long address, long value) {
-        DirectStoreNode.store(address, value, Kind.Long);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putFloat(@SuppressWarnings("unused") final Object thisObj, long address, float value) {
-        DirectStoreNode.store(address, value, Kind.Float);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static void putDouble(@SuppressWarnings("unused") final Object thisObj, long address, double value) {
-        DirectStoreNode.store(address, value, Kind.Double);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static byte getByte(@SuppressWarnings("unused") final Object thisObj, long address) {
-        return DirectReadNode.read(address, Kind.Byte);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static short getShort(@SuppressWarnings("unused") final Object thisObj, long address) {
-        return DirectReadNode.read(address, Kind.Short);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static char getChar(@SuppressWarnings("unused") final Object thisObj, long address) {
-        return DirectReadNode.read(address, Kind.Char);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static int getInt(@SuppressWarnings("unused") final Object thisObj, long address) {
-        return DirectReadNode.read(address, Kind.Int);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static long getLong(@SuppressWarnings("unused") final Object thisObj, long address) {
-        return DirectReadNode.read(address, Kind.Long);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static float getFloat(@SuppressWarnings("unused") final Object thisObj, long address) {
-        return DirectReadNode.read(address, Kind.Float);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static double getDouble(@SuppressWarnings("unused") final Object thisObj, long address) {
-        return DirectReadNode.read(address, Kind.Double);
-    }
-
-    @MethodSubstitution(isStatic = false)
-    public static Object allocateInstance(final Unsafe thisObj, Class<?> clazz) throws InstantiationException {
-        if (clazz.isPrimitive()) {
-            throw new InstantiationException(clazz.getName());
+    public static Object allocateInstance(@SuppressWarnings("unused") final Unsafe thisObj, Class<?> clazz) {
+        if (probability(SLOW_PATH_PROBABILITY, clazz.isPrimitive())) {
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
-        if (clazz.isArray() || clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
-            throw new InstantiationException(clazz.getName());
+        if (probability(SLOW_PATH_PROBABILITY, clazz.isArray() || clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()))) {
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
-        if (clazz == Class.class) {
-            thisObj.throwException(new IllegalAccessException(clazz.getName()));
+        if (probability(SLOW_PATH_PROBABILITY, clazz == Class.class)) {
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
         return DynamicNewInstanceNode.allocateInstance(clazz, true);
     }
-
-    /**
-     * Guard for {@link Unsafe#getAndSetInt} method family.
-     */
-    public static class GetAndSetGuard implements SubstitutionGuard {
-        public boolean execute() {
-            // FIXME should return whether the current compilation target supports these
-            String arch = System.getProperty("os.arch");
-            switch (arch) {
-                case "amd64":
-                case "x86_64":
-                    return true;
-                default:
-                    return false;
-            }
-        }
-    }
-
-    @MethodSubstitution(isStatic = false, guard = GetAndSetGuard.class)
-    public static int getAndAddInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int delta) {
-        return AtomicReadAndAddNode.getAndAddInt(o, offset, delta, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false, guard = GetAndSetGuard.class)
-    public static long getAndAddLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long delta) {
-        return AtomicReadAndAddNode.getAndAddLong(o, offset, delta, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false, guard = GetAndSetGuard.class)
-    public static int getAndSetInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int newValue) {
-        return AtomicReadAndWriteNode.getAndSetInt(o, offset, newValue, Kind.Int, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false, guard = GetAndSetGuard.class)
-    public static long getAndSetLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long newValue) {
-        return AtomicReadAndWriteNode.getAndSetLong(o, offset, newValue, Kind.Long, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution(isStatic = false, guard = GetAndSetGuard.class)
-    public static Object getAndSetObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object newValue) {
-        return AtomicReadAndWriteNode.getAndSetObject(o, offset, newValue, Kind.Object, LocationIdentity.ANY_LOCATION);
-    }
-
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsignedMathSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
-/*
- * Copyright (c) 2011, 2014, 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.compiler.common.calc.Condition.*;
-import static com.oracle.graal.nodes.calc.ConditionalNode.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.calc.*;
-
-/**
- * Substitutions for {@link UnsignedMath}.
- */
-@ClassSubstitution(UnsignedMath.class)
-public class UnsignedMathSubstitutions {
-
-    @MethodSubstitution
-    public static boolean aboveThan(int a, int b) {
-        return materializeCondition(BT, b, a);
-    }
-
-    @MethodSubstitution
-    public static boolean aboveOrEqual(int a, int b) {
-        return !materializeCondition(BT, a, b);
-    }
-
-    /**
-     * Unsigned comparison belowThan for two numbers.
-     */
-    @MethodSubstitution
-    public static boolean belowThan(int a, int b) {
-        return materializeCondition(BT, a, b);
-    }
-
-    /**
-     * Unsigned comparison belowOrEqual for two numbers.
-     */
-    @MethodSubstitution
-    public static boolean belowOrEqual(int a, int b) {
-        return !materializeCondition(BT, b, a);
-    }
-
-    /**
-     * Unsigned comparison aboveThan for two numbers.
-     */
-    @MethodSubstitution
-    public static boolean aboveThan(long a, long b) {
-        return materializeCondition(BT, b, a);
-    }
-
-    /**
-     * Unsigned comparison aboveOrEqual for two numbers.
-     */
-    @MethodSubstitution
-    public static boolean aboveOrEqual(long a, long b) {
-        return !materializeCondition(BT, a, b);
-    }
-
-    /**
-     * Unsigned comparison belowThan for two numbers.
-     */
-    @MethodSubstitution
-    public static boolean belowThan(long a, long b) {
-        return materializeCondition(BT, a, b);
-    }
-
-    /**
-     * Unsigned comparison belowOrEqual for two numbers.
-     */
-    @MethodSubstitution
-    public static boolean belowOrEqual(long a, long b) {
-        return !materializeCondition(BT, b, a);
-    }
-
-    /**
-     * Unsigned division for two numbers.
-     */
-    @MethodSubstitution
-    public static int divide(int a, int b) {
-        return UnsignedDivNode.unsignedDivide(a, b);
-    }
-
-    /**
-     * Unsigned remainder for two numbers.
-     */
-    @MethodSubstitution
-    public static int remainder(int a, int b) {
-        return UnsignedRemNode.unsignedRemainder(a, b);
-    }
-
-    /**
-     * Unsigned division for two numbers.
-     */
-    @MethodSubstitution
-    public static long divide(long a, long b) {
-        return UnsignedDivNode.unsignedDivide(a, b);
-    }
-
-    /**
-     * Unsigned remainder for two numbers.
-     */
-    @MethodSubstitution
-    public static long remainder(long a, long b) {
-        return UnsignedRemNode.unsignedRemainder(a, b);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java	Thu Mar 12 15:59:01 2015 +0100
@@ -0,0 +1,297 @@
+/*
+ * 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.meta.LocationIdentity.*;
+import static com.oracle.graal.nodes.ConstantNode.*;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugin.GenericInvocationPlugin;
+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.word.*;
+import com.oracle.graal.word.Word.Opcode;
+import com.oracle.graal.word.Word.Operation;
+import com.oracle.graal.word.nodes.*;
+
+/**
+ * A {@link GenericInvocationPlugin} for calls to {@linkplain Operation word operations}.
+ */
+public class WordOperationPlugin implements GenericInvocationPlugin {
+    protected final WordTypes wordTypes;
+    protected final Kind wordKind;
+    protected final SnippetReflectionProvider snippetReflection;
+
+    public WordOperationPlugin(SnippetReflectionProvider snippetReflection, WordTypes wordTypes) {
+        this.snippetReflection = snippetReflection;
+        this.wordTypes = wordTypes;
+        this.wordKind = wordTypes.getWordKind();
+    }
+
+    /**
+     * Processes a call to a method if it is annotated with {@link Operation} by adding nodes to the
+     * graph being built that implement the denoted operation.
+     *
+     * @return {@code true} iff {@code method} is annotated with {@link Operation} (and was thus
+     *         processed by this method)
+     */
+    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        if (!wordTypes.isWordOperation(method)) {
+            return false;
+        }
+        processWordOperation(b, args, wordTypes.getWordOperation(method, b.getMethod().getDeclaringClass()));
+        return true;
+    }
+
+    protected void processWordOperation(GraphBuilderContext b, ValueNode[] args, ResolvedJavaMethod wordMethod) throws GraalInternalError {
+        Operation operation = wordMethod.getAnnotation(Word.Operation.class);
+        Kind returnKind = wordMethod.getSignature().getReturnKind();
+        Kind returnStackKind = returnKind.getStackKind();
+        switch (operation.opcode()) {
+            case NODE_CLASS:
+                assert args.length == 2;
+                ValueNode left = args[0];
+                ValueNode right = operation.rightOperandIsInt() ? toUnsigned(b, args[1], Kind.Int) : fromSigned(b, args[1]);
+
+                b.push(returnStackKind, b.append(createBinaryNodeInstance(operation.node(), left, right)));
+                break;
+
+            case COMPARISON:
+                assert args.length == 2;
+                b.push(returnStackKind, comparisonOp(b, operation.condition(), args[0], fromSigned(b, args[1])));
+                break;
+
+            case NOT:
+                assert args.length == 1;
+                b.push(returnStackKind, b.append(new XorNode(args[0], b.append(forIntegerKind(wordKind, -1)))));
+                break;
+
+            case READ_POINTER:
+            case READ_OBJECT:
+            case READ_BARRIERED: {
+                assert args.length == 2 || args.length == 3;
+                Kind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass()));
+                LocationNode location;
+                if (args.length == 2) {
+                    location = makeLocation(b, args[1], ANY_LOCATION);
+                } else {
+                    location = makeLocation(b, args[1], args[2]);
+                }
+                b.push(returnStackKind, readOp(b, readKind, args[0], location, operation.opcode()));
+                break;
+            }
+            case READ_HEAP: {
+                assert args.length == 3;
+                Kind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass()));
+                LocationNode location = makeLocation(b, args[1], ANY_LOCATION);
+                BarrierType barrierType = snippetReflection.asObject(BarrierType.class, args[2].asJavaConstant());
+                b.push(returnStackKind, readOp(b, readKind, args[0], location, barrierType, true));
+                break;
+            }
+            case WRITE_POINTER:
+            case WRITE_OBJECT:
+            case WRITE_BARRIERED:
+            case INITIALIZE: {
+                assert args.length == 3 || args.length == 4;
+                Kind writeKind = wordTypes.asKind(wordMethod.getSignature().getParameterType(wordMethod.isStatic() ? 2 : 1, wordMethod.getDeclaringClass()));
+                LocationNode location;
+                if (args.length == 3) {
+                    location = makeLocation(b, args[1], LocationIdentity.ANY_LOCATION);
+                } else {
+                    location = makeLocation(b, args[1], args[3]);
+                }
+                writeOp(b, writeKind, args[0], args[2], location, operation.opcode());
+                break;
+            }
+            case ZERO:
+                assert args.length == 0;
+                b.push(returnStackKind, b.append(forIntegerKind(wordKind, 0L)));
+                break;
+
+            case FROM_UNSIGNED:
+                assert args.length == 1;
+                b.push(returnStackKind, fromUnsigned(b, args[0]));
+                break;
+
+            case FROM_SIGNED:
+                assert args.length == 1;
+                b.push(returnStackKind, fromSigned(b, args[0]));
+                break;
+
+            case TO_RAW_VALUE:
+                assert args.length == 1;
+                b.push(returnStackKind, toUnsigned(b, args[0], Kind.Long));
+                break;
+
+            case FROM_WORDBASE:
+                assert args.length == 1;
+                b.push(returnStackKind, args[0]);
+                break;
+
+            case FROM_OBJECT:
+                assert args.length == 1;
+                WordCastNode objectToWord = b.append(WordCastNode.objectToWord(args[0], wordKind));
+                b.push(returnStackKind, objectToWord);
+                break;
+
+            case FROM_ARRAY:
+                assert args.length == 2;
+                b.push(returnStackKind, b.append(new ComputeAddressNode(args[0], args[1], StampFactory.forKind(wordKind))));
+                break;
+
+            case TO_OBJECT:
+                assert args.length == 1;
+                WordCastNode wordToObject = b.append(WordCastNode.wordToObject(args[0], wordKind));
+                b.push(returnStackKind, wordToObject);
+                break;
+
+            default:
+                throw new GraalInternalError("Unknown opcode: %s", operation.opcode());
+        }
+    }
+
+    /**
+     * Create an instance of a binary node which is used to lower {@link Word} operations. This
+     * method is called for all {@link Word} operations which are annotated with @Operation(node =
+     * ...) and encapsulates the reflective allocation of the node.
+     */
+    private static ValueNode createBinaryNodeInstance(Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right) {
+        try {
+            Constructor<?> cons = nodeClass.getDeclaredConstructor(ValueNode.class, ValueNode.class);
+            return (ValueNode) cons.newInstance(left, right);
+        } catch (Throwable ex) {
+            throw new GraalInternalError(ex).addContext(nodeClass.getName());
+        }
+    }
+
+    private ValueNode comparisonOp(GraphBuilderContext graph, Condition condition, ValueNode left, ValueNode right) {
+        assert left.getKind() == wordKind && right.getKind() == wordKind;
+
+        // mirroring gets the condition into canonical form
+        boolean mirror = condition.canonicalMirror();
+
+        ValueNode a = mirror ? right : left;
+        ValueNode b = mirror ? left : right;
+
+        CompareNode comparison;
+        if (condition == Condition.EQ || condition == Condition.NE) {
+            comparison = new IntegerEqualsNode(a, b);
+        } else if (condition.isUnsigned()) {
+            comparison = new IntegerBelowNode(a, b);
+        } else {
+            comparison = new IntegerLessThanNode(a, b);
+        }
+
+        ConstantNode trueValue = graph.append(forInt(1));
+        ConstantNode falseValue = graph.append(forInt(0));
+
+        if (condition.canonicalNegate()) {
+            ConstantNode temp = trueValue;
+            trueValue = falseValue;
+            falseValue = temp;
+        }
+        ConditionalNode materialize = graph.append(new ConditionalNode(graph.append(comparison), trueValue, falseValue));
+        return materialize;
+    }
+
+    protected ValueNode readOp(GraphBuilderContext b, Kind readKind, ValueNode base, LocationNode location, Opcode op) {
+        assert op == Opcode.READ_POINTER || op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED;
+        final BarrierType barrier = (op == Opcode.READ_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE);
+        final boolean compressible = (op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED);
+
+        return readOp(b, readKind, base, location, barrier, compressible);
+    }
+
+    public static ValueNode readOp(GraphBuilderContext b, Kind readKind, ValueNode base, LocationNode location, BarrierType barrierType, boolean compressible) {
+        JavaReadNode read = b.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(AbstractBeginNode.prevBegin(read));
+        return read;
+    }
+
+    protected void writeOp(GraphBuilderContext b, Kind writeKind, ValueNode base, ValueNode value, LocationNode location, Opcode op) {
+        assert op == Opcode.WRITE_POINTER || op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED || op == Opcode.INITIALIZE;
+        final BarrierType barrier = (op == Opcode.WRITE_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE);
+        final boolean compressible = (op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED);
+        final boolean initialize = (op == Opcode.INITIALIZE);
+        b.append(new JavaWriteNode(writeKind, base, value, location, barrier, compressible, initialize));
+    }
+
+    public LocationNode makeLocation(GraphBuilderContext b, ValueNode offset, LocationIdentity locationIdentity) {
+        return b.append(new IndexedLocationNode(locationIdentity, 0, fromSigned(b, offset), 1));
+    }
+
+    public LocationNode makeLocation(GraphBuilderContext b, ValueNode offset, ValueNode locationIdentity) {
+        if (locationIdentity.isConstant()) {
+            return makeLocation(b, offset, snippetReflection.asObject(LocationIdentity.class, locationIdentity.asJavaConstant()));
+        }
+        return b.append(new SnippetLocationNode(snippetReflection, locationIdentity, b.append(ConstantNode.forLong(0)), fromSigned(b, offset), b.append(ConstantNode.forInt(1))));
+    }
+
+    public ValueNode fromUnsigned(GraphBuilderContext b, ValueNode value) {
+        return convert(b, value, wordKind, true);
+    }
+
+    public ValueNode fromSigned(GraphBuilderContext b, ValueNode value) {
+        return convert(b, value, wordKind, false);
+    }
+
+    public ValueNode toUnsigned(GraphBuilderContext b, ValueNode value, Kind toKind) {
+        return convert(b, value, toKind, true);
+    }
+
+    public ValueNode convert(GraphBuilderContext b, ValueNode value, Kind toKind, boolean unsigned) {
+        if (value.getKind() == toKind) {
+            return value;
+        }
+
+        if (toKind == Kind.Int) {
+            assert value.getKind() == Kind.Long;
+            return b.append(new NarrowNode(value, 32));
+        } else {
+            assert toKind == Kind.Long;
+            assert value.getKind().getStackKind() == Kind.Int;
+            if (unsigned) {
+                return b.append(new ZeroExtendNode(value, 64));
+            } else {
+                return b.append(new SignExtendNode(value, 64));
+            }
+        }
+    }
+
+    public WordTypes getWordTypes() {
+        return wordTypes;
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/AssertionNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/AssertionNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -86,9 +86,6 @@
         }
     }
 
-    @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static void assertion(@ConstantNodeParameter boolean compileTimeAssertion, boolean value, @ConstantNodeParameter String message) {
-        assert value : message;
-    }
+    public static native void assertion(@ConstantNodeParameter boolean compileTimeAssertion, boolean value, @ConstantNodeParameter String message);
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -24,8 +24,8 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
@@ -77,10 +77,10 @@
         } else if (objectStamp.isExactType()) {
             return isCloneableType(objectStamp.type(), metaAccess) ? objectStamp.type() : null;
         } else {
-            ResolvedJavaType type = objectStamp.type().findUniqueConcreteSubtype();
-            if (type != null && isCloneableType(type, metaAccess)) {
-                assumptions.recordConcreteSubtype(objectStamp.type(), type);
-                return type;
+            AssumptionResult<ResolvedJavaType> leafConcreteSubtype = objectStamp.type().findLeafConcreteSubtype();
+            if (leafConcreteSubtype != null && isCloneableType(leafConcreteSubtype.getResult(), metaAccess)) {
+                assumptions.record(leafConcreteSubtype);
+                return leafConcreteSubtype.getResult();
             } else {
                 return null;
             }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -47,28 +47,18 @@
         IntegerStamp valueStamp = (IntegerStamp) getValue().stamp();
         assert (valueStamp.downMask() & CodeUtil.mask(valueStamp.getBits())) == valueStamp.downMask();
         assert (valueStamp.upMask() & CodeUtil.mask(valueStamp.getBits())) == valueStamp.upMask();
-        return updateStamp(StampFactory.forInteger(Kind.Int, bitCount(valueStamp.downMask()), bitCount(valueStamp.upMask())));
+        return updateStamp(StampFactory.forInteger(Kind.Int, Long.bitCount(valueStamp.downMask()), Long.bitCount(valueStamp.upMask())));
     }
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
         if (forValue.isConstant()) {
             JavaConstant c = forValue.asJavaConstant();
-            return ConstantNode.forInt(forValue.getKind() == Kind.Int ? bitCount(c.asInt()) : bitCount(c.asLong()));
+            return ConstantNode.forInt(forValue.getKind() == Kind.Int ? Integer.bitCount(c.asInt()) : Long.bitCount(c.asLong()));
         }
         return this;
     }
 
-    @NodeIntrinsic
-    public static int bitCount(int v) {
-        return Integer.bitCount(v);
-    }
-
-    @NodeIntrinsic
-    public static int bitCount(long v) {
-        return Long.bitCount(v);
-    }
-
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         Value result = gen.getLIRGeneratorTool().emitBitCount(gen.operand(getValue()));
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DeferredPiNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DeferredPiNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -66,5 +66,5 @@
     }
 
     @NodeIntrinsic
-    public static native <T> T piCast(Class<T> type, Object object);
+    public static native Object piCast(Class<?> type, Object object);
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.replacements.nodes;
 
-import static com.oracle.graal.compiler.common.UnsafeAccess.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -81,32 +79,4 @@
         }
         gen.setResult(this, loaded);
     }
-
-    @SuppressWarnings("unchecked")
-    @NodeIntrinsic
-    public static <T> T read(long address, @ConstantNodeParameter Kind kind) {
-        if (kind == Kind.Boolean) {
-            return (T) Boolean.valueOf(unsafe.getByte(address) != 0);
-        }
-        if (kind == Kind.Byte) {
-            return (T) (Byte) unsafe.getByte(address);
-        }
-        if (kind == Kind.Short) {
-            return (T) (Short) unsafe.getShort(address);
-        }
-        if (kind == Kind.Char) {
-            return (T) (Character) unsafe.getChar(address);
-        }
-        if (kind == Kind.Int) {
-            return (T) (Integer) unsafe.getInt(address);
-        }
-        if (kind == Kind.Float) {
-            return (T) (Float) unsafe.getFloat(address);
-        }
-        if (kind == Kind.Long) {
-            return (T) (Long) unsafe.getLong(address);
-        }
-        assert kind == Kind.Double;
-        return (T) (Double) unsafe.getDouble(address);
-    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.replacements.nodes;
 
-import static com.oracle.graal.compiler.common.UnsafeAccess.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -66,58 +64,6 @@
         return value;
     }
 
-    /*
-     * The kind of the store is provided explicitly in these intrinsics because it is not always
-     * possible to determine the kind from the given value during compilation (because stack kinds
-     * are used).
-     */
-
-    @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static void store(long address, boolean value, @ConstantNodeParameter Kind kind) {
-        int b = value ? 1 : 0;
-        unsafe.putByte(address, (byte) b);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(long address, byte value, @ConstantNodeParameter Kind kind) {
-        unsafe.putByte(address, value);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(long address, short value, @ConstantNodeParameter Kind kind) {
-        unsafe.putShort(address, value);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(long address, char value, @ConstantNodeParameter Kind kind) {
-        unsafe.putChar(address, value);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(long address, int value, @ConstantNodeParameter Kind kind) {
-        unsafe.putInt(address, value);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(long address, long value, @ConstantNodeParameter Kind kind) {
-        unsafe.putLong(address, value);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(long address, float value, @ConstantNodeParameter Kind kind) {
-        unsafe.putFloat(address, value);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static void store(long address, double value, @ConstantNodeParameter Kind kind) {
-        unsafe.putDouble(address, value);
-    }
+    public static native void storeBoolean(long address, boolean value, @ConstantNodeParameter Kind kind);
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -51,7 +51,23 @@
         return operation;
     }
 
-    public MathIntrinsicNode(ValueNode value, Operation op) {
+    public static ValueNode create(ValueNode value, Operation op) {
+        ValueNode c = tryConstantFold(value, op);
+        if (c != null) {
+            return c;
+        }
+        return new MathIntrinsicNode(value, op);
+    }
+
+    protected static ValueNode tryConstantFold(ValueNode value, Operation op) {
+        if (value.isConstant()) {
+            double ret = doCompute(value.asJavaConstant().asDouble(), op);
+            return ConstantNode.forDouble(ret);
+        }
+        return null;
+    }
+
+    protected MathIntrinsicNode(ValueNode value, Operation op) {
         super(TYPE, StampFactory.forKind(Kind.Double), value);
         assert value.stamp() instanceof FloatStamp && PrimitiveStamp.getBits(value.stamp()) == 64;
         this.operation = op;
@@ -85,17 +101,15 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
-        if (forValue.isConstant()) {
-            double ret = doCompute(forValue.asJavaConstant().asDouble(), operation());
-            return ConstantNode.forDouble(ret);
+        ValueNode c = tryConstantFold(forValue, operation());
+        if (c != null) {
+            return c;
         }
         return this;
     }
 
     @NodeIntrinsic
-    public static double compute(double value, @ConstantNodeParameter Operation op) {
-        return doCompute(value, op);
-    }
+    public static native double compute(double value, @ConstantNodeParameter Operation op);
 
     private static double doCompute(double value, Operation op) {
         switch (op) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -48,9 +48,9 @@
         Stamp newStamp;
         if (getKind() == Kind.Int) {
             long mask = CodeUtil.mask(Kind.Int.getBitCount());
-            newStamp = IntegerStamp.stampForMask(valueStamp.getBits(), reverse((int) valueStamp.downMask()) & mask, reverse((int) valueStamp.upMask()) & mask);
+            newStamp = IntegerStamp.stampForMask(valueStamp.getBits(), Integer.reverse((int) valueStamp.downMask()) & mask, Integer.reverse((int) valueStamp.upMask()) & mask);
         } else if (getKind() == Kind.Long) {
-            newStamp = IntegerStamp.stampForMask(valueStamp.getBits(), reverse(valueStamp.downMask()), reverse(valueStamp.upMask()));
+            newStamp = IntegerStamp.stampForMask(valueStamp.getBits(), Long.reverse(valueStamp.downMask()), Long.reverse(valueStamp.upMask()));
         } else {
             return false;
         }
@@ -61,21 +61,12 @@
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
         if (forValue.isConstant()) {
             JavaConstant c = forValue.asJavaConstant();
-            return ConstantNode.forIntegerKind(getKind(), getKind() == Kind.Int ? reverse(c.asInt()) : reverse(c.asLong()));
+            long reversed = getKind() == Kind.Int ? Integer.reverseBytes(c.asInt()) : Long.reverseBytes(c.asLong());
+            return ConstantNode.forIntegerKind(getKind(), reversed);
         }
         return this;
     }
 
-    @NodeIntrinsic
-    public static int reverse(int v) {
-        return Integer.reverseBytes(v);
-    }
-
-    @NodeIntrinsic
-    public static long reverse(long v) {
-        return Long.reverseBytes(v);
-    }
-
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         Value result = gen.getLIRGeneratorTool().emitByteSwap(gen.operand(getValue()));
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleReplacements.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleReplacements.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,10 +22,8 @@
  */
 package com.oracle.graal.truffle.hotspot;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.runtime.*;
@@ -42,9 +40,4 @@
         SnippetReflectionProvider snippetReflection = Graal.getRequiredCapability(SnippetReflectionProvider.class);
         return new HotSpotTruffleReplacements(providers, snippetReflection);
     }
-
-    @Override
-    protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original, FrameStateProcessing frameStateProcessing) {
-        return new HotSpotReplacementsImpl.HotSpotGraphMaker(this, substitute, original, frameStateProcessing);
-    }
 }
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Thu Mar 12 15:59:01 2015 +0100
@@ -192,7 +192,7 @@
         LIRSuites lirSuites = suitesProvider.createLIRSuites();
         removeInliningPhase(suites);
         StructuredGraph graph = new StructuredGraph(javaMethod, AllowAssumptions.NO);
-        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
+        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL, null).apply(graph);
         PhaseSuite<HighTierContext> graphBuilderSuite = getGraphBuilderSuite(suitesProvider);
         CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
         Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
@@ -315,7 +315,7 @@
     public void notifyTransferToInterpreter() {
         CompilerAsserts.neverPartOfCompilation();
         if (TraceTruffleTransferToInterpreter.getValue()) {
-            Word thread = CurrentJavaThreadNode.get(HotSpotGraalRuntime.runtime().getTarget().wordKind);
+            Word thread = CurrentJavaThreadNode.get();
             boolean deoptimized = thread.readByte(HotSpotGraalRuntime.runtime().getConfig().pendingTransferToInterpreterOffset) != 0;
             if (deoptimized) {
                 thread.writeByte(HotSpotGraalRuntime.runtime().getConfig().pendingTransferToInterpreterOffset, (byte) 0);
--- a/graal/com.oracle.graal.truffle.test/sl/TestInliningRecursive1.sl	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/sl/TestInliningRecursive1.sl	Thu Mar 12 15:59:01 2015 +0100
@@ -20,6 +20,4 @@
 
 function main() {
     callUntilOptimized(test);
-    assertTrue(isInlined(test, test, fib), "fib is not inlined");
-    assertFalse(isInlined(test, fib, fib), "fib -> fib is not inlined");
 }  
--- a/graal/com.oracle.graal.truffle.test/sl/TestInliningRecursive2.sl	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/sl/TestInliningRecursive2.sl	Thu Mar 12 15:59:01 2015 +0100
@@ -29,9 +29,4 @@
 function main() {
     callUntilOptimized(test);
     assertTrue(isInlined(test, test, fib), "not inlined: test -> fib");
-    
-    assertTrue(isInlined(test, fib, call), "not inlined: fib -> call");
-    assertFalse(isInlined(test, call, fib), "inlined: call -> fib"); 
-    assertTrue(isInlined(test, call, void), "inlined: call -> void");
-    
 }  
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ExactMathTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -24,23 +24,17 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.test.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.runtime.*;
+import com.oracle.graal.java.*;
 import com.oracle.graal.truffle.substitutions.*;
 import com.oracle.truffle.api.*;
 
 public class ExactMathTest extends GraalCompilerTest {
 
-    private static boolean substitutionsInstalled;
-
-    public ExactMathTest() {
-        if (!substitutionsInstalled) {
-            Replacements replacements = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getProviders().getReplacements();
-            replacements.registerSubstitutions(ExactMath.class, ExactMathSubstitutions.class);
-            substitutionsInstalled = true;
-        }
+    @Override
+    protected void editGraphBuilderPlugins(GraphBuilderConfiguration.Plugins plugins) {
+        TruffleGraphBuilderPlugins.registerExactMathPlugins(getMetaAccess(), plugins.getInvocationPlugins());
+        super.editGraphBuilderPlugins(plugins);
     }
 
     @Test
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultInliningPolicy.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultInliningPolicy.java	Thu Mar 12 15:59:01 2015 +0100
@@ -28,7 +28,7 @@
 
 public class DefaultInliningPolicy implements TruffleInliningPolicy {
 
-    private static final String REASON_RECURSION = "recursion";
+    private static final String REASON_RECURSION = "number of recursions > " + TruffleMaximumRecursiveInlining.getValue();
     private static final String REASON_MAXIMUM_NODE_COUNT = "deepNodeCount * callSites  > " + TruffleInliningMaxCallerSize.getValue();
     private static final String REASON_MAXIMUM_TOTAL_NODE_COUNT = "totalNodeCount > " + TruffleInliningMaxCallerSize.getValue();
 
@@ -39,7 +39,7 @@
 
     @Override
     public boolean isAllowed(TruffleInliningProfile profile, int currentNodeCount, CompilerOptions options) {
-        if (profile.isRecursiveCall()) {
+        if (profile.getRecursions() > TruffleMaximumRecursiveInlining.getValue()) {
             profile.setFailedReason(REASON_RECURSION);
             return false;
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Thu Mar 12 15:59:01 2015 +0100
@@ -31,6 +31,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
@@ -38,6 +39,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin;
 import com.oracle.graal.java.GraphBuilderPlugin.ParameterPlugin;
 import com.oracle.graal.loop.*;
@@ -175,7 +177,7 @@
             this.receiver = receiver;
         }
 
-        public FloatingNode interceptParameter(int index) {
+        public FloatingNode interceptParameter(GraphBuilderContext b, int index, Stamp stamp) {
             if (index == 0) {
                 return ConstantNode.forConstant(snippetReflection.forObject(receiver), providers.getMetaAccess());
             }
@@ -195,7 +197,7 @@
             this.replacements = replacements;
         }
 
-        public ResolvedJavaMethod getInlinedMethod(GraphBuilderContext builder, ResolvedJavaMethod original, ValueNode[] arguments, JavaType returnType, int depth) {
+        public InlineInfo getInlineInfo(GraphBuilderContext builder, ResolvedJavaMethod original, ValueNode[] arguments, JavaType returnType) {
             if (original.getAnnotation(TruffleBoundary.class) != null) {
                 return null;
             }
@@ -219,10 +221,10 @@
                 if (decision != null && decision.isInline()) {
                     inlining.push(decision);
                     builder.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) decision.getTarget().getNodeRewritingAssumption()));
-                    return callInlinedMethod;
+                    return new InlineInfo(callInlinedMethod, false);
                 }
             }
-            return original;
+            return new InlineInfo(original, false);
         }
 
         public void postInline(ResolvedJavaMethod inlinedTargetMethod) {
@@ -252,13 +254,15 @@
     private void fastPartialEvaluation(OptimizedCallTarget callTarget, StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) {
         GraphBuilderConfiguration newConfig = configForRoot.copy();
         newConfig.setUseProfiling(false);
-        newConfig.setLoadFieldPlugin(new InterceptLoadFieldPlugin());
-        newConfig.setParameterPlugin(new InterceptReceiverPlugin(callTarget));
+        Plugins plugins = newConfig.getPlugins();
+        plugins.setLoadFieldPlugin(new InterceptLoadFieldPlugin());
+        plugins.setParameterPlugin(new InterceptReceiverPlugin(callTarget));
         callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy()));
-        newConfig.setInlineInvokePlugin(new InlineInvokePlugin(callTarget.getInlining(), providers.getReplacements()));
-        newConfig.setLoopExplosionPlugin(new LoopExplosionPlugin());
-        TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), newConfig.getInvocationPlugins());
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), this.snippetReflection, providers.getConstantReflection(), newConfig, TruffleCompilerImpl.Optimizations).apply(graph);
+        plugins.setInlineInvokePlugin(new InlineInvokePlugin(callTarget.getInlining(), providers.getReplacements()));
+        plugins.setLoopExplosionPlugin(new LoopExplosionPlugin());
+        TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), newConfig.getPlugins().getInvocationPlugins());
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), this.snippetReflection, providers.getConstantReflection(), newConfig,
+                        TruffleCompilerImpl.Optimizations, null).apply(graph);
         Debug.dump(graph, "After FastPE");
 
         // Perform deoptimize to guard conversion.
@@ -332,13 +336,13 @@
     }
 
     public StructuredGraph createRootGraph(StructuredGraph graph) {
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations).apply(graph);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations, null).apply(graph);
         return graph;
     }
 
     public StructuredGraph createInlineGraph(String name, StructuredGraph caller) {
         StructuredGraph graph = new StructuredGraph(name, callInlinedMethod, AllowAssumptions.from(caller.getAssumptions() != null));
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations).apply(graph);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations, null).apply(graph);
         return graph;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Thu Mar 12 15:59:01 2015 +0100
@@ -269,7 +269,7 @@
     }
 
     protected StructuredGraph parseGraph(StructuredGraph graph, final PhaseContext phaseContext) {
-        new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), phaseContext.getStampProvider(), null, config, optimisticOptimizations).apply(graph);
+        new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), phaseContext.getStampProvider(), null, config, optimisticOptimizations, null).apply(graph);
         return graph;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Thu Mar 12 15:59:01 2015 +0100
@@ -27,7 +27,7 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.Assumptions.Assumption;
+import com.oracle.graal.api.meta.Assumptions.Assumption;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
@@ -93,7 +93,7 @@
         this.config = GraphBuilderConfiguration.getDefault().withSkippedExceptionTypes(skippedExceptionTypes);
         if (TruffleCompilerOptions.FastPE.getValue()) {
             GraphBuilderPhase phase = (GraphBuilderPhase) backend.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous();
-            this.config.getInvocationPlugins().setDefaults(phase.getGraphBuilderConfig().getInvocationPlugins());
+            this.config.getPlugins().getInvocationPlugins().setDefaults(phase.getGraphBuilderConfig().getPlugins().getInvocationPlugins());
         }
 
         this.truffleCache = new TruffleCacheImpl(providers, eagerConfig, TruffleCompilerImpl.Optimizations);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Thu Mar 12 15:59:01 2015 +0100
@@ -74,6 +74,9 @@
     @Option(help = "Stop inlining if caller's cumulative tree size would exceed this limit", type = OptionType.Expert)
     public static final OptionValue<Integer> TruffleInliningMaxCallerSize = new OptionValue<>(2250);
 
+    @Option(help = "Maximum level of recursive inlining", type = OptionType.Expert)
+    public static final OptionValue<Integer> TruffleMaximumRecursiveInlining = new OptionValue<>(4);
+
     @Option(help = "Defines the number of graal nodes that triggers a performance warning.", type = OptionType.Debug)
     public static final OptionValue<Integer> TrufflePerformanceWarningGraalNodeCount = new OptionValue<>(1000);
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java	Thu Mar 12 15:59:01 2015 +0100
@@ -68,15 +68,15 @@
         double frequency = calculateFrequency(parentTarget, callNode);
         int nodeCount = callNode.getCurrentCallTarget().countNonTrivialNodes();
 
-        boolean recursive = isRecursiveStack(callStack);
+        int recursions = countRecursions(callStack);
         int deepNodeCount = nodeCount;
-        if (!recursive && callStack.size() < 15) {
+        if (callStack.size() < 15 && recursions <= TruffleCompilerOptions.TruffleMaximumRecursiveInlining.getValue()) {
             /*
              * We make a preliminary optimistic inlining decision with best possible characteristics
              * to avoid the exploration of unnecessary paths in the inlining tree.
              */
             final CompilerOptions options = callNode.getRootNode().getCompilerOptions();
-            if (policy.isAllowed(new TruffleInliningProfile(callNode, nodeCount, nodeCount, frequency, recursive), callStackNodeCount, options)) {
+            if (policy.isAllowed(new TruffleInliningProfile(callNode, nodeCount, nodeCount, frequency, recursions), callStackNodeCount, options)) {
                 List<TruffleInliningDecision> exploredCallSites = exploreCallSites(callStack, callStackNodeCount + nodeCount, policy);
                 childCallSites = decideInlining(exploredCallSites, policy, nodeCount, options);
                 for (TruffleInliningDecision childCallSite : childCallSites) {
@@ -90,7 +90,7 @@
             }
         }
 
-        TruffleInliningProfile profile = new TruffleInliningProfile(callNode, nodeCount, deepNodeCount, frequency, recursive);
+        TruffleInliningProfile profile = new TruffleInliningProfile(callNode, nodeCount, deepNodeCount, frequency, recursions);
         profile.setScore(policy.calculateScore(profile));
         return new TruffleInliningDecision(currentTarget, profile, childCallSites);
     }
@@ -99,14 +99,16 @@
         return (double) Math.max(1, ocn.getCallCount()) / (double) Math.max(1, target.getCompilationProfile().getInterpreterCallCount());
     }
 
-    private static boolean isRecursiveStack(List<OptimizedCallTarget> stack) {
+    private static int countRecursions(List<OptimizedCallTarget> stack) {
+        int count = 0;
         OptimizedCallTarget top = stack.get(stack.size() - 1);
         for (int i = 0; i < stack.size() - 1; i++) {
             if (stack.get(i) == top) {
-                return true;
+                count++;
             }
         }
-        return false;
+
+        return count;
     }
 
     private static List<TruffleInliningDecision> decideInlining(List<TruffleInliningDecision> callSites, TruffleInliningPolicy policy, int nodeCount, CompilerOptions options) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Thu Mar 12 15:59:01 2015 +0100
@@ -30,22 +30,22 @@
     private final int nodeCount;
     private final int deepNodeCount;
     private final double frequency;
-    private final boolean recursiveCall;
+    private final int recursions;
 
     private String failedReason;
     private int queryIndex = -1;
     private double score;
 
-    public TruffleInliningProfile(OptimizedDirectCallNode callNode, int nodeCount, int deepNodeCount, double frequency, boolean recursiveCall) {
+    public TruffleInliningProfile(OptimizedDirectCallNode callNode, int nodeCount, int deepNodeCount, double frequency, int recursions) {
         this.callNode = callNode;
         this.nodeCount = nodeCount;
         this.deepNodeCount = deepNodeCount;
         this.frequency = frequency;
-        this.recursiveCall = recursiveCall;
+        this.recursions = recursions;
     }
 
-    public boolean isRecursiveCall() {
-        return recursiveCall;
+    public int getRecursions() {
+        return recursions;
     }
 
     public OptimizedDirectCallNode getCallNode() {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Thu Mar 12 15:59:01 2015 +0100
@@ -32,7 +32,6 @@
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.truffle.substitutions.*;
-import com.oracle.graal.truffle.unsafe.*;
 import com.oracle.truffle.api.*;
 
 /**
@@ -52,18 +51,13 @@
     protected void registerTruffleSubstitutions() {
         if (!TruffleCompilerOptions.FastPE.getValue()) {
             registerSubstitutions(CompilerAsserts.class, CompilerAssertsSubstitutions.class);
-            registerSubstitutions(CompilerDirectives.class, CompilerDirectivesSubstitutions.class);
-            registerSubstitutions(ExactMath.class, ExactMathSubstitutions.class);
             registerSubstitutions(OptimizedAssumption.class, OptimizedAssumptionSubstitutions.class);
-            registerSubstitutions(OptimizedCallTarget.class, OptimizedCallTargetSubstitutions.class);
-            registerSubstitutions(FrameWithoutBoxing.class, FrameWithoutBoxingSubstitutions.class);
-            registerSubstitutions(UnsafeAccessImpl.class, UnsafeAccessSubstitutions.class);
         }
     }
 
     @Override
-    public StructuredGraph getSnippet(ResolvedJavaMethod method) {
-        return graalReplacements.getSnippet(method);
+    public StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args) {
+        return graalReplacements.getSnippet(method, null, args);
     }
 
     @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.truffle.nodes;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionValidAssumption.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionValidAssumption.java	Thu Mar 12 15:59:01 2015 +0100
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.truffle.nodes;
 
-import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.truffle.*;
 
 public final class AssumptionValidAssumption extends Assumptions.Assumption {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -107,14 +107,4 @@
     public void lower(LoweringTool tool) {
         IntegerExactArithmeticSplitNode.lower(tool, this);
     }
-
-    @NodeIntrinsic
-    public static int addExact(int a, int b) {
-        return ExactMath.addExact(a, b);
-    }
-
-    @NodeIntrinsic
-    public static long addExact(long a, long b) {
-        return ExactMath.addExact(a, b);
-    }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -90,14 +90,4 @@
     public void lower(LoweringTool tool) {
         IntegerExactArithmeticSplitNode.lower(tool, this);
     }
-
-    @NodeIntrinsic
-    public static int multiplyExact(int a, int b) {
-        return ExactMath.multiplyExact(a, b);
-    }
-
-    @NodeIntrinsic
-    public static long multiplyExact(long a, long b) {
-        return ExactMath.multiplyExact(a, b);
-    }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulHighNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulHighNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -88,14 +88,4 @@
         Value b = builder.operand(getY());
         builder.setResult(this, gen.emitMulHigh(a, b));
     }
-
-    @NodeIntrinsic
-    public static int multiplyHigh(int a, int b) {
-        return ExactMath.multiplyHigh(a, b);
-    }
-
-    @NodeIntrinsic
-    public static long multiplyHigh(long a, long b) {
-        return ExactMath.multiplyHigh(a, b);
-    }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -96,12 +96,8 @@
     }
 
     @NodeIntrinsic
-    public static int subtractExact(int a, int b) {
-        return ExactMath.subtractExact(a, b);
-    }
+    public static native int subtractExact(int a, int b);
 
     @NodeIntrinsic
-    public static long subtractExact(long a, long b) {
-        return ExactMath.subtractExact(a, b);
-    }
+    public static native long subtractExact(long a, long b);
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/UnsignedMulHighNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/UnsignedMulHighNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -93,14 +93,4 @@
         Value b = builder.operand(getY());
         builder.setResult(this, gen.emitUMulHigh(a, b));
     }
-
-    @NodeIntrinsic
-    public static int multiplyHighUnsigned(int a, int b) {
-        return ExactMath.multiplyHighUnsigned(a, b);
-    }
-
-    @NodeIntrinsic
-    public static long multiplyHighUnsigned(long a, long b) {
-        return ExactMath.multiplyHighUnsigned(a, b);
-    }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/MaterializeFrameNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/MaterializeFrameNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -46,5 +46,5 @@
     }
 
     @NodeIntrinsic
-    public static native <T> T materialize(VirtualFrame frame);
+    public static native MaterializedFrame materialize(VirtualFrame frame);
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * 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.truffle.substitutions;
-
-import java.util.concurrent.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.truffle.nodes.*;
-import com.oracle.graal.truffle.nodes.frame.*;
-import com.oracle.truffle.api.*;
-
-@ClassSubstitution(CompilerDirectives.class)
-public class CompilerDirectivesSubstitutions {
-
-    @MethodSubstitution
-    public static void transferToInterpreter() {
-        DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter);
-    }
-
-    @MethodSubstitution
-    public static void transferToInterpreterAndInvalidate() {
-        DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter);
-    }
-
-    @MethodSubstitution
-    public static boolean inInterpreter() {
-        return false;
-    }
-
-    @MethodSubstitution
-    public static boolean inCompiledCode() {
-        return true;
-    }
-
-    @MethodSubstitution
-    public static void interpreterOnly(@SuppressWarnings("unused") Runnable runnable) {
-    }
-
-    @MethodSubstitution
-    public static <T> T interpreterOnly(@SuppressWarnings("unused") Callable<T> callable) throws Exception {
-        return null;
-    }
-
-    @MethodSubstitution
-    public static boolean injectBranchProbability(double probability, boolean condition) {
-        return BranchProbabilityNode.probability(probability, condition);
-    }
-
-    @MacroSubstitution(macro = BailoutNode.class, isStatic = true)
-    public static native void bailout(String reason);
-
-    @MethodSubstitution
-    public static boolean isCompilationConstant(Object value) {
-        return IsCompilationConstantNode.check(value);
-    }
-
-    @MethodSubstitution
-    public static void materialize(Object obj) {
-        ForceMaterializeNode.force(obj);
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/ExactMathSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * 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.truffle.substitutions;
-
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.truffle.nodes.arithmetic.*;
-import com.oracle.truffle.api.*;
-
-/**
- * Intrinsics for exact math operations that throw an exception in case the operation would overflow
- * the allowed range.
- */
-@ClassSubstitution(ExactMath.class)
-public class ExactMathSubstitutions {
-
-    @MethodSubstitution
-    public static int addExact(int x, int y) {
-        return IntegerAddExactNode.addExact(x, y);
-    }
-
-    @MethodSubstitution
-    public static long addExact(long x, long y) {
-        return IntegerAddExactNode.addExact(x, y);
-    }
-
-    @MethodSubstitution
-    public static int subtractExact(int x, int y) {
-        return IntegerSubExactNode.subtractExact(x, y);
-    }
-
-    @MethodSubstitution
-    public static long subtractExact(long x, long y) {
-        return IntegerSubExactNode.subtractExact(x, y);
-    }
-
-    @MethodSubstitution
-    public static int multiplyExact(int x, int y) {
-        return IntegerMulExactNode.multiplyExact(x, y);
-    }
-
-    @MethodSubstitution
-    public static long multiplyExact(long x, long y) {
-        return IntegerMulExactNode.multiplyExact(x, y);
-    }
-
-    @MethodSubstitution
-    public static int multiplyHigh(int x, int y) {
-        return IntegerMulHighNode.multiplyHigh(x, y);
-    }
-
-    @MethodSubstitution
-    public static int multiplyHighUnsigned(int x, int y) {
-        return UnsignedMulHighNode.multiplyHighUnsigned(x, y);
-    }
-
-    @MethodSubstitution
-    public static long multiplyHigh(long x, long y) {
-        return IntegerMulHighNode.multiplyHigh(x, y);
-    }
-
-    @MethodSubstitution
-    public static long multiplyHighUnsigned(long x, long y) {
-        return UnsignedMulHighNode.multiplyHighUnsigned(x, y);
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/FrameWithoutBoxingSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2014, 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.truffle.substitutions;
-
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.truffle.*;
-import com.oracle.graal.truffle.nodes.frame.*;
-import com.oracle.graal.truffle.nodes.typesystem.*;
-import com.oracle.truffle.api.frame.*;
-
-@ClassSubstitution(FrameWithoutBoxing.class)
-public class FrameWithoutBoxingSubstitutions {
-
-    @MethodSubstitution(isStatic = false)
-    public static MaterializedFrame materialize(FrameWithoutBoxing frame) {
-        return MaterializeFrameNode.materialize(frame);
-    }
-
-    @MacroSubstitution(macro = UnsafeTypeCastMacroNode.class, isStatic = true)
-    public static native Object unsafeCast(Object value, Class<?> clazz, boolean condition, boolean nonNull);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native int unsafeGetInt(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native long unsafeGetLong(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native float unsafeGetFloat(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native double unsafeGetDouble(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native Object unsafeGetObject(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutInt(Object receiver, long offset, int value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutLong(Object receiver, long offset, long value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutFloat(Object receiver, long offset, float value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutDouble(Object receiver, long offset, double value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutObject(Object receiver, long offset, Object value, Object locationIdentity);
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * 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.truffle.substitutions;
-
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.truffle.*;
-import com.oracle.graal.truffle.nodes.frame.*;
-import com.oracle.truffle.api.frame.*;
-
-@ClassSubstitution(OptimizedCallTarget.class)
-public class OptimizedCallTargetSubstitutions {
-
-    @MethodSubstitution
-    private static VirtualFrame createFrame(FrameDescriptor descriptor, Object[] args) {
-        return NewFrameNode.allocate(FrameWithoutBoxing.class, descriptor, args);
-    }
-
-    @MethodSubstitution
-    private static Object castArrayFixedLength(Object[] args, int length) {
-        return PiArrayNode.piArrayCast(args, length, StampFactory.forNodeIntrinsic());
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Thu Mar 12 15:59:01 2015 +0100
@@ -70,16 +70,16 @@
     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) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) {
                 if (arg.isConstant()) {
                     Constant constant = arg.asConstant();
-                    OptimizedAssumption assumption = builder.getSnippetReflection().asObject(OptimizedAssumption.class, (JavaConstant) constant);
-                    builder.push(Kind.Boolean.getStackKind(), builder.append(ConstantNode.forBoolean(assumption.isValid())));
+                    OptimizedAssumption assumption = b.getSnippetReflection().asObject(OptimizedAssumption.class, (JavaConstant) constant);
+                    b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(assumption.isValid())));
                     if (assumption.isValid()) {
-                        builder.getAssumptions().record(new AssumptionValidAssumption(assumption));
+                        b.getAssumptions().record(new AssumptionValidAssumption(assumption));
                     }
                 } else {
-                    throw builder.bailout("assumption could not be reduced to a constant");
+                    throw b.bailout("assumption could not be reduced to a constant");
                 }
                 return true;
             }
@@ -89,33 +89,34 @@
     public static void registerExactMathPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
         Registration r = new Registration(plugins, metaAccess, ExactMath.class);
         for (Kind kind : new Kind[]{Kind.Int, Kind.Long}) {
-            r.register2("addExact", kind.toJavaClass(), kind.toJavaClass(), new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
-                    builder.push(kind.getStackKind(), builder.append(new IntegerAddExactNode(x, y)));
+            Class<?> type = kind.toJavaClass();
+            r.register2("addExact", type, type, new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
+                    b.push(kind.getStackKind(), b.append(new IntegerAddExactNode(x, y)));
                     return true;
                 }
             });
-            r.register2("subtractExact", kind.toJavaClass(), kind.toJavaClass(), new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
-                    builder.push(kind.getStackKind(), builder.append(new IntegerSubExactNode(x, y)));
+            r.register2("subtractExact", type, type, new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
+                    b.push(kind.getStackKind(), b.append(new IntegerSubExactNode(x, y)));
                     return true;
                 }
             });
-            r.register2("multiplyExact", kind.toJavaClass(), kind.toJavaClass(), new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
-                    builder.push(kind.getStackKind(), builder.append(new IntegerMulExactNode(x, y)));
+            r.register2("multiplyExact", type, type, new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
+                    b.push(kind.getStackKind(), b.append(new IntegerMulExactNode(x, y)));
                     return true;
                 }
             });
-            r.register2("multiplyHigh", kind.toJavaClass(), kind.toJavaClass(), new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
-                    builder.push(kind.getStackKind(), builder.append(new IntegerMulHighNode(x, y)));
+            r.register2("multiplyHigh", type, type, new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
+                    b.push(kind.getStackKind(), b.append(new IntegerMulHighNode(x, y)));
                     return true;
                 }
             });
-            r.register2("multiplyHighUnsigned", kind.toJavaClass(), kind.toJavaClass(), new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
-                    builder.push(kind.getStackKind(), builder.append(new UnsignedMulHighNode(x, y)));
+            r.register2("multiplyHighUnsigned", type, type, new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
+                    b.push(kind.getStackKind(), b.append(new UnsignedMulHighNode(x, y)));
                     return true;
                 }
             });
@@ -125,73 +126,73 @@
     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)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+                b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(false)));
                 return true;
             }
         });
         r.register0("inCompiledCode", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder) {
-                builder.push(Kind.Boolean.getStackKind(), builder.append(ConstantNode.forBoolean(true)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+                b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(true)));
                 return true;
             }
         });
         r.register0("transferToInterpreter", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder) {
-                builder.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+                b.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
         });
         r.register0("transferToInterpreterAndInvalidate", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder) {
-                builder.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+                b.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
         });
         r.register1("interpreterOnly", Runnable.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode arg) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) {
                 return true;
             }
         });
         r.register1("interpreterOnly", Callable.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode arg) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) {
                 return true;
             }
         });
         r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode probability, ValueNode condition) {
-                builder.push(Kind.Boolean.getStackKind(), builder.append(new BranchProbabilityNode(probability, condition)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode probability, ValueNode condition) {
+                b.push(Kind.Boolean.getStackKind(), b.append(new BranchProbabilityNode(probability, condition)));
                 return true;
             }
         });
         r.register1("bailout", String.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode message) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode message) {
                 if (message.isConstant()) {
-                    throw builder.bailout(message.asConstant().toValueString());
+                    throw b.bailout(message.asConstant().toValueString());
                 }
-                throw builder.bailout("bailout (message is not compile-time constant, so no additional information is available)");
+                throw b.bailout("bailout (message is not compile-time constant, so no additional information is available)");
             }
         });
         r.register1("isCompilationConstant", Object.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
                 if ((value instanceof BoxNode ? ((BoxNode) value).getValue() : value).isConstant()) {
-                    builder.push(Kind.Boolean.getStackKind(), builder.append(ConstantNode.forBoolean(true)));
+                    b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(true)));
                 } else {
-                    builder.push(Kind.Boolean.getStackKind(), builder.append(new IsCompilationConstantNode(value)));
+                    b.push(Kind.Boolean.getStackKind(), b.append(new IsCompilationConstantNode(value)));
                 }
                 return true;
             }
         });
         r.register1("materialize", Object.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode value) {
-                builder.append(new ForceMaterializeNode(value));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                b.append(new ForceMaterializeNode(value));
                 return true;
             }
         });
 
         r = new Registration(plugins, metaAccess, CompilerAsserts.class);
         r.register1("partialEvaluationConstant", Object.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
                 ValueNode curValue = value;
                 if (curValue instanceof BoxNode) {
                     BoxNode boxNode = (BoxNode) curValue;
@@ -211,18 +212,18 @@
                         }
                         sb.append(")");
                     }
-                    throw builder.bailout("Partial evaluation did not reduce value to a constant, is a regular compiler node: " + sb.toString());
+                    throw b.bailout("Partial evaluation did not reduce value to a constant, is a regular compiler node: " + sb.toString());
                 }
             }
         });
         r.register1("neverPartOfCompilation", String.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode message) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode message) {
                 if (message.isConstant()) {
                     String messageString = message.asConstant().toValueString();
-                    builder.append(new NeverPartOfCompilationNode(messageString));
+                    b.append(new NeverPartOfCompilationNode(messageString));
                     return true;
                 }
-                throw builder.bailout("message for never part of compilation is non-constant");
+                throw b.bailout("message for never part of compilation is non-constant");
             }
         });
     }
@@ -230,9 +231,15 @@
     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) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode descriptor, ValueNode args) {
                 Class<?> frameClass = TruffleCompilerOptions.TruffleUseFrameWithoutBoxing.getValue() ? FrameWithoutBoxing.class : FrameWithBoxing.class;
-                builder.push(Kind.Object, builder.append(new NewFrameNode(StampFactory.exactNonNull(metaAccess.lookupJavaType(frameClass)), arg1, arg2)));
+                b.push(Kind.Object, b.append(new NewFrameNode(StampFactory.exactNonNull(metaAccess.lookupJavaType(frameClass)), descriptor, args)));
+                return true;
+            }
+        });
+        r.register2("castArrayFixedLength", Object[].class, int.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode args, ValueNode length) {
+                b.push(Kind.Object, b.append(new PiArrayNode(args, length, args.stamp())));
                 return true;
             }
         });
@@ -259,8 +266,8 @@
 
     private static void registerMaterialize(Registration r) {
         r.register1("materialize", Receiver.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode frame) {
-                builder.push(Kind.Object, builder.append(new MaterializeFrameNode(frame)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode frame) {
+                b.push(Kind.Object, b.append(new MaterializeFrameNode(frame)));
                 return true;
             }
         });
@@ -268,12 +275,12 @@
 
     private static void registerUnsafeCast(Registration r) {
         r.register4("unsafeCast", Object.class, Class.class, boolean.class, boolean.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode object, ValueNode clazz, ValueNode condition, ValueNode nonNull) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object, ValueNode clazz, ValueNode condition, ValueNode nonNull) {
                 if (clazz.isConstant() && nonNull.isConstant()) {
-                    ConstantReflectionProvider constantReflection = builder.getConstantReflection();
+                    ConstantReflectionProvider constantReflection = b.getConstantReflection();
                     ResolvedJavaType javaType = constantReflection.asJavaType(clazz.asConstant());
                     if (javaType == null) {
-                        builder.push(Kind.Object, object);
+                        b.push(Kind.Object, object);
                     } else {
                         Stamp piStamp = null;
                         if (javaType.isArray()) {
@@ -295,10 +302,10 @@
                         }
                         ConditionAnchorNode valueAnchorNode = null;
                         if (!skipAnchor) {
-                            valueAnchorNode = builder.append(new ConditionAnchorNode(compareNode));
+                            valueAnchorNode = b.append(new ConditionAnchorNode(compareNode));
                         }
-                        PiNode piCast = builder.append(new PiNode(object, piStamp, valueAnchorNode));
-                        builder.push(Kind.Object, piCast);
+                        PiNode piCast = b.append(new PiNode(object, piStamp, valueAnchorNode));
+                        b.push(Kind.Object, piCast);
                     }
                     return true;
                 }
@@ -326,7 +333,7 @@
             this.returnKind = returnKind;
         }
 
-        public boolean apply(GraphBuilderContext builder, ValueNode object, ValueNode offset, ValueNode condition, ValueNode location) {
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object, ValueNode offset, ValueNode condition, ValueNode location) {
             if (location.isConstant()) {
                 LocationIdentity locationIdentity;
                 if (location.isNullConstant()) {
@@ -334,8 +341,8 @@
                 } else {
                     locationIdentity = ObjectLocationIdentity.create(location.asJavaConstant());
                 }
-                LogicNode compare = builder.append(CompareNode.createCompareNode(Condition.EQ, condition, ConstantNode.forBoolean(true, object.graph()), builder.getConstantReflection()));
-                builder.push(returnKind.getStackKind(), builder.append(new UnsafeLoadNode(object, offset, returnKind, locationIdentity, compare)));
+                LogicNode compare = b.append(CompareNode.createCompareNode(Condition.EQ, condition, ConstantNode.forBoolean(true, object.graph()), b.getConstantReflection()));
+                b.push(returnKind.getStackKind(), b.append(new UnsafeLoadNode(object, offset, returnKind, locationIdentity, compare)));
                 return true;
             }
             // TODO: should we throw GraalInternalError.shouldNotReachHere() here?
@@ -351,7 +358,7 @@
             this.kind = kind;
         }
 
-        public boolean apply(GraphBuilderContext builder, ValueNode object, ValueNode offset, ValueNode value, ValueNode location) {
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object, ValueNode offset, ValueNode value, ValueNode location) {
             ValueNode locationArgument = location;
             if (locationArgument.isConstant()) {
                 LocationIdentity locationIdentity;
@@ -361,7 +368,7 @@
                     locationIdentity = ObjectLocationIdentity.create(locationArgument.asJavaConstant());
                 }
 
-                builder.append(new UnsafeStoreNode(object, offset, value, kind, locationIdentity, null));
+                b.append(new UnsafeStoreNode(object, offset, value, kind, locationIdentity, null));
                 return true;
             }
             // TODO: should we throw GraalInternalError.shouldNotReachHere() here?
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/UnsafeAccessSubstitutions.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2013, 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.truffle.substitutions;
-
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.truffle.nodes.typesystem.*;
-import com.oracle.graal.truffle.unsafe.*;
-
-@ClassSubstitution(UnsafeAccessImpl.class)
-public class UnsafeAccessSubstitutions {
-    @MacroSubstitution(macro = UnsafeTypeCastMacroNode.class, isStatic = true)
-    public static native Object unsafeCast(Object value, Class<?> clazz, boolean condition, boolean nonNull);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native boolean unsafeGetBoolean(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native byte unsafeGetByte(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native short unsafeGetShort(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native int unsafeGetInt(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native long unsafeGetLong(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native float unsafeGetFloat(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native double unsafeGetDouble(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native Object unsafeGetObject(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutBoolean(Object receiver, long offset, boolean value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutByte(Object receiver, long offset, byte value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutShort(Object receiver, long offset, short value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutInt(Object receiver, long offset, int value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutLong(Object receiver, long offset, long value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutFloat(Object receiver, long offset, float value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutDouble(Object receiver, long offset, double value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutObject(Object receiver, long offset, Object value, Object locationIdentity);
-}
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/BarrieredAccess.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/BarrieredAccess.java	Thu Mar 12 15:59:01 2015 +0100
@@ -33,7 +33,7 @@
  * checks. However, these methods use read- or write barriers. When the VM uses compressed pointers,
  * then readObject and writeObject methods access compressed pointers.
  */
-public class BarrieredAccess {
+public final class BarrieredAccess {
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Thu Mar 12 15:59:01 2015 +0100
@@ -72,6 +72,7 @@
          FROM_UNSIGNED,
          FROM_SIGNED,
          FROM_OBJECT,
+         FROM_WORDBASE,
          FROM_ARRAY,
          TO_OBJECT,
          TO_RAW_VALUE,
@@ -170,6 +171,9 @@
         return unbox();
     }
 
+    @Operation(opcode = Opcode.FROM_WORDBASE)
+    public static native Word fromWordBase(WordBase val);
+
     @Operation(opcode = Opcode.FROM_OBJECT)
     public static native Pointer fromObject(Object val);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/WordTypes.java	Thu Mar 12 15:59:01 2015 +0100
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2012, 2014, 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.word;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.word.Word.Operation;
+
+/**
+ * Encapsulates information for Java types representing raw words (as opposed to Objects).
+ */
+public class WordTypes {
+
+    /**
+     * Resolved type for {@link WordBase}.
+     */
+    private final ResolvedJavaType wordBaseType;
+
+    /**
+     * Resolved type for {@link Word}.
+     */
+    private final ResolvedJavaType wordImplType;
+
+    /**
+     * Resolved type for {@link ObjectAccess}.
+     */
+    private final ResolvedJavaType objectAccessType;
+
+    /**
+     * Resolved type for {@link BarrieredAccess}.
+     */
+    private final ResolvedJavaType barrieredAccessType;
+
+    private final Kind wordKind;
+
+    public WordTypes(MetaAccessProvider metaAccess, Kind wordKind) {
+        this.wordKind = wordKind;
+        this.wordBaseType = metaAccess.lookupJavaType(WordBase.class);
+        this.wordImplType = metaAccess.lookupJavaType(Word.class);
+        this.objectAccessType = metaAccess.lookupJavaType(ObjectAccess.class);
+        this.barrieredAccessType = metaAccess.lookupJavaType(BarrieredAccess.class);
+    }
+
+    /**
+     * Determines if a given method denotes a word operation.
+     */
+    public boolean isWordOperation(ResolvedJavaMethod targetMethod) {
+        final boolean isObjectAccess = objectAccessType.equals(targetMethod.getDeclaringClass());
+        final boolean isBarrieredAccess = barrieredAccessType.equals(targetMethod.getDeclaringClass());
+        if (isObjectAccess || isBarrieredAccess) {
+            assert targetMethod.getAnnotation(Operation.class) != null : targetMethod + " should be annotated with @" + Operation.class.getSimpleName();
+            return true;
+        }
+        return isWord(targetMethod.getDeclaringClass());
+    }
+
+    /**
+     * Gets the method annotated with {@link Operation} based on a given method that represents a
+     * word operation (but may not necessarily have the annotation).
+     *
+     * @param callingContextType the {@linkplain ResolvedJavaType type} from which
+     *            {@code targetMethod} is invoked
+     * @return the {@link Operation} method resolved for {@code targetMethod} if any
+     */
+    public ResolvedJavaMethod getWordOperation(ResolvedJavaMethod targetMethod, ResolvedJavaType callingContextType) {
+        final boolean isWordBase = wordBaseType.isAssignableFrom(targetMethod.getDeclaringClass());
+        ResolvedJavaMethod wordMethod = targetMethod;
+        if (isWordBase && !targetMethod.isStatic()) {
+            assert wordImplType.isLinked();
+            wordMethod = wordImplType.resolveConcreteMethod(targetMethod, callingContextType);
+        }
+        assert wordMethod.getAnnotation(Operation.class) != null : wordMethod;
+        return wordMethod;
+    }
+
+    /**
+     * Determines if a given node has a word type.
+     */
+    public boolean isWord(ValueNode node) {
+        return isWord(StampTool.typeOrNull(node));
+    }
+
+    /**
+     * Determines if a given type is a word type.
+     */
+    public boolean isWord(ResolvedJavaType type) {
+        return type != null && wordBaseType.isAssignableFrom(type);
+    }
+
+    /**
+     * Gets the kind for a given type, returning the {@linkplain #getWordKind() word kind} if
+     * {@code type} is a {@linkplain #isWord(ResolvedJavaType) word type}.
+     */
+    public Kind asKind(JavaType type) {
+        if (type instanceof ResolvedJavaType && isWord((ResolvedJavaType) type)) {
+            return wordKind;
+        } else {
+            return type.getKind();
+        }
+    }
+
+    public Kind getWordKind() {
+        return wordKind;
+    }
+
+    /**
+     * Gets the stamp for a given {@linkplain #isWord(ResolvedJavaType) word type}.
+     */
+    public Stamp getWordStamp(ResolvedJavaType type) {
+        assert isWord(type);
+        return StampFactory.forKind(wordKind);
+    }
+
+    public ResolvedJavaType getWordImplType() {
+        return wordImplType;
+    }
+}
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Thu Mar 12 15:59:01 2015 +0100
@@ -29,11 +29,12 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.word.phases.*;
+import com.oracle.graal.word.Word.Opcode;
 
 /**
- * Cast between Word and Object that is introduced by the {@link WordTypeRewriterPhase}. It has an
- * impact on the pointer maps for the GC, so it must not be scheduled or optimized away.
+ * Casts between Word and Object exposed by the {@link Opcode#FROM_OBJECT} and
+ * {@link Opcode#TO_OBJECT} operations. It has an impact on the pointer maps for the GC, so it must
+ * not be scheduled or optimized away.
  */
 @NodeInfo
 public final class WordCastNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable {
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,458 +0,0 @@
-/*
- * Copyright (c) 2012, 2014, 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.word.phases;
-
-import static com.oracle.graal.api.meta.LocationIdentity.*;
-
-import java.lang.reflect.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-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.type.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.graph.*;
-import com.oracle.graal.word.*;
-import com.oracle.graal.word.Word.Opcode;
-import com.oracle.graal.word.Word.Operation;
-import com.oracle.graal.word.nodes.*;
-
-/**
- * Transforms all uses of the {@link Word} class into unsigned operations on {@code int} or
- * {@code long} values, depending on the word kind of the underlying platform.
- */
-public class WordTypeRewriterPhase extends Phase {
-
-    protected final MetaAccessProvider metaAccess;
-    protected final SnippetReflectionProvider snippetReflection;
-    protected final ConstantReflectionProvider constantReflection;
-    protected final ResolvedJavaType wordBaseType;
-    protected final ResolvedJavaType wordImplType;
-    protected final ResolvedJavaType objectAccessType;
-    protected final ResolvedJavaType barrieredAccessType;
-    protected final Kind wordKind;
-
-    public WordTypeRewriterPhase(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ConstantReflectionProvider constantReflection, Kind wordKind) {
-        this.metaAccess = metaAccess;
-        this.snippetReflection = snippetReflection;
-        this.constantReflection = constantReflection;
-        this.wordKind = wordKind;
-        this.wordBaseType = metaAccess.lookupJavaType(WordBase.class);
-        this.wordImplType = metaAccess.lookupJavaType(Word.class);
-        this.objectAccessType = metaAccess.lookupJavaType(ObjectAccess.class);
-        this.barrieredAccessType = metaAccess.lookupJavaType(BarrieredAccess.class);
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        InferStamps.inferStamps(graph);
-
-        for (Node n : graph.getNodes()) {
-            if (n instanceof ValueNode) {
-                changeToWord(graph, (ValueNode) n);
-            }
-        }
-
-        for (Node node : graph.getNodes()) {
-            rewriteNode(graph, node);
-        }
-    }
-
-    /**
-     * Change the stamp for word nodes from the object stamp ({@link WordBase} or anything extending
-     * or implementing that interface) to the primitive word stamp.
-     */
-    protected void changeToWord(StructuredGraph graph, ValueNode node) {
-        if (isWord(node)) {
-            if (node.isConstant()) {
-                ConstantNode oldConstant = (ConstantNode) node;
-                assert oldConstant.asJavaConstant().getKind() == Kind.Object;
-                WordBase value = snippetReflection.asObject(WordBase.class, oldConstant.asJavaConstant());
-                ConstantNode newConstant = ConstantNode.forIntegerKind(wordKind, value.rawValue(), node.graph());
-                graph.replaceFloating(oldConstant, newConstant);
-
-            } else {
-                node.setStamp(StampFactory.forKind(wordKind));
-            }
-        }
-    }
-
-    /**
-     * Clean up nodes that are no longer necessary or valid after the stamp change, and perform
-     * intrinsification of all methods called on word types.
-     */
-    protected void rewriteNode(StructuredGraph graph, Node node) {
-        if (node instanceof CheckCastNode) {
-            rewriteCheckCast(graph, (CheckCastNode) node);
-        } else if (node instanceof PiNode) {
-            rewritePi(graph, (PiNode) node);
-        } else if (node instanceof LoadFieldNode) {
-            rewriteLoadField(graph, (LoadFieldNode) node);
-        } else if (node instanceof AccessIndexedNode) {
-            rewriteAccessIndexed(graph, (AccessIndexedNode) node);
-        } else if (node instanceof MethodCallTargetNode) {
-            rewriteInvoke(graph, (MethodCallTargetNode) node);
-        }
-    }
-
-    /**
-     * Remove casts between word types (which by now no longer have kind Object).
-     */
-    protected void rewriteCheckCast(StructuredGraph graph, CheckCastNode node) {
-        if (node.getKind() == wordKind) {
-            node.replaceAtUsages(node.object());
-            graph.removeFixed(node);
-        }
-    }
-
-    /**
-     * Remove casts between word types (which by now no longer have kind Object).
-     */
-    protected void rewritePi(StructuredGraph graph, PiNode node) {
-        if (node.getKind() == wordKind) {
-            node.replaceAtUsages(node.object());
-            graph.removeFloating(node);
-        }
-    }
-
-    /**
-     * Fold constant field reads, e.g. enum constants.
-     */
-    protected void rewriteLoadField(StructuredGraph graph, LoadFieldNode node) {
-        ConstantNode constant = node.asConstant(metaAccess, constantReflection, node.object());
-        if (constant != null) {
-            node.replaceAtUsages(graph.unique(constant));
-            graph.removeFixed(node);
-        }
-    }
-
-    /**
-     * Change loads and stores of word-arrays. Since the element kind is managed by the node on its
-     * own and not in the stamp, {@link #changeToWord} does not perform all necessary changes.
-     */
-    protected void rewriteAccessIndexed(StructuredGraph graph, AccessIndexedNode node) {
-        ResolvedJavaType arrayType = StampTool.typeOrNull(node.array());
-        /*
-         * There are cases where the array does not have a known type yet, i.e., the type is null.
-         * In that case we assume it is not a word type.
-         */
-        if (arrayType != null && isWord(arrayType.getComponentType()) && node.elementKind() != wordKind) {
-            /*
-             * The elementKind of the node is a final field, and other information such as the stamp
-             * depends on elementKind. Therefore, just create a new node and replace the old one.
-             */
-            if (node instanceof LoadIndexedNode) {
-                graph.replaceFixedWithFixed(node, graph.add(new LoadIndexedNode(node.array(), node.index(), wordKind)));
-            } else if (node instanceof StoreIndexedNode) {
-                graph.replaceFixedWithFixed(node, graph.add(new StoreIndexedNode(node.array(), node.index(), wordKind, ((StoreIndexedNode) node).value())));
-            } else {
-                throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-    }
-
-    /**
-     * Intrinsification of methods defined on the {@link Word} class that are annotated with
-     * {@link Operation}.
-     */
-    protected void rewriteInvoke(StructuredGraph graph, MethodCallTargetNode callTargetNode) {
-        ResolvedJavaMethod targetMethod = callTargetNode.targetMethod();
-        final boolean isWordBase = wordBaseType.isAssignableFrom(targetMethod.getDeclaringClass());
-        final boolean isObjectAccess = objectAccessType.equals(targetMethod.getDeclaringClass());
-        final boolean isBarrieredAccess = barrieredAccessType.equals(targetMethod.getDeclaringClass());
-        if (!isWordBase && !isObjectAccess && !isBarrieredAccess) {
-            /*
-             * Not a method defined on WordBase or a subclass / subinterface, and not on
-             * ObjectAccess and not on BarrieredAccess, so nothing to rewrite.
-             */
-            return;
-        }
-
-        if (!callTargetNode.isStatic()) {
-            assert callTargetNode.receiver().getKind() == wordKind : "changeToWord() missed the receiver " + callTargetNode.receiver();
-            assert wordImplType.isLinked();
-            targetMethod = wordImplType.resolveConcreteMethod(targetMethod, callTargetNode.invoke().getContextType());
-        }
-        rewriteWordOperation(graph, callTargetNode, targetMethod);
-    }
-
-    protected void rewriteWordOperation(StructuredGraph graph, MethodCallTargetNode callTargetNode, ResolvedJavaMethod targetMethod) throws GraalInternalError {
-        Invoke invoke = callTargetNode.invoke();
-        Operation operation = targetMethod.getAnnotation(Word.Operation.class);
-        assert operation != null : targetMethod;
-
-        NodeInputList<ValueNode> arguments = callTargetNode.arguments();
-
-        switch (operation.opcode()) {
-            case NODE_CLASS:
-                assert arguments.size() == 2;
-                ValueNode left = arguments.get(0);
-                ValueNode right = operation.rightOperandIsInt() ? toUnsigned(graph, arguments.get(1), Kind.Int) : fromSigned(graph, arguments.get(1));
-
-                ValueNode replacement = graph.addOrUnique(createBinaryNodeInstance(operation.node(), left, right));
-                if (replacement instanceof FixedWithNextNode) {
-                    graph.addBeforeFixed(invoke.asNode(), (FixedWithNextNode) replacement);
-                }
-                replace(invoke, replacement);
-                break;
-
-            case COMPARISON:
-                assert arguments.size() == 2;
-                replace(invoke, comparisonOp(graph, operation.condition(), arguments.get(0), fromSigned(graph, arguments.get(1))));
-                break;
-
-            case NOT:
-                assert arguments.size() == 1;
-                replace(invoke, graph.unique(new XorNode(arguments.get(0), ConstantNode.forIntegerKind(wordKind, -1, graph))));
-                break;
-
-            case READ_POINTER:
-            case READ_OBJECT:
-            case READ_BARRIERED: {
-                assert arguments.size() == 2 || arguments.size() == 3;
-                Kind readKind = asKind(callTargetNode.returnType());
-                LocationNode location;
-                if (arguments.size() == 2) {
-                    location = makeLocation(graph, arguments.get(1), ANY_LOCATION);
-                } else {
-                    location = makeLocation(graph, arguments.get(1), arguments.get(2));
-                }
-                replace(invoke, readOp(graph, readKind, arguments.get(0), invoke, location, operation.opcode()));
-                break;
-            }
-            case READ_HEAP: {
-                assert arguments.size() == 3;
-                Kind readKind = asKind(callTargetNode.returnType());
-                LocationNode location = makeLocation(graph, arguments.get(1), ANY_LOCATION);
-                BarrierType barrierType = snippetReflection.asObject(BarrierType.class, arguments.get(2).asJavaConstant());
-                replace(invoke, readOp(graph, readKind, arguments.get(0), invoke, location, barrierType, true));
-                break;
-            }
-            case WRITE_POINTER:
-            case WRITE_OBJECT:
-            case WRITE_BARRIERED:
-            case INITIALIZE: {
-                assert arguments.size() == 3 || arguments.size() == 4;
-                Kind writeKind = asKind(targetMethod.getSignature().getParameterType(targetMethod.isStatic() ? 2 : 1, targetMethod.getDeclaringClass()));
-                LocationNode location;
-                if (arguments.size() == 3) {
-                    location = makeLocation(graph, arguments.get(1), LocationIdentity.ANY_LOCATION);
-                } else {
-                    location = makeLocation(graph, arguments.get(1), arguments.get(3));
-                }
-                replace(invoke, writeOp(graph, writeKind, arguments.get(0), arguments.get(2), invoke, location, operation.opcode()));
-                break;
-            }
-            case ZERO:
-                assert arguments.size() == 0;
-                replace(invoke, ConstantNode.forIntegerKind(wordKind, 0L, graph));
-                break;
-
-            case FROM_UNSIGNED:
-                assert arguments.size() == 1;
-                replace(invoke, fromUnsigned(graph, arguments.get(0)));
-                break;
-
-            case FROM_SIGNED:
-                assert arguments.size() == 1;
-                replace(invoke, fromSigned(graph, arguments.get(0)));
-                break;
-
-            case TO_RAW_VALUE:
-                assert arguments.size() == 1;
-                replace(invoke, toUnsigned(graph, arguments.get(0), Kind.Long));
-                break;
-
-            case FROM_OBJECT:
-                assert arguments.size() == 1;
-                WordCastNode objectToWord = graph.add(WordCastNode.objectToWord(arguments.get(0), wordKind));
-                graph.addBeforeFixed(invoke.asNode(), objectToWord);
-                replace(invoke, objectToWord);
-                break;
-
-            case FROM_ARRAY:
-                assert arguments.size() == 2;
-                replace(invoke, graph.unique(new ComputeAddressNode(arguments.get(0), arguments.get(1), StampFactory.forKind(wordKind))));
-                break;
-
-            case TO_OBJECT:
-                assert arguments.size() == 1;
-                WordCastNode wordToObject = graph.add(WordCastNode.wordToObject(arguments.get(0), wordKind));
-                graph.addBeforeFixed(invoke.asNode(), wordToObject);
-                replace(invoke, wordToObject);
-                break;
-
-            default:
-                throw new GraalInternalError("Unknown opcode: %s", operation.opcode());
-        }
-    }
-
-    protected ValueNode fromUnsigned(StructuredGraph graph, ValueNode value) {
-        return convert(graph, value, wordKind, true);
-    }
-
-    private ValueNode fromSigned(StructuredGraph graph, ValueNode value) {
-        return convert(graph, value, wordKind, false);
-    }
-
-    protected ValueNode toUnsigned(StructuredGraph graph, ValueNode value, Kind toKind) {
-        return convert(graph, value, toKind, true);
-    }
-
-    private static ValueNode convert(StructuredGraph graph, ValueNode value, Kind toKind, boolean unsigned) {
-        if (value.getKind() == toKind) {
-            return value;
-        }
-
-        if (toKind == Kind.Int) {
-            assert value.getKind() == Kind.Long;
-            return graph.unique(new NarrowNode(value, 32));
-        } else {
-            assert toKind == Kind.Long;
-            assert value.getKind().getStackKind() == Kind.Int;
-            if (unsigned) {
-                return graph.unique(new ZeroExtendNode(value, 64));
-            } else {
-                return graph.unique(new SignExtendNode(value, 64));
-            }
-        }
-    }
-
-    /**
-     * Create an instance of a binary node which is used to lower Word operations. This method is
-     * called for all Word operations which are annotated with @Operation(node = ...) and
-     * encapsulates the reflective allocation of the node.
-     */
-    private static ValueNode createBinaryNodeInstance(Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right) {
-        try {
-            Constructor<?> cons = nodeClass.getDeclaredConstructor(ValueNode.class, ValueNode.class);
-            return (ValueNode) cons.newInstance(left, right);
-        } catch (Throwable ex) {
-            throw new GraalInternalError(ex).addContext(nodeClass.getName());
-        }
-    }
-
-    private ValueNode comparisonOp(StructuredGraph graph, Condition condition, ValueNode left, ValueNode right) {
-        assert left.getKind() == wordKind && right.getKind() == wordKind;
-
-        // mirroring gets the condition into canonical form
-        boolean mirror = condition.canonicalMirror();
-
-        ValueNode a = mirror ? right : left;
-        ValueNode b = mirror ? left : right;
-
-        CompareNode comparison;
-        if (condition == Condition.EQ || condition == Condition.NE) {
-            comparison = new IntegerEqualsNode(a, b);
-        } else if (condition.isUnsigned()) {
-            comparison = new IntegerBelowNode(a, b);
-        } else {
-            comparison = new IntegerLessThanNode(a, b);
-        }
-
-        ConstantNode trueValue = ConstantNode.forInt(1, graph);
-        ConstantNode falseValue = ConstantNode.forInt(0, graph);
-
-        if (condition.canonicalNegate()) {
-            ConstantNode temp = trueValue;
-            trueValue = falseValue;
-            falseValue = temp;
-        }
-        ConditionalNode materialize = graph.unique(new ConditionalNode(graph.unique(comparison), trueValue, falseValue));
-        return materialize;
-    }
-
-    protected LocationNode makeLocation(StructuredGraph graph, ValueNode offset, ValueNode locationIdentity) {
-        if (locationIdentity.isConstant()) {
-            return makeLocation(graph, offset, snippetReflection.asObject(LocationIdentity.class, locationIdentity.asJavaConstant()));
-        }
-        return graph.unique(new SnippetLocationNode(snippetReflection, locationIdentity, ConstantNode.forLong(0, graph), fromSigned(graph, offset), ConstantNode.forInt(1, graph)));
-    }
-
-    protected LocationNode makeLocation(StructuredGraph graph, ValueNode offset, LocationIdentity locationIdentity) {
-        return graph.unique(new IndexedLocationNode(locationIdentity, 0, fromSigned(graph, offset), 1));
-    }
-
-    protected ValueNode readOp(StructuredGraph graph, Kind readKind, ValueNode base, Invoke invoke, LocationNode location, Opcode op) {
-        assert op == Opcode.READ_POINTER || op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED;
-        final BarrierType barrier = (op == Opcode.READ_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE);
-        final boolean compressible = (op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED);
-
-        return readOp(graph, readKind, base, invoke, location, barrier, compressible);
-    }
-
-    protected ValueNode readOp(StructuredGraph graph, Kind readKind, ValueNode base, Invoke invoke, LocationNode location, BarrierType barrierType, boolean compressible) {
-        JavaReadNode read = graph.add(new JavaReadNode(readKind, base, location, barrierType, compressible));
-        graph.addBeforeFixed(invoke.asNode(), read);
-        /*
-         * The read must not float outside its block otherwise it may float above an explicit zero
-         * check on its base address.
-         */
-        read.setGuard(AbstractBeginNode.prevBegin(invoke.asNode()));
-        return read;
-    }
-
-    protected ValueNode writeOp(StructuredGraph graph, Kind writeKind, ValueNode base, ValueNode value, Invoke invoke, LocationNode location, Opcode op) {
-        assert op == Opcode.WRITE_POINTER || op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED || op == Opcode.INITIALIZE;
-        final BarrierType barrier = (op == Opcode.WRITE_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE);
-        final boolean compressible = (op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED);
-        final boolean initialize = (op == Opcode.INITIALIZE);
-        JavaWriteNode write = graph.add(new JavaWriteNode(writeKind, base, value, location, barrier, compressible, initialize));
-        write.setStateAfter(invoke.stateAfter());
-        graph.addBeforeFixed(invoke.asNode(), write);
-        return write;
-    }
-
-    protected void replace(Invoke invoke, ValueNode value) {
-        FixedNode next = invoke.next();
-        invoke.setNext(null);
-        invoke.asNode().replaceAtPredecessor(next);
-        invoke.asNode().replaceAtUsages(value);
-        GraphUtil.killCFG(invoke.asNode());
-    }
-
-    protected boolean isWord(ValueNode node) {
-        return isWord(StampTool.typeOrNull(node));
-    }
-
-    protected boolean isWord(ResolvedJavaType type) {
-        return type != null && wordBaseType.isAssignableFrom(type);
-    }
-
-    protected Kind asKind(JavaType type) {
-        if (type instanceof ResolvedJavaType && isWord((ResolvedJavaType) type)) {
-            return wordKind;
-        } else {
-            return type.getKind();
-        }
-    }
-}
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java	Thu Mar 12 15:58:28 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,166 +0,0 @@
-/*
- * Copyright (c) 2011, 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.word.phases;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.graph.*;
-import com.oracle.graal.word.*;
-import com.oracle.graal.word.Word.Operation;
-
-/**
- * Verifies invariants that must hold for code that uses the {@link WordBase word type} above and
- * beyond normal bytecode verification.
- */
-public class WordTypeVerificationPhase extends Phase {
-
-    private final WordTypeRewriterPhase wordAccess;
-
-    public WordTypeVerificationPhase(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ConstantReflectionProvider constantReflection, Kind wordKind) {
-        this.wordAccess = new WordTypeRewriterPhase(metaAccess, snippetReflection, constantReflection, wordKind);
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        assert verify(graph);
-    }
-
-    protected boolean verify(StructuredGraph inputGraph) {
-        /*
-         * This is a verification phase, so we do not want to have side effects. Since inferStamps()
-         * modifies the stamp of nodes, we copy the graph before running the verification.
-         */
-        StructuredGraph graph = inputGraph.copy();
-        InferStamps.inferStamps(graph);
-
-        for (ValueNode node : graph.getNodes().filter(ValueNode.class)) {
-            for (Node usage : node.usages()) {
-                if (usage instanceof AccessMonitorNode) {
-                    verify(!isWord(node), node, usage, "word value has no monitor");
-                } else if (usage instanceof LoadFieldNode) {
-                    verify(!isWord(node) || ((LoadFieldNode) usage).object() != node, node, usage, "cannot load from word value");
-                } else if (usage instanceof StoreFieldNode) {
-                    verify(!isWord(node) || ((StoreFieldNode) usage).object() != node, node, usage, "cannot store to word value");
-                } else if (usage instanceof CheckCastNode) {
-                    verify(isWord(((CheckCastNode) usage).type()) == isWord(node), node, usage, "word cannot be cast to object, and vice versa");
-                } else if (usage instanceof LoadIndexedNode) {
-                    verify(!isWord(node) || ((LoadIndexedNode) usage).array() != node, node, usage, "cannot load from word value");
-                    verify(!isWord(node) || ((LoadIndexedNode) usage).index() != node, node, usage, "cannot use word value as index");
-                } else if (usage instanceof StoreIndexedNode) {
-                    verify(!isWord(node) || ((StoreIndexedNode) usage).array() != node, node, usage, "cannot store to word value");
-                    verify(!isWord(node) || ((StoreIndexedNode) usage).index() != node, node, usage, "cannot use word value as index");
-                } else if (usage instanceof MethodCallTargetNode) {
-                    MethodCallTargetNode callTarget = (MethodCallTargetNode) usage;
-                    verifyInvoke(node, callTarget);
-                } else if (usage instanceof ObjectEqualsNode) {
-                    verify(!isWord(node) || ((ObjectEqualsNode) usage).getX() != node, node, usage, "cannot use word type in comparison");
-                    verify(!isWord(node) || ((ObjectEqualsNode) usage).getY() != node, node, usage, "cannot use word type in comparison");
-                } else if (usage instanceof ArrayLengthNode) {
-                    verify(!isWord(node) || ((ArrayLengthNode) usage).array() != node, node, usage, "cannot get array length from word value");
-                } else if (usage instanceof ValuePhiNode) {
-                    if (!(node instanceof AbstractMergeNode)) {
-                        ValuePhiNode phi = (ValuePhiNode) usage;
-                        for (ValueNode input : phi.values()) {
-                            verify(isWord(node) == isWord(input), node, input, "cannot merge word and non-word values");
-                        }
-                    }
-                }
-            }
-        }
-        return true;
-    }
-
-    protected void verifyInvoke(ValueNode node, MethodCallTargetNode callTarget) {
-        ResolvedJavaMethod method = callTarget.targetMethod();
-        if (method.getAnnotation(NodeIntrinsic.class) == null) {
-            Invoke invoke = (Invoke) callTarget.usages().first();
-            NodeInputList<ValueNode> arguments = callTarget.arguments();
-            boolean isStatic = method.isStatic();
-            int argc = 0;
-            if (!isStatic) {
-                ValueNode receiver = arguments.get(argc);
-                if (receiver == node && isWord(node)) {
-                    ResolvedJavaMethod resolvedMethod = wordAccess.wordImplType.resolveConcreteMethod(method, invoke.getContextType());
-                    verify(resolvedMethod != null, node, invoke.asNode(), "cannot resolve method on Word class: " + method.format("%H.%n(%P) %r"));
-                    Operation operation = resolvedMethod.getAnnotation(Word.Operation.class);
-                    verify(operation != null, node, invoke.asNode(), "cannot dispatch on word value to non @Operation annotated method " + resolvedMethod);
-                }
-                argc++;
-            }
-            Signature signature = method.getSignature();
-            for (int i = 0; i < signature.getParameterCount(false); i++) {
-                ValueNode argument = arguments.get(argc);
-                if (argument == node) {
-                    ResolvedJavaType type = (ResolvedJavaType) signature.getParameterType(i, method.getDeclaringClass());
-                    verify(isWord(type) == isWord(argument), node, invoke.asNode(), "cannot pass word value to non-word parameter " + i + " or vice-versa");
-                }
-                argc++;
-            }
-        }
-    }
-
-    private boolean isWord(ValueNode node) {
-        return wordAccess.isWord(node);
-    }
-
-    private boolean isWord(ResolvedJavaType type) {
-        return wordAccess.isWord(type);
-    }
-
-    private static void verify(boolean condition, Node node, Node usage, String message) {
-        if (!condition) {
-            error(node, usage, message);
-        }
-    }
-
-    private static void error(Node node, Node usage, String message) {
-        throw new GraalInternalError(String.format("Snippet verification error: %s" + "%n   node: %s (%s)" + "%n  usage: %s (%s)", message, node, sourceLocation(node), usage, sourceLocation(usage)));
-    }
-
-    private static String sourceLocation(Node n) {
-        if (n instanceof PhiNode) {
-            StringBuilder buf = new StringBuilder();
-            for (Node usage : n.usages()) {
-                String loc = sourceLocation(usage);
-                if (!loc.equals("<unknown>")) {
-                    if (buf.length() != 0) {
-                        buf.append(", ");
-                    }
-                    buf.append(loc);
-                }
-            }
-            return buf.toString();
-        } else {
-            String loc = GraphUtil.approxSourceLocation(n);
-            return loc == null ? ((StructuredGraph) n.graph()).method().format("method %h.%n") : loc;
-        }
-    }
-}
--- a/graal/com.oracle.nfi.test/test/com/oracle/nfi/test/NativeFunctionInterfaceTest.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.nfi.test/test/com/oracle/nfi/test/NativeFunctionInterfaceTest.java	Thu Mar 12 15:59:01 2015 +0100
@@ -36,7 +36,6 @@
 import com.oracle.nfi.*;
 import com.oracle.nfi.api.*;
 
-@Ignore
 public class NativeFunctionInterfaceTest {
 
     public final NativeFunctionInterface nfi;
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Cached.java	Thu Mar 12 15:58:28 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Cached.java	Thu Mar 12 15:59:01 2015 +0100
@@ -86,7 +86,7 @@
  *
  * <pre>
  *  &#064;Specialization
- *  void doCached(int operand, @Local(&quot;operand&quot;) int cachedOperand) {
+ *  void doCached(int operand, @Cached(&quot;operand&quot;) int cachedOperand) {
  *      CompilerAsserts.compilationConstant(cachedOperand);
  *      ...
  *  }
@@ -111,7 +111,7 @@
  * specialization instantiation limit is <code>3</code>.
  *
  * <pre>
- * &#064;Specialization(guards = &quot;==(operand, cachedOperand)&quot;)
+ * &#064;Specialization(guards = &quot;operand == cachedOperand&quot;)
  * void doCached(int operand, @Cached(&quot;operand&quot;) int cachedOperand) {
  *    CompilerAsserts.compilationConstant(cachedOperand);
  *    ...
@@ -139,7 +139,7 @@
  * <code>doCached</code> instances remain but no new instances are created.
  *
  * <code>
- * &#064;Specialization(guards = &quot;==(operand, cachedOperand)&quot;)
+ * &#064;Specialization(guards = &quot;operand == cachedOperand&quot;)
  * void doCached(int operand, @Cached(&quot;operand&quot;) int cachedOperand) {
  *    CompilerAsserts.compilationConstant(cachedOperand);
  *    ...
@@ -209,7 +209,7 @@
  *
  * <pre>
  * &#064;Specialization
- * void s(int operand, @Local(&quot;create()&quot;) BranchProfile profile) {
+ * void s(int operand, @Cached(&quot;create()&quot;) BranchProfile profile) {
  * }
  * </pre>
  *
--- a/mx/mx_graal.py	Thu Mar 12 15:58:28 2015 +0100
+++ b/mx/mx_graal.py	Thu Mar 12 15:59:01 2015 +0100
@@ -2203,6 +2203,9 @@
 
     includedirs = set()
     for p in mx.projects():
+        projsetting = getattr(p, 'jacoco', '')
+        if projsetting == 'exclude':
+            continue
         for include in includes:
             if include in p.dir:
                 includedirs.add(p.dir)
--- a/mx/suite.py	Thu Mar 12 15:58:28 2015 +0100
+++ b/mx/suite.py	Thu Mar 12 15:59:01 2015 +0100
@@ -579,7 +579,7 @@
     "com.oracle.graal.word" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
-      "dependencies" : ["com.oracle.graal.phases"],
+      "dependencies" : ["com.oracle.graal.nodes"],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "API,Graal",
--- a/mxtool/mx.py	Thu Mar 12 15:58:28 2015 +0100
+++ b/mxtool/mx.py	Thu Mar 12 15:59:01 2015 +0100
@@ -2806,7 +2806,7 @@
                 if exists(dirname(dst)) and (not exists(dst) or os.path.getmtime(dst) < os.path.getmtime(src)):
                     shutil.copyfile(src, dst)
 
-def _chunk_files_for_command_line(files, limit=None, pathFunction=None):
+def _chunk_files_for_command_line(files, limit=None, pathFunction=lambda f: f):
     """
     Returns a generator for splitting up a list of files into chunks such that the
     size of the space separated file paths in a chunk is less than a given limit.
@@ -2824,9 +2824,11 @@
             # Using just SC_ARG_MAX without extra downwards adjustment
             # results in "[Errno 7] Argument list too long" on MacOS.
             syslimit = os.sysconf('SC_ARG_MAX') - 20000
+            if syslimit == -1:
+                syslimit = 262144 # we could use sys.maxint but we prefer a more robust smaller value
             limit = syslimit - commandLinePrefixAllowance
     for i in range(len(files)):
-        path = files[i] if pathFunction is None else pathFunction(files[i])
+        path = pathFunction(files[i])
         size = len(path) + 1
         if chunkSize + size < limit:
             chunkSize += size
--- a/src/share/vm/classfile/systemDictionary.hpp	Thu Mar 12 15:58:28 2015 +0100
+++ b/src/share/vm/classfile/systemDictionary.hpp	Thu Mar 12 15:59:01 2015 +0100
@@ -204,10 +204,11 @@
   GRAAL_ONLY(do_klass(HotSpotMetaspaceConstantImpl_klass,    com_oracle_graal_hotspot_meta_HotSpotMetaspaceConstantImpl,   Graal)) \
   GRAAL_ONLY(do_klass(HotSpotStackFrameReference_klass,      com_oracle_graal_hotspot_HotSpotStackFrameReference,          Graal)) \
   GRAAL_ONLY(do_klass(CompilationTask_klass,                 com_oracle_graal_hotspot_CompilationTask,                     Graal)) \
-  GRAAL_ONLY(do_klass(Assumptions_ConcreteMethod_klass,      com_oracle_graal_api_code_Assumptions_ConcreteMethod,         Graal)) \
-  GRAAL_ONLY(do_klass(Assumptions_NoFinalizableSubclass_klass, com_oracle_graal_api_code_Assumptions_NoFinalizableSubclass, Graal))\
-  GRAAL_ONLY(do_klass(Assumptions_ConcreteSubtype_klass,     com_oracle_graal_api_code_Assumptions_ConcreteSubtype,        Graal)) \
-  GRAAL_ONLY(do_klass(Assumptions_CallSiteTargetValue_klass, com_oracle_graal_api_code_Assumptions_CallSiteTargetValue,    Graal)) \
+  GRAAL_ONLY(do_klass(Assumptions_ConcreteMethod_klass,      com_oracle_graal_api_meta_Assumptions_ConcreteMethod,         Graal)) \
+  GRAAL_ONLY(do_klass(Assumptions_NoFinalizableSubclass_klass, com_oracle_graal_api_meta_Assumptions_NoFinalizableSubclass, Graal))\
+  GRAAL_ONLY(do_klass(Assumptions_ConcreteSubtype_klass,     com_oracle_graal_api_meta_Assumptions_ConcreteSubtype,        Graal)) \
+  GRAAL_ONLY(do_klass(Assumptions_LeafType_klass,            com_oracle_graal_api_meta_Assumptions_LeafType,               Graal)) \
+  GRAAL_ONLY(do_klass(Assumptions_CallSiteTargetValue_klass, com_oracle_graal_api_meta_Assumptions_CallSiteTargetValue,    Graal)) \
   GRAAL_ONLY(do_klass(BytecodePosition_klass,                com_oracle_graal_api_code_BytecodePosition,                   Graal)) \
   GRAAL_ONLY(do_klass(DebugInfo_klass,                       com_oracle_graal_api_code_DebugInfo,                          Graal)) \
   GRAAL_ONLY(do_klass(RegisterSaveLayout_klass,              com_oracle_graal_api_code_RegisterSaveLayout,                 Graal)) \
--- a/src/share/vm/classfile/vmSymbols.hpp	Thu Mar 12 15:58:28 2015 +0100
+++ b/src/share/vm/classfile/vmSymbols.hpp	Thu Mar 12 15:59:01 2015 +0100
@@ -321,10 +321,11 @@
   GRAAL_ONLY(template(com_oracle_graal_api_meta_Kind,                           "com/oracle/graal/api/meta/Kind"))                                \
   GRAAL_ONLY(template(com_oracle_graal_api_meta_LIRKind,                        "com/oracle/graal/api/meta/LIRKind"))                             \
   GRAAL_ONLY(template(com_oracle_graal_api_meta_AbstractValue,                  "com/oracle/graal/api/meta/AbstractValue"))                       \
-  GRAAL_ONLY(template(com_oracle_graal_api_code_Assumptions_ConcreteSubtype,    "com/oracle/graal/api/code/Assumptions$ConcreteSubtype"))         \
-  GRAAL_ONLY(template(com_oracle_graal_api_code_Assumptions_NoFinalizableSubclass, "com/oracle/graal/api/code/Assumptions$NoFinalizableSubclass")) \
-  GRAAL_ONLY(template(com_oracle_graal_api_code_Assumptions_ConcreteMethod,     "com/oracle/graal/api/code/Assumptions$ConcreteMethod"))          \
-  GRAAL_ONLY(template(com_oracle_graal_api_code_Assumptions_CallSiteTargetValue,"com/oracle/graal/api/code/Assumptions$CallSiteTargetValue"))     \
+  GRAAL_ONLY(template(com_oracle_graal_api_meta_Assumptions_ConcreteSubtype,    "com/oracle/graal/api/meta/Assumptions$ConcreteSubtype"))         \
+  GRAAL_ONLY(template(com_oracle_graal_api_meta_Assumptions_LeafType,           "com/oracle/graal/api/meta/Assumptions$LeafType"))                \
+  GRAAL_ONLY(template(com_oracle_graal_api_meta_Assumptions_NoFinalizableSubclass, "com/oracle/graal/api/meta/Assumptions$NoFinalizableSubclass")) \
+  GRAAL_ONLY(template(com_oracle_graal_api_meta_Assumptions_ConcreteMethod,     "com/oracle/graal/api/meta/Assumptions$ConcreteMethod"))          \
+  GRAAL_ONLY(template(com_oracle_graal_api_meta_Assumptions_CallSiteTargetValue,"com/oracle/graal/api/meta/Assumptions$CallSiteTargetValue"))     \
   GRAAL_ONLY(template(com_oracle_graal_api_code_CompilationResult,              "com/oracle/graal/api/code/CompilationResult"))                   \
   GRAAL_ONLY(template(com_oracle_graal_api_code_CompilationResult_Call,         "com/oracle/graal/api/code/CompilationResult$Call"))              \
   GRAAL_ONLY(template(com_oracle_graal_api_code_CompilationResult_ConstantReference, "com/oracle/graal/api/code/CompilationResult$ConstantReference")) \
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Thu Mar 12 15:58:28 2015 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Thu Mar 12 15:59:01 2015 +0100
@@ -400,6 +400,8 @@
           assumption_NoFinalizableSubclass(assumption);
         } else if (assumption->klass() == Assumptions_ConcreteSubtype::klass()) {
           assumption_ConcreteSubtype(assumption);
+        } else if (assumption->klass() == Assumptions_LeafType::klass()) {
+          assumption_LeafType(assumption);
         } else if (assumption->klass() == Assumptions_ConcreteMethod::klass()) {
           assumption_ConcreteMethod(assumption);
         } else if (assumption->klass() == Assumptions_CallSiteTargetValue::klass()) {
@@ -658,11 +660,15 @@
   Klass* context = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(context_handle));
   Klass* subtype = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(subtype_handle));
 
-  if (context != subtype) {
-    assert(context->is_abstract(), "");
-    _dependencies->assert_abstract_with_unique_concrete_subtype(context, subtype);
-  }
-  _dependencies->assert_leaf_type(subtype);
+  assert(context->is_abstract(), "");
+  _dependencies->assert_abstract_with_unique_concrete_subtype(context, subtype);
+}
+
+void CodeInstaller::assumption_LeafType(Handle assumption) {
+  Handle context_handle = Assumptions_LeafType::context(assumption());
+  Klass* context = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(context_handle));
+
+  _dependencies->assert_leaf_type(context);
 }
 
 void CodeInstaller::assumption_ConcreteMethod(Handle assumption) {
--- a/src/share/vm/graal/graalCodeInstaller.hpp	Thu Mar 12 15:58:28 2015 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.hpp	Thu Mar 12 15:59:01 2015 +0100
@@ -131,6 +131,7 @@
 
   void assumption_NoFinalizableSubclass(Handle assumption);
   void assumption_ConcreteSubtype(Handle assumption);
+  void assumption_LeafType(Handle assumption);
   void assumption_ConcreteMethod(Handle assumption);
   void assumption_CallSiteTargetValue(Handle assumption);
 
--- a/src/share/vm/graal/graalJavaAccess.hpp	Thu Mar 12 15:58:28 2015 +0100
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Thu Mar 12 15:59:01 2015 +0100
@@ -97,7 +97,7 @@
     int_field(CompilationResult, totalFrameSize)                                                                                                               \
     int_field(CompilationResult, customStackAreaOffset)                                                                                                        \
     typeArrayOop_field(CompilationResult, targetCode, "[B")                                                                                                    \
-    objArrayOop_field(CompilationResult, assumptions, "[Lcom/oracle/graal/api/code/Assumptions$Assumption;")                                                   \
+    objArrayOop_field(CompilationResult, assumptions, "[Lcom/oracle/graal/api/meta/Assumptions$Assumption;")                                                   \
     objArrayOop_field(CompilationResult, methods, "[Lcom/oracle/graal/api/meta/ResolvedJavaMethod;")                                                           \
     int_field(CompilationResult, targetCodeSize)                                                                                                               \
   end_class                                                                                                                                                    \
@@ -108,6 +108,9 @@
     oop_field(Assumptions_ConcreteSubtype, context, "Lcom/oracle/graal/api/meta/ResolvedJavaType;")                                                            \
     oop_field(Assumptions_ConcreteSubtype, subtype, "Lcom/oracle/graal/api/meta/ResolvedJavaType;")                                                            \
   end_class                                                                                                                                                    \
+  start_class(Assumptions_LeafType)                                                                                                                            \
+    oop_field(Assumptions_LeafType, context, "Lcom/oracle/graal/api/meta/ResolvedJavaType;")                                                                   \
+  end_class                                                                                                                                                    \
   start_class(Assumptions_ConcreteMethod)                                                                                                                      \
     oop_field(Assumptions_ConcreteMethod, method, "Lcom/oracle/graal/api/meta/ResolvedJavaMethod;")                                                            \
     oop_field(Assumptions_ConcreteMethod, context, "Lcom/oracle/graal/api/meta/ResolvedJavaType;")                                                             \
@@ -317,20 +320,21 @@
         oop_store((oop*)addr, x);                                                                              \
       }                                                                                                        \
     }
-#define STATIC_PRIMITIVE_FIELD(klassName, name, typename, jtypename)                                           \
+#define STATIC_PRIMITIVE_FIELD(klassName, name, jtypename)                                                     \
     static int _##name##_offset;                                                                               \
-    static typename name() {                                                                                   \
+    static jtypename name() {                                                                                  \
       InstanceKlass* ik = InstanceKlass::cast(klassName::klass());                                             \
       address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \
       return *((jtypename *)addr);                                                                             \
     }                                                                                                          \
-    static void set_##name(typename x) {                                                                       \
+    static void set_##name(jtypename x) {                                                                      \
       InstanceKlass* ik = InstanceKlass::cast(klassName::klass());                                             \
       address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \
       *((jtypename *)addr) = x;                                                                                \
     }
-#define STATIC_INT_FIELD(klassName, name) STATIC_PRIMITIVE_FIELD(klassName, name, int, jint)
-#define STATIC_BOOLEAN_FIELD(klassName, name) STATIC_PRIMITIVE_FIELD(klassName, name, bool, jboolean)
+
+#define STATIC_INT_FIELD(klassName, name) STATIC_PRIMITIVE_FIELD(klassName, name, jint)
+#define STATIC_BOOLEAN_FIELD(klassName, name) STATIC_PRIMITIVE_FIELD(klassName, name, jboolean)
 
 COMPILER_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OOP_FIELD, TYPEARRAYOOP_FIELD, OBJARRAYOOP_FIELD, STATIC_OOP_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD)
 #undef START_CLASS