@@ -119,7 +119,7 @@ impl SessionManager {
119119 } ;
120120 let join_handle = thread:: Builder :: new ( )
121121 . name ( format ! ( "session-{}" , name_prefix) )
122- . stack_size ( 32 * 1024 * 1024 ) // 32 MiB — V8 with large module graphs needs extra stack
122+ . stack_size ( 32 * 1024 * 1024 ) // 32 MiB — V8 microtask checkpoints with large module graphs need extra stack
123123 . spawn ( move || {
124124 session_thread (
125125 heap_limit_mb,
@@ -512,12 +512,19 @@ fn session_thread(
512512 )
513513 } ;
514514
515- // Re-initialize module resolve state for the event loop.
516- // execute_script/execute_module clear MODULE_RESOLVE_STATE
517- // on return, but dynamic import() calls during the event loop
518- // (e.g. from timer callbacks) need it to resolve modules.
515+ // Update module resolve state for the event loop.
516+ // execute_module preserves the module cache (names + compiled
517+ // modules) on success so the event loop can reuse them for
518+ // dynamic import() in timer callbacks. We update the bridge_ctx
519+ // pointer (it points to the stack-local bridge_ctx which is still
520+ // valid). For execute_script (CJS), state was cleared on return,
521+ // so we initialize fresh if needed.
519522 execution:: MODULE_RESOLVE_STATE . with ( |cell| {
520- if cell. borrow ( ) . is_none ( ) {
523+ if cell. borrow ( ) . is_some ( ) {
524+ // Preserve module cache, just update bridge pointer
525+ execution:: update_bridge_ctx ( & bridge_ctx as * const _ ) ;
526+ } else {
527+ // CJS path or error path — initialize fresh
521528 * cell. borrow_mut ( ) = Some ( execution:: ModuleResolveState {
522529 bridge_ctx : & bridge_ctx as * const _ ,
523530 module_names : std:: collections:: HashMap :: new ( ) ,
@@ -527,6 +534,12 @@ fn session_thread(
527534 } ) ;
528535
529536 // Run event loop if there are pending async promises
537+ // Keep auto microtask policy during event loop.
538+ // The SIGSEGV that previously occurred during auto microtask
539+ // processing in resolver.resolve() was caused by V8's native
540+ // Intl.Segmenter crashing (JSSegments::Create NULL deref in ICU).
541+ // With Intl.Segmenter polyfilled in JS, auto policy works correctly.
542+
530543 let mut terminated = if pending. len ( ) > 0 {
531544 let scope = & mut v8:: HandleScope :: new ( iso) ;
532545 let ctx = v8:: Local :: new ( scope, & exec_context) ;
@@ -576,6 +589,7 @@ fn session_thread(
576589 }
577590 }
578591
592+
579593 // Clear module resolve state after event loop completes
580594 execution:: MODULE_RESOLVE_STATE . with ( |cell| {
581595 * cell. borrow_mut ( ) = None ;
0 commit comments