@@ -133,12 +133,23 @@ ModuleWrap::ModuleWrap(Realm* realm,
133133 object->SetInternalField (kSyntheticEvaluationStepsSlot ,
134134 synthetic_evaluation_step);
135135 object->SetInternalField (kContextObjectSlot , context_object);
136+ object->SetInternalField (kLinkedRequestsSlot ,
137+ v8::Undefined (realm->isolate ()));
136138
137139 if (!synthetic_evaluation_step->IsUndefined ()) {
138140 synthetic_ = true ;
139141 }
140142 MakeWeak ();
141143 module_.SetWeak ();
144+
145+ HandleScope scope (realm->isolate ());
146+ Local<Context> context = realm->context ();
147+ Local<FixedArray> requests = module ->GetModuleRequests ();
148+ for (int i = 0 ; i < requests->Length (); i++) {
149+ ModuleCacheKey module_cache_key = ModuleCacheKey::From (
150+ context, requests->Get (context, i).As <ModuleRequest>());
151+ resolve_cache_[module_cache_key] = i;
152+ }
142153}
143154
144155ModuleWrap::~ModuleWrap () {
@@ -159,6 +170,30 @@ Local<Context> ModuleWrap::context() const {
159170 return obj.As <Object>()->GetCreationContextChecked ();
160171}
161172
173+ ModuleWrap* ModuleWrap::GetLinkedRequest (uint32_t index) {
174+ DCHECK (IsLinked ());
175+ Isolate* isolate = env ()->isolate ();
176+ EscapableHandleScope scope (isolate);
177+ Local<Data> linked_requests_data =
178+ object ()->GetInternalField (kLinkedRequestsSlot );
179+ DCHECK (linked_requests_data->IsValue () &&
180+ linked_requests_data.As <Value>()->IsArray ());
181+ Local<Array> requests = linked_requests_data.As <Array>();
182+
183+ CHECK_LT (index, requests->Length ());
184+
185+ Local<Value> module_value;
186+ if (!requests->Get (context (), index).ToLocal (&module_value)) {
187+ return nullptr ;
188+ }
189+ CHECK (module_value->IsObject ());
190+ Local<Object> module_object = module_value.As <Object>();
191+
192+ ModuleWrap* module_wrap;
193+ ASSIGN_OR_RETURN_UNWRAP (&module_wrap, module_object, nullptr );
194+ return module_wrap;
195+ }
196+
162197ModuleWrap* ModuleWrap::GetFromModule (Environment* env,
163198 Local<Module> module ) {
164199 auto range = env->hash_to_module_map .equal_range (module ->GetIdentityHash ());
@@ -571,34 +606,28 @@ void ModuleWrap::GetModuleRequests(const FunctionCallbackInfo<Value>& args) {
571606void ModuleWrap::Link (const FunctionCallbackInfo<Value>& args) {
572607 Realm* realm = Realm::GetCurrent (args);
573608 Isolate* isolate = args.GetIsolate ();
574- Local<Context> context = realm->context ();
575609
576610 ModuleWrap* dependent;
577611 ASSIGN_OR_RETURN_UNWRAP (&dependent, args.This ());
578612
579613 CHECK_EQ (args.Length (), 1 );
580614
615+ Local<Data> linked_requests =
616+ args.This ()->GetInternalField (kLinkedRequestsSlot );
617+ if (linked_requests->IsValue () &&
618+ !linked_requests.As <Value>()->IsUndefined ()) {
619+ // If the module is already linked, we should not link it again.
620+ THROW_ERR_VM_MODULE_LINK_FAILURE (realm->env (), " module is already linked" );
621+ return ;
622+ }
623+
581624 Local<FixedArray> requests =
582625 dependent->module_ .Get (isolate)->GetModuleRequests ();
583626 Local<Array> modules = args[0 ].As <Array>();
584627 CHECK_EQ (modules->Length (), static_cast <uint32_t >(requests->Length ()));
585628
586- std::vector<Global<Value>> modules_buffer;
587- if (FromV8Array (context, modules, &modules_buffer).IsNothing ()) {
588- return ;
589- }
590-
591- for (uint32_t i = 0 ; i < modules_buffer.size (); i++) {
592- Local<Object> module_object = modules_buffer[i].Get (isolate).As <Object>();
593-
594- CHECK (
595- realm->isolate_data ()->module_wrap_constructor_template ()->HasInstance (
596- module_object));
597-
598- ModuleCacheKey module_cache_key = ModuleCacheKey::From (
599- context, requests->Get (context, i).As <ModuleRequest>());
600- dependent->resolve_cache_ [module_cache_key].Reset (isolate, module_object);
601- }
629+ args.This ()->SetInternalField (kLinkedRequestsSlot , modules);
630+ dependent->linked_ = true ;
602631}
603632
604633void ModuleWrap::Instantiate (const FunctionCallbackInfo<Value>& args) {
@@ -612,9 +641,6 @@ void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
612641 USE (module ->InstantiateModule (
613642 context, ResolveModuleCallback, ResolveSourceCallback));
614643
615- // clear resolve cache on instantiate
616- obj->resolve_cache_ .clear ();
617-
618644 if (try_catch.HasCaught () && !try_catch.HasTerminated ()) {
619645 CHECK (!try_catch.Message ().IsEmpty ());
620646 CHECK (!try_catch.Exception ().IsEmpty ());
@@ -722,9 +748,6 @@ void ModuleWrap::InstantiateSync(const FunctionCallbackInfo<Value>& args) {
722748 USE (module ->InstantiateModule (
723749 context, ResolveModuleCallback, ResolveSourceCallback));
724750
725- // clear resolve cache on instantiate
726- obj->resolve_cache_ .clear ();
727-
728751 if (try_catch.HasCaught () && !try_catch.HasTerminated ()) {
729752 CHECK (!try_catch.Message ().IsEmpty ());
730753 CHECK (!try_catch.Exception ().IsEmpty ());
@@ -965,48 +988,51 @@ void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
965988 args.GetReturnValue ().Set (module ->GetException ());
966989}
967990
991+ // static
968992MaybeLocal<Module> ModuleWrap::ResolveModuleCallback (
969993 Local<Context> context,
970994 Local<String> specifier,
971995 Local<FixedArray> import_attributes,
972996 Local<Module> referrer) {
973- Isolate* isolate = context->GetIsolate ();
974- Environment* env = Environment::GetCurrent (context);
975- if (env == nullptr ) {
976- THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE (isolate);
977- return MaybeLocal<Module>();
978- }
979-
980- ModuleCacheKey cache_key =
981- ModuleCacheKey::From (context, specifier, import_attributes);
982-
983- ModuleWrap* dependent = GetFromModule (env, referrer);
984- if (dependent == nullptr ) {
985- THROW_ERR_VM_MODULE_LINK_FAILURE (
986- env, " request for '%s' is from invalid module" , cache_key.specifier );
987- return MaybeLocal<Module>();
997+ ModuleWrap* resolved_module;
998+ if (!ResolveModule (context, specifier, import_attributes, referrer)
999+ .To (&resolved_module)) {
1000+ return {};
9881001 }
1002+ DCHECK_NOT_NULL (resolved_module);
1003+ return resolved_module->module_ .Get (context->GetIsolate ());
1004+ }
9891005
990- if (dependent->resolve_cache_ .count (cache_key) != 1 ) {
991- THROW_ERR_VM_MODULE_LINK_FAILURE (
992- env, " request for '%s' is not in cache" , cache_key.specifier );
993- return MaybeLocal<Module>();
1006+ // static
1007+ MaybeLocal<Object> ModuleWrap::ResolveSourceCallback (
1008+ Local<Context> context,
1009+ Local<String> specifier,
1010+ Local<FixedArray> import_attributes,
1011+ Local<Module> referrer) {
1012+ ModuleWrap* resolved_module;
1013+ if (!ResolveModule (context, specifier, import_attributes, referrer)
1014+ .To (&resolved_module)) {
1015+ return {};
9941016 }
1017+ DCHECK_NOT_NULL (resolved_module);
9951018
996- Local<Object> module_object =
997- dependent->resolve_cache_ [cache_key].Get (isolate);
998- if (module_object.IsEmpty () || !module_object->IsObject ()) {
999- THROW_ERR_VM_MODULE_LINK_FAILURE (
1000- env, " request for '%s' did not return an object" , cache_key.specifier );
1001- return MaybeLocal<Module>();
1019+ Local<Value> module_source_object =
1020+ resolved_module->object ()
1021+ ->GetInternalField (ModuleWrap::kModuleSourceObjectSlot )
1022+ .As <Value>();
1023+ if (module_source_object->IsUndefined ()) {
1024+ Local<String> url = resolved_module->object ()
1025+ ->GetInternalField (ModuleWrap::kURLSlot )
1026+ .As <String>();
1027+ THROW_ERR_SOURCE_PHASE_NOT_DEFINED (context->GetIsolate (), url);
1028+ return {};
10021029 }
1003-
1004- ModuleWrap* module ;
1005- ASSIGN_OR_RETURN_UNWRAP (&module , module_object, MaybeLocal<Module>());
1006- return module ->module_ .Get (isolate);
1030+ CHECK (module_source_object->IsObject ());
1031+ return module_source_object.As <Object>();
10071032}
10081033
1009- MaybeLocal<Object> ModuleWrap::ResolveSourceCallback (
1034+ // static
1035+ Maybe<ModuleWrap*> ModuleWrap::ResolveModule (
10101036 Local<Context> context,
10111037 Local<String> specifier,
10121038 Local<FixedArray> import_attributes,
@@ -1015,46 +1041,38 @@ MaybeLocal<Object> ModuleWrap::ResolveSourceCallback(
10151041 Environment* env = Environment::GetCurrent (context);
10161042 if (env == nullptr ) {
10171043 THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE (isolate);
1018- return MaybeLocal<Object >();
1044+ return Nothing<ModuleWrap* >();
10191045 }
1046+ // Check that the referrer is not yet been instantiated.
1047+ DCHECK (referrer->GetStatus () <= Module::kInstantiated );
10201048
10211049 ModuleCacheKey cache_key =
10221050 ModuleCacheKey::From (context, specifier, import_attributes);
10231051
1024- ModuleWrap* dependent = GetFromModule (env, referrer);
1052+ ModuleWrap* dependent = ModuleWrap:: GetFromModule (env, referrer);
10251053 if (dependent == nullptr ) {
10261054 THROW_ERR_VM_MODULE_LINK_FAILURE (
10271055 env, " request for '%s' is from invalid module" , cache_key.specifier );
1028- return MaybeLocal<Object >();
1056+ return Nothing<ModuleWrap* >();
10291057 }
1030-
1031- if (dependent->resolve_cache_ .count (cache_key) != 1 ) {
1058+ if (!dependent->IsLinked ()) {
10321059 THROW_ERR_VM_MODULE_LINK_FAILURE (
1033- env, " request for '%s' is not in cache" , cache_key.specifier );
1034- return MaybeLocal<Object>();
1060+ env,
1061+ " request for '%s' is from a module not been linked" ,
1062+ cache_key.specifier );
1063+ return Nothing<ModuleWrap*>();
10351064 }
10361065
1037- Local<Object> module_object =
1038- dependent->resolve_cache_ [cache_key].Get (isolate);
1039- if (module_object.IsEmpty () || !module_object->IsObject ()) {
1066+ auto it = dependent->resolve_cache_ .find (cache_key);
1067+ if (it == dependent->resolve_cache_ .end ()) {
10401068 THROW_ERR_VM_MODULE_LINK_FAILURE (
1041- env, " request for '%s' did not return an object " , cache_key.specifier );
1042- return MaybeLocal<Object >();
1069+ env, " request for '%s' is not in cache " , cache_key.specifier );
1070+ return Nothing<ModuleWrap* >();
10431071 }
10441072
1045- ModuleWrap* module ;
1046- ASSIGN_OR_RETURN_UNWRAP (&module , module_object, MaybeLocal<Object>());
1047-
1048- Local<Value> module_source_object =
1049- module ->object ()->GetInternalField (kModuleSourceObjectSlot ).As <Value>();
1050- if (module_source_object->IsUndefined ()) {
1051- Local<String> url =
1052- module ->object ()->GetInternalField (kURLSlot ).As <String>();
1053- THROW_ERR_SOURCE_PHASE_NOT_DEFINED (isolate, url);
1054- return MaybeLocal<Object>();
1055- }
1056- CHECK (module_source_object->IsObject ());
1057- return module_source_object.As <Object>();
1073+ ModuleWrap* module_wrap = dependent->GetLinkedRequest (it->second );
1074+ CHECK_NOT_NULL (module_wrap);
1075+ return Just (module_wrap);
10581076}
10591077
10601078static MaybeLocal<Promise> ImportModuleDynamicallyWithPhase (
0 commit comments