changeset 5411:128b3f574991

Merge
author Gilles Duboscq <duboscq@ssw.jku.at>
date Tue, 15 May 2012 16:27:12 +0200
parents c574c4540791 (diff) 206df7b3e022 (current diff)
children bb47fd6a6290
files
diffstat 26 files changed, 640 insertions(+), 270 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Tue May 15 16:27:12 2012 +0200
@@ -259,10 +259,10 @@
 
     /**
      * Use HIR lowering instead of LIR lowering for checkcast instructions.
-     * Only checkcasts in methods in a class whose name contains this option will be HIR lowered.
-     * TDOD (dnsimon) remove once HIR checkcast lowering works reliably
+     * Only checkcasts in methods whose fully qualified name contains this option will be HIR lowered.
+     * TODO (dnsimon) remove once HIR checkcast lowering works reliably
      */
-    public static String HIRLowerCheckcast;
+    public static String HIRLowerCheckcast = "";
 
     /**
      * The profiling info cache directory.
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java	Tue May 15 16:27:12 2012 +0200
@@ -44,9 +44,56 @@
         this.runtime = runtime;
         this.assumptions = assumptions;
     }
-
     @Override
     protected void run(final StructuredGraph graph) {
+        // Step 1: repeatedly lower fixed nodes until no new ones are created
+        NodeBitMap processed = graph.createNodeBitMap();
+        while (true) {
+            int mark = graph.getMark();
+            ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, false, true, true);
+            processBlock(cfg.getStartBlock(), graph.createNodeBitMap(), processed, null);
+
+            if (graph.getNewNodes(mark).filter(FixedNode.class).isEmpty()) {
+                break;
+            }
+            graph.verify();
+            processed.grow();
+        }
+
+        // Step 2: lower the floating nodes
+        processed.negate();
+        final CiLoweringTool loweringTool = new CiLoweringTool() {
+
+            @Override
+            public Node getGuardAnchor() {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public GraalRuntime getRuntime() {
+                return runtime;
+            }
+
+            @Override
+            public Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, long leafGraphId) {
+                // TODO (thomaswue): Document why this must not be called on floating nodes.
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public CiAssumptions assumptions() {
+                return assumptions;
+            }
+        };
+        for (Node node : processed) {
+            if (node instanceof Lowerable) {
+                assert !(node instanceof FixedNode) || node.predecessor() == null : node;
+                ((Lowerable) node).lower(loweringTool);
+            }
+        }
+    }
+
+    protected void run0(final StructuredGraph graph) {
         ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, false, true, true);
 
         NodeBitMap processed = graph.createNodeBitMap();
@@ -138,7 +185,7 @@
                 FixedNode guardAnchor = (FixedNode) getGuardAnchor();
                 if (GraalOptions.OptEliminateGuards) {
                     for (Node usage : condition.usages()) {
-                        if (activeGuards.isMarked(usage)) {
+                        if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage)) {
                             return usage;
                         }
                     }
@@ -157,9 +204,11 @@
 
         // Lower the instructions of this block.
         for (Node node : b.getNodes()) {
-            processed.mark(node);
-            if (node instanceof Lowerable) {
-                ((Lowerable) node).lower(loweringTool);
+            if (!processed.isMarked(node)) {
+                processed.mark(node);
+                if (node instanceof Lowerable) {
+                    ((Lowerable) node).lower(loweringTool);
+                }
             }
         }
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java	Tue May 15 16:27:12 2012 +0200
@@ -31,6 +31,7 @@
 
 import com.oracle.max.asm.*;
 import com.oracle.max.asm.target.amd64.*;
+import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ci.CiTargetMethod.Mark;
 import com.oracle.max.cri.ri.*;
@@ -499,11 +500,10 @@
 
 
     @Override
-    public void emitDeoptimizeOn(Condition cond, RiDeoptAction action, RiDeoptReason reason, Object deoptInfo) {
-        assert cond != null;
+    public void emitDeoptimizeOnOverflow(RiDeoptAction action, RiDeoptReason reason, Object deoptInfo) {
         LIRDebugInfo info = state();
         LabelRef stubEntry = createDeoptStub(action, reason, info, deoptInfo);
-        append(new BranchOp(cond, stubEntry, info));
+        append(new BranchOp(ConditionFlag.overflow, stubEntry, info));
     }
 
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Tue May 15 16:27:12 2012 +0200
@@ -33,6 +33,7 @@
 import com.oracle.graal.cri.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.*;
 import com.oracle.graal.lir.cfg.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.PhiNode.PhiType;
@@ -40,7 +41,6 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.max.cri.ci.*;
@@ -909,7 +909,6 @@
 
     /**
      * Performs replacement of a node with a snippet graph.
-     *
      * @param replacee the node that will be replaced
      * @param anchor the control flow replacee
      * @param snippetGraph the graph that the replacee will be replaced with
@@ -922,12 +921,11 @@
                     final StructuredGraph snippetGraph,
                     final boolean explodeLoops,
                     final IsImmutablePredicate immutabilityPredicate,
-                    final CiLoweringTool tool,
                     final Object... args) {
         Debug.scope("InliningSnippet", snippetGraph.method(), new Runnable() {
             @Override
             public void run() {
-                inlineSnippet0(runtime, replacee, anchor, snippetGraph, explodeLoops, immutabilityPredicate, tool, args);
+                inlineSnippet0(runtime, replacee, anchor, snippetGraph, explodeLoops, immutabilityPredicate, args);
             }
         });
     }
@@ -937,7 +935,7 @@
                     StructuredGraph snippetGraph,
                     boolean explodeLoops,
                     IsImmutablePredicate immutabilityPredicate,
-                    CiLoweringTool tool, Object... args) {
+                    Object... args) {
 
         Debug.dump(replacee.graph(), "Before lowering %s", replacee);
 
@@ -1018,25 +1016,11 @@
 
         // Remove all frame states from the inlined snippet graph. Snippets must be atomic (i.e. free
         // of side-effects that prevent deoptimizing to a point before the snippet).
-        if (tool != null) {
-            boolean innerLowering = false;
-            for (Node node : duplicates.values()) {
-                if (node instanceof Lowerable) {
-                    innerLowering = true;
-                    ((Lowerable) node).lower(tool);
-
-                }
-            }
-            if (innerLowering) {
-                Debug.dump(graph, "After inner lowering");
-            }
-        }
-
         for (Node node : graph.getNewNodes(mark)) {
             if (node instanceof StateSplit) {
                 StateSplit stateSplit = (StateSplit) node;
                 FrameState frameState = stateSplit.stateAfter();
-                assert !stateSplit.hasSideEffect() : "snippets cannot contain side-effecting node " + node + "\n    " + replacee.graph();
+                assert !stateSplit.hasSideEffect() : "snippets cannot contain side-effecting node " + node + "\n    " + frameState.toString(Verbosity.Debugger);
                 if (frameState != null) {
                     stateSplit.setStateAfter(null);
                 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Tue May 15 16:27:12 2012 +0200
@@ -289,6 +289,7 @@
         CiCompilationStatistics.clear("final");
         MethodEntryCounters.printCounters(compiler);
         HotSpotXirGenerator.printCounters(TTY.out().out());
+        CheckCastSnippets.printCounters(TTY.out().out());
     }
 
     private void flattenChildren(DebugValueMap map, DebugValueMap globalMap) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TypeCheckSlowPath.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TypeCheckSlowPath.java	Tue May 15 16:27:12 2012 +0200
@@ -25,6 +25,7 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.target.amd64.*;
+import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.type.*;
@@ -48,7 +49,7 @@
     }
 
     public TypeCheckSlowPath(ValueNode objectHub, ValueNode hub) {
-        super(StampFactory.forKind(CiKind.Object));
+        super(StampFactory.forKind(CiKind.Boolean));
         this.objectHub = objectHub;
         this.hub = hub;
     }
@@ -56,14 +57,20 @@
     @Override
     public void generate(LIRGenerator gen) {
         CiValue objectHubOpr = gen.operand(objectHub);
-        AMD64TypeCheckSlowPathOp op = new AMD64TypeCheckSlowPathOp(objectHubOpr, gen.operand(hub));
+        Variable result = gen.newVariable(CiKind.Boolean);
+        AMD64TypeCheckSlowPathOp op = new AMD64TypeCheckSlowPathOp(result, objectHubOpr, gen.operand(hub));
         gen.append(op);
-        gen.setResult(this, objectHubOpr);
+        gen.setResult(this, result);
     }
 
+    /**
+     * Checks if {@code objectHub} is a subclass of {@code hub}.
+     *
+     * @return {@code true} if {@code objectHub} is a subclass of {@code hub}, {@code false} otherwise
+     */
     @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static Object check(Object objectHub, Object hub) {
+    public static boolean check(Object objectHub, Object hub) {
         throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler");
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Tue May 15 16:27:12 2012 +0200
@@ -28,8 +28,8 @@
 import java.util.*;
 
 import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate;
 import com.oracle.graal.compiler.phases.*;
-import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.compiler.util.*;
 import com.oracle.graal.cri.*;
@@ -39,6 +39,7 @@
 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.*;
@@ -81,7 +82,11 @@
         Snippets.install(this, compiler.getTarget(), new ArrayCopySnippets());
         Snippets.install(this, compiler.getTarget(), new CheckCastSnippets());
         try {
-            checkcastSnippet = getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcast", Object.class, Object.class, Object[].class, boolean.class));
+            if (GraalOptions.CheckcastCounters) {
+                checkcastSnippet = getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastWithCounters", Object.class, Object.class, Object[].class, boolean.class, Counter.class));
+            } else {
+                checkcastSnippet = getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcast", Object.class, Object.class, Object[].class, boolean.class));
+            }
         } catch (NoSuchMethodException e) {
             throw new GraalInternalError(e);
         }
@@ -282,7 +287,7 @@
 
         if (n instanceof ArrayLengthNode) {
             ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n;
-            SafeReadNode safeReadArrayLength = safeReadArrayLength(arrayLengthNode.graph(), arrayLengthNode.array(), arrayLengthNode.stamp(), StructuredGraph.INVALID_GRAPH_ID);
+            SafeReadNode safeReadArrayLength = safeReadArrayLength(arrayLengthNode.array(), StructuredGraph.INVALID_GRAPH_ID);
             graph.replaceFixedWithFixed(arrayLengthNode, safeReadArrayLength);
             safeReadArrayLength.lower(tool);
         } else if (n instanceof LoadFieldNode) {
@@ -336,7 +341,8 @@
             }
         } else if (n instanceof LoadIndexedNode) {
             LoadIndexedNode loadIndexed = (LoadIndexedNode) n;
-            Node boundsCheck = createBoundsCheck(loadIndexed, tool, loadIndexed.leafGraphId());
+
+            Node boundsCheck = createBoundsCheck(loadIndexed, tool);
 
             CiKind elementKind = loadIndexed.elementKind();
             LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index());
@@ -345,7 +351,7 @@
             graph.replaceFixedWithFixed(loadIndexed, memoryRead);
         } else if (n instanceof StoreIndexedNode) {
             StoreIndexedNode storeIndexed = (StoreIndexedNode) n;
-            Node boundsCheck = createBoundsCheck(storeIndexed, tool, storeIndexed.leafGraphId());
+            Node boundsCheck = createBoundsCheck(storeIndexed, tool);
 
             CiKind elementKind = storeIndexed.elementKind();
             LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index());
@@ -412,7 +418,7 @@
             memoryRead.dependencies().add(tool.createGuard(graph.unique(new NullCheckNode(objectClassNode.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID));
             graph.replaceFixed(objectClassNode, memoryRead);
         } else if (n instanceof CheckCastNode) {
-            if (GraalOptions.HIRLowerCheckcast != null && graph.method() != null && graph.method().holder().name().contains(GraalOptions.HIRLowerCheckcast)) {
+            if (shouldLowerCheckcast(graph)) {
                 final Map<CiConstant, CiConstant> hintHubsSet = new IdentityHashMap<>();
                 IsImmutablePredicate immutabilityPredicate = new IsImmutablePredicate() {
                     public boolean apply(CiConstant constant) {
@@ -432,8 +438,12 @@
                 final CiConstant hintHubsConst = CiConstant.forObject(hintHubs);
                 hintHubsSet.put(hintHubsConst, hintHubsConst);
                 Debug.log("Lowering checkcast in %s: node=%s, hintsHubs=%s, exact=%b", graph, checkcast, Arrays.toString(hints.types), hints.exact);
-
-                InliningUtil.inlineSnippet(this, checkcast, checkcast, snippetGraph, true, immutabilityPredicate, tool, hub, object, hintHubsConst, CiConstant.forBoolean(hints.exact));
+                if (GraalOptions.CheckcastCounters) {
+                    Counter noHintsCounter = checkcast.targetClass() == null ? Counter.noHints_unknown : checkcast.targetClass().isInterface() ? Counter.noHints_iface : Counter.noHints_class;
+                    InliningUtil.inlineSnippet(this, checkcast, checkcast, snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(hints.exact), CiConstant.forObject(noHintsCounter));
+                } else {
+                    InliningUtil.inlineSnippet(this, checkcast, checkcast, snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(hints.exact));
+                }
                 new DeadCodeEliminationPhase().apply(graph);
             }
         } else {
@@ -441,12 +451,33 @@
         }
     }
 
+    private static boolean shouldLowerCheckcast(StructuredGraph graph) {
+        String option = GraalOptions.HIRLowerCheckcast;
+        if (option != null) {
+            if (option.length() == 0) {
+                return true;
+            }
+            RiResolvedMethod method = graph.method();
+            return method != null && CiUtil.format("%H.%n", method).contains(option);
+        }
+        return false;
+    }
+
     private IndexedLocationNode createArrayLocation(Graph graph, CiKind elementKind, ValueNode index) {
         return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, config.getArrayOffset(elementKind), index, graph);
     }
 
-    private static Node createBoundsCheck(AccessIndexedNode n, CiLoweringTool tool, long leafGraphId) {
-        return tool.createGuard(n.graph().unique(new CompareNode(n.index(), Condition.BT, n.length())), RiDeoptReason.BoundsCheckException, RiDeoptAction.InvalidateReprofile, leafGraphId);
+    private SafeReadNode safeReadArrayLength(ValueNode array, long leafGraphId) {
+        return safeRead(array.graph(), CiKind.Int, array, config.arrayLengthOffset, StampFactory.positiveInt(), leafGraphId);
+    }
+
+    private Node createBoundsCheck(AccessIndexedNode n, CiLoweringTool tool) {
+        SafeReadNode arrayLength = safeReadArrayLength(n.array(), n.leafGraphId());
+        Node guard = tool.createGuard(n.graph().unique(new CompareNode(n.index(), Condition.BT, arrayLength)), RiDeoptReason.BoundsCheckException, RiDeoptAction.InvalidateReprofile, n.leafGraphId());
+
+        ((StructuredGraph) n.graph()).addBeforeFixed(n, arrayLength);
+        arrayLength.lower(tool);
+        return guard;
     }
 
     @Override
@@ -500,10 +531,6 @@
         return safeRead(graph, CiKind.Object, value, config.hubOffset, StampFactory.objectNonNull(), leafGraphId);
     }
 
-    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, long leafGraphId) {
         return graph.add(new SafeReadNode(value, LocationNode.create(LocationNode.FINAL_LOCATION, kind, offset, graph), stamp, leafGraphId));
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java	Tue May 15 16:27:12 2012 +0200
@@ -1010,7 +1010,7 @@
     }
 
     private static void printCounter(PrintStream out, CheckcastCounter name, long count, long total) {
-        double percent = ((double) (count * 100)) / total;
+        double percent = total == 0D ? 0D : ((double) (count * 100)) / total;
         out.println(String.format("%16s: %5.2f%%%10d  // %s", name, percent, count, name.desc));
     }
 
@@ -1036,7 +1036,7 @@
         Arrays.sort(counters);
 
         out.println();
-        out.println("** Checkcast counters **");
+        out.println("** XIR checkcast counters **");
         for (Count c : counters) {
             printCounter(out, c.name, c.c, total);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java	Tue May 15 16:27:12 2012 +0200
@@ -21,8 +21,7 @@
  * questions.
  */
 package com.oracle.graal.hotspot.snippets;
-import com.oracle.graal.cri.*;
-import com.oracle.graal.graph.Node.*;
+import com.oracle.graal.graph.Node.Fold;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -32,6 +31,7 @@
 import com.oracle.max.cri.ci.*;
 
 
+@SuppressWarnings("unused")
 public class ArrayCopySnippets implements SnippetsInterface{
 
     @Snippet
@@ -346,92 +346,13 @@
             DirectObjectStoreNode.store(dest, header, i + destOffset, a);
         }
     }
-    private static class GetObjectAddressNode extends FixedWithNextNode implements LIRLowerable {
-        @Input private ValueNode object;
-
-        public GetObjectAddressNode(ValueNode obj) {
-            super(StampFactory.forKind(CiKind.Long));
-            this.object = obj;
-        }
-
-        @SuppressWarnings("unused")
-        @NodeIntrinsic
-        public static long get(Object array) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void generate(LIRGeneratorTool gen) {
-            CiValue obj = gen.newVariable(gen.target().wordKind);
-            gen.emitMove(gen.operand(object), obj);
-            gen.setResult(this, obj);
-        }
-    }
-    private static class DirectStoreNode extends FixedWithNextNode implements LIRLowerable {
-        @Input private ValueNode address;
-        @Input private ValueNode value;
-
-        public DirectStoreNode(ValueNode address, ValueNode value) {
-            super(StampFactory.illegal());
-            this.address = address;
-            this.value = value;
-        }
-
-        @SuppressWarnings("unused")
-        @NodeIntrinsic
-        public static void store(long address, long value) {
-            throw new UnsupportedOperationException();
-        }
-
-        @SuppressWarnings("unused")
-        @NodeIntrinsic
-        public static void store(long address, boolean value) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void generate(LIRGeneratorTool gen) {
-            CiValue v = gen.operand(value);
-            gen.emitStore(new CiAddress(v.kind, gen.operand(address)), v, false);
-        }
-    }
-
-    private static class DirectObjectStoreNode extends FixedWithNextNode implements Lowerable {
-        @Input private ValueNode object;
-        @Input private ValueNode value;
-        @Input private ValueNode offset;
-        private final int displacement;
-
-        public DirectObjectStoreNode(ValueNode object, int displacement, ValueNode offset, ValueNode value) {
-            super(StampFactory.illegal());
-            this.object = object;
-            this.value = value;
-            this.offset = offset;
-            this.displacement = displacement;
-        }
-
-        @SuppressWarnings("unused")
-        @NodeIntrinsic
-        public static void store(Object obj, @ConstantNodeParameter int displacement, long offset, Object value) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void lower(CiLoweringTool tool) {
-            StructuredGraph graph = (StructuredGraph) this.graph();
-            IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), displacement, offset, graph, false);
-            WriteNode write = graph.add(new WriteNode(object, value, location));
-            graph.replaceFixedWithFixed(this, write);
-        }
-    }
-
     @Fold
     private static int wordSize() {
         return CompilerImpl.getInstance().getTarget().wordSize;
     }
 
     @Fold
-    private static int arrayHeaderSizeFor(CiKind elementKind) {
+    static int arrayHeaderSizeFor(CiKind elementKind) {
         return CompilerImpl.getInstance().getConfig().getArrayOffset(elementKind);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Tue May 15 16:27:12 2012 +0200
@@ -21,18 +21,40 @@
  * questions.
  */
 package com.oracle.graal.hotspot.snippets;
+import static com.oracle.graal.hotspot.snippets.CheckCastSnippets.Counter.*;
+
+import java.io.*;
+import java.util.*;
+
+import sun.misc.*;
+
+import com.oracle.graal.compiler.*;
+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.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.snippets.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 
-
+/**
+ * Snippets used for lowering {@link CheckCastNode}s.
+ */
 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}
+     * @return {@code object} if the type check succeeds
+     * @throws ClassCastException if the type check fails
+     */
     @Snippet
     public static Object checkcast(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact) {
         if (object == null) {
@@ -46,14 +68,144 @@
                 return object;
             }
         }
-        if (hintsAreExact || TypeCheckSlowPath.check(objectHub, hub) == null) {
+        if (hintsAreExact || !TypeCheckSlowPath.check(objectHub, hub)) {
             DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
         }
         return object;
     }
 
+    /**
+     * Counters for the various code paths through a type check.
+     */
+    public enum Counter {
+        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"),
+        isNull("object tested is null"),
+        exception("type test failed with a ClassCastException");
+
+        final String description;
+        final int index;
+        long count;
+
+        private Counter(String desc) {
+            this.description = desc;
+            this.index = ordinal();
+        }
+
+        @Fold
+        static int countOffset() {
+            try {
+                return (int) Unsafe.getUnsafe().objectFieldOffset(Counter.class.getDeclaredField("count"));
+            } catch (Exception e) {
+                throw new GraalInternalError(e);
+            }
+        }
+
+        /**
+         * Increments this counter if counters are enabled. The body of this method has been carefully crafted
+         * such that it contains no safepoints and no calls, neither of which are permissible in a snippet.
+         * Also, increments are not guaranteed to be atomic but that's acceptable for a counter like this.
+         */
+        void inc() {
+            if (ENABLED) {
+                DirectObjectStoreNode.store(this, countOffset(), 0, count + 1);
+            }
+        }
+
+        static final Counter[] VALUES = values();
+        static final boolean ENABLED = GraalOptions.CheckcastCounters;
+    }
+
+    /**
+     * @see #checkcast(Object, Object, Object[], boolean)
+     */
+    @Snippet
+    public static Object checkcastWithCounters(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, Counter noHintsCounter) {
+        if (object == null) {
+            isNull.inc();
+            return object;
+        }
+        Object objectHub = UnsafeLoadNode.load(object, 0, hubOffset(), CiKind.Object);
+        if (hintHubs.length == 0) {
+            noHintsCounter.inc();
+            if (!TypeCheckSlowPath.check(objectHub, hub)) {
+                exception.inc();
+                DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
+            }
+        } else {
+            // if we get an exact match: succeed immediately
+            for (int i = 0; i < hintHubs.length; i++) {
+                Object hintHub = hintHubs[i];
+                if (hintHub == objectHub) {
+                    if (hintsAreExact) {
+                        exact.inc();
+                    } else {
+                        hintsHit.inc();
+                    }
+                    return object;
+                }
+            }
+            if (!hintsAreExact) {
+                if (!TypeCheckSlowPath.check(objectHub, hub)) {
+                    exception.inc();
+                    DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
+                } else {
+                    hintsMissed.inc();
+                }
+            } else {
+                exception.inc();
+                DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
+            }
+        }
+        return object;
+    }
+
     @Fold
     private static int hubOffset() {
         return CompilerImpl.getInstance().getConfig().hubOffset;
     }
+
+    @Fold
+    private static boolean isInterface(RiResolvedType type) {
+        return type.isInterface();
+    }
+
+    public static void printCounter(PrintStream out, Counter c, long total) {
+        double percent = total == 0D ? 0D : ((double) (c.count * 100)) / total;
+        out.println(String.format("%16s: %5.2f%%%10d  // %s", c.name(), percent, c.count, c.description));
+    }
+
+    public static void printCounters(PrintStream out) {
+        if (!Counter.ENABLED) {
+            return;
+        }
+        Counter[] counters = Counter.values();
+        Arrays.sort(counters, new Comparator<Counter>() {
+            @Override
+            public int compare(Counter o1, Counter o2) {
+                if (o1.count > o2.count) {
+                    return -1;
+                } else if (o2.count > o1.count) {
+                    return 1;
+                }
+                return 0;
+            }
+
+        });
+
+        long total = 0;
+        for (Counter c : counters) {
+            total += c.count;
+        }
+
+        out.println();
+        out.println("** Checkcast counters **");
+        for (Counter c : counters) {
+            printCounter(out, c, total);
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/DirectObjectStoreNode.java	Tue May 15 16:27:12 2012 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.snippets;
+
+import com.oracle.graal.cri.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * A special purpose store node that differs from {@link UnsafeStoreNode} in that
+ * it is not a {@link StateSplit} and does not include a write barrier.
+ */
+class DirectObjectStoreNode extends FixedWithNextNode implements Lowerable {
+    @Input private ValueNode object;
+    @Input private ValueNode value;
+    @Input private ValueNode offset;
+    private final int displacement;
+
+    public DirectObjectStoreNode(ValueNode object, int displacement, ValueNode offset, ValueNode value) {
+        super(StampFactory.illegal());
+        this.object = object;
+        this.value = value;
+        this.offset = offset;
+        this.displacement = displacement;
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static void store(Object obj, @ConstantNodeParameter int displacement, long offset, Object value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static void store(Object obj, @ConstantNodeParameter int displacement, long offset, long value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void lower(CiLoweringTool tool) {
+        StructuredGraph graph = (StructuredGraph) this.graph();
+        IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), displacement, offset, graph, false);
+        WriteNode write = graph.add(new WriteNode(object, value, location));
+        graph.replaceFixedWithFixed(this, write);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/DirectStoreNode.java	Tue May 15 16:27:12 2012 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.snippets;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.max.cri.ci.*;
+
+/**
+ * A special purpose store node that differs from {@link UnsafeStoreNode} in that
+ * it is not a {@link StateSplit} and takes a computed address instead of an object.
+ */
+class DirectStoreNode extends FixedWithNextNode implements LIRLowerable {
+    @Input private ValueNode address;
+    @Input private ValueNode value;
+
+    public DirectStoreNode(ValueNode address, ValueNode value) {
+        super(StampFactory.illegal());
+        this.address = address;
+        this.value = value;
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static void store(long address, long value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static void store(long address, boolean value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool gen) {
+        CiValue v = gen.operand(value);
+        gen.emitStore(new CiAddress(v.kind, gen.operand(address)), v, false);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/GetObjectAddressNode.java	Tue May 15 16:27:12 2012 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.snippets;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.max.cri.ci.*;
+
+/**
+ * Intrinsification for getting the address of an object.
+ * The code path(s) between a call to {@link #get(Object)} and all uses
+ * of the returned value must be atomic. The only exception to this is
+ * if the usage is not an attempt to dereference the value.
+ */
+class GetObjectAddressNode extends FixedWithNextNode implements LIRLowerable {
+    @Input private ValueNode object;
+
+    public GetObjectAddressNode(ValueNode obj) {
+        super(StampFactory.forKind(CiKind.Long));
+        this.object = obj;
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static long get(Object array) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool gen) {
+        CiValue obj = gen.newVariable(gen.target().wordKind);
+        gen.emitMove(gen.operand(object), obj);
+        gen.setResult(this, obj);
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64TypeCheckSlowPathOp.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64TypeCheckSlowPathOp.java	Tue May 15 16:27:12 2012 +0200
@@ -38,8 +38,8 @@
  */
 public class AMD64TypeCheckSlowPathOp extends AMD64LIRInstruction {
 
-    public AMD64TypeCheckSlowPathOp(CiValue objectHub, CiValue hub) {
-        super("TYPECHECK_SLOW", new CiValue[] {objectHub}, null, new CiValue[] {objectHub, hub}, NO_OPERANDS, NO_OPERANDS);
+    public AMD64TypeCheckSlowPathOp(CiValue result, CiValue objectHub, CiValue hub) {
+        super("TYPECHECK_SLOW", new CiValue[] {result}, null, new CiValue[] {objectHub, hub}, NO_OPERANDS, NO_OPERANDS);
     }
 
     @Override
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue May 15 16:27:12 2012 +0200
@@ -302,8 +302,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, graphId)));
+        ValueNode v = append(currentGraph.add(new LoadIndexedNode(array, index, kind, graphId)));
         frameState.push(kind.stackKind(), v);
     }
 
@@ -313,8 +312,7 @@
         ValueNode value = frameState.pop(kind.stackKind());
         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, graphId));
+        StoreIndexedNode result = currentGraph.add(new StoreIndexedNode(array, index, kind, value, graphId));
         append(result);
     }
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Tue May 15 16:27:12 2012 +0200
@@ -63,10 +63,14 @@
 
 
     public static class BranchOp extends AMD64LIRInstruction implements StandardOp.BranchOp {
-        protected Condition condition;
+        protected ConditionFlag condition;
         protected LabelRef destination;
 
         public BranchOp(Condition condition, LabelRef destination, LIRDebugInfo info) {
+            this(intCond(condition), destination, info);
+        }
+
+        public BranchOp(ConditionFlag condition, LabelRef destination, LIRDebugInfo info) {
             super("BRANCH", LIRInstruction.NO_OPERANDS, info, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
             this.condition = condition;
             this.destination = destination;
@@ -74,7 +78,7 @@
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            masm.jcc(intCond(condition), destination.label());
+            masm.jcc(condition, destination.label());
         }
 
         @Override
@@ -104,7 +108,7 @@
         protected boolean unorderedIsTrue;
 
         public FloatBranchOp(Condition condition, boolean unorderedIsTrue, LabelRef destination, LIRDebugInfo info) {
-            super(condition, destination, info);
+            super(floatCond(condition), destination, info);
             this.unorderedIsTrue = unorderedIsTrue;
         }
 
@@ -168,11 +172,11 @@
 
 
     public static class CondMoveOp extends AMD64LIRInstruction {
-        private final Condition condition;
+        private final ConditionFlag condition;
 
         public CondMoveOp(Variable result, Condition condition, Variable trueValue, CiValue falseValue) {
             super("CMOVE", new CiValue[] {result}, null, new CiValue[] {falseValue}, new CiValue[] {trueValue}, LIRInstruction.NO_OPERANDS);
-            this.condition = condition;
+            this.condition = intCond(condition);
         }
 
         @Override
@@ -200,12 +204,12 @@
 
 
     public static class FloatCondMoveOp extends AMD64LIRInstruction {
-        private final Condition condition;
+        private final ConditionFlag condition;
         private final boolean unorderedIsTrue;
 
         public FloatCondMoveOp(Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) {
             super("FLOAT_CMOVE", new CiValue[] {result}, null, LIRInstruction.NO_OPERANDS, new CiValue[] {trueValue, falseValue}, LIRInstruction.NO_OPERANDS);
-            this.condition = condition;
+            this.condition = floatCond(condition);
             this.unorderedIsTrue = unorderedIsTrue;
         }
 
@@ -289,30 +293,28 @@
         tasm.targetMethod.addAnnotation(jt);
     }
 
-    private static void floatJcc(AMD64MacroAssembler masm, Condition condition, boolean unorderedIsTrue, Label label) {
-        ConditionFlag cond = floatCond(condition);
+    private static void floatJcc(AMD64MacroAssembler masm, ConditionFlag condition, boolean unorderedIsTrue, Label label) {
         Label endLabel = new Label();
-        if (unorderedIsTrue && !trueOnUnordered(cond)) {
+        if (unorderedIsTrue && !trueOnUnordered(condition)) {
             masm.jcc(ConditionFlag.parity, label);
-        } else if (!unorderedIsTrue && trueOnUnordered(cond)) {
+        } else if (!unorderedIsTrue && trueOnUnordered(condition)) {
             masm.jcc(ConditionFlag.parity, endLabel);
         }
-        masm.jcc(cond, label);
+        masm.jcc(condition, label);
         masm.bind(endLabel);
     }
 
-    private static void cmove(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, boolean isFloat, Condition condition, boolean unorderedIsTrue, CiValue trueValue, CiValue falseValue) {
-        ConditionFlag cond = isFloat ? floatCond(condition) : intCond(condition);
+    private static void cmove(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, boolean isFloat, ConditionFlag condition, boolean unorderedIsTrue, CiValue trueValue, CiValue falseValue) {
         // check that we don't overwrite an input operand before it is used.
         assert !result.equals(trueValue);
 
         AMD64Move.move(tasm, masm, result, falseValue);
-        cmove(tasm, masm, result, cond, trueValue);
+        cmove(tasm, masm, result, condition, trueValue);
 
         if (isFloat) {
-            if (unorderedIsTrue && !trueOnUnordered(cond)) {
+            if (unorderedIsTrue && !trueOnUnordered(condition)) {
                 cmove(tasm, masm, result, ConditionFlag.parity, trueValue);
-            } else if (!unorderedIsTrue && trueOnUnordered(cond)) {
+            } else if (!unorderedIsTrue && trueOnUnordered(condition)) {
                 cmove(tasm, masm, result, ConditionFlag.parity, falseValue);
             }
         }
@@ -347,8 +349,6 @@
             case AE: return ConditionFlag.aboveEqual;
             case AT: return ConditionFlag.above;
             case BT: return ConditionFlag.below;
-            case OF: return ConditionFlag.overflow;
-            case NOF: return ConditionFlag.noOverflow;
             default: throw GraalInternalError.shouldNotReachHere();
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Tue May 15 16:27:12 2012 +0200
@@ -216,7 +216,6 @@
                 // both are constant, this should be canonicalized...
             }
         } else if (kind == CiKind.Int || kind == CiKind.Long) {
-            assert condition != Condition.NOF && condition != Condition.OF;
             if (y().isConstant() && !x().isConstant()) {
                 tool.addScalar(x()).constantBound(condition, y().asConstant());
             } else if (x().isConstant() && !y().isConstant()) {
@@ -236,7 +235,6 @@
     public Result canonical(TypeFeedbackTool tool) {
         CiKind kind = x().kind();
         if (kind == CiKind.Int || kind == CiKind.Long) {
-            assert condition != Condition.NOF && condition != Condition.OF;
             ScalarTypeQuery queryX = tool.queryScalar(x());
             if (y().isConstant() && !x().isConstant()) {
                 if (queryX.constantBound(condition, y().asConstant())) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/Condition.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/Condition.java	Tue May 15 16:27:12 2012 +0200
@@ -78,17 +78,7 @@
     /**
      * Unsigned less than ("below than").
      */
-    BT("|<|"),
-
-    /**
-     * Operation produced an overflow.
-     */
-    OF("overflow"),
-
-    /**
-     * Operation did not produce an overflow.
-     */
-    NOF("noOverflow");
+    BT("|<|");
 
     public final String operator;
 
@@ -109,7 +99,28 @@
             case AT: return UnsignedMath.aboveThan(left, right);
             case BT: return UnsignedMath.belowThan(left, right);
         }
-        throw new IllegalArgumentException();
+        throw new IllegalArgumentException(this.toString());
+    }
+
+    /**
+     * Given a condition and its negation, this method returns true for one of the two and false for the other one.
+     * This can be used to keep comparisons in a canonical form.
+     * @return true if this condition is considered to be the canonical form, false otherwise.
+     */
+    public boolean isCanonical() {
+        switch (this) {
+            case EQ: return true;
+            case NE: return false;
+            case LT: return true;
+            case LE: return false;
+            case GT: return false;
+            case GE: return false;
+            case BT: return true;
+            case BE: return false;
+            case AT: return false;
+            case AE: return false;
+        }
+        throw new IllegalArgumentException(this.toString());
     }
 
     /**
@@ -128,8 +139,6 @@
             case BE: return AT;
             case AT: return BE;
             case AE: return BT;
-            case OF: return NOF;
-            case NOF: return OF;
         }
         throw new IllegalArgumentException(this.toString());
     }
@@ -149,8 +158,6 @@
             case BE: return false;
             case AT: return other == AE || other == NE;
             case AE: return false;
-            case OF: return false;
-            case NOF: return false;
         }
         throw new IllegalArgumentException(this.toString());
     }
@@ -278,9 +285,6 @@
         if (other == this) {
             return this;
         }
-        if (this == OF || this == NOF || other == OF || other == NOF) {
-            return null;
-        }
         switch (this) {
             case EQ:
                 if (other == LE || other == GE || other == BE || other == AE) {
@@ -366,9 +370,6 @@
         if (other == this) {
             return this;
         }
-        if (this == OF || this == NOF || other == OF || other == NOF) {
-            return null;
-        }
         switch (this) {
             case EQ:
                 if (other == LE || other == GE || other == BE || other == AE) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Tue May 15 16:27:12 2012 +0200
@@ -35,7 +35,6 @@
 public abstract class AccessIndexedNode extends AccessArrayNode implements TypeFeedbackProvider {
 
     @Input private ValueNode index;
-    @Input private ValueNode length;
     private final CiKind elementType;
     private final long leafGraphId;
 
@@ -43,22 +42,16 @@
         return index;
     }
 
-    public ValueNode length() {
-        return length;
-    }
-
     /**
      * Create an new AccessIndexedNode.
      * @param kind the result kind of the access
      * @param array the instruction producing the array
      * @param index the instruction producing the index
-     * @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, long leafGraphId) {
+    protected AccessIndexedNode(Stamp stamp, ValueNode array, ValueNode index, CiKind elementKind, long leafGraphId) {
         super(stamp, array);
         this.index = index;
-        this.length = length;
         this.elementType = elementKind;
         this.leafGraphId = leafGraphId;
     }
@@ -78,6 +71,5 @@
     @Override
     public void typeFeedback(TypeFeedbackTool tool) {
         tool.addScalar(index()).constantBound(Condition.GE, CiConstant.INT_0);
-        tool.addScalar(index()).valueBound(Condition.LT, length, tool.queryScalar(length));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Tue May 15 16:27:12 2012 +0200
@@ -42,11 +42,10 @@
      * Creates a new LoadIndexedNode.
      * @param array the instruction producing the array
      * @param index the instruction producing the index
-     * @param length the instruction producing the length
      * @param elementKind the element type
      */
-    public LoadIndexedNode(ValueNode array, ValueNode index, ValueNode length, CiKind elementKind, long leafGraphId) {
-        super(createStamp(array, elementKind), array, index, length, elementKind, leafGraphId);
+    public LoadIndexedNode(ValueNode array, ValueNode index, CiKind elementKind, long leafGraphId) {
+        super(createStamp(array, elementKind), array, index, elementKind, leafGraphId);
     }
 
     private static Stamp createStamp(ValueNode array, CiKind kind) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Tue May 15 16:27:12 2012 +0200
@@ -58,12 +58,11 @@
      * Creates a new StoreIndexedNode.
      * @param array the node producing the array
      * @param index the node producing the index
-     * @param length the node producing the length
      * @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, long leafGraphId) {
-        super(StampFactory.illegal(), array, index, length, elementKind, leafGraphId);
+    public StoreIndexedNode(ValueNode array, ValueNode index, CiKind elementKind, ValueNode value, long leafGraphId) {
+        super(StampFactory.illegal(), array, index, elementKind, leafGraphId);
         this.value = value;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Tue May 15 16:27:12 2012 +0200
@@ -79,7 +79,7 @@
 
     public abstract CiValue emitConvert(ConvertNode.Op opcode, CiValue inputVal);
     public abstract void emitMembar(int barriers);
-    public abstract void emitDeoptimizeOn(Condition cond, RiDeoptAction action, RiDeoptReason reason, Object deoptInfo);
+    public abstract void emitDeoptimizeOnOverflow(RiDeoptAction action, RiDeoptReason reason, Object deoptInfo);
     public abstract void emitDeoptimize(RiDeoptAction action, RiDeoptReason reason, Object deoptInfo, long leafGraphId);
     public abstract CiValue emitCall(Object target, CiKind result, CiKind[] arguments, boolean canTrap, CiValue... args);
     public final CiValue emitCall(CiRuntimeCall runtimeCall, boolean canTrap, CiValue... args) {
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ConditionTest.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ConditionTest.java	Tue May 15 16:27:12 2012 +0200
@@ -40,7 +40,7 @@
         for (Condition c1 : Condition.values()) {
             for (Condition c2 : Condition.values()) {
                 boolean implies = c1.implies(c2);
-                if (implies && c1 != Condition.OF && c2 != Condition.OF && c1 != Condition.NOF && c2 != Condition.NOF) {
+                if (implies) {
                     for (int i = 0; i < 10000; i++) {
                         CiConstant a = CiConstant.forInt(rand.nextInt());
                         CiConstant b = CiConstant.forInt(i < 100 ? a.asInt() : rand.nextInt());
@@ -62,7 +62,7 @@
             for (Condition c2 : Condition.values()) {
                 Condition join = c1.join(c2);
                 assertTrue(join == c2.join(c1));
-                if (join != null && c1 != Condition.OF && c2 != Condition.OF && c1 != Condition.NOF && c2 != Condition.NOF) {
+                if (join != null) {
                     for (int i = 0; i < 10000; i++) {
                         CiConstant a = CiConstant.forInt(rand.nextInt());
                         CiConstant b = CiConstant.forInt(i < 100 ? a.asInt() : rand.nextInt());
@@ -85,7 +85,7 @@
             for (Condition c2 : Condition.values()) {
                 Condition meet = c1.meet(c2);
                 assertTrue(meet == c2.meet(c1));
-                if (meet != null && c1 != Condition.OF && c2 != Condition.OF && c1 != Condition.NOF && c2 != Condition.NOF) {
+                if (meet != null) {
                     for (int i = 0; i < 10000; i++) {
                         CiConstant a = CiConstant.forInt(rand.nextInt());
                         CiConstant b = CiConstant.forInt(i < 100 ? a.asInt() : rand.nextInt());
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java	Tue May 15 16:27:12 2012 +0200
@@ -30,28 +30,18 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
-import com.oracle.max.cri.ri.RiTypeProfile.*;
+import com.oracle.max.cri.ri.RiTypeProfile.ProfiledType;
 
 public class LowerCheckCastTest extends GraphTest {
 
-    static {
-        // Ensure that the methods to be compiled and executed are fully resolved
-        asNumber(0);
-        asString("0");
-        asNumberExt(0);
-        asStringExt("0");
-    }
-
-    private RiCompiledMethod compile(String name, RiTypeProfile profile) {
-        //System.out.println("compiling: " + name + ", hints=" + Arrays.toString(hintClasses) + ", exact=" + exact);
-
-        Method method = getMethod(name);
+    private RiCompiledMethod compile(Method method, RiTypeProfile profile) {
         final StructuredGraph graph = parse(method);
 
         CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first();
-        assert ccn != null;
-        CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.targetClassInstruction(), ccn.targetClass(), ccn.object(), profile));
-        graph.replaceFixedWithFixed(ccn, ccnNew);
+        if (ccn != null) {
+            CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.targetClassInstruction(), ccn.targetClass(), ccn.object(), profile));
+            graph.replaceFixedWithFixed(ccn, ccnNew);
+        }
 
         final RiResolvedMethod riMethod = runtime.getRiMethod(method);
         CiTargetMethod targetMethod = runtime.compile(riMethod, graph);
@@ -69,50 +59,78 @@
         return new RiTypeProfile(0.0D, ptypes);
     }
 
-    private void test(String name, RiTypeProfile profile, Object expected, Object... args) {
-        RiCompiledMethod compiledMethod = compile(name, profile);
-        Assert.assertEquals(expected, compiledMethod.executeVarargs(args));
+    private void test(String name, RiTypeProfile profile, Object... args) {
+        Method method = getMethod(name);
+        Object expect = null;
+        Throwable exception = null;
+        try {
+            // This gives us both the expected return value as well as ensuring that the method to be compiled is fully resolved
+            expect = method.invoke(null, args);
+        } catch (InvocationTargetException e) {
+            exception = e.getTargetException();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        RiCompiledMethod compiledMethod = compile(method, profile);
+        compiledMethod.method();
+
+        if (exception != null) {
+            try {
+                compiledMethod.executeVarargs(args);
+                Assert.fail("expected " + exception);
+            } catch (Throwable e) {
+                Assert.assertEquals(exception.getClass(), e.getClass());
+            }
+        } else {
+            Object actual = compiledMethod.executeVarargs(args);
+            Assert.assertEquals(expect, actual);
+        }
     }
 
     @Test
     public void test1() {
-        test("asNumber",    profile(),                        111, 111);
-        test("asNumber",    profile(Integer.class),           111, 111);
-        test("asNumber",    profile(Long.class, Short.class), 111, 111);
-        test("asNumberExt", profile(),                        121, 111);
-        test("asNumberExt", profile(Integer.class),           121, 111);
-        test("asNumberExt", profile(Long.class, Short.class), 121, 111);
+        test("asNumber",    profile(),                        111);
+        test("asNumber",    profile(Integer.class),           111);
+        test("asNumber",    profile(Long.class, Short.class), 111);
+        test("asNumberExt", profile(),                        111);
+        test("asNumberExt", profile(Integer.class),           111);
+        test("asNumberExt", profile(Long.class, Short.class), 111);
     }
 
     @Test
     public void test2() {
-        test("asString",    profile(),             "111", "111");
-        test("asString",    profile(String.class), "111", "111");
-        test("asString",    profile(String.class), "111", "111");
+        test("asString",    profile(),             "111");
+        test("asString",    profile(String.class), "111");
+        test("asString",    profile(String.class), "111");
 
-        test("asStringExt", profile(),             "#111", "111");
-        test("asStringExt", profile(String.class), "#111", "111");
-        test("asStringExt", profile(String.class), "#111", "111");
-    }
+        final String nullString = null;
+        test("asString",    profile(),             nullString);
+        test("asString",    profile(String.class), nullString);
+        test("asString",    profile(String.class), nullString);
 
-    @Test(expected = ClassCastException.class)
-    public void test3() {
-        test("asNumber", profile(), 111, "111");
+        test("asStringExt", profile(),             "111");
+        test("asStringExt", profile(String.class), "111");
+        test("asStringExt", profile(String.class), "111");
     }
 
-    @Test(expected = ClassCastException.class)
-    public void test4() {
-        test("asString", profile(String.class), "111", 111);
+    @Test
+    public void test3() {
+        test("asNumber", profile(), "111");
     }
 
-    @Test(expected = ClassCastException.class)
-    public void test5() {
-        test("asNumberExt", profile(), 111, "111");
+    @Test
+    public void test4() {
+        test("asString", profile(String.class), 111);
     }
 
-    @Test(expected = ClassCastException.class)
+    @Test
+    public void test5() {
+        test("asNumberExt", profile(), "111");
+    }
+
+    @Test
     public void test6() {
-        test("asStringExt", profile(String.class), "111", 111);
+        test("asStringExt", profile(String.class), 111);
     }
 
     public static Number asNumber(Object o) {
@@ -132,4 +150,16 @@
         String s = (String) o;
         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;
+    }
 }
--- a/graal/com.oracle.max.asm/src/com/oracle/max/asm/target/amd64/AMD64Assembler.java	Tue May 15 16:26:55 2012 +0200
+++ b/graal/com.oracle.max.asm/src/com/oracle/max/asm/target/amd64/AMD64Assembler.java	Tue May 15 16:27:12 2012 +0200
@@ -46,34 +46,60 @@
      * The x86 condition codes used for conditional jumps/moves.
      */
     public enum ConditionFlag {
-        zero(0x4),
-        notZero(0x5),
-        equal(0x4),
-        notEqual(0x5),
-        less(0xc),
-        lessEqual(0xe),
-        greater(0xf),
-        greaterEqual(0xd),
-        below(0x2),
-        belowEqual(0x6),
-        above(0x7),
-        aboveEqual(0x3),
-        overflow(0x0),
-        noOverflow(0x1),
-        carrySet(0x2),
-        carryClear(0x3),
-        negative(0x8),
-        positive(0x9),
-        parity(0xa),
-        noParity(0xb);
+        zero(0x4, "|zero|"),
+        notZero(0x5, "|nzero|"),
+        equal(0x4, "="),
+        notEqual(0x5, "!="),
+        less(0xc, "<"),
+        lessEqual(0xe, "<="),
+        greater(0xf, ">"),
+        greaterEqual(0xd, ">="),
+        below(0x2, "|<|"),
+        belowEqual(0x6, "|<=|"),
+        above(0x7, "|>|"),
+        aboveEqual(0x3, "|>=|"),
+        overflow(0x0, "|of|"),
+        noOverflow(0x1, "|nof|"),
+        carrySet(0x2, "|carry|"),
+        carryClear(0x3, "|ncarry|"),
+        negative(0x8, "|neg|"),
+        positive(0x9, "|pos|"),
+        parity(0xa, "|par|"),
+        noParity(0xb, "|npar|");
 
         public final int value;
-
-        private ConditionFlag(int value) {
+        public final String operator;
+
+        private ConditionFlag(int value, String operator) {
             this.value = value;
+            this.operator = operator;
         }
 
-        public static final ConditionFlag[] values = values();
+        public ConditionFlag negate() {
+            switch(this) {
+                case zero: return notZero;
+                case notZero: return zero;
+                case equal: return notEqual;
+                case notEqual: return equal;
+                case less: return greaterEqual;
+                case lessEqual: return greater;
+                case greater: return lessEqual;
+                case greaterEqual: return less;
+                case below: return aboveEqual;
+                case belowEqual: return above;
+                case above: return belowEqual;
+                case aboveEqual: return below;
+                case overflow: return noOverflow;
+                case noOverflow: return overflow;
+                case carrySet: return carryClear;
+                case carryClear: return carrySet;
+                case negative: return positive;
+                case positive: return negative;
+                case parity: return noParity;
+                case noParity: return parity;
+            }
+            throw new IllegalArgumentException();
+        }
     }
 
     /**
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Tue May 15 16:26:55 2012 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Tue May 15 16:27:12 2012 +0200
@@ -1047,7 +1047,7 @@
 
   if (jap.get_ret_type() == T_VOID) {
     return NULL;
-  } else if (jap.get_ret_type() == T_OBJECT) {
+  } else if (jap.get_ret_type() == T_OBJECT || jap.get_ret_type() == T_ARRAY) {
     return JNIHandles::make_local((oop) result.get_jobject());
   } else {
     oop o = java_lang_boxing_object::create(jap.get_ret_type(), (jvalue *) result.get_value_addr(), CHECK_NULL);