changeset 20087:0b2bd777d933

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Mon, 30 Mar 2015 17:57:31 +0200
parents 00decb5cd984 (current diff) 8529bfcef6f5 (diff)
children 2c86be269fad
files graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleReplacements.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java
diffstat 18 files changed, 289 insertions(+), 331 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Mon Mar 30 17:56:43 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Mon Mar 30 17:57:31 2015 +0200
@@ -122,6 +122,11 @@
 
     SaveRbp saveRbp;
 
+    /**
+     * Helper instruction to reserve a stack slot for the whole method. Note that the actual users
+     * of the stack slot might be inserted after stack slot allocation. This dummy instruction
+     * ensures that the stack slot is alive and gets a real stack slot assigned.
+     */
     private static final class RescueSlotDummyOp extends LIRInstruction {
         public static final LIRInstructionClass<RescueSlotDummyOp> TYPE = LIRInstructionClass.create(RescueSlotDummyOp.class);
 
@@ -144,17 +149,16 @@
     private RescueSlotDummyOp rescueSlotOp;
 
     private StackSlotValue getOrInitRescueSlot() {
+        RescueSlotDummyOp op = getOrInitRescueSlotOp();
+        return op.getSlot();
+    }
+
+    private RescueSlotDummyOp getOrInitRescueSlotOp() {
         if (rescueSlotOp == null) {
             // create dummy instruction to keep the rescue slot alive
             rescueSlotOp = new RescueSlotDummyOp(getResult().getFrameMapBuilder(), getLIRKindTool().getWordKind());
-            // insert dummy instruction into the start block
-            LIR lir = getResult().getLIR();
-            List<LIRInstruction> instructions = lir.getLIRforBlock(lir.getControlFlowGraph().getStartBlock());
-            // Note: we do not insert at position 1 to avoid interference with the save rpb op
-            instructions.add(instructions.size() - 1, rescueSlotOp);
-            Debug.dump(lir, "created rescue dummy op");
         }
-        return rescueSlotOp.getSlot();
+        return rescueSlotOp;
     }
 
     /**
@@ -481,7 +485,12 @@
         }
         if (BenchmarkCounters.enabled) {
             // ensure that the rescue slot is available
-            getOrInitRescueSlot();
+            LIRInstruction op = getOrInitRescueSlotOp();
+            // insert dummy instruction into the start block
+            LIR lir = getResult().getLIR();
+            List<LIRInstruction> instructions = lir.getLIRforBlock(lir.getControlFlowGraph().getStartBlock());
+            instructions.add(1, op);
+            Debug.dump(lir, "created rescue dummy op");
         }
     }
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Mon Mar 30 17:56:43 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Mon Mar 30 17:57:31 2015 +0200
@@ -205,10 +205,9 @@
     }
 
     private StructuredGraph compile(String test, boolean compileAOT) {
-        StructuredGraph graph = parseEager(test, AllowAssumptions.YES);
-        ResolvedJavaMethod method = graph.method();
-
         try (OverrideScope s = OptionValue.override(ImmutableCode, compileAOT)) {
+            StructuredGraph graph = parseEager(test, AllowAssumptions.YES);
+            ResolvedJavaMethod method = graph.method();
             CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
             // create suites everytime, as we modify options for the compiler
             SuitesProvider suitesProvider = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites();
@@ -217,8 +216,7 @@
             final CompilationResult compResult = compileGraph(graph, cc, method, getProviders(), getBackend(), getCodeCache().getTarget(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL,
                             getProfilingInfo(graph), getSpeculationLog(), suitesLocal, lirSuitesLocal, new CompilationResult(), CompilationResultBuilderFactory.Default);
             addMethod(method, compResult);
+            return graph;
         }
-
-        return graph;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java	Mon Mar 30 17:56:43 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java	Mon Mar 30 17:57:31 2015 +0200
@@ -23,7 +23,6 @@
 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.*;
@@ -42,7 +41,7 @@
     static final ThreadLocal<Boolean> FieldReadEnabledInImmutableCode = new ThreadLocal<>();
 
     public boolean apply(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) {
-        if ((InlineDuringParsing.getValue() && !ImmutableCode.getValue()) || b.parsingReplacement()) {
+        if (!ImmutableCode.getValue() || b.parsingReplacement()) {
             if (receiver.isConstant()) {
                 JavaConstant asJavaConstant = receiver.asJavaConstant();
                 return tryReadField(b, field, asJavaConstant);
@@ -65,7 +64,7 @@
     }
 
     public boolean apply(GraphBuilderContext b, ResolvedJavaField staticField) {
-        if ((InlineDuringParsing.getValue() && !ImmutableCode.getValue()) || b.parsingReplacement()) {
+        if (!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")) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Mon Mar 30 17:56:43 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Mon Mar 30 17:57:31 2015 +0200
@@ -206,7 +206,9 @@
         }
 
         public void replace(LIR lir, LIRInstruction replacement) {
-            lir.getLIRforBlock(block).set(index, replacement);
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            assert instructions.get(index).equals(this) : String.format("Replacing the wrong instruction: %s instead of %s", instructions.get(index), this);
+            instructions.set(index, replacement);
         }
 
         @Override
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/Interval.java	Mon Mar 30 17:56:43 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/Interval.java	Mon Mar 30 17:57:31 2015 +0200
@@ -414,7 +414,7 @@
         }
 
         public void setRegisterPriority(int index, RegisterPriority registerPriority) {
-            list.set(index * 2, registerPriority.ordinal());
+            list.set((index << 1) + 1, registerPriority.ordinal());
         }
 
         @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Mon Mar 30 17:56:43 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Mon Mar 30 17:57:31 2015 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 @NodeInfo
 public final class UnboxNode extends FixedWithNextNode implements Virtualizable, Lowerable, Canonicalizable.Unary<ValueNode> {
@@ -78,6 +79,9 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (hasNoUsages() && StampTool.isPointerNonNull(forValue)) {
+            return null;
+        }
         ValueNode synonym = findSynonym(tool.getMetaAccess(), tool.getConstantReflection(), forValue, boxingKind);
         if (synonym != null) {
             return synonym;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Mon Mar 30 17:56:43 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Mon Mar 30 17:57:31 2015 +0200
@@ -122,7 +122,7 @@
 
     /**
      * Checks whether this {@link Stamp} represents a {@linkplain Stamp#isLegal() legal} pointer
-     * stamp whose values known to be always null.
+     * stamp whose values are known to never be null.
      *
      * @param stamp the stamp to check
      * @return true if this stamp represents a legal object stamp whose values are known to be
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Mon Mar 30 17:56:43 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Mon Mar 30 17:57:31 2015 +0200
@@ -208,7 +208,7 @@
         }
 
         @Override
-        public void replace(ValueNode oldNode, ValueNode newNode, MemoryMap mmap) {
+        public void replace(ValueNode oldNode, ValueNode newNode) {
             assert newNode instanceof PhiNode;
             assert oldNode == instanceOf;
             newNode.inferStamp();
@@ -239,7 +239,7 @@
         }
 
         @Override
-        public void replace(ValueNode oldNode, ValueNode newNode, MemoryMap mmap) {
+        public void replace(ValueNode oldNode, ValueNode newNode) {
             assert newNode instanceof PhiNode;
             assert oldNode == instanceOf;
             newNode.inferStamp();
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon Mar 30 17:56:43 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon Mar 30 17:57:31 2015 +0200
@@ -722,18 +722,20 @@
 
         new FloatingReadPhase(false, true).apply(snippetCopy);
 
-        MemoryAnchorNode memoryAnchor = snippetCopy.add(new MemoryAnchorNode());
-        snippetCopy.start().replaceAtUsages(InputType.Memory, memoryAnchor);
+        MemoryAnchorNode anchor = snippetCopy.add(new MemoryAnchorNode());
+        snippetCopy.start().replaceAtUsages(InputType.Memory, anchor);
 
         this.snippet = snippetCopy;
 
         Debug.dump(snippet, "SnippetTemplate after fixing memory anchoring");
 
         StartNode entryPointNode = snippet.start();
-        if (memoryAnchor.hasNoUsages()) {
-            memoryAnchor.safeDelete();
+        if (anchor.hasNoUsages()) {
+            anchor.safeDelete();
+            this.memoryAnchor = null;
         } else {
-            snippetCopy.addAfterFixed(snippetCopy.start(), memoryAnchor);
+            snippetCopy.addAfterFixed(snippetCopy.start(), anchor);
+            this.memoryAnchor = anchor;
         }
         List<ReturnNode> returnNodes = snippet.getNodes(ReturnNode.TYPE).snapshot();
         if (returnNodes.isEmpty()) {
@@ -832,6 +834,11 @@
     private final ReturnNode returnNode;
 
     /**
+     * The memory anchor (if any) of the snippet.
+     */
+    private final MemoryAnchorNode memoryAnchor;
+
+    /**
      * Nodes that inherit the {@link StateSplit#stateAfter()} from the replacee during
      * instantiation.
      */
@@ -948,7 +955,7 @@
         /**
          * Replaces all usages of {@code oldNode} with direct or indirect usages of {@code newNode}.
          */
-        void replace(ValueNode oldNode, ValueNode newNode, MemoryMap mmap);
+        void replace(ValueNode oldNode, ValueNode newNode);
     }
 
     /**
@@ -957,48 +964,8 @@
      */
     public static final UsageReplacer DEFAULT_REPLACER = new UsageReplacer() {
 
-        private LocationIdentity getLocationIdentity(Node node) {
-            if (node instanceof MemoryAccess) {
-                return ((MemoryAccess) node).getLocationIdentity();
-            } else if (node instanceof MemoryProxy) {
-                return ((MemoryProxy) node).getLocationIdentity();
-            } else if (node instanceof MemoryPhiNode) {
-                return ((MemoryPhiNode) node).getLocationIdentity();
-            } else {
-                return null;
-            }
-        }
-
         @Override
-        public void replace(ValueNode oldNode, ValueNode newNode, MemoryMap mmap) {
-            if (mmap != null) {
-                for (Node usage : oldNode.usages().snapshot()) {
-                    LocationIdentity identity = getLocationIdentity(usage);
-                    boolean usageReplaced = false;
-                    if (identity != null && !identity.isImmutable()) {
-                        // lastLocationAccess points into the snippet graph. find a proper
-                        // MemoryCheckPoint inside the snippet graph
-                        MemoryNode lastAccess = mmap.getLastLocationAccess(identity);
-
-                        assert lastAccess != null : "no mapping found for lowerable node " + oldNode + ". (No node in the snippet kills the same location as the lowerable node?)";
-                        if (usage instanceof MemoryAccess) {
-                            MemoryAccess access = (MemoryAccess) usage;
-                            if (access.getLastLocationAccess() == oldNode) {
-                                assert oldNode.graph().isAfterFloatingReadPhase();
-                                access.setLastLocationAccess(lastAccess);
-                                usageReplaced = true;
-                            }
-                        } else {
-                            assert usage instanceof MemoryProxy || usage instanceof MemoryPhiNode;
-                            usage.replaceFirstInput(oldNode, lastAccess.asNode());
-                            usageReplaced = true;
-                        }
-                    }
-                    if (!usageReplaced) {
-                        assert newNode != null : "this branch is only valid if we have a newNode for replacement";
-                    }
-                }
-            }
+        public void replace(ValueNode oldNode, ValueNode newNode) {
             if (newNode == null) {
                 assert oldNode.hasNoUsages();
             } else {
@@ -1066,14 +1033,48 @@
         return true;
     }
 
-    private class DuplicateMapper implements MemoryMap {
+    private static class MemoryInputMap implements MemoryMap {
+
+        private final LocationIdentity locationIdentity;
+        private final MemoryNode lastLocationAccess;
+
+        public MemoryInputMap(ValueNode replacee) {
+            if (replacee instanceof MemoryAccess) {
+                MemoryAccess access = (MemoryAccess) replacee;
+                locationIdentity = access.getLocationIdentity();
+                lastLocationAccess = access.getLastLocationAccess();
+            } else {
+                locationIdentity = null;
+                lastLocationAccess = null;
+            }
+        }
+
+        @Override
+        public MemoryNode getLastLocationAccess(LocationIdentity location) {
+            if (locationIdentity != null && locationIdentity.equals(location)) {
+                return lastLocationAccess;
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public Collection<LocationIdentity> getLocations() {
+            if (locationIdentity == null) {
+                return Collections.emptySet();
+            } else {
+                return Collections.singleton(locationIdentity);
+            }
+        }
+    }
+
+    private class MemoryOutputMap extends MemoryInputMap {
 
         private final Map<Node, Node> duplicates;
-        private StartNode replaceeStart;
 
-        public DuplicateMapper(Map<Node, Node> duplicates, StartNode replaceeStart) {
+        public MemoryOutputMap(ValueNode replacee, Map<Node, Node> duplicates) {
+            super(replacee);
             this.duplicates = duplicates;
-            this.replaceeStart = replaceeStart;
         }
 
         @Override
@@ -1081,9 +1082,9 @@
             MemoryMapNode memoryMap = returnNode.getMemoryMap();
             assert memoryMap != null : "no memory map stored for this snippet graph (snippet doesn't have a ReturnNode?)";
             MemoryNode lastLocationAccess = memoryMap.getLastLocationAccess(locationIdentity);
-            assert lastLocationAccess != null;
-            if (lastLocationAccess instanceof StartNode) {
-                return replaceeStart;
+            assert lastLocationAccess != null : locationIdentity;
+            if (lastLocationAccess == memoryAnchor) {
+                return super.getLastLocationAccess(locationIdentity);
             } else {
                 return (MemoryNode) duplicates.get(ValueNodeUtil.asNode(lastLocationAccess));
             }
@@ -1095,6 +1096,60 @@
         }
     }
 
+    private void rewireMemoryGraph(ValueNode replacee, Map<Node, Node> duplicates) {
+        // rewire outgoing memory edges
+        replaceMemoryUsages(replacee, new MemoryOutputMap(replacee, duplicates));
+
+        ReturnNode ret = (ReturnNode) duplicates.get(returnNode);
+        MemoryMapNode memoryMap = ret.getMemoryMap();
+        ret.setMemoryMap(null);
+        memoryMap.safeDelete();
+
+        if (memoryAnchor != null) {
+            // rewire incoming memory edges
+            MemoryAnchorNode memoryDuplicate = (MemoryAnchorNode) duplicates.get(memoryAnchor);
+            replaceMemoryUsages(memoryDuplicate, new MemoryInputMap(replacee));
+
+            if (memoryDuplicate.hasNoUsages()) {
+                memoryDuplicate.graph().removeFixed(memoryDuplicate);
+            }
+        }
+    }
+
+    private static LocationIdentity getLocationIdentity(Node node) {
+        if (node instanceof MemoryAccess) {
+            return ((MemoryAccess) node).getLocationIdentity();
+        } else if (node instanceof MemoryProxy) {
+            return ((MemoryProxy) node).getLocationIdentity();
+        } else if (node instanceof MemoryPhiNode) {
+            return ((MemoryPhiNode) node).getLocationIdentity();
+        } else {
+            return null;
+        }
+    }
+
+    private static void replaceMemoryUsages(ValueNode node, MemoryMap map) {
+        for (Node usage : node.usages().snapshot()) {
+            if (usage instanceof MemoryMapNode) {
+                continue;
+            }
+
+            LocationIdentity location = getLocationIdentity(usage);
+            if (location != null) {
+                NodePosIterator iter = usage.inputs().iterator();
+                while (iter.hasNext()) {
+                    Position pos = iter.nextPosition();
+                    if (pos.getInputType() == InputType.Memory && pos.get(usage) == node) {
+                        MemoryNode replacement = map.getLastLocationAccess(location);
+                        if (replacement != null) {
+                            pos.set(usage, replacement.asNode());
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Replaces a given fixed node with this specialized snippet.
      *
@@ -1181,17 +1236,18 @@
 
             updateStamps(replacee, duplicates);
 
+            rewireMemoryGraph(replacee, duplicates);
+
             // Replace all usages of the replacee with the value returned by the snippet
             ValueNode returnValue = null;
             if (returnNode != null && !(replacee instanceof ControlSinkNode)) {
                 ReturnNode returnDuplicate = (ReturnNode) duplicates.get(returnNode);
                 returnValue = returnDuplicate.result();
-                MemoryMap mmap = new DuplicateMapper(duplicates, replaceeGraph.start());
                 if (returnValue == null && replacee.usages().isNotEmpty() && replacee instanceof MemoryCheckpoint) {
-                    replacer.replace(replacee, null, mmap);
+                    replacer.replace(replacee, null);
                 } else {
                     assert returnValue != null || replacee.hasNoUsages();
-                    replacer.replace(replacee, returnValue, mmap);
+                    replacer.replace(replacee, returnValue);
                 }
                 if (returnDuplicate.isAlive()) {
                     FixedNode next = null;
@@ -1284,11 +1340,13 @@
             }
             updateStamps(replacee, duplicates);
 
+            rewireMemoryGraph(replacee, duplicates);
+
             // Replace all usages of the replacee with the value returned by the snippet
             ReturnNode returnDuplicate = (ReturnNode) duplicates.get(returnNode);
             ValueNode returnValue = returnDuplicate.result();
             assert returnValue != null || replacee.hasNoUsages();
-            replacer.replace(replacee, returnValue, new DuplicateMapper(duplicates, replaceeGraph.start()));
+            replacer.replace(replacee, returnValue);
 
             if (returnDuplicate.isAlive()) {
                 returnDuplicate.replaceAndDelete(next);
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleReplacements.java	Mon Mar 30 17:56:43 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +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.hotspot;
-
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.phases.util.*;
-import com.oracle.graal.runtime.*;
-import com.oracle.graal.truffle.*;
-
-public final class HotSpotTruffleReplacements extends TruffleReplacements {
-
-    private HotSpotTruffleReplacements(Providers providers, SnippetReflectionProvider snippetReflection) {
-        super(providers, snippetReflection);
-    }
-
-    public static Replacements makeInstance() {
-        Providers providers = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getProviders();
-        SnippetReflectionProvider snippetReflection = Graal.getRequiredCapability(SnippetReflectionProvider.class);
-        return new HotSpotTruffleReplacements(providers, snippetReflection);
-    }
-}
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Mon Mar 30 17:56:43 2015 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Mon Mar 30 17:57:31 2015 +0200
@@ -50,7 +50,6 @@
 import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
@@ -74,7 +73,6 @@
     }
 
     private TruffleCompilerImpl truffleCompiler;
-    private Replacements truffleReplacements;
     private Map<OptimizedCallTarget, Future<?>> compilations = newIdentityMap();
     private final ThreadPoolExecutor compileQueue;
 
@@ -143,14 +141,6 @@
         return createCallTargetImpl(source, root);
     }
 
-    @Override
-    public Replacements getReplacements() {
-        if (truffleReplacements == null) {
-            truffleReplacements = HotSpotTruffleReplacements.makeInstance();
-        }
-        return truffleReplacements;
-    }
-
     public static void installOptimizedCallTargetCallMethod() {
         Providers providers = getGraalProviders();
         MetaAccessProvider metaAccess = providers.getMetaAccess();
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Mon Mar 30 17:56:43 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Mon Mar 30 17:57:31 2015 +0200
@@ -32,7 +32,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.truffle.debug.*;
 import com.oracle.graal.truffle.unsafe.*;
 import com.oracle.truffle.api.*;
@@ -270,8 +269,6 @@
 
     public abstract Collection<OptimizedCallTarget> getQueuedCallTargets();
 
-    public abstract Replacements getReplacements();
-
     public abstract void compile(OptimizedCallTarget optimizedCallTarget, boolean mayBeAsynchronous);
 
     public abstract boolean cancelInstalledTask(OptimizedCallTarget optimizedCallTarget, Object source, CharSequence reason);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Mon Mar 30 17:56:43 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Mon Mar 30 17:57:31 2015 +0200
@@ -26,9 +26,7 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -42,7 +40,6 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
@@ -71,7 +68,7 @@
     private final ResolvedJavaMethod callDirectMethod;
     private final ResolvedJavaMethod callInlinedMethod;
     private final ResolvedJavaMethod callSiteProxyMethod;
-    protected final ResolvedJavaMethod callRootMethod;
+    private final ResolvedJavaMethod callRootMethod;
     private final GraphBuilderConfiguration configForRoot;
 
     public PartialEvaluator(Providers providers, GraphBuilderConfiguration configForRoot, SnippetReflectionProvider snippetReflection) {
@@ -173,13 +170,6 @@
             if (original.getAnnotation(TruffleBoundary.class) != null) {
                 return null;
             }
-            IntrinsicMethod intrinsicMethod = builder.getConstantReflection().getMethodHandleAccess().lookupMethodHandleIntrinsic(original);
-            if (intrinsicMethod != null) {
-                InlineInfo inlineInfo = getMethodHandleIntrinsicInlineInfo(builder, arguments, intrinsicMethod);
-                if (inlineInfo != null) {
-                    return inlineInfo;
-                }
-            }
             if (replacements != null && replacements.getMethodSubstitutionMethod(original) != null) {
                 return null;
             }
@@ -214,59 +204,6 @@
                 inlining.pop();
             }
         }
-
-        private InlineInfo getMethodHandleIntrinsicInlineInfo(GraphBuilderContext builder, ValueNode[] arguments, IntrinsicMethod intrinsicMethod) {
-            ResolvedJavaMethod targetMethod = null;
-            switch (intrinsicMethod) {
-                case INVOKE_BASIC:
-                    ValueNode methodHandleNode = arguments[0];
-                    if (methodHandleNode.isConstant()) {
-                        targetMethod = builder.getConstantReflection().getMethodHandleAccess().resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true);
-                    }
-                    break;
-                case LINK_TO_STATIC:
-                case LINK_TO_SPECIAL:
-                case LINK_TO_VIRTUAL:
-                case LINK_TO_INTERFACE:
-                    ValueNode memberNameNode = arguments[arguments.length - 1];
-                    if (memberNameNode.isConstant()) {
-                        targetMethod = builder.getConstantReflection().getMethodHandleAccess().resolveLinkToTarget(memberNameNode.asJavaConstant());
-                    }
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-            if (targetMethod != null) {
-                // TODO maybe cast arguments
-
-                if (!targetMethod.canBeInlined()) {
-                    return null;
-                }
-                if (targetMethod.canBeStaticallyBound()) {
-                    return new InlineInfo(targetMethod, false, false);
-                }
-
-                // Try to get the most accurate receiver type
-                if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
-                    ResolvedJavaType receiverType = StampTool.typeOrNull(arguments[0].stamp());
-                    if (receiverType != null) {
-                        AssumptionResult<ResolvedJavaMethod> concreteMethod = receiverType.findUniqueConcreteMethod(targetMethod);
-                        if (concreteMethod != null) {
-                            builder.getAssumptions().record(concreteMethod);
-                            return new InlineInfo(concreteMethod.getResult(), false, false);
-                        }
-                    }
-                } else {
-                    AssumptionResult<ResolvedJavaMethod> concreteMethod = targetMethod.getDeclaringClass().findUniqueConcreteMethod(targetMethod);
-                    if (concreteMethod != null) {
-                        builder.getAssumptions().record(concreteMethod);
-                        return new InlineInfo(concreteMethod.getResult(), false, false);
-                    }
-                }
-            }
-
-            return null;
-        }
     }
 
     private class PELoopExplosionPlugin implements LoopExplosionPlugin {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Mon Mar 30 17:56:43 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +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;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.phases.util.*;
-import com.oracle.graal.replacements.*;
-
-/**
- * Custom {@link Replacements} for Truffle compilation.
- */
-public abstract class TruffleReplacements extends ReplacementsImpl {
-
-    private final Replacements graalReplacements;
-
-    protected TruffleReplacements(Providers providers, SnippetReflectionProvider snippetReflection) {
-        super(providers, snippetReflection, providers.getCodeCache().getTarget());
-        this.graalReplacements = providers.getReplacements();
-    }
-
-    @Override
-    public StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args) {
-        return graalReplacements.getSnippet(method, null, args);
-    }
-
-    @Override
-    public StructuredGraph getMethodSubstitution(ResolvedJavaMethod method) {
-        StructuredGraph graph = graalReplacements.getMethodSubstitution(method);
-        if (graph == null) {
-            return super.getMethodSubstitution(method);
-        }
-        return graph;
-    }
-
-    @Override
-    public Collection<ResolvedJavaMethod> getAllReplacements() {
-        throw GraalInternalError.shouldNotReachHere();
-    }
-
-    @Override
-    public boolean isForcedSubstitution(ResolvedJavaMethod method) {
-        return graalReplacements.isForcedSubstitution(method) || super.isForcedSubstitution(method);
-    }
-
-    @Override
-    public void registerSnippetTemplateCache(SnippetTemplateCache templates) {
-        throw GraalInternalError.shouldNotReachHere();
-    }
-
-    @Override
-    public <T extends SnippetTemplateCache> T getSnippetTemplateCache(Class<T> templatesClass) {
-        return graalReplacements.getSnippetTemplateCache(templatesClass);
-    }
-}
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Mon Mar 30 17:56:43 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Mon Mar 30 17:57:31 2015 +0200
@@ -33,20 +33,23 @@
 
     final HashMap<ReadCacheEntry, ValueNode> readCache;
 
-    static class ReadCacheEntry {
+    static final class ReadCacheEntry {
 
         public final LocationIdentity identity;
         public final ValueNode object;
+        public final int index;
 
-        public ReadCacheEntry(LocationIdentity identity, ValueNode object) {
+        public ReadCacheEntry(LocationIdentity identity, ValueNode object, int index) {
             this.identity = identity;
             this.object = object;
+            this.index = index;
         }
 
         @Override
         public int hashCode() {
             int result = 31 + ((identity == null) ? 0 : identity.hashCode());
-            return 31 * result + ((object == null) ? 0 : object.hashCode());
+            result = 31 * result + ((object == null) ? 0 : object.hashCode());
+            return result * 31 + index;
         }
 
         @Override
@@ -60,7 +63,7 @@
 
         @Override
         public String toString() {
-            return object + ":" + identity;
+            return index == -1 ? (object + ":" + identity) : (object + "[" + index + "]:" + identity);
         }
     }
 
@@ -83,7 +86,7 @@
         if (virtual instanceof VirtualInstanceNode) {
             VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
             for (int i = 0; i < instance.entryCount(); i++) {
-                readCache.put(new ReadCacheEntry(instance.field(i).getLocationIdentity(), representation), values.get(i));
+                readCache.put(new ReadCacheEntry(instance.field(i).getLocationIdentity(), representation, -1), values.get(i));
             }
         }
     }
@@ -96,7 +99,7 @@
         return super.equivalentTo(other);
     }
 
-    public void addReadCache(ValueNode object, LocationIdentity identity, ValueNode value, PartialEscapeClosure<?> closure) {
+    public void addReadCache(ValueNode object, LocationIdentity identity, int index, ValueNode value, PartialEscapeClosure<?> closure) {
         ValueNode cacheObject;
         ObjectState obj = closure.getObjectState(this, object);
         if (obj != null) {
@@ -105,10 +108,10 @@
         } else {
             cacheObject = object;
         }
-        readCache.put(new ReadCacheEntry(identity, cacheObject), value);
+        readCache.put(new ReadCacheEntry(identity, cacheObject, index), value);
     }
 
-    public ValueNode getReadCache(ValueNode object, LocationIdentity identity, PartialEscapeClosure<?> closure) {
+    public ValueNode getReadCache(ValueNode object, LocationIdentity identity, int index, PartialEscapeClosure<?> closure) {
         ValueNode cacheObject;
         ObjectState obj = closure.getObjectState(this, object);
         if (obj != null) {
@@ -117,7 +120,7 @@
         } else {
             cacheObject = object;
         }
-        ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject));
+        ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject, index));
         obj = closure.getObjectState(this, cacheValue);
         if (obj != null) {
             assert !obj.isVirtual();
@@ -133,11 +136,11 @@
         readCache.clear();
     }
 
-    public void killReadCache(LocationIdentity identity) {
+    public void killReadCache(LocationIdentity identity, int index) {
         Iterator<Map.Entry<ReadCacheEntry, ValueNode>> iter = readCache.entrySet().iterator();
         while (iter.hasNext()) {
-            Map.Entry<ReadCacheEntry, ValueNode> entry = iter.next();
-            if (entry.getKey().identity.equals(identity)) {
+            ReadCacheEntry entry = iter.next().getKey();
+            if (entry.identity.equals(identity) && (index == -1 || entry.index == -1 || index == entry.index)) {
                 iter.remove();
             }
         }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Mon Mar 30 17:56:43 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Mon Mar 30 17:57:31 2015 +0200
@@ -38,6 +38,14 @@
 
 public class PEReadEliminationClosure extends PartialEscapeClosure<PEReadEliminationBlockState> {
 
+    private static final EnumMap<Kind, LocationIdentity> UNBOX_LOCATIONS;
+    static {
+        UNBOX_LOCATIONS = new EnumMap<>(Kind.class);
+        for (Kind kind : Kind.values()) {
+            UNBOX_LOCATIONS.put(kind, NamedLocationIdentity.immutable("PEA unbox " + kind.getJavaName()));
+        }
+    }
+
     public PEReadEliminationClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
         super(schedule, metaAccess, constantReflection);
     }
@@ -57,8 +65,14 @@
             return processLoadField((LoadFieldNode) node, state, effects);
         } else if (node instanceof StoreFieldNode) {
             return processStoreField((StoreFieldNode) node, state, effects);
+        } else if (node instanceof LoadIndexedNode) {
+            return processLoadIndexed((LoadIndexedNode) node, state, effects);
+        } else if (node instanceof StoreIndexedNode) {
+            return processStoreIndexed((StoreIndexedNode) node, state, effects);
         } else if (node instanceof ArrayLengthNode) {
             return processArrayLength((ArrayLengthNode) node, state, effects);
+        } else if (node instanceof UnboxNode) {
+            return processUnbox((UnboxNode) node, state, effects);
         } else if (node instanceof MemoryCheckpoint.Single) {
             METRIC_MEMORYCHECKPOINT.increment();
             LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
@@ -75,13 +89,13 @@
 
     private boolean processArrayLength(ArrayLengthNode length, PEReadEliminationBlockState state, GraphEffectList effects) {
         ValueNode array = GraphUtil.unproxify(length.array());
-        ValueNode cachedValue = state.getReadCache(array, ARRAY_LENGTH_LOCATION, this);
+        ValueNode cachedValue = state.getReadCache(array, ARRAY_LENGTH_LOCATION, -1, this);
         if (cachedValue != null) {
             effects.replaceAtUsages(length, cachedValue);
             addScalarAlias(length, cachedValue);
             return true;
         } else {
-            state.addReadCache(array, ARRAY_LENGTH_LOCATION, length, this);
+            state.addReadCache(array, ARRAY_LENGTH_LOCATION, -1, length, this);
         }
         return false;
     }
@@ -89,7 +103,7 @@
     private boolean processStoreField(StoreFieldNode store, PEReadEliminationBlockState state, GraphEffectList effects) {
         if (!store.isVolatile()) {
             ValueNode object = GraphUtil.unproxify(store.object());
-            ValueNode cachedValue = state.getReadCache(object, store.field().getLocationIdentity(), this);
+            ValueNode cachedValue = state.getReadCache(object, store.field().getLocationIdentity(), -1, this);
 
             ValueNode value = getScalarAlias(store.value());
             boolean result = false;
@@ -97,8 +111,8 @@
                 effects.deleteNode(store);
                 result = true;
             }
-            state.killReadCache(store.field().getLocationIdentity());
-            state.addReadCache(object, store.field().getLocationIdentity(), value, this);
+            state.killReadCache(store.field().getLocationIdentity(), -1);
+            state.addReadCache(object, store.field().getLocationIdentity(), -1, value, this);
             return result;
         } else {
             processIdentity(state, any());
@@ -111,14 +125,67 @@
             processIdentity(state, any());
         } else {
             ValueNode object = GraphUtil.unproxify(load.object());
-            ValueNode cachedValue = state.getReadCache(object, load.field().getLocationIdentity(), this);
+            ValueNode cachedValue = state.getReadCache(object, load.field().getLocationIdentity(), -1, this);
             if (cachedValue != null) {
                 effects.replaceAtUsages(load, cachedValue);
                 addScalarAlias(load, cachedValue);
                 return true;
             } else {
-                state.addReadCache(object, load.field().getLocationIdentity(), load, this);
+                state.addReadCache(object, load.field().getLocationIdentity(), -1, load, this);
+            }
+        }
+        return false;
+    }
+
+    private boolean processStoreIndexed(StoreIndexedNode store, PEReadEliminationBlockState state, GraphEffectList effects) {
+        LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(store.elementKind());
+        if (store.index().isConstant()) {
+            int index = ((JavaConstant) store.index().asConstant()).asInt();
+            ValueNode object = GraphUtil.unproxify(store.array());
+            ValueNode cachedValue = state.getReadCache(object, arrayLocation, index, this);
+
+            ValueNode value = getScalarAlias(store.value());
+            boolean result = false;
+            if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
+                effects.deleteNode(store);
+                result = true;
             }
+            state.killReadCache(arrayLocation, index);
+            state.addReadCache(object, arrayLocation, index, value, this);
+            return result;
+        } else {
+            state.killReadCache(arrayLocation, -1);
+        }
+        return false;
+    }
+
+    private boolean processLoadIndexed(LoadIndexedNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
+        if (load.index().isConstant()) {
+            int index = ((JavaConstant) load.index().asConstant()).asInt();
+            LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(load.elementKind());
+            ValueNode object = GraphUtil.unproxify(load.array());
+            ValueNode cachedValue = state.getReadCache(object, arrayLocation, index, this);
+            if (cachedValue != null) {
+                effects.replaceAtUsages(load, cachedValue);
+                addScalarAlias(load, cachedValue);
+                return true;
+            } else {
+                state.addReadCache(object, arrayLocation, index, load, this);
+            }
+        }
+        return false;
+    }
+
+    private boolean processUnbox(UnboxNode unbox, PEReadEliminationBlockState state, GraphEffectList effects) {
+        ValueNode object = GraphUtil.unproxify(unbox.getValue());
+        LocationIdentity identity = UNBOX_LOCATIONS.get(unbox.getBoxingKind());
+        ValueNode cachedValue = state.getReadCache(object, identity, -1, this);
+        if (cachedValue != null) {
+            effects.replaceAtUsages(unbox, cachedValue);
+            addScalarAlias(unbox, cachedValue);
+            return true;
+        } else {
+            state.addReadCache(object, identity, -1, unbox, this);
         }
         return false;
     }
@@ -127,7 +194,7 @@
         if (identity.isAny()) {
             state.killReadCache();
         } else {
-            state.killReadCache(identity);
+            state.killReadCache(identity, -1);
         }
     }
 
@@ -138,7 +205,7 @@
         if (exitNode.graph().hasValueProxies()) {
             for (Map.Entry<ReadCacheEntry, ValueNode> entry : exitState.getReadCache().entrySet()) {
                 if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) {
-                    ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity, this);
+                    ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity, entry.getKey().index, this);
                     if (!(value instanceof ProxyNode) || ((ProxyNode) value).proxyPoint() != exitNode) {
                         ProxyNode proxy = new ValueProxyNode(value, exitNode);
                         effects.addFloatingNode(proxy, "readCacheProxy");
@@ -192,7 +259,7 @@
                     PhiNode phiNode = getPhi(entry, value.stamp().unrestricted());
                     mergeEffects.addFloatingNode(phiNode, "mergeReadCache");
                     for (int i = 0; i < states.size(); i++) {
-                        afterMergeEffects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity, PEReadEliminationClosure.this));
+                        afterMergeEffects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity, key.index, PEReadEliminationClosure.this));
                     }
                     newState.readCache.put(key, phiNode);
                 } else if (value != null) {
@@ -203,7 +270,7 @@
                 if (phi.getKind() == Kind.Object) {
                     for (Map.Entry<ReadCacheEntry, ValueNode> entry : states.get(0).readCache.entrySet()) {
                         if (entry.getKey().object == phi.valueAt(0)) {
-                            mergeReadCachePhi(phi, entry.getKey().identity, states);
+                            mergeReadCachePhi(phi, entry.getKey().identity, entry.getKey().index, states);
                         }
                     }
 
@@ -211,22 +278,22 @@
             }
         }
 
-        private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, List<PEReadEliminationBlockState> states) {
+        private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, List<PEReadEliminationBlockState> states) {
             ValueNode[] values = new ValueNode[phi.valueCount()];
             for (int i = 0; i < phi.valueCount(); i++) {
-                ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity, PEReadEliminationClosure.this);
+                ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity, index, PEReadEliminationClosure.this);
                 if (value == null) {
                     return;
                 }
                 values[i] = value;
             }
 
-            PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi), values[0].stamp().unrestricted());
+            PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi, index), values[0].stamp().unrestricted());
             mergeEffects.addFloatingNode(phiNode, "mergeReadCachePhi");
             for (int i = 0; i < values.length; i++) {
                 afterMergeEffects.addPhiInput(phiNode, values[i]);
             }
-            newState.readCache.put(new ReadCacheEntry(identity, phi), phiNode);
+            newState.readCache.put(new ReadCacheEntry(identity, phi, index), phiNode);
         }
     }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ExactClassValueProfile.java	Mon Mar 30 17:56:43 2015 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ExactClassValueProfile.java	Mon Mar 30 17:57:31 2015 +0200
@@ -40,14 +40,16 @@
     @SuppressWarnings("unchecked")
     @Override
     public <T> T profile(T value) {
-        if (cachedClass != null && cachedClass.isInstance(value)) {
-            return (T) cachedClass.cast(value);
-        } else {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            if (cachedClass == null && value != null) {
-                cachedClass = value.getClass();
+        if (cachedClass != Object.class) {
+            if (cachedClass != null && cachedClass.isInstance(value)) {
+                return (T) cachedClass.cast(value);
             } else {
-                cachedClass = Object.class;
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                if (cachedClass == null && value != null) {
+                    cachedClass = value.getClass();
+                } else {
+                    cachedClass = Object.class;
+                }
             }
         }
         return value;
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/PrimitiveValueProfile.java	Mon Mar 30 17:56:43 2015 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/PrimitiveValueProfile.java	Mon Mar 30 17:57:31 2015 +0200
@@ -53,27 +53,42 @@
     public Object profile(Object value) {
         Object snapshot = this.cachedValue;
         if (snapshot != GENERIC) {
-            if (snapshot instanceof Byte && value instanceof Byte && (byte) snapshot == (byte) value) {
-                return snapshot;
-            } else if (snapshot instanceof Short && value instanceof Short && (short) snapshot == (short) value) {
-                return snapshot;
-            } else if (snapshot instanceof Integer && value instanceof Integer && (int) snapshot == (int) value) {
-                return snapshot;
-            } else if (snapshot instanceof Long && value instanceof Long && (long) snapshot == (long) value) {
-                return snapshot;
-            } else if (snapshot instanceof Float && value instanceof Float && exactCompare((float) snapshot, (float) value)) {
-                return snapshot;
-            } else if (snapshot instanceof Double && value instanceof Double && exactCompare((double) snapshot, (double) value)) {
-                return snapshot;
-            } else if (snapshot instanceof Boolean && value instanceof Boolean && (boolean) snapshot == (boolean) value) {
-                return snapshot;
-            } else if (snapshot instanceof Character && value instanceof Character && (char) snapshot == (char) value) {
-                return snapshot;
+            if (snapshot instanceof Byte) {
+                if (value instanceof Byte && (byte) snapshot == (byte) value) {
+                    return snapshot;
+                }
+            } else if (snapshot instanceof Short) {
+                if (value instanceof Short && (short) snapshot == (short) value) {
+                    return snapshot;
+                }
+            } else if (snapshot instanceof Integer) {
+                if (value instanceof Integer && (int) snapshot == (int) value) {
+                    return snapshot;
+                }
+            } else if (snapshot instanceof Long) {
+                if (value instanceof Long && (long) snapshot == (long) value) {
+                    return snapshot;
+                }
+            } else if (snapshot instanceof Float) {
+                if (value instanceof Float && exactCompare((float) snapshot, (float) value)) {
+                    return snapshot;
+                }
+            } else if (snapshot instanceof Double) {
+                if (value instanceof Double && exactCompare((double) snapshot, (double) value)) {
+                    return snapshot;
+                }
+            } else if (snapshot instanceof Boolean) {
+                if (value instanceof Boolean && (boolean) snapshot == (boolean) value) {
+                    return snapshot;
+                }
+            } else if (snapshot instanceof Character) {
+                if (value instanceof Character && (char) snapshot == (char) value) {
+                    return snapshot;
+                }
             } else if (snapshot == value) {
                 return snapshot;
-            } else {
-                cacheMiss(value);
             }
+            cacheMiss(value);
         }
         return value;
     }