# HG changeset patch # User Lukas Stadler # Date 1365497294 -7200 # Node ID cdd70fd1479bfc9ad3d046ab416ba3cb9181c27f # Parent a214dada94c44844e23e9f5b835a435a8bb2843e# Parent f2bddf68d293e8404ed817ef0f810282019f3edf Merge diff -r a214dada94c4 -r cdd70fd1479b graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java Tue Apr 09 10:29:44 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java Tue Apr 09 10:48:14 2013 +0200 @@ -36,10 +36,31 @@ */ public class TypeCheckHints { - private static final ResolvedJavaType[] NO_TYPES = {}; + /** + * A receiver type profiled in a type check instruction. + */ + public static class Hint { + + /** + * A type seen while profiling a type check instruction. + */ + public final ResolvedJavaType type; + + /** + * Specifies if {@link #type} was a sub-type of the checked type. + */ + public final boolean positive; + + Hint(ResolvedJavaType type, boolean positive) { + this.type = type; + this.positive = positive; + } + } + + private static final Hint[] NO_HINTS = {}; /** - * If true, then {@link #types} contains the only possible type that could pass the type check + * If true, then {@link #hints} 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. */ @@ -48,7 +69,7 @@ /** * The most likely types that the type check instruction will see. */ - public final ResolvedJavaType[] types; + public final Hint[] hints; /** * Derives hint information for use when generating the code for a type check instruction. @@ -58,18 +79,18 @@ * @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 of the - * profiled types (up to {@code maxHints}) is below this value, then {@link #types} + * profiled types (up to {@code maxHints}) is below this value, then {@link #hints} * will be null - * @param maxHints the maximum length of {@link #types} + * @param maxHints the maximum length of {@link #hints} */ public TypeCheckHints(ResolvedJavaType type, JavaTypeProfile profile, Assumptions assumptions, double minHintHitProbability, int maxHints) { if (type != null && !canHaveSubtype(type)) { - types = new ResolvedJavaType[]{type}; + hints = new Hint[]{new Hint(type, true)}; exact = true; } else { ResolvedJavaType uniqueSubtype = type == null ? null : type.findUniqueConcreteSubtype(); if (uniqueSubtype != null) { - types = new ResolvedJavaType[]{uniqueSubtype}; + hints = new Hint[]{new Hint(uniqueSubtype, true)}; if (assumptions.useOptimisticAssumptions()) { assumptions.recordConcreteSubtype(type, uniqueSubtype); exact = true; @@ -78,33 +99,32 @@ } } else { exact = false; - ResolvedJavaType[] hintTypes = NO_TYPES; + Hint[] hintsBuf = NO_HINTS; JavaTypeProfile typeProfile = profile; if (typeProfile != null) { double notRecordedTypes = typeProfile.getNotRecordedProbability(); ProfiledType[] ptypes = typeProfile.getTypes(); if (notRecordedTypes < (1D - minHintHitProbability) && ptypes != null && ptypes.length > 0) { - hintTypes = new ResolvedJavaType[ptypes.length]; + hintsBuf = new Hint[ptypes.length]; int hintCount = 0; double totalHintProbability = 0.0d; for (ProfiledType ptype : ptypes) { - ResolvedJavaType hint = ptype.getType(); - if (type != null && type.isAssignableFrom(hint)) { - hintTypes[hintCount++] = hint; + if (type != null) { + hintsBuf[hintCount++] = new Hint(type, type.isAssignableFrom(ptype.getType())); totalHintProbability += ptype.getProbability(); } } if (totalHintProbability >= minHintHitProbability) { - if (hintTypes.length != hintCount || hintCount > maxHints) { - hintTypes = Arrays.copyOf(hintTypes, Math.min(maxHints, hintCount)); + if (hintsBuf.length != hintCount || hintCount > maxHints) { + hintsBuf = Arrays.copyOf(hintsBuf, Math.min(maxHints, hintCount)); } } else { - hintTypes = NO_TYPES; + hintsBuf = NO_HINTS; } } } - this.types = hintTypes; + this.hints = hintsBuf; } } } diff -r a214dada94c4 -r cdd70fd1479b graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java Tue Apr 09 10:29:44 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java Tue Apr 09 10:48:14 2013 +0200 @@ -122,7 +122,9 @@ } /** - * A list of types for which the runtime has recorded probability information. + * A list of types for which the runtime has recorded probability information. Note that this + * includes both positive and negative types where a positive type is a subtype of the checked + * type and a negative type is not. */ public ProfiledType[] getTypes() { return ptypes; diff -r a214dada94c4 -r cdd70fd1479b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java Tue Apr 09 10:29:44 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java Tue Apr 09 10:48:14 2013 +0200 @@ -202,7 +202,7 @@ assert type != null; if (hintInfo.exact) { - ConstantNode[] hints = createHints(hintInfo, runtime, graph); + ConstantNode[] hints = createHints(hintInfo, runtime, true, graph).hubs; assert hints.length == 1; key = new Key(exact).add("checkNull", checkNull); arguments = arguments("object", object).add("exactHub", hints[0]); @@ -210,7 +210,7 @@ key = new Key(primary).add("checkNull", checkNull).add("superCheckOffset", type.superCheckOffset()); arguments = arguments("hub", hub).add("object", object); } else { - ConstantNode[] hints = createHints(hintInfo, runtime, graph); + ConstantNode[] hints = createHints(hintInfo, runtime, true, graph).hubs; key = new Key(secondary).add("hints", Varargs.vargargs(new Word[hints.length], StampFactory.forKind(wordKind()))).add("checkNull", checkNull); arguments = arguments("hub", hub).add("object", object).add("hints", hints); } diff -r a214dada94c4 -r cdd70fd1479b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Tue Apr 09 10:29:44 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Tue Apr 09 10:48:14 2013 +0200 @@ -192,7 +192,7 @@ Arguments arguments; Key key; if (hintInfo.exact) { - ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph()); + ConstantNode[] hints = createHints(hintInfo, runtime, true, hub.graph()).hubs; assert hints.length == 1; key = new Key(instanceofExact).add("checkNull", checkNull); arguments = arguments("object", object).add("exactHub", hints[0]).add("trueValue", trueValue).add("falseValue", falseValue); @@ -200,7 +200,7 @@ key = new Key(instanceofPrimary).add("checkNull", checkNull).add("superCheckOffset", type.superCheckOffset()); arguments = arguments("hub", hub).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue); } else { - ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph()); + ConstantNode[] hints = createHints(hintInfo, runtime, true, hub.graph()).hubs; key = new Key(instanceofSecondary).add("hints", Varargs.vargargs(new Word[hints.length], StampFactory.forKind(wordKind()))).add("checkNull", checkNull); arguments = arguments("hub", hub).add("object", object).add("hints", hints).add("trueValue", trueValue).add("falseValue", falseValue); } diff -r a214dada94c4 -r cdd70fd1479b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java Tue Apr 09 10:29:44 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java Tue Apr 09 10:48:14 2013 +0200 @@ -25,6 +25,8 @@ import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; +import java.util.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; @@ -98,12 +100,45 @@ return false; } - static ConstantNode[] createHints(TypeCheckHints hints, MetaAccessProvider runtime, Graph graph) { - ConstantNode[] hintHubs = new ConstantNode[hints.types.length]; - for (int i = 0; i < hintHubs.length; i++) { - hintHubs[i] = ConstantNode.forConstant(((HotSpotResolvedObjectType) hints.types[i]).klass(), runtime, graph); + /** + * A set of type check hints ordered by decreasing probabilities. + */ + public static class Hints { + + /** + * The hubs of the hint types. + */ + public final ConstantNode[] hubs; + + /** + * A predicate over {@link #hubs} specifying whether the corresponding hint type is a + * sub-type of the checked type. + */ + public final boolean[] isPositive; + + Hints(ConstantNode[] hints, boolean[] hintIsPositive) { + this.hubs = hints; + this.isPositive = hintIsPositive; } - return hintHubs; + } + + static Hints createHints(TypeCheckHints hints, MetaAccessProvider runtime, boolean positiveOnly, Graph graph) { + ConstantNode[] hubs = new ConstantNode[hints.hints.length]; + boolean[] isPositive = new boolean[hints.hints.length]; + int index = 0; + for (int i = 0; i < hubs.length; i++) { + if (!positiveOnly || hints.hints[i].positive) { + hubs[index] = ConstantNode.forConstant(((HotSpotResolvedObjectType) hints.hints[i].type).klass(), runtime, graph); + isPositive[index] = hints.hints[i].positive; + index++; + } + } + if (positiveOnly && index != hubs.length) { + assert index < hubs.length; + hubs = Arrays.copyOf(hubs, index); + isPositive = Arrays.copyOf(isPositive, index); + } + return new Hints(hubs, isPositive); } static Word loadSecondarySupersElement(Word metaspaceArray, int index) { diff -r a214dada94c4 -r cdd70fd1479b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Tue Apr 09 10:29:44 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Tue Apr 09 10:48:14 2013 +0200 @@ -105,7 +105,7 @@ ResolvedJavaType fieldType = ((ResolvedJavaField) locId).getDeclaringClass(); ResolvedJavaType beforePiType = parent.object().objectStamp().type(); - if (fieldType.isAssignableFrom(beforePiType)) { + if (beforePiType != null && fieldType.isAssignableFrom(beforePiType)) { replaceFirstInput(parent, parent.object()); return true; } diff -r a214dada94c4 -r cdd70fd1479b graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Tue Apr 09 10:29:44 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Tue Apr 09 10:48:14 2013 +0200 @@ -496,7 +496,7 @@ } else { Kind kind = ((LocalNode) parameter).kind(); assert argument != null || kind == Kind.Object : this + " cannot accept null for non-object parameter named " + name; - Constant constant = Constant.forBoxed(kind, argument); + Constant constant = forBoxed(argument, kind); replacements.put((LocalNode) parameter, ConstantNode.forConstant(constant, runtime, replaceeGraph)); } } else if (parameter instanceof LocalNode[]) { @@ -520,7 +520,7 @@ if (value instanceof ValueNode) { replacements.put(local, (ValueNode) value); } else { - Constant constant = Constant.forBoxed(local.kind(), value); + Constant constant = forBoxed(value, local.kind()); ConstantNode element = ConstantNode.forConstant(constant, runtime, replaceeGraph); replacements.put(local, element); } @@ -533,6 +533,32 @@ } /** + * Converts a Java boxed value to a {@link Constant} of the right kind. This adjusts for the + * limitation that a {@link Local}'s kind is a {@linkplain Kind#getStackKind() stack kind} and + * so cannot be used for re-boxing primitives smaller than an int. + * + * @param argument a Java boxed value + * @param localKind the kind of the {@link Local} to which {@code argument} will be bound + */ + protected Constant forBoxed(Object argument, Kind localKind) { + assert localKind == localKind.getStackKind(); + if (localKind == Kind.Int && !(argument instanceof Integer)) { + if (argument instanceof Boolean) { + return Constant.forBoxed(Kind.Boolean, argument); + } + if (argument instanceof Byte) { + return Constant.forBoxed(Kind.Byte, argument); + } + if (argument instanceof Short) { + return Constant.forBoxed(Kind.Short, argument); + } + assert argument instanceof Character; + return Constant.forBoxed(Kind.Char, argument); + } + return Constant.forBoxed(localKind, argument); + } + + /** * Logic for replacing a snippet-lowered node at its usages with the return value of the * snippet. An alternative to the {@linkplain SnippetTemplate#DEFAULT_REPLACER default} * replacement logic can be used to handle mismatches between the stamp of the node being