@@ -165,15 +165,6 @@ ModuleWrap::ModuleWrap(Realm* realm,
165165 }
166166 MakeWeak ();
167167 module_.SetWeak ();
168-
169- HandleScope scope (realm->isolate ());
170- Local<Context> context = realm->context ();
171- Local<FixedArray> requests = module ->GetModuleRequests ();
172- for (int i = 0 ; i < requests->Length (); i++) {
173- ModuleCacheKey module_cache_key = ModuleCacheKey::From (
174- context, requests->Get (context, i).As <ModuleRequest>());
175- resolve_cache_[module_cache_key] = i;
176- }
177168}
178169
179170ModuleWrap::~ModuleWrap () {
@@ -194,30 +185,6 @@ Local<Context> ModuleWrap::context() const {
194185 return obj.As <Object>()->GetCreationContextChecked ();
195186}
196187
197- ModuleWrap* ModuleWrap::GetLinkedRequest (uint32_t index) {
198- DCHECK (IsLinked ());
199- Isolate* isolate = env ()->isolate ();
200- EscapableHandleScope scope (isolate);
201- Local<Data> linked_requests_data =
202- object ()->GetInternalField (kLinkedRequestsSlot );
203- DCHECK (linked_requests_data->IsValue () &&
204- linked_requests_data.As <Value>()->IsArray ());
205- Local<Array> requests = linked_requests_data.As <Array>();
206-
207- CHECK_LT (index, requests->Length ());
208-
209- Local<Value> module_value;
210- if (!requests->Get (context (), index).ToLocal (&module_value)) {
211- return nullptr ;
212- }
213- CHECK (module_value->IsObject ());
214- Local<Object> module_object = module_value.As <Object>();
215-
216- ModuleWrap* module_wrap;
217- ASSIGN_OR_RETURN_UNWRAP (&module_wrap, module_object, nullptr );
218- return module_wrap;
219- }
220-
221188ModuleWrap* ModuleWrap::GetFromModule (Environment* env,
222189 Local<Module> module ) {
223190 auto range = env->hash_to_module_map .equal_range (module ->GetIdentityHash ());
@@ -653,6 +620,7 @@ void ModuleWrap::GetModuleRequests(const FunctionCallbackInfo<Value>& args) {
653620// moduleWrap.link(moduleWraps)
654621void ModuleWrap::Link (const FunctionCallbackInfo<Value>& args) {
655622 Isolate* isolate = args.GetIsolate ();
623+ HandleScope handle_scope (isolate);
656624 Realm* realm = Realm::GetCurrent (args);
657625 Local<Context> context = realm->context ();
658626
@@ -664,33 +632,70 @@ void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
664632 Local<FixedArray> requests =
665633 dependent->module_ .Get (isolate)->GetModuleRequests ();
666634 Local<Array> modules = args[0 ].As <Array>();
667- CHECK_EQ (modules->Length (), static_cast <uint32_t >(requests->Length ()));
668-
669- for (int i = 0 ; i < requests->Length (); i++) {
635+ std::vector<Global<Value>> modules_vector;
636+ if (FromV8Array (context, modules, &modules_vector).IsEmpty ()) {
637+ return ;
638+ }
639+ size_t request_count = static_cast <size_t >(requests->Length ());
640+ CHECK_EQ (modules_vector.size (), request_count);
641+ std::vector<ModuleWrap*> linked_module_wraps (request_count);
642+
643+ // Track the duplicated module requests. For example if a modulelooks like
644+ // this:
645+ //
646+ // import { foo } from 'mod' with { type: 'json' };
647+ // import source ModSource from 'mod' with { type: 'json' };
648+ // import { baz } from 'mod2';
649+ //
650+ // The first two module requests are identical. The map would look like
651+ // { mod_key: 0, mod2_key: 2 } in this case, so that module request 0 and
652+ // module request 1 would be mapped to mod_key and both should resolve to the
653+ // module identified by module request 0 (the first one with this identity),
654+ // and module request 2 should resolve the module identified by index 2.
655+ std::unordered_map<ModuleCacheKey, size_t , ModuleCacheKey::Hash>
656+ module_request_map;
657+
658+ for (size_t i = 0 ; i < request_count; i++) {
659+ // TODO(joyeecheung): merge this with the serializeKey() in module_map.js.
660+ // This currently doesn't sort the import attributes.
661+ Local<Value> module_value = modules_vector[i].Get (isolate);
670662 ModuleCacheKey module_cache_key = ModuleCacheKey::From (
671663 context, requests->Get (context, i).As <ModuleRequest>());
672- DCHECK (dependent->resolve_cache_ .contains (module_cache_key));
673-
674- Local<Value> module_i;
675- Local<Value> module_cache_i;
676- uint32_t coalesced_index = dependent->resolve_cache_ [module_cache_key];
677- if (!modules->Get (context, i).ToLocal (&module_i) ||
678- !modules->Get (context, coalesced_index).ToLocal (&module_cache_i) ||
679- !module_i->StrictEquals (module_cache_i)) {
680- // If the module is different from the one of the same request, throw an
681- // error.
682- THROW_ERR_MODULE_LINK_MISMATCH (
683- realm->env (),
684- " Module request '%s' at index %d must be linked "
685- " to the same module requested at index %d" ,
686- module_cache_key.ToString (),
687- i,
688- coalesced_index);
689- return ;
664+ auto it = module_request_map.find (module_cache_key);
665+ if (it == module_request_map.end ()) {
666+ // This is the first request with this identity, record it - any mismatch
667+ // for this would only be found in subsequent requests, so no need to
668+ // check here.
669+ module_request_map[module_cache_key] = i;
670+ } else { // This identity has been seen before, check for mismatch.
671+ size_t first_seen_index = it->second ;
672+ // Check that the module is the same as the one resolved by the first
673+ // request with this identity.
674+ Local<Value> first_seen_value =
675+ modules_vector[first_seen_index].Get (isolate);
676+ if (!module_value->StrictEquals (first_seen_value)) {
677+ // If the module is different from the one of the same request, throw an
678+ // error.
679+ THROW_ERR_MODULE_LINK_MISMATCH (
680+ realm->env (),
681+ " Module request '%s' at index %d must be linked "
682+ " to the same module requested at index %d" ,
683+ module_cache_key.ToString (),
684+ i,
685+ first_seen_index);
686+ return ;
687+ }
690688 }
689+
690+ CHECK (module_value->IsObject ()); // Guaranteed by link methods in JS land.
691+ ModuleWrap* resolved =
692+ BaseObject::Unwrap<ModuleWrap>(module_value.As <Object>());
693+ CHECK_NOT_NULL (resolved); // Guaranteed by link methods in JS land.
694+ linked_module_wraps[i] = resolved;
691695 }
692696
693697 args.This ()->SetInternalField (kLinkedRequestsSlot , modules);
698+ std::swap (dependent->linked_module_wraps_ , linked_module_wraps);
694699 dependent->linked_ = true ;
695700}
696701
@@ -1012,11 +1017,10 @@ void ModuleWrap::HasAsyncGraph(Local<Name> property,
10121017// static
10131018MaybeLocal<Module> ModuleWrap::ResolveModuleCallback (
10141019 Local<Context> context,
1015- Local<String> specifier,
1016- Local<FixedArray> import_attributes,
1020+ size_t module_request_index,
10171021 Local<Module> referrer) {
10181022 ModuleWrap* resolved_module;
1019- if (!ResolveModule (context, specifier, import_attributes , referrer)
1023+ if (!ResolveModule (context, module_request_index , referrer)
10201024 .To (&resolved_module)) {
10211025 return {};
10221026 }
@@ -1027,11 +1031,10 @@ MaybeLocal<Module> ModuleWrap::ResolveModuleCallback(
10271031// static
10281032MaybeLocal<Object> ModuleWrap::ResolveSourceCallback (
10291033 Local<Context> context,
1030- Local<String> specifier,
1031- Local<FixedArray> import_attributes,
1034+ size_t module_request_index,
10321035 Local<Module> referrer) {
10331036 ModuleWrap* resolved_module;
1034- if (!ResolveModule (context, specifier, import_attributes , referrer)
1037+ if (!ResolveModule (context, module_request_index , referrer)
10351038 .To (&resolved_module)) {
10361039 return {};
10371040 }
@@ -1050,12 +1053,22 @@ MaybeLocal<Object> ModuleWrap::ResolveSourceCallback(
10501053 return module_source_object.As <Object>();
10511054}
10521055
1056+ static std::string GetSpecifierFromModuleRequest (Local<Context> context,
1057+ Local<Module> referrer,
1058+ size_t module_request_index) {
1059+ Local<ModuleRequest> raw_request =
1060+ referrer->GetModuleRequests ()
1061+ ->Get (context, static_cast <int >(module_request_index))
1062+ .As <ModuleRequest>();
1063+ Local<String> specifier = raw_request->GetSpecifier ();
1064+ Utf8Value specifier_utf8 (Isolate::GetCurrent (), specifier);
1065+ return specifier_utf8.ToString ();
1066+ }
1067+
10531068// static
1054- Maybe<ModuleWrap*> ModuleWrap::ResolveModule (
1055- Local<Context> context,
1056- Local<String> specifier,
1057- Local<FixedArray> import_attributes,
1058- Local<Module> referrer) {
1069+ Maybe<ModuleWrap*> ModuleWrap::ResolveModule (Local<Context> context,
1070+ size_t module_request_index,
1071+ Local<Module> referrer) {
10591072 Isolate* isolate = Isolate::GetCurrent ();
10601073 Environment* env = Environment::GetCurrent (context);
10611074 if (env == nullptr ) {
@@ -1065,37 +1078,34 @@ Maybe<ModuleWrap*> ModuleWrap::ResolveModule(
10651078 // Check that the referrer is not yet been instantiated.
10661079 DCHECK (referrer->GetStatus () <= Module::kInstantiated );
10671080
1068- ModuleCacheKey cache_key =
1069- ModuleCacheKey::From (context, specifier, import_attributes);
1070-
10711081 ModuleWrap* dependent = ModuleWrap::GetFromModule (env, referrer);
10721082 if (dependent == nullptr ) {
1083+ std::string specifier =
1084+ GetSpecifierFromModuleRequest (context, referrer, module_request_index);
10731085 THROW_ERR_VM_MODULE_LINK_FAILURE (
1074- env, " request for '%s' is from invalid module" , cache_key. specifier );
1086+ env, " request for '%s' is from invalid module" , specifier);
10751087 return Nothing<ModuleWrap*>();
10761088 }
10771089 if (!dependent->IsLinked ()) {
1090+ std::string specifier =
1091+ GetSpecifierFromModuleRequest (context, referrer, module_request_index);
10781092 THROW_ERR_VM_MODULE_LINK_FAILURE (env,
10791093 " request for '%s' can not be resolved on "
10801094 " module '%s' that is not linked" ,
1081- cache_key. specifier ,
1095+ specifier,
10821096 dependent->url_ );
10831097 return Nothing<ModuleWrap*>();
10841098 }
10851099
1086- auto it = dependent->resolve_cache_ .find (cache_key);
1087- if (it == dependent->resolve_cache_ .end ()) {
1088- THROW_ERR_VM_MODULE_LINK_FAILURE (
1089- env,
1090- " request for '%s' is not cached on module '%s'" ,
1091- cache_key.specifier ,
1092- dependent->url_ );
1093- return Nothing<ModuleWrap*>();
1100+ size_t linked_module_count = dependent->linked_module_wraps_ .size ();
1101+ if (linked_module_count > 0 ) {
1102+ CHECK_LT (module_request_index, linked_module_count);
1103+ } else {
1104+ UNREACHABLE (" Module resolution callback invoked for a module"
1105+ " without linked requests" );
10941106 }
10951107
1096- ModuleWrap* module_wrap = dependent->GetLinkedRequest (it->second );
1097- CHECK_NOT_NULL (module_wrap);
1098- return Just (module_wrap);
1108+ return Just (dependent->linked_module_wraps_ [module_request_index]);
10991109}
11001110
11011111static MaybeLocal<Promise> ImportModuleDynamicallyWithPhase (
0 commit comments