changeset 8913:653110156f8a

refactored boxing identification and lowering, removed BoxingMethodPool and explicit boxing phases
author Lukas Stadler <lukas.stadler@jku.at>
date Mon, 08 Apr 2013 17:30:05 +0200
parents 9631f95971a3
children 7828409c364c
files graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/BoxingSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/BoxingSubstitutions.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxingMethodPool.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/BoxingEliminationPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandBoxingNodesPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IdentifyBoxingPhase.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java
diffstat 20 files changed, 635 insertions(+), 728 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java	Mon Apr 08 14:19:52 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +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.compiler.test;
-
-import java.util.*;
-
-import org.junit.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.PhasePlan.PhasePosition;
-import com.oracle.graal.phases.common.*;
-
-public class IfBoxingEliminationTest extends GraalCompilerTest {
-
-    private static final String REFERENCE_SNIPPET = "referenceSnippet";
-
-    public static int referenceSnippet(int a) {
-        int result;
-        if (a < 0) {
-            result = 1;
-        } else {
-            result = 2;
-        }
-        return result;
-    }
-
-    public static Integer boxedInteger() {
-        return 1;
-    }
-
-    public static Object boxedObject() {
-        return 2;
-    }
-
-    @Test
-    public void test1() {
-        test("test1Snippet");
-    }
-
-    public static int test1Snippet(int a) {
-        Integer result;
-        if (a < 0) {
-            result = boxedInteger();
-        } else {
-            result = (Integer) boxedObject();
-        }
-        return result;
-    }
-
-    private void test(final String snippet) {
-        Debug.scope("IfBoxingEliminationTest", new DebugDumpScope(snippet), new Runnable() {
-
-            @Override
-            public void run() {
-                StructuredGraph graph = parse(snippet);
-                BoxingMethodPool pool = new BoxingMethodPool(runtime());
-                IdentifyBoxingPhase identifyBoxingPhase = new IdentifyBoxingPhase(pool);
-                PhasePlan phasePlan = getDefaultPhasePlan();
-                phasePlan.addPhase(PhasePosition.AFTER_PARSING, identifyBoxingPhase);
-                phasePlan.addPhase(PhasePosition.AFTER_PARSING, new PhiStampPhase());
-                identifyBoxingPhase.apply(graph);
-                Map<Invoke, Double> hints = new HashMap<>();
-                for (Invoke invoke : graph.getInvokes()) {
-                    hints.put(invoke, 1000d);
-                }
-
-                Assumptions assumptions = new Assumptions(false);
-                new InliningPhase(runtime(), hints, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph);
-                new CanonicalizerPhase(runtime(), assumptions).apply(graph);
-                new PhiStampPhase().apply(graph);
-                new CanonicalizerPhase(runtime(), assumptions).apply(graph);
-                Debug.dump(graph, "Graph");
-                new BoxingEliminationPhase(runtime()).apply(graph);
-                Debug.dump(graph, "Graph");
-                new ExpandBoxingNodesPhase(pool).apply(graph);
-                new CanonicalizerPhase(runtime(), assumptions).apply(graph);
-                new CanonicalizerPhase(runtime(), assumptions).apply(graph);
-                new DeadCodeEliminationPhase().apply(graph);
-                StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET);
-                new CanonicalizerPhase(runtime(), assumptions).apply(referenceGraph);
-                new DeadCodeEliminationPhase().apply(referenceGraph);
-
-                assertEquals(referenceGraph, graph);
-            }
-        });
-    }
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Mon Apr 08 14:19:52 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Mon Apr 08 17:30:05 2013 +0200
@@ -82,21 +82,16 @@
                 for (Entry<VirtualObjectNode, VirtualObject> entry : virtualObjectsCopy.entrySet()) {
                     if (entry.getValue().getValues() == null) {
                         VirtualObjectNode vobj = entry.getKey();
-                        if (vobj instanceof BoxedVirtualObjectNode) {
-                            BoxedVirtualObjectNode boxedVirtualObjectNode = (BoxedVirtualObjectNode) vobj;
-                            entry.getValue().setValues(new Value[]{toValue(boxedVirtualObjectNode.getUnboxedValue())});
-                        } else {
-                            Value[] values = new Value[vobj.entryCount()];
-                            if (values.length > 0) {
-                                changed = true;
-                                VirtualObjectState currentField = (VirtualObjectState) objectStates.get(vobj);
-                                assert currentField != null;
-                                for (int i = 0; i < vobj.entryCount(); i++) {
-                                    values[i] = toValue(currentField.fieldValues().get(i));
-                                }
+                        Value[] values = new Value[vobj.entryCount()];
+                        if (values.length > 0) {
+                            changed = true;
+                            VirtualObjectState currentField = (VirtualObjectState) objectStates.get(vobj);
+                            assert currentField != null;
+                            for (int i = 0; i < vobj.entryCount(); i++) {
+                                values[i] = toValue(currentField.fieldValues().get(i));
                             }
-                            entry.getValue().setValues(values);
                         }
+                        entry.getValue().setValues(values);
                     }
                 }
             } while (changed);
@@ -165,7 +160,7 @@
         if (value instanceof VirtualObjectNode) {
             VirtualObjectNode obj = (VirtualObjectNode) value;
             EscapeObjectState state = objectStates.get(obj);
-            if (state == null && obj.entryCount() > 0 && !(obj instanceof BoxedVirtualObjectNode)) {
+            if (state == null && obj.entryCount() > 0) {
                 // null states occur for objects with 0 fields
                 throw new GraalInternalError("no mapping found for virtual object %s", obj);
             }
@@ -173,7 +168,7 @@
                 assert !(((MaterializedObjectState) state).materializedValue() instanceof VirtualObjectNode);
                 return toValue(((MaterializedObjectState) state).materializedValue());
             } else {
-                assert obj.entryCount() == 0 || state instanceof VirtualObjectState || obj instanceof BoxedVirtualObjectNode;
+                assert obj.entryCount() == 0 || state instanceof VirtualObjectState;
                 VirtualObject vobject = virtualObjects.get(value);
                 if (vobject == null) {
                     vobject = VirtualObject.get(obj.type(), null, virtualObjects.size());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Mon Apr 08 14:19:52 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Mon Apr 08 17:30:05 2013 +0200
@@ -90,6 +90,7 @@
     private NewObjectSnippets.Templates newObjectSnippets;
     private MonitorSnippets.Templates monitorSnippets;
     private WriteBarrierSnippets.Templates writeBarrierSnippets;
+    private BoxingSnippets.Templates boxingSnippets;
 
     private final Map<Descriptor, HotSpotRuntimeCallTarget> runtimeCalls = new HashMap<>();
     private final Map<ResolvedJavaMethod, Stub> stubs = new HashMap<>();
@@ -341,11 +342,17 @@
         replacements.registerSnippets(NewArrayStub.class);
         replacements.registerSnippets(WriteBarrierSnippets.class);
 
+        replacements.registerSnippets(BoxingSnippets.class);
+        for (Class<?> clazz : BoxingSubstitutions.getClasses()) {
+            replacements.registerSubstitutions(clazz);
+        }
+
         checkcastSnippets = new CheckCastSnippets.Templates(this, replacements, graalRuntime.getTarget());
         instanceofSnippets = new InstanceOfSnippets.Templates(this, replacements, graalRuntime.getTarget());
         newObjectSnippets = new NewObjectSnippets.Templates(this, replacements, graalRuntime.getTarget(), config.useTLAB);
         monitorSnippets = new MonitorSnippets.Templates(this, replacements, graalRuntime.getTarget(), config.useFastLocking);
         writeBarrierSnippets = new WriteBarrierSnippets.Templates(this, replacements, graalRuntime.getTarget());
+        boxingSnippets = new BoxingSnippets.Templates(this, replacements, graalRuntime.getTarget());
 
         registerStub(new NewInstanceStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_INSTANCE)));
         registerStub(new NewArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_ARRAY)));
@@ -782,6 +789,10 @@
             // zero and the MIN_VALUE / -1 cases.
         } else if (n instanceof UnwindNode || n instanceof ExceptionObjectNode) {
             // Nothing to do, using direct LIR lowering for these nodes.
+        } else if (n instanceof BoxNode) {
+            boxingSnippets.lower((BoxNode) n);
+        } else if (n instanceof UnboxNode) {
+            boxingSnippets.lower((UnboxNode) n);
         } else {
             assert false : "Node implementing Lowerable not handled: " + n;
             throw GraalInternalError.shouldNotReachHere();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/BoxingSnippets.java	Mon Apr 08 17:30:05 2013 +0200
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.replacements;
+
+import static com.oracle.graal.replacements.SnippetTemplate.*;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.Snippet.Fold;
+import com.oracle.graal.replacements.Snippet.Parameter;
+import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
+import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
+import com.oracle.graal.replacements.SnippetTemplate.Arguments;
+import com.oracle.graal.replacements.SnippetTemplate.Key;
+import com.oracle.graal.word.*;
+
+public class BoxingSnippets implements Snippets {
+
+    /**
+     * This snippet inlining policy differs from the default one in that it does normal inlining of
+     * boxing methods like {@link Integer#valueOf(int)} (as opposed to method substitution).
+     */
+    public static class BoxingSnippetInliningPolicy implements SnippetInliningPolicy {
+
+        @Override
+        public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) {
+            if (Modifier.isNative(method.getModifiers())) {
+                return false;
+            }
+            if (method.getAnnotation(Fold.class) != null) {
+                return false;
+            }
+            if (method.getAnnotation(NodeIntrinsic.class) != null) {
+                return false;
+            }
+            if (method.getAnnotation(Word.Operation.class) != null) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse) {
+            return false;
+        }
+    }
+
+    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    public static Boolean valueOf(@Parameter("value") boolean value) {
+        valueOfCounter.inc();
+        return UnsafeCastNode.unsafeCast(Boolean.valueOf(value), StampFactory.forNodeIntrinsic());
+    }
+
+    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    public static Byte valueOf(@Parameter("value") byte value) {
+        valueOfCounter.inc();
+        return UnsafeCastNode.unsafeCast(Byte.valueOf(value), StampFactory.forNodeIntrinsic());
+    }
+
+    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    public static Character valueOf(@Parameter("value") char value) {
+        valueOfCounter.inc();
+        return UnsafeCastNode.unsafeCast(Character.valueOf(value), StampFactory.forNodeIntrinsic());
+    }
+
+    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    public static Double valueOf(@Parameter("value") double value) {
+        valueOfCounter.inc();
+        return UnsafeCastNode.unsafeCast(Double.valueOf(value), StampFactory.forNodeIntrinsic());
+    }
+
+    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    public static Float valueOf(@Parameter("value") float value) {
+        valueOfCounter.inc();
+        return UnsafeCastNode.unsafeCast(Float.valueOf(value), StampFactory.forNodeIntrinsic());
+    }
+
+    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    public static Integer valueOf(@Parameter("value") int value) {
+        valueOfCounter.inc();
+        return UnsafeCastNode.unsafeCast(Integer.valueOf(value), StampFactory.forNodeIntrinsic());
+    }
+
+    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    public static Long valueOf(@Parameter("value") long value) {
+        valueOfCounter.inc();
+        return UnsafeCastNode.unsafeCast(Long.valueOf(value), StampFactory.forNodeIntrinsic());
+    }
+
+    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    public static Short valueOf(@Parameter("value") short value) {
+        valueOfCounter.inc();
+        return UnsafeCastNode.unsafeCast(Short.valueOf(value), StampFactory.forNodeIntrinsic());
+    }
+
+    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    public static boolean booleanValue(@Parameter("value") Boolean value) {
+        valueOfCounter.inc();
+        return value.booleanValue();
+    }
+
+    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    public static byte byteValue(@Parameter("value") Byte value) {
+        valueOfCounter.inc();
+        return value.byteValue();
+    }
+
+    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    public static char charValue(@Parameter("value") Character value) {
+        valueOfCounter.inc();
+        return value.charValue();
+    }
+
+    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    public static double doubleValue(@Parameter("value") Double value) {
+        valueOfCounter.inc();
+        return value.doubleValue();
+    }
+
+    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    public static float floatValue(@Parameter("value") Float value) {
+        valueOfCounter.inc();
+        return value.floatValue();
+    }
+
+    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    public static int intValue(@Parameter("value") Integer value) {
+        valueOfCounter.inc();
+        return value.intValue();
+    }
+
+    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    public static long longValue(@Parameter("value") Long value) {
+        valueOfCounter.inc();
+        return value.longValue();
+    }
+
+    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    public static short shortValue(@Parameter("value") Short value) {
+        valueOfCounter.inc();
+        return value.shortValue();
+    }
+
+    public static class Templates extends AbstractTemplates<BoxingSnippets> {
+
+        private final ResolvedJavaMethod[] valueOfMethods = new ResolvedJavaMethod[Kind.values().length];
+        private final ResolvedJavaMethod[] unboxMethods = new ResolvedJavaMethod[Kind.values().length];
+
+        public Templates(CodeCacheProvider runtime, Replacements replacements, TargetDescription target) {
+            super(runtime, replacements, target, BoxingSnippets.class);
+            for (Kind kind : new Kind[]{Kind.Boolean, Kind.Byte, Kind.Char, Kind.Double, Kind.Float, Kind.Int, Kind.Long, Kind.Short}) {
+                valueOfMethods[kind.ordinal()] = snippet("valueOf", kind.toJavaClass());
+                unboxMethods[kind.ordinal()] = snippet(kind.getJavaName() + "Value", kind.toBoxedJavaClass());
+            }
+        }
+
+        private ResolvedJavaMethod getValueOf(Kind kind) {
+            assert valueOfMethods[kind.ordinal()] != null;
+            return valueOfMethods[kind.ordinal()];
+        }
+
+        private ResolvedJavaMethod getUnbox(Kind kind) {
+            assert unboxMethods[kind.ordinal()] != null;
+            return unboxMethods[kind.ordinal()];
+        }
+
+        public void lower(BoxNode boxingValueOf) {
+            Key key = new Key(getValueOf(boxingValueOf.getBoxingKind()));
+            Arguments arguments = new Arguments().add("value", boxingValueOf.getValue());
+            SnippetTemplate template = cache.get(key);
+            Debug.log("Lowering integerValueOf in %s: node=%s, template=%s, arguments=%s", boxingValueOf.graph(), boxingValueOf, template, arguments);
+            template.instantiate(runtime, boxingValueOf, DEFAULT_REPLACER, arguments);
+        }
+
+        public void lower(UnboxNode unbox) {
+            Key key = new Key(getUnbox(unbox.getBoxingKind()));
+            Arguments arguments = new Arguments().add("value", unbox.getValue());
+            SnippetTemplate template = cache.get(key);
+            Debug.log("Lowering integerValueOf in %s: node=%s, template=%s, arguments=%s", unbox.graph(), unbox, template, arguments);
+            template.instantiate(runtime, unbox, DEFAULT_REPLACER, arguments);
+        }
+    }
+
+    private static final SnippetCounter.Group integerCounters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("Integer intrinsifications") : null;
+    private static final SnippetCounter valueOfCounter = new SnippetCounter(integerCounters, "valueOf", "valueOf intrinsification");
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/BoxingSubstitutions.java	Mon Apr 08 17:30:05 2013 +0200
@@ -0,0 +1,147 @@
+/*
+ * 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.hotspot.replacements;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.nodes.extended.*;
+
+public class BoxingSubstitutions {
+
+    @ClassSubstitution(Boolean.class)
+    private static class BooleanSubstitutions {
+
+        @MethodSubstitution
+        public static Boolean valueOf(boolean value) {
+            return BoxNode.box(value, Boolean.class, Kind.Boolean);
+        }
+
+        @MethodSubstitution(isStatic = false)
+        public static boolean booleanValue(Boolean value) {
+            return UnboxNode.unbox(value, Kind.Boolean);
+        }
+    }
+
+    @ClassSubstitution(Byte.class)
+    private static class ByteSubstitutions {
+
+        @MethodSubstitution
+        public static Byte valueOf(byte value) {
+            return BoxNode.box(value, Byte.class, Kind.Byte);
+        }
+
+        @MethodSubstitution(isStatic = false)
+        public static byte byteValue(Byte value) {
+            return UnboxNode.unbox(value, Kind.Byte);
+        }
+    }
+
+    @ClassSubstitution(Character.class)
+    private static class CharacterSubstitutions {
+
+        @MethodSubstitution
+        public static Character valueOf(char value) {
+            return BoxNode.box(value, Character.class, Kind.Char);
+        }
+
+        @MethodSubstitution(isStatic = false)
+        public static char charValue(Character value) {
+            return UnboxNode.unbox(value, Kind.Char);
+        }
+    }
+
+    @ClassSubstitution(Double.class)
+    private static class DoubleSubstitutions {
+
+        @MethodSubstitution
+        public static Double valueOf(double value) {
+            return BoxNode.box(value, Double.class, Kind.Double);
+        }
+
+        @MethodSubstitution(isStatic = false)
+        public static double doubleValue(Double value) {
+            return UnboxNode.unbox(value, Kind.Double);
+        }
+    }
+
+    @ClassSubstitution(Float.class)
+    private static class FloatSubstitutions {
+
+        @MethodSubstitution
+        public static Float valueOf(float value) {
+            return BoxNode.box(value, Float.class, Kind.Float);
+        }
+
+        @MethodSubstitution(isStatic = false)
+        public static float floatValue(Float value) {
+            return UnboxNode.unbox(value, Kind.Float);
+        }
+    }
+
+    @ClassSubstitution(Integer.class)
+    private static class IntegerSubstitutions {
+
+        @MethodSubstitution
+        public static Integer valueOf(int value) {
+            return BoxNode.box(value, Integer.class, Kind.Int);
+        }
+
+        @MethodSubstitution(isStatic = false)
+        public static int intValue(Integer value) {
+            return UnboxNode.unbox(value, Kind.Int);
+        }
+    }
+
+    @ClassSubstitution(Long.class)
+    private static class LongSubstitutions {
+
+        @MethodSubstitution
+        public static Long valueOf(long value) {
+            return BoxNode.box(value, Long.class, Kind.Long);
+        }
+
+        @MethodSubstitution(isStatic = false)
+        public static long longValue(Long value) {
+            return UnboxNode.unbox(value, Kind.Long);
+        }
+    }
+
+    @ClassSubstitution(Short.class)
+    private static class ShortSubstitutions {
+
+        @MethodSubstitution
+        public static Short valueOf(short value) {
+            return BoxNode.box(value, Short.class, Kind.Short);
+        }
+
+        @MethodSubstitution(isStatic = false)
+        public static short shortValue(Short value) {
+            return UnboxNode.unbox(value, Kind.Short);
+        }
+    }
+
+    public static Class<?>[] getClasses() {
+        return new Class<?>[]{BooleanSubstitutions.class, ByteSubstitutions.class, CharacterSubstitutions.class, DoubleSubstitutions.class, FloatSubstitutions.class, IntegerSubstitutions.class,
+                        LongSubstitutions.class, ShortSubstitutions.class};
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Mon Apr 08 14:19:52 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Mon Apr 08 17:30:05 2013 +0200
@@ -186,5 +186,5 @@
     }
 
     @NodeIntrinsic
-    public static native <T> T anchor(@ConstantNodeParameter Stamp stamp);
+    public static native BeginNode anchor(@ConstantNodeParameter Stamp stamp);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Mon Apr 08 14:19:52 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Mon Apr 08 17:30:05 2013 +0200
@@ -239,7 +239,7 @@
                 copy.remove(copy.size() - 1);
             }
             ValueNode lastSlot = copy.get(copy.size() - 1);
-            assert lastSlot.kind().getStackKind() == popKind.getStackKind() || (lastSlot instanceof BoxedVirtualObjectNode && popKind == Kind.Object);
+            assert lastSlot.kind().getStackKind() == popKind.getStackKind();
             copy.remove(copy.size() - 1);
         }
         Collections.addAll(copy, pushedValues);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Mon Apr 08 14:19:52 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Mon Apr 08 17:30:05 2013 +0200
@@ -172,5 +172,15 @@
     }
 
     @NodeIntrinsic
-    public static native <S, T> S convert(@ConstantNodeParameter Op op, T value);
+    public static native float convert(@ConstantNodeParameter Op op, int value);
+
+    @NodeIntrinsic
+    public static native int convert(@ConstantNodeParameter Op op, float value);
+
+    @NodeIntrinsic
+    public static native double convert(@ConstantNodeParameter Op op, long value);
+
+    @NodeIntrinsic
+    public static native long convert(@ConstantNodeParameter Op op, double value);
+
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Mon Apr 08 14:19:52 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Mon Apr 08 17:30:05 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,51 +23,45 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.IterableNodeType;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
-
-public final class BoxNode extends AbstractStateSplit implements StateSplit, Node.IterableNodeType, Canonicalizable {
+import com.oracle.graal.nodes.virtual.*;
 
-    @Input private ValueNode source;
-    private final int bci;
-    private final Kind sourceKind;
+public class BoxNode extends FixedWithNextNode implements VirtualizableAllocation, IterableNodeType, Lowerable, Canonicalizable {
 
-    public BoxNode(ValueNode value, ResolvedJavaType type, Kind sourceKind, int bci) {
-        super(StampFactory.exactNonNull(type));
-        this.source = value;
-        this.bci = bci;
-        this.sourceKind = sourceKind;
-        assert value.kind() != Kind.Object : "can only box from primitive type";
+    @Input private ValueNode value;
+    private final Kind boxingKind;
+
+    public BoxNode(Invoke invoke) {
+        this(invoke.methodCallTarget().arguments().get(0), invoke.node().objectStamp().type(), invoke.methodCallTarget().targetMethod().getSignature().getParameterKind(0));
     }
 
-    public ValueNode source() {
-        return source;
-    }
-
-    public Kind getSourceKind() {
-        return sourceKind;
+    public BoxNode(ValueNode value, ResolvedJavaType resultType, Kind boxingKind) {
+        super(StampFactory.exactNonNull(resultType));
+        this.value = value;
+        this.boxingKind = boxingKind;
     }
 
-    public void expand(BoxingMethodPool pool) {
-        ResolvedJavaMethod boxingMethod = pool.getBoxingMethod(sourceKind);
-        MethodCallTargetNode callTarget = graph().add(
-                        new MethodCallTargetNode(InvokeKind.Static, boxingMethod, new ValueNode[]{source}, boxingMethod.getSignature().getReturnType(boxingMethod.getDeclaringClass())));
-        InvokeNode invokeNode = graph().add(new InvokeNode(callTarget, bci));
-        invokeNode.setProbability(this.probability());
-        invokeNode.setStateAfter(stateAfter());
-        ((StructuredGraph) graph()).replaceFixedWithFixed(this, invokeNode);
+    public Kind getBoxingKind() {
+        return boxingKind;
+    }
+
+    public ValueNode getValue() {
+        return value;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
     }
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-
-        if (source.isConstant()) {
-            Constant sourceConstant = source.asConstant();
-            switch (sourceKind) {
+        if (value.isConstant()) {
+            Constant sourceConstant = value.asConstant();
+            switch (boxingKind) {
                 case Boolean:
                     return ConstantNode.forObject(Boolean.valueOf(sourceConstant.asBoolean()), tool.runtime(), graph());
                 case Byte:
@@ -90,13 +84,51 @@
 
             }
         }
+        if (usages().isEmpty()) {
+            return null;
+        }
+        return this;
+    }
 
-        for (Node usage : usages()) {
-            if (usage != stateAfter()) {
-                return this;
-            }
-        }
-        replaceAtUsages(null);
-        return null;
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode v = tool.getReplacedValue(getValue());
+        ResolvedJavaType type = objectStamp().type();
+
+        VirtualBoxingNode newVirtual = new VirtualBoxingNode(type, boxingKind);
+        assert newVirtual.getFields().length == 1;
+
+        tool.createVirtualObject(newVirtual, new ValueNode[]{v}, 0);
+        tool.replaceWithVirtual(newVirtual);
     }
+
+    /*
+     * Normally, all these variants wouldn't be needed because this can be accomplished by using a
+     * generic method with automatic unboxing. These intrinsics, however, are themselves used for
+     * recognizing boxings, which means that there would be a circularity issue.
+     */
+
+    @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/BoxingMethodPool.java	Mon Apr 08 14:19:52 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +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.nodes.extended;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-
-public class BoxingMethodPool {
-
-    private final Set<JavaMethod> specialMethods = new HashSet<>();
-    private final MetaAccessProvider runtime;
-    private final ResolvedJavaMethod[] boxingMethods = new ResolvedJavaMethod[Kind.values().length];
-    private final ResolvedJavaMethod[] unboxingMethods = new ResolvedJavaMethod[Kind.values().length];
-    private final ResolvedJavaField[] boxFields = new ResolvedJavaField[Kind.values().length];
-
-    public BoxingMethodPool(MetaAccessProvider runtime) {
-        this.runtime = runtime;
-
-        try {
-            initialize(Kind.Boolean, Boolean.class, "booleanValue");
-            initialize(Kind.Byte, Byte.class, "byteValue");
-            initialize(Kind.Char, Character.class, "charValue");
-            initialize(Kind.Short, Short.class, "shortValue");
-            initialize(Kind.Int, Integer.class, "intValue");
-            initialize(Kind.Long, Long.class, "longValue");
-            initialize(Kind.Float, Float.class, "floatValue");
-            initialize(Kind.Double, Double.class, "doubleValue");
-        } catch (SecurityException | NoSuchMethodException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    private void initialize(Kind kind, Class<?> type, String unboxMethod) throws SecurityException, NoSuchMethodException {
-        // Get boxing method from runtime.
-        ResolvedJavaMethod boxingMethod = runtime.lookupJavaMethod(type.getDeclaredMethod("valueOf", kind.toJavaClass()));
-        specialMethods.add(boxingMethod);
-        boxingMethods[kind.ordinal()] = boxingMethod;
-
-        // Get unboxing method from runtime.
-        ResolvedJavaMethod unboxingMethod = runtime.lookupJavaMethod(type.getDeclaredMethod(unboxMethod));
-        unboxingMethods[kind.ordinal()] = unboxingMethod;
-        specialMethods.add(unboxingMethod);
-
-        // Get the field that contains the boxed value.
-        ResolvedJavaField[] fields = runtime.lookupJavaType(type).getInstanceFields(false);
-        ResolvedJavaField boxField = fields[0];
-        assert fields.length == 1 && boxField.getKind() == kind;
-        boxFields[kind.ordinal()] = boxField;
-    }
-
-    public boolean isSpecialMethod(ResolvedJavaMethod method) {
-        return specialMethods.contains(method);
-    }
-
-    public boolean isBoxingMethod(ResolvedJavaMethod method) {
-        return isSpecialMethod(method) && method.getSignature().getReturnKind() == Kind.Object;
-    }
-
-    public boolean isUnboxingMethod(ResolvedJavaMethod method) {
-        return isSpecialMethod(method) && method.getSignature().getReturnKind() != Kind.Object;
-    }
-
-    public ResolvedJavaMethod getBoxingMethod(Kind kind) {
-        return boxingMethods[kind.ordinal()];
-    }
-
-    public ResolvedJavaMethod getUnboxingMethod(Kind kind) {
-        return unboxingMethods[kind.ordinal()];
-    }
-
-    public ResolvedJavaField getBoxField(Kind kind) {
-        return boxFields[kind.ordinal()];
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Mon Apr 08 14:19:52 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Mon Apr 08 17:30:05 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,47 +23,50 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.IterableNodeType;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public final class UnboxNode extends FixedWithNextNode implements Node.IterableNodeType, Canonicalizable {
+public class UnboxNode extends FixedWithNextNode implements VirtualizableAllocation, IterableNodeType, Lowerable, Canonicalizable {
 
-    @Input private ValueNode source;
-    private Kind destinationKind;
+    @Input private ValueNode value;
+    private final Kind boxingKind;
 
-    public UnboxNode(Kind kind, ValueNode source) {
-        super(StampFactory.forKind(kind));
-        this.source = source;
-        this.destinationKind = kind;
-        assert kind != Kind.Object : "can only unbox to primitive";
-        assert source.kind() == Kind.Object : "can only unbox objects";
+    public UnboxNode(ValueNode value, Kind boxingKind) {
+        super(StampFactory.forKind(boxingKind.getStackKind()));
+        this.value = value;
+        this.boxingKind = boxingKind;
+    }
+
+    public Kind getBoxingKind() {
+        return boxingKind;
     }
 
-    public ValueNode source() {
-        return source;
+    public ValueNode getValue() {
+        return value;
     }
 
-    public Kind destinationKind() {
-        return destinationKind;
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
     }
 
-    public void expand(BoxingMethodPool pool) {
-        ResolvedJavaField field = pool.getBoxField(kind());
-        LoadFieldNode loadField = graph().add(new LoadFieldNode(source, field));
-        loadField.setProbability(probability());
-        ((StructuredGraph) graph()).replaceFixedWithFixed(this, loadField);
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        State state = tool.getObjectState(value);
+        if (state != null && state.getState() == EscapeState.Virtual) {
+            tool.replaceWithValue(state.getEntry(0));
+        }
     }
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        if (source.isConstant()) {
-            Constant constant = source.asConstant();
+        if (value.isConstant()) {
+            Constant constant = value.asConstant();
             Object o = constant.asObject();
             if (o != null) {
-                switch (destinationKind) {
+                switch (boxingKind) {
                     case Boolean:
                         return ConstantNode.forBoolean((Boolean) o, graph());
                     case Byte:
@@ -84,7 +87,42 @@
                         ValueNodeUtil.shouldNotReachHere();
                 }
             }
+        } else if (value instanceof BoxNode) {
+            return ((BoxNode) value).getValue();
+        }
+        if (usages().isEmpty()) {
+            return null;
         }
         return this;
     }
+
+    /*
+     * Normally, all these variants wouldn't be needed because this can be accomplished by using a
+     * generic method with automatic unboxing. These intrinsics, however, are themselves used for
+     * recognizing boxings, which means that there would be a circularity issue.
+     */
+
+    @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);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java	Mon Apr 08 14:19:52 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.virtual;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-
-public class BoxedVirtualObjectNode extends VirtualObjectNode implements LIRLowerable, Node.ValueNumberable {
-
-    @Input ValueNode unboxedValue;
-    private final ResolvedJavaType type;
-    private final Kind kind;
-
-    public BoxedVirtualObjectNode(ResolvedJavaType type, Kind kind, ValueNode unboxedValue) {
-        this.type = type;
-        this.kind = kind;
-        this.unboxedValue = unboxedValue;
-    }
-
-    public ValueNode getUnboxedValue() {
-        return unboxedValue;
-    }
-
-    @Override
-    public ResolvedJavaType type() {
-        return type;
-    }
-
-    @Override
-    public int entryCount() {
-        return 1;
-    }
-
-    @Override
-    public String fieldName(int index) {
-        assert index == 0;
-        return "value";
-    }
-
-    @Override
-    public int entryIndexForOffset(long constantOffset) {
-        // (lstadler) unsafe access to a newly created boxing object should only ever touch the
-        // value field
-        return 0;
-    }
-
-    @Override
-    public Kind entryKind(int index) {
-        return kind;
-    }
-
-    @Override
-    public BoxedVirtualObjectNode duplicate() {
-        return new BoxedVirtualObjectNode(type, kind, unboxedValue);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java	Mon Apr 08 17:30:05 2013 +0200
@@ -0,0 +1,49 @@
+/*
+ * 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.nodes.virtual;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+
+public class VirtualBoxingNode extends VirtualInstanceNode {
+
+    private final Kind boxingKind;
+
+    public VirtualBoxingNode(ResolvedJavaType type, Kind boxingKind) {
+        super(type);
+        this.boxingKind = boxingKind;
+    }
+
+    @Override
+    public VirtualBoxingNode duplicate() {
+        return new VirtualBoxingNode(type(), boxingKind);
+    }
+
+    @Override
+    public boolean hasIdentity() {
+        return false;
+    }
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/BoxingEliminationPhase.java	Mon Apr 08 14:19:52 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +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.phases.common;
-
-import static com.oracle.graal.graph.iterators.NodePredicates.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.iterators.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.virtual.*;
-import com.oracle.graal.phases.*;
-
-public class BoxingEliminationPhase extends Phase {
-
-    private final MetaAccessProvider metaAccess;
-
-    public BoxingEliminationPhase(MetaAccessProvider metaAccess) {
-        this.metaAccess = metaAccess;
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        if (graph.getNodes(UnboxNode.class).isNotEmpty()) {
-
-            Map<PhiNode, PhiNode> phiReplacements = new HashMap<>();
-            for (UnboxNode unboxNode : graph.getNodes(UnboxNode.class)) {
-                tryEliminate(graph, unboxNode, phiReplacements);
-            }
-
-            new DeadCodeEliminationPhase().apply(graph);
-
-            for (BoxNode boxNode : graph.getNodes(BoxNode.class)) {
-                tryEliminate(boxNode);
-            }
-        }
-    }
-
-    private void tryEliminate(StructuredGraph graph, UnboxNode unboxNode, Map<PhiNode, PhiNode> phiReplacements) {
-        ValueNode unboxedValue = unboxedValue(unboxNode.source(), unboxNode.destinationKind(), phiReplacements);
-        if (unboxedValue != null) {
-            assert unboxedValue.kind() == unboxNode.kind();
-            unboxNode.replaceAtUsages(unboxedValue);
-            graph.removeFixed(unboxNode);
-        }
-    }
-
-    private PhiNode getReplacementPhi(PhiNode phiNode, Kind kind, Map<PhiNode, PhiNode> phiReplacements) {
-        if (!phiReplacements.containsKey(phiNode)) {
-            PhiNode result = null;
-            ObjectStamp stamp = phiNode.objectStamp();
-            if (stamp.nonNull() && stamp.isExactType()) {
-                ResolvedJavaType type = stamp.type();
-                if (type != null && type.equals(metaAccess.lookupJavaType(kind.toBoxedJavaClass()))) {
-                    StructuredGraph graph = (StructuredGraph) phiNode.graph();
-                    result = graph.add(new PhiNode(kind, phiNode.merge()));
-                    phiReplacements.put(phiNode, result);
-                    virtualizeUsages(phiNode, result, type, kind);
-                    int i = 0;
-                    for (ValueNode n : phiNode.values()) {
-                        ValueNode unboxedValue = unboxedValue(n, kind, phiReplacements);
-                        if (unboxedValue != null) {
-                            assert unboxedValue.kind() == kind;
-                            result.addInput(unboxedValue);
-                        } else {
-                            UnboxNode unboxNode = graph.add(new UnboxNode(kind, n));
-                            FixedNode pred = phiNode.merge().phiPredecessorAt(i);
-                            graph.addBeforeFixed(pred, unboxNode);
-                            result.addInput(unboxNode);
-                        }
-                        ++i;
-                    }
-                }
-            }
-        }
-        return phiReplacements.get(phiNode);
-    }
-
-    private ValueNode unboxedValue(ValueNode n, Kind kind, Map<PhiNode, PhiNode> phiReplacements) {
-        if (n instanceof BoxNode) {
-            BoxNode boxNode = (BoxNode) n;
-            return boxNode.source();
-        } else if (n instanceof PhiNode) {
-            PhiNode phiNode = (PhiNode) n;
-            return getReplacementPhi(phiNode, kind, phiReplacements);
-        } else {
-            return null;
-        }
-    }
-
-    private static void tryEliminate(BoxNode boxNode) {
-
-        assert boxNode.objectStamp().isExactType();
-        virtualizeUsages(boxNode, boxNode.source(), boxNode.objectStamp().type(), boxNode.getSourceKind());
-
-        if (boxNode.usages().filter(isNotA(VirtualState.class)).isNotEmpty()) {
-            // Elimination failed, because boxing object escapes.
-            return;
-        }
-
-        FrameState stateAfter = boxNode.stateAfter();
-        boxNode.setStateAfter(null);
-        stateAfter.safeDelete();
-
-        ((StructuredGraph) boxNode.graph()).removeFixed(boxNode);
-    }
-
-    private static void virtualizeUsages(ValueNode boxNode, ValueNode replacement, ResolvedJavaType exactType, Kind sourceKind) {
-        ValueNode virtualValueNode = null;
-        VirtualObjectNode virtualObjectNode = null;
-        for (Node n : boxNode.usages().filter(NodePredicates.isA(VirtualState.class)).snapshot()) {
-            if (virtualValueNode == null) {
-                virtualObjectNode = n.graph().unique(new BoxedVirtualObjectNode(exactType, sourceKind, replacement));
-            }
-            n.replaceFirstInput(boxNode, virtualObjectNode);
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandBoxingNodesPhase.java	Mon Apr 08 14:19:52 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +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.phases.common;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.phases.*;
-
-public class ExpandBoxingNodesPhase extends Phase {
-
-    private final BoxingMethodPool pool;
-
-    public ExpandBoxingNodesPhase(BoxingMethodPool pool) {
-        this.pool = pool;
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        for (BoxNode boxNode : graph.getNodes(BoxNode.class)) {
-            boxNode.expand(pool);
-        }
-
-        for (UnboxNode unboxNode : graph.getNodes(UnboxNode.class)) {
-            unboxNode.expand(pool);
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IdentifyBoxingPhase.java	Mon Apr 08 14:19:52 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +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.phases.common;
-
-import java.lang.reflect.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.phases.*;
-
-public class IdentifyBoxingPhase extends Phase {
-
-    private final BoxingMethodPool pool;
-
-    public IdentifyBoxingPhase(BoxingMethodPool pool) {
-        this.pool = pool;
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        for (Invoke invoke : graph.getInvokes()) {
-            tryIntrinsify(invoke);
-        }
-    }
-
-    public void tryIntrinsify(Invoke invoke) {
-        if (!(invoke.callTarget() instanceof MethodCallTargetNode)) {
-            return;
-        }
-        MethodCallTargetNode callTarget = invoke.methodCallTarget();
-        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
-        if (pool.isSpecialMethod(targetMethod)) {
-            assert callTarget.arguments().size() == 1 : "boxing/unboxing method must have exactly one argument";
-            Kind returnKind = callTarget.returnKind();
-            ValueNode sourceValue = callTarget.arguments().get(0);
-
-            // Check whether this is a boxing or an unboxing.
-            Node newNode = null;
-            if (returnKind == Kind.Object) {
-                // We have a boxing method here.
-                assert Modifier.isStatic(targetMethod.getModifiers()) : "boxing method must be static";
-                Kind sourceKind = targetMethod.getSignature().getParameterKind(0);
-                newNode = invoke.graph().add(new BoxNode(sourceValue, targetMethod.getDeclaringClass(), sourceKind, invoke.bci()));
-            } else {
-                // We have an unboxing method here.
-                assert !Modifier.isStatic(targetMethod.getModifiers()) : "unboxing method must be an instance method";
-                newNode = invoke.graph().add(new UnboxNode(returnKind, sourceValue));
-            }
-
-            // Intrinsify the invoke to the special node.
-            invoke.intrinsify(newNode);
-        }
-    }
-}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Mon Apr 08 14:19:52 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Mon Apr 08 17:30:05 2013 +0200
@@ -28,16 +28,18 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.nodes.*;
+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.replacements.Snippet.*;
+import com.oracle.graal.replacements.Snippet.Fold;
 
 /**
  * Replaces calls to {@link NodeIntrinsic}s with nodes and calls to methods annotated with
@@ -46,20 +48,23 @@
 public class NodeIntrinsificationPhase extends Phase {
 
     private final MetaAccessProvider runtime;
-    private final BoxingMethodPool pool;
 
-    public NodeIntrinsificationPhase(MetaAccessProvider runtime, BoxingMethodPool pool) {
+    public NodeIntrinsificationPhase(MetaAccessProvider runtime) {
         this.runtime = runtime;
-        this.pool = pool;
     }
 
     @Override
     protected void run(StructuredGraph graph) {
+        ArrayList<Node> cleanUpReturnList = new ArrayList<>();
         for (Invoke i : graph.getInvokes()) {
             if (i.callTarget() instanceof MethodCallTargetNode) {
-                tryIntrinsify(i);
+                tryIntrinsify(i, cleanUpReturnList);
             }
         }
+
+        for (Node node : cleanUpReturnList) {
+            cleanUpReturnCheckCast(node);
+        }
     }
 
     public static Class<?>[] signatureToTypes(Signature signature, JavaType receiverType, ResolvedJavaType accessingClass) {
@@ -76,7 +81,7 @@
         return result;
     }
 
-    private boolean tryIntrinsify(Invoke invoke) {
+    private boolean tryIntrinsify(Invoke invoke, List<Node> cleanUpReturnList) {
         ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod();
         NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class);
         ResolvedJavaType declaringClass = target.getDeclaringClass();
@@ -103,7 +108,7 @@
             invoke.intrinsify(newInstance);
 
             // Clean up checkcast instructions inserted by javac if the return type is generic.
-            cleanUpReturnCheckCast(newInstance);
+            cleanUpReturnList.add(newInstance);
         } else if (target.getAnnotation(Fold.class) != null) {
             Class<?>[] parameterTypes = signatureToTypes(target.getSignature(), receiverType, declaringClass);
 
@@ -129,7 +134,7 @@
                 invoke.intrinsify(node);
 
                 // Clean up checkcast instructions inserted by javac if the return type is generic.
-                cleanUpReturnCheckCast(node);
+                cleanUpReturnList.add(node);
             } else {
                 // Remove the invoke
                 invoke.intrinsify(null);
@@ -154,7 +159,7 @@
             if (!invoke.methodCallTarget().isStatic()) {
                 parameterIndex--;
             }
-            ValueNode argument = tryBoxingElimination(parameterIndex, target, arguments.get(i));
+            ValueNode argument = arguments.get(i);
             if (folding || MetaUtil.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex, target) != null) {
                 if (!(argument instanceof ConstantNode)) {
                     return null;
@@ -195,47 +200,6 @@
         return result;
     }
 
-    private ValueNode tryBoxingElimination(int parameterIndex, ResolvedJavaMethod target, ValueNode node) {
-        if (parameterIndex >= 0) {
-            Type type = target.getGenericParameterTypes()[parameterIndex];
-            if (type instanceof TypeVariable) {
-                TypeVariable typeVariable = (TypeVariable) type;
-                if (typeVariable.getBounds().length == 1) {
-                    Type boundType = typeVariable.getBounds()[0];
-                    if (boundType instanceof Class && ((Class) boundType).getSuperclass() == null) {
-                        // Unbound generic => try boxing elimination
-                        if (node.usages().count() == 2) {
-                            if (node instanceof Invoke) {
-                                Invoke invokeNode = (Invoke) node;
-                                MethodCallTargetNode callTarget = invokeNode.methodCallTarget();
-                                if (pool.isBoxingMethod(callTarget.targetMethod())) {
-                                    FrameState stateAfter = invokeNode.stateAfter();
-                                    assert stateAfter.usages().count() == 1;
-                                    invokeNode.node().replaceAtUsages(null);
-                                    ValueNode result = callTarget.arguments().get(0);
-                                    StructuredGraph graph = (StructuredGraph) node.graph();
-                                    if (invokeNode instanceof InvokeWithExceptionNode) {
-                                        // Destroy exception edge & clear stateAfter.
-                                        InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode;
-
-                                        invokeWithExceptionNode.killExceptionEdge();
-                                        graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next());
-                                    } else {
-                                        graph.removeFixed((InvokeNode) invokeNode);
-                                    }
-                                    stateAfter.safeDelete();
-                                    GraphUtil.propagateKill(callTarget);
-                                    return result;
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        return node;
-    }
-
     private static Class asBoxedType(Class type) {
         if (!type.isPrimitive()) {
             return type;
@@ -379,32 +343,25 @@
                     if (checkCastUsage instanceof ValueAnchorNode) {
                         ValueAnchorNode valueAnchorNode = (ValueAnchorNode) checkCastUsage;
                         graph.removeFixed(valueAnchorNode);
+                    } else if (checkCastUsage instanceof UnboxNode) {
+                        UnboxNode unbox = (UnboxNode) checkCastUsage;
+                        unbox.replaceAtUsages(newInstance);
+                        graph.removeFixed(unbox);
                     } else if (checkCastUsage instanceof MethodCallTargetNode) {
                         MethodCallTargetNode checkCastCallTarget = (MethodCallTargetNode) checkCastUsage;
-                        if (pool.isUnboxingMethod(checkCastCallTarget.targetMethod())) {
-                            Invoke invokeNode = checkCastCallTarget.invoke();
-                            invokeNode.node().replaceAtUsages(newInstance);
-                            if (invokeNode instanceof InvokeWithExceptionNode) {
-                                // Destroy exception edge & clear stateAfter.
-                                InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode;
-
-                                invokeWithExceptionNode.killExceptionEdge();
-                                graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next());
-                            } else {
-                                graph.removeFixed((InvokeNode) invokeNode);
-                            }
-                            checkCastCallTarget.safeDelete();
-                        } else {
-                            assert checkCastCallTarget.targetMethod().getAnnotation(NodeIntrinsic.class) != null : "checkcast at " + sourceLocation(checkCastNode) +
-                                            " not used by an unboxing method or node intrinsic, but by a call at " + sourceLocation(checkCastCallTarget.usages().first()) + " to " +
-                                            checkCastCallTarget.targetMethod();
-                            checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object());
-                        }
+                        assert checkCastCallTarget.targetMethod().getAnnotation(NodeIntrinsic.class) != null : "checkcast at " + sourceLocation(checkCastNode) +
+                                        " not used by an unboxing method or node intrinsic, but by a call at " + sourceLocation(checkCastCallTarget.usages().first()) + " to " +
+                                        checkCastCallTarget.targetMethod();
+                        checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object());
                     } else if (checkCastUsage instanceof FrameState) {
                         checkCastUsage.replaceFirstInput(checkCastNode, null);
                     } else if (checkCastUsage instanceof ReturnNode && checkCastNode.object().stamp() == StampFactory.forNodeIntrinsic()) {
                         checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object());
+                    } else if (checkCastUsage instanceof IsNullNode) {
+                        assert checkCastUsage.usages().count() == 1 && checkCastUsage.usages().first().predecessor() == checkCastNode;
+                        graph.replaceFloating((FloatingNode) checkCastUsage, LogicConstantNode.contradiction(graph));
                     } else {
+                        Debug.dump(graph, "exception");
                         assert false : sourceLocation(checkCastUsage) + " has unexpected usage " + checkCastUsage + " of checkcast at " + sourceLocation(checkCastNode);
                     }
                 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Mon Apr 08 14:19:52 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Mon Apr 08 17:30:05 2013 +0200
@@ -37,7 +37,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.phases.*;
@@ -52,8 +51,6 @@
     protected final TargetDescription target;
     protected final Assumptions assumptions;
 
-    private BoxingMethodPool pool;
-
     /**
      * The preprocessed replacement graphs.
      */
@@ -204,7 +201,7 @@
             policyClass = snippet.inlining();
         }
         if (policyClass == SnippetInliningPolicy.class) {
-            return new DefaultSnippetInliningPolicy(runtime, pool());
+            return new DefaultSnippetInliningPolicy(runtime);
         }
         try {
             return policyClass.getConstructor().newInstance();
@@ -283,7 +280,7 @@
          * Does final processing of a snippet graph.
          */
         protected void finalizeGraph(StructuredGraph graph) {
-            new NodeIntrinsificationPhase(runtime, pool()).apply(graph);
+            new NodeIntrinsificationPhase(runtime).apply(graph);
             assert SnippetTemplate.hasConstantParameter(method) || NodeIntrinsificationVerificationPhase.verify(graph);
 
             if (original == null) {
@@ -317,7 +314,6 @@
             Debug.dump(graph, "%s: %s", methodToParse.getName(), GraphBuilderPhase.class.getSimpleName());
 
             new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph);
-            new NodeIntrinsificationPhase(runtime, pool()).apply(graph);
 
             return graph;
         }
@@ -339,7 +335,7 @@
          * Called after all inlining for a given graph is complete.
          */
         protected void afterInlining(StructuredGraph graph) {
-            new NodeIntrinsificationPhase(runtime, pool()).apply(graph);
+            new NodeIntrinsificationPhase(runtime).apply(graph);
 
             new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph);
 
@@ -366,7 +362,13 @@
                     substituteCallsOriginal = true;
                 } else {
                     if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) && policy.shouldInline(callee, methodToParse)) {
-                        StructuredGraph targetGraph = parseGraph(callee, policy);
+                        StructuredGraph targetGraph;
+                        StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(callee);
+                        if (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)) {
+                            targetGraph = intrinsicGraph;
+                        } else {
+                            targetGraph = parseGraph(callee, policy);
+                        }
                         InliningUtil.inline(invoke, targetGraph, true);
                         Debug.dump(graph, "after inlining %s", callee);
                         afterInline(graph, targetGraph);
@@ -467,14 +469,6 @@
         }
     }
 
-    protected BoxingMethodPool pool() {
-        if (pool == null) {
-            // A race to create the pool is ok
-            pool = new BoxingMethodPool(runtime);
-        }
-        return pool;
-    }
-
     @Override
     public Collection<ResolvedJavaMethod> getAllReplacements() {
         HashSet<ResolvedJavaMethod> result = new HashSet<>();
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java	Mon Apr 08 14:19:52 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java	Mon Apr 08 17:30:05 2013 +0200
@@ -27,7 +27,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.word.*;
@@ -55,6 +54,13 @@
          * Determines if {@code method} should be inlined into {@code caller}.
          */
         boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller);
+
+        /**
+         * Determines if {@code method} should be inlined using its replacement graph.
+         * 
+         * @return true if the replacement graph should be used, false for normal inlining.
+         */
+        boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse);
     }
 
     /**
@@ -70,11 +76,9 @@
     public static class DefaultSnippetInliningPolicy implements SnippetInliningPolicy {
 
         private final MetaAccessProvider metaAccess;
-        private final BoxingMethodPool pool;
 
-        public DefaultSnippetInliningPolicy(MetaAccessProvider metaAccess, BoxingMethodPool pool) {
+        public DefaultSnippetInliningPolicy(MetaAccessProvider metaAccess) {
             this.metaAccess = metaAccess;
-            this.pool = pool;
         }
 
         @Override
@@ -89,16 +93,18 @@
                 return false;
             }
             if (metaAccess.lookupJavaType(Throwable.class).isAssignableFrom(method.getDeclaringClass())) {
-                if (method.getName().equals("<init>")) {
+                if (method.isConstructor()) {
                     return false;
                 }
             }
             if (method.getAnnotation(Word.Operation.class) != null) {
                 return false;
             }
-            if (pool.isSpecialMethod(method)) {
-                return false;
-            }
+            return true;
+        }
+
+        @Override
+        public boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse) {
             return true;
         }
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon Apr 08 14:19:52 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon Apr 08 17:30:05 2013 +0200
@@ -35,13 +35,15 @@
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
 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.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.common.*;
-import com.oracle.graal.replacements.Snippet.*;
+import com.oracle.graal.replacements.Snippet.ConstantParameter;
+import com.oracle.graal.replacements.Snippet.Parameter;
+import com.oracle.graal.replacements.Snippet.Varargs;
+import com.oracle.graal.replacements.Snippet.VarargsParameter;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.word.*;
 import com.oracle.graal.word.phases.*;
@@ -283,7 +285,7 @@
         Debug.dump(snippetCopy, "Before specialization");
         if (!nodeReplacements.isEmpty()) {
             // Do deferred intrinsification of node intrinsics
-            new NodeIntrinsificationPhase(runtime, new BoxingMethodPool(runtime)).apply(snippetCopy);
+            new NodeIntrinsificationPhase(runtime).apply(snippetCopy);
             new WordTypeRewriterPhase(runtime, target.wordKind).apply(snippetCopy);
 
             new CanonicalizerPhase(runtime, replacements.getAssumptions(), 0, null).apply(snippetCopy);