Search in sources :

Example 1 with MultiTypeGuardInlineInfo

use of org.graalvm.compiler.phases.common.inlining.info.MultiTypeGuardInlineInfo 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)

Aggregations

ArrayList (java.util.ArrayList)1 JavaTypeProfile (jdk.vm.ci.meta.JavaTypeProfile)1 ResolvedJavaMethod (jdk.vm.ci.meta.ResolvedJavaMethod)1 ResolvedJavaType (jdk.vm.ci.meta.ResolvedJavaType)1 MethodCallTargetNode (org.graalvm.compiler.nodes.java.MethodCallTargetNode)1 OptionValues (org.graalvm.compiler.options.OptionValues)1 OptimisticOptimizations (org.graalvm.compiler.phases.OptimisticOptimizations)1 MultiTypeGuardInlineInfo (org.graalvm.compiler.phases.common.inlining.info.MultiTypeGuardInlineInfo)1 TypeGuardInlineInfo (org.graalvm.compiler.phases.common.inlining.info.TypeGuardInlineInfo)1