# HG changeset patch # User Gilles Duboscq # Date 1337092032 -7200 # Node ID 128b3f57499115a3a0da8c89903ee8efecf8c0cf # Parent c574c454079136b3fd5665a84f1dca67ca07c843# Parent 206df7b3e022c742ff6167ff23b14c524dad56d7 Merge diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java --- 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. diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java --- 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); + } } } } diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java --- 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)); } diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java --- 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); } diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- 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) { diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TypeCheckSlowPath.java --- 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"); } diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java --- 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 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)); } diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java --- 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); } diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java --- 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); } diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java --- 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() { + @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); + } + } } diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/DirectObjectStoreNode.java --- /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); + } +} diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/DirectStoreNode.java --- /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); + } +} diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/GetObjectAddressNode.java --- /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); + } +} diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64TypeCheckSlowPathOp.java --- 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 diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- 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); } diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java --- 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(); } } diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java --- 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())) { diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/Condition.java --- 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) { diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java --- 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)); } } diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java --- 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) { diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java --- 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; } diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java --- 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) { diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ConditionTest.java --- 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()); diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java --- 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; + } } diff -r 206df7b3e022 -r 128b3f574991 graal/com.oracle.max.asm/src/com/oracle/max/asm/target/amd64/AMD64Assembler.java --- 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(); + } } /** diff -r 206df7b3e022 -r 128b3f574991 src/share/vm/graal/graalCompilerToVM.cpp --- 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);