@@ -115,6 +115,140 @@ ModuleCacheKey ModuleCacheKey::From(Local<Context> context,
115115 context, v8_request->GetSpecifier (), v8_request->GetImportAttributes ());
116116}
117117
118+ // static
119+ thread_local ModuleInstantiationContext*
120+ ModuleInstantiationContext::thread_local_context_;
121+
122+ // static
123+ MaybeLocal<Module> ModuleInstantiationContext::ResolveModuleCallback (
124+ Local<Context> context,
125+ Local<String> specifier,
126+ Local<FixedArray> import_attributes,
127+ Local<Module> referrer) {
128+ CHECK_NOT_NULL (thread_local_context_);
129+ ModuleWrap* resolved_module;
130+ if (!thread_local_context_
131+ ->ResolveModule (context, specifier, import_attributes, referrer)
132+ .To (&resolved_module)) {
133+ return {};
134+ }
135+ DCHECK_NOT_NULL (resolved_module);
136+ return resolved_module->module ();
137+ }
138+
139+ // static
140+ MaybeLocal<Object> ModuleInstantiationContext::ResolveSourceCallback (
141+ Local<Context> context,
142+ Local<String> specifier,
143+ Local<FixedArray> import_attributes,
144+ Local<Module> referrer) {
145+ CHECK_NOT_NULL (thread_local_context_);
146+ ModuleWrap* resolved_module;
147+ if (!thread_local_context_
148+ ->ResolveModule (context, specifier, import_attributes, referrer)
149+ .To (&resolved_module)) {
150+ return {};
151+ }
152+ DCHECK_NOT_NULL (resolved_module);
153+
154+ Local<Value> module_source_object =
155+ resolved_module->object ()
156+ ->GetInternalField (ModuleWrap::kModuleSourceObjectSlot )
157+ .As <Value>();
158+ if (module_source_object->IsUndefined ()) {
159+ Local<String> url = resolved_module->object ()
160+ ->GetInternalField (ModuleWrap::kURLSlot )
161+ .As <String>();
162+ THROW_ERR_SOURCE_PHASE_NOT_DEFINED (context->GetIsolate (), url);
163+ return {};
164+ }
165+ CHECK (module_source_object->IsObject ());
166+ return module_source_object.As <Object>();
167+ }
168+
169+ ModuleInstantiationContext::ModuleInstantiationContext () {
170+ // Only one ModuleInstantiationContext can exist per thread at a time.
171+ CHECK_NULL (thread_local_context_);
172+ thread_local_context_ = this ;
173+ }
174+
175+ ModuleInstantiationContext::~ModuleInstantiationContext () {
176+ // Ensure that the thread-local context is this context.
177+ CHECK_EQ (thread_local_context_, this );
178+ thread_local_context_ = nullptr ;
179+ }
180+
181+ Maybe<ModuleWrap*> ModuleInstantiationContext::ResolveModule (
182+ Local<Context> context,
183+ Local<String> specifier,
184+ Local<FixedArray> import_attributes,
185+ Local<Module> referrer) {
186+ Isolate* isolate = context->GetIsolate ();
187+ Environment* env = Environment::GetCurrent (context);
188+ if (env == nullptr ) {
189+ THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE (isolate);
190+ return Nothing<ModuleWrap*>();
191+ }
192+ // Check that the referrer is not yet been instantiated.
193+ DCHECK (referrer->GetStatus () <= Module::kInstantiated );
194+
195+ ModuleCacheKey cache_key =
196+ ModuleCacheKey::From (context, specifier, import_attributes);
197+
198+ ModuleWrap* dependent = ModuleWrap::GetFromModule (env, referrer);
199+ if (dependent == nullptr ) {
200+ THROW_ERR_VM_MODULE_LINK_FAILURE (
201+ env, " request for '%s' is from invalid module" , cache_key.specifier );
202+ return Nothing<ModuleWrap*>();
203+ }
204+ if (!dependent->IsLinked ()) {
205+ THROW_ERR_VM_MODULE_LINK_FAILURE (
206+ env,
207+ " request for '%s' is from a module not been linked" ,
208+ cache_key.specifier );
209+ return Nothing<ModuleWrap*>();
210+ }
211+
212+ ResolveCache& resolve_cache = GetModuleResolveCache (env, dependent);
213+ if (resolve_cache.count (cache_key) != 1 ) {
214+ THROW_ERR_VM_MODULE_LINK_FAILURE (
215+ env, " request for '%s' is not in cache" , cache_key.specifier );
216+ return Nothing<ModuleWrap*>();
217+ }
218+
219+ ModuleWrap* module_wrap =
220+ dependent->GetLinkedRequest (resolve_cache[cache_key]);
221+ CHECK_NOT_NULL (module_wrap);
222+ return Just (module_wrap);
223+ }
224+
225+ ModuleInstantiationContext::ResolveCache&
226+ ModuleInstantiationContext::GetModuleResolveCache (Environment* env,
227+ ModuleWrap* module_wrap) {
228+ CHECK (module_wrap->IsLinked ());
229+
230+ auto it = module_instance_graph_.find (module_wrap);
231+ if (it != module_instance_graph_.end ()) {
232+ return it->second ;
233+ }
234+
235+ Isolate* isolate = env->isolate ();
236+ HandleScope scope (isolate);
237+ Local<Context> context = env->context ();
238+
239+ Local<FixedArray> requests = module_wrap->module ()->GetModuleRequests ();
240+
241+ ResolveCache& resolve_cache = module_instance_graph_[module_wrap];
242+
243+ for (int i = 0 ; i < requests->Length (); i++) {
244+ ModuleCacheKey module_cache_key = ModuleCacheKey::From (
245+ context, requests->Get (context, i).As <ModuleRequest>());
246+ resolve_cache[module_cache_key] = i;
247+ }
248+
249+ return resolve_cache;
250+ }
251+
118252ModuleWrap::ModuleWrap (Realm* realm,
119253 Local<Object> object,
120254 Local<Module> module ,
@@ -133,6 +267,8 @@ ModuleWrap::ModuleWrap(Realm* realm,
133267 object->SetInternalField (kSyntheticEvaluationStepsSlot ,
134268 synthetic_evaluation_step);
135269 object->SetInternalField (kContextObjectSlot , context_object);
270+ object->SetInternalField (kLinkedRequestsSlot ,
271+ v8::Undefined (realm->isolate ()));
136272
137273 if (!synthetic_evaluation_step->IsUndefined ()) {
138274 synthetic_ = true ;
@@ -159,6 +295,34 @@ Local<Context> ModuleWrap::context() const {
159295 return obj.As <Object>()->GetCreationContextChecked ();
160296}
161297
298+ Local<Module> ModuleWrap::module () {
299+ return module_.Get (env ()->isolate ());
300+ }
301+
302+ ModuleWrap* ModuleWrap::GetLinkedRequest (uint32_t index) {
303+ DCHECK (IsLinked ());
304+ Isolate* isolate = env ()->isolate ();
305+ EscapableHandleScope scope (isolate);
306+ Local<Data> linked_requests_data =
307+ object ()->GetInternalField (kLinkedRequestsSlot );
308+ DCHECK (linked_requests_data->IsValue () &&
309+ linked_requests_data.As <Value>()->IsArray ());
310+ Local<Array> requests = linked_requests_data.As <Array>();
311+
312+ CHECK_LT (index, requests->Length ());
313+
314+ Local<Value> module_value;
315+ if (!requests->Get (context (), index).ToLocal (&module_value)) {
316+ return nullptr ;
317+ }
318+ CHECK (module_value->IsObject ());
319+ Local<Object> module_object = module_value.As <Object>();
320+
321+ ModuleWrap* module_wrap;
322+ ASSIGN_OR_RETURN_UNWRAP (&module_wrap, module_object, nullptr );
323+ return module_wrap;
324+ }
325+
162326ModuleWrap* ModuleWrap::GetFromModule (Environment* env,
163327 Local<Module> module ) {
164328 auto range = env->hash_to_module_map .equal_range (module ->GetIdentityHash ());
@@ -571,34 +735,28 @@ void ModuleWrap::GetModuleRequests(const FunctionCallbackInfo<Value>& args) {
571735void ModuleWrap::Link (const FunctionCallbackInfo<Value>& args) {
572736 Realm* realm = Realm::GetCurrent (args);
573737 Isolate* isolate = args.GetIsolate ();
574- Local<Context> context = realm->context ();
575738
576739 ModuleWrap* dependent;
577740 ASSIGN_OR_RETURN_UNWRAP (&dependent, args.This ());
578741
579742 CHECK_EQ (args.Length (), 1 );
580743
744+ Local<Data> linked_requests =
745+ args.This ()->GetInternalField (kLinkedRequestsSlot );
746+ if (linked_requests->IsValue () &&
747+ !linked_requests.As <Value>()->IsUndefined ()) {
748+ // If the module is already linked, we should not link it again.
749+ THROW_ERR_VM_MODULE_LINK_FAILURE (realm->env (), " module is already linked" );
750+ return ;
751+ }
752+
581753 Local<FixedArray> requests =
582754 dependent->module_ .Get (isolate)->GetModuleRequests ();
583755 Local<Array> modules = args[0 ].As <Array>();
584756 CHECK_EQ (modules->Length (), static_cast <uint32_t >(requests->Length ()));
585757
586- std::vector<Global<Value>> modules_buffer;
587- if (FromV8Array (context, modules, &modules_buffer).IsNothing ()) {
588- return ;
589- }
590-
591- for (uint32_t i = 0 ; i < modules_buffer.size (); i++) {
592- Local<Object> module_object = modules_buffer[i].Get (isolate).As <Object>();
593-
594- CHECK (
595- realm->isolate_data ()->module_wrap_constructor_template ()->HasInstance (
596- module_object));
597-
598- ModuleCacheKey module_cache_key = ModuleCacheKey::From (
599- context, requests->Get (context, i).As <ModuleRequest>());
600- dependent->resolve_cache_ [module_cache_key].Reset (isolate, module_object);
601- }
758+ args.This ()->SetInternalField (kLinkedRequestsSlot , modules);
759+ dependent->linked_ = true ;
602760}
603761
604762void ModuleWrap::Instantiate (const FunctionCallbackInfo<Value>& args) {
@@ -609,11 +767,16 @@ void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
609767 Local<Context> context = obj->context ();
610768 Local<Module> module = obj->module_ .Get (isolate);
611769 TryCatchScope try_catch (realm->env ());
612- USE (module ->InstantiateModule (
613- context, ResolveModuleCallback, ResolveSourceCallback));
614770
615- // clear resolve cache on instantiate
616- obj->resolve_cache_ .clear ();
771+ {
772+ ModuleInstantiationContext instantiation_context;
773+ USE (module ->InstantiateModule (
774+ context,
775+ ModuleInstantiationContext::ResolveModuleCallback,
776+ ModuleInstantiationContext::ResolveSourceCallback));
777+
778+ // instantiation_context goes out of scope.
779+ }
617780
618781 if (try_catch.HasCaught () && !try_catch.HasTerminated ()) {
619782 CHECK (!try_catch.Message ().IsEmpty ());
@@ -719,11 +882,16 @@ void ModuleWrap::InstantiateSync(const FunctionCallbackInfo<Value>& args) {
719882
720883 {
721884 TryCatchScope try_catch (env);
722- USE (module ->InstantiateModule (
723- context, ResolveModuleCallback, ResolveSourceCallback));
724885
725- // clear resolve cache on instantiate
726- obj->resolve_cache_ .clear ();
886+ {
887+ ModuleInstantiationContext instantiation_context;
888+ USE (module ->InstantiateModule (
889+ context,
890+ ModuleInstantiationContext::ResolveModuleCallback,
891+ ModuleInstantiationContext::ResolveSourceCallback));
892+
893+ // instantiation_context goes out of scope.
894+ }
727895
728896 if (try_catch.HasCaught () && !try_catch.HasTerminated ()) {
729897 CHECK (!try_catch.Message ().IsEmpty ());
@@ -965,98 +1133,6 @@ void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
9651133 args.GetReturnValue ().Set (module ->GetException ());
9661134}
9671135
968- MaybeLocal<Module> ModuleWrap::ResolveModuleCallback (
969- Local<Context> context,
970- Local<String> specifier,
971- Local<FixedArray> import_attributes,
972- Local<Module> referrer) {
973- Isolate* isolate = context->GetIsolate ();
974- Environment* env = Environment::GetCurrent (context);
975- if (env == nullptr ) {
976- THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE (isolate);
977- return MaybeLocal<Module>();
978- }
979-
980- ModuleCacheKey cache_key =
981- ModuleCacheKey::From (context, specifier, import_attributes);
982-
983- ModuleWrap* dependent = GetFromModule (env, referrer);
984- if (dependent == nullptr ) {
985- THROW_ERR_VM_MODULE_LINK_FAILURE (
986- env, " request for '%s' is from invalid module" , cache_key.specifier );
987- return MaybeLocal<Module>();
988- }
989-
990- if (dependent->resolve_cache_ .count (cache_key) != 1 ) {
991- THROW_ERR_VM_MODULE_LINK_FAILURE (
992- env, " request for '%s' is not in cache" , cache_key.specifier );
993- return MaybeLocal<Module>();
994- }
995-
996- Local<Object> module_object =
997- dependent->resolve_cache_ [cache_key].Get (isolate);
998- if (module_object.IsEmpty () || !module_object->IsObject ()) {
999- THROW_ERR_VM_MODULE_LINK_FAILURE (
1000- env, " request for '%s' did not return an object" , cache_key.specifier );
1001- return MaybeLocal<Module>();
1002- }
1003-
1004- ModuleWrap* module ;
1005- ASSIGN_OR_RETURN_UNWRAP (&module , module_object, MaybeLocal<Module>());
1006- return module ->module_ .Get (isolate);
1007- }
1008-
1009- MaybeLocal<Object> ModuleWrap::ResolveSourceCallback (
1010- Local<Context> context,
1011- Local<String> specifier,
1012- Local<FixedArray> import_attributes,
1013- Local<Module> referrer) {
1014- Isolate* isolate = context->GetIsolate ();
1015- Environment* env = Environment::GetCurrent (context);
1016- if (env == nullptr ) {
1017- THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE (isolate);
1018- return MaybeLocal<Object>();
1019- }
1020-
1021- ModuleCacheKey cache_key =
1022- ModuleCacheKey::From (context, specifier, import_attributes);
1023-
1024- ModuleWrap* dependent = GetFromModule (env, referrer);
1025- if (dependent == nullptr ) {
1026- THROW_ERR_VM_MODULE_LINK_FAILURE (
1027- env, " request for '%s' is from invalid module" , cache_key.specifier );
1028- return MaybeLocal<Object>();
1029- }
1030-
1031- if (dependent->resolve_cache_ .count (cache_key) != 1 ) {
1032- THROW_ERR_VM_MODULE_LINK_FAILURE (
1033- env, " request for '%s' is not in cache" , cache_key.specifier );
1034- return MaybeLocal<Object>();
1035- }
1036-
1037- Local<Object> module_object =
1038- dependent->resolve_cache_ [cache_key].Get (isolate);
1039- if (module_object.IsEmpty () || !module_object->IsObject ()) {
1040- THROW_ERR_VM_MODULE_LINK_FAILURE (
1041- env, " request for '%s' did not return an object" , cache_key.specifier );
1042- return MaybeLocal<Object>();
1043- }
1044-
1045- ModuleWrap* module ;
1046- ASSIGN_OR_RETURN_UNWRAP (&module , module_object, MaybeLocal<Object>());
1047-
1048- Local<Value> module_source_object =
1049- module ->object ()->GetInternalField (kModuleSourceObjectSlot ).As <Value>();
1050- if (module_source_object->IsUndefined ()) {
1051- Local<String> url =
1052- module ->object ()->GetInternalField (kURLSlot ).As <String>();
1053- THROW_ERR_SOURCE_PHASE_NOT_DEFINED (isolate, url);
1054- return MaybeLocal<Object>();
1055- }
1056- CHECK (module_source_object->IsObject ());
1057- return module_source_object.As <Object>();
1058- }
1059-
10601136static MaybeLocal<Promise> ImportModuleDynamicallyWithPhase (
10611137 Local<Context> context,
10621138 Local<Data> host_defined_options,
0 commit comments