@@ -63,6 +63,51 @@ using v8::UnboundModuleScript;
6363using v8::Undefined;
6464using v8::Value;
6565
66+ void ModuleCacheKey::MemoryInfo (MemoryTracker* tracker) const {
67+ tracker->TrackField (" specifier" , specifier);
68+ tracker->TrackField (" import_attributes" , import_attributes);
69+ }
70+
71+ template <int elements_per_attribute>
72+ ModuleCacheKey ModuleCacheKey::From (Local<Context> context,
73+ Local<String> specifier,
74+ Local<FixedArray> import_attributes) {
75+ CHECK_EQ (import_attributes->Length () % elements_per_attribute, 0 );
76+ Isolate* isolate = context->GetIsolate ();
77+ std::size_t h1 = specifier->GetIdentityHash ();
78+ size_t num_attributes = import_attributes->Length () / elements_per_attribute;
79+ ImportAttributeVector attributes;
80+ attributes.reserve (num_attributes);
81+
82+ std::size_t h2 = 0 ;
83+
84+ for (int i = 0 ; i < import_attributes->Length ();
85+ i += elements_per_attribute) {
86+ Local<String> v8_key = import_attributes->Get (context, i).As <String>();
87+ Local<String> v8_value =
88+ import_attributes->Get (context, i + 1 ).As <String>();
89+ Utf8Value key_utf8 (isolate, v8_key);
90+ Utf8Value value_utf8 (isolate, v8_value);
91+
92+ attributes.emplace_back (key_utf8.ToString (), value_utf8.ToString ());
93+ h2 ^= v8_key->GetIdentityHash ();
94+ h2 ^= v8_value->GetIdentityHash ();
95+ }
96+
97+ // Combine the hashes using a simple XOR and bit shift to reduce
98+ // collisions. Note that the hash does not guarantee uniqueness.
99+ std::size_t hash = h1 ^ (h2 << 1 );
100+
101+ Utf8Value utf8_specifier (isolate, specifier);
102+ return ModuleCacheKey{utf8_specifier.ToString (), attributes, hash};
103+ }
104+
105+ ModuleCacheKey ModuleCacheKey::From (Local<Context> context,
106+ Local<ModuleRequest> v8_request) {
107+ return From (
108+ context, v8_request->GetSpecifier (), v8_request->GetImportAttributes ());
109+ }
110+
66111ModuleWrap::ModuleWrap (Realm* realm,
67112 Local<Object> object,
68113 Local<Module> module ,
@@ -509,7 +554,7 @@ void ModuleWrap::GetModuleRequests(const FunctionCallbackInfo<Value>& args) {
509554 realm, isolate, module ->GetModuleRequests ()));
510555}
511556
512- // moduleWrap.link(specifiers, moduleWraps)
557+ // moduleWrap.link(moduleWraps)
513558void ModuleWrap::Link (const FunctionCallbackInfo<Value>& args) {
514559 Realm* realm = Realm::GetCurrent (args);
515560 Isolate* isolate = args.GetIsolate ();
@@ -518,33 +563,28 @@ void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
518563 ModuleWrap* dependent;
519564 ASSIGN_OR_RETURN_UNWRAP (&dependent, args.This ());
520565
521- CHECK_EQ (args.Length (), 2 );
566+ CHECK_EQ (args.Length (), 1 );
522567
523- Local<Array> specifiers = args[0 ].As <Array>();
524- Local<Array> modules = args[1 ].As <Array>();
525- CHECK_EQ (specifiers->Length (), modules->Length ());
568+ Local<FixedArray> requests =
569+ dependent->module_ .Get (isolate)->GetModuleRequests ();
570+ Local<Array> modules = args[0 ].As <Array>();
571+ CHECK_EQ (modules->Length (), static_cast <uint32_t >(requests->Length ()));
526572
527- std::vector<Global<Value>> specifiers_buffer;
528- if (FromV8Array (context, specifiers, &specifiers_buffer).IsNothing ()) {
529- return ;
530- }
531573 std::vector<Global<Value>> modules_buffer;
532574 if (FromV8Array (context, modules, &modules_buffer).IsNothing ()) {
533575 return ;
534576 }
535577
536- for (uint32_t i = 0 ; i < specifiers->Length (); i++) {
537- Local<String> specifier_str =
538- specifiers_buffer[i].Get (isolate).As <String>();
578+ for (uint32_t i = 0 ; i < modules_buffer.size (); i++) {
539579 Local<Object> module_object = modules_buffer[i].Get (isolate).As <Object>();
540580
541581 CHECK (
542582 realm->isolate_data ()->module_wrap_constructor_template ()->HasInstance (
543583 module_object));
544584
545- Utf8Value specifier (isolate, specifier_str);
546- dependent-> resolve_cache_ [specifier. ToString ()]. Reset (isolate,
547- module_object);
585+ ModuleCacheKey module_cache_key = ModuleCacheKey::From (
586+ context, requests-> Get (context, i). As <ModuleRequest>());
587+ dependent-> resolve_cache_ [module_cache_key]. Reset (isolate, module_object);
548588 }
549589}
550590
@@ -924,27 +964,27 @@ MaybeLocal<Module> ModuleWrap::ResolveModuleCallback(
924964 return MaybeLocal<Module>();
925965 }
926966
927- Utf8Value specifier_utf8 (isolate, specifier);
928- std::string specifier_std (*specifier_utf8, specifier_utf8. length () );
967+ ModuleCacheKey cache_key =
968+ ModuleCacheKey::From (context, specifier, import_attributes );
929969
930970 ModuleWrap* dependent = GetFromModule (env, referrer);
931971 if (dependent == nullptr ) {
932972 THROW_ERR_VM_MODULE_LINK_FAILURE (
933- env, " request for '%s' is from invalid module" , specifier_std );
973+ env, " request for '%s' is from invalid module" , cache_key. specifier );
934974 return MaybeLocal<Module>();
935975 }
936976
937- if (dependent->resolve_cache_ .count (specifier_std ) != 1 ) {
977+ if (dependent->resolve_cache_ .count (cache_key ) != 1 ) {
938978 THROW_ERR_VM_MODULE_LINK_FAILURE (
939- env, " request for '%s' is not in cache" , specifier_std );
979+ env, " request for '%s' is not in cache" , cache_key. specifier );
940980 return MaybeLocal<Module>();
941981 }
942982
943983 Local<Object> module_object =
944- dependent->resolve_cache_ [specifier_std ].Get (isolate);
984+ dependent->resolve_cache_ [cache_key ].Get (isolate);
945985 if (module_object.IsEmpty () || !module_object->IsObject ()) {
946986 THROW_ERR_VM_MODULE_LINK_FAILURE (
947- env, " request for '%s' did not return an object" , specifier_std );
987+ env, " request for '%s' did not return an object" , cache_key. specifier );
948988 return MaybeLocal<Module>();
949989 }
950990
@@ -965,27 +1005,27 @@ MaybeLocal<Object> ModuleWrap::ResolveSourceCallback(
9651005 return MaybeLocal<Object>();
9661006 }
9671007
968- Utf8Value specifier_utf8 (isolate, specifier);
969- std::string specifier_std (*specifier_utf8, specifier_utf8. length () );
1008+ ModuleCacheKey cache_key =
1009+ ModuleCacheKey::From (context, specifier, import_attributes );
9701010
9711011 ModuleWrap* dependent = GetFromModule (env, referrer);
9721012 if (dependent == nullptr ) {
9731013 THROW_ERR_VM_MODULE_LINK_FAILURE (
974- env, " request for '%s' is from invalid module" , specifier_std );
1014+ env, " request for '%s' is from invalid module" , cache_key. specifier );
9751015 return MaybeLocal<Object>();
9761016 }
9771017
978- if (dependent->resolve_cache_ .count (specifier_std ) != 1 ) {
1018+ if (dependent->resolve_cache_ .count (cache_key ) != 1 ) {
9791019 THROW_ERR_VM_MODULE_LINK_FAILURE (
980- env, " request for '%s' is not in cache" , specifier_std );
1020+ env, " request for '%s' is not in cache" , cache_key. specifier );
9811021 return MaybeLocal<Object>();
9821022 }
9831023
9841024 Local<Object> module_object =
985- dependent->resolve_cache_ [specifier_std ].Get (isolate);
1025+ dependent->resolve_cache_ [cache_key ].Get (isolate);
9861026 if (module_object.IsEmpty () || !module_object->IsObject ()) {
9871027 THROW_ERR_VM_MODULE_LINK_FAILURE (
988- env, " request for '%s' did not return an object" , specifier_std );
1028+ env, " request for '%s' did not return an object" , cache_key. specifier );
9891029 return MaybeLocal<Object>();
9901030 }
9911031
0 commit comments