@@ -41,6 +41,21 @@ var emnapiAWMT = {
4141 /* napi_async_complete_callback */ complete : 6 * POINTER_SIZE + 24 ,
4242 end : 7 * POINTER_SIZE + 24
4343 } ,
44+ /**
45+ * When another thread grows the shared WebAssembly.Memory, this agent's
46+ * cached `wasmMemory.buffer` may still have the old shorter length
47+ * (V8 refreshes it lazily). If a pointer derived from shared memory lies
48+ * beyond the cached length, `wasmMemory.grow(0)` forces the agent to
49+ * observe the current memory size and refreshes the buffer.
50+ */
51+ ensureBufferFor ( end : number ) : ArrayBufferLike {
52+ let buffer = wasmMemory . buffer
53+ if ( end > buffer . byteLength ) {
54+ wasmMemory . grow ( 0 )
55+ buffer = wasmMemory . buffer
56+ }
57+ return buffer
58+ } ,
4459 init ( ) {
4560 emnapiAWMT . pool = [ ]
4661 emnapiAWMT . workerReady = null
@@ -94,7 +109,7 @@ var emnapiAWMT = {
94109 from64 ( 'emnapiAWMT.globalAddress' )
95110 const size = emnapiAWMT . globalOffset . end
96111 const addr = emnapiAWMT . globalAddress
97- new Uint8Array ( wasmMemory . buffer , addr , size ) . fill ( 0 )
112+ new Uint8Array ( emnapiAWMT . ensureBufferFor ( addr + size ) , addr , size ) . fill ( 0 )
98113 emnapiAWMT . queueInit ( emnapiAWMT . globalAddress + emnapiAWMT . globalOffset . q )
99114 emnapiAWMT . queueInit ( emnapiAWMT . globalAddress + emnapiAWMT . globalOffset . exit_message )
100115 }
@@ -133,8 +148,8 @@ var emnapiAWMT = {
133148 }
134149 from64 ( 'index' )
135150
136- const view = new DataView ( wasmMemory . buffer )
137151 const tidOffset = 20
152+ const view = new DataView ( emnapiAWMT . ensureBufferFor ( ( index as number ) + tidOffset + 4 ) )
138153 const tid = view . getInt32 ( index + tidOffset , true )
139154 worker = PThread . pthreads [ tid ]
140155 return worker . whenLoaded !
@@ -143,26 +158,31 @@ var emnapiAWMT = {
143158 return emnapiAWMT . workerReady as Promise < any >
144159 } ,
145160 getResource ( work : number ) : number {
161+ emnapiAWMT . ensureBufferFor ( work + emnapiAWMT . offset . resource + 4 )
146162 return makeGetValue ( 'work' , 'emnapiAWMT.offset.resource' , '*' )
147163 } ,
148164 getExecute ( work : number ) : number {
165+ emnapiAWMT . ensureBufferFor ( work + emnapiAWMT . offset . execute + 4 )
149166 return makeGetValue ( 'work' , 'emnapiAWMT.offset.execute' , '*' )
150167 } ,
151168 getComplete ( work : number ) : number {
169+ emnapiAWMT . ensureBufferFor ( work + emnapiAWMT . offset . complete + 4 )
152170 return makeGetValue ( 'work' , 'emnapiAWMT.offset.complete' , '*' )
153171 } ,
154172 getEnv ( work : number ) : number {
173+ emnapiAWMT . ensureBufferFor ( work + emnapiAWMT . offset . env + 4 )
155174 return makeGetValue ( 'work' , 'emnapiAWMT.offset.env' , '*' )
156175 } ,
157176 getData ( work : number ) : number {
177+ emnapiAWMT . ensureBufferFor ( work + emnapiAWMT . offset . data + 4 )
158178 return makeGetValue ( 'work' , 'emnapiAWMT.offset.data' , '*' )
159179 } ,
160180 getMutex ( ) {
161181 const index = emnapiAWMT . globalAddress + emnapiAWMT . globalOffset . mutex
162182 const mutex = {
163183 lock ( ) {
164184 const isBrowserMain = typeof window !== 'undefined' && typeof document !== 'undefined' && ! ENVIRONMENT_IS_NODE
165- const i32a = new Int32Array ( wasmMemory . buffer , index , 1 )
185+ const i32a = new Int32Array ( emnapiAWMT . ensureBufferFor ( index + 4 ) , index , 1 )
166186 if ( isBrowserMain ) {
167187 while ( true ) {
168188 const oldValue = Atomics . compareExchange ( i32a , 0 , 0 , 10 )
@@ -181,7 +201,7 @@ var emnapiAWMT = {
181201 }
182202 } ,
183203 unlock ( ) {
184- const i32a = new Int32Array ( wasmMemory . buffer , index , 1 )
204+ const i32a = new Int32Array ( emnapiAWMT . ensureBufferFor ( index + 4 ) , index , 1 )
185205 const oldValue = Atomics . compareExchange ( i32a , 0 , 10 , 0 )
186206 if ( oldValue !== 10 ) {
187207 throw new Error ( 'Tried to unlock while not holding the mutex' )
@@ -205,25 +225,28 @@ var emnapiAWMT = {
205225 const mutex = emnapiAWMT . getMutex ( )
206226 const cond = {
207227 wait ( ) {
208- const i32a = new Int32Array ( wasmMemory . buffer , index , 1 )
228+ const i32a = new Int32Array ( emnapiAWMT . ensureBufferFor ( index + 4 ) , index , 1 )
209229 const value = Atomics . load ( i32a , 0 )
210230 mutex . unlock ( )
211231 Atomics . wait ( i32a , 0 , value )
212232 mutex . lock ( )
213233 } ,
214234 signal ( ) {
215- const i32a = new Int32Array ( wasmMemory . buffer , index , 1 )
235+ const i32a = new Int32Array ( emnapiAWMT . ensureBufferFor ( index + 4 ) , index , 1 )
216236 Atomics . add ( i32a , 0 , 1 )
217237 Atomics . notify ( i32a , 0 , 1 )
218238 }
219239 }
220240 return cond
221241 } ,
222242 queueInit ( q : number ) {
243+ emnapiAWMT . ensureBufferFor ( q + POINTER_SIZE + 4 )
223244 makeSetValue ( 'q' , 0 , 'q' , '*' )
224245 makeSetValue ( 'q' , POINTER_SIZE , 'q' , '*' )
225246 } ,
226247 queueInsertTail ( h : number , q : number ) : void {
248+ emnapiAWMT . ensureBufferFor ( h + POINTER_SIZE + 4 )
249+ emnapiAWMT . ensureBufferFor ( q + POINTER_SIZE + 4 )
227250 makeSetValue ( 'q' , 0 , 'h' , '*' )
228251 // eslint-disable-next-line @typescript-eslint/no-unused-vars
229252 const tempValue = makeGetValue ( 'h' , POINTER_SIZE , '*' )
@@ -234,6 +257,7 @@ var emnapiAWMT = {
234257 makeSetValue ( 'h' , POINTER_SIZE , 'q' , '*' )
235258 } ,
236259 queueRemove ( q : number ) : void {
260+ emnapiAWMT . ensureBufferFor ( q + POINTER_SIZE + 4 )
237261 // eslint-disable-next-line @typescript-eslint/no-unused-vars
238262 const qprev = makeGetValue ( 'q' , POINTER_SIZE , '*' )
239263 // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -242,6 +266,7 @@ var emnapiAWMT = {
242266 makeSetValue ( 'qnext' , POINTER_SIZE , 'qprev' , '*' )
243267 } ,
244268 queueEmpty ( q : number ) : boolean {
269+ emnapiAWMT . ensureBufferFor ( q + 4 )
245270 // eslint-disable-next-line eqeqeq
246271 return q == makeGetValue ( 'q' , 0 , '*' )
247272 } ,
@@ -257,7 +282,7 @@ var emnapiAWMT = {
257282
258283 _emnapi_runtime_keepalive_push ( )
259284 emnapiCtx . increaseWaitingRequestCounter ( )
260- const statusBuffer = new Int32Array ( wasmMemory . buffer , work + emnapiAWMT . offset . status , 1 )
285+ const statusBuffer = new Int32Array ( emnapiAWMT . ensureBufferFor ( work + emnapiAWMT . offset . status + 4 ) , work + emnapiAWMT . offset . status , 1 )
261286 Atomics . store ( statusBuffer , 0 , AsyncWorkStatus . Pending )
262287
263288 const mutex = emnapiAWMT . getMutex ( )
@@ -272,6 +297,7 @@ var emnapiAWMT = {
272297 throw err
273298 }
274299
300+ emnapiAWMT . ensureBufferFor ( emnapiAWMT . globalAddress + emnapiAWMT . globalOffset . idle_threads + 4 )
275301 if ( makeGetValue ( 'emnapiAWMT.globalAddress' , 'emnapiAWMT.globalOffset.idle_threads' , 'u32' ) > 0 ) {
276302 cond . signal ( )
277303 }
@@ -280,6 +306,7 @@ var emnapiAWMT = {
280306 cancelWork ( work : number ) {
281307 let cancelled = false
282308 emnapiAWMT . getMutex ( ) . execute ( ( ) => {
309+ emnapiAWMT . ensureBufferFor ( work + emnapiAWMT . offset . status + 4 )
283310 cancelled = ! emnapiAWMT . queueEmpty ( work + emnapiAWMT . offset . queue ) && makeGetValue ( 'work' , 'emnapiAWMT.offset.status' , 'i32' ) !== AsyncWorkStatus . Completed
284311 if ( cancelled ) {
285312 emnapiAWMT . queueRemove ( work + emnapiAWMT . offset . queue )
@@ -288,7 +315,7 @@ var emnapiAWMT = {
288315 if ( ! cancelled ) {
289316 return napi_status . napi_generic_failure
290317 }
291- if ( Atomics . compareExchange ( new Int32Array ( wasmMemory . buffer , work + emnapiAWMT . offset . status , 1 ) , 0 , AsyncWorkStatus . Pending , AsyncWorkStatus . Cancelled ) !== AsyncWorkStatus . Pending ) {
318+ if ( Atomics . compareExchange ( new Int32Array ( emnapiAWMT . ensureBufferFor ( work + emnapiAWMT . offset . status + 4 ) , work + emnapiAWMT . offset . status , 1 ) , 0 , AsyncWorkStatus . Pending , AsyncWorkStatus . Cancelled ) !== AsyncWorkStatus . Pending ) {
292319 return napi_status . napi_generic_failure
293320 }
294321 emnapiCtx . feature . setImmediate ( ( ) => {
@@ -316,7 +343,7 @@ var emnapiAWMT = {
316343 const resource = emnapiAWMT . getResource ( work )
317344 const resource_value = emnapiCtx . refStore . get ( resource ) ! . get ( )
318345 const resourceObject = emnapiCtx . handleStore . get ( resource_value ) ! . value
319- const view = new DataView ( wasmMemory . buffer )
346+ const view = new DataView ( emnapiAWMT . ensureBufferFor ( work + emnapiAWMT . offset . trigger_async_id + 8 ) )
320347 const asyncId = view . getFloat64 ( work + emnapiAWMT . offset . async_id , true )
321348 const triggerAsyncId = view . getFloat64 ( work + emnapiAWMT . offset . trigger_async_id , true )
322349 emnapiNodeBinding . node . makeCallback ( resourceObject , callback , [ ] , {
@@ -375,7 +402,7 @@ export var napi_create_async_work = singleThreadAsyncWork
375402 const aw = _malloc ( to64 ( 'sizeofAW' ) )
376403 if ( ! aw ) return envObject . setLastError ( napi_status . napi_generic_failure )
377404 from64 ( 'aw' )
378- new Uint8Array ( wasmMemory . buffer ) . subarray ( aw , aw + sizeofAW ) . fill ( 0 )
405+ new Uint8Array ( emnapiAWMT . ensureBufferFor ( aw + sizeofAW ) ) . subarray ( aw , aw + sizeofAW ) . fill ( 0 )
379406 const s = envObject . ensureHandleId ( resourceObject )
380407 const resourceRef = emnapiCtx . createReference ( envObject , s , 1 , ReferenceOwnership . kUserland as any )
381408 // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -409,7 +436,7 @@ export var napi_delete_async_work = singleThreadAsyncWork
409436 emnapiCtx . refStore . get ( resource ) ! . dispose ( )
410437
411438 if ( emnapiNodeBinding ) {
412- const view = new DataView ( wasmMemory . buffer )
439+ const view = new DataView ( emnapiAWMT . ensureBufferFor ( work + emnapiAWMT . offset . trigger_async_id + 8 ) )
413440 const asyncId = view . getFloat64 ( work + emnapiAWMT . offset . async_id , true )
414441 const triggerAsyncId = view . getFloat64 ( work + emnapiAWMT . offset . trigger_async_id , true )
415442 _emnapi_node_emit_async_destroy ( asyncId , triggerAsyncId )
@@ -470,10 +497,11 @@ export function _emnapi_async_worker (globalAddress: number): number {
470497 const idleThreadsAddr = globalAddress + emnapiAWMT . globalOffset . idle_threads
471498 const workerQueueAddr = globalAddress + emnapiAWMT . globalOffset . q
472499 for ( ; ; ) {
500+ emnapiAWMT . ensureBufferFor ( workerQueueAddr + 4 )
473501 while ( emnapiAWMT . queueEmpty ( workerQueueAddr ) ) {
474- Atomics . add ( new Int32Array ( wasmMemory . buffer , idleThreadsAddr , 1 ) , 0 , 1 )
502+ Atomics . add ( new Int32Array ( emnapiAWMT . ensureBufferFor ( idleThreadsAddr + 4 ) , idleThreadsAddr , 1 ) , 0 , 1 )
475503 cond . wait ( )
476- Atomics . sub ( new Int32Array ( wasmMemory . buffer , idleThreadsAddr , 1 ) , 0 , 1 )
504+ Atomics . sub ( new Int32Array ( emnapiAWMT . ensureBufferFor ( idleThreadsAddr + 4 ) , idleThreadsAddr , 1 ) , 0 , 1 )
477505 }
478506 const q = makeGetValue ( 'workerQueueAddr' , 0 , '*' )
479507 if ( q === exitMessageAddr ) {
@@ -487,7 +515,7 @@ export function _emnapi_async_worker (globalAddress: number): number {
487515
488516 mutex . unlock ( )
489517
490- const statusBuffer = new Int32Array ( wasmMemory . buffer , work + emnapiAWMT . offset . status , 1 )
518+ const statusBuffer = new Int32Array ( emnapiAWMT . ensureBufferFor ( work + emnapiAWMT . offset . status + 4 ) , work + emnapiAWMT . offset . status , 1 )
491519 if ( Atomics . load ( statusBuffer , 0 ) === AsyncWorkStatus . Cancelled ) {
492520 abort ( 'unreachable' )
493521 }
0 commit comments