# HG changeset patch # User Gilles Duboscq # Date 1400331478 -7200 # Node ID ef6b8d1898e6d5c9704d94d725d752a463a2a817 # Parent a9f969e65b61a3b3e4aae211333ef2a62ac3921b Add resolved receiver type to ResolvedJavaMethod.isInVirtualMethodTable in order to be able to do vtable-calls for miranda and default methods diff -r a9f969e65b61 -r ef6b8d1898e6 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java --- 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); } diff -r a9f969e65b61 -r ef6b8d1898e6 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- 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; diff -r a9f969e65b61 -r ef6b8d1898e6 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java --- 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); } diff -r a9f969e65b61 -r ef6b8d1898e6 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java --- 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); } diff -r a9f969e65b61 -r ef6b8d1898e6 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java --- 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. diff -r a9f969e65b61 -r ef6b8d1898e6 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java --- 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 diff -r a9f969e65b61 -r ef6b8d1898e6 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java --- 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); } diff -r a9f969e65b61 -r ef6b8d1898e6 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java --- 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; + } } diff -r a9f969e65b61 -r ef6b8d1898e6 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java --- 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; + } } diff -r a9f969e65b61 -r ef6b8d1898e6 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java --- 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 ≥ 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; } } diff -r a9f969e65b61 -r ef6b8d1898e6 src/share/vm/graal/graalCompilerToVM.cpp --- 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;