@@ -123,12 +123,23 @@ ModuleWrap::ModuleWrap(Realm* realm,
123123 object->SetInternalField (kSyntheticEvaluationStepsSlot ,
124124 synthetic_evaluation_step);
125125 object->SetInternalField (kContextObjectSlot , context_object);
126+ object->SetInternalField (kLinkedRequestsSlot ,
127+ v8::Undefined (realm->isolate ()));
126128
127129 if (!synthetic_evaluation_step->IsUndefined ()) {
128130 synthetic_ = true ;
129131 }
130132 MakeWeak ();
131133 module_.SetWeak ();
134+
135+ HandleScope scope (realm->isolate ());
136+ Local<Context> context = realm->context ();
137+ Local<FixedArray> requests = module ->GetModuleRequests ();
138+ for (int i = 0 ; i < requests->Length (); i++) {
139+ ModuleCacheKey module_cache_key = ModuleCacheKey::From (
140+ context, requests->Get (context, i).As <ModuleRequest>());
141+ resolve_cache_[module_cache_key] = i;
142+ }
132143}
133144
134145ModuleWrap::~ModuleWrap () {
@@ -149,6 +160,30 @@ Local<Context> ModuleWrap::context() const {
149160 return obj.As <Object>()->GetCreationContextChecked ();
150161}
151162
163+ ModuleWrap* ModuleWrap::GetLinkedRequest (uint32_t index) {
164+ DCHECK (IsLinked ());
165+ Isolate* isolate = env ()->isolate ();
166+ EscapableHandleScope scope (isolate);
167+ Local<Data> linked_requests_data =
168+ object ()->GetInternalField (kLinkedRequestsSlot );
169+ DCHECK (linked_requests_data->IsValue () &&
170+ linked_requests_data.As <Value>()->IsArray ());
171+ Local<Array> requests = linked_requests_data.As <Array>();
172+
173+ CHECK_LT (index, requests->Length ());
174+
175+ Local<Value> module_value;
176+ if (!requests->Get (context (), index).ToLocal (&module_value)) {
177+ return nullptr ;
178+ }
179+ CHECK (module_value->IsObject ());
180+ Local<Object> module_object = module_value.As <Object>();
181+
182+ ModuleWrap* module_wrap;
183+ ASSIGN_OR_RETURN_UNWRAP (&module_wrap, module_object, nullptr );
184+ return module_wrap;
185+ }
186+
152187ModuleWrap* ModuleWrap::GetFromModule (Environment* env,
153188 Local<Module> module ) {
154189 auto range = env->hash_to_module_map .equal_range (module ->GetIdentityHash ());
@@ -542,34 +577,28 @@ void ModuleWrap::GetModuleRequests(const FunctionCallbackInfo<Value>& args) {
542577void ModuleWrap::Link (const FunctionCallbackInfo<Value>& args) {
543578 Realm* realm = Realm::GetCurrent (args);
544579 Isolate* isolate = args.GetIsolate ();
545- Local<Context> context = realm->context ();
546580
547581 ModuleWrap* dependent;
548582 ASSIGN_OR_RETURN_UNWRAP (&dependent, args.This ());
549583
550584 CHECK_EQ (args.Length (), 1 );
551585
586+ Local<Data> linked_requests =
587+ args.This ()->GetInternalField (kLinkedRequestsSlot );
588+ if (linked_requests->IsValue () &&
589+ !linked_requests.As <Value>()->IsUndefined ()) {
590+ // If the module is already linked, we should not link it again.
591+ THROW_ERR_VM_MODULE_LINK_FAILURE (realm->env (), " module is already linked" );
592+ return ;
593+ }
594+
552595 Local<FixedArray> requests =
553596 dependent->module_ .Get (isolate)->GetModuleRequests ();
554597 Local<Array> modules = args[0 ].As <Array>();
555598 CHECK_EQ (modules->Length (), static_cast <uint32_t >(requests->Length ()));
556599
557- std::vector<Global<Value>> modules_buffer;
558- if (FromV8Array (context, modules, &modules_buffer).IsNothing ()) {
559- return ;
560- }
561-
562- for (uint32_t i = 0 ; i < modules_buffer.size (); i++) {
563- Local<Object> module_object = modules_buffer[i].Get (isolate).As <Object>();
564-
565- CHECK (
566- realm->isolate_data ()->module_wrap_constructor_template ()->HasInstance (
567- module_object));
568-
569- ModuleCacheKey module_cache_key = ModuleCacheKey::From (
570- context, requests->Get (context, i).As <ModuleRequest>());
571- dependent->resolve_cache_ [module_cache_key].Reset (isolate, module_object);
572- }
600+ args.This ()->SetInternalField (kLinkedRequestsSlot , modules);
601+ dependent->linked_ = true ;
573602}
574603
575604void ModuleWrap::Instantiate (const FunctionCallbackInfo<Value>& args) {
@@ -582,9 +611,6 @@ void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
582611 TryCatchScope try_catch (realm->env ());
583612 USE (module ->InstantiateModule (context, ResolveModuleCallback));
584613
585- // clear resolve cache on instantiate
586- obj->resolve_cache_ .clear ();
587-
588614 if (try_catch.HasCaught () && !try_catch.HasTerminated ()) {
589615 CHECK (!try_catch.Message ().IsEmpty ());
590616 CHECK (!try_catch.Exception ().IsEmpty ());
@@ -731,9 +757,6 @@ void ModuleWrap::InstantiateSync(const FunctionCallbackInfo<Value>& args) {
731757 TryCatchScope try_catch (env);
732758 USE (module ->InstantiateModule (context, ResolveModuleCallback));
733759
734- // clear resolve cache on instantiate
735- obj->resolve_cache_ .clear ();
736-
737760 if (try_catch.HasCaught () && !try_catch.HasTerminated ()) {
738761 CHECK (!try_catch.Message ().IsEmpty ());
739762 CHECK (!try_catch.Exception ().IsEmpty ());
@@ -940,45 +963,63 @@ void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
940963 args.GetReturnValue ().Set (module ->GetException ());
941964}
942965
966+ // static
943967MaybeLocal<Module> ModuleWrap::ResolveModuleCallback (
944968 Local<Context> context,
945969 Local<String> specifier,
946970 Local<FixedArray> import_attributes,
947971 Local<Module> referrer) {
972+ ModuleWrap* resolved_module;
973+ if (!ResolveModule (context, specifier, import_attributes, referrer)
974+ .To (&resolved_module)) {
975+ return {};
976+ }
977+ DCHECK_NOT_NULL (resolved_module);
978+ return resolved_module->module_ .Get (context->GetIsolate ());
979+ }
980+
981+ // static
982+ Maybe<ModuleWrap*> ModuleWrap::ResolveModule (
983+ Local<Context> context,
984+ Local<String> specifier,
985+ Local<FixedArray> import_attributes,
986+ Local<Module> referrer) {
948987 Isolate* isolate = context->GetIsolate ();
949988 Environment* env = Environment::GetCurrent (context);
950989 if (env == nullptr ) {
951990 THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE (isolate);
952- return MaybeLocal<Module >();
991+ return Nothing<ModuleWrap* >();
953992 }
993+ // Check that the referrer is not yet been instantiated.
994+ DCHECK (referrer->GetStatus () <= Module::kInstantiated );
954995
955996 ModuleCacheKey cache_key =
956997 ModuleCacheKey::From (context, specifier, import_attributes);
957998
958- ModuleWrap* dependent = GetFromModule (env, referrer);
999+ ModuleWrap* dependent = ModuleWrap:: GetFromModule (env, referrer);
9591000 if (dependent == nullptr ) {
9601001 THROW_ERR_VM_MODULE_LINK_FAILURE (
9611002 env, " request for '%s' is from invalid module" , cache_key.specifier );
962- return MaybeLocal<Module >();
1003+ return Nothing<ModuleWrap* >();
9631004 }
964-
965- if (dependent->resolve_cache_ .count (cache_key) != 1 ) {
1005+ if (!dependent->IsLinked ()) {
9661006 THROW_ERR_VM_MODULE_LINK_FAILURE (
967- env, " request for '%s' is not in cache" , cache_key.specifier );
968- return MaybeLocal<Module>();
1007+ env,
1008+ " request for '%s' is from a module not been linked" ,
1009+ cache_key.specifier );
1010+ return Nothing<ModuleWrap*>();
9691011 }
9701012
971- Local<Object> module_object =
972- dependent->resolve_cache_ [cache_key].Get (isolate);
973- if (module_object.IsEmpty () || !module_object->IsObject ()) {
1013+ auto it = dependent->resolve_cache_ .find (cache_key);
1014+ if (it == dependent->resolve_cache_ .end ()) {
9741015 THROW_ERR_VM_MODULE_LINK_FAILURE (
975- env, " request for '%s' did not return an object " , cache_key.specifier );
976- return MaybeLocal<Module >();
1016+ env, " request for '%s' is not in cache " , cache_key.specifier );
1017+ return Nothing<ModuleWrap* >();
9771018 }
9781019
979- ModuleWrap* module ;
980- ASSIGN_OR_RETURN_UNWRAP (& module , module_object, MaybeLocal<Module>() );
981- return module -> module_ . Get (isolate );
1020+ ModuleWrap* module_wrap = dependent-> GetLinkedRequest (it-> second ) ;
1021+ CHECK_NOT_NULL (module_wrap );
1022+ return Just (module_wrap );
9821023}
9831024
9841025static MaybeLocal<Promise> ImportModuleDynamically (
0 commit comments