changeset 22029:0eedd37f45ba

Remove method-based IC dispatch.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Fri, 19 Jun 2015 15:18:18 +0200
parents 9015ec60f729
children 5b4a974d9ae6 f368142e5631 0571d4a8d7cc
files graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java
diffstat 2 files changed, 15 insertions(+), 107 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Fri Jun 19 15:04:01 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Fri Jun 19 15:18:18 2015 +0200
@@ -25,19 +25,16 @@
 import com.oracle.jvmci.meta.ResolvedJavaType;
 import com.oracle.jvmci.meta.Kind;
 import com.oracle.jvmci.meta.DeoptimizationReason;
-import com.oracle.jvmci.meta.Constant;
 import com.oracle.jvmci.meta.DeoptimizationAction;
 import com.oracle.jvmci.meta.ResolvedJavaMethod;
-import com.oracle.jvmci.meta.MetaAccessProvider;
+
 import java.util.*;
 
 import com.oracle.jvmci.meta.JavaTypeProfile.ProfiledType;
-import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
@@ -59,17 +56,14 @@
     private final double maximumMethodProbability;
     private final ArrayList<Integer> typesToConcretes;
     private final ArrayList<ProfiledType> ptypes;
-    private final ArrayList<Double> concretesProbabilities;
     private final double notRecordedTypeProbability;
     private final Inlineable[] inlineableElements;
 
-    public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList<ResolvedJavaMethod> concretes, ArrayList<Double> concretesProbabilities, ArrayList<ProfiledType> ptypes,
-                    ArrayList<Integer> typesToConcretes, double notRecordedTypeProbability) {
+    public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList<ResolvedJavaMethod> concretes, ArrayList<ProfiledType> ptypes, ArrayList<Integer> typesToConcretes, double notRecordedTypeProbability) {
         super(invoke);
         assert concretes.size() > 0 : "must have at least one method";
         assert ptypes.size() == typesToConcretes.size() : "array lengths must match";
 
-        this.concretesProbabilities = concretesProbabilities;
         this.concretes = concretes;
         this.ptypes = ptypes;
         this.typesToConcretes = typesToConcretes;
@@ -143,7 +137,7 @@
     @Override
     public Collection<Node> inline(Providers providers) {
         if (hasSingleMethod()) {
-            return inlineSingleMethod(graph(), providers.getMetaAccess(), providers.getStampProvider());
+            return inlineSingleMethod(graph(), providers.getStampProvider());
         } else {
             return inlineMultipleMethods(graph(), providers);
         }
@@ -220,7 +214,7 @@
         assert invoke.asNode().isAlive();
 
         // replace the invoke with a switch on the type of the actual receiver
-        boolean methodDispatch = createDispatchOnTypeBeforeInvoke(graph, successors, false, providers.getMetaAccess(), providers.getStampProvider());
+        boolean methodDispatch = createDispatchOnTypeBeforeInvoke(graph, successors, false, providers.getStampProvider());
 
         assert invoke.next() == continuation;
         invoke.setNext(null);
@@ -301,67 +295,26 @@
         return result;
     }
 
-    private Collection<Node> inlineSingleMethod(StructuredGraph graph, MetaAccessProvider metaAccess, StampProvider stampProvider) {
+    private Collection<Node> inlineSingleMethod(StructuredGraph graph, StampProvider stampProvider) {
         assert concretes.size() == 1 && inlineableElements.length == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
 
         AbstractBeginNode calleeEntryNode = graph.add(new BeginNode());
 
         AbstractBeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
         AbstractBeginNode[] successors = new AbstractBeginNode[]{calleeEntryNode, unknownTypeSux};
-        createDispatchOnTypeBeforeInvoke(graph, successors, false, metaAccess, stampProvider);
+        createDispatchOnTypeBeforeInvoke(graph, successors, false, stampProvider);
 
         calleeEntryNode.setNext(invoke.asNode());
 
         return inline(invoke, methodAt(0), inlineableElementAt(0), false);
     }
 
-    private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, AbstractBeginNode[] successors, boolean invokeIsOnlySuccessor, MetaAccessProvider metaAccess, StampProvider stampProvider) {
+    private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, AbstractBeginNode[] successors, boolean invokeIsOnlySuccessor, StampProvider stampProvider) {
         assert ptypes.size() >= 1;
         ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
         LoadHubNode hub = graph.unique(new LoadHubNode(stampProvider, nonNullReceiver));
 
-        if (!invokeIsOnlySuccessor && chooseMethodDispatch()) {
-            assert successors.length == concretes.size() + 1;
-            assert concretes.size() > 0;
-            Debug.log("Method check cascade with %d methods", concretes.size());
-
-            ConstantNode[] constantMethods = new ConstantNode[concretes.size()];
-            double[] probability = new double[concretes.size()];
-            for (int i = 0; i < concretes.size(); ++i) {
-                ResolvedJavaMethod firstMethod = concretes.get(i);
-                Constant firstMethodConstant = firstMethod.getEncoding();
-
-                ConstantNode firstMethodConstantNode = ConstantNode.forConstant(stampProvider.createMethodStamp(), firstMethodConstant, metaAccess, graph);
-                constantMethods[i] = firstMethodConstantNode;
-                double concretesProbability = concretesProbabilities.get(i);
-                assert concretesProbability >= 0.0;
-                probability[i] = concretesProbability;
-                if (i > 0) {
-                    double prevProbability = probability[i - 1];
-                    if (prevProbability == 1.0) {
-                        probability[i] = 1.0;
-                    } else {
-                        probability[i] = Math.min(1.0, Math.max(0.0, probability[i] / (1.0 - prevProbability)));
-                    }
-                }
-            }
-
-            ResolvedJavaType receiverType = invoke.getReceiverType();
-            FixedNode lastSucc = successors[concretes.size()];
-            for (int i = concretes.size() - 1; i >= 0; --i) {
-                LoadMethodNode method = graph.add(new LoadMethodNode(stampProvider.createMethodStamp(), concretes.get(i), receiverType, hub));
-                LogicNode methodCheck = CompareNode.createCompareNode(graph, Condition.EQ, method, constantMethods[i], null);
-                IfNode ifNode = graph.add(new IfNode(methodCheck, successors[i], lastSucc, probability[i]));
-                method.setNext(ifNode);
-                lastSucc = method;
-            }
-
-            FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
-            pred.setNext(lastSucc);
-            return true;
-        } else {
-            Debug.log("Type switch with %d types", concretes.size());
-        }
+        Debug.log("Type switch with %d types", concretes.size());
 
         ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.size()];
         double[] keyProbabilities = new double[ptypes.size() + 1];
@@ -388,51 +341,6 @@
         return false;
     }
 
-    private boolean chooseMethodDispatch() {
-        ResolvedJavaType receiverType = invoke.getReceiverType();
-        for (ResolvedJavaMethod concrete : concretes) {
-            if (!concrete.isInVirtualMethodTable(receiverType)) {
-                return false;
-            }
-        }
-
-        if (concretes.size() == 1 && this.notRecordedTypeProbability > 0) {
-            // Always chose method dispatch if there is a single concrete method and the call
-            // site is megamorphic.
-            return true;
-        }
-
-        if (concretes.size() == ptypes.size()) {
-            // Always prefer types over methods if the number of types is smaller than the
-            // number of methods.
-            return false;
-        }
-
-        return chooseMethodDispatchCostBased();
-    }
-
-    private boolean chooseMethodDispatchCostBased() {
-        double remainder = 1.0 - this.notRecordedTypeProbability;
-        double costEstimateMethodDispatch = remainder;
-        for (int i = 0; i < concretes.size(); ++i) {
-            if (i != 0) {
-                costEstimateMethodDispatch += remainder;
-            }
-            remainder -= concretesProbabilities.get(i);
-        }
-
-        double costEstimateTypeDispatch = 0.0;
-        remainder = 1.0;
-        for (int i = 0; i < ptypes.size(); ++i) {
-            if (i != 0) {
-                costEstimateTypeDispatch += remainder;
-            }
-            remainder -= ptypes.get(i).getProbability();
-        }
-        costEstimateTypeDispatch += notRecordedTypeProbability;
-        return costEstimateMethodDispatch < costEstimateTypeDispatch;
-    }
-
     private static AbstractBeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, AbstractMergeNode returnMerge, PhiNode returnValuePhi, AbstractMergeNode exceptionMerge,
                     PhiNode exceptionObjectPhi, boolean useForInlining) {
         Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining);
@@ -487,13 +395,13 @@
     @Override
     public void tryToDevirtualizeInvoke(Providers providers) {
         if (hasSingleMethod()) {
-            devirtualizeWithTypeSwitch(graph(), InvokeKind.Special, concretes.get(0), providers.getMetaAccess(), providers.getStampProvider());
+            devirtualizeWithTypeSwitch(graph(), InvokeKind.Special, concretes.get(0), providers.getStampProvider());
         } else {
-            tryToDevirtualizeMultipleMethods(graph(), providers.getMetaAccess(), providers.getStampProvider());
+            tryToDevirtualizeMultipleMethods(graph(), providers.getStampProvider());
         }
     }
 
-    private void tryToDevirtualizeMultipleMethods(StructuredGraph graph, MetaAccessProvider metaAccess, StampProvider stampProvider) {
+    private void tryToDevirtualizeMultipleMethods(StructuredGraph graph, StampProvider stampProvider) {
         MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget();
         if (methodCallTarget.invokeKind() == InvokeKind.Interface) {
             ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod();
@@ -505,17 +413,17 @@
             if (!leastCommonType.isInterface() && targetMethod.getDeclaringClass().isAssignableFrom(leastCommonType)) {
                 ResolvedJavaMethod baseClassTargetMethod = leastCommonType.resolveConcreteMethod(targetMethod, contextType);
                 if (baseClassTargetMethod != null) {
-                    devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveConcreteMethod(targetMethod, contextType), metaAccess, stampProvider);
+                    devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveConcreteMethod(targetMethod, contextType), stampProvider);
                 }
             }
         }
     }
 
-    private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target, MetaAccessProvider metaAccess, StampProvider stampProvider) {
+    private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target, StampProvider stampProvider) {
         AbstractBeginNode invocationEntry = graph.add(new BeginNode());
         AbstractBeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
         AbstractBeginNode[] successors = new AbstractBeginNode[]{invocationEntry, unknownTypeSux};
-        createDispatchOnTypeBeforeInvoke(graph, successors, true, metaAccess, stampProvider);
+        createDispatchOnTypeBeforeInvoke(graph, successors, true, stampProvider);
 
         invocationEntry.setNext(invoke.asNode());
         ValueNode receiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Fri Jun 19 15:04:01 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Fri Jun 19 15:18:18 2015 +0200
@@ -335,7 +335,7 @@
                     return null;
                 }
             }
-            return new MultiTypeGuardInlineInfo(invoke, concreteMethods, concreteMethodsProbabilities, usedTypes, typesToConcretes, notRecordedTypeProbability);
+            return new MultiTypeGuardInlineInfo(invoke, concreteMethods, usedTypes, typesToConcretes, notRecordedTypeProbability);
         }
     }