use of org.graalvm.compiler.nodes.java.MethodCallTargetNode in project graal by oracle.
the class InliningData method getTypeCheckedInlineInfo.
private InlineInfo getTypeCheckedInlineInfo(Invoke invoke, ResolvedJavaMethod targetMethod) {
JavaTypeProfile typeProfile = ((MethodCallTargetNode) invoke.callTarget()).getProfile();
if (typeProfile == null) {
InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "no type profile exists");
return null;
}
JavaTypeProfile.ProfiledType[] ptypes = typeProfile.getTypes();
if (ptypes == null || ptypes.length <= 0) {
InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "no types in profile");
return null;
}
ResolvedJavaType contextType = invoke.getContextType();
double notRecordedTypeProbability = typeProfile.getNotRecordedProbability();
final OptimisticOptimizations optimisticOpts = context.getOptimisticOptimizations();
OptionValues options = invoke.asNode().getOptions();
if (ptypes.length == 1 && notRecordedTypeProbability == 0) {
if (!optimisticOpts.inlineMonomorphicCalls(options)) {
InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "inlining monomorphic calls is disabled");
return null;
}
ResolvedJavaType type = ptypes[0].getType();
assert type.isArray() || type.isConcrete();
ResolvedJavaMethod concrete = type.resolveConcreteMethod(targetMethod, contextType);
if (!checkTargetConditions(invoke, concrete)) {
return null;
}
return new TypeGuardInlineInfo(invoke, concrete, type);
} else {
invoke.setPolymorphic(true);
if (!optimisticOpts.inlinePolymorphicCalls(options) && notRecordedTypeProbability == 0) {
InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length);
return null;
}
if (!optimisticOpts.inlineMegamorphicCalls(options) && 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.traceNotInlinedMethod(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<ResolvedJavaMethod> concreteMethods = new ArrayList<>();
ArrayList<Double> concreteMethodsProbabilities = new ArrayList<>();
for (int i = 0; i < ptypes.length; i++) {
ResolvedJavaMethod concrete = ptypes[i].getType().resolveConcreteMethod(targetMethod, contextType);
if (concrete == null) {
InliningUtil.traceNotInlinedMethod(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);
}
}
// Clear methods that fall below the threshold.
if (notRecordedTypeProbability > 0) {
ArrayList<ResolvedJavaMethod> newConcreteMethods = new ArrayList<>();
ArrayList<Double> newConcreteMethodsProbabilities = new ArrayList<>();
for (int i = 0; i < concreteMethods.size(); ++i) {
if (concreteMethodsProbabilities.get(i) >= MegamorphicInliningMinMethodProbability.getValue(options)) {
newConcreteMethods.add(concreteMethods.get(i));
newConcreteMethodsProbabilities.add(concreteMethodsProbabilities.get(i));
}
}
if (newConcreteMethods.isEmpty()) {
// No method left that is worth inlining.
InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)", concreteMethods.size());
return null;
}
concreteMethods = newConcreteMethods;
concreteMethodsProbabilities = newConcreteMethodsProbabilities;
}
if (concreteMethods.size() > maxMethodPerInlining) {
InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxMethodPerInlining);
return null;
}
// Clean out types whose methods are no longer available.
ArrayList<JavaTypeProfile.ProfiledType> usedTypes = new ArrayList<>();
ArrayList<Integer> typesToConcretes = new ArrayList<>();
for (JavaTypeProfile.ProfiledType type : ptypes) {
ResolvedJavaMethod concrete = type.getType().resolveConcreteMethod(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.isEmpty()) {
// No type left that is worth checking for.
InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length);
return null;
}
for (ResolvedJavaMethod concrete : concreteMethods) {
if (!checkTargetConditions(invoke, concrete)) {
InliningUtil.traceNotInlinedMethod(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, usedTypes, typesToConcretes, notRecordedTypeProbability);
}
}
use of org.graalvm.compiler.nodes.java.MethodCallTargetNode in project graal by oracle.
the class InliningData method getInlineInfo.
/**
* 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) {
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() == CallTargetNode.InvokeKind.Special || targetMethod.canBeStaticallyBound()) {
return getExactInlineInfo(invoke, targetMethod);
}
assert callTarget.invokeKind().isIndirect();
ResolvedJavaType holder = targetMethod.getDeclaringClass();
if (!(callTarget.receiver().stamp(NodeView.DEFAULT) instanceof ObjectStamp)) {
return null;
}
ObjectStamp receiverStamp = (ObjectStamp) callTarget.receiver().stamp(NodeView.DEFAULT);
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.resolveConcreteMethod(targetMethod, contextType);
if (resolvedMethod != null) {
return getExactInlineInfo(invoke, resolvedMethod);
}
}
}
}
if (holder.isArray()) {
// arrays can be treated as Objects
ResolvedJavaMethod resolvedMethod = holder.resolveConcreteMethod(targetMethod, contextType);
if (resolvedMethod != null) {
return getExactInlineInfo(invoke, resolvedMethod);
}
}
AssumptionResult<ResolvedJavaType> leafConcreteSubtype = holder.findLeafConcreteSubtype();
if (leafConcreteSubtype != null) {
ResolvedJavaMethod resolvedMethod = leafConcreteSubtype.getResult().resolveConcreteMethod(targetMethod, contextType);
if (resolvedMethod != null) {
if (leafConcreteSubtype.canRecordTo(callTarget.graph().getAssumptions())) {
return getAssumptionInlineInfo(invoke, resolvedMethod, leafConcreteSubtype);
} else {
return getTypeCheckedAssumptionInfo(invoke, resolvedMethod, leafConcreteSubtype.getResult());
}
}
}
AssumptionResult<ResolvedJavaMethod> concrete = holder.findUniqueConcreteMethod(targetMethod);
if (concrete != null && concrete.canRecordTo(callTarget.graph().getAssumptions())) {
return getAssumptionInlineInfo(invoke, concrete.getResult(), concrete);
}
// type check based inlining
return getTypeCheckedInlineInfo(invoke, targetMethod);
}
use of org.graalvm.compiler.nodes.java.MethodCallTargetNode in project graal by oracle.
the class InliningIterator method apply.
public LinkedList<Invoke> apply() {
LinkedList<Invoke> invokes = new LinkedList<>();
FixedNode current;
forcedQueue(start);
while ((current = nextQueuedNode()) != null) {
assert current.isAlive();
if (current instanceof Invoke && ((Invoke) current).callTarget() instanceof MethodCallTargetNode) {
if (current != start) {
invokes.addLast((Invoke) current);
}
queueSuccessors(current);
} else if (current instanceof LoopBeginNode) {
queueSuccessors(current);
} else if (current instanceof LoopEndNode) {
// nothing to do
} else if (current instanceof AbstractMergeNode) {
queueSuccessors(current);
} else if (current instanceof FixedWithNextNode) {
queueSuccessors(current);
} else if (current instanceof EndNode) {
queueMerge((EndNode) current);
} else if (current instanceof ControlSinkNode) {
// nothing to do
} else if (current instanceof ControlSplitNode) {
queueSuccessors(current);
} else {
assert false : current;
}
}
assert invokes.size() == count(start.graph().getInvokes());
return invokes;
}
use of org.graalvm.compiler.nodes.java.MethodCallTargetNode in project graal by oracle.
the class MultiTypeGuardInlineInfo method tryToDevirtualizeMultipleMethods.
private void tryToDevirtualizeMultipleMethods(StructuredGraph graph, StampProvider stampProvider, ConstantReflectionProvider constantReflection) {
MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget();
if (methodCallTarget.invokeKind() == InvokeKind.Interface) {
ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod();
ResolvedJavaType leastCommonType = getLeastCommonType();
ResolvedJavaType contextType = invoke.getContextType();
// virtual call
if (!leastCommonType.isInterface() && targetMethod.getDeclaringClass().isAssignableFrom(leastCommonType)) {
ResolvedJavaMethod baseClassTargetMethod = leastCommonType.resolveConcreteMethod(targetMethod, contextType);
if (baseClassTargetMethod != null) {
devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveConcreteMethod(targetMethod, contextType), stampProvider, constantReflection);
}
}
}
}
use of org.graalvm.compiler.nodes.java.MethodCallTargetNode in project graal by oracle.
the class MultiTypeGuardInlineInfo method devirtualizeWithTypeSwitch.
private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target, StampProvider stampProvider, ConstantReflectionProvider constantReflection) {
AbstractBeginNode invocationEntry = graph.add(new BeginNode());
AbstractBeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
AbstractBeginNode[] successors = new AbstractBeginNode[] { invocationEntry, unknownTypeSux };
createDispatchOnTypeBeforeInvoke(graph, successors, true, stampProvider, constantReflection);
invocationEntry.setNext(invoke.asNode());
ValueNode receiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
PiNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, invocationEntry, target.getDeclaringClass(), receiver, false);
invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver);
InliningUtil.replaceInvokeCallTarget(invoke, graph, kind, target);
}
Aggregations