Skip to content

Commit 62c32ee

Browse files
committed
[GR-62596] Introduce IndirectCallTargets for Open Type World Hub Layout.
PullRequest: graal/20812
2 parents 9ec2ad2 + 6e25248 commit 62c32ee

File tree

20 files changed

+378
-277
lines changed

20 files changed

+378
-277
lines changed

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java

Lines changed: 0 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,6 @@ public record Signature(String name, AnalysisType[] parameterTypes) {
126126

127127
public final ResolvedJavaMethod wrapped;
128128

129-
private AnalysisMethod indirectCallTarget = null;
130-
public boolean invalidIndirectCallTarget = false;
131-
132129
private final int id;
133130
/** Marks a method loaded from a base layer. */
134131
private final boolean isInBaseLayer;
@@ -347,69 +344,6 @@ public AnalysisUniverse getUniverse() {
347344
return declaringClass.getUniverse();
348345
}
349346

350-
private static boolean matchingSignature(AnalysisMethod o1, AnalysisMethod o2) {
351-
if (o1.equals(o2)) {
352-
return true;
353-
}
354-
355-
if (!o1.getName().equals(o2.getName())) {
356-
return false;
357-
}
358-
359-
return o1.getSignature().equals(o2.getSignature());
360-
}
361-
362-
private AnalysisMethod setIndirectCallTarget(AnalysisMethod method, boolean foundMatch) {
363-
indirectCallTarget = method;
364-
invalidIndirectCallTarget = !foundMatch;
365-
return indirectCallTarget;
366-
}
367-
368-
/**
369-
* For methods where its {@link #getDeclaringClass()} does not explicitly declare the method,
370-
* find an alternative explicit declaration for the method which can be used as an indirect call
371-
* target. This logic is currently used for deciding the target of virtual/interface calls when
372-
* using the open type world.
373-
*/
374-
public AnalysisMethod getIndirectCallTarget() {
375-
if (indirectCallTarget != null) {
376-
return indirectCallTarget;
377-
}
378-
if (isStatic() || isConstructor()) {
379-
/*
380-
* Static methods and constructors must always be explicitly declared.
381-
*/
382-
return setIndirectCallTarget(this, true);
383-
}
384-
385-
var dispatchTableMethods = declaringClass.getOrCalculateOpenTypeWorldDispatchTableMethods();
386-
387-
if (dispatchTableMethods.contains(this)) {
388-
return setIndirectCallTarget(this, true);
389-
}
390-
391-
for (AnalysisType interfaceType : declaringClass.getAllInterfaces()) {
392-
if (interfaceType.equals(declaringClass)) {
393-
// already checked
394-
continue;
395-
}
396-
dispatchTableMethods = interfaceType.getOrCalculateOpenTypeWorldDispatchTableMethods();
397-
for (AnalysisMethod candidate : dispatchTableMethods) {
398-
if (matchingSignature(candidate, this)) {
399-
return setIndirectCallTarget(candidate, true);
400-
}
401-
}
402-
}
403-
404-
/*
405-
* For some methods (e.g., methods labeled as @PolymorphicSignature or @Delete), we
406-
* currently do not find matches. However, these methods will not be indirect calls within
407-
* our generated code, so it is not necessary to determine an accurate virtual/interface
408-
* call target.
409-
*/
410-
return setIndirectCallTarget(this, false);
411-
}
412-
413347
/**
414348
* @see PointsToAnalysis#validateFixedPointState
415349
*/

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,6 @@ public abstract class AnalysisType extends AnalysisElement implements WrappedJav
175175
private AnalysisMethod[] declaredMethods;
176176
private Set<AnalysisMethod> dispatchTableMethods;
177177

178-
private AnalysisType[] allInterfaces;
179-
180178
/* isArray is an expensive operation so we eagerly compute it */
181179
private final boolean isArray;
182180
private final boolean isJavaLangObject;
@@ -377,36 +375,6 @@ public int getArrayDimension() {
377375
return dimension;
378376
}
379377

380-
/**
381-
* @return All interfaces this type inherits (including itself if it is an interface).
382-
*/
383-
public AnalysisType[] getAllInterfaces() {
384-
if (allInterfaces != null) {
385-
return allInterfaces;
386-
}
387-
388-
Set<AnalysisType> allInterfaceSet = new HashSet<>();
389-
390-
if (isInterface()) {
391-
allInterfaceSet.add(this);
392-
}
393-
394-
if (this.superClass != null) {
395-
allInterfaceSet.addAll(Arrays.asList(this.superClass.getAllInterfaces()));
396-
}
397-
398-
for (AnalysisType i : interfaces) {
399-
allInterfaceSet.addAll(Arrays.asList(i.getAllInterfaces()));
400-
}
401-
402-
var result = allInterfaceSet.toArray(AnalysisType[]::new);
403-
404-
// ensure result is fully visible across threads
405-
VarHandle.storeStoreFence();
406-
allInterfaces = result;
407-
return allInterfaces;
408-
}
409-
410378
public void cleanupAfterAnalysis() {
411379
instantiatedTypes = null;
412380
instantiatedTypesNonNull = null;
@@ -1356,18 +1324,6 @@ public AnalysisMethod[] getDeclaredConstructors(boolean forceLink) {
13561324
return universe.lookup(wrapped.getDeclaredConstructors(forceLink));
13571325
}
13581326

1359-
public AnalysisMethod findConstructor(Signature signature) {
1360-
if (wrapped instanceof BaseLayerType) {
1361-
return null;
1362-
}
1363-
for (AnalysisMethod ctor : getDeclaredConstructors(false)) {
1364-
if (ctor.getSignature().equals(signature)) {
1365-
return ctor;
1366-
}
1367-
}
1368-
return null;
1369-
}
1370-
13711327
public boolean isOpenTypeWorldDispatchTableMethodsCalculated() {
13721328
return dispatchTableMethods != null;
13731329
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/OpenTypeWorldDispatchTableSnippets.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ public void lower(LoadOpenTypeWorldDispatchTableStartingOffset node, LoweringToo
122122
SharedMethod target = node.getTarget();
123123
int vtableStartingOffset = KnownOffsets.singleton().getVTableBaseOffset();
124124
if (target != null) {
125+
/*
126+
* Update target to point to indirect call target. The indirect call target is
127+
* different than the original target when the original target is a method we have
128+
* not placed in any virtual/interface table. See SharedMethod#getIndirectCallTarget
129+
* and HostedMethod#indirectCallVTableIndex for more information.
130+
*/
131+
target = target.getIndirectCallTarget();
125132
/*
126133
* If the target is known, then we know whether to use the class dispatch table or
127134
* an interface dispatch table.

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SharedMethod.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,24 @@ public interface SharedMethod extends ResolvedJavaMethod {
6565

6666
int getVTableIndex();
6767

68+
/**
69+
* In the open type world, our virtual/interface tables will only contain declared methods.
70+
* However, sometimes JVMCI will expose special methods HotSpot introduces into vtables, such as
71+
* miranda and overpass methods. When these special methods serve as call targets for indirect
72+
* calls, we must switch the call target to an alternative method (with the same resolution)
73+
* that will be present in the open type world virtual/interface tables.
74+
*
75+
* <p>
76+
* Note normally in the open type world {@code indirectCallTarget == this}. Only for special
77+
* HotSpot-specific methods such as miranda and overpass methods will the indirectCallTarget be
78+
* a different method. The logic for setting the indirectCallTarget can be found in
79+
* {@code OpenTypeWorldFeature#calculateIndirectCallTarget}.
80+
*
81+
* <p>
82+
* In the closed type world, this method will always return {@code this}.
83+
*/
84+
SharedMethod getIndirectCallTarget();
85+
6886
/**
6987
* Returns the deopt stub type for the stub methods in {@link Deoptimizer}. Only used when
7088
* compiling the deopt stubs during image generation.

substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/GraalGraphObjectReplacer.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -476,23 +476,33 @@ public void updateSubstrateDataAfterCompilation(HostedUniverse hUniverse, Provid
476476
? providers.getConstantReflection().readFieldValue(hField, null)
477477
: null;
478478
constantValue = SubstrateGraalUtils.hostedToRuntime(constantValue, providers.getConstantReflection());
479-
sField.setSubstrateData(hField.getLocation(), hField.isAccessed(), hField.isWritten() || !hField.isValueAvailable(), constantValue);
479+
sField.setSubstrateDataAfterCompilation(hField.getLocation(), hField.isAccessed(), hField.isWritten() || !hField.isValueAvailable(), constantValue);
480480
}
481+
482+
methods.forEach((aMethod, sMethod) -> {
483+
HostedMethod hMethod = hUniverse.lookup(aMethod);
484+
SubstrateMethod indirectCallTarget = sMethod;
485+
if (!hMethod.getIndirectCallTarget().equals(hMethod)) {
486+
indirectCallTarget = methods.get(hMethod.getIndirectCallTarget().getWrapped());
487+
}
488+
int vTableIndex = (hMethod.hasVTableIndex() ? hMethod.getVTableIndex() : HostedMethod.MISSING_VTABLE_IDX);
489+
sMethod.setSubstrateDataAfterCompilation(indirectCallTarget, vTableIndex);
490+
});
491+
481492
}
482493

483494
public void updateSubstrateDataAfterHeapLayout(HostedUniverse hUniverse) {
484495
for (Map.Entry<AnalysisMethod, SubstrateMethod> entry : methods.entrySet()) {
485496
AnalysisMethod aMethod = entry.getKey();
486497
SubstrateMethod sMethod = entry.getValue();
487498
HostedMethod hMethod = hUniverse.lookup(aMethod);
488-
int vTableIndex = (hMethod.hasVTableIndex() ? hMethod.getVTableIndex() : -1);
489499

490500
/*
491501
* We access the offset of methods in the image code section here. Therefore, this code
492502
* can only run after the heap and code cache layout was done.
493503
*/
494504
int imageCodeOffset = hMethod.isCodeAddressOffsetValid() ? hMethod.getCodeAddressOffset() : 0;
495-
sMethod.setSubstrateData(vTableIndex, imageCodeOffset, hMethod.getImageCodeDeoptOffset());
505+
sMethod.setSubstrateDataAfterHeapLayout(imageCodeOffset, hMethod.getImageCodeDeoptOffset());
496506
}
497507
}
498508

substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateField.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public void setLinks(SubstrateType type, SubstrateType declaringClass) {
8989
this.declaringClass = declaringClass;
9090
}
9191

92-
public void setSubstrateData(int location, boolean isAccessed, boolean isWritten, JavaConstant constantValue) {
92+
public void setSubstrateDataAfterCompilation(int location, boolean isAccessed, boolean isWritten, JavaConstant constantValue) {
9393
this.location = location;
9494
this.isAccessed = isAccessed;
9595
this.isWritten = isWritten;

substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateMethod.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.graalvm.nativeimage.c.function.CEntryPoint;
3838

3939
import com.oracle.graal.pointsto.meta.AnalysisMethod;
40+
import com.oracle.svm.core.BuildPhaseProvider.AfterCompilation;
4041
import com.oracle.svm.core.BuildPhaseProvider.AfterHeapLayout;
4142
import com.oracle.svm.core.BuildPhaseProvider.ReadyForCompilation;
4243
import com.oracle.svm.core.Uninterruptible;
@@ -50,6 +51,7 @@
5051
import com.oracle.svm.core.graal.phases.SubstrateSafepointInsertionPhase;
5152
import com.oracle.svm.core.heap.UnknownObjectField;
5253
import com.oracle.svm.core.heap.UnknownPrimitiveField;
54+
import com.oracle.svm.core.meta.SharedMethod;
5355
import com.oracle.svm.core.snippets.SubstrateForeignCallTarget;
5456
import com.oracle.svm.core.util.HostedStringDeduplication;
5557
import com.oracle.svm.core.util.VMError;
@@ -88,7 +90,8 @@ public class SubstrateMethod implements SharedRuntimeMethod {
8890
private final int hashCode;
8991
private SubstrateType declaringClass;
9092
@UnknownPrimitiveField(availability = ReadyForCompilation.class) private int encodedGraphStartOffset;
91-
@UnknownPrimitiveField(availability = AfterHeapLayout.class) private int vTableIndex;
93+
@UnknownPrimitiveField(availability = AfterCompilation.class) private int vTableIndex;
94+
@UnknownObjectField(availability = AfterCompilation.class) private SubstrateMethod indirectCallTarget;
9295

9396
/**
9497
* A metadata object describing the image code that contains the compiled code of this method.
@@ -195,8 +198,12 @@ public Object getRawImplementations() {
195198
return implementations;
196199
}
197200

198-
public void setSubstrateData(int vTableIndex, int imageCodeOffset, int imageCodeDeoptOffset) {
201+
public void setSubstrateDataAfterCompilation(SubstrateMethod indirectCallTarget, int vTableIndex) {
202+
this.indirectCallTarget = indirectCallTarget;
199203
this.vTableIndex = vTableIndex;
204+
}
205+
206+
public void setSubstrateDataAfterHeapLayout(int imageCodeOffset, int imageCodeDeoptOffset) {
200207
this.imageCodeOffset = imageCodeOffset;
201208
this.imageCodeDeoptOffset = imageCodeDeoptOffset;
202209
}
@@ -302,6 +309,11 @@ public int getVTableIndex() {
302309
return vTableIndex;
303310
}
304311

312+
@Override
313+
public SharedMethod getIndirectCallTarget() {
314+
return indirectCallTarget;
315+
}
316+
305317
@Override
306318
public Deoptimizer.StubType getDeoptStubType() {
307319
return Deoptimizer.StubType.NoDeoptStub;

substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -96,36 +96,37 @@ struct PersistedAnalysisMethod {
9696
annotationList @20 :List(Annotation);
9797
isVarArgs @21 :Bool;
9898
isBridge @22 :Bool;
99-
analysisGraphLocation @23 :Text;
100-
analysisGraphIsIntrinsic @24 :Bool;
101-
strengthenedGraphLocation @25 :Text;
102-
hostedMethodIndex @26 :HostedMethodIndex;
99+
isDeclared @23 :Bool;
100+
analysisGraphLocation @24 :Text;
101+
analysisGraphIsIntrinsic @25 :Bool;
102+
strengthenedGraphLocation @26 :Text;
103+
hostedMethodIndex @27 :HostedMethodIndex;
103104
wrappedMethod :union {
104-
none @27 :Void; # default
105+
none @28 :Void; # default
105106
factoryMethod :group {
106-
targetConstructorId @28 :MethodId;
107-
throwAllocatedObject @29 :Bool;
108-
instantiatedTypeId @30 :TypeId;
107+
targetConstructorId @29 :MethodId;
108+
throwAllocatedObject @30 :Bool;
109+
instantiatedTypeId @31 :TypeId;
109110
}
110111
outlinedSB :group {
111-
methodTypeReturn @31 :Text;
112-
methodTypeParameters @32 :List(Text);
112+
methodTypeReturn @32 :Text;
113+
methodTypeParameters @33 :List(Text);
113114
}
114115
cEntryPointCallStub :group {
115-
originalMethodId @33 :MethodId;
116-
notPublished @34 :Bool;
116+
originalMethodId @34 :MethodId;
117+
notPublished @35 :Bool;
117118
}
118119
wrappedMember :group {
119120
union {
120-
reflectionExpandSignature @35 :Void;
121-
javaCallVariantWrapper @36 :Void;
121+
reflectionExpandSignature @36 :Void;
122+
javaCallVariantWrapper @37 :Void;
122123
}
123-
name @37 :Text;
124-
declaringClassName @38 :Text;
125-
argumentTypeNames @39 :List(Text);
124+
name @38 :Text;
125+
declaringClassName @39 :Text;
126+
argumentTypeNames @40 :List(Text);
126127
}
127128
polymorphicSignature :group {
128-
callers @40 :List(MethodId);
129+
callers @41 :List(MethodId);
129130
}
130131
}
131132
}

0 commit comments

Comments
 (0)