From 15914ec5780e7867ab508a48a83311c56950f8a9 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Fri, 27 Nov 2020 15:47:49 +0000 Subject: Issue #1691 - Part 1: Provide a way of associating a private value with a script or module. This is a prerequisite for dynamic import --- js/src/builtin/ModuleObject.cpp | 20 ++++++-------- js/src/builtin/ModuleObject.h | 6 ++--- js/src/jsapi.cpp | 20 +++++++++++--- js/src/jsapi.h | 25 ++++++++++++----- js/src/jsscript.h | 20 ++++++++++---- js/src/shell/js.cpp | 59 +++++++++++++++++++++++++++++++++++++++-- js/src/vm/SelfHosting.cpp | 3 ++- 7 files changed, 119 insertions(+), 34 deletions(-) (limited to 'js') diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index 2790b1c44..ae966c89a 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -725,6 +725,12 @@ ModuleObject::namespace_() return &value.toObject().as(); } +ScriptSourceObject* +ModuleObject::scriptSourceObject() const +{ + return &getReservedSlot(ScriptSourceObjectSlot).toObject().as(); +} + FunctionDeclarationVector* ModuleObject::functionDeclarations() { @@ -738,8 +744,10 @@ ModuleObject::functionDeclarations() void ModuleObject::init(HandleScript script) { + MOZ_ASSERT(script); initReservedSlot(ScriptSlot, PrivateValue(script)); initReservedSlot(StatusSlot, Int32Value(MODULE_STATUS_UNINSTANTIATED)); + initReservedSlot(ScriptSourceObjectSlot, ObjectValue(script->scriptSourceUnwrap())); } void @@ -868,18 +876,6 @@ ModuleObject::evaluationError() const return getReservedSlot(EvaluationErrorSlot); } -Value -ModuleObject::hostDefinedField() const -{ - return getReservedSlot(HostDefinedSlot); -} - -void -ModuleObject::setHostDefinedField(const JS::Value& value) -{ - setReservedSlot(HostDefinedSlot, value); -} - Scope* ModuleObject::enclosingScope() const { diff --git a/js/src/builtin/ModuleObject.h b/js/src/builtin/ModuleObject.h index dc078e6b2..c2514e876 100644 --- a/js/src/builtin/ModuleObject.h +++ b/js/src/builtin/ModuleObject.h @@ -219,7 +219,7 @@ class ModuleObject : public NativeObject NamespaceSlot, StatusSlot, EvaluationErrorSlot, - HostDefinedSlot, + ScriptSourceObjectSlot, RequestedModulesSlot, ImportEntriesSlot, LocalExportEntriesSlot, @@ -271,7 +271,7 @@ class ModuleObject : public NativeObject ModuleStatus status() const; bool hadEvaluationError() const; Value evaluationError() const; - Value hostDefinedField() const; + ScriptSourceObject* scriptSourceObject() const; ArrayObject& requestedModules() const; ArrayObject& importEntries() const; ArrayObject& localExportEntries() const; @@ -284,8 +284,6 @@ class ModuleObject : public NativeObject static bool Instantiate(JSContext* cx, HandleModuleObject self); static bool Evaluate(JSContext* cx, HandleModuleObject self); - void setHostDefinedField(const JS::Value& value); - // For BytecodeEmitter. bool noteFunctionDeclaration(ExclusiveContext* cx, HandleAtom name, HandleFunction fun); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index dab4c25a4..74d64e312 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4691,15 +4691,27 @@ JS::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options, } JS_PUBLIC_API(void) -JS::SetModuleHostDefinedField(JSObject* module, const JS::Value& value) +JS::SetModulePrivate(JSObject* module, const JS::Value& value) { - module->as().setHostDefinedField(value); + module->as().scriptSourceObject()->setPrivate(value); } JS_PUBLIC_API(JS::Value) -JS::GetModuleHostDefinedField(JSObject* module) +JS::GetModulePrivate(JSObject* module) { - return module->as().hostDefinedField(); + return module->as().scriptSourceObject()->getPrivate(); +} + +JS_PUBLIC_API(void) +JS::SetScriptPrivate(JSScript* script, const JS::Value& value) +{ + script->scriptSourceUnwrap().setPrivate(value); +} + +JS_PUBLIC_API(JS::Value) +JS::GetScriptPrivate(JSScript* script) +{ + return script->scriptSourceUnwrap().getPrivate(); } JS_PUBLIC_API(bool) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index f8203ee1f..82477f9a7 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -4324,7 +4324,7 @@ extern JS_PUBLIC_API(bool) Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, const char* filename, JS::MutableHandleValue rval); -using ModuleResolveHook = JSObject* (*)(JSContext*, HandleObject, HandleString); +using ModuleResolveHook = JSObject* (*)(JSContext*, HandleValue, HandleString); /** * Get the HostResolveImportedModule hook for the runtime. @@ -4347,17 +4347,30 @@ CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options, SourceBufferHolder& srcBuf, JS::MutableHandleObject moduleRecord); /** - * Set the [[HostDefined]] field of a source text module record to the given - * value. + * Set a private value associated with a source text module record. */ extern JS_PUBLIC_API(void) -SetModuleHostDefinedField(JSObject* module, const JS::Value& value); +SetModulePrivate(JSObject* module, const JS::Value& value); /** - * Get the [[HostDefined]] field of a source text module record. + * Get the private value associated with a source text module record. */ extern JS_PUBLIC_API(JS::Value) -GetModuleHostDefinedField(JSObject* module); +GetModulePrivate(JSObject* module); + +/** + * Set a private value associated with a script. Note that this value is shared + * by all nested scripts compiled from a single source file. + */ +extern JS_PUBLIC_API(void) +SetScriptPrivate(JSScript* script, const JS::Value& value); + +/** + * Get the private value associated with a script. Note that this value is + * shared by all nested scripts compiled from a single source file. + */ +extern JS_PUBLIC_API(JS::Value) +GetScriptPrivate(JSScript* script); /* * Perform the ModuleInstantiate operation on the given source text module diff --git a/js/src/jsscript.h b/js/src/jsscript.h index d8d28ebeb..fd5c96a16 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -638,12 +638,22 @@ class ScriptSourceObject : public NativeObject return static_cast(untyped); } + void setPrivate(const Value& value) { + setReservedSlot(PRIVATE_SLOT, value); + } + Value getPrivate() const { + return getReservedSlot(PRIVATE_SLOT); + } + private: - static const uint32_t SOURCE_SLOT = 0; - static const uint32_t ELEMENT_SLOT = 1; - static const uint32_t ELEMENT_PROPERTY_SLOT = 2; - static const uint32_t INTRODUCTION_SCRIPT_SLOT = 3; - static const uint32_t RESERVED_SLOTS = 4; + enum { + SOURCE_SLOT = 0, + ELEMENT_SLOT, + ELEMENT_PROPERTY_SLOT, + INTRODUCTION_SCRIPT_SLOT, + PRIVATE_SLOT, + RESERVED_SLOTS + }; }; enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator }; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 6e155d3ff..acd2ec207 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -4039,12 +4039,12 @@ SetModuleResolveHook(JSContext* cx, unsigned argc, Value* vp) } static JSObject* -CallModuleResolveHook(JSContext* cx, HandleObject module, HandleString specifier) +CallModuleResolveHook(JSContext* cx, HandleValue referencingPrivate, HandleString specifier) { ShellContext* sc = GetShellContext(cx); JS::AutoValueArray<2> args(cx); - args[0].setObject(*module); + args[0].set(referencingPrivate); args[1].setString(specifier); RootedValue result(cx); @@ -4059,6 +4059,53 @@ CallModuleResolveHook(JSContext* cx, HandleObject module, HandleString specifier return &result.toObject(); } +static bool +ReportArgumentTypeError(JSContext* cx, HandleValue value, const char* expected) +{ + const char* typeName = InformalValueTypeName(value); + JS_ReportErrorASCII(cx, "Expected %s, got %s", expected, typeName); + return false; +} + +static bool +ShellSetModulePrivate(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + if (args.length() != 2) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED, + "setModulePrivate", "0", "s"); + return false; + } + + if (!args[0].isObject() || !args[0].toObject().is()) { + return ReportArgumentTypeError(cx, args[0], "module object"); + } + + JS::SetModulePrivate(&args[0].toObject(), args[1]); + args.rval().setUndefined(); + return true; +} + +static bool +ShellGetModulePrivate(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + if (args.length() != 1) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED, + "getModulePrivate", "0", "s"); + return false; + } + + if (!args[0].isObject() || !args[0].toObject().is()) { + return ReportArgumentTypeError(cx, args[0], "module object"); + } + + args.rval().set(JS::GetModulePrivate(&args[0].toObject())); + return true; +} + static bool GetModuleLoadPath(JSContext* cx, unsigned argc, Value* vp) { @@ -5927,6 +5974,14 @@ static const JSFunctionSpecWithHelp shell_functions[] = { " This hook is used to look up a previously loaded module object. It should\n" " be implemented by the module loader."), + JS_FN_HELP("setModulePrivate", ShellSetModulePrivate, 2, 0, +"setModulePrivate(scriptObject, privateValue)", +" Associate a private value with a module object.\n"), + + JS_FN_HELP("getModulePrivate", ShellGetModulePrivate, 2, 0, +"getModulePrivate(scriptObject)", +" Get the private value associated with a module object.\n"), + JS_FN_HELP("getModuleLoadPath", GetModuleLoadPath, 0, 0, "getModuleLoadPath()", " Return any --module-load-path argument passed to the shell. Used by the\n" diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index dc1dfb9fa..781ddcf16 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -2035,7 +2035,8 @@ intrinsic_HostResolveImportedModule(JSContext* cx, unsigned argc, Value* vp) } RootedObject result(cx); - result = moduleResolveHook(cx, module, specifier); + RootedValue referencingPrivate(cx, JS::GetModulePrivate(module)); + result = moduleResolveHook(cx, referencingPrivate, specifier); if (!result) return false; -- cgit v1.2.3