# HG changeset patch # User Lukas Stadler # Date 1336652665 -7200 # Node ID 31ec401eb5922e00c4278bb5752e84b825866c67 # Parent 4485e0edd1af42f5d1a610ce34f514f26237f1b8# Parent c7f92c6246ba0d4d00b8076f6e1d7bc276c10f76 Merge diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Thu May 10 14:24:25 2012 +0200 @@ -90,7 +90,7 @@ }); final FrameMap frameMap = Debug.scope("BackEnd", lir, new Callable() { public FrameMap call() { - return emitLIR(lir, graph, method); + return emitLIR(lir, graph, method, assumptions); } }); return Debug.scope("CodeGen", frameMap, new Callable() { @@ -235,9 +235,9 @@ }); } - public FrameMap emitLIR(final LIR lir, StructuredGraph graph, final RiResolvedMethod method) { + public FrameMap emitLIR(final LIR lir, StructuredGraph graph, final RiResolvedMethod method, CiAssumptions assumptions) { final FrameMap frameMap = backend.newFrameMap(runtime.getRegisterConfig(method)); - final LIRGenerator lirGenerator = backend.newLIRGenerator(graph, frameMap, method, lir, xir); + final LIRGenerator lirGenerator = backend.newLIRGenerator(graph, frameMap, method, lir, xir, assumptions); Debug.scope("LIRGen", lirGenerator, new Runnable() { public void run() { diff -r c7f92c6246ba -r 31ec401eb592 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 Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Thu May 10 14:24:25 2012 +0200 @@ -246,6 +246,14 @@ */ public static int CheckcastMaxHints = 2; + /** + * @see #CheckcastMinHintHitProbability + */ + public static double InstanceOfMinHintHitProbability = 0.5; + + /** + * @see #CheckcastMaxHints + */ public static int InstanceOfMaxHints = 1; /** diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Thu May 10 14:24:25 2012 +0200 @@ -141,7 +141,7 @@ private LockScope curLocks; - public LIRGenerator(Graph graph, RiRuntime runtime, CiTarget target, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir) { + public LIRGenerator(Graph graph, RiRuntime runtime, CiTarget target, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir, CiAssumptions assumptions) { this.graph = graph; this.runtime = runtime; this.target = target; @@ -150,7 +150,7 @@ this.nodeOperands = graph.createNodeMap(); this.lir = lir; this.xir = xir; - this.xirSupport = new XirSupport(); + this.xirSupport = new XirSupport(assumptions); this.debugInfoBuilder = new DebugInfoBuilder(nodeOperands); this.blockLocks = new BlockMap<>(lir.cfg); this.blockLastState = new BlockMap<>(lir.cfg); @@ -509,7 +509,7 @@ @Override public void visitCheckCast(CheckCastNode x) { - XirSnippet snippet = xir.genCheckCast(site(x, x.object()), toXirArgument(x.object()), toXirArgument(x.targetClassInstruction()), x.targetClass(), x.hints(), x.hintsExact()); + XirSnippet snippet = xir.genCheckCast(site(x, x.object()), toXirArgument(x.object()), toXirArgument(x.targetClassInstruction()), x.targetClass(), x.profile()); emitXir(snippet, x, state(), true); // The result of a checkcast is the unmodified object, so no need to allocate a new variable for it. setResult(x, operand(x.object())); @@ -716,7 +716,7 @@ private void emitInstanceOfBranch(InstanceOfNode x, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) { XirArgument obj = toXirArgument(x.object()); - XirSnippet snippet = xir.genInstanceOf(site(x, x.object()), obj, toXirArgument(x.targetClassInstruction()), x.targetClass(), x.hints(), x.hintsExact()); + XirSnippet snippet = xir.genInstanceOf(site(x, x.object()), obj, toXirArgument(x.targetClassInstruction()), x.targetClass(), x.profile()); emitXir(snippet, x, info, null, false, x.negated() ? falseSuccessor : trueSuccessor, x.negated() ? trueSuccessor : falseSuccessor); } @@ -767,7 +767,7 @@ XirArgument obj = toXirArgument(x.object()); XirArgument trueArg = toXirArgument(x.negated() ? falseValue : trueValue); XirArgument falseArg = toXirArgument(x.negated() ? trueValue : falseValue); - XirSnippet snippet = xir.genMaterializeInstanceOf(site(x, x.object()), obj, toXirArgument(x.targetClassInstruction()), trueArg, falseArg, x.targetClass(), x.hints(), x.hintsExact()); + XirSnippet snippet = xir.genMaterializeInstanceOf(site(x, x.object()), obj, toXirArgument(x.targetClassInstruction()), trueArg, falseArg, x.targetClass(), x.profile()); return (Variable) emitXir(snippet, null, null, false); } @@ -1358,9 +1358,15 @@ * Implements site-specific information for the XIR interface. */ static class XirSupport implements XirSite { + final CiAssumptions assumptions; ValueNode current; ValueNode receiver; + + public XirSupport(CiAssumptions assumptions) { + this.assumptions = assumptions; + } + public boolean isNonNull(XirArgument argument) { return false; } @@ -1385,6 +1391,10 @@ return true; } + public CiAssumptions assumptions() { + return assumptions; + } + XirSupport site(ValueNode v, ValueNode r) { current = v; receiver = r; diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java Thu May 10 14:24:25 2012 +0200 @@ -255,7 +255,10 @@ assert false : "unexpected checkcast usage: " + checkCastUsage; } } - checkCastNode.safeDelete(); + FixedNode next = checkCastNode.next(); + checkCastNode.setNext(null); + checkCastNode.replaceAtPredecessors(next); + GraphUtil.killCFG(checkCastNode); } } } diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Thu May 10 14:24:25 2012 +0200 @@ -72,7 +72,7 @@ return new FrameMap(runtime, target, registerConfig); } - public abstract LIRGenerator newLIRGenerator(Graph graph, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir); + public abstract LIRGenerator newLIRGenerator(Graph graph, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir, CiAssumptions assumptions); public abstract TargetMethodAssembler newAssembler(FrameMap frameMap, LIR lir); diff -r c7f92c6246ba -r 31ec401eb592 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 Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java Thu May 10 14:24:25 2012 +0200 @@ -96,8 +96,8 @@ } } - public AMD64LIRGenerator(Graph graph, RiRuntime runtime, CiTarget target, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir) { - super(graph, runtime, target, frameMap, method, lir, xir); + public AMD64LIRGenerator(Graph graph, RiRuntime runtime, CiTarget target, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir, CiAssumptions assumptions) { + super(graph, runtime, target, frameMap, method, lir, xir, assumptions); lir.spillMoveFactory = new AMD64SpillMoveFactory(); } diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java Thu May 10 14:24:25 2012 +0200 @@ -228,7 +228,12 @@ } } ValueNode replacement = canonical.replacement; - currentGraph.replaceFloating((FloatingNode) node, replacement); + if (node instanceof FloatingNode) { + currentGraph.replaceFloating((FloatingNode) node, replacement); + } else { + assert node instanceof FixedWithNextNode; + currentGraph.replaceFixed((FixedWithNextNode) node, replacement); + } changedNodes.addAll(replacement.usages()); } } diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/Util.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/Util.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/Util.java Thu May 10 14:24:25 2012 +0200 @@ -22,15 +22,13 @@ */ package com.oracle.graal.compiler.util; -import java.lang.reflect.*; import java.util.*; -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ri.*; -import com.oracle.max.criutils.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.criutils.*; /** * The {@code Util} class contains a motley collection of utility methods used throughout the compiler. @@ -357,8 +355,4 @@ public static boolean isFloating(Node n) { return n instanceof FloatingNode; } - - public static boolean isFinalClass(RiResolvedType type) { - return Modifier.isFinal(type.accessFlags()) || (type.isArrayClass() && Modifier.isFinal(type.componentType().accessFlags())); - } } diff -r c7f92c6246ba -r 31ec401eb592 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 Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Thu May 10 14:24:25 2012 +0200 @@ -160,8 +160,6 @@ } } - - /** * This method is the first method compiled during bootstrapping. Put any code in there that warms up compiler paths * that are otherwise not exercised during bootstrapping and lead to later deoptimization when application code is @@ -237,18 +235,27 @@ compileMethod((HotSpotMethodResolved) riMethod, 0, false, 10); } + private static void shutdownCompileQueue(ThreadPoolExecutor queue) throws InterruptedException { + if (queue != null) { + queue.shutdown(); + if (Debug.isEnabled() && GraalOptions.Dump != null) { + // Wait 5 seconds to try and flush out all graph dumps + queue.awaitTermination(5, TimeUnit.SECONDS); + } + } + } + public void shutdownCompiler() throws Throwable { try { assert !CompilationTask.withinEnqueue.get(); CompilationTask.withinEnqueue.set(Boolean.TRUE); - compileQueue.shutdown(); - if (slowCompileQueue != null) { - slowCompileQueue.shutdown(); - } + shutdownCompileQueue(compileQueue); + shutdownCompileQueue(slowCompileQueue); } finally { CompilationTask.withinEnqueue.set(Boolean.FALSE); } + if (Debug.isEnabled()) { List topLevelMaps = DebugValueMap.getTopLevelMaps(); List debugValues = KeyRegistry.getDebugValues(); diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodData.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodData.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodData.java Thu May 10 14:24:25 2012 +0200 @@ -386,7 +386,7 @@ Arrays.sort(ptypes); double notRecordedTypeProbability = entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); - return new RiTypeProfile(ptypes, notRecordedTypeProbability); + return new RiTypeProfile(notRecordedTypeProbability, ptypes); } private static int getReceiverOffset(int row) { diff -r c7f92c6246ba -r 31ec401eb592 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 Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java Thu May 10 14:24:25 2012 +0200 @@ -336,21 +336,21 @@ if (array.exactType() != null) { RiResolvedType elementType = array.exactType().componentType(); if (elementType.superType() != null) { - AnchorNode anchor = graph.add(new AnchorNode()); - graph.addBeforeFixed(storeIndexed, anchor); ConstantNode type = ConstantNode.forCiConstant(elementType.getEncoding(Representation.ObjectHub), this, graph); - value = graph.unique(new CheckCastNode(anchor, type, elementType, value)); + CheckCastNode checkcast = graph.add(new CheckCastNode(type, elementType, value)); + graph.addBeforeFixed(storeIndexed, checkcast); + value = checkcast; } else { assert elementType.name().equals("Ljava/lang/Object;") : elementType.name(); } } else { - AnchorNode anchor = graph.add(new AnchorNode()); - graph.addBeforeFixed(storeIndexed, anchor); GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(array, false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID); FloatingReadNode arrayClass = graph.unique(new FloatingReadNode(array, null, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph), StampFactory.objectNonNull())); arrayClass.setGuard(guard); FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, null, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.arrayClassElementOffset, graph), StampFactory.objectNonNull())); - value = graph.unique(new CheckCastNode(anchor, arrayElementKlass, null, value)); + CheckCastNode checkcast = graph.add(new CheckCastNode(arrayElementKlass, null, value)); + graph.addBeforeFixed(storeIndexed, checkcast); + value = checkcast; } } WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation)); diff -r c7f92c6246ba -r 31ec401eb592 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 Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java Thu May 10 14:24:25 2012 +0200 @@ -45,6 +45,7 @@ import com.oracle.max.cri.xir.CiXirAssembler.XirMark; import com.oracle.max.cri.xir.CiXirAssembler.XirOperand; import com.oracle.max.cri.xir.CiXirAssembler.XirParameter; +import com.oracle.max.criutils.*; public class HotSpotXirGenerator implements RiXirGenerator { @@ -806,9 +807,11 @@ } @Override - public XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiResolvedType type, RiResolvedType[] hints, boolean hintsExact) { + public XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiResolvedType type, RiTypeProfile profile) { final boolean useCounters = GraalOptions.CheckcastCounters; - if (hints == null || hints.length == 0) { + TypeCheckHints hints = new TypeCheckHints(type, profile, site.assumptions(), GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints); + int hintsLength = hints.types.length; + if (hintsLength == 0) { if (useCounters) { if (type == null) { return new XirSnippet(checkCastTemplates.get(site, 0, NULL_TYPE), XirArgument.forObject(checkcastCounters), receiver, hub); @@ -821,59 +824,63 @@ return new XirSnippet(checkCastTemplates.get(site, 0), receiver, hub); } } else { - XirArgument[] params = new XirArgument[(useCounters ? 1 : 0) + hints.length + (hintsExact ? 1 : 2)]; + XirArgument[] params = new XirArgument[(useCounters ? 1 : 0) + hintsLength + (hints.exact ? 1 : 2)]; int i = 0; if (useCounters) { params[i++] = XirArgument.forObject(checkcastCounters); } params[i++] = receiver; - if (!hintsExact) { + if (!hints.exact) { params[i++] = hub; } - for (RiResolvedType hint : hints) { + for (RiResolvedType hint : hints.types) { params[i++] = XirArgument.forObject(((HotSpotType) hint).klassOop()); } - XirTemplate template = hintsExact ? checkCastTemplates.get(site, hints.length, EXACT_HINTS) : checkCastTemplates.get(site, hints.length); + XirTemplate template = hints.exact ? checkCastTemplates.get(site, hintsLength, EXACT_HINTS) : checkCastTemplates.get(site, hintsLength); return new XirSnippet(template, params); } } @Override - public XirSnippet genInstanceOf(XirSite site, XirArgument object, XirArgument hub, RiType type, RiResolvedType[] hints, boolean hintsExact) { - if (hints == null || hints.length == 0) { + public XirSnippet genInstanceOf(XirSite site, XirArgument object, XirArgument hub, RiResolvedType type, RiTypeProfile profile) { + TypeCheckHints hints = new TypeCheckHints(type, profile, site.assumptions(), GraalOptions.InstanceOfMinHintHitProbability, GraalOptions.InstanceOfMaxHints); + int hintsLength = hints.types.length; + if (hintsLength == 0) { return new XirSnippet(instanceOfTemplates.get(site, 0), object, hub); } else { - XirArgument[] params = new XirArgument[hints.length + (hintsExact ? 1 : 2)]; + XirArgument[] params = new XirArgument[hintsLength + (hints.exact ? 1 : 2)]; int i = 0; params[i++] = object; - if (!hintsExact) { + if (!hints.exact) { params[i++] = hub; } - for (RiResolvedType hint : hints) { + for (RiResolvedType hint : hints.types) { params[i++] = XirArgument.forObject(((HotSpotType) hint).klassOop()); } - XirTemplate template = hintsExact ? instanceOfTemplates.get(site, hints.length, EXACT_HINTS) : instanceOfTemplates.get(site, hints.length); + XirTemplate template = hints.exact ? instanceOfTemplates.get(site, hintsLength, EXACT_HINTS) : instanceOfTemplates.get(site, hintsLength); return new XirSnippet(template, params); } } @Override - public XirSnippet genMaterializeInstanceOf(XirSite site, XirArgument object, XirArgument hub, XirArgument trueValue, XirArgument falseValue, RiType type, RiResolvedType[] hints, boolean hintsExact) { - if (hints == null || hints.length == 0) { + public XirSnippet genMaterializeInstanceOf(XirSite site, XirArgument object, XirArgument hub, XirArgument trueValue, XirArgument falseValue, RiResolvedType type, RiTypeProfile profile) { + TypeCheckHints hints = new TypeCheckHints(type, profile, site.assumptions(), GraalOptions.InstanceOfMinHintHitProbability, GraalOptions.InstanceOfMaxHints); + int hintsLength = hints.types.length; + if (hintsLength == 0) { return new XirSnippet(materializeInstanceOfTemplates.get(site, 0), object, hub, trueValue, falseValue); } else { - XirArgument[] params = new XirArgument[hints.length + (hintsExact ? 3 : 4)]; + XirArgument[] params = new XirArgument[hintsLength + (hints.exact ? 3 : 4)]; int i = 0; params[i++] = object; - if (!hintsExact) { + if (!hints.exact) { params[i++] = hub; } params[i++] = trueValue; params[i++] = falseValue; - for (RiResolvedType hint : hints) { + for (RiResolvedType hint : hints.types) { params[i++] = XirArgument.forObject(((HotSpotType) hint).klassOop()); } - XirTemplate template = hintsExact ? materializeInstanceOfTemplates.get(site, hints.length, EXACT_HINTS) : materializeInstanceOfTemplates.get(site, hints.length); + XirTemplate template = hints.exact ? materializeInstanceOfTemplates.get(site, hintsLength, EXACT_HINTS) : materializeInstanceOfTemplates.get(site, hintsLength); return new XirSnippet(template, params); } } diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/LowerCheckCastPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/LowerCheckCastPhase.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/LowerCheckCastPhase.java Thu May 10 14:24:25 2012 +0200 @@ -24,6 +24,7 @@ import java.util.*; +import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate; import com.oracle.graal.compiler.util.*; @@ -35,6 +36,7 @@ import com.oracle.graal.nodes.java.*; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; +import com.oracle.max.criutils.*; /** * Lowers a {@link CheckCastNode} by replacing it with the graph of a {@linkplain CheckCastSnippets checkcast snippet}. @@ -63,19 +65,19 @@ for (CheckCastNode node : graph.getNodes(CheckCastNode.class)) { ValueNode hub = node.targetClassInstruction(); ValueNode object = node.object(); - RiResolvedType[] hints = node.hints(); + CiAssumptions assumptions = null; + TypeCheckHints hints = new TypeCheckHints(node.targetClass(), node.profile(), assumptions, GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints); StructuredGraph snippetGraph = (StructuredGraph) checkcast.compilerStorage().get(Graph.class); assert snippetGraph != null : CheckCastSnippets.class.getSimpleName() + " should be installed"; - HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.length]; + HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.types.length]; for (int i = 0; i < hintHubs.length; i++) { - hintHubs[i] = ((HotSpotType) hints[i]).klassOop(); + hintHubs[i] = ((HotSpotType) hints.types[i]).klassOop(); } - assert !node.hintsExact() || hints.length > 0 : "cannot have 0 exact hints!"; final CiConstant hintHubsConst = CiConstant.forObject(hintHubs); hintHubsSet.put(hintHubsConst, hintHubsConst); - Debug.log("Lowering checkcast in %s: node=%s, hintsHubs=%s, exact=%b", graph, node, Arrays.toString(hints), node.hintsExact()); + Debug.log("Lowering checkcast in %s: node=%s, hintsHubs=%s, exact=%b", graph, node, Arrays.toString(hints.types), hints.exact); - InliningUtil.inlineSnippet(runtime, node, (FixedWithNextNode) node.anchor(), snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(node.hintsExact())); + InliningUtil.inlineSnippet(runtime, node, node, snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(hints.exact)); } if (!hintHubsSet.isEmpty()) { Debug.log("Lowered %d checkcasts in %s ", hintHubsSet.size(), graph); diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java Thu May 10 14:24:25 2012 +0200 @@ -56,8 +56,8 @@ } @Override - public LIRGenerator newLIRGenerator(Graph graph, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir) { - return new AMD64LIRGenerator(graph, runtime, target, frameMap, method, lir, xir) { + public LIRGenerator newLIRGenerator(Graph graph, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir, CiAssumptions assumptions) { + return new AMD64LIRGenerator(graph, runtime, target, frameMap, method, lir, xir, assumptions) { @Override public void visitSafepointNode(SafepointNode i) { diff -r c7f92c6246ba -r 31ec401eb592 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 Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Thu May 10 14:24:25 2012 +0200 @@ -255,7 +255,7 @@ FrameStateBuilder dispatchState = frameState.copy(); dispatchState.clearStack(); - BeginNode dispatchBegin = currentGraph.add(new BeginStateSplitNode()); + BeginNode dispatchBegin = currentGraph.add(new DispatchBeginNode()); dispatchBegin.setStateAfter(dispatchState.create(bci)); if (exceptionObject == null) { @@ -590,40 +590,15 @@ } } - private static final RiResolvedType[] EMPTY_TYPE_ARRAY = new RiResolvedType[0]; - - private RiResolvedType[] getTypeCheckHints(RiResolvedType type, int maxHints) { - if (!optimisticOpts.useTypeCheckHints() || Util.isFinalClass(type)) { - return new RiResolvedType[] {type}; + private RiTypeProfile getProfileForTypeCheck(RiResolvedType type) { + if (!optimisticOpts.useTypeCheckHints() || TypeCheckHints.isFinalClass(type)) { + return null; } else { RiResolvedType uniqueSubtype = type.uniqueConcreteSubtype(); if (uniqueSubtype != null) { - return new RiResolvedType[] {uniqueSubtype}; + return new RiTypeProfile(0.0D, new ProfiledType(uniqueSubtype, 1.0D)); } else { - RiTypeProfile typeProfile = profilingInfo.getTypeProfile(bci()); - if (typeProfile != null) { - double notRecordedTypes = typeProfile.getNotRecordedProbability(); - ProfiledType[] ptypes = typeProfile.getTypes(); - if (notRecordedTypes < (1D - GraalOptions.CheckcastMinHintHitProbability) && ptypes != null && ptypes.length > 0) { - RiResolvedType[] hints = new RiResolvedType[ptypes.length]; - int hintCount = 0; - double totalHintProbability = 0.0d; - for (ProfiledType ptype : ptypes) { - RiResolvedType hint = ptype.type; - if (hint.isSubtypeOf(type)) { - hints[hintCount++] = hint; - totalHintProbability += ptype.probability; - } - } - if (totalHintProbability >= GraalOptions.CheckcastMinHintHitProbability) { - if (hints.length == hintCount && hintCount <= maxHints) { - return hints; - } - return Arrays.copyOf(hints, Math.min(maxHints, hintCount)); - } - } - } - return EMPTY_TYPE_ARRAY; + return profilingInfo.getTypeProfile(bci()); } } } @@ -635,13 +610,8 @@ if (initialized) { ConstantNode typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, true); ValueNode object = frameState.apop(); - AnchorNode anchor = currentGraph.add(new AnchorNode()); - append(anchor); - CheckCastNode checkCast; - RiResolvedType[] hints = getTypeCheckHints((RiResolvedType) type, GraalOptions.CheckcastMaxHints); - boolean hintsExact = Util.isFinalClass((RiResolvedType) type); - checkCast = currentGraph.unique(new CheckCastNode(anchor, typeInstruction, (RiResolvedType) type, object, hints, hintsExact)); - append(currentGraph.add(new ValueAnchorNode(checkCast))); + CheckCastNode checkCast = currentGraph.add(new CheckCastNode(typeInstruction, (RiResolvedType) type, object, getProfileForTypeCheck((RiResolvedType) type))); + append(checkCast); frameState.apush(checkCast); } else { ValueNode object = frameState.apop(); @@ -657,9 +627,7 @@ if (type instanceof RiResolvedType) { RiResolvedType resolvedType = (RiResolvedType) type; ConstantNode hub = appendConstant(resolvedType.getEncoding(RiType.Representation.ObjectHub)); - - RiResolvedType[] hints = getTypeCheckHints(resolvedType, GraalOptions.InstanceOfMaxHints); - InstanceOfNode instanceOfNode = new InstanceOfNode(hub, (RiResolvedType) type, object, hints, Util.isFinalClass(resolvedType), false); + InstanceOfNode instanceOfNode = new InstanceOfNode(hub, (RiResolvedType) type, object, getProfileForTypeCheck(resolvedType), false); frameState.ipush(append(MaterializeNode.create(currentGraph.unique(instanceOfNode), currentGraph))); } else { BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode()); diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java Thu May 10 14:24:25 2012 +0200 @@ -25,7 +25,7 @@ /** * Base class for {@link BeginNode}s that are associated with a frame state. */ -public class BeginStateSplitNode extends BeginNode implements StateSplit { +public abstract class BeginStateSplitNode extends BeginNode implements StateSplit { /** * A begin node has no side effect. diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DispatchBeginNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DispatchBeginNode.java Thu May 10 14:24:25 2012 +0200 @@ -0,0 +1,30 @@ +/* + * 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.nodes; + +/** + * The entry node of an exception dispatcher block. + */ +public class DispatchBeginNode extends BeginStateSplitNode { + +} diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java Thu May 10 14:24:25 2012 +0200 @@ -29,6 +29,17 @@ import com.oracle.graal.nodes.type.*; import com.oracle.max.cri.ri.*; +/** + * A guard is a node that deoptimizes based on a conditional expression. Guards are not attached to a certain frame + * state, they can move around freely and will always use the correct frame state when the nodes are scheduled (i.e., + * the last emitted frame state). The node that is guarded has a data dependency on the guard and the guard in turn has + * a data dependency on the condition. A guard may only be executed if it is guaranteed that the guarded node is + * executed too (if no exceptions are thrown). Therefore, an {@linkplain AnchorNode anchor} is placed after a control + * flow split and the guard has a data dependency to the anchor. The anchor is the most distant node that is + * post-dominated by the guarded node and the guard can be scheduled anywhere between those two nodes. This ensures + * maximum flexibility for the guard node and guarantees that deoptimization occurs only if the control flow would have + * reached the guarded node (without taking exceptions into account). + */ public final class GuardNode extends FloatingNode implements Canonicalizable, LIRLowerable, TypeFeedbackProvider, Node.IterableNodeType { @Input private BooleanNode condition; diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java Thu May 10 14:24:25 2012 +0200 @@ -0,0 +1,30 @@ +/* + * 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.nodes; + +/** + * The start node of a graph. + */ +public class StartNode extends BeginStateSplitNode { + +} diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Thu May 10 14:24:25 2012 +0200 @@ -64,7 +64,7 @@ private StructuredGraph(String name, RiResolvedMethod method, long graphId) { super(name); - this.start = add(new BeginStateSplitNode()); + this.start = add(new StartNode()); this.method = method; this.graphId = graphId; } diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Thu May 10 14:24:25 2012 +0200 @@ -25,7 +25,6 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.spi.types.*; import com.oracle.graal.nodes.type.*; @@ -33,32 +32,31 @@ import com.oracle.max.cri.ri.*; /** - * The {@code CheckCastNode} represents a {@link Bytecodes#CHECKCAST}. - * - * The {@link #targetClass()} of a CheckCastNode can be null for array store checks! + * Implements a type check that results in a {@link ClassCastException} if it fails. */ -public final class CheckCastNode extends TypeCheckNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType, TypeFeedbackProvider, TypeCanonicalizable { +public final class CheckCastNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType, TypeFeedbackProvider, TypeCanonicalizable { - @Input(notDataflow = true) protected final FixedNode anchor; - - public FixedNode anchor() { - return anchor; - } + @Input private ValueNode object; + @Input private ValueNode targetClassInstruction; + private final RiResolvedType targetClass; + private final RiTypeProfile profile; /** * Creates a new CheckCast instruction. - * * @param targetClassInstruction the instruction which produces the class which is being cast to * @param targetClass the class being cast to * @param object the instruction producing the object */ - public CheckCastNode(FixedNode anchor, ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object) { - this(anchor, targetClassInstruction, targetClass, object, EMPTY_HINTS, false); + public CheckCastNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object) { + this(targetClassInstruction, targetClass, object, null); } - public CheckCastNode(FixedNode anchor, ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiResolvedType[] hints, boolean hintsExact) { - super(targetClassInstruction, targetClass, object, hints, hintsExact, targetClass == null ? StampFactory.forKind(CiKind.Object) : StampFactory.declared(targetClass)); - this.anchor = anchor; + public CheckCastNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiTypeProfile profile) { + super(targetClass == null ? StampFactory.forKind(CiKind.Object) : StampFactory.declared(targetClass)); + this.targetClassInstruction = targetClassInstruction; + this.targetClass = targetClass; + this.object = object; + this.profile = profile; } @Override @@ -71,10 +69,8 @@ assert object() != null : this; RiResolvedType objectDeclaredType = object().declaredType(); - RiResolvedType targetClass = targetClass(); if (objectDeclaredType != null && targetClass != null && objectDeclaredType.isSubtypeOf(targetClass)) { // we don't have to check for null types here because they will also pass the checkcast. - freeAnchor(); return object(); } @@ -82,33 +78,12 @@ if (constant != null) { assert constant.kind == CiKind.Object; if (constant.isNull()) { - freeAnchor(); return object(); } } - - if (tool.assumptions() != null && hints() != null && targetClass() != null) { - if (!hintsExact() && hints().length == 1 && hints()[0] == targetClass().uniqueConcreteSubtype()) { - tool.assumptions().recordConcreteSubtype(targetClass(), hints()[0]); - return graph().unique(new CheckCastNode(anchor, targetClassInstruction(), targetClass(), object(), hints(), true)); - } - } return this; } - // TODO (thomaswue): Find a better way to handle anchors. - private void freeAnchor() { - ValueAnchorNode anchorUsage = usages().filter(ValueAnchorNode.class).first(); - if (anchorUsage != null) { - anchorUsage.replaceFirstInput(this, null); - } - } - - @Override - public BooleanNode negate() { - throw new Error("A CheckCast does not produce a boolean value, so it should actually not be a subclass of BooleanNode"); - } - @Override public void typeFeedback(TypeFeedbackTool tool) { if (targetClass() != null) { @@ -128,4 +103,27 @@ } return null; } + + public ValueNode object() { + return object; + } + + public ValueNode targetClassInstruction() { + return targetClassInstruction; + } + + /** + * Gets the target class, i.e. the class being cast to, or the class being tested against. + * This may be null in the case where the type being tested is dynamically loaded such as + * when checking an object array store. + * + * @return the target class or null if not known + */ + public RiResolvedType targetClass() { + return targetClass; + } + + public RiTypeProfile profile() { + return profile; + } } diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Thu May 10 14:24:25 2012 +0200 @@ -33,9 +33,13 @@ /** * The {@code InstanceOfNode} represents an instanceof test. */ -public final class InstanceOfNode extends TypeCheckNode implements Canonicalizable, LIRLowerable, ConditionalTypeFeedbackProvider, TypeCanonicalizable { +public final class InstanceOfNode extends BooleanNode implements Canonicalizable, LIRLowerable, ConditionalTypeFeedbackProvider, TypeCanonicalizable { private final boolean negated; + @Input private ValueNode object; + @Input private ValueNode targetClassInstruction; + private final RiResolvedType targetClass; + private final RiTypeProfile profile; public boolean negated() { return negated; @@ -49,11 +53,15 @@ * @param object the instruction producing the object input to this instruction */ public InstanceOfNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, boolean negated) { - this(targetClassInstruction, targetClass, object, EMPTY_HINTS, false, negated); + this(targetClassInstruction, targetClass, object, null, negated); } - public InstanceOfNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiResolvedType[] hints, boolean hintsExact, boolean negated) { - super(targetClassInstruction, targetClass, object, hints, hintsExact, StampFactory.illegal()); + public InstanceOfNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiTypeProfile profile, boolean negated) { + super(StampFactory.illegal()); + this.targetClassInstruction = targetClassInstruction; + this.targetClass = targetClass; + this.object = object; + this.profile = profile; this.negated = negated; assert targetClass != null; } @@ -112,18 +120,12 @@ assert false : "non-null constants are always expected to provide an exactType"; } } - if (tool.assumptions() != null && hints() != null && targetClass() != null) { - if (!hintsExact() && hints().length == 1 && hints()[0] == targetClass().uniqueConcreteSubtype()) { - tool.assumptions().recordConcreteSubtype(targetClass(), hints()[0]); - return graph().unique(new InstanceOfNode(targetClassInstruction(), targetClass(), object(), hints(), true, negated)); - } - } return this; } @Override public BooleanNode negate() { - return graph().unique(new InstanceOfNode(targetClassInstruction(), targetClass(), object(), hints(), hintsExact(), !negated)); + return graph().unique(new InstanceOfNode(targetClassInstruction(), targetClass(), object(), profile(), !negated)); } @Override @@ -161,4 +163,24 @@ } return null; } + + public ValueNode object() { + return object; + } + + public ValueNode targetClassInstruction() { + return targetClassInstruction; + } + + /** + * Gets the target class, i.e. the class being cast to, or the class being tested against. + * @return the target class + */ + public RiResolvedType targetClass() { + return targetClass; + } + + public RiTypeProfile profile() { + return profile; + } } diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java Wed May 09 12:11:36 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2009, 2011, 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.nodes.java; - -import com.oracle.max.cri.ri.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; - -/** - * The {@code TypeCheckNode} is the base class of casts and instanceof tests. - */ -public abstract class TypeCheckNode extends BooleanNode { - - protected static final RiResolvedType[] EMPTY_HINTS = new RiResolvedType[0]; - @Input private ValueNode object; - @Input private ValueNode targetClassInstruction; - private final RiResolvedType targetClass; - private final RiResolvedType[] hints; - private final boolean hintsExact; - - /** - * Creates a new TypeCheckNode. - * @param targetClassInstruction the instruction which produces the class which is being cast to or checked against - * @param targetClass the class that is being casted to or checked against - * @param object the node which produces the object - * @param kind the result type of this node - */ - public TypeCheckNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiResolvedType[] hints, boolean hintsExact, Stamp stamp) { - super(stamp); - this.targetClassInstruction = targetClassInstruction; - this.targetClass = targetClass; - this.object = object; - this.hints = hints; - this.hintsExact = hintsExact; - } - - public ValueNode object() { - return object; - } - - public ValueNode targetClassInstruction() { - return targetClassInstruction; - } - - /** - * Gets the target class, i.e. the class being cast to, or the class being tested against. - * @return the target class - */ - public RiResolvedType targetClass() { - return targetClass; - } - - public RiResolvedType[] hints() { - return hints; - } - - public boolean hintsExact() { - return hintsExact; - } -} diff -r c7f92c6246ba -r 31ec401eb592 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 Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java Thu May 10 14:24:25 2012 +0200 @@ -30,6 +30,7 @@ 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.*; public class LowerCheckCastTest extends GraphTest { @@ -41,78 +42,77 @@ asStringExt("0"); } - private RiCompiledMethod compile(String name, Class[] hintClasses, boolean exact) { + private RiCompiledMethod compile(String name, RiTypeProfile profile) { //System.out.println("compiling: " + name + ", hints=" + Arrays.toString(hintClasses) + ", exact=" + exact); Method method = getMethod(name); final StructuredGraph graph = parse(method); - RiResolvedType[] hints = new RiResolvedType[hintClasses.length]; - for (int i = 0; i < hintClasses.length; i++) { - hints[i] = runtime.getType(hintClasses[i]); - } - CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first(); assert ccn != null; - CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.anchor(), ccn.targetClassInstruction(), ccn.targetClass(), ccn.object(), hints, exact)); - graph.replaceFloating(ccn, ccnNew); + 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); return addMethod(riMethod, targetMethod); } - private static final boolean EXACT = true; - private static final boolean NOT_EXACT = false; - - private static Class[] hints(Class... classes) { - return classes; + private RiTypeProfile profile(Class... types) { + if (types.length == 0) { + return null; + } + ProfiledType[] ptypes = new ProfiledType[types.length]; + for (int i = 0; i < types.length; i++) { + ptypes[i] = new ProfiledType(runtime.getType(types[i]), 1.0D / types.length); + } + return new RiTypeProfile(0.0D, ptypes); } - private void test(String name, Class[] hints, boolean exact, Object expected, Object... args) { - RiCompiledMethod compiledMethod = compile(name, hints, exact); + private void test(String name, RiTypeProfile profile, Object expected, Object... args) { + RiCompiledMethod compiledMethod = compile(name, profile); Assert.assertEquals(expected, compiledMethod.executeVarargs(args)); } @Test public void test1() { - test("asNumber", hints(), NOT_EXACT, 111, 111); - test("asNumber", hints(Integer.class), NOT_EXACT, 111, 111); - test("asNumber", hints(Long.class, Short.class), NOT_EXACT, 111, 111); - test("asNumberExt", hints(), NOT_EXACT, 121, 111); - test("asNumberExt", hints(Integer.class), NOT_EXACT, 121, 111); - test("asNumberExt", hints(Long.class, Short.class), NOT_EXACT, 121, 111); + 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 public void test2() { - test("asString", hints(), NOT_EXACT, "111", "111"); - test("asString", hints(String.class), EXACT, "111", "111"); - test("asString", hints(String.class), NOT_EXACT, "111", "111"); + test("asString", profile(), "111", "111"); + test("asString", profile(String.class), "111", "111"); + test("asString", profile(String.class), "111", "111"); - test("asStringExt", hints(), NOT_EXACT, "#111", "111"); - test("asStringExt", hints(String.class), EXACT, "#111", "111"); - test("asStringExt", hints(String.class), NOT_EXACT, "#111", "111"); + test("asStringExt", profile(), "#111", "111"); + test("asStringExt", profile(String.class), "#111", "111"); + test("asStringExt", profile(String.class), "#111", "111"); } @Test(expected = ClassCastException.class) public void test3() { - test("asNumber", hints(), NOT_EXACT, 111, "111"); + test("asNumber", profile(), 111, "111"); } @Test(expected = ClassCastException.class) public void test4() { - test("asString", hints(String.class), EXACT, "111", 111); + test("asString", profile(String.class), "111", 111); } @Test(expected = ClassCastException.class) public void test5() { - test("asNumberExt", hints(), NOT_EXACT, 111, "111"); + test("asNumberExt", profile(), 111, "111"); } @Test(expected = ClassCastException.class) public void test6() { - test("asStringExt", hints(String.class), EXACT, "111", 111); + test("asStringExt", profile(String.class), "111", 111); } public static Number asNumber(Object o) { diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java Thu May 10 14:24:25 2012 +0200 @@ -43,6 +43,8 @@ public final double probability; public ProfiledType(RiResolvedType type, double probability) { + assert type != null; + assert probability >= 0.0D && probability <= 1.0D; this.type = type; this.probability = probability; } @@ -73,7 +75,7 @@ return true; } - public RiTypeProfile(ProfiledType[] ptypes, double notRecordedProbability) { + public RiTypeProfile(double notRecordedProbability, ProfiledType... ptypes) { this.ptypes = ptypes; this.notRecordedProbability = notRecordedProbability; assert isSorted(ptypes); diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java Thu May 10 14:24:25 2012 +0200 @@ -49,11 +49,11 @@ XirSnippet genNewMultiArray(XirSite site, XirArgument[] lengths, RiType type); - XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiResolvedType type, RiResolvedType[] hints, boolean hintsExact); + XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiResolvedType type, RiTypeProfile profile); - XirSnippet genInstanceOf(XirSite site, XirArgument receiver, XirArgument hub, RiType type, RiResolvedType[] hints, boolean hintsExact); + XirSnippet genInstanceOf(XirSite site, XirArgument receiver, XirArgument hub, RiResolvedType type, RiTypeProfile profile); - XirSnippet genMaterializeInstanceOf(XirSite site, XirArgument receiver, XirArgument hub, XirArgument trueValue, XirArgument falseValue, RiType type, RiResolvedType[] hints, boolean hintsExact); + XirSnippet genMaterializeInstanceOf(XirSite site, XirArgument receiver, XirArgument hub, XirArgument trueValue, XirArgument falseValue, RiResolvedType type, RiTypeProfile profile); /** * Generates code that checks that the {@linkplain Representation#ObjectHub hub} of diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/XirSite.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/XirSite.java Wed May 09 12:11:36 2012 +0200 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/XirSite.java Thu May 10 14:24:25 2012 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.max.cri.xir; +import com.oracle.max.cri.ci.*; + /** * Encapsulates the notion of a site where XIR can be supplied. It is supplied to the {@link RiXirGenerator} by the * compiler for each place where XIR can be generated. This interface allows a number of queries, including the @@ -65,4 +67,10 @@ * @return {@code true} if an array store check is required */ boolean requiresArrayStoreCheck(); + + /** + * The object for recording speculations made during compilation. + * May be null. + */ + CiAssumptions assumptions(); } diff -r c7f92c6246ba -r 31ec401eb592 graal/com.oracle.max.criutils/src/com/oracle/max/criutils/TypeCheckHints.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.criutils/src/com/oracle/max/criutils/TypeCheckHints.java Thu May 10 14:24:25 2012 +0200 @@ -0,0 +1,111 @@ +/* + * 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.max.criutils; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; +import com.oracle.max.cri.ri.RiTypeProfile.ProfiledType; + +/** + * Utility for deriving hint types for a type check instruction (e.g. checkcast or instanceof) + * based on the target type of the check and any profiling information available for the instruction. + */ +public class TypeCheckHints { + + private static final RiResolvedType[] NO_TYPES = {}; + + /** + * If true, then {@link #types} contains the only possible type that could pass the type check + * because the target of the type check is a final class or has been speculated to be a final class. + */ + public final boolean exact; + + /** + * The most likely types that the type check instruction will see. + */ + public final RiResolvedType[] types; + + /** + * Derives hint information for use when generating the code for a type check instruction. + * + * @param type the target type of the type check + * @param profile the profiling information available for the instruction (if any) + * @param assumptions the object in which speculations are recorded. This is null if speculations are not supported. + * @param minHintHitProbability if the probability that the type check will hit one the profiled types (up to + * {@code maxHints}) is below this value, then {@link #types} will be null + * @param maxHints the maximum length of {@link #types} + */ + public TypeCheckHints(RiResolvedType type, RiTypeProfile profile, CiAssumptions assumptions, double minHintHitProbability, int maxHints) { + if (type != null && isFinalClass(type)) { + types = new RiResolvedType[] {type}; + exact = true; + } else { + RiResolvedType uniqueSubtype = type == null ? null : type.uniqueConcreteSubtype(); + if (uniqueSubtype != null) { + types = new RiResolvedType[] {uniqueSubtype}; + if (assumptions != null) { + assumptions.recordConcreteSubtype(type, uniqueSubtype); + exact = true; + } else { + exact = false; + } + } else { + exact = false; + RiResolvedType[] hintTypes = NO_TYPES; + RiTypeProfile typeProfile = profile; + if (typeProfile != null) { + double notRecordedTypes = typeProfile.getNotRecordedProbability(); + ProfiledType[] ptypes = typeProfile.getTypes(); + if (notRecordedTypes < (1D - minHintHitProbability) && ptypes != null && ptypes.length > 0) { + hintTypes = new RiResolvedType[ptypes.length]; + int hintCount = 0; + double totalHintProbability = 0.0d; + for (ProfiledType ptype : ptypes) { + RiResolvedType hint = ptype.type; + if (type != null && hint.isSubtypeOf(type)) { + hintTypes[hintCount++] = hint; + totalHintProbability += ptype.probability; + } + } + if (totalHintProbability >= minHintHitProbability) { + if (hintTypes.length != hintCount || hintCount > maxHints) { + hintTypes = Arrays.copyOf(hintTypes, Math.min(maxHints, hintCount)); + } + } else { + hintTypes = NO_TYPES; + } + + } + } + this.types = hintTypes; + } + } + } + + public static boolean isFinalClass(RiResolvedType type) { + return Modifier.isFinal(type.accessFlags()) || (type.isArrayClass() && Modifier.isFinal(type.componentType().accessFlags())); + } +}