# HG changeset patch # User Doug Simon # Date 1336594918 -7200 # Node ID 2e9a5365dfb00c122688df9f4c7a5b2735d3e5af # Parent a4218dd1b157322a0c55c41db836d260221d8209 moved conversion of type profiles into hints for type check instructions from front end to lowering phase diff -r a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed May 09 22:21:58 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() { @@ -232,9 +232,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 a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Wed May 09 22:21:58 2012 +0200 @@ -245,6 +245,14 @@ */ public static int CheckcastMaxHints = 2; + /** + * @see #CheckcastMinHintHitProbability + */ + public static double InstanceOfMinHintHitProbability = 0.5; + + /** + * @see #CheckcastMaxHints + */ public static int InstanceOfMaxHints = 1; /** diff -r a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Wed May 09 22:21:58 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 a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Wed May 09 22:21:58 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 a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java Wed May 09 22:21:58 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 a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/Util.java Wed May 09 22:21:58 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 a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodData.java Wed May 09 22:21:58 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 a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java Wed May 09 22:21:58 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 a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/LowerCheckCastPhase.java Wed May 09 22:21:58 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, (FixedWithNextNode) node.anchor(), 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 a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java Wed May 09 22:21:58 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 a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed May 09 22:21:58 2012 +0200 @@ -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()); } } } @@ -638,9 +613,7 @@ 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)); + checkCast = currentGraph.unique(new CheckCastNode(anchor, typeInstruction, (RiResolvedType) type, object, getProfileForTypeCheck((RiResolvedType) type))); append(currentGraph.add(new ValueAnchorNode(checkCast))); frameState.apush(checkCast); } else { @@ -657,9 +630,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 a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Wed May 09 22:21:58 2012 +0200 @@ -53,11 +53,11 @@ * @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); + this(anchor, 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)); + public CheckCastNode(FixedNode anchor, ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiTypeProfile profile) { + super(targetClassInstruction, targetClass, object, profile, targetClass == null ? StampFactory.forKind(CiKind.Object) : StampFactory.declared(targetClass)); this.anchor = anchor; } @@ -87,12 +87,12 @@ } } - 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)); - } - } +// 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; } diff -r a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Wed May 09 22:21:58 2012 +0200 @@ -49,11 +49,11 @@ * @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(targetClassInstruction, targetClass, object, profile, StampFactory.illegal()); this.negated = negated; assert targetClass != null; } @@ -112,18 +112,18 @@ 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)); - } - } +// 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 diff -r a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java Wed May 09 22:21:58 2012 +0200 @@ -35,23 +35,22 @@ @Input private ValueNode object; @Input private ValueNode targetClassInstruction; private final RiResolvedType targetClass; - private final RiResolvedType[] hints; - private final boolean hintsExact; + private final RiTypeProfile profile; /** * 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) { + public TypeCheckNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiTypeProfile profile, Stamp stamp) { super(stamp); this.targetClassInstruction = targetClassInstruction; this.targetClass = targetClass; this.object = object; - this.hints = hints; - this.hintsExact = hintsExact; + this.profile = profile; } public ValueNode object() { @@ -70,11 +69,7 @@ return targetClass; } - public RiResolvedType[] hints() { - return hints; - } - - public boolean hintsExact() { - return hintsExact; + public RiTypeProfile profile() { + return profile; } } diff -r a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java Wed May 09 22:21:58 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,20 +42,15 @@ 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)); + CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.anchor(), ccn.targetClassInstruction(), ccn.targetClass(), ccn.object(), profile)); graph.replaceFloating(ccn, ccnNew); final RiResolvedMethod riMethod = runtime.getRiMethod(method); @@ -62,57 +58,61 @@ 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 a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java Wed May 09 22:21:58 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 a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java Wed May 09 22:21:58 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 a4218dd1b157 -r 2e9a5365dfb0 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 16:39:52 2012 +0200 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/XirSite.java Wed May 09 22:21:58 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 a4218dd1b157 -r 2e9a5365dfb0 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 Wed May 09 22:21:58 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())); + } +}