5656import java .util .List ;
5757import java .util .Map ;
5858import java .util .Set ;
59+ import java .util .TreeSet ;
5960import java .util .function .Supplier ;
6061
6162import com .oracle .js .parser .ir .Expression ;
@@ -609,13 +610,14 @@ public void moduleInstantiation(JSRealm realm, JSModuleRecord moduleRecord) {
609610 throw e ;
610611 }
611612
612- assert moduleRecord .getStatus () == Status .Linked || moduleRecord .getStatus () == Status .Evaluated ;
613+ assert moduleRecord .getStatus () == Status .Linked || moduleRecord .getStatus () == Status .EvaluatingAsync || moduleRecord . getStatus () == Status . Evaluated ;
613614 assert stack .isEmpty ();
614615 }
615616
616617 private int innerModuleInstantiation (JSRealm realm , JSModuleRecord moduleRecord , Deque <JSModuleRecord > stack , int index0 ) {
617618 int index = index0 ;
618- if (moduleRecord .getStatus () == Status .Linking || moduleRecord .getStatus () == Status .Linked || moduleRecord .getStatus () == Status .Evaluated ) {
619+ if (moduleRecord .getStatus () == Status .Linking || moduleRecord .getStatus () == Status .Linked || moduleRecord .getStatus () == Status .EvaluatingAsync ||
620+ moduleRecord .getStatus () == Status .Evaluated ) {
619621 return index ;
620622 }
621623 assert moduleRecord .getStatus () == Status .Unlinked ;
@@ -630,7 +632,7 @@ private int innerModuleInstantiation(JSRealm realm, JSModuleRecord moduleRecord,
630632 JSModuleRecord requiredModule = hostResolveImportedModule (moduleRecord , requestedModule );
631633 index = innerModuleInstantiation (realm , requiredModule , stack , index );
632634 assert requiredModule .getStatus () == Status .Linking || requiredModule .getStatus () == Status .Linked ||
633- requiredModule .getStatus () == Status .Evaluated : requiredModule .getStatus ();
635+ requiredModule .getStatus () == Status .EvaluatingAsync || requiredModule . getStatus () == Status . Evaluated : requiredModule .getStatus ();
634636 assert (requiredModule .getStatus () == Status .Linking ) == stack .contains (requiredModule );
635637 if (requiredModule .getStatus () == Status .Linking ) {
636638 moduleRecord .setDFSAncestorIndex (Math .min (moduleRecord .getDFSAncestorIndex (), requiredModule .getDFSAncestorIndex ()));
@@ -674,9 +676,9 @@ public Object moduleEvaluation(JSRealm realm, JSModuleRecord moduleRecord) {
674676 JSModuleRecord module = moduleRecord ;
675677 Deque <JSModuleRecord > stack = new ArrayDeque <>(4 );
676678 if (realm .getContext ().isOptionTopLevelAwait ()) {
677- assert module .getStatus () == Status .Linked || module .getStatus () == Status .Evaluated ;
678- if (module .getStatus () == Status .Evaluated ) {
679- module = getAsyncCycleRoot ( module );
679+ assert module .getStatus () == Status .Linked || module .getStatus () == Status .EvaluatingAsync || module . getStatus () == Status . Evaluated ;
680+ if (module .getStatus () == Status .EvaluatingAsync || module . getStatus () == Status . Evaluated ) {
681+ module = module . getCycleRoot ( );
680682 }
681683 if (module .getTopLevelCapability () != null ) {
682684 return module .getTopLevelCapability ().getPromise ();
@@ -685,9 +687,10 @@ public Object moduleEvaluation(JSRealm realm, JSModuleRecord moduleRecord) {
685687 module .setTopLevelCapability (capability );
686688 try {
687689 innerModuleEvaluation (realm , module , stack , 0 );
688- assert module .getStatus () == Status .Evaluated ;
690+ assert module .getStatus () == Status .EvaluatingAsync || module . getStatus () == Status . Evaluated ;
689691 assert module .getEvaluationError () == null ;
690- if (!module .isAsyncEvaluating ()) {
692+ if (!module .isAsyncEvaluation ()) {
693+ assert module .getStatus () == Status .Evaluated ;
691694 JSFunction .call (JSArguments .create (Undefined .instance , capability .getResolve (), Undefined .instance ));
692695 }
693696 assert stack .isEmpty ();
@@ -720,39 +723,20 @@ public Object moduleEvaluation(JSRealm realm, JSModuleRecord moduleRecord) {
720723 }
721724 throw e ;
722725 }
723- assert module .getStatus () == Status .Evaluated && module .getEvaluationError () == null ;
726+ assert module .getStatus () == Status .EvaluatingAsync || module .getStatus () == Status .Evaluated ;
727+ assert module .getEvaluationError () == null ;
724728
725729 assert stack .isEmpty ();
726730 Object result = module .getExecutionResult ();
727731 return result == null ? Undefined .instance : result ;
728732 }
729733 }
730734
731- @ TruffleBoundary
732- private static JSModuleRecord getAsyncCycleRoot (JSModuleRecord moduleRecord ) {
733- // GetAsyncCycleRoot ( module )
734- JSModuleRecord module = moduleRecord ;
735- assert module .getStatus () == Status .Evaluated ;
736-
737- if (module .getAsyncParentModules ().size () == 0 ) {
738- return module ;
739- }
740- while (module .getDFSIndex () > module .getDFSAncestorIndex ()) {
741- assert module .getAsyncParentModules ().size () != 0 ;
742- JSModuleRecord nextCycleModule = module .getAsyncParentModules ().remove (0 );
743- assert nextCycleModule .getDFSAncestorIndex () <= module .getDFSAncestorIndex ();
744- module = nextCycleModule ;
745- }
746-
747- assert module .getDFSIndex () == module .getDFSAncestorIndex ();
748- return module ;
749- }
750-
751735 @ TruffleBoundary
752736 private int innerModuleEvaluation (JSRealm realm , JSModuleRecord moduleRecord , Deque <JSModuleRecord > stack , int index0 ) {
753737 // InnerModuleEvaluation( module, stack, index )
754738 int index = index0 ;
755- if (moduleRecord .getStatus () == Status .Evaluated ) {
739+ if (moduleRecord .getStatus () == Status .EvaluatingAsync || moduleRecord . getStatus () == Status . Evaluated ) {
756740 if (moduleRecord .getEvaluationError () == null ) {
757741 return index ;
758742 } else {
@@ -777,26 +761,29 @@ private int innerModuleEvaluation(JSRealm realm, JSModuleRecord moduleRecord, De
777761 // Note: Instantiate must have completed successfully prior to invoking this method,
778762 // so every requested module is guaranteed to resolve successfully.
779763 index = innerModuleEvaluation (realm , requiredModule , stack , index );
780- assert requiredModule .getStatus () == Status .Evaluating || requiredModule .getStatus () == Status .Evaluated : requiredModule .getStatus ();
764+ assert requiredModule .getStatus () == Status .Evaluating || requiredModule .getStatus () == Status .EvaluatingAsync ||
765+ requiredModule .getStatus () == Status .Evaluated : requiredModule .getStatus ();
781766 assert (requiredModule .getStatus () == Status .Evaluating ) == stack .contains (requiredModule );
782767 if (requiredModule .getStatus () == Status .Evaluating ) {
783768 moduleRecord .setDFSAncestorIndex (Math .min (moduleRecord .getDFSAncestorIndex (), requiredModule .getDFSAncestorIndex ()));
784769 } else {
785- requiredModule = getAsyncCycleRoot ( requiredModule );
786- assert requiredModule .getStatus () == Status .Evaluated ;
770+ requiredModule = requiredModule . getCycleRoot ( );
771+ assert requiredModule .getStatus () == Status .EvaluatingAsync || requiredModule . getStatus () == Status . Evaluated ;
787772 if (requiredModule .getEvaluationError () != null ) {
788773 throw JSRuntime .rethrow (moduleRecord .getEvaluationError ());
789774 }
790775 }
791- if (requiredModule .isAsyncEvaluating ()) {
776+ if (requiredModule .isAsyncEvaluation ()) {
792777 moduleRecord .incPendingAsyncDependencies ();
793778 requiredModule .appendAsyncParentModules (moduleRecord );
794779 }
795780 }
796- if (moduleRecord .getPendingAsyncDependencies () > 0 ) {
797- moduleRecord .setAsyncEvaluating (true );
798- } else if (moduleRecord .isTopLevelAsync ()) {
799- moduleAsyncExecution (realm , moduleRecord );
781+ if (moduleRecord .getPendingAsyncDependencies () > 0 || moduleRecord .hasTLA ()) {
782+ assert !moduleRecord .isAsyncEvaluation ();
783+ moduleRecord .setAsyncEvaluatingOrder (realm .nextAsyncEvaluationOrder ());
784+ if (moduleRecord .getPendingAsyncDependencies () == 0 ) {
785+ moduleAsyncExecution (realm , moduleRecord );
786+ }
800787 } else {
801788 Object result = moduleExecution (realm , moduleRecord , null );
802789 moduleRecord .setExecutionResult (result );
@@ -807,7 +794,12 @@ private int innerModuleEvaluation(JSRealm realm, JSModuleRecord moduleRecord, De
807794 if (moduleRecord .getDFSAncestorIndex () == moduleRecord .getDFSIndex ()) {
808795 while (true ) {
809796 JSModuleRecord requiredModule = stack .pop ();
810- requiredModule .setStatus (Status .Evaluated );
797+ if (!requiredModule .isAsyncEvaluation ()) {
798+ requiredModule .setStatus (Status .Evaluated );
799+ } else {
800+ requiredModule .setStatus (Status .EvaluatingAsync );
801+ }
802+ requiredModule .setCycleRoot (moduleRecord );
811803 if (requiredModule .equals (moduleRecord )) {
812804 break ;
813805 }
@@ -819,9 +811,8 @@ private int innerModuleEvaluation(JSRealm realm, JSModuleRecord moduleRecord, De
819811 @ TruffleBoundary
820812 private static void moduleAsyncExecution (JSRealm realm , JSModuleRecord module ) {
821813 // ExecuteAsyncModule ( module )
822- assert module .getStatus () == Status .Evaluating || module .getStatus () == Status .Evaluated ;
823- assert module .isTopLevelAsync ();
824- module .setAsyncEvaluating (true );
814+ assert module .getStatus () == Status .Evaluating || module .getStatus () == Status .EvaluatingAsync ;
815+ assert module .hasTLA ();
825816 PromiseCapabilityRecord capability = NewPromiseCapabilityNode .createDefault (realm );
826817 DynamicObject onFulfilled = createCallAsyncModuleFulfilled (realm , module );
827818 DynamicObject onRejected = createCallAsyncModuleRejected (realm , module );
@@ -885,71 +876,91 @@ public Object execute(VirtualFrame frame) {
885876 return JSFunctionData .createCallOnly (context , callTarget , 1 , "" );
886877 }
887878
879+ private static void gatherAvailableAncestors (JSModuleRecord module , Set <JSModuleRecord > execList ) {
880+ // GatherAvailableAncestors ( module, execList )
881+ for (JSModuleRecord m : module .getAsyncParentModules ()) {
882+ if (!execList .contains (m ) && m .getCycleRoot ().getEvaluationError () == null ) {
883+ assert m .getStatus () == Status .EvaluatingAsync ;
884+ assert m .getEvaluationError () == null ;
885+ assert m .isAsyncEvaluation ();
886+ assert m .getPendingAsyncDependencies () > 0 ;
887+ m .decPendingAsyncDependencies ();
888+ if (m .getPendingAsyncDependencies () == 0 ) {
889+ execList .add (m );
890+ if (!m .hasTLA ()) {
891+ gatherAvailableAncestors (m , execList );
892+ }
893+ }
894+ }
895+ }
896+ }
897+
888898 @ TruffleBoundary
889899 private static Object asyncModuleExecutionFulfilled (JSRealm realm , JSModuleRecord module , Object dynamicImportResolutionResult ) {
890- assert module .getStatus () == Status .Evaluated ;
891- if (!module .isAsyncEvaluating ()) {
900+ if (module .getStatus () == Status .Evaluated ) {
892901 assert module .getEvaluationError () != null ;
893902 return Undefined .instance ;
894903 }
904+ assert module .getStatus () == Status .EvaluatingAsync ;
905+ assert module .isAsyncEvaluation ();
895906 assert module .getEvaluationError () == null ;
896- module .setAsyncEvaluating (false );
897- for (JSModuleRecord m : module .getAsyncParentModules ()) {
898- if (module .getDFSIndex () != module .getDFSAncestorIndex ()) {
899- assert m .getDFSAncestorIndex () <= module .getDFSAncestorIndex ();
900- }
901- m .decPendingAsyncDependencies ();
902- if (m .getPendingAsyncDependencies () == 0 && m .getEvaluationError () == null ) {
903- assert m .isAsyncEvaluating ();
904- JSModuleRecord cycleRoot = getAsyncCycleRoot (m );
905- if (cycleRoot .getEvaluationError () != null ) {
906- return Undefined .instance ;
907- }
908- if (m .isTopLevelAsync ()) {
909- moduleAsyncExecution (realm , m );
910- } else {
911- try {
912- moduleExecution (realm , m , null );
913- asyncModuleExecutionFulfilled (realm , m , dynamicImportResolutionResult );
914- } catch (Exception e ) {
915- asyncModuleExecutionRejected (realm , m , e );
907+ module .setStatus (Status .Evaluated );
908+ if (module .getTopLevelCapability () != null ) {
909+ assert module .getCycleRoot () == module ;
910+ JSFunction .call (JSArguments .create (Undefined .instance , module .getTopLevelCapability ().getResolve (), dynamicImportResolutionResult ));
911+ }
912+ Set <JSModuleRecord > execList = new TreeSet <>(new Comparator <JSModuleRecord >() {
913+ @ Override
914+ public int compare (JSModuleRecord o1 , JSModuleRecord o2 ) {
915+ return Long .compare (o1 .getAsyncEvaluatingOrder (), o2 .getAsyncEvaluatingOrder ());
916+ }
917+ });
918+ gatherAvailableAncestors (module , execList );
919+ for (JSModuleRecord m : execList ) {
920+ if (m .getStatus () == Status .Evaluated ) {
921+ assert m .getEvaluationError () != null ;
922+ } else if (m .hasTLA ()) {
923+ moduleAsyncExecution (realm , m );
924+ } else {
925+ try {
926+ moduleExecution (realm , m , null );
927+ m .setStatus (Status .Evaluated );
928+ if (m .getTopLevelCapability () != null ) {
929+ assert m .getCycleRoot () == m ;
930+ JSFunction .call (JSArguments .create (Undefined .instance , m .getTopLevelCapability ().getResolve (), dynamicImportResolutionResult ));
916931 }
932+ } catch (Exception e ) {
933+ asyncModuleExecutionRejected (realm , m , e );
917934 }
918935 }
919936 }
920- if (module .getTopLevelCapability () != null ) {
921- assert module .getDFSIndex () == module .getDFSAncestorIndex ();
922- JSFunction .call (JSArguments .create (Undefined .instance , module .getTopLevelCapability ().getResolve (), dynamicImportResolutionResult ));
923- }
924937 return Undefined .instance ;
925938 }
926939
927940 @ TruffleBoundary
928941 private static Object asyncModuleExecutionRejected (JSRealm realm , JSModuleRecord module , Object error ) {
929942 assert error != null : "Cannot reject a module creation with null error" ;
930- assert module .getStatus () == Status .Evaluated ;
931- if (!module .isAsyncEvaluating ()) {
943+ if (module .getStatus () == Status .Evaluated ) {
932944 assert module .getEvaluationError () != null ;
933945 return Undefined .instance ;
934946 }
947+ assert module .getStatus () == Status .EvaluatingAsync ;
948+ assert module .isAsyncEvaluation ();
935949 assert module .getEvaluationError () == null ;
936950 module .setEvaluationError (JSRuntime .getException (error ));
937- module .setAsyncEvaluating ( false );
951+ module .setStatus ( Status . Evaluated );
938952 for (JSModuleRecord m : module .getAsyncParentModules ()) {
939- if (module .getDFSIndex () != module .getDFSAncestorIndex ()) {
940- assert m .getDFSAncestorIndex () == module .getDFSAncestorIndex ();
941- }
942953 asyncModuleExecutionRejected (realm , m , error );
943954 }
944955 if (module .getTopLevelCapability () != null ) {
945- assert module .getDFSIndex () == module . getDFSAncestorIndex () ;
956+ assert module .getCycleRoot () == module ;
946957 JSFunction .call ((DynamicObject ) module .getTopLevelCapability ().getReject (), Undefined .instance , new Object []{error });
947958 }
948959 return Undefined .instance ;
949960 }
950961
951962 private static Object moduleExecution (JSRealm realm , JSModuleRecord moduleRecord , PromiseCapabilityRecord capability ) {
952- if (!moduleRecord .isTopLevelAsync ()) {
963+ if (!moduleRecord .hasTLA ()) {
953964 assert capability == null ;
954965 return JSFunction .call (JSArguments .create (Undefined .instance , JSFunction .create (realm , moduleRecord .getFunctionData ()), moduleRecord ));
955966 } else {
0 commit comments