@@ -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 () {
@@ -664,29 +655,50 @@ void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
664655 Local<FixedArray> requests =
665656 dependent->module_ .Get (isolate)->GetModuleRequests ();
666657 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++) {
658+ int request_count = requests->Length ();
659+ CHECK_EQ (modules->Length (), static_cast <uint32_t >(request_count));
660+
661+ // Track the duplicated module requests. For example if a modulelooks like this:
662+ //
663+ // import { foo } from 'mod' with { type: 'json' };
664+ // import { bar } from 'mod' with { type: 'json' };
665+ // import { baz } from 'mod2';
666+ //
667+ // The first two module requests are identical. The map would look like
668+ // { mod_key: 0, mod2_key: 2 } in this case, so that module request 0 and module
669+ // request 1 would be mapped to mod_key and both should resolve to the module
670+ // identified by module request 0 (the first one with this identity),
671+ // and module request 2 should resolve the module identified by index 2.
672+ std::unordered_map<ModuleCacheKey, int , ModuleCacheKey::Hash> module_request_map;
673+ Local<Value> current_module;
674+ Local<Value> first_seen_module;
675+ for (int i = 0 ; i < request_count; i++) {
676+ // TODO(joyeecheung): merge this with the serializeKey() in module_map.js. This
677+ // currently doesn't sort the import attributes.
670678 ModuleCacheKey module_cache_key = ModuleCacheKey::From (
671679 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 ;
680+ auto it = module_request_map.find (module_cache_key);
681+ if (it == module_request_map.end ()) {
682+ // This is the first request with this identity, record it - any mismatch
683+ // for this would only be found in subsequent requests, so no need to check here.
684+ module_request_map[module_cache_key] = i;
685+ } else { // This identity has been seen before, check for mismatch.
686+ int first_seen_index = it->second ;
687+ // Check that the module is the same as the one resolved by the first request with
688+ // this identity.
689+ if (!modules->Get (context, i).ToLocal (¤t_module) ||
690+ !modules->Get (context, first_seen_index).ToLocal (&first_seen_module) ||
691+ !current_module->StrictEquals (first_seen_module)) {
692+ // If the module is different from the one of the same request, throw an error.
693+ THROW_ERR_MODULE_LINK_MISMATCH (
694+ realm->env (),
695+ " Module request '%s' at index %d must be linked "
696+ " to the same module requested at index %d" ,
697+ module_cache_key.ToString (),
698+ i,
699+ first_seen_index);
700+ return ;
701+ }
690702 }
691703 }
692704
@@ -1013,11 +1025,10 @@ void ModuleWrap::HasAsyncGraph(Local<Name> property,
10131025// static
10141026MaybeLocal<Module> ModuleWrap::ResolveModuleCallback (
10151027 Local<Context> context,
1016- Local<String> specifier,
1017- Local<FixedArray> import_attributes,
1028+ size_t module_request_index,
10181029 Local<Module> referrer) {
10191030 ModuleWrap* resolved_module;
1020- if (!ResolveModule (context, specifier, import_attributes , referrer)
1031+ if (!ResolveModule (context, module_request_index , referrer)
10211032 .To (&resolved_module)) {
10221033 return {};
10231034 }
@@ -1028,11 +1039,10 @@ MaybeLocal<Module> ModuleWrap::ResolveModuleCallback(
10281039// static
10291040MaybeLocal<Object> ModuleWrap::ResolveSourceCallback (
10301041 Local<Context> context,
1031- Local<String> specifier,
1032- Local<FixedArray> import_attributes,
1042+ size_t module_request_index,
10331043 Local<Module> referrer) {
10341044 ModuleWrap* resolved_module;
1035- if (!ResolveModule (context, specifier, import_attributes , referrer)
1045+ if (!ResolveModule (context, module_request_index , referrer)
10361046 .To (&resolved_module)) {
10371047 return {};
10381048 }
@@ -1053,11 +1063,22 @@ MaybeLocal<Object> ModuleWrap::ResolveSourceCallback(
10531063 return module_source_object.As <Object>();
10541064}
10551065
1066+ static std::string GetSpecifierFromModuleRequest (Local<Context> context,
1067+ Local<Module> referrer,
1068+ size_t module_request_index) {
1069+ Local<ModuleRequest> raw_request =
1070+ referrer->GetModuleRequests ()
1071+ ->Get (context, static_cast <int >(module_request_index))
1072+ .As <ModuleRequest>();
1073+ Local<String> specifier = raw_request->GetSpecifier ();
1074+ Utf8Value specifier_utf8 (Isolate::GetCurrent (), specifier);
1075+ return specifier_utf8.ToString ();
1076+ }
1077+
10561078// static
10571079Maybe<ModuleWrap*> ModuleWrap::ResolveModule (
10581080 Local<Context> context,
1059- Local<String> specifier,
1060- Local<FixedArray> import_attributes,
1081+ size_t module_request_index,
10611082 Local<Module> referrer) {
10621083 Isolate* isolate = Isolate::GetCurrent ();
10631084 Environment* env = Environment::GetCurrent (context);
@@ -1068,31 +1089,24 @@ Maybe<ModuleWrap*> ModuleWrap::ResolveModule(
10681089 // Check that the referrer is not yet been instantiated.
10691090 DCHECK (referrer->GetStatus () <= Module::kInstantiated );
10701091
1071- ModuleCacheKey cache_key =
1072- ModuleCacheKey::From (context, specifier, import_attributes);
1073-
10741092 ModuleWrap* dependent = ModuleWrap::GetFromModule (env, referrer);
10751093 if (dependent == nullptr ) {
1094+ std::string specifier =
1095+ GetSpecifierFromModuleRequest (context, referrer, module_request_index);
10761096 THROW_ERR_VM_MODULE_LINK_FAILURE (
1077- env, " request for '%s' is from invalid module" , cache_key. specifier );
1097+ env, " request for '%s' is from invalid module" , specifier);
10781098 return Nothing<ModuleWrap*>();
10791099 }
10801100 if (!dependent->IsLinked ()) {
1101+ std::string specifier =
1102+ GetSpecifierFromModuleRequest (context, referrer, module_request_index);
10811103 THROW_ERR_VM_MODULE_LINK_FAILURE (
1082- env,
1083- " request for '%s' is from a module not been linked" ,
1084- cache_key.specifier );
1085- return Nothing<ModuleWrap*>();
1086- }
1087-
1088- auto it = dependent->resolve_cache_ .find (cache_key);
1089- if (it == dependent->resolve_cache_ .end ()) {
1090- THROW_ERR_VM_MODULE_LINK_FAILURE (
1091- env, " request for '%s' is not in cache" , cache_key.specifier );
1104+ env, " request for '%s' is from a module not been linked" , specifier);
10921105 return Nothing<ModuleWrap*>();
10931106 }
10941107
1095- ModuleWrap* module_wrap = dependent->GetLinkedRequest (it->second );
1108+ ModuleWrap* module_wrap =
1109+ dependent->GetLinkedRequest (static_cast <uint32_t >(module_request_index));
10961110 CHECK_NOT_NULL (module_wrap);
10971111 return Just (module_wrap);
10981112}
0 commit comments