@@ -115,6 +115,140 @@ ModuleCacheKey ModuleCacheKey::From(Local<Context> context,
115
115
context, v8_request->GetSpecifier (), v8_request->GetImportAttributes ());
116
116
}
117
117
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
+
118
252
ModuleWrap::ModuleWrap (Realm* realm,
119
253
Local<Object> object,
120
254
Local<Module> module ,
@@ -133,6 +267,8 @@ ModuleWrap::ModuleWrap(Realm* realm,
133
267
object->SetInternalField (kSyntheticEvaluationStepsSlot ,
134
268
synthetic_evaluation_step);
135
269
object->SetInternalField (kContextObjectSlot , context_object);
270
+ object->SetInternalField (kLinkedRequestsSlot ,
271
+ v8::Undefined (realm->isolate ()));
136
272
137
273
if (!synthetic_evaluation_step->IsUndefined ()) {
138
274
synthetic_ = true ;
@@ -159,6 +295,34 @@ Local<Context> ModuleWrap::context() const {
159
295
return obj.As <Object>()->GetCreationContextChecked ();
160
296
}
161
297
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
+
162
326
ModuleWrap* ModuleWrap::GetFromModule (Environment* env,
163
327
Local<Module> module ) {
164
328
auto range = env->hash_to_module_map .equal_range (module ->GetIdentityHash ());
@@ -571,34 +735,28 @@ void ModuleWrap::GetModuleRequests(const FunctionCallbackInfo<Value>& args) {
571
735
void ModuleWrap::Link (const FunctionCallbackInfo<Value>& args) {
572
736
Realm* realm = Realm::GetCurrent (args);
573
737
Isolate* isolate = args.GetIsolate ();
574
- Local<Context> context = realm->context ();
575
738
576
739
ModuleWrap* dependent;
577
740
ASSIGN_OR_RETURN_UNWRAP (&dependent, args.This ());
578
741
579
742
CHECK_EQ (args.Length (), 1 );
580
743
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
+
581
753
Local<FixedArray> requests =
582
754
dependent->module_ .Get (isolate)->GetModuleRequests ();
583
755
Local<Array> modules = args[0 ].As <Array>();
584
756
CHECK_EQ (modules->Length (), static_cast <uint32_t >(requests->Length ()));
585
757
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 ;
602
760
}
603
761
604
762
void ModuleWrap::Instantiate (const FunctionCallbackInfo<Value>& args) {
@@ -609,11 +767,16 @@ void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
609
767
Local<Context> context = obj->context ();
610
768
Local<Module> module = obj->module_ .Get (isolate);
611
769
TryCatchScope try_catch (realm->env ());
612
- USE (module ->InstantiateModule (
613
- context, ResolveModuleCallback, ResolveSourceCallback));
614
770
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
+ }
617
780
618
781
if (try_catch.HasCaught () && !try_catch.HasTerminated ()) {
619
782
CHECK (!try_catch.Message ().IsEmpty ());
@@ -719,11 +882,16 @@ void ModuleWrap::InstantiateSync(const FunctionCallbackInfo<Value>& args) {
719
882
720
883
{
721
884
TryCatchScope try_catch (env);
722
- USE (module ->InstantiateModule (
723
- context, ResolveModuleCallback, ResolveSourceCallback));
724
885
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
+ }
727
895
728
896
if (try_catch.HasCaught () && !try_catch.HasTerminated ()) {
729
897
CHECK (!try_catch.Message ().IsEmpty ());
@@ -965,98 +1133,6 @@ void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
965
1133
args.GetReturnValue ().Set (module ->GetException ());
966
1134
}
967
1135
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
-
1060
1136
static MaybeLocal<Promise> ImportModuleDynamicallyWithPhase (
1061
1137
Local<Context> context,
1062
1138
Local<Data> host_defined_options,
0 commit comments