44#include < cstdio>
55#include < js/CompilationAndEvaluation.h>
66#include < js/MapAndSet.h>
7+ #include < js/ScriptPrivate.h>
78#include < js/Value.h>
89#include < jsfriendapi.h>
910#include < sys/stat.h>
1011
1112namespace {
1213
13- api::Engine* ENGINE;
14- ScriptLoader* SCRIPT_LOADER;
14+ api::Engine * ENGINE;
15+ ScriptLoader * SCRIPT_LOADER;
1516bool MODULE_MODE = true ;
1617std::string BASE_PATH;
1718
@@ -29,16 +30,14 @@ namespace ScriptLoaderErrors {
2930DEF_ERR (ModuleLoadingError, JSEXN_REFERENCEERR,
3031 " Error loading module \" {0}\" (resolved path \" {1}\" ): {2}" , 3 )
3132DEF_ERR (BuiltinModuleExists, JSEXN_TYPEERR, " Builtin module \" {0}\" already exists" , 1 )
32- };
33+ }; // namespace ScriptLoaderErrors
3334
3435class AutoCloseFile {
35- FILE* file;
36+ FILE * file;
3637
3738public:
3839 explicit AutoCloseFile (FILE *f) : file(f) {}
39- ~AutoCloseFile () {
40- release ();
41- }
40+ ~AutoCloseFile () { release (); }
4241
4342 AutoCloseFile (const AutoCloseFile &) = default ;
4443 AutoCloseFile (AutoCloseFile &&) = delete ;
@@ -65,7 +64,7 @@ static std::string strip_prefix(std::string_view resolved_path,
6564 return std::string (resolved_path);
6665 }
6766
68- const auto & base = *path_prefix;
67+ const auto & base = *path_prefix;
6968 if (!resolved_path.starts_with (base)) {
7069 return std::string (resolved_path);
7170 }
@@ -75,14 +74,12 @@ static std::string strip_prefix(std::string_view resolved_path,
7574
7675struct stat s;
7776
78-
7977static std::string resolve_extension (std::string resolved_path) {
8078 if (stat (resolved_path.c_str (), &s) == 0 ) {
8179 return resolved_path;
8280 }
8381
84- if (resolved_path.size () >= 3 &&
85- resolved_path.compare (resolved_path.size () - 3 , 3 , " .js" ) == 0 ) {
82+ if (resolved_path.size () >= 3 && resolved_path.compare (resolved_path.size () - 3 , 3 , " .js" ) == 0 ) {
8683 return resolved_path;
8784 }
8885
@@ -159,7 +156,7 @@ static std::string resolve_path(std::string_view path, std::string_view base) {
159156 return resolve_extension (std::move (resolved_path));
160157}
161158
162- static JSObject* get_module (JSContext* cx, JS::SourceText<mozilla::Utf8Unit> &source,
159+ static JSObject * get_module (JSContext * cx, JS::SourceText<mozilla::Utf8Unit> &source,
163160 std::string_view resolved_path, const JS::CompileOptions &opts) {
164161 RootedObject module (cx, JS::CompileModule (cx, opts, source));
165162 if (!module ) {
@@ -216,7 +213,7 @@ static JSObject *get_module(JSContext *cx, std::string_view specifier,
216213 return get_module (cx, source, resolved_path, opts);
217214}
218215
219- static JSObject* get_builtin_module (JSContext* cx, HandleValue id, HandleObject builtin) {
216+ static JSObject * get_builtin_module (JSContext * cx, HandleValue id, HandleObject builtin) {
220217 RootedValue module_val (cx);
221218 MOZ_ASSERT (id.isString ());
222219 if (!JS::MapGet (cx, moduleRegistry, id, &module_val)) {
@@ -238,7 +235,7 @@ static JSObject* get_builtin_module(JSContext* cx, HandleValue id, HandleObject
238235 bool firstValue = true ;
239236 for (size_t i = 0 ; i < length; ++i) {
240237 if (firstValue) {
241- firstValue = false ;
238+ firstValue = false ;
242239 } else {
243240 code += " , " ;
244241 }
@@ -262,14 +259,14 @@ static JSObject* get_builtin_module(JSContext* cx, HandleValue id, HandleObject
262259 firstValue = true ;
263260 for (size_t i = 0 ; i < length; ++i) {
264261 if (firstValue) {
265- firstValue = false ;
262+ firstValue = false ;
266263 } else {
267264 code += " , " ;
268265 }
269266
270267 code += " e" ;
271268 code += std::to_string (i);
272-
269+
273270 code += " as '" ;
274271 const auto &prop = props[i];
275272 JS::RootedValue key (cx, js::IdToValue (prop));
@@ -310,36 +307,52 @@ static JSObject* get_builtin_module(JSContext* cx, HandleValue id, HandleObject
310307 return module ;
311308}
312309
313- JSObject* module_resolve_hook (JSContext* cx, HandleValue referencingPrivate,
314- HandleObject moduleRequest) {
315- RootedString specifier (cx, GetModuleRequestSpecifier (cx, moduleRequest));
310+ bool module_load_hook (JSContext *cx, JS::HandleScript referrer, JS::HandleObject module_reques,
311+ JS::HandleValue hostDefined, JS::HandleValue payload, uint32_t lineNumber,
312+ JS::ColumnNumberOneOrigin columnNumber) {
313+ RootedString specifier (cx, GetModuleRequestSpecifier (cx, module_reques));
316314 if (!specifier) {
317- return nullptr ;
315+ return false ;
318316 }
319317
320318 RootedValue path_val (cx, StringValue (specifier));
321319 auto path = JS_EncodeStringToUTF8 (cx, specifier);
322320 if (!path) {
323- return nullptr ;
321+ return false ;
324322 }
325323
326324 RootedValue builtin_val (cx);
327325 if (!MapGet (cx, builtinModules, path_val, &builtin_val)) {
328- return nullptr ;
326+ return false ;
329327 }
330328 if (!builtin_val.isUndefined ()) {
331329 RootedValue specifier_val (cx, StringValue (specifier));
332330 RootedObject builtin_obj (cx, &builtin_val.toObject ());
333- return get_builtin_module (cx, specifier_val, builtin_obj);
331+ RootedObject result (cx, get_builtin_module (cx, specifier_val, builtin_obj));
332+ if (!result) {
333+ return false ;
334+ }
335+ return FinishLoadingImportedModule (cx, referrer, module_reques, payload, result, false );
336+ }
337+
338+ RootedValue ref_priv (cx);
339+ if (referrer) {
340+ ref_priv = JS::GetScriptPrivate (referrer);
334341 }
335342
336- RootedObject info (cx, &referencingPrivate.toObject ());
343+ if (ref_priv.isUndefined () || !ref_priv.isObject ()) {
344+ JS_ReportErrorASCII (cx, " Module referrer has no private value" );
345+ return false ;
346+ }
347+
348+ RootedObject info (cx, &ref_priv.toObject ());
337349 RootedValue parent_path_val (cx);
338350 if (!JS_GetProperty (cx, info, " id" , &parent_path_val)) {
339- return nullptr ;
351+ return false ;
340352 }
341353 if (!parent_path_val.isString ()) {
342- return nullptr ;
354+ JS_ReportErrorASCII (cx, " Module referrer has no id property" );
355+ return false ;
343356 }
344357
345358 HostString str = core::encode (cx, parent_path_val);
@@ -348,11 +361,15 @@ JSObject* module_resolve_hook(JSContext* cx, HandleValue referencingPrivate,
348361 JS::CompileOptions opts (cx, *COMPILE_OPTS);
349362 auto stripped = strip_prefix (resolved_path, PATH_PREFIX);
350363 opts.setFileAndLine (stripped.c_str (), 1 );
351- return get_module (cx, path.get (), resolved_path, opts);
364+ RootedObject result (cx, get_module (cx, path.get (), resolved_path, opts));
365+ if (!result) {
366+ return false ;
367+ }
368+ return FinishLoadingImportedModule (cx, referrer, module_reques, payload, result, false );
352369}
353370
354- bool module_metadata_hook (JSContext* cx, HandleValue referencingPrivate , HandleObject metaObject ) {
355- RootedObject info (cx, &referencingPrivate .toObject ());
371+ bool module_metadata_hook (JSContext * cx, HandleValue ref_priv , HandleObject meta_obj ) {
372+ RootedObject info (cx, &ref_priv .toObject ());
356373 RootedValue parent_id_val (cx);
357374 if (!JS_GetProperty (cx, info, " id" , &parent_id_val)) {
358375 return false ;
@@ -367,29 +384,29 @@ bool module_metadata_hook(JSContext* cx, HandleValue referencingPrivate, HandleO
367384 if (builtin_val.isUndefined ()) {
368385 return false ;
369386 }
370- JS_SetProperty (cx, metaObject , " builtin" , builtin_val);
387+ JS_SetProperty (cx, meta_obj , " builtin" , builtin_val);
371388 return true ;
372389}
373390
374- ScriptLoader::ScriptLoader (api::Engine* engine, JS::CompileOptions *opts,
391+ ScriptLoader::ScriptLoader (api::Engine * engine, JS::CompileOptions *opts,
375392 mozilla::Maybe<std::string> path_prefix) {
376393 MOZ_ASSERT (!SCRIPT_LOADER);
377394 ENGINE = engine;
378395 SCRIPT_LOADER = this ;
379396 COMPILE_OPTS = opts;
380397 PATH_PREFIX = std::move (path_prefix);
381- JSContext* cx = engine->cx ();
398+ JSContext * cx = engine->cx ();
382399 moduleRegistry.init (cx, JS::NewMapObject (cx));
383400 builtinModules.init (cx, JS::NewMapObject (cx));
384401 MOZ_RELEASE_ASSERT (moduleRegistry);
385402 MOZ_RELEASE_ASSERT (builtinModules);
386403 JSRuntime *rt = JS_GetRuntime (cx);
387- SetModuleResolveHook (rt, module_resolve_hook );
404+ SetModuleLoadHook (rt, module_load_hook );
388405 SetModuleMetadataHook (rt, module_metadata_hook);
389406}
390407
391- bool ScriptLoader::define_builtin_module (const char * id, HandleValue builtin) {
392- JSContext* cx = ENGINE->cx ();
408+ bool ScriptLoader::define_builtin_module (const char * id, HandleValue builtin) {
409+ JSContext * cx = ENGINE->cx ();
393410 RootedString id_str (cx, JS_NewStringCopyZ (cx, id));
394411 if (!id_str) {
395412 return false ;
@@ -409,9 +426,7 @@ bool ScriptLoader::define_builtin_module(const char* id, HandleValue builtin) {
409426 return true ;
410427}
411428
412- void ScriptLoader::enable_module_mode (bool enable) {
413- MODULE_MODE = enable;
414- }
429+ void ScriptLoader::enable_module_mode (bool enable) { MODULE_MODE = enable; }
415430
416431bool ScriptLoader::load_resolved_script (JSContext *cx, std::string_view specifier_sv,
417432 std::string_view resolved_path_sv,
@@ -424,30 +439,30 @@ bool ScriptLoader::load_resolved_script(JSContext *cx, std::string_view specifie
424439
425440 FILE *file = fopen (resolved_path, " r" );
426441 if (!file) {
427- return api::throw_error (cx, ScriptLoaderErrors::ModuleLoadingError,
428- specifier, resolved_path, std::strerror (errno));
442+ return api::throw_error (cx, ScriptLoaderErrors::ModuleLoadingError, specifier, resolved_path,
443+ std::strerror (errno));
429444 }
430445
431446 AutoCloseFile autoclose (file);
432447 if (fseek (file, 0 , SEEK_END) != 0 ) {
433- return api::throw_error (cx, ScriptLoaderErrors::ModuleLoadingError,
434- specifier, resolved_path, " can't read from file" );
448+ return api::throw_error (cx, ScriptLoaderErrors::ModuleLoadingError, specifier, resolved_path,
449+ " can't read from file" );
435450 }
436451 size_t len = ftell (file);
437452 if (fseek (file, 0 , SEEK_SET) != 0 ) {
438- return api::throw_error (cx, ScriptLoaderErrors::ModuleLoadingError,
439- specifier, resolved_path, " can't read from file" );
453+ return api::throw_error (cx, ScriptLoaderErrors::ModuleLoadingError, specifier, resolved_path,
454+ " can't read from file" );
440455 }
441456
442457 UniqueChars buf (js_pod_malloc<char >(len + 1 ));
443458 if (!buf) {
444- return api::throw_error (cx, ScriptLoaderErrors::ModuleLoadingError,
445- specifier, resolved_path, " out of memory while reading file" );
459+ return api::throw_error (cx, ScriptLoaderErrors::ModuleLoadingError, specifier, resolved_path,
460+ " out of memory while reading file" );
446461 }
447462 size_t cc = fread (buf.get (), sizeof (char ), len, file);
448463 if (cc != len) {
449- return api::throw_error (cx, ScriptLoaderErrors::ModuleLoadingError,
450- specifier, resolved_path, " error reading file" );
464+ return api::throw_error (cx, ScriptLoaderErrors::ModuleLoadingError, specifier, resolved_path,
465+ " error reading file" );
451466 }
452467
453468 return script.init (cx, std::move (buf), len);
@@ -471,8 +486,10 @@ bool ScriptLoader::load_script(JSContext *cx, std::string_view path,
471486 return load_resolved_script (cx, path, resolved, script);
472487}
473488
474- bool ScriptLoader::eval_top_level_script (std::string_view path, JS::SourceText<mozilla::Utf8Unit> &source,
475- MutableHandleValue result, MutableHandleValue tla_promise) {
489+ bool ScriptLoader::eval_top_level_script (std::string_view path,
490+ JS::SourceText<mozilla::Utf8Unit> &source,
491+ MutableHandleValue result,
492+ MutableHandleValue tla_promise) {
476493 JSContext *cx = ENGINE->cx ();
477494
478495 JS::CompileOptions opts (cx, *COMPILE_OPTS);
@@ -491,7 +508,20 @@ bool ScriptLoader::eval_top_level_script(std::string_view path, JS::SourceText<m
491508 if (!module ) {
492509 return false ;
493510 }
494- if (!ModuleLink (cx, module )) {
511+ RootedValue hostDefined (cx, ObjectValue (*module ));
512+ if (!LoadRequestedModules (
513+ cx, module , hostDefined,
514+ [](JSContext *cx, JS::Handle<JS::Value> hd) {
515+ JS::RootedObject mod (cx, &hd.toObject ());
516+ return JS::ModuleLink (cx, mod);
517+ },
518+ [](JSContext *cx, JS::Handle<JS::Value>, JS::Handle<JS::Value> error) {
519+ JS_SetPendingException (cx, error);
520+ return true ;
521+ })) {
522+ return false ;
523+ }
524+ if (JS_IsExceptionPending (cx)) {
495525 return false ;
496526 }
497527 } else {
0 commit comments