@@ -35,7 +35,7 @@ addToLibrary({
3535 // Asyncify code that is shared between mode 1 (original) and mode 2 (JSPI).
3636 //
3737#if ASYNCIFY == 1 && MEMORY64
38- rewindArguments : { } ,
38+ rewindArguments : new Map ( ) ,
3939#endif
4040 instrumentWasmImports ( imports ) {
4141#if EMBIND_GEN_MODE
@@ -99,13 +99,54 @@ addToLibrary({
9999 }
100100 } ,
101101#if ASYNCIFY == 1 && MEMORY64
102- saveRewindArguments ( funcName , passedArguments ) {
103- return Asyncify . rewindArguments [ funcName ] = Array . from ( passedArguments )
102+ saveRewindArguments ( func , passedArguments ) {
103+ return Asyncify . rewindArguments . set ( func , Array . from ( passedArguments ) ) ;
104104 } ,
105- restoreRewindArguments ( funcName ) {
106- return Asyncify . rewindArguments [ funcName ] || [ ]
105+ restoreRewindArguments ( func ) {
106+ #if ASSERTIONS
107+ assert ( Asyncify . rewindArguments . has ( func ) ) ;
108+ #endif
109+ return Asyncify . rewindArguments . get ( func ) ;
107110 } ,
108111#endif
112+
113+ instrumentFunction ( original ) {
114+ var wrapper = ( ...args ) => {
115+ #if ASYNCIFY_DEBUG >= 2
116+ dbg ( `ASYNCIFY: ${ ' ' . repeat ( Asyncify . exportCallStack . length ) } try ${ original } ` ) ;
117+ #endif
118+ #if ASYNCIFY == 1
119+ Asyncify . exportCallStack . push ( original ) ;
120+ try {
121+ #endif
122+ #if ASYNCIFY == 1 && MEMORY64
123+ Asyncify . saveRewindArguments ( original , args ) ;
124+ #endif
125+ return original ( ...args ) ;
126+ #if ASYNCIFY == 1
127+ } finally {
128+ if ( ! ABORT ) {
129+ var top = Asyncify . exportCallStack . pop ( ) ;
130+ #if ASSERTIONS
131+ assert ( top === original ) ;
132+ #endif
133+ #if ASYNCIFY_DEBUG >= 2
134+ dbg ( `ASYNCIFY: ${ ' ' . repeat ( Asyncify . exportCallStack . length ) } finally ${ original } ` ) ;
135+ #endif
136+ Asyncify . maybeStopUnwind ( ) ;
137+ }
138+ }
139+ #endif
140+ } ;
141+ #if ASYNCIFY == 1
142+ Asyncify . funcWrappers . set ( original , wrapper ) ;
143+ #endif
144+ #if MAIN_MODULE || ASYNCIFY_LAZY_LOAD_CODE
145+ wrapper . orig = original ;
146+ #endif
147+ return wrapper ;
148+ } ,
149+
109150 instrumentWasmExports ( exports ) {
110151#if EMBIND_GEN_MODE
111152 // Instrumenting is not needed when generating code.
@@ -121,48 +162,27 @@ addToLibrary({
121162 var ret = { } ;
122163 for ( let [ x , original ] of Object . entries ( exports ) ) {
123164 if ( typeof original == 'function' ) {
124- #if ASYNCIFY == 2
165+ #if ASYNCIFY == 2
125166 // Wrap all exports with a promising WebAssembly function.
126167 let isAsyncifyExport = exportPattern . test ( x ) ;
127168 if ( isAsyncifyExport ) {
128169 Asyncify . asyncExports . add ( original ) ;
129170 original = Asyncify . makeAsyncFunction ( original ) ;
130171 }
131172#endif
132- ret [ x ] = ( ...args ) => {
133- #if ASYNCIFY_DEBUG >= 2
134- dbg ( `ASYNCIFY: ${ ' ' . repeat ( Asyncify . exportCallStack . length ) } try ${ x } ` ) ;
135- #endif
136- #if ASYNCIFY == 1
137- Asyncify . exportCallStack . push ( x ) ;
138- try {
139- #endif
140- #if ASYNCIFY == 1 && MEMORY64
141- Asyncify . saveRewindArguments ( x , args ) ;
142- #endif
143- return original ( ...args ) ;
144- #if ASYNCIFY == 1
145- } finally {
146- if ( ! ABORT ) {
147- var y = Asyncify . exportCallStack . pop ( ) ;
148- #if ASSERTIONS
149- assert ( y === x ) ;
173+ var wrapper = Asyncify . instrumentFunction ( original ) ;
174+ #if ASYNCIFY_LAZY_LOAD_CODE
175+ original . exportName = x ;
150176#endif
151- #if ASYNCIFY_DEBUG >= 2
152- dbg ( `ASYNCIFY: ${ ' ' . repeat ( Asyncify . exportCallStack . length ) } finally ${ x } ` ) ;
153- #endif
154- Asyncify . maybeStopUnwind ( ) ;
155- }
156- }
157- #endif
158- } ;
159- #if MAIN_MODULE
160- ret [ x ] . orig = original ;
161- #endif
162- } else {
177+ ret [ x ] = wrapper ;
178+
179+ } else {
163180 ret [ x ] = original ;
164181 }
165182 }
183+ #if ASYNCIFY_LAZY_LOAD_CODE
184+ Asyncify . updateFunctionMapping ( ret ) ;
185+ #endif
166186 return ret ;
167187 } ,
168188
@@ -187,24 +207,54 @@ addToLibrary({
187207 // We must track which wasm exports are called into and
188208 // exited, so that we know where the call stack began,
189209 // which is where we must call to rewind it.
210+ // This list contains the original Wasm exports.
190211 exportCallStack : [ ] ,
191- callStackNameToId : { } ,
192- callStackIdToName : { } ,
212+ callstackFuncToId : new Map ( ) ,
213+ callStackIdToFunc : new Map ( ) ,
214+ // Maps wasm functions to their corresponding wrapper function.
215+ funcWrappers : new Map ( ) ,
193216 callStackId : 0 ,
194217 asyncPromiseHandlers : null , // { resolve, reject } pair for when *all* asynchronicity is done
195218 sleepCallbacks : [ ] , // functions to call every time we sleep
196219
197- getCallStackId ( funcName ) {
220+ #if ASYNCIFY_LAZY_LOAD_CODE
221+ updateFunctionMapping ( newExports ) {
222+ #if ASYNCIFY_DEBUG
223+ dbg ( 'updateFunctionMapping' , Asyncify . callStackIdToFunc ) ;
224+ #endif
225+ #if ASSERTIONS
226+ assert ( ! Asyncify . exportCallStack . length ) ;
227+ #endif
228+ Asyncify . callStackIdToFunc . forEach ( ( func, id ) => {
198229#if ASSERTIONS
199- assert ( funcName ) ;
230+ assert ( func . exportName ) ;
231+ assert ( newExports [ func . exportName ] ) ;
232+ assert ( newExports [ func . exportName ] . orig ) ;
233+ #endif
234+ var newFunc = newExports [ func . exportName ] . orig ;
235+ Asyncify . callStackIdToFunc . set ( id , newFunc )
236+ Asyncify . callstackFuncToId . set ( newFunc , id ) ;
237+ #if MEMORY64
238+ var args = Asyncify . rewindArguments . get ( func ) ;
239+ if ( args ) {
240+ Asyncify . rewindArguments . set ( newFunc , args ) ;
241+ Asyncify . rewindArguments . delete ( func ) ;
242+ }
200243#endif
201- var id = Asyncify . callStackNameToId [ funcName ] ;
202- if ( id === undefined ) {
203- id = Asyncify . callStackId ++ ;
204- Asyncify . callStackNameToId [ funcName ] = id ;
205- Asyncify . callStackIdToName [ id ] = funcName ;
244+ } ) ;
245+ } ,
246+ #endif
247+
248+ getCallStackId ( func ) {
249+ #if ASSERTIONS
250+ assert ( func ) ;
251+ #endif
252+ if ( ! Asyncify . callstackFuncToId . has ( func ) ) {
253+ var id = Asyncify . callStackId ++ ;
254+ Asyncify . callstackFuncToId . set ( func , id ) ;
255+ Asyncify . callStackIdToFunc . set ( id , func ) ;
206256 }
207- return id ;
257+ return Asyncify . callstackFuncToId . get ( func ) ;
208258 } ,
209259
210260 maybeStopUnwind ( ) {
@@ -246,7 +296,7 @@ addToLibrary({
246296 // An asyncify data structure has three fields:
247297 // 0 current stack pos
248298 // 4 max stack pos
249- // 8 id of function at bottom of the call stack (callStackIdToName [id] == name of js function )
299+ // 8 id of function at bottom of the call stack (callStackIdToFunc [id] == wasm func )
250300 //
251301 // The Asyncify ABI only interprets the first two fields, the rest is for the runtime.
252302 // We also embed a stack in the same memory region here, right next to the structure.
@@ -274,38 +324,24 @@ addToLibrary({
274324 { { { makeSetValue ( 'ptr' , C_STRUCTS . asyncify_data_s . rewind_id , 'rewindId' , 'i32' ) } } } ;
275325 } ,
276326
277- getDataRewindFuncName ( ptr ) {
327+ getDataRewindFunc ( ptr ) {
278328 var id = { { { makeGetValue ( 'ptr' , C_STRUCTS . asyncify_data_s . rewind_id , 'i32' ) } } } ;
279- var name = Asyncify . callStackIdToName [ id ] ;
280- #if ASSERTIONS
281- assert ( name , `id ${ id } not found in callStackIdToName` ) ;
282- #endif
283- return name ;
284- } ,
285-
286- #if RELOCATABLE
287- getDataRewindFunc__deps : [ '$resolveGlobalSymbol ' ] ,
288- #endif
289- getDataRewindFunc ( name ) {
290- var func = wasmExports [ name ] ;
291- #if RELOCATABLE
292- // Exported functions in side modules are not listed in `wasmExports`,
293- // So we should use `resolveGlobalSymbol` helper function, which is defined in `library_dylink.js`.
294- if ( ! func ) {
295- func = resolveGlobalSymbol ( name , false ) . sym ;
296- }
297- #endif
329+ var func = Asyncify . callStackIdToFunc . get ( id ) ;
298330#if ASSERTIONS
299- assert ( func , `export not found: ${ name } ` ) ;
331+ assert ( func , `id ${ id } not found in callStackIdToFunc ` ) ;
300332#endif
301333 return func ;
302334 } ,
303335
304336 doRewind ( ptr ) {
305- var name = Asyncify . getDataRewindFuncName ( ptr ) ;
306- var func = Asyncify . getDataRewindFunc ( name ) ;
337+ var original = Asyncify . getDataRewindFunc ( ptr ) ;
307338#if ASYNCIFY_DEBUG
308- dbg ( 'ASYNCIFY: doRewind:' , name ) ;
339+ dbg ( 'ASYNCIFY: doRewind:' , original ) ;
340+ #endif
341+ var func = Asyncify . funcWrappers . get ( original ) ;
342+ #if ASSERTIONS
343+ assert ( original ) ;
344+ assert ( func ) ;
309345#endif
310346 // Once we have rewound and the stack we no longer need to artificially
311347 // keep the runtime alive.
@@ -315,7 +351,7 @@ addToLibrary({
315351 // can just call the function with no args at all since and the engine will produce zeros
316352 // for all arguments. However, for i64 arguments we get `undefined cannot be converted to
317353 // BigInt`.
318- return func ( ...Asyncify . restoreRewindArguments ( name ) ) ;
354+ return func ( ...Asyncify . restoreRewindArguments ( original ) ) ;
319355#else
320356 return func ( ) ;
321357#endif
@@ -510,6 +546,7 @@ addToLibrary({
510546 } ) ;
511547 } ,
512548
549+ #if ASYNCIFY_LAZY_LOAD_CODE
513550 emscripten_lazy_load_code__async: true ,
514551 emscripten_lazy_load_code : ( ) => Asyncify . handleSleep ( ( wakeUp ) => {
515552 // Update the expected wasm binary file to be the lazy one.
@@ -519,6 +556,7 @@ addToLibrary({
519556 // Load the new wasm.
520557 createWasm ( ) ;
521558 } ) ,
559+ #endif
522560
523561 _load_secondary_module__sig : 'v' ,
524562 _load_secondary_module : async function ( ) {
0 commit comments