changeset 5471:c9b8994b43d8

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Fri, 01 Jun 2012 16:32:05 +0200
parents 044502e7b5a4 (current diff) 174eb2b7f6ba (diff)
children fa979ebe0186
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java
diffstat 27 files changed, 920 insertions(+), 212 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri Jun 01 16:32:05 2012 +0200
@@ -352,9 +352,20 @@
             for (Block pred : block.getPredecessors()) {
                 if (fs == null) {
                     fs = blockLastState.get(pred);
-                } else if (fs != blockLastState.get(pred)) {
-                    fs = null;
-                    break;
+                } else {
+                    if (blockLastState.get(pred) == null) {
+                        // Only a back edge can have a null state for its enclosing block.
+                        assert pred.getEndNode() instanceof LoopEndNode;
+
+                        if (block.getBeginNode().stateAfter() == null) {
+                            // We'll assert later that the begin and end of a framestate-less loop
+                            // share the frame state that flowed into the loop
+                            blockLastState.put(pred, fs);
+                        }
+                    } else if (fs != blockLastState.get(pred)) {
+                        fs = null;
+                        break;
+                    }
                 }
             }
             if (GraalOptions.TraceLIRGeneratorLevel >= 2) {
@@ -433,6 +444,10 @@
             TTY.println("END Generating LIR for block B" + block.getId());
         }
 
+        // Check that the begin and end of a framestate-less loop
+        // share the frame state that flowed into the loop
+        assert blockLastState.get(block) == null || blockLastState.get(block) == lastState;
+
         blockLocks.put(currentBlock, curLocks);
         blockLastState.put(block, lastState);
         currentBlock = null;
@@ -707,16 +722,24 @@
     }
 
     private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) {
-        emitBranch(operand(node.object()), CiConstant.NULL_OBJECT, Condition.NE, false, falseSuccessor, info);
-        if (trueSuccessor != null) {
-            emitJump(trueSuccessor, null);
+        if (falseSuccessor != null) {
+            emitBranch(operand(node.object()), CiConstant.NULL_OBJECT, Condition.NE, false, falseSuccessor, info);
+            if (trueSuccessor != null) {
+                emitJump(trueSuccessor, null);
+            }
+        } else {
+            emitBranch(operand(node.object()), CiConstant.NULL_OBJECT, Condition.EQ, false, trueSuccessor, info);
         }
     }
 
     public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock, LIRDebugInfo info) {
-        emitBranch(operand(compare.x()), operand(compare.y()), compare.condition().negate(), !compare.unorderedIsTrue(), falseSuccessorBlock, info);
-        if (trueSuccessorBlock != null) {
-            emitJump(trueSuccessorBlock, null);
+        if (falseSuccessorBlock != null) {
+            emitBranch(operand(compare.x()), operand(compare.y()), compare.condition().negate(), !compare.unorderedIsTrue(), falseSuccessorBlock, info);
+            if (trueSuccessorBlock != null) {
+                emitJump(trueSuccessorBlock, null);
+            }
+        } else {
+            emitBranch(operand(compare.x()), operand(compare.y()), compare.condition(), compare.unorderedIsTrue(), trueSuccessorBlock, info);
         }
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopTransformUtil.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopTransformUtil.java	Fri Jun 01 16:32:05 2012 +0200
@@ -35,7 +35,7 @@
     }
 
     public static void peel(Loop loop, SuperBlock wholeLoop) {
-        SuperBlock peel = wholeLoop.duplicate(); // duplicates the nodes, merges early exits
+        SuperBlock peel = wholeLoop.duplicate(true); // duplicates the nodes, merges early exits
 
         peel.insertBefore(loop.loopBegin().forwardEnd()); // connects peeled part's CFG
 
@@ -43,7 +43,7 @@
         resolver.wholeLoop(wholeLoop).peeled(peel); // block (comming from the loop) was peeled into peel
         resolver.resolve();
 
-        peel.finish();
+        peel.finishDuplication();
     }
 
     public static SuperBlock wholeLoop(Loop loop) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/SuperBlock.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/SuperBlock.java	Fri Jun 01 16:32:05 2012 +0200
@@ -38,7 +38,8 @@
     protected List<BeginNode> earlyExits;
     protected Map<Node, Node> duplicationMapping;
     protected SuperBlock original;
-    protected NodeBitMap loopNodes;
+    protected NodeBitMap allNodes;
+    protected NodeBitMap allNodesExcludeLoopPhi;
 
     public SuperBlock(BeginNode entry, BeginNode exit, List<BeginNode> blocks, List<BeginNode> earlyExits) {
         this.entry = entry;
@@ -57,31 +58,45 @@
         return entry;
     }
 
-    public NodeBitMap loopNodes() {
-        if (loopNodes == null) {
-            loopNodes = computeNodes();
+    public NodeBitMap nodes() {
+        if (allNodes == null) {
+            allNodes = computeNodes();
         }
-        return loopNodes;
+        return allNodes;
+    }
+
+    private NodeBitMap nodesExcludeLoopPhi() {
+        if (allNodesExcludeLoopPhi == null) {
+            allNodesExcludeLoopPhi = nodes().copy();
+            if (entry instanceof LoopBeginNode) {
+                for (PhiNode phi : ((LoopBeginNode) entry).phis()) {
+                    allNodesExcludeLoopPhi.clear(phi);
+                }
+            }
+        }
+        return allNodesExcludeLoopPhi;
     }
 
     public SuperBlock duplicate() {
-        NodeBitMap nodes = loopNodes();
+        return duplicate(false);
+    }
+
+    public SuperBlock duplicate(boolean excludeLoop) {
+        NodeBitMap nodes = nodes();
         Map<Node, Node> replacements = new HashMap<>();
         StructuredGraph graph = (StructuredGraph) entry.graph();
-        BeginNode newEntry = graph.add(new BeginNode());
-        BeginNode newExit = null;
+        if (excludeLoop || (entry instanceof MergeNode && !(entry instanceof LoopBeginNode))) {
+            replacements.put(entry, graph.add(new BeginNode())); // no merge/loop begin
+        }
         List<BeginNode> newEarlyExits = new ArrayList<>(earlyExits.size());
-        if (!(exit instanceof MergeNode)) {
-            newExit = graph.add(new BeginNode());
-            replacements.put(exit, newExit);
-        }
-        replacements.put(entry, newEntry); // no merge/loop begin
         for (BeginNode earlyExit : earlyExits) {
             BeginNode newEarlyExit = graph.add(new BeginNode());
             newEarlyExits.add(newEarlyExit);
             replacements.put(earlyExit, newEarlyExit);
         }
-        if (exit instanceof LoopBeginNode) {
+        if (exit instanceof LoopBeginNode && excludeLoop) {
+            assert entry == exit;
+            nodes = nodesExcludeLoopPhi();
             for (LoopEndNode end : ((LoopBeginNode) exit).loopEnds()) {
                 if (nodes.isMarked(end)) {
                     replacements.put(end, graph.add(new EndNode()));
@@ -89,8 +104,14 @@
             }
         }
         Map<Node, Node> duplicates = graph.addDuplicates(nodes, replacements);
-        if (exit instanceof MergeNode) {
+        BeginNode newExit;
+        if (excludeLoop || (exit instanceof MergeNode && !(exit instanceof LoopBeginNode))) {
             newExit = mergeExits(replacements, duplicates);
+        } else if (exit != entry) {
+            newExit = graph.add(new BeginNode());
+            replacements.put(exit, newExit);
+        } else {
+            newExit = (BeginNode) duplicates.get(exit);
         }
 
         List<BeginNode> newBlocks = new ArrayList<>(blocks.size());
@@ -105,7 +126,7 @@
         for (Entry<Node, Node> e : replacements.entrySet()) {
             duplicates.put(e.getKey(), e.getValue());
         }
-        SuperBlock superBlock = new SuperBlock(newEntry, newExit, newBlocks, newEarlyExits);
+        SuperBlock superBlock = new SuperBlock((BeginNode) duplicates.get(entry), newExit, newBlocks, newEarlyExits);
         superBlock.duplicationMapping = duplicates;
         superBlock.original = this;
         return superBlock;
@@ -163,7 +184,7 @@
         return newExit;
     }
 
-    public void finish() {
+    public void finishDuplication() {
         if (original != null) {
             mergeEarlyExits((StructuredGraph) entry.graph(), original.earlyExits, duplicationMapping);
         }
@@ -376,12 +397,6 @@
             }
         }
 
-        if (entry instanceof LoopBeginNode) {
-            for (PhiNode phi : ((LoopBeginNode) entry).phis()) {
-                nodes.clear(phi);
-            }
-        }
-
         return nodes;
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java	Fri Jun 01 16:32:05 2012 +0200
@@ -120,12 +120,23 @@
             if (folding || CiUtil.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex, target) != null) {
                 assert argument instanceof ConstantNode : "parameter " + parameterIndex + " must be a compile time constant for calling " + invoke.callTarget().targetMethod() + ": " + argument;
                 ConstantNode constantNode = (ConstantNode) argument;
-                Object o = constantNode.asConstant().boxedValue();
+                CiConstant constant = constantNode.asConstant();
+                Object o = constant.boxedValue();
                 if (o instanceof Class< ? >) {
                     reflectionCallArguments[i] = runtime.getType((Class< ? >) o);
                     parameterTypes[i] = RiResolvedType.class;
                 } else {
-                    reflectionCallArguments[i] = o;
+                    if (parameterTypes[i] == boolean.class) {
+                        reflectionCallArguments[i] = Boolean.valueOf(constant.asInt() != 0);
+                    } else if (parameterTypes[i] == byte.class) {
+                        reflectionCallArguments[i] = Byte.valueOf((byte) constant.asInt());
+                    } else if (parameterTypes[i] == short.class) {
+                        reflectionCallArguments[i] = Short.valueOf((short) constant.asInt());
+                    } else if (parameterTypes[i] == char.class) {
+                        reflectionCallArguments[i] = Character.valueOf((char) constant.asInt());
+                    } else {
+                        reflectionCallArguments[i] = o;
+                    }
                 }
             } else {
                 reflectionCallArguments[i] = argument;
@@ -186,7 +197,6 @@
     }
 
     private static Node createNodeInstance(Class< ? > nodeClass, Class< ? >[] parameterTypes, Object[] nodeConstructorArguments) {
-
         Constructor< ? > constructor;
         try {
             constructor = nodeClass.getDeclaredConstructor(parameterTypes);
@@ -197,7 +207,7 @@
         try {
             return (ValueNode) constructor.newInstance(nodeConstructorArguments);
         } catch (Exception e) {
-            throw new RuntimeException(e);
+            throw new RuntimeException(constructor + Arrays.toString(nodeConstructorArguments), e);
         }
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java	Fri Jun 01 16:32:05 2012 +0200
@@ -36,9 +36,13 @@
     }
 
     public NodeBitMap(Graph graph, boolean autoGrow) {
+        this(graph, autoGrow, new BitMap(graph.nodeIdCount()));
+    }
+
+    private NodeBitMap(Graph graph, boolean autoGrow, BitMap bits) {
         this.graph = graph;
         this.autoGrow = autoGrow;
-        bitMap = new BitMap(graph.nodeIdCount());
+        bitMap = bits;
     }
 
     public Graph graph() {
@@ -178,4 +182,8 @@
     public int cardinality() {
         return bitMap.cardinality();
     }
+
+    public NodeBitMap copy() {
+        return new NodeBitMap(graph, autoGrow, bitMap.copy());
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Fri Jun 01 16:32:05 2012 +0200
@@ -47,6 +47,9 @@
     public int vmPageSize;
     public int stackShadowPages;
     public int hubOffset;
+    public int superCheckOffsetOffset;
+    public int secondarySuperCacheOffset;
+    public int secondarySupersOffset;
     public int arrayLengthOffset;
     public int klassStateOffset;
     public int klassStateFullyInitialized;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Fri Jun 01 16:32:05 2012 +0200
@@ -28,16 +28,13 @@
 import java.util.*;
 
 import com.oracle.graal.compiler.*;
-import com.oracle.graal.compiler.phases.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.cri.*;
-import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.Compiler;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.snippets.*;
-import com.oracle.graal.hotspot.snippets.CheckCastSnippets.Counter;
 import com.oracle.graal.hotspot.target.amd64.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -342,15 +339,13 @@
         } else if (n instanceof UnsafeLoadNode) {
             UnsafeLoadNode load = (UnsafeLoadNode) n;
             assert load.kind() != CiKind.Illegal;
-            IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, load.loadKind(), load.displacement(), load.offset(), graph);
-            location.setIndexScalingEnabled(false);
+            IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, load.loadKind(), load.displacement(), load.offset(), graph, false);
             ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp()));
             memoryRead.dependencies().add(tool.createNullCheckGuard(load.object(), StructuredGraph.INVALID_GRAPH_ID));
             graph.replaceFixedWithFixed(load, memoryRead);
         } else if (n instanceof UnsafeStoreNode) {
             UnsafeStoreNode store = (UnsafeStoreNode) n;
-            IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, store.storeKind(), store.displacement(), store.offset(), graph);
-            location.setIndexScalingEnabled(false);
+            IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, store.storeKind(), store.displacement(), store.offset(), graph, false);
             WriteNode write = graph.add(new WriteNode(store.object(), store.value(), location));
             write.setStateAfter(store.stateAfter());
             graph.replaceFixedWithFixed(store, write);
@@ -366,31 +361,7 @@
             graph.replaceFixed(objectClassNode, memoryRead);
         } else if (n instanceof CheckCastNode) {
             if (shouldLowerCheckcast(graph)) {
-                CheckCastNode checkcast = (CheckCastNode) n;
-                ValueNode hub = checkcast.targetClassInstruction();
-                ValueNode object = checkcast.object();
-                TypeCheckHints hints = new TypeCheckHints(checkcast.targetClass(), checkcast.profile(), tool.assumptions(), GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints);
-                HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.types.length];
-                for (int i = 0; i < hintHubs.length; i++) {
-                    hintHubs[i] = ((HotSpotType) hints.types[i]).klassOop();
-                }
-                Debug.log("Lowering checkcast in %s: node=%s, hintsHubs=%s, exact=%b", graph, checkcast, Arrays.toString(hints.types), hints.exact);
-
-                final Counter noHintsCounter;
-                if (GraalOptions.CheckcastCounters) {
-                    if (checkcast.targetClass() == null) {
-                        noHintsCounter = Counter.noHints_unknown;
-                    } else if (checkcast.targetClass().isInterface()) {
-                        noHintsCounter = Counter.noHints_iface;
-                    } else {
-                        noHintsCounter = Counter.noHints_class;
-                    }
-                } else {
-                    noHintsCounter = null;
-                }
-                boolean checkNull = !object.stamp().nonNull();
-                checkcasts.get(hintHubs.length, hints.exact, checkNull, noHintsCounter).instantiate(this, checkcast, checkcast, hub, object, hintHubs, noHintsCounter);
-                new DeadCodeEliminationPhase().apply(graph);
+                checkcasts.lower((CheckCastNode) n, tool);
             }
         } else {
             assert false : "Node implementing Lowerable not handled: " + n;
@@ -410,7 +381,7 @@
     }
 
     private IndexedLocationNode createArrayLocation(Graph graph, CiKind elementKind, ValueNode index) {
-        return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, config.getArrayOffset(elementKind), index, graph);
+        return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, config.getArrayOffset(elementKind), index, graph, true);
     }
 
     private SafeReadNode safeReadArrayLength(ValueNode array, long leafGraphId) {
@@ -445,7 +416,7 @@
                 StructuredGraph graph = new StructuredGraph();
                 LocalNode receiver = graph.unique(new LocalNode(0, StampFactory.objectNonNull()));
                 SafeReadNode klassOop = safeReadHub(graph, receiver, StructuredGraph.INVALID_GRAPH_ID);
-                Stamp resultStamp = StampFactory.declared(getType(Class.class));
+                Stamp resultStamp = StampFactory.declaredNonNull(getType(Class.class));
                 FloatingReadNode result = graph.unique(new FloatingReadNode(klassOop, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.classMirrorOffset, graph), null, resultStamp));
                 ReturnNode ret = graph.add(new ReturnNode(result));
                 graph.start().setNext(klassOop);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotTypeResolvedImpl.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotTypeResolvedImpl.java	Fri Jun 01 16:32:05 2012 +0200
@@ -26,6 +26,7 @@
 import java.lang.reflect.*;
 import java.util.*;
 
+import com.oracle.graal.hotspot.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 
@@ -42,6 +43,7 @@
     private boolean hasFinalizer;
     private boolean hasSubclass;
     private boolean hasFinalizableSubclass;
+    private int superCheckOffset;
     private boolean isArrayClass;
     private boolean isInstanceClass;
     private boolean isInterface;
@@ -264,7 +266,7 @@
         return this;
     }
 
-    // (dnsimon) this value may require identity semantics
+    // this value may require identity semantics so cache it
     private HotSpotKlassOop klassOopCache;
 
     @Override
@@ -274,4 +276,14 @@
         }
         return klassOopCache;
     }
+
+    private static final int SECONDARY_SUPER_CACHE_OFFSET = CompilerImpl.getInstance().getConfig().secondarySuperCacheOffset;
+
+    public boolean isPrimaryType() {
+        return SECONDARY_SUPER_CACHE_OFFSET != superCheckOffset;
+    }
+
+    public int superCheckOffset() {
+        return superCheckOffset;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java	Fri Jun 01 16:32:05 2012 +0200
@@ -221,18 +221,19 @@
         if (srcPos < 0 || destPos < 0 || length < 0 || srcPos + length > src.length || destPos + length > dest.length) {
             throw new IndexOutOfBoundsException();
         }
+        final int scale = arrayIndexScale(CiKind.Object);
         if (src == dest && srcPos < destPos) { // bad aliased case
-            copyObjectsDown(src, srcPos * 8L, dest, destPos * 8L, length);
+            copyObjectsDown(src, srcPos * scale, dest, destPos * scale, length);
         } else {
-            copyObjectsUp(src, srcPos * 8L, dest, destPos * 8L, length);
+            copyObjectsUp(src, srcPos * scale, dest, destPos * scale, length);
         }
         if (length > 0) {
-            int header = arrayHeaderSizeFor(CiKind.Object);
+            int header = arrayBaseOffset(CiKind.Object);
             int cardShift = cardTableShift();
             long cardStart = cardTableStart();
             long dstAddr = GetObjectAddressNode.get(dest);
-            long start = (dstAddr + header + destPos * 8L) >>> cardShift;
-            long end = (dstAddr + header + (destPos + length - 1) * 8L) >>> cardShift;
+            long start = (dstAddr + header + destPos * scale) >>> cardShift;
+            long end = (dstAddr + header + (destPos + length - 1) * scale) >>> cardShift;
             long count = end - start + 1;
             while (count-- > 0) {
                 DirectStoreNode.store((start + cardStart) + count, false);
@@ -242,7 +243,7 @@
 
     @Snippet
     public static void copyBytesDown(Object src, int srcPos, Object dest, int destPos, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Byte);
+        int header = arrayBaseOffset(CiKind.Byte);
         for (long i = length - 1; i >= 0; i--) {
             Byte a = UnsafeLoadNode.load(src, header, i + srcPos, CiKind.Byte);
             UnsafeStoreNode.store(dest, header, i + destPos, a.byteValue(), CiKind.Byte);
@@ -251,7 +252,7 @@
 
     @Snippet
     public static void copyShortsDown(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Short);
+        int header = arrayBaseOffset(CiKind.Short);
         for (long i = (length - 1) * 2; i >= 0; i -= 2) {
             Character a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Short);
             UnsafeStoreNode.store(dest, header, i + destOffset, a.charValue(), CiKind.Short);
@@ -260,7 +261,7 @@
 
     @Snippet
     public static void copyIntsDown(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Int);
+        int header = arrayBaseOffset(CiKind.Int);
         for (long i = (length - 1) * 4; i >= 0; i -= 4) {
             Integer a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Int);
             UnsafeStoreNode.store(dest, header, i + destOffset, a.intValue(), CiKind.Int);
@@ -269,7 +270,7 @@
 
     @Snippet
     public static void copyLongsDown(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Long);
+        int header = arrayBaseOffset(CiKind.Long);
         for (long i = (length - 1) * 8; i >= 0; i -= 8) {
             Long a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Long);
             UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), CiKind.Long);
@@ -279,8 +280,9 @@
     // Does NOT perform store checks
     @Snippet
     public static void copyObjectsDown(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Object);
-        for (long i = (length - 1) * wordSize(); i >= 0; i -= wordSize()) {
+        int header = arrayBaseOffset(CiKind.Object);
+        final int scale = arrayIndexScale(CiKind.Object);
+        for (long i = (length - 1) * scale; i >= 0; i -= scale) {
             Object a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Object);
             DirectObjectStoreNode.store(dest, header, i + destOffset, a);
         }
@@ -295,7 +297,7 @@
      */
     @Snippet
     public static void copyBytesUp(Object src, int srcPos, Object dest, int destPos, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Byte);
+        int header = arrayBaseOffset(CiKind.Byte);
         for (long i = 0; i < length; i++) {
             Byte a = UnsafeLoadNode.load(src, header, i + srcPos, CiKind.Byte);
             UnsafeStoreNode.store(dest, header, i + destPos, a.byteValue(), CiKind.Byte);
@@ -312,7 +314,7 @@
      */
     @Snippet
     public static void copyShortsUp(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Short);
+        int header = arrayBaseOffset(CiKind.Short);
         for (long i = 0; i < length * 2L; i += 2) {
             Character a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Short);
             UnsafeStoreNode.store(dest, header, i + destOffset, a.charValue(), CiKind.Short);
@@ -321,7 +323,7 @@
 
     @Snippet
     public static void copyIntsUp(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Int);
+        int header = arrayBaseOffset(CiKind.Int);
         for (long i = 0; i < length * 4L; i += 4) {
             Integer a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Int);
             UnsafeStoreNode.store(dest, header, i + destOffset, a.intValue(), CiKind.Int);
@@ -330,7 +332,7 @@
 
     @Snippet
     public static void copyLongsUp(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Long);
+        int header = arrayBaseOffset(CiKind.Long);
         for (long i = 0; i < length * 8L; i += 8) {
             Long a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Long);
             UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), CiKind.Long);
@@ -340,20 +342,33 @@
     // Does NOT perform store checks
     @Snippet
     public static void copyObjectsUp(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Object);
-        for (long i = 0; i < length * wordSize(); i += wordSize()) {
+        int header = arrayBaseOffset(CiKind.Object);
+        final int scale = arrayIndexScale(CiKind.Object);
+        for (long i = 0; i < length * scale; i += scale) {
             Object a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Object);
             DirectObjectStoreNode.store(dest, header, i + destOffset, a);
         }
     }
+
     @Fold
-    private static int wordSize() {
-        return CompilerImpl.getInstance().getTarget().wordSize;
+    static int arrayBaseOffset(CiKind elementKind) {
+        return elementKind.arrayBaseOffset();
     }
 
     @Fold
-    static int arrayHeaderSizeFor(CiKind elementKind) {
-        return CompilerImpl.getInstance().getConfig().getArrayOffset(elementKind);
+    static int arrayIndexScale(CiKind elementKind) {
+        return elementKind.arrayIndexScale();
+    }
+
+    static {
+        assert arrayIndexScale(CiKind.Byte) == 1;
+        assert arrayIndexScale(CiKind.Boolean) == 1;
+        assert arrayIndexScale(CiKind.Char) == 2;
+        assert arrayIndexScale(CiKind.Short) == 2;
+        assert arrayIndexScale(CiKind.Int) == 4;
+        assert arrayIndexScale(CiKind.Long) == 8;
+        assert arrayIndexScale(CiKind.Float) == 4;
+        assert arrayIndexScale(CiKind.Double) == 8;
     }
 
     @Fold
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Fri Jun 01 16:32:05 2012 +0200
@@ -21,7 +21,9 @@
  * questions.
  */
 package com.oracle.graal.hotspot.snippets;
+import static com.oracle.graal.hotspot.snippets.ArrayCopySnippets.*;
 import static com.oracle.graal.hotspot.snippets.CheckCastSnippets.Counter.*;
+import static com.oracle.graal.hotspot.snippets.CheckCastSnippets.TemplateFlag.*;
 import static com.oracle.graal.snippets.SnippetTemplate.*;
 
 import java.io.*;
@@ -31,53 +33,173 @@
 import sun.misc.*;
 
 import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.phases.*;
+import com.oracle.graal.cri.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.Fold;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.ri.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.snippets.*;
+import com.oracle.graal.snippets.nodes.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
+import com.oracle.max.criutils.*;
 
 /**
- * Snippets used for lowering {@link CheckCastNode}s.
+ * Snippets used for implementing the type test of a checkcast instruction.
+ *
+ * The test first checks against the profiled types (if any) and then implements the
+ * checks described in paper <a href="http://dl.acm.org/citation.cfm?id=583821">
+ * Fast subtype checking in the HotSpot JVM</a> by Cliff Click and John Rose.
  */
 public class CheckCastSnippets implements SnippetsInterface {
 
     /**
-     * Checks that a given object is null or is a subtype of a given type.
-     *
-     * @param hub the hub of the type being checked against
-     * @param object the object whose type is being checked against {@code hub}
-     * @param hintHubs the hubs of objects that have been profiled during previous executions
-     * @param hintsAreExact specifies if {@code hintHubs} contains all subtypes of {@code hub}
-     * @param checkNull specifies if {@code object} may be null
-     * @return {@code object} if the type check succeeds
-     * @throws ClassCastException if the type check fails
+     * Type test used when the type being tested against is a restricted primary type.
      */
     @Snippet
-    public static Object checkcast(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull, @SuppressWarnings("unused") Counter ignore) {
-        if (object == null) {
+    public static Object checkcastPrimary(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull, int superCheckOffset) {
+        if (checkNull && object == null) {
             return object;
         }
-        Object objectHub = UnsafeLoadNode.load(object, 0, hubOffset(), CiKind.Object);
+        Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true);
         // if we get an exact match: succeed immediately
+        ExplodeLoopNode.explodeLoop();
+        for (int i = 0; i < hintHubs.length; i++) {
+            Object hintHub = hintHubs[i];
+            if (hintHub == objectHub) {
+                return object;
+            }
+        }
+        if (hintsAreExact) {
+            DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
+        } else {
+            if (UnsafeLoadNode.loadObject(objectHub, 0, superCheckOffset, true) != hub) {
+                DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
+            }
+        }
+        return object;
+    }
+
+    /**
+     * Type test used when the type being tested against is a restricted secondary type.
+     */
+    @Snippet
+    public static Object checkcastSecondary(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull) {
+        if (checkNull && object == null) {
+            return object;
+        }
+        Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true);
+        // if we get an exact match: succeed immediately
+        ExplodeLoopNode.explodeLoop();
         for (int i = 0; i < hintHubs.length; i++) {
             Object hintHub = hintHubs[i];
             if (hintHub == objectHub) {
                 return object;
             }
         }
-        if (hintsAreExact || !TypeCheckSlowPath.check(objectHub, hub)) {
+        if (hintsAreExact) {
             DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
+        } else {
+            if (!checkSecondarySubType(hub, objectHub)) {
+                DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
+            }
+        }
+        return object;
+    }
+
+    /**
+     * Type test used when the type being tested against is not known at compile time (e.g. the type test
+     * in an object array store check).
+     */
+    @Snippet
+    public static Object checkcastUnknown(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull) {
+        if (checkNull && object == null) {
+            return object;
+        }
+        Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true);
+        // if we get an exact match: succeed immediately
+        ExplodeLoopNode.explodeLoop();
+        for (int i = 0; i < hintHubs.length; i++) {
+            Object hintHub = hintHubs[i];
+            if (hintHub == objectHub) {
+                return object;
+            }
+        }
+        if (hintsAreExact) {
+            DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
+        } else {
+            if (!checkUnknownSubType(hub, objectHub)) {
+                DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
+            }
         }
         return object;
     }
 
+    //This is used instead of a Java array read to avoid the array bounds check.
+    static Object loadNonNullObjectElement(Object array, int index) {
+        return UnsafeLoadNode.loadObject(array, arrayBaseOffset(CiKind.Object), index * arrayIndexScale(CiKind.Object), true);
+    }
+
+    static boolean checkSecondarySubType(Object t, Object s) {
+        // if (S.cache == T) return true
+        if (UnsafeLoadNode.loadObject(s, 0, secondarySuperCacheOffset(), true) == t) {
+            return true;
+        }
+
+        // if (T == S) return true
+        if (s == t) {
+            return true;
+        }
+
+        // if (S.scan_s_s_array(T)) { S.cache = T; return true; }
+        Object[] secondarySupers = UnsafeCastNode.cast(UnsafeLoadNode.loadObject(s, 0, secondarySupersOffset(), true), Object[].class);
+
+        for (int i = 0; i < secondarySupers.length; i++) {
+            if (t == loadNonNullObjectElement(secondarySupers, i)) {
+                DirectObjectStoreNode.store(s, secondarySuperCacheOffset(), 0, t);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    static boolean checkUnknownSubType(Object t, Object s) {
+        // int off = T.offset
+        int superCheckOffset = UnsafeLoadNode.load(t, 0, superCheckOffsetOffset(), CiKind.Int);
+
+        // if (T = S[off]) return true
+        if (UnsafeLoadNode.loadObject(s, 0, superCheckOffset, true) == t) {
+            return true;
+        }
+
+        // if (off != &cache) return false
+        if (superCheckOffset != secondarySuperCacheOffset()) {
+            return false;
+        }
+
+        // if (T == S) return true
+        if (s == t) {
+            return true;
+        }
+
+        // if (S.scan_s_s_array(T)) { S.cache = T; return true; }
+        Object[] secondarySupers = UnsafeCastNode.cast(UnsafeLoadNode.loadObject(s, 0, secondarySupersOffset(), true), Object[].class);
+        for (int i = 0; i < secondarySupers.length; i++) {
+            if (t == loadNonNullObjectElement(secondarySupers, i)) {
+                DirectObjectStoreNode.store(s, secondarySuperCacheOffset(), 0, t);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     /**
      * Counters for the various code paths through a type check.
      */
@@ -85,9 +207,7 @@
         hintsHit("hit a hint type"),
         hintsMissed("missed the hint types"),
         exact("tested type is (statically) final"),
-        noHints_class("profile information is not used (test type is a class)"),
-        noHints_iface("profile information is not used (test type is an interface)"),
-        noHints_unknown("test type is not a compile-time constant"),
+        noHints("profile information is not used"),
         isNull("object tested is null"),
         exception("type test failed with a ClassCastException");
 
@@ -124,21 +244,25 @@
         static final boolean ENABLED = GraalOptions.CheckcastCounters;
     }
 
+    /**
+     * Type test used when {@link GraalOptions#CheckcastCounters} is enabled.
+     */
     @Snippet
-    public static Object checkcastWithCounters(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, @SuppressWarnings("unused") boolean checkNull, Counter noHintsCounter) {
+    public static Object checkcastCounters(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact) {
         if (object == null) {
             isNull.inc();
             return object;
         }
-        Object objectHub = UnsafeLoadNode.load(object, 0, hubOffset(), CiKind.Object);
+        Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true);
         if (hintHubs.length == 0) {
-            noHintsCounter.inc();
-            if (!TypeCheckSlowPath.check(objectHub, hub)) {
+            noHints.inc();
+            if (!checkUnknownSubType(hub, objectHub)) {
                 exception.inc();
                 DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
             }
         } else {
             // if we get an exact match: succeed immediately
+            ExplodeLoopNode.explodeLoop();
             for (int i = 0; i < hintHubs.length; i++) {
                 Object hintHub = hintHubs[i];
                 if (hintHub == objectHub) {
@@ -151,7 +275,7 @@
                 }
             }
             if (!hintsAreExact) {
-                if (!TypeCheckSlowPath.check(objectHub, hub)) {
+                if (!checkUnknownSubType(hub, objectHub)) {
                     exception.inc();
                     DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
                 } else {
@@ -166,6 +290,21 @@
     }
 
     @Fold
+    private static int superCheckOffsetOffset() {
+        return CompilerImpl.getInstance().getConfig().superCheckOffsetOffset;
+    }
+
+    @Fold
+    private static int secondarySuperCacheOffset() {
+        return CompilerImpl.getInstance().getConfig().secondarySuperCacheOffset;
+    }
+
+    @Fold
+    private static int secondarySupersOffset() {
+        return CompilerImpl.getInstance().getConfig().secondarySupersOffset;
+    }
+
+    @Fold
     private static int hubOffset() {
         return CompilerImpl.getInstance().getConfig().hubOffset;
     }
@@ -205,54 +344,148 @@
         }
     }
 
+    public enum TemplateFlag {
+        CHECK_NULL,
+        EXACT_HINTS,
+        COUNTERS,
+        PRIMARY_SUPER,
+        SECONDARY_SUPER,
+        UNKNOWN_SUPER;
+
+        public int bit(boolean value) {
+            if (value) {
+                return bit();
+            }
+            return 0;
+        }
+
+        public boolean bool(int flags) {
+            return (flags & bit()) != 0;
+        }
+
+        static final int FLAGS_BITS = values().length;
+        static final int FLAGS_MASK = (1 << FLAGS_BITS) - 1;
+
+        static final int NHINTS_SHIFT = FLAGS_BITS;
+        static final int NHINTS_BITS = 3;
+        static final int SUPER_CHECK_OFFSET_SHIFT = NHINTS_SHIFT + NHINTS_BITS;
+
+        public int bit() {
+            return 1 << ordinal();
+        }
+    }
+
     /**
      * Templates for partially specialized checkcast snippet graphs.
      */
     public static class Templates {
 
         private final ConcurrentHashMap<Integer, SnippetTemplate> templates;
-        private final RiResolvedMethod method;
+        private final RiResolvedMethod counters;
+        private final RiResolvedMethod primary;
+        private final RiResolvedMethod secondary;
+        private final RiResolvedMethod unknown;
         private final RiRuntime runtime;
 
         public Templates(RiRuntime runtime) {
             this.runtime = runtime;
             this.templates = new ConcurrentHashMap<>();
             try {
-                Class[] parameterTypes = {Object.class, Object.class, Object[].class, boolean.class, boolean.class, Counter.class};
-                String name = GraalOptions.CheckcastCounters ? "checkcastWithCounters" : "checkcast";
-                method = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod(name, parameterTypes));
+                primary = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastPrimary", Object.class, Object.class, Object[].class, boolean.class, boolean.class, int.class));
+                secondary = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastSecondary", Object.class, Object.class, Object[].class, boolean.class, boolean.class));
+                unknown = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastUnknown", Object.class, Object.class, Object[].class, boolean.class, boolean.class));
+                counters = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastCounters", Object.class, Object.class, Object[].class, boolean.class));
             } catch (NoSuchMethodException e) {
                 throw new GraalInternalError(e);
             }
         }
 
         /**
-         * Gets a checkcast snippet specialized for a given set of inputs.
+         * Interface for lazily creating a snippet template.
          */
-        public SnippetTemplate get(int nHints, boolean isExact, boolean checkNull, Counter noHintsCounter) {
-            Integer key = key(nHints, isExact, checkNull);
+        abstract static class Factory {
+            abstract SnippetTemplate create(HotSpotKlassOop[] hints, int flags);
+        }
+
+        /**
+         * Gets a template from the template cache, creating and installing it first if necessary.
+         */
+        private SnippetTemplate getTemplate(int nHints, int flags, int superCheckOffset, Factory factory) {
+            assert (flags & ~FLAGS_MASK) == 0;
+            assert nHints >= 0 && nHints < (1 << NHINTS_BITS) - 1 : "nHints out of range";
+            assert superCheckOffset >= 0 && superCheckOffset == ((superCheckOffset << SUPER_CHECK_OFFSET_SHIFT) >>> SUPER_CHECK_OFFSET_SHIFT) : "superCheckOffset out of range";
+            Integer key = superCheckOffset << SUPER_CHECK_OFFSET_SHIFT | nHints << NHINTS_SHIFT | flags;
             SnippetTemplate result = templates.get(key);
             if (result == null) {
                 HotSpotKlassOop[] hints = new HotSpotKlassOop[nHints];
-                Arrays.fill(hints, new HotSpotKlassOop(null, Templates.class));
-                result = SnippetTemplate.create(runtime, method, _, _, hints, isExact, checkNull, noHintsCounter);
+                for (int i = 0; i < hints.length; i++) {
+                    hints[i] = new HotSpotKlassOop(null, Templates.class);
+                }
+                result = factory.create(hints, flags);
+                //System.err.println(result);
                 templates.put(key, result);
             }
             return result;
         }
 
         /**
-         * Creates a canonical key for a combination of specialization parameters.
+         * Lowers a checkcast node.
          */
-        private static Integer key(int nHints, boolean isExact, boolean checkNull) {
-            int key = nHints << 2;
-            if (isExact) {
-                key |= 2;
+        public void lower(CheckCastNode checkcast, CiLoweringTool tool) {
+            StructuredGraph graph = (StructuredGraph) checkcast.graph();
+            ValueNode hub = checkcast.targetClassInstruction();
+            ValueNode object = checkcast.object();
+            TypeCheckHints hints = new TypeCheckHints(checkcast.targetClass(), checkcast.profile(), tool.assumptions(), GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints);
+            HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.types.length];
+            for (int i = 0; i < hintHubs.length; i++) {
+                hintHubs[i] = ((HotSpotType) hints.types[i]).klassOop();
             }
-            if (checkNull) {
-                key |= 1;
+            Debug.log("Lowering checkcast in %s: node=%s, hintsHubs=%s, exact=%b", graph, checkcast, Arrays.toString(hints.types), hints.exact);
+
+            final HotSpotTypeResolvedImpl target = (HotSpotTypeResolvedImpl) checkcast.targetClass();
+            int flags = EXACT_HINTS.bit(hints.exact) | CHECK_NULL.bit(!object.stamp().nonNull());
+            if (GraalOptions.CheckcastCounters) {
+                SnippetTemplate template = getTemplate(hintHubs.length, flags | COUNTERS.bit(), 0, new Factory() {
+                    @SuppressWarnings("hiding")
+                    @Override
+                    SnippetTemplate create(HotSpotKlassOop[] hints, int flags) {
+                        // checkcastCounters(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact)
+                        return SnippetTemplate.create(runtime, counters, _, _, hints, EXACT_HINTS.bool(flags));
+                    }
+                });
+                template.instantiate(runtime, checkcast, checkcast, hub, object, hintHubs, hints.exact);
+            } else if (target == null) {
+                SnippetTemplate template = getTemplate(hintHubs.length, flags | UNKNOWN_SUPER.bit(), 0, new Factory() {
+                    @SuppressWarnings("hiding")
+                    @Override
+                    SnippetTemplate create(HotSpotKlassOop[] hints, int flags) {
+                        // checkcastUnknown(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull)
+                        return SnippetTemplate.create(runtime, unknown, _, _, hints, EXACT_HINTS.bool(flags), CHECK_NULL.bool(flags));
+                    }
+                });
+                template.instantiate(runtime, checkcast, checkcast, hub, object, hintHubs);
+            } else if (target.isPrimaryType()) {
+                SnippetTemplate template = getTemplate(hintHubs.length, flags | PRIMARY_SUPER.bit(), target.superCheckOffset(), new Factory() {
+                    @SuppressWarnings("hiding")
+                    @Override
+                    SnippetTemplate create(HotSpotKlassOop[] hints, int flags) {
+                        // checkcastPrimary(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull, int superCheckOffset)
+                        return SnippetTemplate.create(runtime, primary, _, _, hints, EXACT_HINTS.bool(flags), CHECK_NULL.bool(flags), target.superCheckOffset());
+                    }
+                });
+                template.instantiate(runtime, checkcast, checkcast, hub, object, hintHubs);
+            } else {
+                SnippetTemplate template = getTemplate(hintHubs.length, flags | SECONDARY_SUPER.bit(), 0, new Factory() {
+                    @SuppressWarnings("hiding")
+                    @Override
+                    SnippetTemplate create(HotSpotKlassOop[] hints, int flags) {
+                        // checkcastSecondary(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull)
+                        return SnippetTemplate.create(runtime, secondary, _, _, hints, EXACT_HINTS.bool(flags), CHECK_NULL.bool(flags));
+                    }
+                });
+                template.instantiate(runtime, checkcast, checkcast, hub, object, hintHubs);
             }
-            return key;
+            new DeadCodeEliminationPhase().apply(graph);
         }
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java	Fri Jun 01 16:32:05 2012 +0200
@@ -68,6 +68,31 @@
         return reversePostOrder[0];
     }
 
+    public Iterable<Block> postOrder() {
+        return new Iterable<Block>() {
+            @Override
+            public Iterator<Block> iterator() {
+                return new Iterator<Block>() {
+                    private int nextIndex = reversePostOrder.length - 1;
+                    @Override
+                    public boolean hasNext() {
+                        return nextIndex >= 0;
+                    }
+
+                    @Override
+                    public Block next() {
+                        return reversePostOrder[nextIndex--];
+                    }
+
+                    @Override
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                };
+            }
+        };
+    }
+
     public NodeMap<Block> getNodeToBlock() {
         return nodeToBlock;
     }
@@ -304,7 +329,7 @@
     }
 
     private void computePostdominators() {
-        for (Block block : reversePostOrder) {
+        for (Block block : postOrder()) {
             if (block.isLoopEnd()) {
                 // We do not want the loop header registered as the postdominator of the loop end.
                 continue;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Fri Jun 01 16:32:05 2012 +0200
@@ -31,7 +31,10 @@
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 
-
+/**
+ * A floating read of a value from memory specified in terms of an object base and an object relative location.
+ * This node does not null check the object.
+ */
 public final class FloatingReadNode extends FloatingAccessNode implements Node.IterableNodeType, LIRLowerable, Canonicalizable {
 
     @Input private Node lastLocationAccess;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Fri Jun 01 16:32:05 2012 +0200
@@ -27,10 +27,20 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
+/**
+ * Extension of a {@linkplain LocationNode location} to include a scaled index or an additional offset.
+ */
 public final class IndexedLocationNode extends LocationNode implements LIRLowerable, Canonicalizable {
+
+    /**
+     * An offset or index depending on whether {@link #indexScalingEnabled} is true or false respectively.
+     */
     @Input private ValueNode index;
-    private boolean indexScalingEnabled;
+    private final boolean indexScalingEnabled;
 
+    /**
+     * Gets the index or offset of this location.
+     */
     public ValueNode index() {
         return index;
     }
@@ -46,17 +56,6 @@
         return indexScalingEnabled;
     }
 
-    /**
-     * Enables or disables scaling of the index by the value kind's size. Has no effect if the index input is not used.
-     */
-    public void setIndexScalingEnabled(boolean enable) {
-        this.indexScalingEnabled = enable;
-    }
-
-    public static IndexedLocationNode create(Object identity, CiKind kind, int displacement, ValueNode index, Graph graph) {
-        return create(identity, kind, displacement, index, graph, true);
-    }
-
     public static IndexedLocationNode create(Object identity, CiKind kind, int displacement, ValueNode index, Graph graph, boolean indexScalingEnabled) {
         return graph.unique(new IndexedLocationNode(identity, kind, index, displacement, indexScalingEnabled));
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Fri Jun 01 16:32:05 2012 +0200
@@ -29,6 +29,10 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
+/**
+ * A location for a memory access in terms of the kind of value accessed and the displacement
+ * (in bytes) from a base object or address.
+ */
 public class LocationNode extends FloatingNode implements LIRLowerable, ValueNumberable {
 
     private int displacement;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Fri Jun 01 16:32:05 2012 +0200
@@ -22,11 +22,11 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import com.oracle.max.cri.ci.*;
 import com.oracle.graal.cri.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.max.cri.ci.*;
 
 /**
  * Load of a value from a location specified as an offset relative to an object.
@@ -50,6 +50,14 @@
         return offset;
     }
 
+    public UnsafeLoadNode(ValueNode object, int displacement, ValueNode offset, boolean nonNull) {
+        super(nonNull ? StampFactory.objectNonNull() : StampFactory.object());
+        this.object = object;
+        this.displacement = displacement;
+        this.offset = offset;
+        this.loadKind = CiKind.Object;
+    }
+
     public UnsafeLoadNode(ValueNode object, int displacement, ValueNode offset, CiKind kind) {
         super(StampFactory.forKind(kind.stackKind()));
         this.object = object;
@@ -72,4 +80,10 @@
     public static <T> T load(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter CiKind kind) {
         throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler");
     }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static Object loadObject(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter boolean nonNull) {
+        throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler");
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Fri Jun 01 16:32:05 2012 +0200
@@ -24,8 +24,6 @@
 
 import java.lang.reflect.*;
 
-import sun.misc.*;
-
 import com.oracle.graal.cri.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -71,7 +69,7 @@
                 int length = Array.getLength(array);
                 if (index >= 0 && index < length) {
                     return ConstantNode.forCiConstant(elementKind().readUnsafeConstant(array,
-                                    Unsafe.ARRAY_OBJECT_BASE_OFFSET + index * Unsafe.ARRAY_OBJECT_INDEX_SCALE), tool.runtime(), graph());
+                                    elementKind().arrayBaseOffset() + index * elementKind().arrayIndexScale()), tool.runtime(), graph());
                 }
             }
         }
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Fri Jun 01 16:32:05 2012 +0200
@@ -35,6 +35,7 @@
 import com.oracle.graal.lir.cfg.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.snippets.nodes.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 
@@ -115,24 +116,41 @@
                     new CanonicalizerPhase(null, runtime, null, 0, immutabilityPredicate).apply(snippetCopy);
                 }
 
-                // Explode all loops in the snippet
-                if (snippetCopy.hasLoops()) {
-                    ControlFlowGraph cfg = ControlFlowGraph.compute(snippetCopy, true, true, false, false);
-                    for (Loop loop : cfg.getLoops()) {
-                        LoopBeginNode loopBegin = loop.loopBegin();
-                        SuperBlock wholeLoop = LoopTransformUtil.wholeLoop(loop);
-                        Debug.dump(snippetCopy, "Before exploding loop %s", loopBegin);
-                        int peel = 0;
-                        while (!loopBegin.isDeleted()) {
-                            int mark = snippetCopy.getMark();
-                            LoopTransformUtil.peel(loop, wholeLoop);
-                            Debug.dump(snippetCopy, "After peel %d", peel);
-                            new CanonicalizerPhase(null, runtime, null, mark, immutabilityPredicate).apply(snippetCopy);
-                            peel++;
+                boolean exploded = false;
+                do {
+                    exploded = false;
+                    for (Node node : snippetCopy.getNodes()) {
+                        if (node instanceof ExplodeLoopNode) {
+                            final ExplodeLoopNode explodeLoop = (ExplodeLoopNode) node;
+                            LoopBeginNode loopBegin = explodeLoop.findLoopBegin();
+                            ControlFlowGraph cfg = ControlFlowGraph.compute(snippetCopy, true, true, false, false);
+                            for (Loop loop : cfg.getLoops()) {
+                                if (loop.loopBegin() == loopBegin) {
+                                    SuperBlock wholeLoop = LoopTransformUtil.wholeLoop(loop);
+                                    Debug.dump(snippetCopy, "Before exploding loop %s", loopBegin);
+                                    int peel = 0;
+                                    while (!loopBegin.isDeleted()) {
+                                        int mark = snippetCopy.getMark();
+                                        LoopTransformUtil.peel(loop, wholeLoop);
+                                        Debug.dump(snippetCopy, "After peel %d", peel);
+                                        new CanonicalizerPhase(null, runtime, null, mark, immutabilityPredicate).apply(snippetCopy);
+                                        peel++;
+                                    }
+                                    Debug.dump(snippetCopy, "After exploding loop %s", loopBegin);
+                                    exploded = true;
+                                    break;
+                                }
+                            }
+
+                            FixedNode explodeLoopNext = explodeLoop.next();
+                            explodeLoop.clearSuccessors();
+                            explodeLoop.replaceAtPredecessors(explodeLoopNext);
+                            explodeLoop.replaceAtUsages(null);
+                            GraphUtil.killCFG(explodeLoop);
+                            break;
                         }
-                        Debug.dump(snippetCopy, "After exploding loop %s", loopBegin);
                     }
-                }
+                } while (exploded);
 
                 // Remove all frame states from inlined snippet graph. Snippets must be atomic (i.e. free
                 // of side-effects that prevent deoptimizing to a point before the snippet).
@@ -245,8 +263,10 @@
             } else if (arg instanceof ValueNode) {
                 assert param instanceof LocalNode;
                 replacements.put((LocalNode) param, (ValueNode) arg);
+            } else if (param instanceof ConstantNode) {
+                replacements.put((ConstantNode) param, ConstantNode.forObject(arg, runtime, replaceeGraph));
             } else {
-                replacements.put((ConstantNode) param, ConstantNode.forObject(arg, runtime, replaceeGraph));
+                assert param.equals(arg) : param + " != " + arg;
             }
         }
         return replacements;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/ExplodeLoopNode.java	Fri Jun 01 16:32:05 2012 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.snippets.nodes;
+
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Placeholder node to denote to snippet preparation that the following loop
+ * must be completely unrolled.
+ */
+public final class ExplodeLoopNode extends FixedWithNextNode {
+
+    public ExplodeLoopNode() {
+        super(StampFactory.forVoid());
+    }
+
+    public LoopBeginNode findLoopBegin() {
+        Node next = next();
+        while (!(next instanceof LoopBeginNode)) {
+            assert next != null : "cannot find loop after " + this;
+            Iterator< ? extends Node> successors = next.cfgSuccessors().iterator();
+            assert successors.hasNext() : "cannot find loop after " + this;
+            next = successors.next();
+            assert !successors.hasNext() : "should only be straight line code after " + this;
+        }
+        return (LoopBeginNode) next;
+    }
+
+    /**
+     * A call to this method must be placed immediately prior to the loop that is to be exploded.
+     */
+    @NodeIntrinsic
+    public static void explodeLoop() {
+        throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler");
+    }
+}
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CheckCastTest.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CheckCastTest.java	Fri Jun 01 16:32:05 2012 +0200
@@ -34,13 +34,27 @@
  */
 public class CheckCastTest extends TypeCheckTest {
 
+    /**
+     * Enables making the target type "unknown" at compile time.
+     */
+    boolean unknown;
+
     @Override
     protected void replaceProfile(StructuredGraph graph, RiTypeProfile profile) {
         CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first();
         if (ccn != null) {
-            CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.targetClassInstruction(), ccn.targetClass(), ccn.object(), profile));
+            RiResolvedType targetClass = unknown ? null : ccn.targetClass();
+            CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.targetClassInstruction(), targetClass, ccn.object(), profile));
             graph.replaceFixedWithFixed(ccn, ccnNew);
         }
+        unknown = false;
+    }
+
+    @Override
+    protected void test(String name, RiTypeProfile profile, Object... args) {
+        super.test(name, profile, args);
+        unknown = true;
+        super.test(name, profile, args);
     }
 
     @Test
@@ -89,6 +103,19 @@
         test("asStringExt", profile(String.class), 111);
     }
 
+    @Test
+    public void test7() {
+        Throwable throwable = new Exception();
+        test("asThrowable",   profile(),                             throwable);
+        test("asThrowable",   profile(Throwable.class),              throwable);
+        test("asThrowable",   profile(Exception.class, Error.class), throwable);
+    }
+
+    @Test
+    public void test8() {
+        test("arrayFill", profile(), new Object[100], "111");
+    }
+
     public static Number asNumber(Object o) {
         return (Number) o;
     }
@@ -97,6 +124,14 @@
         return (String) o;
     }
 
+    public static Throwable asThrowable(Object o) {
+        return (Throwable) o;
+    }
+
+    public static ValueNode asValueNode(Object o) {
+        return (ValueNode) o;
+    }
+
     public static Number asNumberExt(Object o) {
         Number n = (Number) o;
         return n.intValue() + 10;
@@ -107,15 +142,48 @@
         return "#" + s;
     }
 
-    @Test
-    public void test7() {
-        test("arrayFill", profile(), new Object[100], "111");
-    }
-
     public static Object[] arrayFill(Object[] arr, Object value) {
         for (int i = 0; i < arr.length; i++) {
             arr[i] = value;
         }
         return arr;
     }
+
+    static class Depth1 implements Cloneable {}
+    static class Depth2 extends Depth1 {}
+    static class Depth3 extends Depth2 {}
+    static class Depth4 extends Depth3 {}
+    static class Depth5 extends Depth4 {}
+    static class Depth6 extends Depth5 {}
+    static class Depth7 extends Depth6 {}
+    static class Depth8 extends Depth7 {}
+    static class Depth9 extends Depth8 {}
+    static class Depth10 extends Depth9 {}
+    static class Depth11 extends Depth10 {}
+    static class Depth12 extends Depth11 {}
+    static class Depth13 extends Depth12 {}
+
+    public static Depth12 asDepth12(Object o) {
+        return (Depth12) o;
+    }
+
+    public static Depth12[][] asDepth12Arr(Object o) {
+        return (Depth12[][]) o;
+    }
+
+    public static Cloneable asCloneable(Object o) {
+        return (Cloneable) o;
+    }
+
+    @Test
+    public void test9() {
+        Object o = new Depth13();
+        test("asDepth12",   profile(), o);
+    }
+
+    @Test
+    public void test10() {
+        Object o = new Depth13[3][];
+        test("asDepth12Arr",   profile(), o);
+    }
 }
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java	Fri Jun 01 16:32:05 2012 +0200
@@ -158,7 +158,7 @@
     }
 
     protected RiCompiledMethod addMethod(final RiResolvedMethod method, final CiTargetMethod tm) {
-        Debug.scope("CodeInstall", new Object[] {graalCompiler, method}, new Callable<RiCompiledMethod>() {
+        return Debug.scope("CodeInstall", new Object[] {graalCompiler, method}, new Callable<RiCompiledMethod>() {
             @Override
             public RiCompiledMethod call() throws Exception {
                 final RiCodeInfo[] info = Debug.isDumpEnabled() ? new RiCodeInfo[1] : null;
@@ -169,7 +169,6 @@
                 return installedMethod;
             }
         });
-        return runtime.addMethod(method, tm, null);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/cfg/SimpleCFGTest.java	Fri Jun 01 16:32:05 2012 +0200
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.tests.cfg;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.graal.lir.cfg.*;
+import com.oracle.graal.nodes.*;
+
+public class SimpleCFGTest {
+
+    @Test
+    public void testImplies() {
+        StructuredGraph graph = new StructuredGraph();
+
+        EndNode trueEnd = graph.add(new EndNode());
+        EndNode falseEnd = graph.add(new EndNode());
+
+        BeginNode trueBegin = graph.add(new BeginNode());
+        trueBegin.setNext(trueEnd);
+        BeginNode falseBegin = graph.add(new BeginNode());
+        falseBegin.setNext(falseEnd);
+
+        IfNode ifNode = graph.add(new IfNode(null, trueBegin, falseBegin, 0.5));
+        graph.start().setNext(ifNode);
+
+        MergeNode merge = graph.add(new MergeNode());
+        merge.addForwardEnd(trueEnd);
+        merge.addForwardEnd(falseEnd);
+        ReturnNode returnNode = graph.add(new ReturnNode(null));
+        merge.setNext(returnNode);
+
+        ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
+
+        Block[] blocks = cfg.getBlocks();
+        // check number of blocks
+        assertEquals(4, blocks.length);
+
+        // check block - node assignment
+        assertEquals(blocks[0], cfg.blockFor(graph.start()));
+        assertEquals(blocks[0], cfg.blockFor(ifNode));
+        assertEquals(blocks[1], cfg.blockFor(trueBegin));
+        assertEquals(blocks[1], cfg.blockFor(trueEnd));
+        assertEquals(blocks[2], cfg.blockFor(falseBegin));
+        assertEquals(blocks[2], cfg.blockFor(falseEnd));
+        assertEquals(blocks[3], cfg.blockFor(merge));
+        assertEquals(blocks[3], cfg.blockFor(returnNode));
+
+        // check dominators
+        assertDominator(blocks[0], null);
+        assertDominator(blocks[1], blocks[0]);
+        assertDominator(blocks[2], blocks[0]);
+        assertDominator(blocks[3], blocks[0]);
+
+        // check dominated
+        assertDominatedSize(blocks[0], 3);
+        assertDominatedSize(blocks[1], 0);
+        assertDominatedSize(blocks[2], 0);
+        assertDominatedSize(blocks[3], 0);
+
+        // check postdominators
+        assertPostdominator(blocks[0], blocks[3]);
+        assertPostdominator(blocks[1], blocks[3]);
+        assertPostdominator(blocks[2], blocks[3]);
+        assertPostdominator(blocks[3], null);
+    }
+
+    public static void assertDominator(Block block, Block expectedDominator) {
+        assertEquals("dominator of " + block, expectedDominator, block.getDominator());
+    }
+
+    public static void assertDominatedSize(Block block, int size) {
+        assertEquals("number of dominated blocks of " + block, size, block.getDominated().size());
+    }
+
+    public static void assertPostdominator(Block block, Block expectedPostdominator) {
+        assertEquals("postdominator of " + block, expectedPostdominator, block.getPostdominator());
+    }
+
+}
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java	Fri Jun 01 16:31:49 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java	Fri Jun 01 16:32:05 2012 +0200
@@ -344,6 +344,58 @@
         return Character.toUpperCase(typeChar);
     }
 
+    public final int arrayBaseOffset() {
+        switch(this) {
+            case Boolean:
+                return Unsafe.ARRAY_BOOLEAN_BASE_OFFSET;
+            case Byte:
+                return Unsafe.ARRAY_BYTE_BASE_OFFSET;
+            case Char:
+                return Unsafe.ARRAY_CHAR_BASE_OFFSET;
+            case Short:
+                return Unsafe.ARRAY_SHORT_BASE_OFFSET;
+            case Int:
+                return Unsafe.ARRAY_INT_BASE_OFFSET;
+            case Long:
+                return Unsafe.ARRAY_LONG_BASE_OFFSET;
+            case Float:
+                return Unsafe.ARRAY_FLOAT_BASE_OFFSET;
+            case Double:
+                return Unsafe.ARRAY_DOUBLE_BASE_OFFSET;
+            case Object:
+                return Unsafe.ARRAY_OBJECT_BASE_OFFSET;
+            default:
+                assert false : "unexpected kind: " + this;
+                return -1;
+        }
+    }
+
+    public final int arrayIndexScale() {
+        switch(this) {
+            case Boolean:
+                return Unsafe.ARRAY_BOOLEAN_INDEX_SCALE;
+            case Byte:
+                return Unsafe.ARRAY_BYTE_INDEX_SCALE;
+            case Char:
+                return Unsafe.ARRAY_CHAR_INDEX_SCALE;
+            case Short:
+                return Unsafe.ARRAY_SHORT_INDEX_SCALE;
+            case Int:
+                return Unsafe.ARRAY_INT_INDEX_SCALE;
+            case Long:
+                return Unsafe.ARRAY_LONG_INDEX_SCALE;
+            case Float:
+                return Unsafe.ARRAY_FLOAT_INDEX_SCALE;
+            case Double:
+                return Unsafe.ARRAY_DOUBLE_INDEX_SCALE;
+            case Object:
+                return Unsafe.ARRAY_OBJECT_INDEX_SCALE;
+            default:
+                assert false : "unexpected kind: " + this;
+                return -1;
+        }
+    }
+
     public CiConstant readUnsafeConstant(Object value, long displacement) {
         assert value != null;
         Unsafe u = Unsafe.getUnsafe();
--- a/hotspot/.cproject	Fri Jun 01 16:31:49 2012 +0200
+++ b/hotspot/.cproject	Fri Jun 01 16:32:05 2012 +0200
@@ -20,7 +20,7 @@
 					<folderInfo id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.305678577" name="/" resourcePath="">
 						<toolChain id="cdt.managedbuild.toolchain.gnu.base.1866612258" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.base">
 							<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.gnu.platform.base.2075405295" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.gnu.platform.base"/>
-							<builder arguments="${workspace_loc:/hotspot}/../mxtool/mx build" autoBuildTarget="ide-build-target" buildPath="${workspace_loc:/hotspot}/.." cleanBuildTarget="clean" command="bash" enableAutoBuild="true" enableCleanBuild="false" enabledIncrementalBuild="false" id="cdt.managedbuild.target.gnu.builder.base.81453037" incrementalBuildTarget="jvmg1" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" parallelizationNumber="1" superClass="cdt.managedbuild.target.gnu.builder.base">
+							<builder arguments="${workspace_loc:/hotspot}/../mxtool/mx build" autoBuildTarget="ide-build-target" buildPath="${workspace_loc:/hotspot}/.." cleanBuildTarget="clean" command="bash" enableAutoBuild="true" enableCleanBuild="false" enabledIncrementalBuild="false" id="cdt.managedbuild.target.gnu.builder.base.81453037" incrementalBuildTarget="jvmg1" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base">
 								<outputEntries>
 									<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="outputPath" name=""/>
 								</outputEntries>
@@ -80,14 +80,15 @@
 			<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
 			<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
 			<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
-			<storageModule moduleId="scannerConfiguration"/>
 		</cconfiguration>
 	</storageModule>
 	<storageModule moduleId="cdtBuildSystem" version="4.0.0">
 		<project id="hotspot.null.1712822257" name="hotspot"/>
 	</storageModule>
-	<storageModule moduleId="refreshScope" versionNumber="1">
-		<resource resourceType="PROJECT" workspacePath="/hotspot"/>
+	<storageModule moduleId="refreshScope" versionNumber="2">
+		<configuration configurationName="Default">
+			<resource resourceType="PROJECT" workspacePath="/hotspot"/>
+		</configuration>
 	</storageModule>
 	<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
 	<storageModule moduleId="scannerConfiguration">
@@ -111,4 +112,5 @@
 			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
 		</scannerConfigBuildInfo>
 	</storageModule>
+	<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
 </cproject>
--- a/mxtool/mx.py	Fri Jun 01 16:31:49 2012 +0200
+++ b/mxtool/mx.py	Fri Jun 01 16:32:05 2012 +0200
@@ -124,7 +124,7 @@
 Property values can use environment variables with Bash syntax (e.g. ${HOME}).
 """
 
-import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal, xml.sax.saxutils
+import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal, xml.sax.saxutils, tempfile
 import shutil, fnmatch, re, xml.dom.minidom
 from collections import Callable
 from threading import Thread
@@ -404,11 +404,11 @@
 class XMLElement(xml.dom.minidom.Element):
     def writexml(self, writer, indent="", addindent="", newl=""):
         writer.write(indent+"<" + self.tagName)
-    
+
         attrs = self._get_attributes()
         a_names = attrs.keys()
         a_names.sort()
-    
+
         for a_name in a_names:
             writer.write(" %s=\"" % a_name)
             xml.dom.minidom._write_data(writer, attrs[a_name].value)
@@ -416,7 +416,7 @@
         if self.childNodes:
             if not self.ownerDocument.padTextNodeWithoutSiblings and len(self.childNodes) == 1 and isinstance(self.childNodes[0], xml.dom.minidom.Text):
                 # if the only child of an Element node is a Text node, then the
-                # text is printed without any indentation or new line padding  
+                # text is printed without any indentation or new line padding
                 writer.write(">")
                 self.childNodes[0].writexml(writer)
                 writer.write("</%s>%s" % (self.tagName,newl))
@@ -440,7 +440,7 @@
         e = XMLElement(tagName)
         e.ownerDocument = self
         return e
-    
+
     def open(self, tag, attributes={}, data=None):
         element = self.createElement(tag)
         for key, value in attributes.items():
@@ -453,13 +453,13 @@
 
     def close(self, tag):
         assert self.current != self
-        assert tag == self.current.tagName, str(tag) + ' != ' + self.current.tagName  
+        assert tag == self.current.tagName, str(tag) + ' != ' + self.current.tagName
         self.current = self.current.parentNode
         return self
-    
+
     def element(self, tag, attributes={}, data=None):
         return self.open(tag, attributes, data).close(tag)
-            
+
     def xml(self, indent='', newl='', escape=False):
         assert self.current == self
         result = self.toprettyxml(indent, newl, encoding="UTF-8")
@@ -534,20 +534,49 @@
         cp += [_opts.cp_suffix]
     return os.pathsep.join(cp)
 
-def classpath(names=None, resolve=True, includeSelf=True):
+def classpath(names=None, resolve=True, includeSelf=True, includeBootClasspath=False):
     """
     Get the class path for a list of given projects, resolving each entry in the
     path (e.g. downloading a missing library) if 'resolve' is true.
     """
     if names is None:
-        return _as_classpath(sorted_deps(includeLibs=True), resolve)
-    deps = []
-    if isinstance(names, types.StringTypes):
-        project(names).all_deps(deps, True, includeSelf)
+        result = _as_classpath(sorted_deps(includeLibs=True), resolve)
     else:
-        for n in names:
-            project(n).all_deps(deps, True, includeSelf)
-    return _as_classpath(deps, resolve)
+        deps = []
+        if isinstance(names, types.StringTypes):
+            project(names).all_deps(deps, True, includeSelf)
+        else:
+            for n in names:
+                project(n).all_deps(deps, True, includeSelf)
+        result = _as_classpath(deps, resolve)
+    if includeBootClasspath:
+        result = os.pathsep.join([java().bootclasspath(), result])
+    return result
+
+def classpath_walk(names=None, resolve=True, includeSelf=True, includeBootClasspath=False):
+    """
+    Walks the resources available in a given classpath, yielding a tuple for each resource
+    where the first member of the tuple is a directory path or ZipFile object for a
+    classpath entry and the second member is the qualified path of the resource relative
+    to the classpath entry.
+    """
+    cp = classpath(names, resolve, includeSelf, includeBootClasspath)
+    for entry in cp.split(os.pathsep):
+        if not exists(entry):
+            continue
+        if isdir(entry):
+            for root, dirs, files in os.walk(entry):
+                for d in dirs:
+                    entryPath = join(root[len(entry) + 1:], d)
+                    yield entry, entryPath
+                for f in files:
+                    entryPath = join(root[len(entry) + 1:], f)
+                    yield entry, entryPath
+        elif entry.endswith('.jar') or entry.endswith('.zip'):
+            with zipfile.ZipFile(entry, 'r') as zf:
+                for zi in zf.infolist():
+                    entryPath = zi.filename
+                    yield zf, entryPath
 
 def sorted_deps(projectNames=None, includeLibs=False):
     """
@@ -830,6 +859,7 @@
         self.javac = exe_suffix(join(self.jdk, 'bin', 'javac'))
         self.javap = exe_suffix(join(self.jdk, 'bin', 'javap'))
         self.javadoc = exe_suffix(join(self.jdk, 'bin', 'javadoc'))
+        self._bootclasspath = None
 
         if not exists(self.java):
             abort('Java launcher derived from JAVA_HOME does not exist: ' + self.java)
@@ -863,6 +893,27 @@
     def format_cmd(self, args):
         return [self.java] + self.java_args_pfx + self.java_args + self.java_args_sfx + args
 
+    def bootclasspath(self):
+        if self._bootclasspath is None:
+            tmpDir = tempfile.mkdtemp()
+            try:
+                src = join(tmpDir, 'bootclasspath.java')
+                with open(src, 'w') as fp:
+                    print >> fp, """
+public class bootclasspath {
+    public static void main(String[] args) {
+        String s = System.getProperty("sun.boot.class.path");
+        if (s != null) {
+            System.out.println(s);
+        }
+    }
+}"""
+                subprocess.check_call([self.javac, '-d', tmpDir, src])
+                self._bootclasspath = subprocess.check_output([self.java, '-cp', tmpDir, 'bootclasspath'])
+            finally:
+                shutil.rmtree(tmpDir)
+        return self._bootclasspath
+
 def check_get_env(key):
     """
     Gets an environment variable, aborting with a useful message if it is not set.
@@ -1039,7 +1090,7 @@
     javaCompliance = java().javaCompliance
 
     defaultEcjPath = join(_mainSuite.dir, 'mx', 'ecj.jar')
-    
+
     parser = parser if parser is not None else ArgumentParser(prog='mx build')
     parser.add_argument('-f', action='store_true', dest='force', help='force build (disables timestamp checking)')
     parser.add_argument('-c', action='store_true', dest='clean', help='removes existing build output')
@@ -1440,8 +1491,8 @@
         for dep in p.canonical_deps():
             print '"' + p.name + '"->"' + dep + '"'
     print '}'
-    
-    
+
+
 def _source_locator_memento(deps):
     slm = XMLDoc()
     slm.open('sourceLookupDirector')
@@ -1450,7 +1501,7 @@
     # Every Java program depends on the JRE
     memento = XMLDoc().element('classpathContainer', {'path' : 'org.eclipse.jdt.launching.JRE_CONTAINER'}).xml()
     slm.element('classpathContainer', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.classpathContainer'})
-        
+
     for dep in deps:
         if dep.isLibrary():
             if hasattr(dep, 'eclipse.container'):
@@ -1482,7 +1533,7 @@
     launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.VM_CONNECTOR_ID', 'value' : 'org.eclipse.jdt.launching.socketAttachConnector'})
     launch.close('launchConfiguration')
     launch = launch.xml(newl='\n') % slm.xml(escape=True)
-    
+
     if name is None:
         name = 'attach-' + hostname + '-' + port
     eclipseLaunches = join('mx', 'eclipse-launches')
@@ -1516,11 +1567,11 @@
             mainClass = a
             appArgs = list(reversed(argsCopy))
             break
-    
+
     if mainClass is None:
         log('Cannot create Eclipse launch configuration without main class or jar file: java ' + ' '.join(javaArgs))
         return False
-    
+
     if name is None:
         if mainClass == '-jar':
             name = basename(appArgs[0])
@@ -1535,9 +1586,9 @@
             for s in suites():
                 deps += [p for p in s.projects if e == p.output_dir()]
                 deps += [l for l in s.libs if e == l.get_path(False)]
-    
+
     slm = _source_locator_memento(deps)
-    
+
     launch = XMLDoc()
     launch.open('launchConfiguration', {'type' : 'org.eclipse.jdt.launching.localJavaApplication'})
     launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_id', 'value' : 'org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector'})
@@ -1564,13 +1615,13 @@
     for p in projects():
         if p.native:
             continue
-        
+
         if not exists(p.dir):
             os.makedirs(p.dir)
 
         out = XMLDoc()
         out.open('classpath')
-        
+
         for src in p.srcDirs:
             srcDir = join(p.dir, src)
             if not exists(srcDir):
@@ -1677,7 +1728,7 @@
                     content = content.replace('${javaCompliance}', str(p.javaCompliance))
                     update_file(join(settingsDir, name), content)
 
-    make_eclipse_attach('localhost', '8000', deps=projects())                    
+    make_eclipse_attach('localhost', '8000', deps=projects())
 
 def netbeansinit(args, suite=None):
     """(re)generate NetBeans project configurations"""
@@ -1717,7 +1768,7 @@
         out.element('root', {'id' : 'test.src.dir'})
         out.close('test-roots')
         out.close('data')
-        
+
         firstDep = True
         for dep in p.all_deps([], True):
             if dep == p:
@@ -1894,7 +1945,7 @@
 
 def javadoc(args):
     """generate javadoc for some/all Java projects"""
-    
+
     parser = ArgumentParser(prog='mx javadoc')
     parser.add_argument('--unified', action='store_true', help='put javadoc in a single directory instead of one per project')
     parser.add_argument('--force', action='store_true', help='(re)generate javadoc even if package-list file exists')
@@ -2006,6 +2057,20 @@
         run([java().javadoc, memory, '-classpath', cp, '-quiet', '-d', out, '-sourcepath', sp] + docletArgs + links + extraArgs + list(pkgs))
         log('Generated {2} for {0} in {1}'.format(', '.join(names), out, docDir))
 
+def findclass(args):
+    """find all classes matching a given substring"""
+
+    for entry, filename in classpath_walk(includeBootClasspath=True):
+        if filename.endswith('.class'):
+            if isinstance(entry, zipfile.ZipFile):
+                classname = filename.replace('/', '.')
+            else:
+                classname = filename.replace(os.sep, '.')
+            classname = classname[:-len('.class')]
+            for a in args:
+                if a in classname:
+                    log(classname)
+
 def javap(args):
     """launch javap with a -classpath option denoting all available classes
 
@@ -2047,6 +2112,7 @@
     'canonicalizeprojects': [canonicalizeprojects, ''],
     'clean': [clean, ''],
     'eclipseinit': [eclipseinit, ''],
+    'findclass': [findclass, ''],
     'help': [help_, '[command]'],
     'ideclean': [ideclean, ''],
     'ideinit': [ideinit, ''],
--- a/src/share/vm/graal/graalCompiler.cpp	Fri Jun 01 16:31:49 2012 +0200
+++ b/src/share/vm/graal/graalCompiler.cpp	Fri Jun 01 16:32:05 2012 +0200
@@ -275,6 +275,7 @@
   HotSpotTypeResolved::set_simpleName(obj, name());
   HotSpotTypeResolved::set_accessFlags(obj, klass->access_flags().as_int());
   HotSpotTypeResolved::set_isInterface(obj, klass->is_interface());
+  HotSpotTypeResolved::set_superCheckOffset(obj, klass->super_check_offset());
   HotSpotTypeResolved::set_isInstanceClass(obj, klass->oop_is_instance());
 
   if (klass->oop_is_javaArray()) {
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Fri Jun 01 16:31:49 2012 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Fri Jun 01 16:32:05 2012 +0200
@@ -789,6 +789,9 @@
   set_int(env, config, "vmPageSize", os::vm_page_size());
   set_int(env, config, "stackShadowPages", StackShadowPages);
   set_int(env, config, "hubOffset", oopDesc::klass_offset_in_bytes());
+  set_int(env, config, "superCheckOffsetOffset", in_bytes(Klass::super_check_offset_offset()));
+  set_int(env, config, "secondarySuperCacheOffset", in_bytes(Klass::secondary_super_cache_offset()));
+  set_int(env, config, "secondarySupersOffset", in_bytes(Klass::secondary_supers_offset()));
   set_int(env, config, "arrayLengthOffset", arrayOopDesc::length_offset_in_bytes());
   set_int(env, config, "klassStateOffset", in_bytes(instanceKlass::init_state_offset()));
   set_int(env, config, "klassStateFullyInitialized", (int)instanceKlass::fully_initialized);
@@ -1021,6 +1024,7 @@
   if (nm == NULL || !nm->is_alive()) {
     THROW_0(vmSymbols::MethodInvalidatedException());
   }
+
   JavaCalls::call(&result, mh, nm, &jca, CHECK_NULL);
 
   if (jap.get_ret_type() == T_VOID) {
--- a/src/share/vm/graal/graalJavaAccess.hpp	Fri Jun 01 16:31:49 2012 +0200
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Fri Jun 01 16:32:05 2012 +0200
@@ -53,6 +53,7 @@
     boolean_field(HotSpotTypeResolved, hasFinalizer)                                    \
     boolean_field(HotSpotTypeResolved, hasSubclass)                                     \
     boolean_field(HotSpotTypeResolved, hasFinalizableSubclass)                          \
+    int_field(HotSpotTypeResolved, superCheckOffset)                                    \
     boolean_field(HotSpotTypeResolved, isArrayClass)                                    \
     boolean_field(HotSpotTypeResolved, isInstanceClass)                                 \
     boolean_field(HotSpotTypeResolved, isInterface)                                     \