changeset 7223:e2ea829fafd9

use CHA more frequently for inlining filter types when doing a type-checked inlining
author Christian Haeubl <haeubl@ssw.jku.at>
date Tue, 11 Dec 2012 16:38:27 +0100
parents 720925633b3a
children fb16d8681ddc
files graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java 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 graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java
diffstat 4 files changed, 103 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java	Tue Dec 11 09:10:50 2012 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java	Tue Dec 11 16:38:27 2012 +0100
@@ -267,7 +267,7 @@
         record(new MethodContents(method));
     }
 
-    private void record(Assumption assumption) {
+    public void record(Assumption assumption) {
         if (list == null) {
             list = new Assumption[4];
         } else {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Tue Dec 11 09:10:50 2012 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Tue Dec 11 16:38:27 2012 +0100
@@ -27,6 +27,7 @@
 import java.util.concurrent.*;
 
 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.api.meta.ResolvedJavaType.Representation;
@@ -299,15 +300,15 @@
      */
     private static class MultiTypeGuardInlineInfo extends AbstractInlineInfo {
         public final List<ResolvedJavaMethod> concretes;
-        public final ProfiledType[] ptypes;
+        public final ArrayList<ProfiledType> ptypes;
         public final int[] typesToConcretes;
         public final double notRecordedTypeProbability;
 
-        public MultiTypeGuardInlineInfo(Invoke invoke, double weight, List<ResolvedJavaMethod> concretes, ProfiledType[] ptypes,
+        public MultiTypeGuardInlineInfo(Invoke invoke, double weight, ArrayList<ResolvedJavaMethod> concretes, ArrayList<ProfiledType> ptypes,
                         int[] typesToConcretes, double notRecordedTypeProbability) {
             super(invoke, weight);
-            assert concretes.size() > 0 && concretes.size() <= ptypes.length : "must have at least one method but no more than types methods";
-            assert ptypes.length == typesToConcretes.length : "array lengths must match";
+            assert concretes.size() > 0 && concretes.size() <= ptypes.size() : "must have at least one method but no more than types methods";
+            assert ptypes.size() == typesToConcretes.length : "array lengths must match";
 
             this.concretes = concretes;
             this.ptypes = ptypes;
@@ -378,7 +379,7 @@
                 double probability = 0;
                 for (int j = 0; j < typesToConcretes.length; j++) {
                     if (typesToConcretes[j] == i) {
-                        probability += ptypes[j].getProbability();
+                        probability += ptypes.get(j).getProbability();
                     }
                 }
 
@@ -483,9 +484,9 @@
             for (int i = 0; i < typesToConcretes.length; i++) {
                 if (typesToConcretes[i] == concreteMethodIndex) {
                     if (commonType == null) {
-                        commonType = ptypes[i].getType();
+                        commonType = ptypes.get(i).getType();
                     } else {
-                        commonType = commonType.findLeastCommonAncestor(ptypes[i].getType());
+                        commonType = commonType.findLeastCommonAncestor(ptypes.get(i).getType());
                     }
                 }
             }
@@ -494,7 +495,7 @@
         }
 
         private void inlineSingleMethod(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions) {
-            assert concretes.size() == 1 && ptypes.length > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
+            assert concretes.size() == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
 
             BeginNode calleeEntryNode = graph.add(new BeginNode());
             calleeEntryNode.setProbability(invoke.probability());
@@ -517,14 +518,14 @@
         }
 
         private FixedNode createDispatchOnType(StructuredGraph graph, LoadHubNode hub, BeginNode[] successors) {
-            assert ptypes.length > 1;
+            assert ptypes.size() > 1;
 
-            ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.length];
-            double[] keyProbabilities = new double[ptypes.length + 1];
-            int[] keySuccessors = new int[ptypes.length + 1];
-            for (int i = 0; i < ptypes.length; i++) {
-                keys[i] = ptypes[i].getType();
-                keyProbabilities[i] = ptypes[i].getProbability();
+            ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.size()];
+            double[] keyProbabilities = new double[ptypes.size() + 1];
+            int[] keySuccessors = new int[ptypes.size() + 1];
+            for (int i = 0; i < ptypes.size(); i++) {
+                keys[i] = ptypes.get(i).getType();
+                keyProbabilities[i] = ptypes.get(i).getProbability();
                 keySuccessors[i] = typesToConcretes[i];
                 assert keySuccessors[i] < successors.length - 1 : "last successor is the unknownTypeSux";
             }
@@ -605,12 +606,12 @@
                 builder.append(MetaUtil.format("  %H.%n(%p):%r", concretes.get(i)));
             }
             builder.append(" ], ");
-            builder.append(ptypes.length);
+            builder.append(ptypes.size());
             builder.append(" type checks [ ");
-            for (int i = 0; i < ptypes.length; i++) {
+            for (int i = 0; i < ptypes.size(); i++) {
                 builder.append("  ");
-                builder.append(ptypes[i].getType().getName());
-                builder.append(ptypes[i].getProbability());
+                builder.append(ptypes.get(i).getType().getName());
+                builder.append(ptypes.get(i).getProbability());
             }
             builder.append(" ]");
             return builder.toString();
@@ -623,21 +624,17 @@
      * but for which an assumption has to be registered because of non-final classes.
      */
     private static class AssumptionInlineInfo extends ExactInlineInfo {
-        public final ResolvedJavaType context;
+        private final Assumption takenAssumption;
 
-        public AssumptionInlineInfo(Invoke invoke, double weight, ResolvedJavaType context, ResolvedJavaMethod concrete) {
+        public AssumptionInlineInfo(Invoke invoke, double weight, ResolvedJavaMethod concrete, Assumption takenAssumption) {
             super(invoke, weight, concrete);
-            this.context = context;
+            this.takenAssumption = takenAssumption;
         }
 
         @Override
         public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions) {
-            if (Debug.isLogEnabled()) {
-                String targetName = MetaUtil.format("%H.%n(%p):%r", invoke.methodCallTarget().targetMethod());
-                String concreteName = MetaUtil.format("%H.%n(%p):%r", concrete);
-                Debug.log("recording concrete method assumption: %s on receiver type %s -> %s", targetName, context, concreteName);
-            }
-            assumptions.recordConcreteMethod(invoke.methodCallTarget().targetMethod(), context, concrete);
+            assumptions.record(takenAssumption);
+            Debug.log("recording assumption: %s", takenAssumption);
 
             super.inline(graph, runtime, callback, assumptions);
         }
@@ -664,68 +661,90 @@
         ResolvedJavaMethod targetMethod = callTarget.targetMethod();
 
         if (callTarget.invokeKind() == InvokeKind.Special || targetMethod.canBeStaticallyBound()) {
-            if (!checkTargetConditions(invoke, targetMethod, optimisticOpts, runtime)) {
-                return null;
-            }
-            double weight = inliningPolicy.inliningWeight(caller, targetMethod, invoke);
-            return new ExactInlineInfo(invoke, weight, targetMethod);
+            return getExactInlineInfo(invoke, runtime, inliningPolicy, optimisticOpts, caller, targetMethod);
         }
+
+        assert callTarget.invokeKind() == InvokeKind.Virtual || callTarget.invokeKind() == InvokeKind.Interface;
+
+        ResolvedJavaType holder = targetMethod.getDeclaringClass();
         ObjectStamp receiverStamp = callTarget.receiver().objectStamp();
-        ResolvedJavaType receiverType = receiverStamp.type();
-        if (receiverStamp.isExactType()) {
-            assert targetMethod.getDeclaringClass().isAssignableFrom(receiverType) : receiverType + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod;
-            ResolvedJavaMethod resolved = receiverType.resolveMethod(targetMethod);
-            if (!checkTargetConditions(invoke, resolved, optimisticOpts, runtime)) {
-                return null;
-            }
-            double weight = inliningPolicy.inliningWeight(caller, resolved, invoke);
-            return new ExactInlineInfo(invoke, weight, resolved);
-        }
-        ResolvedJavaType holder = targetMethod.getDeclaringClass();
-
         if (receiverStamp.type() != null) {
             // the invoke target might be more specific than the holder (happens after inlining: locals lose their declared type...)
-            // TODO (lstadler) fix this
+            ResolvedJavaType receiverType = receiverStamp.type();
             if (receiverType != null && holder.isAssignableFrom(receiverType)) {
                 holder = receiverType;
-            }
-        }
-        // TODO (thomaswue) fix this
-        if (assumptions.useOptimisticAssumptions()) {
-            ResolvedJavaMethod concrete = holder.findUniqueConcreteMethod(targetMethod);
-            if (concrete != null) {
-                if (!checkTargetConditions(invoke, concrete, optimisticOpts, runtime)) {
-                    return null;
+                if (receiverStamp.isExactType()) {
+                    assert targetMethod.getDeclaringClass().isAssignableFrom(holder) : holder + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod;
+                    return getExactInlineInfo(invoke, runtime, inliningPolicy, optimisticOpts, caller, holder.resolveMethod(targetMethod));
                 }
-                double weight = inliningPolicy.inliningWeight(caller, concrete, invoke);
-                return new AssumptionInlineInfo(invoke, weight, holder, concrete);
             }
         }
 
+        if (holder.isArray()) {
+            // arrays can be treated as Objects
+            return getExactInlineInfo(invoke, runtime, inliningPolicy, optimisticOpts, caller, holder.resolveMethod(targetMethod));
+        }
+
+        // TODO (chaeubl): we could also use the type determined after assumptions for the type-checked inlining case as it might have an effect on type filtering
+        if (assumptions.useOptimisticAssumptions()) {
+            ResolvedJavaType uniqueSubtype = holder.findUniqueConcreteSubtype();
+            if (uniqueSubtype != null) {
+                return getAssumptionInlineInfo(invoke, runtime, inliningPolicy, optimisticOpts, caller, uniqueSubtype.resolveMethod(targetMethod), new Assumptions.ConcreteSubtype(holder, uniqueSubtype));
+            }
+
+            ResolvedJavaMethod concrete = holder.findUniqueConcreteMethod(targetMethod);
+            if (concrete != null) {
+                return getAssumptionInlineInfo(invoke, runtime, inliningPolicy, optimisticOpts, caller, concrete, new Assumptions.ConcreteMethod(targetMethod, holder, concrete));
+            }
+
+            // TODO (chaeubl): C1 has one more assumption in the case of interfaces
+        }
+
         // type check based inlining
-        return getTypeCheckedInlineInfo(invoke, inliningPolicy, caller, targetMethod, optimisticOpts, runtime);
+        return getTypeCheckedInlineInfo(invoke, inliningPolicy, caller, holder, targetMethod, optimisticOpts, runtime);
+    }
+
+    private static InlineInfo getAssumptionInlineInfo(Invoke invoke, GraalCodeCacheProvider runtime, InliningPolicy inliningPolicy, OptimisticOptimizations optimisticOpts,
+                    ResolvedJavaMethod caller, ResolvedJavaMethod concrete, Assumption takenAssumption) {
+        assert !Modifier.isAbstract(concrete.getModifiers());
+        if (!checkTargetConditions(invoke, concrete, optimisticOpts, runtime)) {
+            return null;
+        }
+        double weight = inliningPolicy.inliningWeight(caller, concrete, invoke);
+        return new AssumptionInlineInfo(invoke, weight, concrete, takenAssumption);
+    }
+
+    private static InlineInfo getExactInlineInfo(Invoke invoke, GraalCodeCacheProvider runtime, InliningPolicy inliningPolicy, OptimisticOptimizations optimisticOpts,
+                    ResolvedJavaMethod caller, ResolvedJavaMethod targetMethod) {
+        assert !Modifier.isAbstract(targetMethod.getModifiers());
+        if (!checkTargetConditions(invoke, targetMethod, optimisticOpts, runtime)) {
+            return null;
+        }
+        double weight = inliningPolicy.inliningWeight(caller, targetMethod, invoke);
+        return new ExactInlineInfo(invoke, weight, targetMethod);
     }
 
     private static InlineInfo getTypeCheckedInlineInfo(Invoke invoke, InliningPolicy inliningPolicy, ResolvedJavaMethod caller,
-                    ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts, GraalCodeCacheProvider runtime) {
+                    ResolvedJavaType holder, ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts, GraalCodeCacheProvider runtime) {
         ProfilingInfo profilingInfo = caller.getProfilingInfo();
         JavaTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci());
         if (typeProfile == null) {
             return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no type profile exists");
         }
 
-        ProfiledType[] ptypes = typeProfile.getTypes();
-        if (ptypes == null || ptypes.length <= 0) {
-            return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types/probabilities were recorded");
+        ProfiledType[] rawProfiledTypes = typeProfile.getTypes();
+        ArrayList<ProfiledType> ptypes = getCompatibleTypes(rawProfiledTypes, holder);
+        if (ptypes == null || ptypes.size() <= 0) {
+            return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types remained after filtering (%d types were recorded)", rawProfiledTypes.length);
         }
 
         double notRecordedTypeProbability = typeProfile.getNotRecordedProbability();
-        if (ptypes.length == 1 && notRecordedTypeProbability == 0) {
+        if (ptypes.size() == 1 && notRecordedTypeProbability == 0) {
             if (!optimisticOpts.inlineMonomorphicCalls()) {
                 return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining monomorphic calls is disabled");
             }
 
-            ResolvedJavaType type = ptypes[0].getType();
+            ResolvedJavaType type = ptypes.get(0).getType();
             ResolvedJavaMethod concrete = type.resolveMethod(targetMethod);
             if (!checkTargetConditions(invoke, concrete, optimisticOpts, runtime)) {
                 return null;
@@ -736,10 +755,10 @@
             invoke.setPolymorphic(true);
 
             if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) {
-                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length);
+                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.size());
             }
             if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) {
-                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length, notRecordedTypeProbability * 100);
+                return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.size(), notRecordedTypeProbability * 100);
             }
 
             // TODO (chaeubl) inlining of multiple methods should work differently
@@ -751,9 +770,9 @@
 
             // determine concrete methods and map type to specific method
             ArrayList<ResolvedJavaMethod> concreteMethods = new ArrayList<>();
-            int[] typesToConcretes = new int[ptypes.length];
-            for (int i = 0; i < ptypes.length; i++) {
-                ResolvedJavaMethod concrete = ptypes[i].getType().resolveMethod(targetMethod);
+            int[] typesToConcretes = new int[ptypes.size()];
+            for (int i = 0; i < ptypes.size(); i++) {
+                ResolvedJavaMethod concrete = ptypes.get(i).getType().resolveMethod(targetMethod);
 
                 int index = concreteMethods.indexOf(concrete);
                 if (index < 0) {
@@ -775,6 +794,19 @@
     }
 
 
+    private static ArrayList<ProfiledType> getCompatibleTypes(ProfiledType[] types, ResolvedJavaType holder) {
+        ArrayList<ProfiledType> result = new ArrayList<>();
+        for (int i = 0; i < types.length; i++) {
+            ProfiledType ptype = types[i];
+            ResolvedJavaType type = ptype.getType();
+            assert !type.isInterface() && !Modifier.isAbstract(type.getModifiers());
+            if (holder.isAssignableFrom(type)) {
+                result.add(ptype);
+            }
+        }
+        return result;
+    }
+
     private static ResolvedJavaMethod getCaller(Invoke invoke) {
         return invoke.stateAfter().method();
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Tue Dec 11 09:10:50 2012 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Tue Dec 11 16:38:27 2012 +0100
@@ -199,7 +199,7 @@
     public static boolean OptEliminatePartiallyRedundantGuards = true;
 
     // Intrinsification settings
-    public static boolean IntrinsifyArrayCopy                = false;
+    public static boolean IntrinsifyArrayCopy                = true;
     public static boolean IntrinsifyObjectMethods            = true;
     public static boolean IntrinsifySystemMethods            = true;
     public static boolean IntrinsifyClassMethods             = true;
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java	Tue Dec 11 09:10:50 2012 +0100
+++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java	Tue Dec 11 16:38:27 2012 +0100
@@ -369,6 +369,7 @@
                 StructuredGraph graph = parse(snippet);
                 PhasePlan phasePlan = getDefaultPhasePlan();
                 Assumptions assumptions = new Assumptions(true);
+                new ComputeProbabilityPhase().apply(graph);
                 Debug.dump(graph, "Graph");
                 new InliningPhase(null, runtime(), null, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph);
                 Debug.dump(graph, "Graph");