@@ -39,7 +39,10 @@ struct worker_s {
39
39
std::string last_exception;
40
40
Persistent<Function> recv;
41
41
Persistent<Context> context;
42
+ // canonical path -> module
42
43
std::map<std::string, Eternal<Module>> modules;
44
+ // module hash -> specifier -> module
45
+ std::map<int , std::map<std::string, Eternal<Module>>> resolved;
43
46
};
44
47
45
48
// Extracts a C string from a V8 Utf8Value.
@@ -61,6 +64,41 @@ void FatalErrorCallback2(const char* location, const char* message) {
61
64
}
62
65
*/
63
66
67
+ MaybeLocal<Module> ResolveCallback (Local<Context> context,
68
+ Local<String> specifier,
69
+ Local<Module> referrer) {
70
+ auto isolate = Isolate::GetCurrent ();
71
+ worker* w = (worker*)isolate->GetData (0 );
72
+
73
+ HandleScope handle_scope (isolate);
74
+
75
+ String::Utf8Value str (specifier);
76
+ const char * moduleName = *str;
77
+
78
+ if (w->resolved .count (referrer->GetIdentityHash ()) == 0 ) {
79
+ std::string out;
80
+ out.append (" Module (" );
81
+ out.append (moduleName);
82
+ out.append (" ) has not been loaded" );
83
+ out.append (" \n " );
84
+ w->last_exception = out;
85
+ return MaybeLocal<Module>();
86
+ }
87
+
88
+ std::map<std::string, Eternal<Module>> localResolve = w->resolved [referrer->GetIdentityHash ()];
89
+ if (localResolve.count (moduleName) == 0 ) {
90
+ std::string out;
91
+ out.append (" Module (" );
92
+ out.append (moduleName);
93
+ out.append (" ) has not been loaded" );
94
+ out.append (" \n " );
95
+ w->last_exception = out;
96
+ return MaybeLocal<Module>();
97
+ }
98
+
99
+ return localResolve[moduleName].Get (isolate);
100
+ }
101
+
64
102
void ExitOnPromiseRejectCallback (PromiseRejectMessage promise_reject_message) {
65
103
auto isolate = Isolate::GetCurrent ();
66
104
worker* w = (worker*)isolate->GetData (0 );
@@ -93,30 +131,6 @@ void ExitOnPromiseRejectCallback(PromiseRejectMessage promise_reject_message) {
93
131
exit (1 );
94
132
}
95
133
96
- MaybeLocal<Module> ResolveCallback (Local<Context> context,
97
- Local<String> specifier,
98
- Local<Module> referrer) {
99
- auto isolate = Isolate::GetCurrent ();
100
- worker* w = (worker*)isolate->GetData (0 );
101
-
102
- HandleScope handle_scope (isolate);
103
-
104
- String::Utf8Value str (specifier);
105
- const char * moduleName = *str;
106
-
107
- if (w->modules .count (moduleName) == 0 ) {
108
- std::string out;
109
- out.append (" Module (" );
110
- out.append (moduleName);
111
- out.append (" ) has not been loaded" );
112
- out.append (" \n " );
113
- w->last_exception = out;
114
- return MaybeLocal<Module>();
115
- }
116
-
117
- return w->modules [moduleName].Get (isolate);
118
- }
119
-
120
134
// Exception details will be appended to the first argument.
121
135
std::string ExceptionString (worker* w, TryCatch* try_catch) {
122
136
std::string out;
@@ -224,6 +238,12 @@ int worker_load(worker* w, char* name_s, char* source_s) {
224
238
}
225
239
226
240
int worker_load_module (worker* w, char * name_s, char * source_s, int callback_index) {
241
+ // Assuming the script name is canonical, we can return immediately
242
+ // if has already been loaded.
243
+ if (w->modules .count (name_s) != 0 ) {
244
+ return 0 ;
245
+ }
246
+
227
247
Locker locker (w->isolate );
228
248
Isolate::Scope isolate_scope (w->isolate );
229
249
HandleScope handle_scope (w->isolate );
@@ -257,33 +277,42 @@ int worker_load_module(worker* w, char* name_s, char* source_s, int callback_ind
257
277
return 1 ;
258
278
}
259
279
280
+ // Keep track of the canonical names for resolved modules
281
+ std::map<std::string, Eternal<Module>> resolved;
282
+
260
283
for (int i = 0 ; i < module->GetModuleRequestsLength (); i++) {
261
284
Local<String> dependency = module->GetModuleRequest (i);
262
285
String::Utf8Value str (dependency);
263
286
char * dependencySpecifier = *str;
264
287
265
- // If we've already loaded the module, skip resolving it.
266
- // TODO: Is there ever a time when the specifier would be the same
267
- // but would need to be resolved again?
268
- if (w->modules .count (dependencySpecifier) != 0 ) {
269
- continue ;
270
- }
271
-
272
- int ret = ResolveModule (dependencySpecifier, name_s, callback_index);
273
- if (ret != 0 ) {
288
+ struct ResolveModule_return retval = ResolveModule (dependencySpecifier, name_s, callback_index);
289
+ if (retval.r1 != 0 ) {
274
290
// TODO: Use module->GetModuleRequestLocation() to get source locations
275
291
std::string out;
276
292
out.append (" Module (" );
277
293
out.append (dependencySpecifier);
278
294
out.append (" ) has not been loaded" );
279
295
out.append (" \n " );
280
296
w->last_exception = out;
281
- return ret;
297
+ return retval.r1 ;
298
+ }
299
+ // If we were successful in loading that module, it shall be
300
+ // present in the modules table.
301
+ if (w->modules .count (retval.r0 ) == 0 ) {
302
+ std::string out;
303
+ out.append (" Module dependency (" );
304
+ out.append (retval.r0 );
305
+ out.append (" ) has not been loaded" );
306
+ out.append (" \n " );
307
+ w->last_exception = out;
308
+ return 1 ;
282
309
}
310
+ resolved[dependencySpecifier] = w->modules [retval.r0 ];
283
311
}
284
312
285
313
Eternal<Module> persModule (w->isolate , module);
286
314
w->modules [name_s] = persModule;
315
+ w->resolved [module->GetIdentityHash ()] = resolved;
287
316
288
317
Maybe<bool > ok = module->InstantiateModule (context, ResolveCallback);
289
318
0 commit comments