changeset 5841:f84d11672a86

vtable dispatch inlining for megamorphic virtual calls now works and is enabled by default
author Doug Simon <doug.simon@oracle.com>
date Mon, 16 Jul 2012 15:20:50 +0200
parents f565e8d4d200
children a9ce56ad1860
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java
diffstat 4 files changed, 43 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Mon Jul 16 15:19:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Mon Jul 16 15:20:50 2012 +0200
@@ -181,7 +181,7 @@
     public static boolean GenSafepoints                      = true;
     public static boolean GenLoopSafepoints                  = true;
            static boolean UseTypeCheckHints                  = true;
-    public static boolean InlineVTableStubs                  = ____;
+    public static boolean InlineVTableStubs                  = true;
     public static boolean AlwaysInlineVTableStubs            = ____;
 
     public static boolean GenAssertionCode                   = ____;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Mon Jul 16 15:19:25 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Mon Jul 16 15:20:50 2012 +0200
@@ -246,13 +246,10 @@
                     GraalOptions.InlineVTableStubs &&
                     (GraalOptions.AlwaysInlineVTableStubs || invoke.isMegamorphic())) {
 
-                    // TODO (dnsimon) I'm not sure of other invariants of HotSpot's calling conventions that may
-                    // be required for register indirect calls.
-                    assert false : "HotSpot expects the methodOop of the callee to be in rbx - this is yet to be implemented for inline vtable dispatch";
-
-                    // TODO: successive inlined invokevirtuals to the same method cause register allocation to fail - fix this!
                     HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
                     if (!hsMethod.holder().isInterface()) {
+                        // We use LocationNode.ANY_LOCATION for the reads that access the vtable entry and the compiled code entry
+                        // as HotSpot does not guarantee they are final values.
                         int vtableEntryOffset = hsMethod.vtableEntryOffset();
                         assert vtableEntryOffset != 0;
                         SafeReadNode hub = safeReadHub(graph, receiver, StructuredGraph.INVALID_GRAPH_ID);
@@ -260,7 +257,11 @@
                         Stamp nonNullWordStamp = StampFactory.forWord(wordKind, true);
                         ReadNode methodOop = graph.add(new ReadNode(hub, LocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph), nonNullWordStamp));
                         ReadNode compiledEntry = graph.add(new ReadNode(methodOop, LocationNode.create(LocationNode.ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph), nonNullWordStamp));
-                        callTarget.setAddress(compiledEntry);
+                        callTarget.setComputedAddress(compiledEntry);
+
+                        // Append the methodOop to the arguments so that it can be explicitly passed in RBX as
+                        // is required for all compiled calls in HotSpot.
+                        callTarget.arguments().add(methodOop);
 
                         graph.addBeforeFixed(invoke.node(), hub);
                         graph.addAfterFixed(hub, methodOop);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java	Mon Jul 16 15:19:25 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java	Mon Jul 16 15:20:50 2012 +0200
@@ -112,12 +112,33 @@
             Kind[] signature = MetaUtil.signatureToKinds(callTarget.targetMethod().signature(), callTarget.isStatic() ? null : callTarget.targetMethod().holder().kind());
             CallingConvention cc = frameMap.registerConfig.getCallingConvention(JavaCall, signature, target(), false);
             frameMap.callsMethod(cc, JavaCall);
+
+            Value address = Constant.forLong(0L);
+
+            ValueNode methodOopNode = null;
+
+            if (callTarget.computedAddress() != null) {
+                // If a virtual dispatch address was computed, then an extra argument
+                // was append for passing the methodOop in RBX
+                methodOopNode = callTarget.arguments().remove(callTarget.arguments().size() - 1);
+
+                if (invokeKind == Virtual) {
+                    address = operand(callTarget.computedAddress());
+                } else {
+                    // An invokevirtual may have been canonicalized into an invokespecial;
+                    // the methodOop argument is ignored in this case
+                }
+            }
+
             List<Value> argList = visitInvokeArguments(cc, callTarget.arguments());
 
-            Value address = callTarget.address() == null ? Constant.forLong(0L) : operand(callTarget.address());
+            if (methodOopNode != null) {
+                Value methodOopArg = operand(methodOopNode);
+                emitMove(methodOopArg, AMD64.rbx.asValue());
+                argList.add(methodOopArg);
+            }
 
             final Mark[] callsiteForStaticCallStub = {null};
-
             if (invokeKind == Static || invokeKind == Special) {
                 lir.stubs.add(new AMD64Code() {
                     public String description() {
@@ -145,12 +166,12 @@
                         // that loads the klassOop from the inline cache so that the C++ code can find it
                         // and replace the inline null value with Universe::non_oop_word()
                         assert invokeKind == Virtual || invokeKind == Interface;
-                        if (callTarget.address() == null) {
+                        if (invokeKind == Virtual && callTarget.computedAddress() != null) {
+                            tasm.recordMark(MARK_INLINE_INVOKEVIRTUAL);
+                        } else {
                             tasm.recordMark(invokeKind == Virtual ? MARK_INVOKEVIRTUAL : MARK_INVOKEINTERFACE);
                             AMD64MacroAssembler masm = (AMD64MacroAssembler) tasm.asm;
                             AMD64Move.move(tasm, masm, AMD64.rax.asValue(Kind.Object), Constant.NULL_OBJECT);
-                        } else {
-                            tasm.recordMark(MARK_INLINE_INVOKEVIRTUAL);
                         }
                     }
                 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Mon Jul 16 15:19:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Mon Jul 16 15:20:50 2012 +0200
@@ -31,15 +31,18 @@
 
     @Input protected final NodeInputList<ValueNode> arguments;
 
-    @Input protected ValueNode address;
+    /**
+     * The address computation for an indirect call (e.g., invokevirtual or invokeinterface).
+     */
+    @Input protected ValueNode computedAddress;
 
-    public ValueNode address() {
-        return address;
+    public ValueNode computedAddress() {
+        return computedAddress;
     }
 
-    public void setAddress(ValueNode address) {
-        updateUsages(this.address, address);
-        this.address = address;
+    public void setComputedAddress(ValueNode address) {
+        updateUsages(this.computedAddress, address);
+        this.computedAddress = address;
     }
 
     public CallTargetNode(ValueNode[] arguments) {