Issue #1691 - Part 1: Provide a way of associating a private value with a script or module.

This is a prerequisite for dynamic import

(cherry picked from commit 2e2972647ee29340df51a804f05e40fc1da2c89b)
This commit is contained in:
Brian Smith 2023-04-08 03:26:10 -05:00 • committed by roytam1
commit 1a6b3a822c
10 changed files with 129 additions and 43 deletions

View file

@ -58,9 +58,9 @@ ModuleScript::UnlinkModuleRecord()
{ {
// Remove module's back reference to this object request if present. // Remove module's back reference to this object request if present.
if (mModuleRecord) { if (mModuleRecord) {
MOZ_ASSERT(JS::GetModuleHostDefinedField(mModuleRecord).toPrivate() == MOZ_ASSERT(JS::GetModulePrivate(mModuleRecord).toPrivate() ==
this); this);
JS::SetModuleHostDefinedField(mModuleRecord, JS::UndefinedValue()); JS::SetModulePrivate(mModuleRecord, JS::UndefinedValue());
mModuleRecord = nullptr; mModuleRecord = nullptr;
} }
} }
@ -83,7 +83,7 @@ ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord)
// Make module's host defined field point to this module script object. // Make module's host defined field point to this module script object.
// This is cleared in the UnlinkModuleRecord(). // This is cleared in the UnlinkModuleRecord().
JS::SetModuleHostDefinedField(mModuleRecord, JS::PrivateValue(this)); JS::SetModulePrivate(mModuleRecord, JS::PrivateValue(this));
HoldJSObjects(this); HoldJSObjects(this);
} }

View file

@ -798,13 +798,13 @@ ScriptLoader::StartFetchingModuleAndDependencies(ModuleLoadRequest* aParent,
// 8.1.3.8.1 HostResolveImportedModule(referencingModule, specifier) // 8.1.3.8.1 HostResolveImportedModule(referencingModule, specifier)
JSObject* JSObject*
HostResolveImportedModule(JSContext* aCx, JS::Handle<JSObject*> aModule, HostResolveImportedModule(JSContext* aCx,
JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSString*> aSpecifier) JS::Handle<JSString*> aSpecifier)
{ {
// Let referencing module script be referencingModule.[[HostDefined]]. // Let referencing module script be referencingModule.[[HostDefined]].
JS::Value value = JS::GetModuleHostDefinedField(aModule); auto script = static_cast<ModuleScript*>(aReferencingPrivate.toPrivate());
auto script = static_cast<ModuleScript*>(value.toPrivate()); MOZ_ASSERT(JS::GetModulePrivate(script->ModuleRecord()) == aReferencingPrivate);
MOZ_ASSERT(script->ModuleRecord() == aModule);
// Let url be the result of resolving a module specifier given referencing // Let url be the result of resolving a module specifier given referencing
// module script and specifier. // module script and specifier.

View file

@ -630,8 +630,9 @@ private:
ModuleScript* GetFetchedModule(nsIURI* aURL) const; ModuleScript* GetFetchedModule(nsIURI* aURL) const;
friend JSObject* friend JSObject*
HostResolveImportedModule(JSContext* aCx, JS::Handle<JSObject*> aModule, HostResolveImportedModule(JSContext* aCx,
JS::Handle<JSString*> aSpecifier); JS::Handle<JS::Value> aReferencingPrivate,
JS::Handle<JSString*> aSpecifier);
nsresult CreateModuleScript(ModuleLoadRequest* aRequest); nsresult CreateModuleScript(ModuleLoadRequest* aRequest);
nsresult ProcessFetchedModuleSource(ModuleLoadRequest* aRequest); nsresult ProcessFetchedModuleSource(ModuleLoadRequest* aRequest);

View file

@ -725,6 +725,12 @@ ModuleObject::namespace_()
return &value.toObject().as<ModuleNamespaceObject>(); return &value.toObject().as<ModuleNamespaceObject>();
} }
ScriptSourceObject*
ModuleObject::scriptSourceObject() const
{
return &getReservedSlot(ScriptSourceObjectSlot).toObject().as<ScriptSourceObject>();
}
FunctionDeclarationVector* FunctionDeclarationVector*
ModuleObject::functionDeclarations() ModuleObject::functionDeclarations()
{ {
@ -738,8 +744,10 @@ ModuleObject::functionDeclarations()
void void
ModuleObject::init(HandleScript script) ModuleObject::init(HandleScript script)
{ {
MOZ_ASSERT(script);
initReservedSlot(ScriptSlot, PrivateValue(script)); initReservedSlot(ScriptSlot, PrivateValue(script));
initReservedSlot(StatusSlot, Int32Value(MODULE_STATUS_UNINSTANTIATED)); initReservedSlot(StatusSlot, Int32Value(MODULE_STATUS_UNINSTANTIATED));
initReservedSlot(ScriptSourceObjectSlot, ObjectValue(script->scriptSourceUnwrap()));
} }
void void
@ -868,18 +876,6 @@ ModuleObject::evaluationError() const
return getReservedSlot(EvaluationErrorSlot); return getReservedSlot(EvaluationErrorSlot);
} }
Value
ModuleObject::hostDefinedField() const
{
return getReservedSlot(HostDefinedSlot);
}
void
ModuleObject::setHostDefinedField(const JS::Value& value)
{
setReservedSlot(HostDefinedSlot, value);
}
Scope* Scope*
ModuleObject::enclosingScope() const ModuleObject::enclosingScope() const
{ {

View file

@ -221,7 +221,7 @@ class ModuleObject : public NativeObject
NamespaceSlot, NamespaceSlot,
StatusSlot, StatusSlot,
EvaluationErrorSlot, EvaluationErrorSlot,
HostDefinedSlot, ScriptSourceObjectSlot,
RequestedModulesSlot, RequestedModulesSlot,
ImportEntriesSlot, ImportEntriesSlot,
LocalExportEntriesSlot, LocalExportEntriesSlot,
@ -273,7 +273,7 @@ class ModuleObject : public NativeObject
ModuleStatus status() const; ModuleStatus status() const;
bool hadEvaluationError() const; bool hadEvaluationError() const;
Value evaluationError() const; Value evaluationError() const;
Value hostDefinedField() const; ScriptSourceObject* scriptSourceObject() const;
ArrayObject& requestedModules() const; ArrayObject& requestedModules() const;
ArrayObject& importEntries() const; ArrayObject& importEntries() const;
ArrayObject& localExportEntries() const; ArrayObject& localExportEntries() const;
@ -286,8 +286,6 @@ class ModuleObject : public NativeObject
static bool Instantiate(JSContext* cx, HandleModuleObject self); static bool Instantiate(JSContext* cx, HandleModuleObject self);
static bool Evaluate(JSContext* cx, HandleModuleObject self); static bool Evaluate(JSContext* cx, HandleModuleObject self);
void setHostDefinedField(const JS::Value& value);
// For BytecodeEmitter. // For BytecodeEmitter.
bool noteFunctionDeclaration(ExclusiveContext* cx, HandleAtom name, HandleFunction fun); bool noteFunctionDeclaration(ExclusiveContext* cx, HandleAtom name, HandleFunction fun);

View file

@ -4710,15 +4710,27 @@ JS::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
} }
JS_PUBLIC_API(void) JS_PUBLIC_API(void)
JS::SetModuleHostDefinedField(JSObject* module, const JS::Value& value) JS::SetModulePrivate(JSObject* module, const JS::Value& value)
{ {
module->as<ModuleObject>().setHostDefinedField(value); module->as<ModuleObject>().scriptSourceObject()->setPrivate(value);
} }
JS_PUBLIC_API(JS::Value) JS_PUBLIC_API(JS::Value)
JS::GetModuleHostDefinedField(JSObject* module) JS::GetModulePrivate(JSObject* module)
{ {
return module->as<ModuleObject>().hostDefinedField(); return module->as<ModuleObject>().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) JS_PUBLIC_API(bool)

View file

@ -4324,7 +4324,7 @@ extern JS_PUBLIC_API(bool)
Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* filename, JS::MutableHandleValue rval); 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. * Get the HostResolveImportedModule hook for the runtime.
@ -4347,17 +4347,30 @@ CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf, JS::MutableHandleObject moduleRecord); SourceBufferHolder& srcBuf, JS::MutableHandleObject moduleRecord);
/** /**
* Set the [[HostDefined]] field of a source text module record to the given * Set a private value associated with a source text module record.
* value.
*/ */
extern JS_PUBLIC_API(void) 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) 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 * Perform the ModuleInstantiate operation on the given source text module

View file

@ -638,12 +638,22 @@ class ScriptSourceObject : public NativeObject
return static_cast<JSScript*>(untyped); return static_cast<JSScript*>(untyped);
} }
void setPrivate(const Value& value) {
setReservedSlot(PRIVATE_SLOT, value);
}
Value getPrivate() const {
return getReservedSlot(PRIVATE_SLOT);
}
private: private:
static const uint32_t SOURCE_SLOT = 0; enum {
static const uint32_t ELEMENT_SLOT = 1; SOURCE_SLOT = 0,
static const uint32_t ELEMENT_PROPERTY_SLOT = 2; ELEMENT_SLOT,
static const uint32_t INTRODUCTION_SCRIPT_SLOT = 3; ELEMENT_PROPERTY_SLOT,
static const uint32_t RESERVED_SLOTS = 4; INTRODUCTION_SCRIPT_SLOT,
PRIVATE_SLOT,
RESERVED_SLOTS
};
}; };
enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator }; enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator };

View file

@ -4035,12 +4035,12 @@ SetModuleResolveHook(JSContext* cx, unsigned argc, Value* vp)
} }
static JSObject* static JSObject*
CallModuleResolveHook(JSContext* cx, HandleObject module, HandleString specifier) CallModuleResolveHook(JSContext* cx, HandleValue referencingPrivate, HandleString specifier)
{ {
ShellContext* sc = GetShellContext(cx); ShellContext* sc = GetShellContext(cx);
JS::AutoValueArray<2> args(cx); JS::AutoValueArray<2> args(cx);
args[0].setObject(*module); args[0].set(referencingPrivate);
args[1].setString(specifier); args[1].setString(specifier);
RootedValue result(cx); RootedValue result(cx);
@ -4055,6 +4055,53 @@ CallModuleResolveHook(JSContext* cx, HandleObject module, HandleString specifier
return &result.toObject(); 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<ModuleObject>()) {
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<ModuleObject>()) {
return ReportArgumentTypeError(cx, args[0], "module object");
}
args.rval().set(JS::GetModulePrivate(&args[0].toObject()));
return true;
}
static bool static bool
GetModuleLoadPath(JSContext* cx, unsigned argc, Value* vp) GetModuleLoadPath(JSContext* cx, unsigned argc, Value* vp)
{ {
@ -5923,6 +5970,14 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
" This hook is used to look up a previously loaded module object. It should\n" " This hook is used to look up a previously loaded module object. It should\n"
" be implemented by the module loader."), " 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, JS_FN_HELP("getModuleLoadPath", GetModuleLoadPath, 0, 0,
"getModuleLoadPath()", "getModuleLoadPath()",
" Return any --module-load-path argument passed to the shell. Used by the\n" " Return any --module-load-path argument passed to the shell. Used by the\n"

View file

@ -2006,7 +2006,8 @@ intrinsic_HostResolveImportedModule(JSContext* cx, unsigned argc, Value* vp)
} }
RootedObject result(cx); RootedObject result(cx);
result = moduleResolveHook(cx, module, specifier); RootedValue referencingPrivate(cx, JS::GetModulePrivate(module));
result = moduleResolveHook(cx, referencingPrivate, specifier);
if (!result) if (!result)
return false; return false;