# HG changeset patch # User Christian Haeubl # Date 1355240307 -3600 # Node ID e2ea829fafd95c09c964e070da6e387ba81ab60e # Parent 720925633b3ad703e862038bcc18aad4342af493 use CHA more frequently for inlining filter types when doing a type-checked inlining diff -r 720925633b3a -r e2ea829fafd9 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java Tue Dec 11 09:10:50 2012 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java Tue Dec 11 16:38:27 2012 +0100 @@ -267,7 +267,7 @@ record(new MethodContents(method)); } - private void record(Assumption assumption) { + public void record(Assumption assumption) { if (list == null) { list = new Assumption[4]; } else { diff -r 720925633b3a -r e2ea829fafd9 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Tue Dec 11 09:10:50 2012 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Tue Dec 11 16:38:27 2012 +0100 @@ -27,6 +27,7 @@ import java.util.concurrent.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.Assumptions.Assumption; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType; import com.oracle.graal.api.meta.ResolvedJavaType.Representation; @@ -299,15 +300,15 @@ */ private static class MultiTypeGuardInlineInfo extends AbstractInlineInfo { public final List concretes; - public final ProfiledType[] ptypes; + public final ArrayList ptypes; public final int[] typesToConcretes; public final double notRecordedTypeProbability; - public MultiTypeGuardInlineInfo(Invoke invoke, double weight, List concretes, ProfiledType[] ptypes, + public MultiTypeGuardInlineInfo(Invoke invoke, double weight, ArrayList concretes, ArrayList ptypes, int[] typesToConcretes, double notRecordedTypeProbability) { super(invoke, weight); - assert concretes.size() > 0 && concretes.size() <= ptypes.length : "must have at least one method but no more than types methods"; - assert ptypes.length == typesToConcretes.length : "array lengths must match"; + assert concretes.size() > 0 && concretes.size() <= ptypes.size() : "must have at least one method but no more than types methods"; + assert ptypes.size() == typesToConcretes.length : "array lengths must match"; this.concretes = concretes; this.ptypes = ptypes; @@ -378,7 +379,7 @@ double probability = 0; for (int j = 0; j < typesToConcretes.length; j++) { if (typesToConcretes[j] == i) { - probability += ptypes[j].getProbability(); + probability += ptypes.get(j).getProbability(); } } @@ -483,9 +484,9 @@ for (int i = 0; i < typesToConcretes.length; i++) { if (typesToConcretes[i] == concreteMethodIndex) { if (commonType == null) { - commonType = ptypes[i].getType(); + commonType = ptypes.get(i).getType(); } else { - commonType = commonType.findLeastCommonAncestor(ptypes[i].getType()); + commonType = commonType.findLeastCommonAncestor(ptypes.get(i).getType()); } } } @@ -494,7 +495,7 @@ } private void inlineSingleMethod(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions) { - assert concretes.size() == 1 && ptypes.length > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0; + assert concretes.size() == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0; BeginNode calleeEntryNode = graph.add(new BeginNode()); calleeEntryNode.setProbability(invoke.probability()); @@ -517,14 +518,14 @@ } private FixedNode createDispatchOnType(StructuredGraph graph, LoadHubNode hub, BeginNode[] successors) { - assert ptypes.length > 1; + assert ptypes.size() > 1; - ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.length]; - double[] keyProbabilities = new double[ptypes.length + 1]; - int[] keySuccessors = new int[ptypes.length + 1]; - for (int i = 0; i < ptypes.length; i++) { - keys[i] = ptypes[i].getType(); - keyProbabilities[i] = ptypes[i].getProbability(); + ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.size()]; + double[] keyProbabilities = new double[ptypes.size() + 1]; + int[] keySuccessors = new int[ptypes.size() + 1]; + for (int i = 0; i < ptypes.size(); i++) { + keys[i] = ptypes.get(i).getType(); + keyProbabilities[i] = ptypes.get(i).getProbability(); keySuccessors[i] = typesToConcretes[i]; assert keySuccessors[i] < successors.length - 1 : "last successor is the unknownTypeSux"; } @@ -605,12 +606,12 @@ builder.append(MetaUtil.format(" %H.%n(%p):%r", concretes.get(i))); } builder.append(" ], "); - builder.append(ptypes.length); + builder.append(ptypes.size()); builder.append(" type checks [ "); - for (int i = 0; i < ptypes.length; i++) { + for (int i = 0; i < ptypes.size(); i++) { builder.append(" "); - builder.append(ptypes[i].getType().getName()); - builder.append(ptypes[i].getProbability()); + builder.append(ptypes.get(i).getType().getName()); + builder.append(ptypes.get(i).getProbability()); } builder.append(" ]"); return builder.toString(); @@ -623,21 +624,17 @@ * but for which an assumption has to be registered because of non-final classes. */ private static class AssumptionInlineInfo extends ExactInlineInfo { - public final ResolvedJavaType context; + private final Assumption takenAssumption; - public AssumptionInlineInfo(Invoke invoke, double weight, ResolvedJavaType context, ResolvedJavaMethod concrete) { + public AssumptionInlineInfo(Invoke invoke, double weight, ResolvedJavaMethod concrete, Assumption takenAssumption) { super(invoke, weight, concrete); - this.context = context; + this.takenAssumption = takenAssumption; } @Override public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions) { - if (Debug.isLogEnabled()) { - String targetName = MetaUtil.format("%H.%n(%p):%r", invoke.methodCallTarget().targetMethod()); - String concreteName = MetaUtil.format("%H.%n(%p):%r", concrete); - Debug.log("recording concrete method assumption: %s on receiver type %s -> %s", targetName, context, concreteName); - } - assumptions.recordConcreteMethod(invoke.methodCallTarget().targetMethod(), context, concrete); + assumptions.record(takenAssumption); + Debug.log("recording assumption: %s", takenAssumption); super.inline(graph, runtime, callback, assumptions); } @@ -664,68 +661,90 @@ ResolvedJavaMethod targetMethod = callTarget.targetMethod(); if (callTarget.invokeKind() == InvokeKind.Special || targetMethod.canBeStaticallyBound()) { - if (!checkTargetConditions(invoke, targetMethod, optimisticOpts, runtime)) { - return null; - } - double weight = inliningPolicy.inliningWeight(caller, targetMethod, invoke); - return new ExactInlineInfo(invoke, weight, targetMethod); + return getExactInlineInfo(invoke, runtime, inliningPolicy, optimisticOpts, caller, targetMethod); } + + assert callTarget.invokeKind() == InvokeKind.Virtual || callTarget.invokeKind() == InvokeKind.Interface; + + ResolvedJavaType holder = targetMethod.getDeclaringClass(); ObjectStamp receiverStamp = callTarget.receiver().objectStamp(); - ResolvedJavaType receiverType = receiverStamp.type(); - if (receiverStamp.isExactType()) { - assert targetMethod.getDeclaringClass().isAssignableFrom(receiverType) : receiverType + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod; - ResolvedJavaMethod resolved = receiverType.resolveMethod(targetMethod); - if (!checkTargetConditions(invoke, resolved, optimisticOpts, runtime)) { - return null; - } - double weight = inliningPolicy.inliningWeight(caller, resolved, invoke); - return new ExactInlineInfo(invoke, weight, resolved); - } - ResolvedJavaType holder = targetMethod.getDeclaringClass(); - if (receiverStamp.type() != null) { // the invoke target might be more specific than the holder (happens after inlining: locals lose their declared type...) - // TODO (lstadler) fix this + ResolvedJavaType receiverType = receiverStamp.type(); if (receiverType != null && holder.isAssignableFrom(receiverType)) { holder = receiverType; - } - } - // TODO (thomaswue) fix this - if (assumptions.useOptimisticAssumptions()) { - ResolvedJavaMethod concrete = holder.findUniqueConcreteMethod(targetMethod); - if (concrete != null) { - if (!checkTargetConditions(invoke, concrete, optimisticOpts, runtime)) { - return null; + if (receiverStamp.isExactType()) { + assert targetMethod.getDeclaringClass().isAssignableFrom(holder) : holder + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod; + return getExactInlineInfo(invoke, runtime, inliningPolicy, optimisticOpts, caller, holder.resolveMethod(targetMethod)); } - double weight = inliningPolicy.inliningWeight(caller, concrete, invoke); - return new AssumptionInlineInfo(invoke, weight, holder, concrete); } } + if (holder.isArray()) { + // arrays can be treated as Objects + return getExactInlineInfo(invoke, runtime, inliningPolicy, optimisticOpts, caller, holder.resolveMethod(targetMethod)); + } + + // TODO (chaeubl): we could also use the type determined after assumptions for the type-checked inlining case as it might have an effect on type filtering + if (assumptions.useOptimisticAssumptions()) { + ResolvedJavaType uniqueSubtype = holder.findUniqueConcreteSubtype(); + if (uniqueSubtype != null) { + return getAssumptionInlineInfo(invoke, runtime, inliningPolicy, optimisticOpts, caller, uniqueSubtype.resolveMethod(targetMethod), new Assumptions.ConcreteSubtype(holder, uniqueSubtype)); + } + + ResolvedJavaMethod concrete = holder.findUniqueConcreteMethod(targetMethod); + if (concrete != null) { + return getAssumptionInlineInfo(invoke, runtime, inliningPolicy, optimisticOpts, caller, concrete, new Assumptions.ConcreteMethod(targetMethod, holder, concrete)); + } + + // TODO (chaeubl): C1 has one more assumption in the case of interfaces + } + // type check based inlining - return getTypeCheckedInlineInfo(invoke, inliningPolicy, caller, targetMethod, optimisticOpts, runtime); + return getTypeCheckedInlineInfo(invoke, inliningPolicy, caller, holder, targetMethod, optimisticOpts, runtime); + } + + private static InlineInfo getAssumptionInlineInfo(Invoke invoke, GraalCodeCacheProvider runtime, InliningPolicy inliningPolicy, OptimisticOptimizations optimisticOpts, + ResolvedJavaMethod caller, ResolvedJavaMethod concrete, Assumption takenAssumption) { + assert !Modifier.isAbstract(concrete.getModifiers()); + if (!checkTargetConditions(invoke, concrete, optimisticOpts, runtime)) { + return null; + } + double weight = inliningPolicy.inliningWeight(caller, concrete, invoke); + return new AssumptionInlineInfo(invoke, weight, concrete, takenAssumption); + } + + private static InlineInfo getExactInlineInfo(Invoke invoke, GraalCodeCacheProvider runtime, InliningPolicy inliningPolicy, OptimisticOptimizations optimisticOpts, + ResolvedJavaMethod caller, ResolvedJavaMethod targetMethod) { + assert !Modifier.isAbstract(targetMethod.getModifiers()); + if (!checkTargetConditions(invoke, targetMethod, optimisticOpts, runtime)) { + return null; + } + double weight = inliningPolicy.inliningWeight(caller, targetMethod, invoke); + return new ExactInlineInfo(invoke, weight, targetMethod); } private static InlineInfo getTypeCheckedInlineInfo(Invoke invoke, InliningPolicy inliningPolicy, ResolvedJavaMethod caller, - ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts, GraalCodeCacheProvider runtime) { + ResolvedJavaType holder, ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts, GraalCodeCacheProvider runtime) { ProfilingInfo profilingInfo = caller.getProfilingInfo(); JavaTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci()); if (typeProfile == null) { return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no type profile exists"); } - ProfiledType[] ptypes = typeProfile.getTypes(); - if (ptypes == null || ptypes.length <= 0) { - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types/probabilities were recorded"); + ProfiledType[] rawProfiledTypes = typeProfile.getTypes(); + ArrayList ptypes = getCompatibleTypes(rawProfiledTypes, holder); + if (ptypes == null || ptypes.size() <= 0) { + return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types remained after filtering (%d types were recorded)", rawProfiledTypes.length); } double notRecordedTypeProbability = typeProfile.getNotRecordedProbability(); - if (ptypes.length == 1 && notRecordedTypeProbability == 0) { + if (ptypes.size() == 1 && notRecordedTypeProbability == 0) { if (!optimisticOpts.inlineMonomorphicCalls()) { return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining monomorphic calls is disabled"); } - ResolvedJavaType type = ptypes[0].getType(); + ResolvedJavaType type = ptypes.get(0).getType(); ResolvedJavaMethod concrete = type.resolveMethod(targetMethod); if (!checkTargetConditions(invoke, concrete, optimisticOpts, runtime)) { return null; @@ -736,10 +755,10 @@ invoke.setPolymorphic(true); if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) { - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length); + return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.size()); } if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) { - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length, notRecordedTypeProbability * 100); + return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.size(), notRecordedTypeProbability * 100); } // TODO (chaeubl) inlining of multiple methods should work differently @@ -751,9 +770,9 @@ // determine concrete methods and map type to specific method ArrayList concreteMethods = new ArrayList<>(); - int[] typesToConcretes = new int[ptypes.length]; - for (int i = 0; i < ptypes.length; i++) { - ResolvedJavaMethod concrete = ptypes[i].getType().resolveMethod(targetMethod); + int[] typesToConcretes = new int[ptypes.size()]; + for (int i = 0; i < ptypes.size(); i++) { + ResolvedJavaMethod concrete = ptypes.get(i).getType().resolveMethod(targetMethod); int index = concreteMethods.indexOf(concrete); if (index < 0) { @@ -775,6 +794,19 @@ } + private static ArrayList getCompatibleTypes(ProfiledType[] types, ResolvedJavaType holder) { + ArrayList result = new ArrayList<>(); + for (int i = 0; i < types.length; i++) { + ProfiledType ptype = types[i]; + ResolvedJavaType type = ptype.getType(); + assert !type.isInterface() && !Modifier.isAbstract(type.getModifiers()); + if (holder.isAssignableFrom(type)) { + result.add(ptype); + } + } + return result; + } + private static ResolvedJavaMethod getCaller(Invoke invoke) { return invoke.stateAfter().method(); } diff -r 720925633b3a -r e2ea829fafd9 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Tue Dec 11 09:10:50 2012 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Tue Dec 11 16:38:27 2012 +0100 @@ -199,7 +199,7 @@ public static boolean OptEliminatePartiallyRedundantGuards = true; // Intrinsification settings - public static boolean IntrinsifyArrayCopy = false; + public static boolean IntrinsifyArrayCopy = true; public static boolean IntrinsifyObjectMethods = true; public static boolean IntrinsifySystemMethods = true; public static boolean IntrinsifyClassMethods = true; diff -r 720925633b3a -r e2ea829fafd9 graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java Tue Dec 11 09:10:50 2012 +0100 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java Tue Dec 11 16:38:27 2012 +0100 @@ -369,6 +369,7 @@ StructuredGraph graph = parse(snippet); PhasePlan phasePlan = getDefaultPhasePlan(); Assumptions assumptions = new Assumptions(true); + new ComputeProbabilityPhase().apply(graph); Debug.dump(graph, "Graph"); new InliningPhase(null, runtime(), null, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); Debug.dump(graph, "Graph");