changeset 15725:ef6b8d1898e6

Add resolved receiver type to ResolvedJavaMethod.isInVirtualMethodTable in order to be able to do vtable-calls for miranda and default methods
author Gilles Duboscq <duboscq@ssw.jku.at>
date Sat, 17 May 2014 14:57:58 +0200
parents a9f969e65b61
children 668d158f780c
files graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java src/share/vm/graal/graalCompilerToVM.cpp
diffstat 11 files changed, 108 insertions(+), 73 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Sat May 17 11:41:35 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Sat May 17 14:57:58 2014 +0200
@@ -218,9 +218,10 @@
     Constant getEncoding();
 
     /**
-     * Checks if this method is present in the virtual table.
+     * Checks if this method is present in the virtual table for subtypes of the specified
+     * {@linkplain ResolvedJavaType type}.
      *
-     * @return true is this method is present in the virtual table
+     * @return true is this method is present in the virtual table for subtypes of this type.
      */
-    boolean isInVirtualMethodTable();
+    boolean isInVirtualMethodTable(ResolvedJavaType resolved);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Sat May 17 11:41:35 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Sat May 17 14:57:58 2014 +0200
@@ -1066,6 +1066,7 @@
     @HotSpotVMConstant(name = "Method::_dont_inline") @Stable public int methodFlagsDontInline;
     @HotSpotVMConstant(name = "Method::_hidden") @Stable public int methodFlagsHidden;
     @HotSpotVMConstant(name = "Method::nonvirtual_vtable_index") @Stable public int nonvirtualVtableIndex;
+    @HotSpotVMConstant(name = "Method::invalid_vtable_index") @Stable public int invalidVtableIndex;
 
     @HotSpotVMConstant(name = "JVM_ACC_MONITOR_MATCH") @Stable public int jvmAccMonitorMatch;
     @HotSpotVMConstant(name = "JVM_ACC_HAS_MONITOR_BYTECODES") @Stable public int jvmAccHasMonitorBytecodes;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Sat May 17 11:41:35 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Sat May 17 14:57:58 2014 +0200
@@ -353,4 +353,6 @@
     void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate);
 
     void resolveInvokeDynamic(long metaspaceConstantPool, int index);
+
+    int getVtableIndexForInterface(long metaspaceKlass, long metaspaceMethod);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Sat May 17 11:41:35 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Sat May 17 14:57:58 2014 +0200
@@ -182,4 +182,6 @@
     public native long getTimeStamp();
 
     public native void resolveInvokeDynamic(long metaspaceConstantPool, int index);
+
+    public native int getVtableIndexForInterface(long metaspaceKlass, long metaspaceMethod);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Sat May 17 11:41:35 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Sat May 17 14:57:58 2014 +0200
@@ -230,29 +230,26 @@
             JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
 
             LoweredCallTargetNode loweredCallTarget = null;
-            if (callTarget.invokeKind() == InvokeKind.Virtual && InlineVTableStubs.getValue() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
-
+            boolean isVirtualOrInterface = callTarget.invokeKind() == InvokeKind.Virtual || callTarget.invokeKind() == InvokeKind.Interface;
+            if (InlineVTableStubs.getValue() && isVirtualOrInterface && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
                 HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
-                if (!hsMethod.getDeclaringClass().isInterface()) {
-                    if (hsMethod.isInVirtualMethodTable()) {
-                        int vtableEntryOffset = hsMethod.vtableEntryOffset();
-                        assert vtableEntryOffset > 0;
-                        Kind wordKind = runtime.getTarget().wordKind;
-                        ValueNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck);
+                ResolvedJavaType receiverType = invoke.getReceiverType();
+                if (hsMethod.isInVirtualMethodTable(receiverType)) {
+                    Kind wordKind = runtime.getTarget().wordKind;
+                    ValueNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck);
 
-                        ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod);
-                        // We use LocationNode.ANY_LOCATION for the reads that access the
-                        // compiled code entry as HotSpot does not guarantee they are final
-                        // values.
-                        ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, runtime.getConfig().methodCompiledEntryOffset, graph),
-                                        StampFactory.forKind(wordKind), BarrierType.NONE, false));
+                    ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod, receiverType);
+                    // We use LocationNode.ANY_LOCATION for the reads that access the
+                    // compiled code entry as HotSpot does not guarantee they are final
+                    // values.
+                    ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, runtime.getConfig().methodCompiledEntryOffset, graph),
+                                    StampFactory.forKind(wordKind), BarrierType.NONE, false));
 
-                        loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
-                                        CallingConvention.Type.JavaCall));
+                    loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
+                                    CallingConvention.Type.JavaCall));
 
-                        graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
-                        graph.addAfterFixed(metaspaceMethod, compiledEntry);
-                    }
+                    graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
+                    graph.addAfterFixed(metaspaceMethod, compiledEntry);
                 }
             }
 
@@ -554,8 +551,8 @@
 
     private void lowerLoadMethodNode(LoadMethodNode loadMethodNode) {
         StructuredGraph graph = loadMethodNode.graph();
-        ResolvedJavaMethod method = loadMethodNode.getMethod();
-        ReadNode metaspaceMethod = createReadVirtualMethod(graph, runtime.getTarget().wordKind, loadMethodNode.getHub(), method);
+        HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) loadMethodNode.getMethod();
+        ReadNode metaspaceMethod = createReadVirtualMethod(graph, runtime.getTarget().wordKind, loadMethodNode.getHub(), method, loadMethodNode.getReceiverType());
         graph.replaceFixed(loadMethodNode, metaspaceMethod);
     }
 
@@ -816,12 +813,11 @@
         return false;
     }
 
-    private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, ResolvedJavaMethod method) {
-        HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
-        assert !hsMethod.getDeclaringClass().isInterface();
-        assert hsMethod.isInVirtualMethodTable();
+    private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, HotSpotResolvedJavaMethod method, ResolvedJavaType receiverType) {
+        return createReadVirtualMethod(graph, wordKind, hub, method.vtableEntryOffset(receiverType));
+    }
 
-        int vtableEntryOffset = hsMethod.vtableEntryOffset();
+    private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, int vtableEntryOffset) {
         assert vtableEntryOffset > 0;
         // We use LocationNode.ANY_LOCATION for the reads that access the vtable
         // entry as HotSpot does not guarantee that this is a final value.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Sat May 17 11:41:35 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Sat May 17 14:57:58 2014 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot.meta;
 
+import static com.oracle.graal.compiler.common.GraalInternalError.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
@@ -33,7 +34,6 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
-import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.debug.*;
@@ -589,24 +589,31 @@
 
     /**
      * Returns the offset of this method into the v-table. The method must have a v-table entry as
-     * indicated by {@link #isInVirtualMethodTable()}, otherwise an exception is thrown.
+     * indicated by {@link #isInVirtualMethodTable(ResolvedJavaType)}, otherwise an exception is
+     * thrown.
      *
      * @return the offset of this method into the v-table
      */
-    public int vtableEntryOffset() {
-        if (!isInVirtualMethodTable() || !holder.isInitialized()) {
-            throw new GraalInternalError("%s does not have a vtable entry", this);
-        }
+    public int vtableEntryOffset(ResolvedJavaType resolved) {
+        guarantee(isInVirtualMethodTable(resolved) && holder.isInitialized(), "%s does not have a vtable entry", this);
         HotSpotVMConfig config = runtime().getConfig();
-        final int vtableIndex = getVtableIndex();
+        final int vtableIndex = getVtableIndex(resolved);
         return config.instanceKlassVtableStartOffset + vtableIndex * config.vtableEntrySize + config.vtableEntryMethodOffset;
     }
 
     @Override
-    public boolean isInVirtualMethodTable() {
-        // TODO (gd) this should probably take a ResolvedJavaType as argument so that we can take
-        // advantage of miranda & default methods.
-        return !holder.isInterface() && getVtableIndex() >= 0;
+    public boolean isInVirtualMethodTable(ResolvedJavaType resolved) {
+        return getVtableIndex(resolved) >= 0;
+    }
+
+    private int getVtableIndex(ResolvedJavaType resolved) {
+        if (holder.isInterface()) {
+            if (resolved.isArray() || resolved.isInterface()) {
+                return runtime().getConfig().invalidVtableIndex;
+            }
+            return getVtableIndexForInterface(resolved);
+        }
+        return getVtableIndex();
     }
 
     /**
@@ -615,13 +622,18 @@
      * @return virtual table index
      */
     private int getVtableIndex() {
-        assert !holder.isInterface() : this;
+        assert !holder.isInterface();
         HotSpotVMConfig config = runtime().getConfig();
         int result = unsafe.getInt(metaspaceMethod + config.methodVtableIndexOffset);
         assert result >= config.nonvirtualVtableIndex : "must be linked";
         return result;
     }
 
+    private int getVtableIndexForInterface(ResolvedJavaType resolved) {
+        HotSpotResolvedObjectType hotspotType = (HotSpotResolvedObjectType) resolved;
+        return runtime().getCompilerToVM().getVtableIndexForInterface(hotspotType.metaspaceKlass(), getMetaspaceMethod());
+    }
+
     /**
      * The {@link SpeculationLog} for methods compiled by Graal hang off this per-declaring-type
      * {@link ClassValue}. The raw Method* value is safe to use as a key in the map as a) it is
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Sat May 17 11:41:35 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Sat May 17 14:57:58 2014 +0200
@@ -108,7 +108,7 @@
     /**
      * Gets the metaspace Klass for this type.
      */
-    private long metaspaceKlass() {
+    public long metaspaceKlass() {
         return HotSpotGraalRuntime.unsafeReadWord(javaClass, runtime().getConfig().klassOffset);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java	Sat May 17 11:41:35 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java	Sat May 17 14:57:58 2014 +0200
@@ -25,7 +25,9 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 
 public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode.DeoptDuring, GuardedNode {
 
@@ -85,4 +87,16 @@
         newStateDuring.setDuringCall(true);
         setStateDuring(newStateDuring);
     }
+
+    default ValueNode getReceiver() {
+        return callTarget().arguments().get(0);
+    }
+
+    default ResolvedJavaType getReceiverType() {
+        ResolvedJavaType receiverType = StampTool.typeOrNull(getReceiver());
+        if (receiverType == null) {
+            receiverType = ((MethodCallTargetNode) callTarget()).targetMethod().getDeclaringClass();
+        }
+        return receiverType;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Sat May 17 11:41:35 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Sat May 17 14:57:58 2014 +0200
@@ -34,18 +34,20 @@
 
     @Input private ValueNode hub;
     private final ResolvedJavaMethod method;
+    private final ResolvedJavaType receiverType;
 
     public ValueNode getHub() {
         return hub;
     }
 
-    public LoadMethodNode(ResolvedJavaMethod method, ValueNode hub, Kind kind) {
+    public LoadMethodNode(ResolvedJavaMethod method, ResolvedJavaType receiverType, ValueNode hub, Kind kind) {
         super(kind == Kind.Object ? StampFactory.objectNonNull() : StampFactory.forKind(kind));
+        this.receiverType = receiverType;
         this.hub = hub;
         this.method = method;
         assert !method.isAbstract() : "Cannot load abstract method from a hub";
         assert !method.isStatic() : "Cannot load a static method from a hub";
-        assert method.isInVirtualMethodTable();
+        assert method.isInVirtualMethodTable(receiverType);
     }
 
     @Override
@@ -56,4 +58,8 @@
     public ResolvedJavaMethod getMethod() {
         return method;
     }
+
+    public ResolvedJavaType getReceiverType() {
+        return receiverType;
+    }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Sat May 17 11:41:35 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Sat May 17 14:57:58 2014 +0200
@@ -22,36 +22,28 @@
  */
 package com.oracle.graal.phases.common.inlining.info;
 
-import com.oracle.graal.api.code.Assumptions;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.calc.Condition;
-import com.oracle.graal.compiler.common.type.StampFactory;
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.DebugMetric;
-import com.oracle.graal.graph.Node;
+import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
+import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.CompareNode;
-import com.oracle.graal.nodes.extended.LoadHubNode;
-import com.oracle.graal.nodes.extended.LoadMethodNode;
-import com.oracle.graal.nodes.java.ExceptionObjectNode;
-import com.oracle.graal.nodes.java.MethodCallTargetNode;
-import com.oracle.graal.nodes.java.TypeSwitchNode;
-import com.oracle.graal.nodes.util.GraphUtil;
-import com.oracle.graal.phases.common.CanonicalizerPhase;
-import com.oracle.graal.phases.common.TailDuplicationPhase;
-import com.oracle.graal.phases.common.inlining.InliningUtil;
-import com.oracle.graal.phases.tiers.PhaseContext;
-import com.oracle.graal.phases.util.Providers;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.oracle.graal.compiler.common.GraalOptions.ImmutableCode;
-import static com.oracle.graal.compiler.common.GraalOptions.OptTailDuplication;
-
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.common.inlining.InliningUtil.Inlineable;
-import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.phases.util.*;
 
 /**
  * Polymorphic inlining of m methods with n type checks (n &ge; m) in case that the profiling
@@ -361,9 +353,10 @@
                 }
             }
 
+            ResolvedJavaType receiverType = invoke.getReceiverType();
             FixedNode lastSucc = successors[concretes.size()];
             for (int i = concretes.size() - 1; i >= 0; --i) {
-                LoadMethodNode method = graph.add(new LoadMethodNode(concretes.get(i), hub, constantMethods[i].getKind()));
+                LoadMethodNode method = graph.add(new LoadMethodNode(concretes.get(i), receiverType, hub, constantMethods[i].getKind()));
                 CompareNode methodCheck = CompareNode.createCompareNode(graph, Condition.EQ, method, constantMethods[i]);
                 IfNode ifNode = graph.add(new IfNode(methodCheck, successors[i], lastSucc, probability[i]));
                 method.setNext(ifNode);
@@ -396,8 +389,9 @@
     }
 
     private boolean chooseMethodDispatch() {
+        ResolvedJavaType receiverType = invoke.getReceiverType();
         for (ResolvedJavaMethod concrete : concretes) {
-            if (!concrete.isInVirtualMethodTable()) {
+            if (!concrete.isInVirtualMethodTable(receiverType)) {
                 return false;
             }
         }
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Sat May 17 11:41:35 2014 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Sat May 17 14:57:58 2014 +0200
@@ -468,6 +468,13 @@
   return (jlong) (address) result.field_holder();
 C2V_END
 
+C2V_VMENTRY(jint, getVtableIndexForInterface, (JNIEnv *, jobject, jlong metaspace_klass, jlong metaspace_method))
+  Klass* klass = (Klass*) metaspace_klass;
+  Method* method = (Method*) metaspace_method;
+
+  return LinkResolver::vtable_index_of_interface_method(klass, method);
+C2V_END
+
 C2V_VMENTRY(jlong, resolveMethod, (JNIEnv *, jobject, jlong metaspace_klass_receiver, jlong metaspace_method, jlong metaspace_klass_caller))
   Klass* recv_klass = (Klass*) metaspace_klass_receiver;
   Klass* caller_klass = (Klass*) metaspace_klass_caller;