changeset 9374:8649dbda7d25

New experiment with megamorphic inlining.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sat, 27 Apr 2013 21:09:32 +0200
parents f11381a65725
children c408b74bfc42
files graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java
diffstat 2 files changed, 76 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Sat Apr 27 20:17:10 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Sat Apr 27 21:09:32 2013 +0200
@@ -546,6 +546,7 @@
             if (shouldFallbackToInvoke()) {
                 replacementNodes.add(null);
             }
+
             if (GraalOptions.OptTailDuplication) {
                 /*
                  * We might want to perform tail duplication at the merge after a type switch, if
@@ -619,7 +620,7 @@
         }
 
         private void createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor) {
-            assert ptypes.size() > 1;
+            assert ptypes.size() >= 1;
 
             Kind hubKind = ((MethodCallTargetNode) invoke.callTarget()).targetMethod().getDeclaringClass().getEncoding(Representation.ObjectHub).getKind();
             LoadHubNode hub = graph.add(new LoadHubNode(((MethodCallTargetNode) invoke.callTarget()).receiver(), hubKind));
@@ -906,26 +907,93 @@
                                 notRecordedTypeProbability * 100);
             }
 
+            ArrayList<ProfiledType> usedTypes = ptypes;
+            if (notRecordedTypeProbability > 0) {
+                // Clean out uncommon types.
+                ArrayList<ProfiledType> newTypes = new ArrayList<>();
+                for (ProfiledType type : ptypes) {
+                    if (type.getProbability() < GraalOptions.MegamorphicInliningMinTypeProbability) {
+                        notRecordedTypeProbability += type.getProbability();
+                    } else {
+                        newTypes.add(type);
+                    }
+                }
+
+                if (newTypes.size() == 0) {
+                    // No type left that is worth checking for.
+                    return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.size());
+                }
+
+                usedTypes = newTypes;
+            }
+
             // determine concrete methods and map type to specific method
             ArrayList<ResolvedJavaMethod> concreteMethods = new ArrayList<>();
-            int[] typesToConcretes = new int[ptypes.size()];
-            for (int i = 0; i < ptypes.size(); i++) {
-                ResolvedJavaMethod concrete = ptypes.get(i).getType().resolveMethod(targetMethod);
+            ArrayList<Double> concreteMethodsProbabilities = new ArrayList<>();
+            int[] typesToConcretes = new int[usedTypes.size()];
+            for (int i = 0; i < usedTypes.size(); i++) {
+                ResolvedJavaMethod concrete = usedTypes.get(i).getType().resolveMethod(targetMethod);
 
                 int index = concreteMethods.indexOf(concrete);
                 if (index < 0) {
                     index = concreteMethods.size();
                     concreteMethods.add(concrete);
+                    concreteMethodsProbabilities.add(usedTypes.get(i).getProbability());
+                } else {
+                    concreteMethodsProbabilities.set(index, concreteMethodsProbabilities.get(index) + usedTypes.get(i).getProbability());
                 }
                 typesToConcretes[i] = index;
             }
 
+            if (notRecordedTypeProbability > 0) {
+                // Clean out uncommon methods.
+                ArrayList<ResolvedJavaMethod> newConcreteMethods = new ArrayList<>();
+                for (int i = 0; i < concreteMethods.size(); ++i) {
+                    if (concreteMethodsProbabilities.get(i) >= GraalOptions.MegamorphicInliningMinMethodProbability) {
+                        newConcreteMethods.add(concreteMethods.get(i));
+                    } else {
+                        concreteMethods.set(i, null);
+                    }
+                }
+
+                if (concreteMethods.size() != newConcreteMethods.size()) {
+
+                    if (newConcreteMethods.size() == 0) {
+                        // No method left that is worth inlining.
+                        return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)", concreteMethods.size());
+                    }
+
+                    // Clean all types that referred to cleaned methods.
+                    ArrayList<ProfiledType> newTypes = new ArrayList<>();
+                    ArrayList<Integer> newTypesToConcretes = new ArrayList<>();
+                    for (int i = 0; i < typesToConcretes.length; ++i) {
+                        ResolvedJavaMethod resolvedJavaMethod = concreteMethods.get(typesToConcretes[i]);
+                        if (resolvedJavaMethod != null) {
+                            newTypes.add(usedTypes.get(i));
+                            newTypesToConcretes.add(newConcreteMethods.indexOf(resolvedJavaMethod));
+                        } else {
+                            notRecordedTypeProbability += usedTypes.get(i).getProbability();
+                        }
+                    }
+
+                    int[] newTypesToConcretesArray = new int[newTypesToConcretes.size()];
+                    for (int i = 0; i < newTypesToConcretesArray.length; ++i) {
+                        newTypesToConcretesArray[i] = newTypesToConcretes.get(i);
+                        concreteMethods.get(typesToConcretes[i]);
+                    }
+
+                    usedTypes = newTypes;
+                    typesToConcretes = newTypesToConcretesArray;
+                    concreteMethods = newConcreteMethods;
+                }
+            }
+
             for (ResolvedJavaMethod concrete : concreteMethods) {
                 if (!checkTargetConditions(replacements, invoke, concrete, optimisticOpts)) {
                     return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined");
                 }
             }
-            return new MultiTypeGuardInlineInfo(invoke, concreteMethods, ptypes, typesToConcretes, notRecordedTypeProbability);
+            return new MultiTypeGuardInlineInfo(invoke, concreteMethods, usedTypes, typesToConcretes, notRecordedTypeProbability);
         }
     }
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Sat Apr 27 20:17:10 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Sat Apr 27 21:09:32 2013 +0200
@@ -44,7 +44,9 @@
     public static boolean Intrinsify                         = true;
            static boolean InlineMonomorphicCalls             = true;
            static boolean InlinePolymorphicCalls             = true;
-           static boolean InlineMegamorphicCalls             = ____;
+           static boolean InlineMegamorphicCalls             = true;
+    public static double  MegamorphicInliningMinTypeProbability = 0.1;
+    public static double  MegamorphicInliningMinMethodProbability = 0.25;
     public static int     MaximumDesiredSize                 = 5000;
     public static int     MaximumRecursiveInlining           = 1;
     public static float   BoostInliningForEscapeAnalysis     = 2f;