# HG changeset patch # User Miguel Garcia # Date 1400512895 -7200 # Node ID 402a74c6bc14118b6ae2e78527e47d726cad9950 # Parent 56689688067a4b5bbcc579de96a1eac4ae1aee68# Parent 10830a8ab30d8f1077369ebe561fff86978af7db Merge diff -r 10830a8ab30d -r 402a74c6bc14 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Mon May 19 15:30:57 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Mon May 19 17:21:35 2014 +0200 @@ -30,9 +30,7 @@ import java.util.*; 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.compiler.common.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.debug.*; @@ -168,18 +166,18 @@ } } - private static void logNotInlinedMethod(Invoke invoke, String msg) { + public static void logNotInlinedMethod(Invoke invoke, String msg) { if (shouldLogInliningDecision()) { String methodString = invoke.toString() + (invoke.callTarget() == null ? " callTarget=null" : invoke.callTarget().targetName()); logInliningDecision(methodString, false, msg, new Object[0]); } } - private static void logNotInlined(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) { + public static void logNotInlined(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) { logNotInlinedInvoke(invoke, inliningDepth, method, msg, new Object[0]); } - private static void logNotInlinedInvoke(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg, Object... args) { + public static void logNotInlinedInvoke(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg, Object... args) { printInlining(method, invoke, inliningDepth, false, msg, args); if (shouldLogInliningDecision()) { String methodString = methodName(method, invoke); @@ -236,221 +234,6 @@ invoke.asNode().replaceFirstInput(oldCallTarget, newCallTarget); } - /** - * Determines if inlining is possible at the given invoke node. - * - * @param invoke the invoke that should be inlined - * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke - */ - public static InlineInfo getInlineInfo(InliningData data, Invoke invoke, int maxNumberOfMethods, Replacements replacements, Assumptions assumptions, OptimisticOptimizations optimisticOpts) { - final String failureMessage = checkInvokeConditions(invoke); - if (failureMessage != null) { - logNotInlinedMethod(invoke, failureMessage); - return null; - } - MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); - ResolvedJavaMethod targetMethod = callTarget.targetMethod(); - - if (callTarget.invokeKind() == InvokeKind.Special || targetMethod.canBeStaticallyBound()) { - return getExactInlineInfo(data, invoke, replacements, optimisticOpts, targetMethod); - } - - assert callTarget.invokeKind() == InvokeKind.Virtual || callTarget.invokeKind() == InvokeKind.Interface; - - ResolvedJavaType holder = targetMethod.getDeclaringClass(); - if (!(callTarget.receiver().stamp() instanceof ObjectStamp)) { - return null; - } - ObjectStamp receiverStamp = (ObjectStamp) callTarget.receiver().stamp(); - if (receiverStamp.alwaysNull()) { - // Don't inline if receiver is known to be null - return null; - } - ResolvedJavaType contextType = invoke.getContextType(); - if (receiverStamp.type() != null) { - // the invoke target might be more specific than the holder (happens after inlining: - // parameters lose their declared type...) - ResolvedJavaType receiverType = receiverStamp.type(); - if (receiverType != null && holder.isAssignableFrom(receiverType)) { - holder = receiverType; - if (receiverStamp.isExactType()) { - assert targetMethod.getDeclaringClass().isAssignableFrom(holder) : holder + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod; - ResolvedJavaMethod resolvedMethod = holder.resolveMethod(targetMethod, contextType); - if (resolvedMethod != null) { - return getExactInlineInfo(data, invoke, replacements, optimisticOpts, resolvedMethod); - } - } - } - } - - if (holder.isArray()) { - // arrays can be treated as Objects - ResolvedJavaMethod resolvedMethod = holder.resolveMethod(targetMethod, contextType); - if (resolvedMethod != null) { - return getExactInlineInfo(data, invoke, replacements, optimisticOpts, resolvedMethod); - } - } - - if (assumptions.useOptimisticAssumptions()) { - ResolvedJavaType uniqueSubtype = holder.findUniqueConcreteSubtype(); - if (uniqueSubtype != null) { - ResolvedJavaMethod resolvedMethod = uniqueSubtype.resolveMethod(targetMethod, contextType); - if (resolvedMethod != null) { - return getAssumptionInlineInfo(data, invoke, replacements, optimisticOpts, resolvedMethod, new Assumptions.ConcreteSubtype(holder, uniqueSubtype)); - } - } - - ResolvedJavaMethod concrete = holder.findUniqueConcreteMethod(targetMethod); - if (concrete != null) { - return getAssumptionInlineInfo(data, invoke, replacements, optimisticOpts, concrete, new Assumptions.ConcreteMethod(targetMethod, holder, concrete)); - } - } - - // type check based inlining - return getTypeCheckedInlineInfo(data, invoke, maxNumberOfMethods, replacements, targetMethod, optimisticOpts); - } - - private static InlineInfo getAssumptionInlineInfo(InliningData data, Invoke invoke, Replacements replacements, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod concrete, - Assumption takenAssumption) { - assert !concrete.isAbstract(); - if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) { - return null; - } - return new AssumptionInlineInfo(invoke, concrete, takenAssumption); - } - - private static InlineInfo getExactInlineInfo(InliningData data, Invoke invoke, Replacements replacements, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod targetMethod) { - assert !targetMethod.isAbstract(); - if (!checkTargetConditions(data, replacements, invoke, targetMethod, optimisticOpts)) { - return null; - } - return new ExactInlineInfo(invoke, targetMethod); - } - - private static InlineInfo getTypeCheckedInlineInfo(InliningData data, Invoke invoke, int maxNumberOfMethods, Replacements replacements, ResolvedJavaMethod targetMethod, - OptimisticOptimizations optimisticOpts) { - JavaTypeProfile typeProfile; - ValueNode receiver = invoke.callTarget().arguments().get(0); - if (receiver instanceof TypeProfileProxyNode) { - TypeProfileProxyNode typeProfileProxyNode = (TypeProfileProxyNode) receiver; - typeProfile = typeProfileProxyNode.getProfile(); - } else { - logNotInlined(invoke, data.inliningDepth(), targetMethod, "no type profile exists"); - return null; - } - - ProfiledType[] ptypes = typeProfile.getTypes(); - if (ptypes == null || ptypes.length <= 0) { - logNotInlined(invoke, data.inliningDepth(), targetMethod, "no types in profile"); - return null; - } - ResolvedJavaType contextType = invoke.getContextType(); - double notRecordedTypeProbability = typeProfile.getNotRecordedProbability(); - if (ptypes.length == 1 && notRecordedTypeProbability == 0) { - if (!optimisticOpts.inlineMonomorphicCalls()) { - logNotInlined(invoke, data.inliningDepth(), targetMethod, "inlining monomorphic calls is disabled"); - return null; - } - - ResolvedJavaType type = ptypes[0].getType(); - assert type.isArray() || !type.isAbstract(); - ResolvedJavaMethod concrete = type.resolveMethod(targetMethod, contextType); - if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) { - return null; - } - return new TypeGuardInlineInfo(invoke, concrete, type); - } else { - invoke.setPolymorphic(true); - - if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) { - logNotInlinedInvoke(invoke, data.inliningDepth(), targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length); - return null; - } - if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) { - // due to filtering impossible types, notRecordedTypeProbability can be > 0 although - // the number of types is lower than what can be recorded in a type profile - logNotInlinedInvoke(invoke, data.inliningDepth(), targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length, - notRecordedTypeProbability * 100); - return null; - } - - // Find unique methods and their probabilities. - ArrayList concreteMethods = new ArrayList<>(); - ArrayList concreteMethodsProbabilities = new ArrayList<>(); - for (int i = 0; i < ptypes.length; i++) { - ResolvedJavaMethod concrete = ptypes[i].getType().resolveMethod(targetMethod, contextType); - if (concrete == null) { - logNotInlined(invoke, data.inliningDepth(), targetMethod, "could not resolve method"); - return null; - } - int index = concreteMethods.indexOf(concrete); - double curProbability = ptypes[i].getProbability(); - if (index < 0) { - index = concreteMethods.size(); - concreteMethods.add(concrete); - concreteMethodsProbabilities.add(curProbability); - } else { - concreteMethodsProbabilities.set(index, concreteMethodsProbabilities.get(index) + curProbability); - } - } - - if (concreteMethods.size() > maxNumberOfMethods) { - logNotInlinedInvoke(invoke, data.inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxNumberOfMethods); - return null; - } - - // Clear methods that fall below the threshold. - if (notRecordedTypeProbability > 0) { - ArrayList newConcreteMethods = new ArrayList<>(); - ArrayList newConcreteMethodsProbabilities = new ArrayList<>(); - for (int i = 0; i < concreteMethods.size(); ++i) { - if (concreteMethodsProbabilities.get(i) >= MegamorphicInliningMinMethodProbability.getValue()) { - newConcreteMethods.add(concreteMethods.get(i)); - newConcreteMethodsProbabilities.add(concreteMethodsProbabilities.get(i)); - } - } - - if (newConcreteMethods.size() == 0) { - // No method left that is worth inlining. - logNotInlinedInvoke(invoke, data.inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)", concreteMethods.size()); - return null; - } - - concreteMethods = newConcreteMethods; - concreteMethodsProbabilities = newConcreteMethodsProbabilities; - } - - // Clean out types whose methods are no longer available. - ArrayList usedTypes = new ArrayList<>(); - ArrayList typesToConcretes = new ArrayList<>(); - for (ProfiledType type : ptypes) { - ResolvedJavaMethod concrete = type.getType().resolveMethod(targetMethod, contextType); - int index = concreteMethods.indexOf(concrete); - if (index == -1) { - notRecordedTypeProbability += type.getProbability(); - } else { - assert type.getType().isArray() || !type.getType().isAbstract() : type + " " + concrete; - usedTypes.add(type); - typesToConcretes.add(index); - } - } - - if (usedTypes.size() == 0) { - // No type left that is worth checking for. - logNotInlinedInvoke(invoke, data.inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length); - return null; - } - - for (ResolvedJavaMethod concrete : concreteMethods) { - if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) { - logNotInlined(invoke, data.inliningDepth(), targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined"); - return null; - } - } - return new MultiTypeGuardInlineInfo(invoke, concreteMethods, concreteMethodsProbabilities, usedTypes, typesToConcretes, notRecordedTypeProbability); - } - } - public static GuardedValueNode createAnchoredReceiver(StructuredGraph graph, GuardingNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) { return createAnchoredReceiver(graph, anchor, receiver, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType)); } @@ -463,27 +246,32 @@ /** * @return null iff the check succeeds, otherwise a (non-null) descriptive message. */ - private static String checkInvokeConditions(Invoke invoke) { + public static String checkInvokeConditions(Invoke invoke) { if (invoke.predecessor() == null || !invoke.asNode().isAlive()) { return "the invoke is dead code"; - } else if (!(invoke.callTarget() instanceof MethodCallTargetNode)) { + } + if (!(invoke.callTarget() instanceof MethodCallTargetNode)) { return "the invoke has already been lowered, or has been created as a low-level node"; - } else if (((MethodCallTargetNode) invoke.callTarget()).targetMethod() == null) { + } + MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); + if (callTarget.targetMethod() == null) { return "target method is null"; - } else if (invoke.stateAfter() == null) { + } + if (invoke.stateAfter() == null) { // TODO (chaeubl): why should an invoke not have a state after? return "the invoke has no after state"; - } else if (!invoke.useForInlining()) { + } + if (!invoke.useForInlining()) { return "the invoke is marked to be not used for inlining"; - } else if (((MethodCallTargetNode) invoke.callTarget()).receiver() != null && ((MethodCallTargetNode) invoke.callTarget()).receiver().isConstant() && - ((MethodCallTargetNode) invoke.callTarget()).receiver().asConstant().isNull()) { + } + ValueNode receiver = callTarget.receiver(); + if (receiver != null && receiver.isConstant() && receiver.asConstant().isNull()) { return "receiver is null"; - } else { - return null; } + return null; } - private static boolean checkTargetConditions(InliningData data, Replacements replacements, Invoke invoke, ResolvedJavaMethod method, OptimisticOptimizations optimisticOpts) { + public static boolean checkTargetConditions(InliningData data, Replacements replacements, Invoke invoke, ResolvedJavaMethod method, OptimisticOptimizations optimisticOpts) { String failureMessage = null; if (method == null) { failureMessage = "the method is not resolved"; diff -r 10830a8ab30d -r 402a74c6bc14 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java Mon May 19 15:30:57 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java Mon May 19 17:21:35 2014 +0200 @@ -24,27 +24,32 @@ import com.oracle.graal.api.code.Assumptions; import com.oracle.graal.api.code.BailoutException; +import com.oracle.graal.api.meta.JavaTypeProfile; import com.oracle.graal.api.meta.ResolvedJavaMethod; +import com.oracle.graal.api.meta.ResolvedJavaType; import com.oracle.graal.compiler.common.GraalInternalError; +import com.oracle.graal.compiler.common.type.ObjectStamp; import com.oracle.graal.debug.Debug; import com.oracle.graal.debug.DebugMetric; import com.oracle.graal.graph.Graph; import com.oracle.graal.graph.Node; -import com.oracle.graal.nodes.FixedNode; -import com.oracle.graal.nodes.Invoke; -import com.oracle.graal.nodes.StructuredGraph; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode; +import com.oracle.graal.phases.OptimisticOptimizations; import com.oracle.graal.phases.common.CanonicalizerPhase; import com.oracle.graal.phases.common.inlining.InliningUtil; -import com.oracle.graal.phases.common.inlining.info.InlineInfo; +import com.oracle.graal.phases.common.inlining.info.*; import com.oracle.graal.phases.common.inlining.policy.InliningPolicy; import com.oracle.graal.phases.graph.FixedNodeProbabilityCache; import com.oracle.graal.phases.tiers.HighTierContext; import com.oracle.graal.phases.util.Providers; import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.List; import java.util.function.ToDoubleFunction; +import static com.oracle.graal.compiler.common.GraalOptions.MegamorphicInliningMinMethodProbability; import static com.oracle.graal.compiler.common.GraalOptions.OptCanonicalizer; /** @@ -86,6 +91,221 @@ pushGraph(rootGraph, 1.0, 1.0); } + /** + * Determines if inlining is possible at the given invoke node. + * + * @param invoke the invoke that should be inlined + * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke + */ + private InlineInfo getInlineInfo(Invoke invoke, Assumptions assumptions) { + final String failureMessage = InliningUtil.checkInvokeConditions(invoke); + if (failureMessage != null) { + InliningUtil.logNotInlinedMethod(invoke, failureMessage); + return null; + } + MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); + ResolvedJavaMethod targetMethod = callTarget.targetMethod(); + + if (callTarget.invokeKind() == MethodCallTargetNode.InvokeKind.Special || targetMethod.canBeStaticallyBound()) { + return getExactInlineInfo(invoke, targetMethod); + } + + assert callTarget.invokeKind() == MethodCallTargetNode.InvokeKind.Virtual || callTarget.invokeKind() == MethodCallTargetNode.InvokeKind.Interface; + + ResolvedJavaType holder = targetMethod.getDeclaringClass(); + if (!(callTarget.receiver().stamp() instanceof ObjectStamp)) { + return null; + } + ObjectStamp receiverStamp = (ObjectStamp) callTarget.receiver().stamp(); + if (receiverStamp.alwaysNull()) { + // Don't inline if receiver is known to be null + return null; + } + ResolvedJavaType contextType = invoke.getContextType(); + if (receiverStamp.type() != null) { + // the invoke target might be more specific than the holder (happens after inlining: + // parameters lose their declared type...) + ResolvedJavaType receiverType = receiverStamp.type(); + if (receiverType != null && holder.isAssignableFrom(receiverType)) { + holder = receiverType; + if (receiverStamp.isExactType()) { + assert targetMethod.getDeclaringClass().isAssignableFrom(holder) : holder + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod; + ResolvedJavaMethod resolvedMethod = holder.resolveMethod(targetMethod, contextType); + if (resolvedMethod != null) { + return getExactInlineInfo(invoke, resolvedMethod); + } + } + } + } + + if (holder.isArray()) { + // arrays can be treated as Objects + ResolvedJavaMethod resolvedMethod = holder.resolveMethod(targetMethod, contextType); + if (resolvedMethod != null) { + return getExactInlineInfo(invoke, resolvedMethod); + } + } + + if (assumptions.useOptimisticAssumptions()) { + ResolvedJavaType uniqueSubtype = holder.findUniqueConcreteSubtype(); + if (uniqueSubtype != null) { + ResolvedJavaMethod resolvedMethod = uniqueSubtype.resolveMethod(targetMethod, contextType); + if (resolvedMethod != null) { + return getAssumptionInlineInfo(invoke, resolvedMethod, new Assumptions.ConcreteSubtype(holder, uniqueSubtype)); + } + } + + ResolvedJavaMethod concrete = holder.findUniqueConcreteMethod(targetMethod); + if (concrete != null) { + return getAssumptionInlineInfo(invoke, concrete, new Assumptions.ConcreteMethod(targetMethod, holder, concrete)); + } + } + + // type check based inlining + return getTypeCheckedInlineInfo(invoke, targetMethod); + } + + private InlineInfo getTypeCheckedInlineInfo(Invoke invoke, ResolvedJavaMethod targetMethod) { + JavaTypeProfile typeProfile; + ValueNode receiver = invoke.callTarget().arguments().get(0); + if (receiver instanceof TypeProfileProxyNode) { + TypeProfileProxyNode typeProfileProxyNode = (TypeProfileProxyNode) receiver; + typeProfile = typeProfileProxyNode.getProfile(); + } else { + InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "no type profile exists"); + return null; + } + + JavaTypeProfile.ProfiledType[] ptypes = typeProfile.getTypes(); + if (ptypes == null || ptypes.length <= 0) { + InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "no types in profile"); + return null; + } + ResolvedJavaType contextType = invoke.getContextType(); + double notRecordedTypeProbability = typeProfile.getNotRecordedProbability(); + final OptimisticOptimizations optimisticOpts = context.getOptimisticOptimizations(); + if (ptypes.length == 1 && notRecordedTypeProbability == 0) { + if (!optimisticOpts.inlineMonomorphicCalls()) { + InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "inlining monomorphic calls is disabled"); + return null; + } + + ResolvedJavaType type = ptypes[0].getType(); + assert type.isArray() || !type.isAbstract(); + ResolvedJavaMethod concrete = type.resolveMethod(targetMethod, contextType); + if (!InliningUtil.checkTargetConditions(this, context.getReplacements(), invoke, concrete, optimisticOpts)) { + return null; + } + return new TypeGuardInlineInfo(invoke, concrete, type); + } else { + invoke.setPolymorphic(true); + + if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) { + InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length); + return null; + } + if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) { + // due to filtering impossible types, notRecordedTypeProbability can be > 0 although + // the number of types is lower than what can be recorded in a type profile + InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length, + notRecordedTypeProbability * 100); + return null; + } + + // Find unique methods and their probabilities. + ArrayList concreteMethods = new ArrayList<>(); + ArrayList concreteMethodsProbabilities = new ArrayList<>(); + for (int i = 0; i < ptypes.length; i++) { + ResolvedJavaMethod concrete = ptypes[i].getType().resolveMethod(targetMethod, contextType); + if (concrete == null) { + InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "could not resolve method"); + return null; + } + int index = concreteMethods.indexOf(concrete); + double curProbability = ptypes[i].getProbability(); + if (index < 0) { + index = concreteMethods.size(); + concreteMethods.add(concrete); + concreteMethodsProbabilities.add(curProbability); + } else { + concreteMethodsProbabilities.set(index, concreteMethodsProbabilities.get(index) + curProbability); + } + } + + if (concreteMethods.size() > maxMethodPerInlining) { + InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxMethodPerInlining); + return null; + } + + // Clear methods that fall below the threshold. + if (notRecordedTypeProbability > 0) { + ArrayList newConcreteMethods = new ArrayList<>(); + ArrayList newConcreteMethodsProbabilities = new ArrayList<>(); + for (int i = 0; i < concreteMethods.size(); ++i) { + if (concreteMethodsProbabilities.get(i) >= MegamorphicInliningMinMethodProbability.getValue()) { + newConcreteMethods.add(concreteMethods.get(i)); + newConcreteMethodsProbabilities.add(concreteMethodsProbabilities.get(i)); + } + } + + if (newConcreteMethods.size() == 0) { + // No method left that is worth inlining. + InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)", + concreteMethods.size()); + return null; + } + + concreteMethods = newConcreteMethods; + concreteMethodsProbabilities = newConcreteMethodsProbabilities; + } + + // Clean out types whose methods are no longer available. + ArrayList usedTypes = new ArrayList<>(); + ArrayList typesToConcretes = new ArrayList<>(); + for (JavaTypeProfile.ProfiledType type : ptypes) { + ResolvedJavaMethod concrete = type.getType().resolveMethod(targetMethod, contextType); + int index = concreteMethods.indexOf(concrete); + if (index == -1) { + notRecordedTypeProbability += type.getProbability(); + } else { + assert type.getType().isArray() || !type.getType().isAbstract() : type + " " + concrete; + usedTypes.add(type); + typesToConcretes.add(index); + } + } + + if (usedTypes.size() == 0) { + // No type left that is worth checking for. + InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length); + return null; + } + + for (ResolvedJavaMethod concrete : concreteMethods) { + if (!InliningUtil.checkTargetConditions(this, context.getReplacements(), invoke, concrete, optimisticOpts)) { + InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined"); + return null; + } + } + return new MultiTypeGuardInlineInfo(invoke, concreteMethods, concreteMethodsProbabilities, usedTypes, typesToConcretes, notRecordedTypeProbability); + } + } + + private InlineInfo getAssumptionInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, Assumptions.Assumption takenAssumption) { + assert !concrete.isAbstract(); + if (!InliningUtil.checkTargetConditions(this, context.getReplacements(), invoke, concrete, context.getOptimisticOptimizations())) { + return null; + } + return new AssumptionInlineInfo(invoke, concrete, takenAssumption); + } + + private InlineInfo getExactInlineInfo(Invoke invoke, ResolvedJavaMethod targetMethod) { + assert !targetMethod.isAbstract(); + if (!InliningUtil.checkTargetConditions(this, context.getReplacements(), invoke, targetMethod, context.getOptimisticOptimizations())) { + return null; + } + return new ExactInlineInfo(invoke, targetMethod); + } + private void doInline(CallsiteHolder callerCallsiteHolder, MethodInvocation calleeInfo, Assumptions callerAssumptions) { StructuredGraph callerGraph = callerCallsiteHolder.graph(); Graph.Mark markBeforeInlining = callerGraph.getMark(); @@ -146,12 +366,12 @@ /** * Process the next invoke and enqueue all its graphs for processing. */ - void processNextInvoke() { + private void processNextInvoke() { CallsiteHolder callsiteHolder = currentGraph(); Invoke invoke = callsiteHolder.popInvoke(); MethodInvocation callerInvocation = currentInvocation(); Assumptions parentAssumptions = callerInvocation.assumptions(); - InlineInfo info = InliningUtil.getInlineInfo(this, invoke, maxMethodPerInlining, context.getReplacements(), parentAssumptions, context.getOptimisticOptimizations()); + InlineInfo info = getInlineInfo(invoke, parentAssumptions); if (info != null) { double invokeProbability = callsiteHolder.invokeProbability(invoke); @@ -190,16 +410,16 @@ return !graphQueue.isEmpty(); } - public CallsiteHolder currentGraph() { + private CallsiteHolder currentGraph() { return graphQueue.peek(); } - public void popGraph() { + private void popGraph() { graphQueue.pop(); assert graphQueue.size() <= maxGraphs; } - public void popGraphs(int count) { + private void popGraphs(int count) { assert count >= 0; for (int i = 0; i < count; i++) { graphQueue.pop(); @@ -211,7 +431,7 @@ /** * Gets the call hierarchy of this inlining from outer most call to inner most callee. */ - public Object[] inliningContext() { + private Object[] inliningContext() { if (!Debug.isDumpEnabled()) { return NO_CONTEXT; } @@ -223,7 +443,7 @@ return result; } - public MethodInvocation currentInvocation() { + private MethodInvocation currentInvocation() { return invocationQueue.peekFirst(); } @@ -235,7 +455,7 @@ return methodInvocation; } - public void popInvocation() { + private void popInvocation() { maxGraphs -= invocationQueue.peekFirst().callee().numberOfMethods(); assert graphQueue.size() <= maxGraphs; invocationQueue.removeFirst();