changeset 5823:f238fe91dc7f

partial (non XIR) support for inlining virtual dispatch at call sites - still needs fixing
author Doug Simon <doug.simon@oracle.com>
date Thu, 12 Jul 2012 17:16:34 +0200
parents ec65d0d0c873
children b1dc8fbebb48
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotXirGenerator.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 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java src/share/vm/graal/graalCodeInstaller.cpp src/share/vm/graal/graalCodeInstaller.hpp
diffstat 15 files changed, 84 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Thu Jul 12 12:04:27 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Thu Jul 12 17:16:34 2012 +0200
@@ -273,6 +273,7 @@
     public static String HIRLowerCheckcast = "";
     public static String HIRLowerNewInstance = "";
     public static String HIRLowerNewArray = "";
+    public static String HIRLowerInlineVirtualInvokes = "";
 
     /**
      * Use XIR to lower {@link Invoke} nodes.
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Thu Jul 12 12:04:27 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Thu Jul 12 17:16:34 2012 +0200
@@ -50,6 +50,11 @@
     static final int INITIAL_ID = -1;
     static final int ALIVE_ID_START = 0;
 
+    /**
+     * Denotes a node input. This should be applied to exactly the fields of a node that are of type {@link Node}.
+     * Nodes that update their inputs outside of their constructor should call {@link Node#updateUsages(Node, Node)}
+     * just prior to doing the update of the input.
+     */
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.FIELD)
     public static @interface Input {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Thu Jul 12 12:04:27 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Thu Jul 12 17:16:34 2012 +0200
@@ -232,12 +232,34 @@
             SafeReadNode safeReadArrayLength = safeReadArrayLength(arrayLengthNode.array(), StructuredGraph.INVALID_GRAPH_ID);
             graph.replaceFixedWithFixed(arrayLengthNode, safeReadArrayLength);
         } else if (n instanceof Invoke) {
-            Invoke invoke = (Invoke) n;
-            MethodCallTargetNode callTarget = invoke.callTarget();
-            NodeInputList<ValueNode> parameters = callTarget.arguments();
-            ValueNode firstParam = parameters.size() <= 0 ? null : parameters.get(0);
-            if (!callTarget.isStatic() && firstParam.kind() == Kind.Object && !firstParam.objectStamp().nonNull()) {
-                invoke.node().dependencies().add(tool.createNullCheckGuard(firstParam, invoke.leafGraphId()));
+            if (!GraalOptions.XIRLowerInvokes) {
+                Invoke invoke = (Invoke) n;
+                MethodCallTargetNode callTarget = invoke.callTarget();
+                NodeInputList<ValueNode> parameters = callTarget.arguments();
+                ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
+                if (!callTarget.isStatic() && receiver.kind() == Kind.Object && !receiver.objectStamp().nonNull()) {
+                    invoke.node().dependencies().add(tool.createNullCheckGuard(receiver, invoke.leafGraphId()));
+                }
+
+                int vtableEntryOffset = 0;
+                if (matches(graph, GraalOptions.HIRLowerInlineVirtualInvokes) || (GraalOptions.InlineVTableStubs && (GraalOptions.AlwaysInlineVTableStubs || invoke.isMegamorphic()))) {
+                    // TODO: successive inlined invokevirtuals to the same method cause register allocation to fail - fix this!
+                    HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
+                    if (!hsMethod.holder().isInterface()) {
+                        vtableEntryOffset = hsMethod.vtableEntryOffset();
+                        assert vtableEntryOffset != 0;
+                        SafeReadNode hub = safeReadHub(graph, receiver, StructuredGraph.INVALID_GRAPH_ID);
+                        Kind wordKind = graalRuntime.getTarget().wordKind;
+                        Stamp nonNullWordStamp = StampFactory.forWord(wordKind, true);
+                        ReadNode methodOop = graph.add(new ReadNode(hub, LocationNode.create(LocationNode.FINAL_LOCATION, wordKind, vtableEntryOffset, graph), nonNullWordStamp));
+                        ReadNode compiledEntry = graph.add(new ReadNode(methodOop, LocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.methodCompiledEntryOffset, graph), nonNullWordStamp));
+                        callTarget.setAddress(compiledEntry);
+
+                        graph.addBeforeFixed(invoke.node(), hub);
+                        graph.addAfterFixed(hub, methodOop);
+                        graph.addAfterFixed(methodOop, compiledEntry);
+                    }
+                }
             }
         } else if (n instanceof LoadFieldNode) {
             LoadFieldNode field = (LoadFieldNode) n;
@@ -374,15 +396,15 @@
             memoryRead.dependencies().add(tool.createNullCheckGuard(objectClassNode.object(), StructuredGraph.INVALID_GRAPH_ID));
             graph.replaceFixed(objectClassNode, memoryRead);
         } else if (n instanceof CheckCastNode) {
-            if (shouldLower(graph, GraalOptions.HIRLowerCheckcast)) {
+            if (matches(graph, GraalOptions.HIRLowerCheckcast)) {
                 checkcastSnippets.lower((CheckCastNode) n, tool);
             }
         } else if (n instanceof NewInstanceNode) {
-            if (shouldLower(graph, GraalOptions.HIRLowerNewInstance)) {
+            if (matches(graph, GraalOptions.HIRLowerNewInstance)) {
                 newObjectSnippets.lower((NewInstanceNode) n, tool);
             }
         } else if (n instanceof NewArrayNode) {
-            if (shouldLower(graph, GraalOptions.HIRLowerNewArray)) {
+            if (matches(graph, GraalOptions.HIRLowerNewArray)) {
                 newObjectSnippets.lower((NewArrayNode) n, tool);
             }
         } else if (n instanceof TLABAllocateNode) {
@@ -396,13 +418,13 @@
         }
     }
 
-    private static boolean shouldLower(StructuredGraph graph, String option) {
-        if (option != null) {
-            if (option.length() == 0) {
+    private static boolean matches(StructuredGraph graph, String filter) {
+        if (filter != null) {
+            if (filter.length() == 0) {
                 return true;
             }
             ResolvedJavaMethod method = graph.method();
-            return method != null && MetaUtil.format("%H.%n", method).contains(option);
+            return method != null && MetaUtil.format("%H.%n", method).contains(filter);
         }
         return false;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotXirGenerator.java	Thu Jul 12 12:04:27 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotXirGenerator.java	Thu Jul 12 17:16:34 2012 +0200
@@ -62,6 +62,7 @@
     public static final Integer MARK_INVOKESTATIC              = 0x2002;
     public static final Integer MARK_INVOKESPECIAL             = 0x2003;
     public static final Integer MARK_INVOKEVIRTUAL             = 0x2004;
+    public static final Integer MARK_INLINE_INVOKEVIRTUAL      = 0x2005;
 
     public static final Integer MARK_IMPLICIT_NULL             = 0x3000;
     public static final Integer MARK_POLL_NEAR                 = 0x3001;
@@ -167,7 +168,7 @@
             // load entry point from methodOop
             asm.mark(MARK_IMPLICIT_NULL);
             asm.pload(target.wordKind, temp, method, asm.i(config.methodCompiledEntryOffset), true);
-            asm.mark(MARK_INVOKEVIRTUAL);
+            asm.mark(MARK_INLINE_INVOKEVIRTUAL);
 
             return asm.finishTemplate(temp, "invokevirtual");
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java	Thu Jul 12 12:04:27 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java	Thu Jul 12 17:16:34 2012 +0200
@@ -145,9 +145,13 @@
                         // 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;
-                        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);
+                        if (callTarget.address() == null) {
+                            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);
+                        }
                     }
                 }
                 public void atCall(TargetMethodAssembler tasm) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Thu Jul 12 12:04:27 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Thu Jul 12 17:16:34 2012 +0200
@@ -38,6 +38,7 @@
     }
 
     public void setAddress(ValueNode address) {
+        updateUsages(this.address, address);
         this.address = address;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Thu Jul 12 12:04:27 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Thu Jul 12 17:16:34 2012 +0200
@@ -45,7 +45,7 @@
      */
     public IsNullNode(ValueNode object) {
         super(StampFactory.condition());
-        assert object.kind() == Kind.Object : object.kind();
+        assert object.kind() == Kind.Object : object;
         this.object = object;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java	Thu Jul 12 12:04:27 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java	Thu Jul 12 17:16:34 2012 +0200
@@ -25,6 +25,11 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
+/**
+ * Accesses a value at an memory address specified by an {@linkplain #object object}
+ * and a {@linkplain #location() location}. The access does not include a null check
+ * on the object.
+ */
 public abstract class AccessNode extends FixedWithNextNode implements Access {
 
     @Input private ValueNode object;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Thu Jul 12 12:04:27 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Thu Jul 12 17:16:34 2012 +0200
@@ -40,12 +40,20 @@
     private Kind valueKind;
     private Object locationIdentity;
 
+    /**
+     * Denotes any location. A write to such a location kills all values in a memory map
+     * during an analysis of memory accesses in a graph.
+     */
     public static final Object ANY_LOCATION = new Object() {
         @Override
         public String toString() {
             return "ANY_LOCATION";
         }
     };
+
+    /**
+     * Denotes the location of a value that is guaranteed to be final.
+     */
     public static final Object FINAL_LOCATION = new Object() {
         @Override
         public String toString() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Thu Jul 12 12:04:27 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Thu Jul 12 17:16:34 2012 +0200
@@ -28,7 +28,9 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-
+/**
+ * Reads an {@linkplain AccessNode accessed} value.
+ */
 public final class ReadNode extends AccessNode implements Node.IterableNodeType, LIRLowerable, Canonicalizable {
 
     public ReadNode(ValueNode object, LocationNode location, Stamp stamp) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java	Thu Jul 12 12:04:27 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java	Thu Jul 12 17:16:34 2012 +0200
@@ -26,6 +26,10 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
+/**
+ * An analog to {@link ReadNode} with the additional semantics of null-checking
+ * the receiver object before reading from it.
+ */
 public class SafeReadNode extends SafeAccessNode implements Lowerable {
 
     public SafeReadNode(ValueNode object, LocationNode location, Stamp stamp, long leafGraphId) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java	Thu Jul 12 12:04:27 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java	Thu Jul 12 17:16:34 2012 +0200
@@ -26,6 +26,10 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
+/**
+ * An analog to {@link WriteNode} with the additional semantics of null-checking
+ * the receiver object before writing to it.
+ */
 public class SafeWriteNode extends SafeAccessNode implements StateSplit, Lowerable {
 
     @Input private ValueNode value;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Thu Jul 12 12:04:27 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Thu Jul 12 17:16:34 2012 +0200
@@ -27,6 +27,9 @@
 import com.oracle.graal.nodes.type.*;
 
 
+/**
+ * Writes a given {@linkplain #value() value} a {@linkplain AccessNode memory location}.
+ */
 public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable {
     @Input private ValueNode value;
     @Input(notDataflow = true) private FrameState stateAfter;
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Thu Jul 12 12:04:27 2012 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Thu Jul 12 17:16:34 2012 +0200
@@ -695,10 +695,10 @@
 
     TRACE_graal_3("method call");
     switch (_next_call_type) {
+      case MARK_INLINE_INVOKEVIRTUAL: {
+        break;
+      }
       case MARK_INVOKEVIRTUAL:
-        if (is_call_reg) {
-          break;
-        }
       case MARK_INVOKEINTERFACE: {
         assert(method == NULL || !method->is_static(), "cannot call static method with invokeinterface");
 
@@ -843,6 +843,7 @@
         // Add relocation record for the klassOop embedded in the inline cache
         _instructions->relocate(instruction, oop_Relocation::spec_for_immediate(), Assembler::imm_operand);
       }
+      case MARK_INLINE_INVOKEVIRTUAL:
       case MARK_INVOKE_INVALID:
       case MARK_INVOKESPECIAL:
       case MARK_INVOKESTATIC:
--- a/src/share/vm/graal/graalCodeInstaller.hpp	Thu Jul 12 12:04:27 2012 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.hpp	Thu Jul 12 17:16:34 2012 +0200
@@ -43,6 +43,7 @@
     MARK_INVOKESTATIC               = 0x2002,
     MARK_INVOKESPECIAL              = 0x2003,
     MARK_INVOKEVIRTUAL              = 0x2004,
+    MARK_INLINE_INVOKEVIRTUAL       = 0x2005,
     MARK_IMPLICIT_NULL              = 0x3000,
     MARK_POLL_NEAR                  = 0x3001,
     MARK_POLL_RETURN_NEAR           = 0x3002,