7373import java .util .Objects ;
7474import java .util .Set ;
7575
76- import org .graalvm .wasm .Linker .ResolutionDag .CallsiteSym ;
77- import org .graalvm .wasm .Linker .ResolutionDag .CodeEntrySym ;
7876import org .graalvm .wasm .Linker .ResolutionDag .DataSym ;
7977import org .graalvm .wasm .Linker .ResolutionDag .ElemSym ;
8078import org .graalvm .wasm .Linker .ResolutionDag .ExportFunctionSym ;
9997import org .graalvm .wasm .globals .WasmGlobal ;
10098import org .graalvm .wasm .memory .WasmMemory ;
10199import org .graalvm .wasm .memory .WasmMemoryLibrary ;
102- import org .graalvm .wasm .nodes .WasmCallStubNode ;
103- import org .graalvm .wasm .nodes .WasmDirectCallNode ;
104- import org .graalvm .wasm .nodes .WasmIndirectCallNode ;
105100
106101import com .oracle .truffle .api .CallTarget ;
107102import com .oracle .truffle .api .CompilerAsserts ;
110105import com .oracle .truffle .api .RootCallTarget ;
111106import com .oracle .truffle .api .TruffleContext ;
112107import com .oracle .truffle .api .exception .AbstractTruffleException ;
113- import com .oracle .truffle .api .nodes .Node ;
114108
115109public class Linker {
116110 public enum LinkState {
@@ -122,6 +116,11 @@ public enum LinkState {
122116
123117 private ResolutionDag resolutionDag ;
124118
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+ */
125124 public void tryLink (WasmInstance instance ) {
126125 // The first execution of a WebAssembly call target will trigger the linking of the modules
127126 // that are inside the current context (which will happen behind the call boundary).
@@ -131,22 +130,20 @@ public void tryLink(WasmInstance instance) {
131130 // compilation, and this check will fold away.
132131 // If the code is compiled synchronously, then this check will persist in the compiled code.
133132 // We nevertheless invalidate the compiled code that reaches this point.
134- if (CompilerDirectives .injectBranchProbability (CompilerDirectives .SLOWPATH_PROBABILITY , instance .isNonLinked () || instance .isLinkFailed ())) {
135- // TODO: Once we support multi-threading, add adequate synchronization here.
133+ if (CompilerDirectives .injectBranchProbability (CompilerDirectives .SLOWPATH_PROBABILITY , !instance .isLinkCompleted ())) {
136134 tryLinkOutsidePartialEvaluation (instance );
137- } else {
138- assert instance .isLinkCompleted () || instance .isLinkInProgress ();
139135 }
140136 }
141137
142138 /**
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)
143142 * @see #tryLinkOutsidePartialEvaluation(WasmInstance, ImportValueSupplier)
144143 */
145144 public void tryLink (WasmInstance instance , ImportValueSupplier imports ) {
146- if (instance .isNonLinked () || instance . isLinkFailed ()) {
145+ if (! instance .isLinkCompleted ()) {
147146 tryLinkOutsidePartialEvaluation (instance , imports );
148- } else {
149- assert instance .isLinkCompleted () || instance .isLinkInProgress ();
150147 }
151148 }
152149
@@ -157,7 +154,7 @@ private static WasmException linkFailedError(WasmInstance instance) {
157154
158155 @ CompilerDirectives .TruffleBoundary
159156 private void tryLinkOutsidePartialEvaluation (WasmInstance entryPointInstance ) {
160- tryLink (entryPointInstance , null );
157+ tryLinkOutsidePartialEvaluation (entryPointInstance , null );
161158 }
162159
163160 /**
@@ -172,25 +169,28 @@ private void tryLinkOutsidePartialEvaluation(WasmInstance entryPointInstance) {
172169 */
173170 @ CompilerDirectives .TruffleBoundary
174171 private void tryLinkOutsidePartialEvaluation (WasmInstance entryPointInstance , ImportValueSupplier imports ) {
175- if (entryPointInstance .isLinkFailed ()) {
176- // If the linking of this module failed already, then throw.
177- throw linkFailedError (entryPointInstance );
178- }
179- // Some Truffle configurations allow that the code gets compiled before executing the code.
180- // We therefore check the link state again.
181- if (entryPointInstance .isNonLinked ()) {
182- if (resolutionDag == null ) {
183- resolutionDag = new ResolutionDag ();
184- }
185- final WasmStore store = entryPointInstance .store ();
186- Map <String , WasmInstance > instances = store .moduleInstances ();
187- ArrayList <Throwable > failures = new ArrayList <>();
188- final int maxStartFunctionIndex = runLinkActions (store , instances , imports , failures );
189- linkTopologically (store , failures , maxStartFunctionIndex );
190- assignTypeEquivalenceClasses (store );
191- resolutionDag = null ;
192- runStartFunctions (instances , failures );
193- 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+ }
194194 }
195195 }
196196
@@ -244,7 +244,9 @@ private static void assignTypeEquivalenceClasses(WasmStore store) {
244244 }
245245
246246 private static void assignTypeEquivalenceClasses (WasmModule module , WasmLanguage language ) {
247- synchronized (module ) {
247+ var lock = module .getLock ();
248+ lock .lock ();
249+ try {
248250 if (module .isParsed ()) {
249251 return ;
250252 }
@@ -259,6 +261,8 @@ private static void assignTypeEquivalenceClasses(WasmModule module, WasmLanguage
259261 function .setTypeEquivalenceClass (symtab .equivalenceClass (function .typeIndex ()));
260262 }
261263 module .setParsed ();
264+ } finally {
265+ lock .unlock ();
262266 }
263267 }
264268
@@ -462,33 +466,6 @@ void resolveFunctionExport(WasmModule module, int functionIndex, String exported
462466 resolutionDag .resolveLater (new ExportFunctionSym (module .name (), exportedFunctionName ), dependencies , NO_RESOLVE_ACTION );
463467 }
464468
465- public void resolveCallNode (Node [] callNodes , WasmInstance instance , int callNodeIndex , int bytecodeOffset ) {
466- Node unresolvedCallNode = callNodes [callNodeIndex ];
467- if (unresolvedCallNode instanceof WasmCallStubNode ) {
468- final WasmFunction function = ((WasmCallStubNode ) unresolvedCallNode ).function ();
469- final CallTarget target = instance .target (function .index ());
470- callNodes [callNodeIndex ] = WasmDirectCallNode .create (target , bytecodeOffset );
471- } else {
472- assert unresolvedCallNode instanceof WasmIndirectCallNode : unresolvedCallNode ;
473- }
474- }
475-
476- public void resolveCallsite (WasmInstance instance , Node [] callNodes , int instructionOffset , int controlTableOffset , int bytecodeOffset , WasmFunction function ) {
477- final Runnable resolveAction = () -> resolveCallNode (callNodes , instance , controlTableOffset , bytecodeOffset );
478- final Sym [] dependencies = new Sym []{
479- function .isImported ()
480- ? new ImportFunctionSym (instance .name (), function .importDescriptor (), function .index ())
481- : new CodeEntrySym (instance .name (), function .index ())};
482- resolutionDag .resolveLater (new CallsiteSym (instance .name (), instructionOffset , controlTableOffset ), dependencies , resolveAction );
483- }
484-
485- void resolveCodeEntry (WasmModule module , int functionIndex ) {
486- if (resolutionDag == null ) {
487- resolutionDag = new ResolutionDag ();
488- }
489- resolutionDag .resolveLater (new CodeEntrySym (module .name (), functionIndex ), ResolutionDag .NO_DEPENDENCIES , NO_RESOLVE_ACTION );
490- }
491-
492469 void resolveMemoryImport (WasmStore store , WasmInstance instance , ImportDescriptor importDescriptor , int memoryIndex , long declaredMinSize , long declaredMaxSize , boolean typeIndex64 ,
493470 boolean shared , ImportValueSupplier imports ) {
494471 final String importedModuleName = importDescriptor .moduleName ();
@@ -1160,64 +1137,6 @@ public boolean equals(Object object) {
11601137 }
11611138 }
11621139
1163- static class CallsiteSym extends Sym {
1164- final int instructionOffset ;
1165- final int controlTableOffset ;
1166-
1167- CallsiteSym (String moduleName , int instructionOffset , int controlTableOffset ) {
1168- super (moduleName );
1169- this .instructionOffset = instructionOffset ;
1170- this .controlTableOffset = controlTableOffset ;
1171- }
1172-
1173- @ Override
1174- public String toString () {
1175- return String .format (Locale .ROOT , "(callsite %d at %d in %s)" , controlTableOffset , instructionOffset , moduleName );
1176- }
1177-
1178- @ Override
1179- public int hashCode () {
1180- return moduleName .hashCode () ^ instructionOffset ^ (controlTableOffset << 16 );
1181- }
1182-
1183- @ Override
1184- public boolean equals (Object object ) {
1185- if (!(object instanceof CallsiteSym )) {
1186- return false ;
1187- }
1188- final CallsiteSym that = (CallsiteSym ) object ;
1189- return this .instructionOffset == that .instructionOffset && this .controlTableOffset == that .controlTableOffset && this .moduleName .equals (that .moduleName );
1190- }
1191- }
1192-
1193- static class CodeEntrySym extends Sym {
1194- final int functionIndex ;
1195-
1196- CodeEntrySym (String moduleName , int functionIndex ) {
1197- super (moduleName );
1198- this .functionIndex = functionIndex ;
1199- }
1200-
1201- @ Override
1202- public String toString () {
1203- return String .format (Locale .ROOT , "(code entry at %d in %s)" , functionIndex , moduleName );
1204- }
1205-
1206- @ Override
1207- public int hashCode () {
1208- return moduleName .hashCode () ^ functionIndex ;
1209- }
1210-
1211- @ Override
1212- public boolean equals (Object object ) {
1213- if (!(object instanceof CodeEntrySym )) {
1214- return false ;
1215- }
1216- final CodeEntrySym that = (CodeEntrySym ) object ;
1217- return this .functionIndex == that .functionIndex && this .moduleName .equals (that .moduleName );
1218- }
1219- }
1220-
12211140 static class ImportMemorySym extends Sym {
12221141 final ImportDescriptor importDescriptor ;
12231142 final int memoryIndex ;
0 commit comments