@@ -62,6 +62,51 @@ using v8::UnboundModuleScript;
6262using v8::Undefined;
6363using v8::Value;
6464
65+ void ModuleCacheKey::MemoryInfo (MemoryTracker* tracker) const {
66+ tracker->TrackField (" specifier" , specifier);
67+ tracker->TrackField (" import_attributes" , import_attributes);
68+ }
69+
70+ template <int elements_per_attribute>
71+ ModuleCacheKey ModuleCacheKey::From (Local<Context> context,
72+ Local<String> specifier,
73+ Local<FixedArray> import_attributes) {
74+ CHECK_EQ (import_attributes->Length () % elements_per_attribute, 0 );
75+ Isolate* isolate = context->GetIsolate ();
76+ std::size_t h1 = specifier->GetIdentityHash ();
77+ size_t num_attributes = import_attributes->Length () / elements_per_attribute;
78+ ImportAttributeVector attributes;
79+ attributes.reserve (num_attributes);
80+
81+ std::size_t h2 = 0 ;
82+
83+ for (int i = 0 ; i < import_attributes->Length ();
84+ i += elements_per_attribute) {
85+ Local<String> v8_key = import_attributes->Get (context, i).As <String>();
86+ Local<String> v8_value =
87+ import_attributes->Get (context, i + 1 ).As <String>();
88+ Utf8Value key_utf8 (isolate, v8_key);
89+ Utf8Value value_utf8 (isolate, v8_value);
90+
91+ attributes.emplace_back (key_utf8.ToString (), value_utf8.ToString ());
92+ h2 ^= v8_key->GetIdentityHash ();
93+ h2 ^= v8_value->GetIdentityHash ();
94+ }
95+
96+ // Combine the hashes using a simple XOR and bit shift to reduce
97+ // collisions. Note that the hash does not guarantee uniqueness.
98+ std::size_t hash = h1 ^ (h2 << 1 );
99+
100+ Utf8Value utf8_specifier (isolate, specifier);
101+ return ModuleCacheKey{utf8_specifier.ToString (), attributes, hash};
102+ }
103+
104+ ModuleCacheKey ModuleCacheKey::From (Local<Context> context,
105+ Local<ModuleRequest> v8_request) {
106+ return From (
107+ context, v8_request->GetSpecifier (), v8_request->GetImportAttributes ());
108+ }
109+
65110ModuleWrap::ModuleWrap (Realm* realm,
66111 Local<Object> object,
67112 Local<Module> module ,
@@ -493,7 +538,7 @@ void ModuleWrap::GetModuleRequests(const FunctionCallbackInfo<Value>& args) {
493538 realm, isolate, module ->GetModuleRequests ()));
494539}
495540
496- // moduleWrap.link(specifiers, moduleWraps)
541+ // moduleWrap.link(moduleWraps)
497542void ModuleWrap::Link (const FunctionCallbackInfo<Value>& args) {
498543 Realm* realm = Realm::GetCurrent (args);
499544 Isolate* isolate = args.GetIsolate ();
@@ -502,33 +547,28 @@ void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
502547 ModuleWrap* dependent;
503548 ASSIGN_OR_RETURN_UNWRAP (&dependent, args.This ());
504549
505- CHECK_EQ (args.Length (), 2 );
550+ CHECK_EQ (args.Length (), 1 );
506551
507- Local<Array> specifiers = args[0 ].As <Array>();
508- Local<Array> modules = args[1 ].As <Array>();
509- CHECK_EQ (specifiers->Length (), modules->Length ());
552+ Local<FixedArray> requests =
553+ dependent->module_ .Get (isolate)->GetModuleRequests ();
554+ Local<Array> modules = args[0 ].As <Array>();
555+ CHECK_EQ (modules->Length (), static_cast <uint32_t >(requests->Length ()));
510556
511- std::vector<Global<Value>> specifiers_buffer;
512- if (FromV8Array (context, specifiers, &specifiers_buffer).IsNothing ()) {
513- return ;
514- }
515557 std::vector<Global<Value>> modules_buffer;
516558 if (FromV8Array (context, modules, &modules_buffer).IsNothing ()) {
517559 return ;
518560 }
519561
520- for (uint32_t i = 0 ; i < specifiers->Length (); i++) {
521- Local<String> specifier_str =
522- specifiers_buffer[i].Get (isolate).As <String>();
562+ for (uint32_t i = 0 ; i < modules_buffer.size (); i++) {
523563 Local<Object> module_object = modules_buffer[i].Get (isolate).As <Object>();
524564
525565 CHECK (
526566 realm->isolate_data ()->module_wrap_constructor_template ()->HasInstance (
527567 module_object));
528568
529- Utf8Value specifier (isolate, specifier_str);
530- dependent-> resolve_cache_ [specifier. ToString ()]. Reset (isolate,
531- module_object);
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);
532572 }
533573}
534574
@@ -872,27 +912,27 @@ MaybeLocal<Module> ModuleWrap::ResolveModuleCallback(
872912 return MaybeLocal<Module>();
873913 }
874914
875- Utf8Value specifier_utf8 (isolate, specifier);
876- std::string specifier_std (*specifier_utf8, specifier_utf8. length () );
915+ ModuleCacheKey cache_key =
916+ ModuleCacheKey::From (context, specifier, import_attributes );
877917
878918 ModuleWrap* dependent = GetFromModule (env, referrer);
879919 if (dependent == nullptr ) {
880920 THROW_ERR_VM_MODULE_LINK_FAILURE (
881- env, " request for '%s' is from invalid module" , specifier_std );
921+ env, " request for '%s' is from invalid module" , cache_key. specifier );
882922 return MaybeLocal<Module>();
883923 }
884924
885- if (dependent->resolve_cache_ .count (specifier_std ) != 1 ) {
925+ if (dependent->resolve_cache_ .count (cache_key ) != 1 ) {
886926 THROW_ERR_VM_MODULE_LINK_FAILURE (
887- env, " request for '%s' is not in cache" , specifier_std );
927+ env, " request for '%s' is not in cache" , cache_key. specifier );
888928 return MaybeLocal<Module>();
889929 }
890930
891931 Local<Object> module_object =
892- dependent->resolve_cache_ [specifier_std ].Get (isolate);
932+ dependent->resolve_cache_ [cache_key ].Get (isolate);
893933 if (module_object.IsEmpty () || !module_object->IsObject ()) {
894934 THROW_ERR_VM_MODULE_LINK_FAILURE (
895- env, " request for '%s' did not return an object" , specifier_std );
935+ env, " request for '%s' did not return an object" , cache_key. specifier );
896936 return MaybeLocal<Module>();
897937 }
898938
0 commit comments