Search in sources :

Example 41 with MethodCallTargetNode

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);
    }
}
Also used : OptionValues(org.graalvm.compiler.options.OptionValues) TypeGuardInlineInfo(org.graalvm.compiler.phases.common.inlining.info.TypeGuardInlineInfo) MultiTypeGuardInlineInfo(org.graalvm.compiler.phases.common.inlining.info.MultiTypeGuardInlineInfo) ArrayList(java.util.ArrayList) MultiTypeGuardInlineInfo(org.graalvm.compiler.phases.common.inlining.info.MultiTypeGuardInlineInfo) ResolvedJavaType(jdk.vm.ci.meta.ResolvedJavaType) MethodCallTargetNode(org.graalvm.compiler.nodes.java.MethodCallTargetNode) JavaTypeProfile(jdk.vm.ci.meta.JavaTypeProfile) OptimisticOptimizations(org.graalvm.compiler.phases.OptimisticOptimizations) ResolvedJavaMethod(jdk.vm.ci.meta.ResolvedJavaMethod)

Example 42 with MethodCallTargetNode

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);
}
Also used : MethodCallTargetNode(org.graalvm.compiler.nodes.java.MethodCallTargetNode) ObjectStamp(org.graalvm.compiler.core.common.type.ObjectStamp) ResolvedJavaMethod(jdk.vm.ci.meta.ResolvedJavaMethod) ResolvedJavaType(jdk.vm.ci.meta.ResolvedJavaType)

Example 43 with MethodCallTargetNode

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;
}
Also used : FixedWithNextNode(org.graalvm.compiler.nodes.FixedWithNextNode) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) MethodCallTargetNode(org.graalvm.compiler.nodes.java.MethodCallTargetNode) AbstractEndNode(org.graalvm.compiler.nodes.AbstractEndNode) LoopEndNode(org.graalvm.compiler.nodes.LoopEndNode) EndNode(org.graalvm.compiler.nodes.EndNode) ControlSplitNode(org.graalvm.compiler.nodes.ControlSplitNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode) ControlSinkNode(org.graalvm.compiler.nodes.ControlSinkNode) LinkedList(java.util.LinkedList) Invoke(org.graalvm.compiler.nodes.Invoke) LoopEndNode(org.graalvm.compiler.nodes.LoopEndNode)

Example 44 with MethodCallTargetNode

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);
            }
        }
    }
}
Also used : MethodCallTargetNode(org.graalvm.compiler.nodes.java.MethodCallTargetNode) ResolvedJavaMethod(jdk.vm.ci.meta.ResolvedJavaMethod) ResolvedJavaType(jdk.vm.ci.meta.ResolvedJavaType)

Example 45 with MethodCallTargetNode

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);
}
Also used : MethodCallTargetNode(org.graalvm.compiler.nodes.java.MethodCallTargetNode) BeginNode(org.graalvm.compiler.nodes.BeginNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) PiNode(org.graalvm.compiler.nodes.PiNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode)

Aggregations

MethodCallTargetNode (org.graalvm.compiler.nodes.java.MethodCallTargetNode)46 ResolvedJavaType (jdk.vm.ci.meta.ResolvedJavaType)17 ResolvedJavaMethod (jdk.vm.ci.meta.ResolvedJavaMethod)15 ValueNode (org.graalvm.compiler.nodes.ValueNode)15 StructuredGraph (org.graalvm.compiler.nodes.StructuredGraph)11 Invoke (org.graalvm.compiler.nodes.Invoke)10 Node (org.graalvm.compiler.graph.Node)9 InvokeNode (org.graalvm.compiler.nodes.InvokeNode)9 ArrayList (java.util.ArrayList)7 StampPair (org.graalvm.compiler.core.common.type.StampPair)7 PiNode (org.graalvm.compiler.nodes.PiNode)7 DebugContext (org.graalvm.compiler.debug.DebugContext)6 CallTargetNode (org.graalvm.compiler.nodes.CallTargetNode)6 AbstractBeginNode (org.graalvm.compiler.nodes.AbstractBeginNode)5 FixedWithNextNode (org.graalvm.compiler.nodes.FixedWithNextNode)5 FrameState (org.graalvm.compiler.nodes.FrameState)5 JavaType (jdk.vm.ci.meta.JavaType)4 ObjectStamp (org.graalvm.compiler.core.common.type.ObjectStamp)4 AbstractMergeNode (org.graalvm.compiler.nodes.AbstractMergeNode)4 FixedGuardNode (org.graalvm.compiler.nodes.FixedGuardNode)4