mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-08 08:48:39 +09:00
Issue #1691 - Part 5b: Stop modules from entraining the top-level JSScript. https://bugzilla.mozilla.org/show_bug.cgi?id=1489477
(cherry picked from commit 6ce0af856186e65fb4987daf4e06dc68fb3f7483)
This commit is contained in:
parent
c965fbdd10
commit
5c09a3b3cc
4 changed files with 71 additions and 21 deletions
|
|
@ -835,18 +835,22 @@ ModuleObject::fixEnvironmentsAfterCompartmentMerge()
|
|||
AssertModuleScopesMatch(this);
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleObject::hasScript() const
|
||||
JSScript*
|
||||
ModuleObject::maybeScript() const
|
||||
{
|
||||
// When modules are parsed via the Reflect.parse() API, the module object
|
||||
// doesn't have a script.
|
||||
return !getReservedSlot(ScriptSlot).isUndefined();
|
||||
Value value = getReservedSlot(ScriptSlot);
|
||||
if (value.isUndefined())
|
||||
return nullptr;
|
||||
|
||||
return value.toGCThing()->as<JSScript>();
|
||||
}
|
||||
|
||||
JSScript*
|
||||
ModuleObject::script() const
|
||||
{
|
||||
return static_cast<JSScript*>(getReservedSlot(ScriptSlot).toPrivate());
|
||||
JSScript* ptr = maybeScript();
|
||||
MOZ_RELEASE_ASSERT(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
|
@ -906,8 +910,8 @@ ModuleObject::enclosingScope() const
|
|||
ModuleObject::trace(JSTracer* trc, JSObject* obj)
|
||||
{
|
||||
ModuleObject& module = obj->as<ModuleObject>();
|
||||
if (module.hasScript()) {
|
||||
JSScript* script = module.script();
|
||||
JSScript* script = module.maybeScript();
|
||||
if (script) {
|
||||
TraceManuallyBarrieredEdge(trc, &script, "Module script");
|
||||
module.setReservedSlot(ScriptSlot, PrivateValue(script));
|
||||
}
|
||||
|
|
@ -976,6 +980,11 @@ ModuleObject::execute(JSContext* cx, HandleModuleObject self, MutableHandleValue
|
|||
#endif
|
||||
|
||||
RootedScript script(cx, self->script());
|
||||
|
||||
// The top-level script if a module is only ever executed once. Clear the
|
||||
// reference to prevent us keeping this alive unnecessarily.
|
||||
self->setReservedSlot(ScriptSlot, UndefinedValue());
|
||||
|
||||
RootedModuleEnvironmentObject scope(cx, self->environment());
|
||||
if (!scope) {
|
||||
JS_ReportErrorASCII(cx, "Module declarations have not yet been instantiated");
|
||||
|
|
|
|||
|
|
@ -266,6 +266,7 @@ class ModuleObject : public NativeObject
|
|||
#endif
|
||||
void fixEnvironmentsAfterCompartmentMerge();
|
||||
|
||||
JSScript* maybeScript() const;
|
||||
JSScript* script() const;
|
||||
Scope* enclosingScope() const;
|
||||
ModuleEnvironmentObject& initialEnvironment() const;
|
||||
|
|
@ -312,7 +313,6 @@ class ModuleObject : public NativeObject
|
|||
static void trace(JSTracer* trc, JSObject* obj);
|
||||
static void finalize(js::FreeOp* fop, JSObject* obj);
|
||||
|
||||
bool hasScript() const;
|
||||
bool hasImportBindings() const;
|
||||
FunctionDeclarationVector* functionDeclarations();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,6 +38,18 @@ Reflect.Loader = new class {
|
|||
module.declarationInstantiation();
|
||||
return module.evaluation();
|
||||
}
|
||||
|
||||
populateImportMeta(module, metaObject) {
|
||||
// For the shell, use the script's filename as the base URL.
|
||||
|
||||
let path;
|
||||
if (ReflectApply(MapPrototypeHas, this.modulePaths, [module])) {
|
||||
path = ReflectApply(MapPrototypeGet, this.modulePaths, [module]);
|
||||
} else {
|
||||
path = "(unknown)";
|
||||
}
|
||||
metaObject.url = path;
|
||||
}
|
||||
};
|
||||
|
||||
setModuleResolveHook((referencingInfo, requestName) => {
|
||||
|
|
|
|||
|
|
@ -2830,7 +2830,7 @@ DisassembleToSprinter(JSContext* cx, unsigned argc, Value* vp, Sprinter* sprinte
|
|||
RootedScript script(cx);
|
||||
RootedValue value(cx, p.argv[i]);
|
||||
if (value.isObject() && value.toObject().is<ModuleObject>())
|
||||
script = value.toObject().as<ModuleObject>().script();
|
||||
script = value.toObject().as<ModuleObject>().maybeScript();
|
||||
else
|
||||
script = ValueToScript(cx, value, fun.address());
|
||||
if (!script)
|
||||
|
|
@ -4132,23 +4132,48 @@ ShellGetModulePrivate(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
ShellModuleMetadataHook(JSContext* cx, HandleObject module, HandleObject metaObject)
|
||||
static bool
|
||||
SetModuleMetadataHook(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
// For the shell, just use the script's filename as the base URL.
|
||||
RootedScript script(cx, module->as<ModuleObject>().script());
|
||||
const char* filename = script->scriptSource()->filename();
|
||||
MOZ_ASSERT(filename);
|
||||
|
||||
RootedString url(cx, NewStringCopyZ<CanGC>(cx, filename));
|
||||
if (!url)
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (args.length() != 1) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
|
||||
"setModuleMetadataHook", "0", "s");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!JS_DefineProperty(cx, metaObject, "url", url, JSPROP_ENUMERATE))
|
||||
if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
|
||||
const char* typeName = InformalValueTypeName(args[0]);
|
||||
JS_ReportErrorASCII(cx, "expected hook function, got %s", typeName);
|
||||
return false;
|
||||
}
|
||||
|
||||
Handle<GlobalObject*> global = cx->global();
|
||||
global->setReservedSlot(GlobalAppSlotModuleMetadataHook, args[0]);
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CallModuleMetadataHook(JSContext* cx, HandleObject module, HandleObject metaObject)
|
||||
{
|
||||
Handle<GlobalObject*> global = cx->global();
|
||||
RootedValue hookValue(cx, global->getReservedSlot(GlobalAppSlotModuleMetadataHook));
|
||||
if (hookValue.isUndefined()) {
|
||||
JS_ReportErrorASCII(cx, "Module metadata hook not set");
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(hookValue.toObject().is<JSFunction>());
|
||||
|
||||
JS::AutoValueArray<2> args(cx);
|
||||
args[0].setObject(*module);
|
||||
args[1].setObject(*metaObject);
|
||||
|
||||
RootedValue dummy(cx);
|
||||
return JS_CallFunctionValue(cx, nullptr, hookValue, args, &dummy);
|
||||
}
|
||||
|
||||
static bool
|
||||
SetModuleDynamicImportHook(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
|
@ -5616,7 +5641,11 @@ DumpScopeChain(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
script = JSFunction::getOrCreateScript(cx, fun);
|
||||
} else {
|
||||
script = obj->as<ModuleObject>().script();
|
||||
script = obj->as<ModuleObject>().maybeScript();
|
||||
if (!script) {
|
||||
JS_ReportErrorASCII(cx, "module does not have an associated script");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
script->bodyScope()->dump();
|
||||
|
|
@ -7451,7 +7480,7 @@ ProcessArgs(JSContext* cx, OptionParser* op)
|
|||
if (const char* path = op->getStringOption("module-load-path"))
|
||||
moduleLoadPath = path;
|
||||
|
||||
if (!modulePaths.empty() && !InitModuleLoader(cx))
|
||||
if (!InitModuleLoader(cx))
|
||||
return false;
|
||||
|
||||
while (!filePaths.empty() || !codeChunks.empty() || !modulePaths.empty()) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue