Skip to content

Commit ed6c1a5

Browse files
committed
Add synchronization to module linking.
1 parent fba8201 commit ed6c1a5

File tree

2 files changed

+38
-28
lines changed

2 files changed

+38
-28
lines changed

wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/Linker.java

+33-27
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ public enum LinkState {
116116

117117
private ResolutionDag resolutionDag;
118118

119+
/**
120+
* Tries to link a module instance and other module instances in the store.
121+
*
122+
* @param instance the module instance that triggered the linking
123+
*/
119124
public void tryLink(WasmInstance instance) {
120125
// The first execution of a WebAssembly call target will trigger the linking of the modules
121126
// that are inside the current context (which will happen behind the call boundary).
@@ -125,22 +130,20 @@ public void tryLink(WasmInstance instance) {
125130
// compilation, and this check will fold away.
126131
// If the code is compiled synchronously, then this check will persist in the compiled code.
127132
// We nevertheless invalidate the compiled code that reaches this point.
128-
if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, instance.isNonLinked() || instance.isLinkFailed())) {
129-
// TODO: Once we support multi-threading, add adequate synchronization here.
133+
if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, !instance.isLinkCompleted())) {
130134
tryLinkOutsidePartialEvaluation(instance);
131-
} else {
132-
assert instance.isLinkCompleted() || instance.isLinkInProgress();
133135
}
134136
}
135137

136138
/**
139+
* Tries to link a module instantiated via the JS API, with imports supplied by an importObject.
140+
*
141+
* @see org.graalvm.wasm.api.WebAssembly#moduleInstantiate(WasmModule, Object)
137142
* @see #tryLinkOutsidePartialEvaluation(WasmInstance, ImportValueSupplier)
138143
*/
139144
public void tryLink(WasmInstance instance, ImportValueSupplier imports) {
140-
if (instance.isNonLinked() || instance.isLinkFailed()) {
145+
if (!instance.isLinkCompleted()) {
141146
tryLinkOutsidePartialEvaluation(instance, imports);
142-
} else {
143-
assert instance.isLinkCompleted() || instance.isLinkInProgress();
144147
}
145148
}
146149

@@ -151,7 +154,7 @@ private static WasmException linkFailedError(WasmInstance instance) {
151154

152155
@CompilerDirectives.TruffleBoundary
153156
private void tryLinkOutsidePartialEvaluation(WasmInstance entryPointInstance) {
154-
tryLink(entryPointInstance, null);
157+
tryLinkOutsidePartialEvaluation(entryPointInstance, null);
155158
}
156159

157160
/**
@@ -166,25 +169,28 @@ private void tryLinkOutsidePartialEvaluation(WasmInstance entryPointInstance) {
166169
*/
167170
@CompilerDirectives.TruffleBoundary
168171
private void tryLinkOutsidePartialEvaluation(WasmInstance entryPointInstance, ImportValueSupplier imports) {
169-
if (entryPointInstance.isLinkFailed()) {
170-
// If the linking of this module failed already, then throw.
171-
throw linkFailedError(entryPointInstance);
172-
}
173-
// Some Truffle configurations allow that the code gets compiled before executing the code.
174-
// We therefore check the link state again.
175-
if (entryPointInstance.isNonLinked()) {
176-
if (resolutionDag == null) {
177-
resolutionDag = new ResolutionDag();
178-
}
179-
final WasmStore store = entryPointInstance.store();
180-
Map<String, WasmInstance> instances = store.moduleInstances();
181-
ArrayList<Throwable> failures = new ArrayList<>();
182-
final int maxStartFunctionIndex = runLinkActions(store, instances, imports, failures);
183-
linkTopologically(store, failures, maxStartFunctionIndex);
184-
assignTypeEquivalenceClasses(store);
185-
resolutionDag = null;
186-
runStartFunctions(instances, failures);
187-
checkFailures(failures);
172+
final WasmStore store = entryPointInstance.store();
173+
synchronized (store) {
174+
var linkState = entryPointInstance.linkState();
175+
if (linkState == LinkState.failed) {
176+
// If the linking of this module failed already, then throw.
177+
throw linkFailedError(entryPointInstance);
178+
}
179+
// Some Truffle configurations allow the code to be compiled before executing the code.
180+
// We therefore check the link state again.
181+
if (linkState == LinkState.nonLinked) {
182+
if (resolutionDag == null) {
183+
resolutionDag = new ResolutionDag();
184+
}
185+
Map<String, WasmInstance> instances = store.moduleInstances();
186+
ArrayList<Throwable> failures = new ArrayList<>();
187+
final int maxStartFunctionIndex = runLinkActions(store, instances, imports, failures);
188+
linkTopologically(store, failures, maxStartFunctionIndex);
189+
assignTypeEquivalenceClasses(store);
190+
resolutionDag = null;
191+
runStartFunctions(instances, failures);
192+
checkFailures(failures);
193+
}
188194
}
189195
}
190196

wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/RuntimeState.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public abstract class RuntimeState {
108108
*/
109109
private final int droppedDataInstanceOffset;
110110

111-
@CompilationFinal private Linker.LinkState linkState;
111+
@CompilationFinal private volatile Linker.LinkState linkState;
112112

113113
@CompilationFinal private int startFunctionIndex;
114114

@@ -187,6 +187,10 @@ public WasmContext context() {
187187
return store().context();
188188
}
189189

190+
public Linker.LinkState linkState() {
191+
return linkState;
192+
}
193+
190194
public boolean isNonLinked() {
191195
return linkState == Linker.LinkState.nonLinked;
192196
}

0 commit comments

Comments
 (0)