changeset 5129:51111665eda6

Support for recording a leaf graph id for each deoptimization point in the debug info.
author Lukas Stadler <lukas.stadler@jku.at>
date Wed, 21 Mar 2012 10:47:02 +0100
parents e2da6471a9a1
children ab038e0d6b43
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ConvertDeoptimizeToGuardPhase.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/CiLoweringTool.java graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/GraalRuntime.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.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/SafeAccessNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/types/ObjectTypeFeedbackStore.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/types/ScalarTypeFeedbackStore.java graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiCodePos.java graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiFrame.java src/share/vm/c1/c1_IR.cpp src/share/vm/code/debugInfoRec.cpp src/share/vm/code/debugInfoRec.hpp src/share/vm/code/pcDesc.cpp src/share/vm/code/pcDesc.hpp src/share/vm/graal/graalCodeInstaller.cpp src/share/vm/graal/graalCompiler.cpp src/share/vm/graal/graalCompiler.hpp src/share/vm/graal/graalCompilerToVM.cpp src/share/vm/graal/graalJavaAccess.hpp src/share/vm/runtime/deoptimization.cpp src/share/vm/runtime/mutexLocker.cpp src/share/vm/runtime/mutexLocker.hpp src/share/vm/utilities/macros.hpp
diffstat 45 files changed, 382 insertions(+), 196 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Wed Mar 21 10:47:02 2012 +0100
@@ -43,9 +43,9 @@
 
     private HashMap<VirtualObjectNode, CiVirtualObject> virtualObjects = new HashMap<>();
 
-    public LIRDebugInfo build(FrameState topState, LockScope locks, List<CiStackSlot> pointerSlots, LabelRef exceptionEdge) {
+    public LIRDebugInfo build(FrameState topState, LockScope locks, List<CiStackSlot> pointerSlots, LabelRef exceptionEdge, long leafGraphId) {
         assert virtualObjects.size() == 0;
-        CiFrame frame = computeFrameForState(topState, locks);
+        CiFrame frame = computeFrameForState(topState, locks, leafGraphId);
 
         CiVirtualObject[] virtualObjectsArray = null;
         if (virtualObjects.size() != 0) {
@@ -106,7 +106,7 @@
         return new LIRDebugInfo(frame, virtualObjectsArray, pointerSlots, exceptionEdge);
     }
 
-    private CiFrame computeFrameForState(FrameState state, LockScope locks) {
+    private CiFrame computeFrameForState(FrameState state, LockScope locks, long leafGraphId) {
         int numLocals = state.localsSize();
         int numStack = state.stackSize();
         int numLocks = (locks != null && locks.callerState == state.outerFrameState()) ? locks.stateDepth + 1 : 0;
@@ -133,14 +133,14 @@
 
         CiFrame caller = null;
         if (state.outerFrameState() != null) {
-            caller = computeFrameForState(state.outerFrameState(), nextLock);
+            caller = computeFrameForState(state.outerFrameState(), nextLock, -1);
         } else {
             if (nextLock != null) {
                 throw new CiBailout("unbalanced monitors: found monitor for unknown frame");
             }
         }
         assert state.bci >= 0 || state.bci == FrameState.BEFORE_BCI;
-        CiFrame frame = new CiFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, state.localsSize(), state.stackSize(), numLocks);
+        CiFrame frame = new CiFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, state.localsSize(), state.stackSize(), numLocks, leafGraphId);
         return frame;
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Wed Mar 21 10:47:02 2012 +0100
@@ -249,15 +249,20 @@
 
     public LIRDebugInfo state() {
         assert lastState != null : "must have state before instruction";
-        return stateFor(lastState);
+        return stateFor(lastState, -1);
     }
 
-    public LIRDebugInfo stateFor(FrameState state) {
-        return stateFor(state, null, null);
+    public LIRDebugInfo state(long leafGraphId) {
+        assert lastState != null : "must have state before instruction";
+        return stateFor(lastState, leafGraphId);
     }
 
-    public LIRDebugInfo stateFor(FrameState state, List<CiStackSlot> pointerSlots, LabelRef exceptionEdge) {
-        return debugInfoBuilder.build(state, curLocks, pointerSlots, exceptionEdge);
+    public LIRDebugInfo stateFor(FrameState state, long leafGraphId) {
+        return stateFor(state, null, null, leafGraphId);
+    }
+
+    public LIRDebugInfo stateFor(FrameState state, List<CiStackSlot> pointerSlots, LabelRef exceptionEdge, long leafGraphId) {
+        return debugInfoBuilder.build(state, curLocks, pointerSlots, exceptionEdge, leafGraphId);
     }
 
     /**
@@ -528,7 +533,7 @@
         // The state before the monitor enter is used for null checks, so it must not contain the newly locked object.
         curLocks = new LockScope(curLocks, x.stateAfter().outerFrameState(), x, lockData);
         // The state after the monitor enter is used for deoptimization, after the monitor has blocked, so it must contain the newly locked object.
-        LIRDebugInfo stateAfter = stateFor(x.stateAfter());
+        LIRDebugInfo stateAfter = stateFor(x.stateAfter(), -1);
 
         XirSnippet snippet = xir.genMonitorEnter(site(x, x.object()), obj, lockAddress);
         emitXir(snippet, x, stateBefore, stateAfter, true, null, null);
@@ -745,20 +750,21 @@
     }
 
     @Override
-    public void emitGuardCheck(BooleanNode comp) {
+    public void emitGuardCheck(BooleanNode comp, long leafGraphId) {
         if (comp instanceof NullCheckNode && !((NullCheckNode) comp).expectedNull) {
-            emitNullCheckGuard((NullCheckNode) comp);
+            emitNullCheckGuard((NullCheckNode) comp, leafGraphId);
         } else if (comp instanceof ConstantNode && comp.asConstant().asBoolean()) {
             // True constant, nothing to emit.
+            // False constants are handled within emitBranch.
         } else {
             // Fall back to a normal branch.
-            LIRDebugInfo info = state();
+            LIRDebugInfo info = state(leafGraphId);
             LabelRef stubEntry = createDeoptStub(DeoptAction.InvalidateReprofile, info, comp);
             emitBranch(comp, null, stubEntry, info);
         }
     }
 
-    protected abstract void emitNullCheckGuard(NullCheckNode node);
+    protected abstract void emitNullCheckGuard(NullCheckNode node, long leafGraphId);
 
     public void emitBranch(BooleanNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) {
         if (node instanceof NullCheckNode) {
@@ -926,7 +932,7 @@
         if (!target().invokeSnippetAfterArguments) {
             // This is the version currently necessary for Maxine: since the invokeinterface-snippet uses a division, it
             // destroys rdx, which is also used to pass a parameter.  Therefore, the snippet must be before the parameters are assigned to their locations.
-            LIRDebugInfo addrInfo = stateFor(stateBeforeCallWithArguments(x.stateAfter(), callTarget, x.bci()));
+            LIRDebugInfo addrInfo = stateFor(stateBeforeCallWithArguments(x.stateAfter(), callTarget, x.bci()), x.leafGraphId());
             destinationAddress = emitXir(snippet, x.node(), addrInfo, false);
         }
 
@@ -939,11 +945,11 @@
 
         if (target().invokeSnippetAfterArguments) {
             // This is the version currently active for HotSpot.
-            LIRDebugInfo addrInfo = stateFor(stateBeforeCallWithArguments(x.stateAfter(), callTarget, x.bci()), null, null);
+            LIRDebugInfo addrInfo = stateFor(stateBeforeCallWithArguments(x.stateAfter(), callTarget, x.bci()), null, null, x.leafGraphId());
             destinationAddress = emitXir(snippet, x.node(), addrInfo, false);
         }
 
-        LIRDebugInfo callInfo = stateFor(x.stateDuring(), null, x instanceof InvokeWithExceptionNode ? getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge()) : null);
+        LIRDebugInfo callInfo = stateFor(x.stateDuring(), null, x instanceof InvokeWithExceptionNode ? getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge()) : null, x.leafGraphId());
         emitCall(targetMethod, resultOperand, argList, destinationAddress, callInfo, snippet.marks);
 
         if (isLegal(resultOperand)) {
@@ -985,7 +991,6 @@
         return argList;
     }
 
-
     protected abstract LabelRef createDeoptStub(DeoptAction action, LIRDebugInfo info, Object deoptInfo);
 
     @Override
@@ -1046,7 +1051,7 @@
             }
 
             // TODO is it correct here that the pointerSlots are not passed to the oop map generation?
-            info = stateFor(stateBeforeReturn);
+            info = stateFor(stateBeforeReturn, -1);
         }
 
         emitCall(x.call(), resultOperand, argList, CiConstant.forLong(0), info, null);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ConvertDeoptimizeToGuardPhase.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ConvertDeoptimizeToGuardPhase.java	Wed Mar 21 10:47:02 2012 +0100
@@ -79,7 +79,7 @@
             }
             BeginNode ifBlockBegin = findBeginNode(ifNode);
             Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s. IfBegin=%s", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin, ifBlockBegin);
-            FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode));
+            FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.leafGraphId()));
             otherBegin.replaceAtUsages(ifBlockBegin);
             FixedNode next = otherBegin.next();
             otherBegin.setNext(null);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java	Wed Mar 21 10:47:02 2012 +0100
@@ -59,8 +59,8 @@
             }
 
             @Override
-            public Node createGuard(Node condition) {
-                // TODO (thomaswue): Docuemnt why this must not be called on floating nodes.
+            public Node createGuard(Node condition, long leafGraphId) {
+                // TODO (thomaswue): Document why this must not be called on floating nodes.
                 throw new UnsupportedOperationException();
             }
         };
@@ -117,7 +117,7 @@
             }
 
             @Override
-            public Node createGuard(Node condition) {
+            public Node createGuard(Node condition, long leafGraphId) {
                 FixedNode guardAnchor = (FixedNode) getGuardAnchor();
                 if (GraalOptions.OptEliminateGuards) {
                     for (Node usage : condition.usages()) {
@@ -126,7 +126,7 @@
                         }
                     }
                 }
-                GuardNode newGuard = guardAnchor.graph().unique(new GuardNode((BooleanNode) condition, guardAnchor));
+                GuardNode newGuard = guardAnchor.graph().unique(new GuardNode((BooleanNode) condition, guardAnchor, leafGraphId));
                 activeGuards.grow();
                 activeGuards.mark(newGuard);
                 return newGuard;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java	Wed Mar 21 10:47:02 2012 +0100
@@ -498,16 +498,20 @@
         return result;
     }
 
-
     @Override
     public void emitDeoptimizeOn(Condition cond, DeoptAction action, Object deoptInfo) {
+        assert cond != null;
         LIRDebugInfo info = state();
         LabelRef stubEntry = createDeoptStub(action, info, deoptInfo);
-        if (cond != null) {
-            append(new BranchOp(cond, stubEntry, info));
-        } else {
-            append(new JumpOp(stubEntry, info));
-        }
+        append(new BranchOp(cond, stubEntry, info));
+    }
+
+
+    @Override
+    public void emitDeoptimize(DeoptAction action, Object deoptInfo, long leafGraphId) {
+        LIRDebugInfo info = state(leafGraphId);
+        LabelRef stubEntry = createDeoptStub(action, info, deoptInfo);
+        append(new JumpOp(stubEntry, info));
     }
 
     @Override
@@ -555,10 +559,10 @@
     }
 
     @Override
-    protected void emitNullCheckGuard(NullCheckNode node) {
+    protected void emitNullCheckGuard(NullCheckNode node, long leafGraphId) {
         assert !node.expectedNull;
         Variable value = load(operand(node.object()));
-        LIRDebugInfo info = state();
+        LIRDebugInfo info = state(leafGraphId);
         append(new NullCheckOp(value, info));
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Wed Mar 21 10:47:02 2012 +0100
@@ -176,7 +176,7 @@
             ValueNode receiver = invoke.callTarget().receiver();
             ReadHubNode objectClass = graph.add(new ReadHubNode(receiver));
             IsTypeNode isTypeNode = graph.unique(new IsTypeNode(objectClass, type));
-            FixedGuardNode guard = graph.add(new FixedGuardNode(isTypeNode));
+            FixedGuardNode guard = graph.add(new FixedGuardNode(isTypeNode, invoke.leafGraphId()));
             AnchorNode anchor = graph.add(new AnchorNode());
             assert invoke.predecessor() != null;
 
@@ -304,7 +304,7 @@
             if (shouldFallbackToInvoke()) {
                 unknownTypeNode = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, 1, notRecordedTypeProbability, false);
             } else {
-                unknownTypeNode = graph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile));
+                unknownTypeNode = graph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile, invoke.leafGraphId()));
             }
 
             // replace the invoke exception edge
@@ -369,7 +369,7 @@
             ReadHubNode objectClassNode = graph.add(new ReadHubNode(invoke.callTarget().receiver()));
             graph.addBeforeFixed(invoke.node(), objectClassNode);
 
-            FixedNode unknownTypeNode = graph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile));
+            FixedNode unknownTypeNode = graph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile, invoke.leafGraphId()));
             FixedNode dispatchOnType = createDispatchOnType(graph, objectClassNode, new BeginNode[] {calleeEntryNode}, unknownTypeNode);
 
             FixedWithNextNode pred = (FixedWithNextNode) invoke.node().predecessor();
@@ -812,7 +812,7 @@
         } else {
             if (unwindNode != null) {
                 UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
-                DeoptimizeNode deoptimizeNode = new DeoptimizeNode(DeoptAction.InvalidateRecompile);
+                DeoptimizeNode deoptimizeNode = new DeoptimizeNode(DeoptAction.InvalidateRecompile, invoke.leafGraphId());
                 unwindDuplicate.replaceAndDelete(graph.add(deoptimizeNode));
                 // move the deopt upwards if there is a monitor exit that tries to use the "after exception" frame state
                 // (because there is no "after exception" frame state!)
@@ -900,7 +900,7 @@
         NodeInputList<ValueNode> parameters = callTarget.arguments();
         ValueNode firstParam = parameters.size() <= 0 ? null : parameters.get(0);
         if (!callTarget.isStatic() && firstParam.kind() == CiKind.Object && !firstParam.stamp().nonNull()) {
-            graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new NullCheckNode(firstParam, false)))));
+            graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new NullCheckNode(firstParam, false)), invoke.leafGraphId())));
         }
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Wed Mar 21 10:47:02 2012 +0100
@@ -113,5 +113,7 @@
 
     int RiMethod_vtableEntryOffset(HotSpotMethodResolved method);
 
+    long[] getDeoptedLeafGraphIds();
+
     // Checkstyle: resume
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Wed Mar 21 10:47:02 2012 +0100
@@ -162,5 +162,8 @@
     @Override
     public native int RiMethod_vtableEntryOffset(HotSpotMethodResolved method);
 
+    @Override
+    public native long[] getDeoptedLeafGraphIds();
+
     // Checkstyle: resume
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Wed Mar 21 10:47:02 2012 +0100
@@ -218,7 +218,7 @@
 
         if (n instanceof ArrayLengthNode) {
             ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n;
-            SafeReadNode safeReadArrayLength = safeReadArrayLength(arrayLengthNode.graph(), arrayLengthNode.array(), arrayLengthNode.stamp());
+            SafeReadNode safeReadArrayLength = safeReadArrayLength(arrayLengthNode.graph(), arrayLengthNode.array(), arrayLengthNode.stamp(), StructuredGraph.INVALID_GRAPH_ID);
             graph.replaceFixedWithFixed(arrayLengthNode, safeReadArrayLength);
             safeReadArrayLength.lower(tool);
         } else if (n instanceof LoadFieldNode) {
@@ -229,7 +229,7 @@
             int displacement = ((HotSpotField) field.field()).offset();
             assert field.kind() != CiKind.Illegal;
             ReadNode memoryRead = graph.add(new ReadNode(field.object(), LocationNode.create(field.field(), field.field().kind(true), displacement, graph), field.stamp()));
-            memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(field.object(), false))));
+            memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(field.object(), false)), StructuredGraph.INVALID_GRAPH_ID));
             graph.replaceFixedWithFixed(field, memoryRead);
         } else if (n instanceof StoreFieldNode) {
             StoreFieldNode storeField = (StoreFieldNode) n;
@@ -238,7 +238,7 @@
             }
             HotSpotField field = (HotSpotField) storeField.field();
             WriteNode memoryWrite = graph.add(new WriteNode(storeField.object(), storeField.value(), LocationNode.create(storeField.field(), storeField.field().kind(true), field.offset(), graph)));
-            memoryWrite.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(storeField.object(), false))));
+            memoryWrite.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(storeField.object(), false)), StructuredGraph.INVALID_GRAPH_ID));
             memoryWrite.setStateAfter(storeField.stateAfter());
             graph.replaceFixedWithFixed(storeField, memoryWrite);
 
@@ -247,7 +247,7 @@
             }
         } else if (n instanceof LoadIndexedNode) {
             LoadIndexedNode loadIndexed = (LoadIndexedNode) n;
-            GuardNode boundsCheck = createBoundsCheck(loadIndexed, tool);
+            GuardNode boundsCheck = createBoundsCheck(loadIndexed, tool, loadIndexed.leafGraphId());
 
             CiKind elementKind = loadIndexed.elementKind();
             LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index());
@@ -256,7 +256,7 @@
             graph.replaceFixedWithFixed(loadIndexed, memoryRead);
         } else if (n instanceof StoreIndexedNode) {
             StoreIndexedNode storeIndexed = (StoreIndexedNode) n;
-            GuardNode boundsCheck = createBoundsCheck(storeIndexed, tool);
+            GuardNode boundsCheck = createBoundsCheck(storeIndexed, tool, storeIndexed.leafGraphId());
 
             CiKind elementKind = storeIndexed.elementKind();
             LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index());
@@ -277,7 +277,7 @@
                 } else {
                     AnchorNode anchor = graph.add(new AnchorNode());
                     graph.addBeforeFixed(storeIndexed, anchor);
-                    GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(array, false)));
+                    GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(array, false)), StructuredGraph.INVALID_GRAPH_ID);
                     ReadNode arrayClass = graph.add(new ReadNode(array, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph), StampFactory.objectNonNull()));
                     arrayClass.setGuard(guard);
                     graph.addBeforeFixed(storeIndexed, arrayClass);
@@ -300,7 +300,7 @@
             IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, load.loadKind(), load.displacement(), load.offset(), graph);
             location.setIndexScalingEnabled(false);
             ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp()));
-            memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(load.object(), false))));
+            memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(load.object(), false)), StructuredGraph.INVALID_GRAPH_ID));
             graph.replaceFixedWithFixed(load, memoryRead);
         } else if (n instanceof UnsafeStoreNode) {
             UnsafeStoreNode store = (UnsafeStoreNode) n;
@@ -318,7 +318,7 @@
             ReadHubNode objectClassNode = (ReadHubNode) n;
             LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph);
             ReadNode memoryRead = graph.add(new ReadNode(objectClassNode.object(), location, StampFactory.objectNonNull()));
-            memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(objectClassNode.object(), false))));
+            memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(objectClassNode.object(), false)), StructuredGraph.INVALID_GRAPH_ID));
             graph.replaceFixed(objectClassNode, memoryRead);
         }
     }
@@ -327,8 +327,8 @@
         return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, config.getArrayOffset(elementKind), index, graph);
     }
 
-    private static GuardNode createBoundsCheck(AccessIndexedNode n, CiLoweringTool tool) {
-        return (GuardNode) tool.createGuard(n.graph().unique(new CompareNode(n.index(), Condition.BT, n.length())));
+    private static GuardNode createBoundsCheck(AccessIndexedNode n, CiLoweringTool tool, long leafGraphId) {
+        return (GuardNode) tool.createGuard(n.graph().unique(new CompareNode(n.index(), Condition.BT, n.length())), leafGraphId);
     }
 
     @Override
@@ -348,7 +348,7 @@
                 }
                 StructuredGraph graph = new StructuredGraph();
                 LocalNode receiver = graph.unique(new LocalNode(CiKind.Object, 0));
-                SafeReadNode klassOop = safeReadHub(graph, receiver);
+                SafeReadNode klassOop = safeReadHub(graph, receiver, StructuredGraph.INVALID_GRAPH_ID);
                 ReadNode result = graph.add(new ReadNode(klassOop, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.classMirrorOffset, graph), StampFactory.objectNonNull()));
                 ReturnNode ret = graph.add(new ReturnNode(result));
                 graph.start().setNext(klassOop);
@@ -359,7 +359,7 @@
             if (fullName.equals("getModifiers()I")) {
                 StructuredGraph graph = new StructuredGraph();
                 LocalNode receiver = graph.unique(new LocalNode(CiKind.Object, 0));
-                SafeReadNode klassOop = safeRead(graph, CiKind.Object, receiver, config.klassOopOffset, StampFactory.objectNonNull());
+                SafeReadNode klassOop = safeRead(graph, CiKind.Object, receiver, config.klassOopOffset, StampFactory.objectNonNull(), StructuredGraph.INVALID_GRAPH_ID);
                 graph.start().setNext(klassOop);
                 // TODO(thomaswue): Care about primitive classes! Crashes for primitive classes at the moment (klassOop == null)
                 ReadNode result = graph.add(new ReadNode(klassOop, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Int, config.klassModifierFlagsOffset, graph), StampFactory.forKind(CiKind.Int)));
@@ -378,16 +378,16 @@
         return null;
     }
 
-    private SafeReadNode safeReadHub(Graph graph, ValueNode value) {
-        return safeRead(graph, CiKind.Object, value, config.hubOffset, StampFactory.objectNonNull());
+    private SafeReadNode safeReadHub(Graph graph, ValueNode value, long leafGraphId) {
+        return safeRead(graph, CiKind.Object, value, config.hubOffset, StampFactory.objectNonNull(), leafGraphId);
     }
 
-    private SafeReadNode safeReadArrayLength(Graph graph, ValueNode value, Stamp stamp) {
-        return safeRead(graph, CiKind.Int, value, config.arrayLengthOffset, stamp);
+    private SafeReadNode safeReadArrayLength(Graph graph, ValueNode value, Stamp stamp, long leafGraphId) {
+        return safeRead(graph, CiKind.Int, value, config.arrayLengthOffset, stamp, leafGraphId);
     }
 
-    private static SafeReadNode safeRead(Graph graph, CiKind kind, ValueNode value, int offset, Stamp stamp) {
-        return graph.add(new SafeReadNode(value, LocationNode.create(LocationNode.FINAL_LOCATION, kind, offset, graph), stamp));
+    private static SafeReadNode safeRead(Graph graph, CiKind kind, ValueNode value, int offset, Stamp stamp, long leafGraphId) {
+        return graph.add(new SafeReadNode(value, LocationNode.create(LocationNode.FINAL_LOCATION, kind, offset, graph), stamp, leafGraphId));
     }
 
     public RiResolvedType getType(Class<?> clazz) {
@@ -428,4 +428,9 @@
         plan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
         return compiler.getCompiler().compileMethod(method, graph, -1, plan);
     }
+
+    @Override
+    public long[] getDeoptedLeafGraphIds() {
+        return compiler.getVMEntries().getDeoptedLeafGraphIds();
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Mar 21 10:47:02 2012 +0100
@@ -27,6 +27,7 @@
 
 import java.lang.reflect.*;
 import java.util.*;
+import java.util.concurrent.atomic.*;
 
 
 import com.oracle.max.cri.ci.*;
@@ -89,10 +90,9 @@
 
     private BitSet canTrapBitSet;
 
-    public static final Map<RiMethod, StructuredGraph> cachedGraphs = new WeakHashMap<>();
-
     private final GraphBuilderConfiguration config;
 
+    private long graphId;
 
     /**
      * Node that marks the begin of block during bytecode parsing.  When a block is identified the first
@@ -120,6 +120,7 @@
     @Override
     protected void run(StructuredGraph graph) {
         method = graph.method();
+        graphId = graph.graphId();
         profilingInfo = method.profilingInfo();
         assert method.code() != null : "method must contain bytecodes: " + method;
         this.stream = new BytecodeStream(method.code());
@@ -201,10 +202,6 @@
                 n.safeDelete();
             }
         }
-
-        if (GraalOptions.CacheGraphs && !currentGraph.hasNode(DeoptimizeNode.class)) {
-            cachedGraphs.put(method, currentGraph.copy());
-        }
     }
 
     private Block unwindBlock(int bci) {
@@ -328,7 +325,7 @@
             if (riType instanceof RiResolvedType) {
                 frameState.push(CiKind.Object, append(ConstantNode.forCiConstant(((RiResolvedType) riType).getEncoding(Representation.JavaClass), runtime, currentGraph)));
             } else {
-                append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile)));
+                append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile, graphId)));
                 frameState.push(CiKind.Object, append(ConstantNode.forObject(null, runtime, currentGraph)));
             }
         } else if (con instanceof CiConstant) {
@@ -345,7 +342,7 @@
         ValueNode index = frameState.ipop();
         ValueNode array = frameState.apop();
         ValueNode length = append(currentGraph.add(new ArrayLengthNode(array)));
-        ValueNode v = append(currentGraph.add(new LoadIndexedNode(array, index, length, kind)));
+        ValueNode v = append(currentGraph.add(new LoadIndexedNode(array, index, length, kind, graphId)));
         frameState.push(kind.stackKind(), v);
     }
 
@@ -356,7 +353,7 @@
         ValueNode index = frameState.ipop();
         ValueNode array = frameState.apop();
         ValueNode length = append(currentGraph.add(new ArrayLengthNode(array)));
-        StoreIndexedNode result = currentGraph.add(new StoreIndexedNode(array, index, length, kind, value));
+        StoreIndexedNode result = currentGraph.add(new StoreIndexedNode(array, index, length, kind, value, graphId));
         append(result);
     }
 
@@ -587,7 +584,7 @@
 
     private void genThrow(int bci) {
         ValueNode exception = frameState.apop();
-        FixedGuardNode node = currentGraph.add(new FixedGuardNode(currentGraph.unique(new NullCheckNode(exception, false))));
+        FixedGuardNode node = currentGraph.add(new FixedGuardNode(currentGraph.unique(new NullCheckNode(exception, false)), graphId));
         append(node);
         append(handleException(exception, bci));
     }
@@ -679,7 +676,7 @@
             frameState.apush(checkCast);
         } else {
             ValueNode object = frameState.apop();
-            append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new CompareNode(object, Condition.EQ, ConstantNode.forObject(null, runtime, currentGraph))))));
+            append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new CompareNode(object, Condition.EQ, ConstantNode.forObject(null, runtime, currentGraph))), graphId)));
             frameState.apush(appendConstant(CiConstant.NULL_OBJECT));
         }
     }
@@ -697,7 +694,7 @@
             frameState.ipush(append(MaterializeNode.create(currentGraph.unique(instanceOfNode), currentGraph)));
         } else {
             BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode());
-            DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile));
+            DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile, graphId));
             IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new NullCheckNode(object, true)), trueSucc, deopt, 1));
             append(ifNode);
             lastInstr = trueSucc;
@@ -711,7 +708,7 @@
             NewInstanceNode n = currentGraph.add(new NewInstanceNode((RiResolvedType) type));
             frameState.apush(append(n));
         } else {
-            append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile)));
+            append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile, graphId)));
             frameState.apush(appendConstant(CiConstant.NULL_OBJECT));
         }
     }
@@ -752,7 +749,7 @@
             NewArrayNode n = currentGraph.add(new NewObjectArrayNode((RiResolvedType) type, length));
             frameState.apush(append(n));
         } else {
-            append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile)));
+            append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile, graphId)));
             frameState.apush(appendConstant(CiConstant.NULL_OBJECT));
         }
 
@@ -769,7 +766,7 @@
             FixedWithNextNode n = currentGraph.add(new NewMultiArrayNode((RiResolvedType) type, dims));
             frameState.apush(append(n));
         } else {
-            append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile)));
+            append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile, graphId)));
             frameState.apush(appendConstant(CiConstant.NULL_OBJECT));
         }
     }
@@ -783,7 +780,7 @@
             LoadFieldNode load = currentGraph.add(new LoadFieldNode(receiver, (RiResolvedField) field));
             appendOptimizedLoadField(kind, load);
         } else {
-            append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile)));
+            append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile, graphId)));
             frameState.push(kind.stackKind(), append(ConstantNode.defaultForKind(kind, currentGraph)));
         }
     }
@@ -884,7 +881,7 @@
             StoreFieldNode store = currentGraph.add(new StoreFieldNode(receiver, (RiResolvedField) field, value));
             appendOptimizedStoreField(store);
         } else {
-            append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile)));
+            append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile, graphId)));
         }
     }
 
@@ -926,7 +923,7 @@
         if (initialized) {
             return appendConstant(((RiResolvedType) holder).getEncoding(representation));
         } else {
-            append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile)));
+            append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile, graphId)));
             return null;
         }
     }
@@ -987,7 +984,7 @@
     }
 
     private void genInvokeDeopt(RiMethod unresolvedTarget, boolean withReceiver) {
-        append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile)));
+        append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile, graphId)));
         frameState.popArguments(unresolvedTarget.signature().argumentSlots(withReceiver), unresolvedTarget.signature().argumentCount(withReceiver));
         CiKind kind = unresolvedTarget.signature().returnKind(false);
         if (kind != CiKind.Void) {
@@ -1024,7 +1021,7 @@
     private void appendInvoke(InvokeKind invokeKind, RiResolvedMethod targetMethod, ValueNode[] args) {
         CiKind resultType = targetMethod.signature().returnKind(false);
         if (GraalOptions.DeoptALot) {
-            DeoptimizeNode deoptimize = currentGraph.add(new DeoptimizeNode(DeoptAction.None));
+            DeoptimizeNode deoptimize = currentGraph.add(new DeoptimizeNode(DeoptAction.None, StructuredGraph.INVALID_GRAPH_ID));
             deoptimize.setMessage("invoke " + targetMethod.name());
             append(deoptimize);
             frameState.pushReturn(resultType, ConstantNode.defaultForKind(resultType, currentGraph));
@@ -1033,7 +1030,7 @@
             BeginNode exceptionEdge = handleException(null, bci());
             ValueNode result;
             if (exceptionEdge != null) {
-                InvokeWithExceptionNode invoke = currentGraph.add(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci()));
+                InvokeWithExceptionNode invoke = currentGraph.add(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci(), graphId));
                 result = append(invoke);
                 frameState.pushReturn(resultType, result);
                 Block nextBlock = currentBlock.successors.get(0);
@@ -1044,7 +1041,7 @@
                 invoke.setNext(createTarget(nextBlock, frameState));
                 invoke.setStateAfter(frameState.create(nextBlock.startBci));
             } else {
-                result = appendWithBCI(currentGraph.add(new InvokeNode(callTarget, bci())));
+                result = appendWithBCI(currentGraph.add(new InvokeNode(callTarget, bci(), graphId)));
                 frameState.pushReturn(resultType, result);
             }
         }
@@ -1113,7 +1110,7 @@
         ValueNode local = frameState.loadLocal(localIndex);
         JsrScope scope = currentBlock.jsrScope;
         int retAddress = scope.nextReturnAddress();
-        append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new CompareNode(local, Condition.EQ, ConstantNode.forJsr(retAddress, currentGraph))))));
+        append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new CompareNode(local, Condition.EQ, ConstantNode.forJsr(retAddress, currentGraph))), graphId)));
         if (!successor.jsrScope.equals(scope.pop())) {
             throw new JsrNotSupportedBailout("unstructured control flow (ret leaves more than one scope)");
         }
@@ -1199,7 +1196,7 @@
     private FixedNode createTarget(double probability, Block block, FrameStateBuilder stateAfter) {
         assert probability >= 0 && probability <= 1;
         if (probability == 0 && config.useBranchPrediction()) {
-            return currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile));
+            return currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile, graphId));
         } else {
             return createTarget(block, stateAfter);
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/CiLoweringTool.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/CiLoweringTool.java	Wed Mar 21 10:47:02 2012 +0100
@@ -27,6 +27,6 @@
 public interface CiLoweringTool {
     GraalRuntime getRuntime();
     Node getGuardAnchor();
-    Node createGuard(Node condition);
+    Node createGuard(Node condition, long leafGraphId);
 }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/GraalRuntime.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/GraalRuntime.java	Wed Mar 21 10:47:02 2012 +0100
@@ -39,4 +39,6 @@
     StructuredGraph intrinsicGraph(RiResolvedMethod caller, int bci, RiResolvedMethod method, List<? extends Node> parameters);
 
     CiTargetMethod compile(RiResolvedMethod method, StructuredGraph graph);
+
+    long[] getDeoptedLeafGraphIds();
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Wed Mar 21 10:47:02 2012 +0100
@@ -39,14 +39,16 @@
 
     @Data private String message;
     @Data private final DeoptAction action;
+    private final long leafGraphId;
 
     public DeoptimizeNode() {
-        this(DeoptAction.InvalidateReprofile);
+        this(DeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID);
     }
 
-    public DeoptimizeNode(DeoptAction action) {
+    public DeoptimizeNode(DeoptAction action, long leafGraphId) {
         super(StampFactory.illegal());
         this.action = action;
+        this.leafGraphId = leafGraphId;
     }
 
     public void setMessage(String message) {
@@ -61,9 +63,13 @@
         return action;
     }
 
+    public long leafGraphId() {
+        return leafGraphId;
+    }
+
     @Override
     public void generate(LIRGeneratorTool gen) {
-        gen.emitDeoptimizeOn(null, action, message);
+        gen.emitDeoptimize(action, message, leafGraphId);
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Wed Mar 21 10:47:02 2012 +0100
@@ -31,16 +31,18 @@
 public final class FixedGuardNode extends FixedWithNextNode implements Simplifiable, Lowerable, LIRLowerable, Node.IterableNodeType {
 
     @Input private final NodeInputList<BooleanNode> conditions;
+    private final long leafGraphId;
 
-    public FixedGuardNode(BooleanNode condition) {
+    public FixedGuardNode(BooleanNode condition, long leafGraphId) {
         super(StampFactory.illegal());
+        this.leafGraphId = leafGraphId;
         this.conditions = new NodeInputList<>(this, new BooleanNode[] {condition});
     }
 
     @Override
     public void generate(LIRGeneratorTool gen) {
         for (BooleanNode condition : conditions()) {
-            gen.emitGuardCheck(condition);
+            gen.emitGuardCheck(condition, leafGraphId);
         }
     }
 
@@ -64,7 +66,7 @@
                     if (next != null) {
                         tool.deleteBranch(next);
                     }
-                    setNext(graph().add(new DeoptimizeNode(DeoptAction.InvalidateRecompile)));
+                    setNext(graph().add(new DeoptimizeNode(DeoptAction.InvalidateRecompile, leafGraphId)));
                     return;
                 }
             }
@@ -78,7 +80,7 @@
     public void lower(CiLoweringTool tool) {
         AnchorNode newAnchor = graph().add(new AnchorNode());
         for (BooleanNode b : conditions) {
-            newAnchor.addGuard((GuardNode) tool.createGuard(b));
+            newAnchor.addGuard((GuardNode) tool.createGuard(b, leafGraphId));
         }
         ((StructuredGraph) graph()).replaceFixedWithFixed(this, newAnchor);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Wed Mar 21 10:47:02 2012 +0100
@@ -32,6 +32,7 @@
 
     @Input private BooleanNode condition;
     @Input(notDataflow = true) private FixedNode anchor;
+    private final long leafGraphId;
 
     public FixedNode anchor() {
         return anchor;
@@ -54,15 +55,16 @@
         condition = x;
     }
 
-    public GuardNode(BooleanNode condition, FixedNode anchor) {
+    public GuardNode(BooleanNode condition, FixedNode anchor, long leafGraphId) {
         super(StampFactory.illegal());
         this.condition = condition;
         this.anchor = anchor;
+        this.leafGraphId = leafGraphId;
     }
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        gen.emitGuardCheck(condition());
+        gen.emitGuardCheck(condition(), leafGraphId);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java	Wed Mar 21 10:47:02 2012 +0100
@@ -58,4 +58,6 @@
     boolean megamorph();
 
     void setMegamorph(boolean megamorph);
+
+    long leafGraphId();
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Wed Mar 21 10:47:02 2012 +0100
@@ -41,6 +41,7 @@
     // megamorph should only be true when the compiler is sure that the call site is megamorph, and false when in doubt
     @Data private boolean megamorph;
     private boolean useForInlining;
+    private final long leafGraphId;
 
     /**
      * Constructs a new Invoke instruction.
@@ -50,10 +51,11 @@
      * @param target the target method being called
      * @param args the list of instructions producing arguments to the invocation, including the receiver object
      */
-    public InvokeNode(MethodCallTargetNode callTarget, int bci) {
+    public InvokeNode(MethodCallTargetNode callTarget, int bci, long leafGraphId) {
         super(callTarget.returnStamp());
         this.callTarget = callTarget;
         this.bci = bci;
+        this.leafGraphId = leafGraphId;
         this.megamorph = false;
         this.useForInlining = true;
     }
@@ -82,6 +84,11 @@
     }
 
     @Override
+    public long leafGraphId() {
+        return leafGraphId;
+    }
+
+    @Override
     public Map<Object, Object> getDebugProperties() {
         Map<Object, Object> debugProperties = super.getDebugProperties();
         if (callTarget != null && callTarget.targetMethod() != null) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Wed Mar 21 10:47:02 2012 +0100
@@ -41,16 +41,18 @@
     // megamorph should only be true when the compiler is sure that the call site is megamorph, and false when in doubt
     @Data private boolean megamorph;
     private boolean useForInlining;
+    private final long leafGraphId;
 
     /**
      * @param kind
      * @param blockSuccessors
      * @param branchProbability
      */
-    public InvokeWithExceptionNode(MethodCallTargetNode callTarget, BeginNode exceptionEdge, int bci) {
+    public InvokeWithExceptionNode(MethodCallTargetNode callTarget, BeginNode exceptionEdge, int bci, long leafGraphId) {
         super(callTarget.returnStamp(), new BeginNode[]{null, exceptionEdge}, new double[]{1.0, 0.0});
         this.bci = bci;
         this.callTarget = callTarget;
+        this.leafGraphId = leafGraphId;
         this.megamorph = true;
         this.useForInlining = true;
     }
@@ -96,6 +98,11 @@
     }
 
     @Override
+    public long leafGraphId() {
+        return leafGraphId;
+    }
+
+    @Override
     public String toString(Verbosity verbosity) {
         if (verbosity == Verbosity.Long) {
             return super.toString(Verbosity.Short) + "(bci=" + bci() + ")";
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Wed Mar 21 10:47:02 2012 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes;
 
 import java.util.*;
+import java.util.concurrent.atomic.*;
 
 import com.oracle.max.cri.ri.*;
 import com.oracle.graal.graph.*;
@@ -36,8 +37,19 @@
  * This node is the start of the control flow of the graph.
  */
 public class StructuredGraph extends Graph {
+
+    public static final long INVALID_GRAPH_ID = -1;
+    private static final AtomicLong uniqueGraphIds = new AtomicLong();
     private final BeginNode start;
     private final RiResolvedMethod method;
+    private final long graphId;
+
+    /**
+     * Creates a new Graph containing a single {@link BeginNode} as the {@link #start() start} node.
+     */
+    public StructuredGraph() {
+        this(null, null);
+    }
 
     /**
      * Creates a new Graph containing a single {@link BeginNode} as the {@link #start() start} node.
@@ -50,13 +62,7 @@
         super(name);
         this.start = add(new BeginNode());
         this.method = method;
-    }
-
-    /**
-     * Creates a new Graph containing a single {@link BeginNode} as the {@link #start() start} node.
-     */
-    public StructuredGraph() {
-        this((String) null);
+        this.graphId = uniqueGraphIds.incrementAndGet();
     }
 
     public StructuredGraph(RiResolvedMethod method) {
@@ -71,6 +77,10 @@
         return method;
     }
 
+    public long graphId() {
+        return graphId;
+    }
+
     @Override
     public StructuredGraph copy() {
         return copy(name);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Wed Mar 21 10:47:02 2012 +0100
@@ -57,7 +57,7 @@
     public void expand(BoxingMethodPool pool) {
         RiResolvedMethod boxingMethod = pool.getBoxingMethod(sourceKind);
         MethodCallTargetNode callTarget = graph().add(new MethodCallTargetNode(InvokeKind.Static, boxingMethod, new ValueNode[]{source}, boxingMethod.signature().returnType(boxingMethod.holder())));
-        InvokeNode invokeNode = graph().add(new InvokeNode(callTarget, bci));
+        InvokeNode invokeNode = graph().add(new InvokeNode(callTarget, bci, -1));
         invokeNode.setProbability(this.probability());
         invokeNode.setStateAfter(stateAfter());
         ((StructuredGraph) graph()).replaceFixedWithFixed(this, invokeNode);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeAccessNode.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeAccessNode.java	Wed Mar 21 10:47:02 2012 +0100
@@ -30,11 +30,13 @@
 
     @Input private ValueNode object;
     @Input private LocationNode location;
+    private final long leafGraphId;
 
-    public SafeAccessNode(ValueNode object, LocationNode location, Stamp stamp) {
+    public SafeAccessNode(ValueNode object, LocationNode location, Stamp stamp, long leafGraphId) {
         super(stamp);
         this.object = object;
         this.location = location;
+        this.leafGraphId = leafGraphId;
     }
 
     public ValueNode object() {
@@ -44,4 +46,8 @@
     public LocationNode location() {
         return location;
     }
+
+    public long leafGraphId() {
+        return leafGraphId;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java	Wed Mar 21 10:47:02 2012 +0100
@@ -31,15 +31,15 @@
 
 public class SafeReadNode extends SafeAccessNode implements Lowerable {
 
-    public SafeReadNode(ValueNode object, LocationNode location, Stamp stamp) {
-        super(object, location, stamp);
+    public SafeReadNode(ValueNode object, LocationNode location, Stamp stamp, long leafGraphId) {
+        super(object, location, stamp, leafGraphId);
         assert object != null && location != null;
     }
 
     @Override
     public void lower(CiLoweringTool tool) {
         StructuredGraph graph = (StructuredGraph) graph();
-        GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(object(), false)));
+        GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(object(), false)), StructuredGraph.INVALID_GRAPH_ID);
         ReadNode read = graph.add(new ReadNode(object(), location(), stamp()));
         read.setGuard(guard);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java	Wed Mar 21 10:47:02 2012 +0100
@@ -34,8 +34,8 @@
 
     @Input private ValueNode value;
 
-    public SafeWriteNode(ValueNode object, ValueNode value, LocationNode location) {
-        super(object, location, StampFactory.forKind(CiKind.Void));
+    public SafeWriteNode(ValueNode object, ValueNode value, LocationNode location, long leafGraphId) {
+        super(object, location, StampFactory.forKind(CiKind.Void), leafGraphId);
         this.value = value;
     }
 
@@ -46,7 +46,7 @@
     @Override
     public void lower(CiLoweringTool tool) {
         StructuredGraph graph = (StructuredGraph) graph();
-        GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(object(), false)));
+        GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(object(), false)), StructuredGraph.INVALID_GRAPH_ID);
         WriteNode write = graph.add(new WriteNode(object(), value(), location()));
         write.setGuard(guard);
         graph.replaceFixedWithFixed(this, write);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Wed Mar 21 10:47:02 2012 +0100
@@ -46,6 +46,7 @@
     }
 
     private final CiKind elementType;
+    private final long leafGraphId;
 
     /**
      * Create an new AccessIndexedNode.
@@ -55,11 +56,12 @@
      * @param length the instruction producing the length
      * @param elementKind the type of the elements of the array
      */
-    protected AccessIndexedNode(Stamp stamp, ValueNode array, ValueNode index, ValueNode length, CiKind elementKind) {
+    protected AccessIndexedNode(Stamp stamp, ValueNode array, ValueNode index, ValueNode length, CiKind elementKind, long leafGraphId) {
         super(stamp, array);
         this.index = index;
         this.length = length;
         this.elementType = elementKind;
+        this.leafGraphId = leafGraphId;
     }
 
     /**
@@ -70,6 +72,10 @@
         return elementType;
     }
 
+    public long leafGraphId() {
+        return leafGraphId;
+    }
+
     @Override
     public void typeFeedback(TypeFeedbackTool tool) {
         tool.addScalar(index()).constantBound(Condition.GE, CiConstant.INT_0);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Wed Mar 21 10:47:02 2012 +0100
@@ -41,8 +41,8 @@
      * @param length the instruction producing the length
      * @param elementKind the element type
      */
-    public LoadIndexedNode(ValueNode array, ValueNode index, ValueNode length, CiKind elementKind) {
-        super(createStamp(array, elementKind), array, index, length, elementKind);
+    public LoadIndexedNode(ValueNode array, ValueNode index, ValueNode length, CiKind elementKind, long leafGraphId) {
+        super(createStamp(array, elementKind), array, index, length, elementKind, leafGraphId);
     }
 
     private static Stamp createStamp(ValueNode array, CiKind kind) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Wed Mar 21 10:47:02 2012 +0100
@@ -47,8 +47,8 @@
      * @param elementKind the element type
      * @param value the value to store into the array
      */
-    public StoreIndexedNode(ValueNode array, ValueNode index, ValueNode length, CiKind elementKind, ValueNode value) {
-        super(StampFactory.illegal(), array, index, length, elementKind);
+    public StoreIndexedNode(ValueNode array, ValueNode index, ValueNode length, CiKind elementKind, ValueNode value, long leafGraphId) {
+        super(StampFactory.illegal(), array, index, length, elementKind, leafGraphId);
         this.value = value;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Wed Mar 21 10:47:02 2012 +0100
@@ -79,12 +79,13 @@
 
     public abstract CiValue emitConvert(ConvertNode.Op opcode, CiValue inputVal);
     public abstract void emitMembar(int barriers);
-    public abstract void emitDeoptimizeOn(Condition of, DeoptAction action, Object deoptInfo);
+    public abstract void emitDeoptimizeOn(Condition cond, DeoptAction action, Object deoptInfo);
+    public abstract void emitDeoptimize(DeoptAction action, Object deoptInfo, long leafGraphId);
     public abstract CiValue emitCallToRuntime(CiRuntimeCall runtimeCall, boolean canTrap, CiValue... args);
 
     public abstract void emitIf(IfNode i);
     public abstract void emitConditional(ConditionalNode i);
-    public abstract void emitGuardCheck(BooleanNode comp);
+    public abstract void emitGuardCheck(BooleanNode comp, long leafGraphId);
 
     public abstract void emitLookupSwitch(LookupSwitchNode i);
     public abstract void emitTableSwitch(TableSwitchNode i);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/types/ObjectTypeFeedbackStore.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/types/ObjectTypeFeedbackStore.java	Wed Mar 21 10:47:02 2012 +0100
@@ -114,8 +114,17 @@
         }
 
         @Override
-        public boolean notExactType(RiResolvedType type) {
-            return false;
+        public boolean notExactType(final RiResolvedType type) {
+            return store.prove(Info.class, new BooleanPredicate<Info>() {
+                @Override
+                public boolean evaluate(Info element) {
+                    if (element instanceof ObjectTypeExact) {
+                        return ((ObjectTypeExact) element).type != type;
+                    } else {
+                        return (element instanceof Equals) && ((Equals) element).constant.isNull();
+                    }
+                }
+            });
         }
 
         @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/types/ScalarTypeFeedbackStore.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/types/ScalarTypeFeedbackStore.java	Wed Mar 21 10:47:02 2012 +0100
@@ -24,10 +24,10 @@
 
 import java.util.*;
 
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.max.cri.ci.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
 
 public class ScalarTypeFeedbackStore extends TypeFeedbackStore<ScalarTypeFeedbackStore> implements ScalarTypeFeedbackTool, CloneableTypeFeedback {
 
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiCodePos.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiCodePos.java	Wed Mar 21 10:47:02 2012 +0100
@@ -32,10 +32,8 @@
  * can be used by the runtime system to reconstruct a source-level stack trace
  * for exceptions and to create {@linkplain CiFrame frames} for deoptimization.
  */
-public class CiCodePos implements Serializable {
-    /**
-     * 
-     */
+public abstract class CiCodePos implements Serializable {
+
     private static final long serialVersionUID = 8633885274526033515L;
 
     /**
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiFrame.java	Fri Mar 16 11:03:54 2012 +0100
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiFrame.java	Wed Mar 21 10:47:02 2012 +0100
@@ -65,6 +65,8 @@
      */
     public final int numLocks;
 
+    public final long leafGraphId;
+
     public final boolean rethrowException;
 
     public final boolean duringCall;
@@ -81,15 +83,16 @@
      * @param numStack the depth of the stack
      * @param numLocks the number of locked objects
      */
-    public CiFrame(CiFrame caller, RiResolvedMethod method, int bci, boolean rethrowException, boolean duringCall, CiValue[] values, int numLocals, int numStack, int numLocks) {
+    public CiFrame(CiFrame caller, RiResolvedMethod method, int bci, boolean rethrowException, boolean duringCall, CiValue[] values, int numLocals, int numStack, int numLocks, long leafGraphId) {
         super(caller, method, bci);
         assert values != null;
         this.rethrowException = rethrowException;
+        this.duringCall = duringCall;
         this.values = values;
-        this.numLocks = numLocks;
         this.numLocals = numLocals;
         this.numStack = numStack;
-        this.duringCall = duringCall;
+        this.numLocks = numLocks;
+        this.leafGraphId = leafGraphId;
         assert !rethrowException || numStack == 1 : "must have exception on top of the stack";
     }
 
--- a/src/share/vm/c1/c1_IR.cpp	Fri Mar 16 11:03:54 2012 +0100
+++ b/src/share/vm/c1/c1_IR.cpp	Wed Mar 21 10:47:02 2012 +0100
@@ -210,7 +210,7 @@
 
 void CodeEmitInfo::record_debug_info(DebugInformationRecorder* recorder, int pc_offset) {
   // record the safepoint before recording the debug info for enclosing scopes
-  recorder->add_safepoint(pc_offset, _oop_map->deep_copy());
+  recorder->add_safepoint(pc_offset, -1, _oop_map->deep_copy());
   _scope_debug_info->record_debug_info(recorder, pc_offset, true/*topmost*/, _is_method_handle_invoke);
   recorder->end_safepoint(pc_offset);
 }
--- a/src/share/vm/code/debugInfoRec.cpp	Fri Mar 16 11:03:54 2012 +0100
+++ b/src/share/vm/code/debugInfoRec.cpp	Wed Mar 21 10:47:02 2012 +0100
@@ -127,14 +127,14 @@
   _oopmaps->add_gc_map(pc_offset, map);
 }
 
-void DebugInformationRecorder::add_safepoint(int pc_offset, OopMap* map) {
+void DebugInformationRecorder::add_safepoint(int pc_offset, jlong leaf_graph_id, OopMap* map) {
   assert(!_oop_recorder->is_complete(), "not frozen yet");
   // Store the new safepoint
 
   // Add the oop map
   add_oopmap(pc_offset, map);
 
-  add_new_pc_offset(pc_offset);
+  add_new_pc_offset(pc_offset, leaf_graph_id);
 
   assert(_recording_state == rs_null, "nesting of recording calls");
   debug_only(_recording_state = rs_safepoint);
@@ -150,7 +150,7 @@
   debug_only(_recording_state = rs_non_safepoint);
 }
 
-void DebugInformationRecorder::add_new_pc_offset(int pc_offset) {
+void DebugInformationRecorder::add_new_pc_offset(int pc_offset, jlong leaf_graph_id) {
   assert(_pcs_length == 0 || last_pc()->pc_offset() < pc_offset,
          "must specify a new, larger pc offset");
 
@@ -168,7 +168,7 @@
   assert(_pcs_size > _pcs_length, "There must be room for after expanding");
 
   _pcs[_pcs_length++] = PcDesc(pc_offset, DebugInformationRecorder::serialized_null,
-                               DebugInformationRecorder::serialized_null);
+                               DebugInformationRecorder::serialized_null, leaf_graph_id);
 }
 
 
--- a/src/share/vm/code/debugInfoRec.hpp	Fri Mar 16 11:03:54 2012 +0100
+++ b/src/share/vm/code/debugInfoRec.hpp	Wed Mar 21 10:47:02 2012 +0100
@@ -82,7 +82,7 @@
   void add_oopmap(int pc_offset, OopMap* map);
 
   // adds a jvm mapping at pc-offset, for a safepoint only
-  void add_safepoint(int pc_offset, OopMap* map);
+  void add_safepoint(int pc_offset, jlong leaf_graph_id, OopMap* map);
 
   // adds a jvm mapping at pc-offset, for a non-safepoint (profile point)
   void add_non_safepoint(int pc_offset);
@@ -188,7 +188,7 @@
     guarantee(_pcs_length > 1, "a safepoint must be declared already");
     return &_pcs[_pcs_length-2];
   }
-  void add_new_pc_offset(int pc_offset);
+  void add_new_pc_offset(int pc_offset, jlong leaf_graph_id = -1);
   void end_scopes(int pc_offset, bool is_safepoint);
 
   int  serialize_monitor_values(GrowableArray<MonitorValue*>* monitors);
--- a/src/share/vm/code/pcDesc.cpp	Fri Mar 16 11:03:54 2012 +0100
+++ b/src/share/vm/code/pcDesc.cpp	Wed Mar 21 10:47:02 2012 +0100
@@ -29,11 +29,12 @@
 #include "code/scopeDesc.hpp"
 #include "memory/resourceArea.hpp"
 
-PcDesc::PcDesc(int pc_offset, int scope_decode_offset, int obj_decode_offset) {
+PcDesc::PcDesc(int pc_offset, int scope_decode_offset, int obj_decode_offset, jlong leaf_graph_id) {
   _pc_offset           = pc_offset;
   _scope_decode_offset = scope_decode_offset;
   _obj_decode_offset   = obj_decode_offset;
   _flags               = 0;
+  GRAAL_ONLY(_leaf_graph_id = leaf_graph_id);
 }
 
 address PcDesc::real_pc(const nmethod* code) const {
@@ -43,7 +44,11 @@
 void PcDesc::print(nmethod* code) {
 #ifndef PRODUCT
   ResourceMark rm;
+#ifdef GRAAL
+  tty->print_cr("PcDesc(pc=0x%lx offset=%x bits=%x leaf_graph_id=%d):", real_pc(code), pc_offset(), _flags, leaf_graph_id());
+#else
   tty->print_cr("PcDesc(pc=0x%lx offset=%x bits=%x):", real_pc(code), pc_offset(), _flags);
+#endif
 
   if (scope_decode_offset() == DebugInformationRecorder::serialized_null) {
     return;
--- a/src/share/vm/code/pcDesc.hpp	Fri Mar 16 11:03:54 2012 +0100
+++ b/src/share/vm/code/pcDesc.hpp	Wed Mar 21 10:47:02 2012 +0100
@@ -38,6 +38,7 @@
   int _pc_offset;           // offset from start of nmethod
   int _scope_decode_offset; // offset for scope in nmethod
   int _obj_decode_offset;
+  GRAAL_ONLY(jlong _leaf_graph_id;)
 
   enum {
     PCDESC_reexecute               = 1 << 0,
@@ -56,14 +57,16 @@
   int pc_offset() const           { return _pc_offset;   }
   int scope_decode_offset() const { return _scope_decode_offset; }
   int obj_decode_offset() const   { return _obj_decode_offset; }
+  jlong leaf_graph_id() const     { return _leaf_graph_id; }
 
   void set_pc_offset(int x)           { _pc_offset           = x; }
   void set_scope_decode_offset(int x) { _scope_decode_offset = x; }
   void set_obj_decode_offset(int x)   { _obj_decode_offset   = x; }
+  void set_leaf_graph_id(jlong x)     { _leaf_graph_id = x; }
 
   // Constructor (only used for static in nmethod.cpp)
   // Also used by ScopeDesc::sender()]
-  PcDesc(int pc_offset, int scope_decode_offset, int obj_decode_offset);
+  PcDesc(int pc_offset, int scope_decode_offset, int obj_decode_offset, jlong leaf_graph_id);
 
   enum {
     // upper and lower exclusive limits real offsets:
@@ -81,7 +84,9 @@
   bool is_same_info(const PcDesc* pd) {
     return _scope_decode_offset == pd->_scope_decode_offset &&
       _obj_decode_offset == pd->_obj_decode_offset &&
-      _flags == pd->_flags;
+      _flags == pd->_flags
+      GRAAL_ONLY(&& _leaf_graph_id == pd->_leaf_graph_id)
+      ;
   }
 
   bool     is_method_handle_invoke()       const { return (_flags & PCDESC_is_method_handle_invoke) != 0;     }
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Fri Mar 16 11:03:54 2012 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Wed Mar 21 10:47:02 2012 +0100
@@ -428,19 +428,16 @@
   }
 }
 
-void CodeInstaller::record_scope(jint pc_offset, oop code_pos, GrowableArray<ScopeValue*>* objects) {
-  oop caller_pos = CiCodePos::caller(code_pos);
-  if (caller_pos != NULL) {
-    record_scope(pc_offset, caller_pos, objects);
-  }
-  oop frame = NULL;
-  if (code_pos->klass()->klass_part()->name() == vmSymbols::com_oracle_max_cri_ci_CiFrame()) {
-    frame = code_pos;
+void CodeInstaller::record_scope(jint pc_offset, oop frame, GrowableArray<ScopeValue*>* objects) {
+  assert(frame->klass() == CiFrame::klass(), "CiFrame expected");
+  oop caller_frame = CiCodePos::caller(frame);
+  if (caller_frame != NULL) {
+    record_scope(pc_offset, caller_frame, objects);
   }
 
-  oop hotspot_method = CiCodePos::method(code_pos);
+  oop hotspot_method = CiCodePos::method(frame);
   methodOop method = getMethodFromHotSpotMethod(hotspot_method);
-  jint bci = CiCodePos::bci(code_pos);
+  jint bci = CiCodePos::bci(frame);
   bool reexecute;
   if (bci == -1) {
      reexecute = false;
@@ -456,64 +453,60 @@
     tty->print_cr("Recording scope pc_offset=%d bci=%d frame=%d", pc_offset, bci, frame);
   }
 
-  if (frame != NULL) {
-    jint local_count = CiFrame::numLocals(frame);
-    jint expression_count = CiFrame::numStack(frame);
-    jint monitor_count = CiFrame::numLocks(frame);
-    arrayOop values = (arrayOop) CiFrame::values(frame);
+  jint local_count = CiFrame::numLocals(frame);
+  jint expression_count = CiFrame::numStack(frame);
+  jint monitor_count = CiFrame::numLocks(frame);
+  arrayOop values = (arrayOop) CiFrame::values(frame);
 
-    assert(local_count + expression_count + monitor_count == values->length(), "unexpected values length");
+  assert(local_count + expression_count + monitor_count == values->length(), "unexpected values length");
 
-    GrowableArray<ScopeValue*>* locals = new GrowableArray<ScopeValue*> ();
-    GrowableArray<ScopeValue*>* expressions = new GrowableArray<ScopeValue*> ();
-    GrowableArray<MonitorValue*>* monitors = new GrowableArray<MonitorValue*> ();
+  GrowableArray<ScopeValue*>* locals = new GrowableArray<ScopeValue*> ();
+  GrowableArray<ScopeValue*>* expressions = new GrowableArray<ScopeValue*> ();
+  GrowableArray<MonitorValue*>* monitors = new GrowableArray<MonitorValue*> ();
 
-    if (TraceGraal >= 2) {
-      tty->print_cr("Scope at bci %d with %d values", bci, values->length());
-      tty->print_cr("%d locals %d expressions, %d monitors", local_count, expression_count, monitor_count);
-    }
+  if (TraceGraal >= 2) {
+    tty->print_cr("Scope at bci %d with %d values", bci, values->length());
+    tty->print_cr("%d locals %d expressions, %d monitors", local_count, expression_count, monitor_count);
+  }
 
-    for (jint i = 0; i < values->length(); i++) {
-      ScopeValue* second = NULL;
-      oop value = ((oop*) values->base(T_OBJECT))[i];
+  for (jint i = 0; i < values->length(); i++) {
+    ScopeValue* second = NULL;
+    oop value = ((oop*) values->base(T_OBJECT))[i];
 
-      if (i < local_count) {
-        ScopeValue* first = get_hotspot_value(value, _total_frame_size, objects, second);
-        if (second != NULL) {
-          locals->append(second);
-        }
-        locals->append(first);
-      } else if (i < local_count + expression_count) {
-        ScopeValue* first = get_hotspot_value(value, _total_frame_size, objects, second);
-        if (second != NULL) {
-          expressions->append(second);
-        }
-        expressions->append(first);
-      } else {
-        monitors->append(get_monitor_value(value, _total_frame_size, objects));
+    if (i < local_count) {
+      ScopeValue* first = get_hotspot_value(value, _total_frame_size, objects, second);
+      if (second != NULL) {
+        locals->append(second);
       }
+      locals->append(first);
+    } else if (i < local_count + expression_count) {
+      ScopeValue* first = get_hotspot_value(value, _total_frame_size, objects, second);
       if (second != NULL) {
-        i++;
-        assert(i < values->length(), "double-slot value not followed by CiValue.IllegalValue");
-        assert(((oop*) values->base(T_OBJECT))[i] == CiValue::IllegalValue(), "double-slot value not followed by CiValue.IllegalValue");
+        expressions->append(second);
       }
+      expressions->append(first);
+    } else {
+      monitors->append(get_monitor_value(value, _total_frame_size, objects));
     }
-
-    _debug_recorder->dump_object_pool(objects);
+    if (second != NULL) {
+      i++;
+      assert(i < values->length(), "double-slot value not followed by CiValue.IllegalValue");
+      assert(((oop*) values->base(T_OBJECT))[i] == CiValue::IllegalValue(), "double-slot value not followed by CiValue.IllegalValue");
+    }
+  }
 
-    DebugToken* locals_token = _debug_recorder->create_scope_values(locals);
-    DebugToken* expressions_token = _debug_recorder->create_scope_values(expressions);
-    DebugToken* monitors_token = _debug_recorder->create_monitor_values(monitors);
+  _debug_recorder->dump_object_pool(objects);
+
+  DebugToken* locals_token = _debug_recorder->create_scope_values(locals);
+  DebugToken* expressions_token = _debug_recorder->create_scope_values(expressions);
+  DebugToken* monitors_token = _debug_recorder->create_monitor_values(monitors);
 
-    bool throw_exception = false;
-    if (CiFrame::rethrowException(frame)) {
-      throw_exception = true;
-    }
+  bool throw_exception = false;
+  if (CiFrame::rethrowException(frame)) {
+    throw_exception = true;
+  }
 
-    _debug_recorder->describe_scope(pc_offset, method, NULL, bci, reexecute, throw_exception, false, false, locals_token, expressions_token, monitors_token);
-  } else {
-    _debug_recorder->describe_scope(pc_offset, method, NULL, bci, reexecute, false, false, false, NULL, NULL, NULL);
-  }
+  _debug_recorder->describe_scope(pc_offset, method, NULL, bci, reexecute, throw_exception, false, false, locals_token, expressions_token, monitors_token);
 }
 
 void CodeInstaller::site_Safepoint(CodeBuffer& buffer, jint pc_offset, oop site) {
@@ -522,7 +515,7 @@
 
   // address instruction = _instructions->start() + pc_offset;
   // jint next_pc_offset = Assembler::locate_next_instruction(instruction) - _instructions->start();
-  _debug_recorder->add_safepoint(pc_offset, create_oop_map(_total_frame_size, _parameter_count, debug_info));
+  _debug_recorder->add_safepoint(pc_offset, -1, create_oop_map(_total_frame_size, _parameter_count, debug_info));
 
   oop code_pos = CiDebugInfo::codePos(debug_info);
   record_scope(pc_offset, code_pos, new GrowableArray<ScopeValue*>());
@@ -636,9 +629,9 @@
   }
 
   if (debug_info != NULL) {
-    _debug_recorder->add_safepoint(next_pc_offset, create_oop_map(_total_frame_size, _parameter_count, debug_info));
-    oop code_pos = CiDebugInfo::codePos(debug_info);
-    record_scope(next_pc_offset, code_pos, new GrowableArray<ScopeValue*>());
+    oop frame = CiDebugInfo::codePos(debug_info);
+    _debug_recorder->add_safepoint(next_pc_offset, CiFrame::leafGraphId(frame), create_oop_map(_total_frame_size, _parameter_count, debug_info));
+    record_scope(next_pc_offset, frame, new GrowableArray<ScopeValue*>());
   }
 
   if (runtime_call != NULL) {
--- a/src/share/vm/graal/graalCompiler.cpp	Fri Mar 16 11:03:54 2012 +0100
+++ b/src/share/vm/graal/graalCompiler.cpp	Wed Mar 21 10:47:02 2012 +0100
@@ -47,6 +47,8 @@
   JavaThread* THREAD = JavaThread::current();
   TRACE_graal_1("GraalCompiler::initialize");
 
+  _deopted_leaf_graph_count = 0;
+
   initialize_buffer_blob();
   Runtime1::initialize(THREAD->get_buffer_blob());
 
@@ -91,6 +93,47 @@
   }
 }
 
+void GraalCompiler::deopt_leaf_graph(jlong leaf_graph_id) {
+  assert(leaf_graph_id != -1, "unexpected leaf graph id");
+
+  if (_deopted_leaf_graph_count < LEAF_GRAPH_ARRAY_SIZE) {
+    MutexLockerEx y(GraalDeoptLeafGraphIds_lock, Mutex::_no_safepoint_check_flag);
+    if (_deopted_leaf_graph_count < LEAF_GRAPH_ARRAY_SIZE) {
+      _deopted_leaf_graphs[_deopted_leaf_graph_count++] = leaf_graph_id;
+    }
+  }
+}
+
+oop GraalCompiler::dump_deopted_leaf_graphs(TRAPS) {
+  if (_deopted_leaf_graph_count == 0) {
+    return NULL;
+  }
+  jlong* elements;
+  int length;
+  {
+    MutexLockerEx y(GraalDeoptLeafGraphIds_lock, Mutex::_no_safepoint_check_flag);
+    if (_deopted_leaf_graph_count == 0) {
+      return NULL;
+    }
+    if (_deopted_leaf_graph_count == LEAF_GRAPH_ARRAY_SIZE) {
+      length = 0;
+    } else {
+      length = _deopted_leaf_graph_count;
+    }
+    elements = new jlong[length];
+    for (int i = 0; i < length; i++) {
+      elements[i] = _deopted_leaf_graphs[i];
+    }
+    _deopted_leaf_graph_count = 0;
+  }
+  typeArrayOop array = oopFactory::new_longArray(length, CHECK_NULL);
+  for (int i = 0; i < length; i++) {
+    array->long_at_put(i, elements[i]);
+  }
+  delete elements;
+  return array;
+}
+
 void GraalCompiler::initialize_buffer_blob() {
 
   JavaThread* THREAD = JavaThread::current();
--- a/src/share/vm/graal/graalCompiler.hpp	Fri Mar 16 11:03:54 2012 +0100
+++ b/src/share/vm/graal/graalCompiler.hpp	Wed Mar 21 10:47:02 2012 +0100
@@ -23,13 +23,18 @@
 
 #include "compiler/abstractCompiler.hpp"
 
+#define LEAF_GRAPH_ARRAY_SIZE (8192)
+
 class GraalCompiler : public AbstractCompiler {
 
 private:
 
   bool                  _initialized;
 
-  static GraalCompiler*   _instance;
+  static GraalCompiler* _instance;
+
+  jlong                 _deopted_leaf_graphs[LEAF_GRAPH_ARRAY_SIZE];
+  int                   _deopted_leaf_graph_count;
 
 public:
 
@@ -56,6 +61,9 @@
 
   void compile_method(methodHandle target, int entry_bci, jboolean blocking);
 
+  void deopt_leaf_graph(jlong leaf_graph_id);
+  oop dump_deopted_leaf_graphs(TRAPS);
+
   // Print compilation timers and statistics
   virtual void print_timers();
   
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Fri Mar 16 11:03:54 2012 +0100
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Wed Mar 21 10:47:02 2012 +0100
@@ -966,6 +966,21 @@
   return vtable_entry_offset;
 }
 
+// public native long[] getDeoptedLeafGraphIds();
+JNIEXPORT jobject JNICALL Java_com_oracle_graal_hotspot_bridge_CompilerToVMImpl_getDeoptedLeafGraphIds(JNIEnv *, jobject) {
+  TRACE_graal_3("CompilerToVM::getDeoptedLeafGraphIds");
+
+  VM_ENTRY_MARK;
+
+  // the contract for this method is as follows:
+  // returning null: no deopted leaf graphs
+  // returning array (size > 0): the ids of the deopted leaf graphs
+  // returning array (size == 0): there was an overflow, the compiler needs to clear its cache completely
+
+  oop array = GraalCompiler::instance()->dump_deopted_leaf_graphs(CHECK_NULL);
+  return JNIHandles::make_local(array);
+}
+
 
 #define CC (char*)  /*cast a literal from (const char*)*/
 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(Java_com_oracle_graal_hotspot_bridge_CompilerToVMImpl_##f))
@@ -1029,6 +1044,7 @@
   {CC"disassembleJava",                   CC"("RESOLVED_METHOD")"STRING,                        FN_PTR(disassembleJava)},
   {CC"executeCompiledMethod",             CC"("HS_COMP_METHOD OBJECT OBJECT OBJECT")"OBJECT,    FN_PTR(executeCompiledMethod)},
   {CC"RiMethod_vtableEntryOffset",        CC"("RESOLVED_METHOD")I",                             FN_PTR(RiMethod_vtableEntryOffset)},
+  {CC"getDeoptedLeafGraphIds",            CC"()[J",                                             FN_PTR(getDeoptedLeafGraphIds)},
 };
 
 int CompilerToVM_methods_count() {
--- a/src/share/vm/graal/graalJavaAccess.hpp	Fri Mar 16 11:03:54 2012 +0100
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Wed Mar 21 10:47:02 2012 +0100
@@ -163,6 +163,7 @@
     int_field(CiFrame, numLocals)                                                       \
     int_field(CiFrame, numStack)                                                        \
     int_field(CiFrame, numLocks)                                                        \
+    long_field(CiFrame, leafGraphId)                                                    \
     boolean_field(CiFrame, rethrowException)                                            \
     boolean_field(CiFrame, duringCall)                                                  \
   end_class                                                                             \
--- a/src/share/vm/runtime/deoptimization.cpp	Fri Mar 16 11:03:54 2012 +0100
+++ b/src/share/vm/runtime/deoptimization.cpp	Wed Mar 21 10:47:02 2012 +0100
@@ -86,6 +86,11 @@
 #endif
 #endif
 
+#ifdef GRAAL
+#include "graal/graalCompiler.hpp"
+#endif
+
+
 bool DeoptimizationMarker::_is_active = false;
 
 Deoptimization::UnrollBlock::UnrollBlock(int  size_of_deoptimized_frame,
@@ -201,6 +206,19 @@
   // Create a growable array of VFrames where each VFrame represents an inlined
   // Java frame.  This storage is allocated with the usual system arena.
   assert(deoptee.is_compiled_frame(), "Wrong frame type");
+
+#ifdef GRAAL
+  PcDesc* pc_desc = ((nmethod*) deoptee.cb())->pc_desc_at(deoptee.pc());
+  int decode_offset;
+  if (pc_desc != NULL && pc_desc->leaf_graph_id() != -1) {
+    GraalCompiler* compiler = (GraalCompiler*) ((nmethod*) deoptee.cb())->compiler();
+    if (PrintDeoptimizationDetails) {
+      tty->print_cr("leaf graph id: %d", pc_desc->leaf_graph_id());
+    }
+    compiler->deopt_leaf_graph(pc_desc->leaf_graph_id());
+  }
+#endif
+
   GrowableArray<compiledVFrame*>* chunk = new GrowableArray<compiledVFrame*>(10);
   vframe* vf = vframe::new_vframe(&deoptee, &map, thread);
   while (!vf->is_top()) {
--- a/src/share/vm/runtime/mutexLocker.cpp	Fri Mar 16 11:03:54 2012 +0100
+++ b/src/share/vm/runtime/mutexLocker.cpp	Wed Mar 21 10:47:02 2012 +0100
@@ -141,6 +141,10 @@
 Mutex*   JfrBuffer_lock               = NULL;
 Mutex*   JfrStream_lock               = NULL;
 
+#ifdef GRAAL
+Mutex*   GraalDeoptLeafGraphIds_lock  = NULL;
+#endif // GRAAL
+
 #define MAX_NUM_MUTEX 128
 static Monitor * _mutex_array[MAX_NUM_MUTEX];
 static int _num_mutex;
@@ -285,6 +289,10 @@
   def(JfrMsg_lock                  , Monitor, nonleaf+2,   true);
   def(JfrBuffer_lock               , Mutex,   nonleaf+3,   true);
   def(JfrStream_lock               , Mutex,   nonleaf+4,   true);
+
+#ifdef GRAAL
+  def(GraalDeoptLeafGraphIds_lock  , Mutex,   special,   true);
+#endif // GRAAL
 }
 
 GCMutexLocker::GCMutexLocker(Monitor * mutex) {
--- a/src/share/vm/runtime/mutexLocker.hpp	Fri Mar 16 11:03:54 2012 +0100
+++ b/src/share/vm/runtime/mutexLocker.hpp	Wed Mar 21 10:47:02 2012 +0100
@@ -143,6 +143,10 @@
 extern Mutex*   JfrBuffer_lock;                  // protects JFR buffer operations
 extern Mutex*   JfrStream_lock;                  // protects JFR stream access
 
+#ifdef GRAAL
+extern Mutex*   GraalDeoptLeafGraphIds_lock;     // protects access to the global array of deopt'ed leaf graphs
+#endif // GRAAL
+
 // A MutexLocker provides mutual exclusion with respect to a given mutex
 // for the scope which contains the locker.  The lock is an OS lock, not
 // an object lock, and the two do not interoperate.  Do not use Mutex-based
--- a/src/share/vm/utilities/macros.hpp	Fri Mar 16 11:03:54 2012 +0100
+++ b/src/share/vm/utilities/macros.hpp	Wed Mar 21 10:47:02 2012 +0100
@@ -258,6 +258,14 @@
 #define NOT_EMBEDDED(code) code
 #endif
 
+#ifdef GRAAL
+#define GRAAL_ONLY(code...) code
+#define NOT_GRAAL(code...)
+#else
+#define GRAAL_ONLY(code...)
+#define NOT_GRAAL(code...) code
+#endif
+
 #define define_pd_global(type, name, value) const type pd_##name = value;
 
 #endif // SHARE_VM_UTILITIES_MACROS_HPP