@@ -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 ());
@@ -724,9 +750,6 @@ void ModuleWrap::InstantiateSync(const FunctionCallbackInfo<Value>& args) {
724750 TryCatchScope try_catch (env);
725751 USE (module ->InstantiateModule (context, ResolveModuleCallback));
726752
727- // clear resolve cache on instantiate
728- obj->resolve_cache_ .clear ();
729-
730753 if (try_catch.HasCaught () && !try_catch.HasTerminated ()) {
731754 CHECK (!try_catch.Message ().IsEmpty ());
732755 CHECK (!try_catch.Exception ().IsEmpty ());
@@ -933,45 +956,63 @@ void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
933956 args.GetReturnValue ().Set (module ->GetException ());
934957}
935958
959+ // static
936960MaybeLocal<Module> ModuleWrap::ResolveModuleCallback (
937961 Local<Context> context,
938962 Local<String> specifier,
939963 Local<FixedArray> import_attributes,
940964 Local<Module> referrer) {
965+ ModuleWrap* resolved_module;
966+ if (!ResolveModule (context, specifier, import_attributes, referrer)
967+ .To (&resolved_module)) {
968+ return {};
969+ }
970+ DCHECK_NOT_NULL (resolved_module);
971+ return resolved_module->module_ .Get (context->GetIsolate ());
972+ }
973+
974+ // static
975+ Maybe<ModuleWrap*> ModuleWrap::ResolveModule (
976+ Local<Context> context,
977+ Local<String> specifier,
978+ Local<FixedArray> import_attributes,
979+ Local<Module> referrer) {
941980 Isolate* isolate = context->GetIsolate ();
942981 Environment* env = Environment::GetCurrent (context);
943982 if (env == nullptr ) {
944983 THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE (isolate);
945- return MaybeLocal<Module >();
984+ return Nothing<ModuleWrap* >();
946985 }
986+ // Check that the referrer is not yet been instantiated.
987+ DCHECK (referrer->GetStatus () <= Module::kInstantiated );
947988
948989 ModuleCacheKey cache_key =
949990 ModuleCacheKey::From (context, specifier, import_attributes);
950991
951- ModuleWrap* dependent = GetFromModule (env, referrer);
992+ ModuleWrap* dependent = ModuleWrap:: GetFromModule (env, referrer);
952993 if (dependent == nullptr ) {
953994 THROW_ERR_VM_MODULE_LINK_FAILURE (
954995 env, " request for '%s' is from invalid module" , cache_key.specifier );
955- return MaybeLocal<Module >();
996+ return Nothing<ModuleWrap* >();
956997 }
957-
958- if (dependent->resolve_cache_ .count (cache_key) != 1 ) {
998+ if (!dependent->IsLinked ()) {
959999 THROW_ERR_VM_MODULE_LINK_FAILURE (
960- env, " request for '%s' is not in cache" , cache_key.specifier );
961- return MaybeLocal<Module>();
1000+ env,
1001+ " request for '%s' is from a module not been linked" ,
1002+ cache_key.specifier );
1003+ return Nothing<ModuleWrap*>();
9621004 }
9631005
964- Local<Object> module_object =
965- dependent->resolve_cache_ [cache_key].Get (isolate);
966- if (module_object.IsEmpty () || !module_object->IsObject ()) {
1006+ auto it = dependent->resolve_cache_ .find (cache_key);
1007+ if (it == dependent->resolve_cache_ .end ()) {
9671008 THROW_ERR_VM_MODULE_LINK_FAILURE (
968- env, " request for '%s' did not return an object " , cache_key.specifier );
969- return MaybeLocal<Module >();
1009+ env, " request for '%s' is not in cache " , cache_key.specifier );
1010+ return Nothing<ModuleWrap* >();
9701011 }
9711012
972- ModuleWrap* module ;
973- ASSIGN_OR_RETURN_UNWRAP (& module , module_object, MaybeLocal<Module>() );
974- return module -> module_ . Get (isolate );
1013+ ModuleWrap* module_wrap = dependent-> GetLinkedRequest (it-> second ) ;
1014+ CHECK_NOT_NULL (module_wrap );
1015+ return Just (module_wrap );
9751016}
9761017
9771018static MaybeLocal<Promise> ImportModuleDynamically (
0 commit comments