@@ -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,55 @@ 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
662+ // this:
663+ //
664+ // import { foo } from 'mod' with { type: 'json' };
665+ // import { bar } from 'mod' with { type: 'json' };
666+ // import { baz } from 'mod2';
667+ //
668+ // The first two module requests are identical. The map would look like
669+ // { mod_key: 0, mod2_key: 2 } in this case, so that module request 0 and
670+ // module request 1 would be mapped to mod_key and both should resolve to the
671+ // module identified by module request 0 (the first one with this identity),
672+ // and module request 2 should resolve the module identified by index 2.
673+ std::unordered_map<ModuleCacheKey, int , ModuleCacheKey::Hash>
674+ module_request_map;
675+ Local<Value> current_module;
676+ Local<Value> first_seen_module;
677+ for (int i = 0 ; i < request_count; i++) {
678+ // TODO(joyeecheung): merge this with the serializeKey() in module_map.js.
679+ // This currently doesn't sort the import attributes.
670680 ModuleCacheKey module_cache_key = ModuleCacheKey::From (
671681 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 ;
682+ auto it = module_request_map.find (module_cache_key);
683+ if (it == module_request_map.end ()) {
684+ // This is the first request with this identity, record it - any mismatch
685+ // for this would only be found in subsequent requests, so no need to
686+ // check here.
687+ module_request_map[module_cache_key] = i;
688+ } else { // This identity has been seen before, check for mismatch.
689+ int first_seen_index = it->second ;
690+ // Check that the module is the same as the one resolved by the first
691+ // request with this identity.
692+ if (!modules->Get (context, i).ToLocal (¤t_module) ||
693+ !modules->Get (context, first_seen_index)
694+ .ToLocal (&first_seen_module) ||
695+ !current_module->StrictEquals (first_seen_module)) {
696+ // If the module is different from the one of the same request, throw an
697+ // error.
698+ THROW_ERR_MODULE_LINK_MISMATCH (
699+ realm->env (),
700+ " Module request '%s' at index %d must be linked "
701+ " to the same module requested at index %d" ,
702+ module_cache_key.ToString (),
703+ i,
704+ first_seen_index);
705+ return ;
706+ }
690707 }
691708 }
692709
@@ -1013,11 +1030,10 @@ void ModuleWrap::HasAsyncGraph(Local<Name> property,
10131030// static
10141031MaybeLocal<Module> ModuleWrap::ResolveModuleCallback (
10151032 Local<Context> context,
1016- Local<String> specifier,
1017- Local<FixedArray> import_attributes,
1033+ size_t module_request_index,
10181034 Local<Module> referrer) {
10191035 ModuleWrap* resolved_module;
1020- if (!ResolveModule (context, specifier, import_attributes , referrer)
1036+ if (!ResolveModule (context, module_request_index , referrer)
10211037 .To (&resolved_module)) {
10221038 return {};
10231039 }
@@ -1028,11 +1044,10 @@ MaybeLocal<Module> ModuleWrap::ResolveModuleCallback(
10281044// static
10291045MaybeLocal<Object> ModuleWrap::ResolveSourceCallback (
10301046 Local<Context> context,
1031- Local<String> specifier,
1032- Local<FixedArray> import_attributes,
1047+ size_t module_request_index,
10331048 Local<Module> referrer) {
10341049 ModuleWrap* resolved_module;
1035- if (!ResolveModule (context, specifier, import_attributes , referrer)
1050+ if (!ResolveModule (context, module_request_index , referrer)
10361051 .To (&resolved_module)) {
10371052 return {};
10381053 }
@@ -1053,12 +1068,22 @@ MaybeLocal<Object> ModuleWrap::ResolveSourceCallback(
10531068 return module_source_object.As <Object>();
10541069}
10551070
1071+ static std::string GetSpecifierFromModuleRequest (Local<Context> context,
1072+ Local<Module> referrer,
1073+ size_t module_request_index) {
1074+ Local<ModuleRequest> raw_request =
1075+ referrer->GetModuleRequests ()
1076+ ->Get (context, static_cast <int >(module_request_index))
1077+ .As <ModuleRequest>();
1078+ Local<String> specifier = raw_request->GetSpecifier ();
1079+ Utf8Value specifier_utf8 (Isolate::GetCurrent (), specifier);
1080+ return specifier_utf8.ToString ();
1081+ }
1082+
10561083// static
1057- Maybe<ModuleWrap*> ModuleWrap::ResolveModule (
1058- Local<Context> context,
1059- Local<String> specifier,
1060- Local<FixedArray> import_attributes,
1061- Local<Module> referrer) {
1084+ Maybe<ModuleWrap*> ModuleWrap::ResolveModule (Local<Context> context,
1085+ size_t module_request_index,
1086+ Local<Module> referrer) {
10621087 Isolate* isolate = Isolate::GetCurrent ();
10631088 Environment* env = Environment::GetCurrent (context);
10641089 if (env == nullptr ) {
@@ -1068,31 +1093,24 @@ Maybe<ModuleWrap*> ModuleWrap::ResolveModule(
10681093 // Check that the referrer is not yet been instantiated.
10691094 DCHECK (referrer->GetStatus () <= Module::kInstantiated );
10701095
1071- ModuleCacheKey cache_key =
1072- ModuleCacheKey::From (context, specifier, import_attributes);
1073-
10741096 ModuleWrap* dependent = ModuleWrap::GetFromModule (env, referrer);
10751097 if (dependent == nullptr ) {
1098+ std::string specifier =
1099+ GetSpecifierFromModuleRequest (context, referrer, module_request_index);
10761100 THROW_ERR_VM_MODULE_LINK_FAILURE (
1077- env, " request for '%s' is from invalid module" , cache_key. specifier );
1101+ env, " request for '%s' is from invalid module" , specifier);
10781102 return Nothing<ModuleWrap*>();
10791103 }
10801104 if (!dependent->IsLinked ()) {
1105+ std::string specifier =
1106+ GetSpecifierFromModuleRequest (context, referrer, module_request_index);
10811107 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 );
1108+ env, " request for '%s' is from a module not been linked" , specifier);
10921109 return Nothing<ModuleWrap*>();
10931110 }
10941111
1095- ModuleWrap* module_wrap = dependent->GetLinkedRequest (it->second );
1112+ ModuleWrap* module_wrap =
1113+ dependent->GetLinkedRequest (static_cast <uint32_t >(module_request_index));
10961114 CHECK_NOT_NULL (module_wrap);
10971115 return Just (module_wrap);
10981116}
0 commit comments