@@ -55,6 +55,7 @@ internal ModuleEntry(string path, ProgramNode program, JsEnvironment environment
5555 internal ModuleNamespace ? DeferredNamespace { get ; set ; }
5656 internal JsObject ? ImportMeta { get ; set ; }
5757 internal object ? LastValue { get ; set ; }
58+ internal bool HasAsyncDependency { get ; set ; }
5859 }
5960
6061 // Module registry: maps module paths to their exported values
@@ -718,17 +719,28 @@ private async Task StopEventLoopAsync()
718719 moduleKey ) ;
719720 _moduleRegistry [ moduleKey ] = entry ;
720721 }
722+ entry . HasAsyncDependency = ModuleHasAsyncDependency ( entry . Program , entry . Path ,
723+ new HashSet < string > ( StringComparer . Ordinal ) ) ;
721724 }
722725 else
723726 {
724727 entry = CreateModuleEntry ( EnsureStrictProgram ( program ) ,
725728 CreateModuleEnvironment ( moduleKey ) ,
726729 new JsObject ( ) ,
727730 string . Empty ) ;
731+ entry . HasAsyncDependency = ModuleHasAsyncDependency ( entry . Program , entry . Path ,
732+ new HashSet < string > ( StringComparer . Ordinal ) ) ;
728733 }
729734
730735 EnsureModuleInstantiated ( entry ) ;
731- EnsureModuleEvaluated ( entry ) ;
736+ if ( entry . IsAsync || entry . HasAsyncDependency )
737+ {
738+ EnsureModuleEvaluatedAsync ( entry ) . GetAwaiter ( ) . GetResult ( ) ;
739+ }
740+ else
741+ {
742+ EnsureModuleEvaluated ( entry ) ;
743+ }
732744 return entry . LastValue ;
733745 }
734746
@@ -785,17 +797,21 @@ private async Task StopEventLoopAsync()
785797 moduleKey ) ;
786798 _moduleRegistry [ moduleKey ] = entry ;
787799 }
800+ entry . HasAsyncDependency = ModuleHasAsyncDependency ( entry . Program , entry . Path ,
801+ new HashSet < string > ( StringComparer . Ordinal ) ) ;
788802 }
789803 else
790804 {
791805 entry = CreateModuleEntry ( EnsureStrictProgram ( program ) ,
792806 CreateModuleEnvironment ( moduleKey ) ,
793807 new JsObject ( ) ,
794808 string . Empty ) ;
809+ entry . HasAsyncDependency = ModuleHasAsyncDependency ( entry . Program , entry . Path ,
810+ new HashSet < string > ( StringComparer . Ordinal ) ) ;
795811 }
796812
797813 EnsureModuleInstantiated ( entry ) ;
798- if ( entry . IsAsync )
814+ if ( entry . IsAsync || entry . HasAsyncDependency )
799815 {
800816 await EnsureModuleEvaluatedAsync ( entry ) . ConfigureAwait ( false ) ;
801817 }
@@ -883,17 +899,21 @@ private async Task StopEventLoopAsync()
883899 moduleKey ) ;
884900 _moduleRegistry [ moduleKey ] = entry ;
885901 }
902+ entry . HasAsyncDependency = ModuleHasAsyncDependency ( entry . Program , entry . Path ,
903+ new HashSet < string > ( StringComparer . Ordinal ) ) ;
886904 }
887905 else
888906 {
889907 entry = CreateModuleEntry ( EnsureStrictProgram ( program ) ,
890908 CreateModuleEnvironment ( moduleKey ) ,
891909 new JsObject ( ) ,
892910 string . Empty ) ;
911+ entry . HasAsyncDependency = ModuleHasAsyncDependency ( entry . Program , entry . Path ,
912+ new HashSet < string > ( StringComparer . Ordinal ) ) ;
893913 }
894914
895915 EnsureModuleInstantiated ( entry ) ;
896- if ( entry . IsAsync )
916+ if ( entry . IsAsync || entry . HasAsyncDependency )
897917 {
898918 EnsureModuleEvaluatedAsync ( entry ) . GetAwaiter ( ) . GetResult ( ) ;
899919 }
@@ -1449,7 +1469,9 @@ private bool ModuleHasAsyncDependency(
14491469 var importPhase = importStatement . IsDeferred ? ImportPhase . Defer : ImportPhase . Module ;
14501470 var imported = LoadModuleForInstantiation ( importStatement . ModulePath , modulePath , importPhase , null ,
14511471 importStatement . Attributes , computeAsyncDependencies : false ) ;
1452- if ( imported . IsAsync || ModuleHasAsyncDependency ( imported . Program , imported . Path , visited ) )
1472+ if ( imported . IsAsync ||
1473+ imported . HasAsyncDependency ||
1474+ ModuleHasAsyncDependency ( imported . Program , imported . Path , visited ) )
14531475 {
14541476 return true ;
14551477 }
@@ -1459,7 +1481,9 @@ private bool ModuleHasAsyncDependency(
14591481 {
14601482 var sourceEntry = LoadModuleForInstantiation ( fromModule , modulePath , ImportPhase . Module ,
14611483 computeAsyncDependencies : false ) ;
1462- if ( sourceEntry . IsAsync || ModuleHasAsyncDependency ( sourceEntry . Program , sourceEntry . Path , visited ) )
1484+ if ( sourceEntry . IsAsync ||
1485+ sourceEntry . HasAsyncDependency ||
1486+ ModuleHasAsyncDependency ( sourceEntry . Program , sourceEntry . Path , visited ) )
14631487 {
14641488 return true ;
14651489 }
@@ -1470,7 +1494,9 @@ private bool ModuleHasAsyncDependency(
14701494 {
14711495 var sourceEntry = LoadModuleForInstantiation ( exportAll . ModulePath , modulePath , ImportPhase . Module ,
14721496 computeAsyncDependencies : false ) ;
1473- if ( sourceEntry . IsAsync || ModuleHasAsyncDependency ( sourceEntry . Program , sourceEntry . Path , visited ) )
1497+ if ( sourceEntry . IsAsync ||
1498+ sourceEntry . HasAsyncDependency ||
1499+ ModuleHasAsyncDependency ( sourceEntry . Program , sourceEntry . Path , visited ) )
14741500 {
14751501 return true ;
14761502 }
@@ -1482,6 +1508,7 @@ private bool ModuleHasAsyncDependency(
14821508 var namespaceEntry = LoadModuleForInstantiation ( exportNamespace . ModulePath , modulePath ,
14831509 ImportPhase . Module , computeAsyncDependencies : false ) ;
14841510 if ( namespaceEntry . IsAsync ||
1511+ namespaceEntry . HasAsyncDependency ||
14851512 ModuleHasAsyncDependency ( namespaceEntry . Program , namespaceEntry . Path , visited ) )
14861513 {
14871514 return true ;
@@ -1575,7 +1602,9 @@ private void EnsureModuleEvaluated(ModuleEntry entry)
15751602
15761603 EnsureModuleInstantiated ( entry ) ;
15771604
1578- if ( ! entry . IsAsync )
1605+ var requiresAsyncEvaluation = entry . IsAsync || entry . HasAsyncDependency ;
1606+
1607+ if ( ! requiresAsyncEvaluation )
15791608 {
15801609 if ( entry . Evaluating )
15811610 {
@@ -1598,7 +1627,9 @@ private void EnsureModuleEvaluated(ModuleEntry entry)
15981627 if ( entry . EvaluationTask is null )
15991628 {
16001629 entry . Evaluating = true ;
1601- entry . EvaluationTask = EvaluateModuleBodyWithTopLevelAwait ( entry , waitForAsync ) ;
1630+ entry . EvaluationTask = entry . IsAsync
1631+ ? EvaluateModuleBodyWithTopLevelAwait ( entry , waitForAsync )
1632+ : EvaluateModuleBodyWithAsyncDependencies ( entry , waitForAsync ) ;
16021633 }
16031634
16041635 if ( ! waitForAsync )
@@ -2112,7 +2143,7 @@ private enum ImportPhase
21122143 // Load the module synchronously (it's cached if already loaded)
21132144 var referrerPath = callee ? . CallingJsEnvironment is JsEnvironment env ? env . ModulePath : _currentModulePath ;
21142145 var moduleEntry = LoadModule ( specifierString , referrerPath , phase ) ;
2115- if ( moduleEntry . IsAsync )
2146+ if ( moduleEntry . IsAsync || moduleEntry . HasAsyncDependency )
21162147 {
21172148 await EnsureModuleEvaluatedAsync ( moduleEntry ) . ConfigureAwait ( false ) ;
21182149 }
@@ -2176,10 +2207,14 @@ private ModuleEntry LoadModule(
21762207 if ( _moduleRegistry . TryGetValue ( resolvedPath , out var cachedEntry ) )
21772208 {
21782209 EnsureModuleImportMeta ( cachedEntry ) ;
2210+ var cachedHasAsyncDependency = ModuleHasAsyncDependency ( cachedEntry . Program , cachedEntry . Path ,
2211+ new HashSet < string > ( StringComparer . Ordinal ) ) ;
2212+ cachedEntry . HasAsyncDependency = cachedHasAsyncDependency ;
2213+ cachedEntry . Environment . IsAsyncModule = cachedEntry . IsAsync ;
21792214 EnsureModuleInstantiated ( cachedEntry , phase , exportStarSet ) ;
21802215 if ( phase == ImportPhase . Module )
21812216 {
2182- if ( cachedEntry . IsAsync )
2217+ if ( cachedEntry . IsAsync || cachedEntry . HasAsyncDependency )
21832218 {
21842219 EnsureModuleEvaluatedAsync ( cachedEntry , waitForAsync : false ) ;
21852220 }
@@ -2223,10 +2258,15 @@ private ModuleEntry LoadModule(
22232258
22242259 _moduleRegistry [ resolvedPath ] = entry ;
22252260
2261+ var computedHasAsyncDependency = ModuleHasAsyncDependency ( entry . Program , entry . Path ,
2262+ new HashSet < string > ( StringComparer . Ordinal ) ) ;
2263+ entry . HasAsyncDependency = computedHasAsyncDependency ;
2264+ entry . Environment . IsAsyncModule = entry . IsAsync ;
2265+
22262266 EnsureModuleInstantiated ( entry , phase , exportStarSet ) ;
22272267 if ( phase == ImportPhase . Module )
22282268 {
2229- if ( entry . IsAsync )
2269+ if ( entry . IsAsync || entry . HasAsyncDependency )
22302270 {
22312271 EnsureModuleEvaluatedAsync ( entry , waitForAsync : false ) ;
22322272 }
@@ -2308,11 +2348,7 @@ private ModuleEntry LoadModuleForInstantiation(
23082348 {
23092349 var hasAsyncDependency = ModuleHasAsyncDependency ( cachedEntry . Program , cachedEntry . Path ,
23102350 new HashSet < string > ( StringComparer . Ordinal ) ) ;
2311- if ( hasAsyncDependency )
2312- {
2313- cachedEntry . IsAsync = true ;
2314- }
2315-
2351+ cachedEntry . HasAsyncDependency = hasAsyncDependency ;
23162352 cachedEntry . Environment . IsAsyncModule = cachedEntry . IsAsync ;
23172353 }
23182354 // Only instantiate, don't evaluate
@@ -2353,6 +2389,7 @@ private ModuleEntry LoadModuleForInstantiation(
23532389 {
23542390 var hasAsyncDependency = ModuleHasAsyncDependency ( entry . Program , entry . Path ,
23552391 new HashSet < string > ( StringComparer . Ordinal ) ) ;
2392+ entry . HasAsyncDependency = hasAsyncDependency ;
23562393 entry . Environment . IsAsyncModule = entry . IsAsync ;
23572394 }
23582395
@@ -3315,23 +3352,55 @@ private IReadOnlyList<ModuleEntry> GetModuleDependencies(ModuleEntry entry)
33153352 return dependencies ;
33163353 }
33173354
3318- private async Task < object ? > EvaluateModuleBodyWithTopLevelAwait (
3355+ private async Task < object ? > EvaluateModuleBodyWithAsyncDependencies (
33193356 ModuleEntry entry ,
33203357 bool drainAwaitMicrotasks = true )
33213358 {
33223359 entry . Evaluating = true ;
33233360 try
33243361 {
3325- var dependencyTasks = new List < Task < object ? > > ( ) ;
33263362 foreach ( var dependency in GetModuleDependencies ( entry ) )
33273363 {
33283364 EnsureModuleInstantiated ( dependency ) ;
3329- dependencyTasks . Add ( EnsureModuleEvaluatedAsync ( dependency , waitForAsync : true ) ) ;
3365+ await EnsureModuleEvaluatedAsync ( dependency , waitForAsync : true ) . ConfigureAwait ( false ) ;
33303366 }
33313367
3332- if ( dependencyTasks . Count > 0 )
3368+ var previousModulePath = _currentModulePath ;
3369+ _currentModulePath = entry . Path ;
3370+ try
33333371 {
3334- await Task . WhenAll ( dependencyTasks ) . ConfigureAwait ( false ) ;
3372+ var result = ExecuteModuleBody (
3373+ entry . Program ,
3374+ entry . Environment ,
3375+ entry . Exports ,
3376+ entry . Path ,
3377+ drainAwaitMicrotasks ) ;
3378+ entry . LastValue = result ;
3379+ entry . Evaluated = true ;
3380+ return result ;
3381+ }
3382+ finally
3383+ {
3384+ _currentModulePath = previousModulePath ;
3385+ }
3386+ }
3387+ finally
3388+ {
3389+ entry . Evaluating = false ;
3390+ }
3391+ }
3392+
3393+ private async Task < object ? > EvaluateModuleBodyWithTopLevelAwait (
3394+ ModuleEntry entry ,
3395+ bool drainAwaitMicrotasks = true )
3396+ {
3397+ entry . Evaluating = true ;
3398+ try
3399+ {
3400+ foreach ( var dependency in GetModuleDependencies ( entry ) )
3401+ {
3402+ EnsureModuleInstantiated ( dependency ) ;
3403+ await EnsureModuleEvaluatedAsync ( dependency , waitForAsync : true ) . ConfigureAwait ( false ) ;
33353404 }
33363405
33373406 var result = await Task
@@ -3398,18 +3467,15 @@ private void EvaluateImport(
33983467 }
33993468
34003469 var engine = moduleEnv . RealmState ? . Engine ;
3401- var hasBindings = importStatement . DefaultBinding is not null ||
3402- importStatement . NamespaceBinding is not null ||
3403- ! importStatement . NamedImports . IsEmpty ;
3470+ var isAsyncImport = moduleEntry . IsAsync || moduleEntry . HasAsyncDependency ;
34043471
34053472 List < Action > ? preservedMicrotasks = null ;
34063473
34073474 try
34083475 {
34093476 var shouldWaitForAsync =
34103477 ! importStatement . IsDeferred &&
3411- moduleEntry . IsAsync &&
3412- hasBindings &&
3478+ isAsyncImport &&
34133479 ! string . Equals ( moduleEntry . Path , referrerPath , StringComparison . Ordinal ) &&
34143480 engine is not null ;
34153481
@@ -3420,17 +3486,10 @@ importStatement.NamespaceBinding is not null ||
34203486
34213487 if ( ! importStatement . IsDeferred )
34223488 {
3423- if ( moduleEntry . IsAsync &&
3489+ if ( isAsyncImport &&
34243490 ! string . Equals ( moduleEntry . Path , referrerPath , StringComparison . Ordinal ) )
34253491 {
3426- if ( ! hasBindings )
3427- {
3428- EnsureModuleEvaluatedAsync ( moduleEntry , waitForAsync : false ) ;
3429- }
3430- else
3431- {
3432- EnsureModuleEvaluatedAsync ( moduleEntry ) . GetAwaiter ( ) . GetResult ( ) ;
3433- }
3492+ EnsureModuleEvaluatedAsync ( moduleEntry ) . GetAwaiter ( ) . GetResult ( ) ;
34343493 }
34353494 else
34363495 {
0 commit comments