Skip to content

Commit 3b8f7ab

Browse files
committed
share RuntimeStub info across libgraal isolates
1 parent 2a0af49 commit 3b8f7ab

File tree

13 files changed

+331
-68
lines changed

13 files changed

+331
-68
lines changed

compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import jdk.vm.ci.code.CallingConvention;
3939
import jdk.vm.ci.code.CallingConvention.Type;
4040
import jdk.vm.ci.code.CodeCacheProvider;
41-
import jdk.vm.ci.code.InstalledCode;
4241
import jdk.vm.ci.code.Register;
4342
import jdk.vm.ci.code.RegisterConfig;
4443
import jdk.vm.ci.code.ValueKindFactory;
@@ -92,8 +91,15 @@ public class HotSpotForeignCallLinkageImpl extends HotSpotForeignCallTarget impl
9291
* @param outgoingCcType outgoing (caller) calling convention type
9392
* @param incomingCcType incoming (callee) calling convention type (can be null)
9493
*/
95-
public static HotSpotForeignCallLinkage create(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, WordTypes wordTypes, HotSpotForeignCallsProvider foreignCalls,
96-
HotSpotForeignCallDescriptor descriptor, long address, RegisterEffect effect, Type outgoingCcType, Type incomingCcType) {
94+
public static HotSpotForeignCallLinkage create(MetaAccessProvider metaAccess,
95+
CodeCacheProvider codeCache,
96+
WordTypes wordTypes,
97+
HotSpotForeignCallsProvider foreignCalls,
98+
HotSpotForeignCallDescriptor descriptor,
99+
long address,
100+
RegisterEffect effect,
101+
Type outgoingCcType,
102+
Type incomingCcType) {
97103
CallingConvention outgoingCc = createCallingConvention(metaAccess, codeCache, wordTypes, foreignCalls, descriptor, outgoingCcType);
98104
CallingConvention incomingCc = incomingCcType == null ? null : createCallingConvention(metaAccess, codeCache, wordTypes, foreignCalls, descriptor, incomingCcType);
99105
HotSpotForeignCallLinkageImpl linkage = new HotSpotForeignCallLinkageImpl(descriptor, address, effect, outgoingCc, incomingCc);
@@ -106,8 +112,12 @@ public static HotSpotForeignCallLinkage create(MetaAccessProvider metaAccess, Co
106112
/**
107113
* Gets a calling convention for a given descriptor and call type.
108114
*/
109-
public static CallingConvention createCallingConvention(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, WordTypes wordTypes, ValueKindFactory<?> valueKindFactory,
110-
ForeignCallDescriptor descriptor, Type ccType) {
115+
public static CallingConvention createCallingConvention(MetaAccessProvider metaAccess,
116+
CodeCacheProvider codeCache,
117+
WordTypes wordTypes,
118+
ValueKindFactory<?> valueKindFactory,
119+
ForeignCallDescriptor descriptor,
120+
Type ccType) {
111121
assert ccType != null;
112122
Class<?>[] argumentTypes = descriptor.getArgumentTypes();
113123
JavaType[] parameterTypes = new JavaType[argumentTypes.length];
@@ -210,22 +220,50 @@ private boolean checkStubCondition() {
210220
return true;
211221
}
212222

223+
/**
224+
* Encapsulates a stub's entry point and set of killed registers.
225+
*/
226+
public static final class CodeInfo {
227+
/**
228+
* Address of first instruction in the stub.
229+
*/
230+
final long start;
231+
232+
/**
233+
* @see Stub#getDestroyedCallerRegisters()
234+
*/
235+
final EconomicSet<Register> killedRegisters;
236+
237+
public CodeInfo(long start, EconomicSet<Register> killedRegisters) {
238+
this.start = start;
239+
this.killedRegisters = killedRegisters;
240+
}
241+
}
242+
243+
/**
244+
* Substituted by
245+
* {@code com.oracle.svm.graal.hotspot.libgraal.Target_org_graalvm_compiler_hotspot_HotSpotForeignCallLinkageImpl}.
246+
*/
247+
private static CodeInfo getCodeInfo(Stub stub, Backend backend) {
248+
return new CodeInfo(stub.getCode(backend).getStart(), stub.getDestroyedCallerRegisters());
249+
}
250+
213251
@Override
214252
public void finalizeAddress(Backend backend) {
215253
if (address == 0) {
216254
assert checkStubCondition();
217-
InstalledCode code = stub.getCode(backend);
255+
CodeInfo codeInfo = getCodeInfo(stub, backend);
218256

219-
EconomicSet<Register> destroyedRegisters = stub.getDestroyedCallerRegisters();
220-
if (!destroyedRegisters.isEmpty()) {
221-
AllocatableValue[] temporaryLocations = new AllocatableValue[destroyedRegisters.size()];
257+
EconomicSet<Register> killedRegisters = codeInfo.killedRegisters;
258+
if (!killedRegisters.isEmpty()) {
259+
AllocatableValue[] temporaryLocations = new AllocatableValue[killedRegisters.size()];
222260
int i = 0;
223-
for (Register reg : destroyedRegisters) {
261+
for (Register reg : killedRegisters) {
224262
temporaryLocations[i++] = reg.asValue();
225263
}
226264
temporaries = temporaryLocations;
227265
}
228-
address = code.getStart();
266+
address = codeInfo.start;
229267
}
230268
}
231269

compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProvider.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,7 @@
2424
*/
2525
package org.graalvm.compiler.hotspot.meta;
2626

27-
import java.util.List;
28-
2927
import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
30-
import org.graalvm.compiler.hotspot.stubs.Stub;
3128

3229
import jdk.vm.ci.meta.Value;
3330

@@ -40,9 +37,4 @@ public interface HotSpotForeignCallsProvider extends ForeignCallsProvider {
4037
* Gets the registers that must be saved across a foreign call into the runtime.
4138
*/
4239
Value[] getNativeABICallerSaveRegisters();
43-
44-
/**
45-
* Gets the set of stubs linked to by the foreign calls represented by this object.
46-
*/
47-
List<Stub> getStubs();
4840
}

compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@
3434
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.MARK_WORD_LOCATION;
3535
import static org.graalvm.word.LocationIdentity.any;
3636

37-
import java.util.ArrayList;
38-
import java.util.List;
37+
import java.util.function.BiConsumer;
3938

4039
import org.graalvm.collections.EconomicMap;
40+
import org.graalvm.collections.MapCursor;
4141
import org.graalvm.compiler.core.common.LIRKind;
4242
import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
4343
import org.graalvm.compiler.core.common.spi.ForeignCallSignature;
@@ -106,12 +106,26 @@ public HotSpotJVMCIRuntime getJVMCIRuntime() {
106106
return jvmciRuntime;
107107
}
108108

109+
/**
110+
* Registers a foreign call signature that may subsequently have linkage
111+
* {@linkplain #register(HotSpotForeignCallLinkage) registered}.
112+
*
113+
* This exists to support foreign calls who linkage is not generated eagerly. Libgraal needs to
114+
* know the signature of such calls during image building.
115+
*/
116+
public void register(ForeignCallSignature sig) {
117+
if (!foreignCalls.containsKey(sig)) {
118+
foreignCalls.put(sig, null);
119+
}
120+
}
121+
109122
/**
110123
* Registers the linkage for a foreign call.
111124
*/
112125
public HotSpotForeignCallLinkage register(HotSpotForeignCallLinkage linkage) {
113-
assert !foreignCalls.containsKey(linkage.getDescriptor().getSignature()) : "already registered linkage for " + linkage.getDescriptor();
114-
foreignCalls.put(linkage.getDescriptor().getSignature(), linkage);
126+
ForeignCallSignature key = linkage.getDescriptor().getSignature();
127+
HotSpotForeignCallLinkage existing = foreignCalls.put(key, linkage);
128+
GraalError.guarantee(existing == null, "already registered linkage for %s: %s", key, existing);
115129
return linkage;
116130
}
117131

@@ -161,8 +175,8 @@ public HotSpotForeignCallLinkage registerForeignCall(
161175
throw new IllegalArgumentException("address must be non-zero");
162176
}
163177
Class<?> resultType = descriptor.getResultType();
164-
assert descriptor.getTransition() != SAFEPOINT || resultType.isPrimitive() || Word.class.isAssignableFrom(resultType) : "non-leaf foreign calls must return objects in thread local storage: " +
165-
descriptor;
178+
GraalError.guarantee(descriptor.getTransition() != SAFEPOINT || resultType.isPrimitive() || Word.class.isAssignableFrom(resultType),
179+
"non-leaf foreign calls must return objects in thread local storage: %s", descriptor);
166180
return register(HotSpotForeignCallLinkageImpl.create(metaAccess,
167181
codeCache,
168182
wordTypes,
@@ -213,7 +227,7 @@ public void invokeJavaMethodStub(OptionValues options,
213227
HotSpotForeignCallLinkage targetLinkage = stub.getTargetLinkage();
214228
linkage.setCompiledStub(stub);
215229
register(linkage);
216-
if (!foreignCalls.containsKey(targetLinkage.getDescriptor().getSignature())) {
230+
if (foreignCalls.get(targetLinkage.getDescriptor().getSignature()) == null) {
217231
register(targetLinkage);
218232
}
219233
}
@@ -222,25 +236,30 @@ public void invokeJavaMethodStub(OptionValues options,
222236
public static final boolean DONT_PREPEND_THREAD = !PREPEND_THREAD;
223237

224238
@Override
225-
public HotSpotForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor) {
226-
assert foreignCalls != null : descriptor;
227-
HotSpotForeignCallLinkage callTarget = foreignCalls.get(descriptor.getSignature());
239+
public HotSpotForeignCallLinkage lookupForeignCall(ForeignCallSignature signature) {
240+
GraalError.guarantee(foreignCalls != null, "%s", signature);
241+
HotSpotForeignCallLinkage callTarget = foreignCalls.get(signature);
228242
if (callTarget == null) {
229-
throw GraalError.shouldNotReachHere("Missing implementation for runtime call: " + descriptor);
243+
throw GraalError.shouldNotReachHere("Missing implementation for runtime call: " + signature);
230244
}
231245
callTarget.finalizeAddress(runtime.getHostBackend());
232246
return callTarget;
233247
}
234248

249+
@Override
250+
public HotSpotForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor) {
251+
return lookupForeignCall(descriptor.getSignature());
252+
}
253+
235254
@Override
236255
public HotSpotForeignCallDescriptor getDescriptor(ForeignCallSignature signature) {
237256
HotSpotForeignCallDescriptor descriptor = signatureMap.get(signature);
238-
assert descriptor != null : signature;
257+
GraalError.guarantee(descriptor != null, "%s", signature);
239258
return descriptor;
240259
}
241260

242261
HotSpotForeignCallDescriptor createDescriptor(ForeignCallSignature signature, Transition transition, Reexecutability reexecutability, LocationIdentity... killLocations) {
243-
assert signatureMap.get(signature) == null;
262+
GraalError.guarantee(!signatureMap.containsKey(signature), "%s", signature);
244263
HotSpotForeignCallDescriptor descriptor = new HotSpotForeignCallDescriptor(signature, transition, reexecutability, killLocations);
245264
signatureMap.put(signature, descriptor);
246265
return descriptor;
@@ -251,16 +270,14 @@ public LIRKind getValueKind(JavaKind javaKind) {
251270
return LIRKind.fromJavaKind(codeCache.getTarget().arch, javaKind);
252271
}
253272

254-
@Override
255-
public List<Stub> getStubs() {
256-
List<Stub> stubs = new ArrayList<>();
257-
for (HotSpotForeignCallLinkage linkage : foreignCalls.getValues()) {
258-
if (linkage.isCompiledStub()) {
259-
Stub stub = linkage.getStub();
260-
assert stub != null;
261-
stubs.add(stub);
262-
}
273+
/**
274+
* Performs {@code action} for each registered foreign call. The second parameter to
275+
* {@code action} is {@code null} when linkage is not yet available for the call.
276+
*/
277+
public void forEachForeignCall(BiConsumer<ForeignCallSignature, HotSpotForeignCallLinkage> action) {
278+
MapCursor<ForeignCallSignature, HotSpotForeignCallLinkage> cursor = foreignCalls.getEntries();
279+
while (cursor.advance()) {
280+
action.accept(cursor.getKey(), cursor.getValue());
263281
}
264-
return stubs;
265282
}
266283
}

compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/AbstractForeignCallStub.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,34 @@ public abstract class AbstractForeignCallStub extends Stub {
9898
* @param prependThread true if the JavaThread value for the current thread is to be prepended
9999
* to the arguments for the call to {@code address}
100100
*/
101-
public AbstractForeignCallStub(OptionValues options, HotSpotJVMCIRuntime runtime, HotSpotProviders providers, long address, HotSpotForeignCallDescriptor descriptor, boolean prependThread) {
102-
super(options, providers, HotSpotForeignCallLinkageImpl.create(providers.getMetaAccess(), providers.getCodeCache(), providers.getWordTypes(), providers.getForeignCalls(), descriptor, 0L,
103-
COMPUTES_REGISTERS_KILLED, JavaCall, JavaCallee));
101+
public AbstractForeignCallStub(OptionValues options,
102+
HotSpotJVMCIRuntime runtime,
103+
HotSpotProviders providers,
104+
long address,
105+
HotSpotForeignCallDescriptor descriptor,
106+
boolean prependThread) {
107+
super(options, providers, HotSpotForeignCallLinkageImpl.create(providers.getMetaAccess(),
108+
providers.getCodeCache(),
109+
providers.getWordTypes(),
110+
providers.getForeignCalls(),
111+
descriptor,
112+
0L,
113+
COMPUTES_REGISTERS_KILLED,
114+
JavaCall,
115+
JavaCallee));
104116
this.jvmciRuntime = runtime;
105117
this.prependThread = prependThread;
106118
MetaAccessProvider metaAccess = providers.getMetaAccess();
107119
HotSpotForeignCallDescriptor targetSig = getTargetSignature(descriptor);
108-
target = HotSpotForeignCallLinkageImpl.create(metaAccess, providers.getCodeCache(), providers.getWordTypes(), providers.getForeignCalls(), targetSig, address,
109-
DESTROYS_ALL_CALLER_SAVE_REGISTERS, NativeCall, NativeCall);
120+
target = HotSpotForeignCallLinkageImpl.create(metaAccess,
121+
providers.getCodeCache(),
122+
providers.getWordTypes(),
123+
providers.getForeignCalls(),
124+
targetSig,
125+
address,
126+
DESTROYS_ALL_CALLER_SAVE_REGISTERS,
127+
NativeCall,
128+
NativeCall);
110129
}
111130

112131
protected abstract HotSpotForeignCallDescriptor getTargetSignature(HotSpotForeignCallDescriptor descriptor);

compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/InvokeJavaMethodStub.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,11 @@ public class InvokeJavaMethodStub extends AbstractForeignCallStub {
6868
* @param descriptor the signature of the call to this stub
6969
* @param staticMethod the Java method to be invoked by HotSpot
7070
*/
71-
public InvokeJavaMethodStub(OptionValues options, HotSpotJVMCIRuntime runtime, HotSpotProviders providers, long address, HotSpotForeignCallDescriptor descriptor,
71+
public InvokeJavaMethodStub(OptionValues options,
72+
HotSpotJVMCIRuntime runtime,
73+
HotSpotProviders providers,
74+
long address,
75+
HotSpotForeignCallDescriptor descriptor,
7276
ResolvedJavaMethod staticMethod) {
7377
super(options, runtime, providers, address, descriptor, true);
7478
this.javaMethod = staticMethod;

compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public void initDestroyedCallerRegisters(EconomicSet<Register> registers) {
118118

119119
/**
120120
* Gets the registers destroyed by this stub from a caller's perspective. These are the
121-
* temporaries of this stub and must thus be caller saved by a callers of this stub.
121+
* temporaries of this stub and must thus be caller saved by a caller of this stub.
122122
*/
123123
public EconomicSet<Register> getDestroyedCallerRegisters() {
124124
assert destroyedCallerRegisters != null : "not yet initialized";

compiler/src/org.graalvm.compiler.truffle.compiler.hotspot/src/org/graalvm/compiler/truffle/compiler/hotspot/HotSpotTruffleSafepointLoweringSnippet.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ public void initialize(HotSpotProviders providers,
168168
GraalError.guarantee(templates == null, "cannot re-initialize %s", this);
169169
if (config.invokeJavaMethodAddress != 0 && config.jvmciReserved0Offset != -1) {
170170
this.templates = new Templates(options, providers, config.jvmciReserved0Offset);
171+
foreignCalls.register(THREAD_LOCAL_HANDSHAKE.getSignature());
171172
this.deferredInit = () -> {
172173
long address = config.invokeJavaMethodAddress;
173174
GraalError.guarantee(address != 0, "Cannot lower %s as JVMCIRuntime::invoke_static_method_one_arg is missing", address);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalDataFactory.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
* objects} can be used to access the data by address at runtime. In order for the data to be
4343
* actually allocated in the native image, it must be reachable during the static analysis.
4444
* <p>
45-
* All method of this class can only be used at native image build time, and not at run time. It is
45+
* All methods of this class can only be used at native image build time, and not at run time. It is
4646
* not possible to extend the data section of an executable or define new symbols in an executable
4747
* at run time.
4848
*/
@@ -58,11 +58,13 @@ public static <T extends PointerBase> CGlobalData<T> forSymbol(String symbolName
5858

5959
/**
6060
* Create a reference to the symbol with the specified name. Calling {@link CGlobalData#get()}
61-
* on the returned object at runtime returns the referenced symbol's address.
61+
* on the returned object at runtime returns the referenced symbol's address. This introduces a
62+
* linking dependency on that symbol in the image.
6263
*
63-
* @param nonConstant the provided object does not have to be used as a compile-time constant
64-
* (for example, it can be retrieved from a map), but it will always introduce a
65-
* linking dependency on that symbol in the image.
64+
* @param nonConstant if {@code true}, the returned value is not restricted to be used as a
65+
* build time constant. For example, it can be stored in and retrieved from a map. If
66+
* {@code false}, the returned value must be a build time constant (e.g., accessed
67+
* from a static final field).
6668
*/
6769
public static <T extends PointerBase> CGlobalData<T> forSymbol(String symbolName, boolean nonConstant) {
6870
return new CGlobalDataImpl<>(symbolName, nonConstant);
@@ -128,11 +130,24 @@ public static <T extends PointerBase> CGlobalData<T> createWord(WordBase initial
128130
* name for the allocated word.
129131
*/
130132
public static <T extends PointerBase> CGlobalData<T> createWord(WordBase initialValue, String symbolName) {
133+
return createWord(initialValue, symbolName, false);
134+
}
135+
136+
/**
137+
* Same as {@link #createWord(WordBase)}, and additionally creates a symbol with the provided
138+
* name for the allocated word.
139+
*
140+
* @param nonConstant if {@code true}, the returned value is not restricted to be used as a
141+
* build time constant. For example, it can be stored in and retrieved from a map. If
142+
* {@code false}, the returned value must be a build time constant (e.g., accessed
143+
* from a static final field).
144+
*/
145+
public static <T extends PointerBase> CGlobalData<T> createWord(WordBase initialValue, String symbolName, boolean nonConstant) {
131146
Supplier<byte[]> supplier = () -> {
132147
assert ConfigurationValues.getTarget().wordSize == Long.BYTES;
133148
return ByteBuffer.allocate(Long.BYTES).order(ConfigurationValues.getTarget().arch.getByteOrder()).putLong(initialValue.rawValue()).array();
134149
};
135-
return new CGlobalDataImpl<>(symbolName, supplier);
150+
return new CGlobalDataImpl<>(symbolName, supplier, nonConstant);
136151
}
137152

138153
/**

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalDataImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ public final class CGlobalDataImpl<T extends PointerBase> extends CGlobalData<T>
4747
this(symbolName, bytesSupplier, null, false); // pre-existing data
4848
}
4949

50+
@Platforms(Platform.HOSTED_ONLY.class)
51+
CGlobalDataImpl(String symbolName, Supplier<byte[]> bytesSupplier, boolean nonConstant) {
52+
this(symbolName, bytesSupplier, null, nonConstant);
53+
}
54+
5055
@Platforms(Platform.HOSTED_ONLY.class)
5156
CGlobalDataImpl(String symbolName, IntSupplier sizeSupplier) {
5257
this(symbolName, null, sizeSupplier, false); // zero-initialized data

0 commit comments

Comments
 (0)