# HG changeset patch # User Doug Simon # Date 1342444850 -7200 # Node ID f84d11672a869a1c5b7af23ed7ca9077f24c3dd8 # Parent f565e8d4d200da231bbd57c7abe6438dd5c2dcff vtable dispatch inlining for megamorphic virtual calls now works and is enabled by default diff -r f565e8d4d200 -r f84d11672a86 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java --- 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 = ____; diff -r f565e8d4d200 -r f84d11672a86 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- 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); diff -r f565e8d4d200 -r f84d11672a86 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java --- 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 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); } } } diff -r f565e8d4d200 -r f84d11672a86 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java --- 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 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) {