Bug 1519140 - Add AddRef/Release hooks for embedding's script or module private value and set this script source object where appropriate r=jandem

This commit is contained in:
Jon Coppeard
2019-01-18 13:37:43 +00:00
parent 33aec9da96
commit 79adfa338b
24 changed files with 179 additions and 138 deletions

View File

@@ -48,29 +48,40 @@ LoadedScript::LoadedScript(ScriptKind aKind, ScriptFetchOptions* aFetchOptions,
LoadedScript::~LoadedScript() { DropJSObjects(this); } LoadedScript::~LoadedScript() { DropJSObjects(this); }
void LoadedScript::AssociateWithScript(JSScript* aScript) { void LoadedScript::AssociateWithScript(JSScript* aScript) {
// Set a JSScript's private value to point to this object and // Set a JSScript's private value to point to this object. The JS engine will
// increment our reference count. This is decremented by // increment our reference count by calling HostAddRefTopLevelScript(). This
// HostFinalizeTopLevelScript() below when the JSScript dies. // is decremented by HostReleaseTopLevelScript() below when the JSScript dies.
MOZ_ASSERT(JS::GetScriptPrivate(aScript).isUndefined()); MOZ_ASSERT(JS::GetScriptPrivate(aScript).isUndefined());
JS::SetScriptPrivate(aScript, JS::PrivateValue(this)); JS::SetScriptPrivate(aScript, JS::PrivateValue(this));
AddRef();
} }
void HostFinalizeTopLevelScript(JSFreeOp* aFop, const JS::Value& aPrivate) { inline void CheckModuleScriptPrivate(LoadedScript* script, const JS::Value& aPrivate) {
// Decrement the reference count of a LoadedScript object that is
// pointed to by a dying JSScript. The reference count was
// originally incremented by AssociateWithScript() above.
auto script = static_cast<LoadedScript*>(aPrivate.toPrivate());
#ifdef DEBUG #ifdef DEBUG
if (script->IsModuleScript()) { if (script->IsModuleScript()) {
JSObject* module = script->AsModuleScript()->mModuleRecord.unbarrieredGet(); JSObject* module = script->AsModuleScript()->mModuleRecord.unbarrieredGet();
MOZ_ASSERT_IF(module, JS::GetModulePrivate(module) == aPrivate); MOZ_ASSERT_IF(module, JS::GetModulePrivate(module) == aPrivate);
} }
#endif #endif
}
void HostAddRefTopLevelScript(const JS::Value& aPrivate) {
// Increment the reference count of a LoadedScript object that is now pointed
// to by a JSScript. The reference count is decremented by
// HostReleaseTopLevelScript() below.
auto script = static_cast<LoadedScript*>(aPrivate.toPrivate());
CheckModuleScriptPrivate(script, aPrivate);
script->AddRef();
}
void HostReleaseTopLevelScript(const JS::Value& aPrivate) {
// Decrement the reference count of a LoadedScript object that was pointed to
// by a JSScript. The reference count was originally incremented by
// HostAddRefTopLevelScript() above.
auto script = static_cast<LoadedScript*>(aPrivate.toPrivate());
CheckModuleScriptPrivate(script, aPrivate);
script->Release(); script->Release();
} }
@@ -125,7 +136,6 @@ void ModuleScript::UnlinkModuleRecord() {
MOZ_ASSERT(JS::GetModulePrivate(mModuleRecord).toPrivate() == this); MOZ_ASSERT(JS::GetModulePrivate(mModuleRecord).toPrivate() == this);
JS::SetModulePrivate(mModuleRecord, JS::UndefinedValue()); JS::SetModulePrivate(mModuleRecord, JS::UndefinedValue());
mModuleRecord = nullptr; mModuleRecord = nullptr;
Release();
} }
} }
@@ -141,14 +151,14 @@ void ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord) {
mModuleRecord = aModuleRecord; mModuleRecord = aModuleRecord;
// Make module's host defined field point to this object and // Make module's host defined field point to this object. The JS engine will
// increment our reference count. This is decremented by // increment our reference count by calling HostAddRefTopLevelScript(). This
// UnlinkModuleRecord() above. // is decremented when the field is cleared in UnlinkModuleRecord() above or
// when the module record dies.
MOZ_ASSERT(JS::GetModulePrivate(mModuleRecord).isUndefined()); MOZ_ASSERT(JS::GetModulePrivate(mModuleRecord).isUndefined());
JS::SetModulePrivate(mModuleRecord, JS::PrivateValue(this)); JS::SetModulePrivate(mModuleRecord, JS::PrivateValue(this));
HoldJSObjects(this); HoldJSObjects(this);
AddRef();
} }
void ModuleScript::SetParseError(const JS::Value& aError) { void ModuleScript::SetParseError(const JS::Value& aError) {

View File

@@ -19,7 +19,8 @@ namespace dom {
class ScriptLoader; class ScriptLoader;
void HostFinalizeTopLevelScript(JSFreeOp* aFop, const JS::Value& aPrivate); void HostAddRefTopLevelScript(const JS::Value& aPrivate);
void HostReleaseTopLevelScript(const JS::Value& aPrivate);
class ClassicScript; class ClassicScript;
class ModuleScript; class ModuleScript;
@@ -89,7 +90,7 @@ class ModuleScript final : public LoadedScript {
void UnlinkModuleRecord(); void UnlinkModuleRecord();
friend void HostFinalizeTopLevelScript(JSFreeOp*, const JS::Value&); friend void CheckModuleScriptPrivate(LoadedScript*, const JS::Value&);
}; };
ClassicScript* LoadedScript::AsClassicScript() { ClassicScript* LoadedScript::AsClassicScript() {

View File

@@ -966,7 +966,9 @@ void ScriptLoader::EnsureModuleHooksInitialized() {
JS::SetModuleResolveHook(rt, HostResolveImportedModule); JS::SetModuleResolveHook(rt, HostResolveImportedModule);
JS::SetModuleMetadataHook(rt, HostPopulateImportMeta); JS::SetModuleMetadataHook(rt, HostPopulateImportMeta);
JS::SetScriptPrivateFinalizeHook(rt, HostFinalizeTopLevelScript); JS::SetScriptPrivateReferenceHooks(rt,
HostAddRefTopLevelScript,
HostReleaseTopLevelScript);
Preferences::RegisterCallbackAndCall(DynamicImportPrefChangedCallback, Preferences::RegisterCallbackAndCall(DynamicImportPrefChangedCallback,
"javascript.options.dynamicImport", "javascript.options.dynamicImport",

View File

@@ -145,6 +145,15 @@ class JS_PUBLIC_API TransitiveCompileOptions {
virtual JSString* elementAttributeName() const = 0; virtual JSString* elementAttributeName() const = 0;
virtual JSScript* introductionScript() const = 0; virtual JSScript* introductionScript() const = 0;
// For some compilations the spec requires the ScriptOrModule field of the
// resulting script to be set to the currently executing script. This can be
// achieved by setting this option with setScriptOrModule() below.
//
// Note that this field doesn't explicitly exist in our implementation;
// instead the ScriptSourceObject's private value is set to that associated
// with the specified script.
virtual JSScript* scriptOrModule() const = 0;
private: private:
void operator=(const TransitiveCompileOptions&) = delete; void operator=(const TransitiveCompileOptions&) = delete;
}; };
@@ -202,9 +211,10 @@ class JS_PUBLIC_API ReadOnlyCompileOptions : public TransitiveCompileOptions {
const char* filename() const { return filename_; } const char* filename() const { return filename_; }
const char* introducerFilename() const { return introducerFilename_; } const char* introducerFilename() const { return introducerFilename_; }
const char16_t* sourceMapURL() const { return sourceMapURL_; } const char16_t* sourceMapURL() const { return sourceMapURL_; }
virtual JSObject* element() const override = 0; JSObject* element() const override = 0;
virtual JSString* elementAttributeName() const override = 0; JSString* elementAttributeName() const override = 0;
virtual JSScript* introductionScript() const override = 0; JSScript* introductionScript() const override = 0;
JSScript* scriptOrModule() const override = 0;
private: private:
void operator=(const ReadOnlyCompileOptions&) = delete; void operator=(const ReadOnlyCompileOptions&) = delete;
@@ -227,6 +237,7 @@ class JS_PUBLIC_API OwningCompileOptions final : public ReadOnlyCompileOptions {
PersistentRooted<JSObject*> elementRoot; PersistentRooted<JSObject*> elementRoot;
PersistentRooted<JSString*> elementAttributeNameRoot; PersistentRooted<JSString*> elementAttributeNameRoot;
PersistentRooted<JSScript*> introductionScriptRoot; PersistentRooted<JSScript*> introductionScriptRoot;
PersistentRooted<JSScript*> scriptOrModuleRoot;
public: public:
// A minimal constructor, for use with OwningCompileOptions::copy. // A minimal constructor, for use with OwningCompileOptions::copy.
@@ -240,6 +251,9 @@ class JS_PUBLIC_API OwningCompileOptions final : public ReadOnlyCompileOptions {
JSScript* introductionScript() const override { JSScript* introductionScript() const override {
return introductionScriptRoot; return introductionScriptRoot;
} }
JSScript* scriptOrModule() const override {
return scriptOrModuleRoot;
}
/** Set this to a copy of |rhs|. Return false on OOM. */ /** Set this to a copy of |rhs|. Return false on OOM. */
bool copy(JSContext* cx, const ReadOnlyCompileOptions& rhs); bool copy(JSContext* cx, const ReadOnlyCompileOptions& rhs);
@@ -272,6 +286,11 @@ class JS_PUBLIC_API OwningCompileOptions final : public ReadOnlyCompileOptions {
return *this; return *this;
} }
OwningCompileOptions& setScriptOrModule(JSScript* s) {
scriptOrModuleRoot = s;
return *this;
}
OwningCompileOptions& setMutedErrors(bool mute) { OwningCompileOptions& setMutedErrors(bool mute) {
mutedErrors_ = mute; mutedErrors_ = mute;
return *this; return *this;
@@ -361,6 +380,7 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
Rooted<JSObject*> elementRoot; Rooted<JSObject*> elementRoot;
Rooted<JSString*> elementAttributeNameRoot; Rooted<JSString*> elementAttributeNameRoot;
Rooted<JSScript*> introductionScriptRoot; Rooted<JSScript*> introductionScriptRoot;
Rooted<JSScript*> scriptOrModuleRoot;
public: public:
explicit CompileOptions(JSContext* cx); explicit CompileOptions(JSContext* cx);
@@ -369,7 +389,8 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
: ReadOnlyCompileOptions(), : ReadOnlyCompileOptions(),
elementRoot(cx), elementRoot(cx),
elementAttributeNameRoot(cx), elementAttributeNameRoot(cx),
introductionScriptRoot(cx) { introductionScriptRoot(cx),
scriptOrModuleRoot(cx) {
copyPODOptions(rhs); copyPODOptions(rhs);
filename_ = rhs.filename(); filename_ = rhs.filename();
@@ -378,13 +399,15 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
elementRoot = rhs.element(); elementRoot = rhs.element();
elementAttributeNameRoot = rhs.elementAttributeName(); elementAttributeNameRoot = rhs.elementAttributeName();
introductionScriptRoot = rhs.introductionScript(); introductionScriptRoot = rhs.introductionScript();
scriptOrModuleRoot = rhs.scriptOrModule();
} }
CompileOptions(JSContext* cx, const TransitiveCompileOptions& rhs) CompileOptions(JSContext* cx, const TransitiveCompileOptions& rhs)
: ReadOnlyCompileOptions(), : ReadOnlyCompileOptions(),
elementRoot(cx), elementRoot(cx),
elementAttributeNameRoot(cx), elementAttributeNameRoot(cx),
introductionScriptRoot(cx) { introductionScriptRoot(cx),
scriptOrModuleRoot(cx) {
copyPODTransitiveOptions(rhs); copyPODTransitiveOptions(rhs);
filename_ = rhs.filename(); filename_ = rhs.filename();
@@ -393,6 +416,7 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
elementRoot = rhs.element(); elementRoot = rhs.element();
elementAttributeNameRoot = rhs.elementAttributeName(); elementAttributeNameRoot = rhs.elementAttributeName();
introductionScriptRoot = rhs.introductionScript(); introductionScriptRoot = rhs.introductionScript();
scriptOrModuleRoot = rhs.scriptOrModule();
} }
JSObject* element() const override { return elementRoot; } JSObject* element() const override { return elementRoot; }
@@ -405,6 +429,10 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
return introductionScriptRoot; return introductionScriptRoot;
} }
JSScript* scriptOrModule() const override {
return scriptOrModuleRoot;
}
CompileOptions& setFile(const char* f) { CompileOptions& setFile(const char* f) {
filename_ = f; filename_ = f;
return *this; return *this;
@@ -441,6 +469,11 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
return *this; return *this;
} }
CompileOptions& setScriptOrModule(JSScript* s) {
scriptOrModuleRoot = s;
return *this;
}
CompileOptions& setMutedErrors(bool mute) { CompileOptions& setMutedErrors(bool mute) {
mutedErrors_ = mute; mutedErrors_ = mute;
return *this; return *this;

View File

@@ -283,7 +283,8 @@ static bool EvalKernel(JSContext* cx, HandleValue v, EvalType evalType,
options.setIsRunOnce(true) options.setIsRunOnce(true)
.setNoScriptRval(false) .setNoScriptRval(false)
.setMutedErrors(mutedErrors) .setMutedErrors(mutedErrors)
.maybeMakeStrictMode(evalType == DIRECT_EVAL && IsStrictEvalPC(pc)); .maybeMakeStrictMode(evalType == DIRECT_EVAL && IsStrictEvalPC(pc))
.setScriptOrModule(maybeScript);
if (introducerFilename) { if (introducerFilename) {
options.setFileAndLine(filename, 1); options.setFileAndLine(filename, 1);
@@ -310,7 +311,7 @@ static bool EvalKernel(JSContext* cx, HandleValue v, EvalType evalType,
} }
frontend::EvalScriptInfo info(cx, options, env, enclosing); frontend::EvalScriptInfo info(cx, options, env, enclosing);
JSScript* compiled = frontend::CompileEvalScript(info, srcBuf); RootedScript compiled(cx, frontend::CompileEvalScript(info, srcBuf));
if (!compiled) { if (!compiled) {
return false; return false;
} }

View File

@@ -1679,8 +1679,15 @@ JSObject* js::CallModuleResolveHook(JSContext* cx,
} }
JSObject* js::StartDynamicModuleImport(JSContext* cx, JSObject* js::StartDynamicModuleImport(JSContext* cx,
HandleValue referencingPrivate, HandleObject referencingScriptSource,
HandleValue specifierArg) { HandleValue specifierArg) {
RootedValue referencingPrivate(cx);
if (referencingScriptSource) {
ScriptSourceObject* sso =
&UncheckedUnwrap(referencingScriptSource)->as<ScriptSourceObject>();
referencingPrivate = sso->canonicalPrivate();
}
RootedObject promiseConstructor(cx, JS::GetPromiseConstructor(cx)); RootedObject promiseConstructor(cx, JS::GetPromiseConstructor(cx));
if (!promiseConstructor) { if (!promiseConstructor) {
return nullptr; return nullptr;

View File

@@ -407,7 +407,7 @@ JSObject* CallModuleResolveHook(JSContext* cx, HandleValue referencingPrivate,
HandleString specifier); HandleString specifier);
JSObject* StartDynamicModuleImport(JSContext* cx, JSObject* StartDynamicModuleImport(JSContext* cx,
HandleValue referencingPrivate, HandleObject referencingScriptSource,
HandleValue specifier); HandleValue specifier);
bool FinishDynamicModuleImport(JSContext* cx, HandleValue referencingPrivate, bool FinishDynamicModuleImport(JSContext* cx, HandleValue referencingPrivate,

View File

@@ -0,0 +1,3 @@
// |jit-test| --more-compartments
fullcompartmentchecks(true);
newGlobal().eval(`import("javascript:")`).catch(() => {});

View File

@@ -5413,7 +5413,7 @@ bool BaselineCodeGen<Handler>::emit_JSOP_IMPORTMETA() {
return true; return true;
} }
typedef JSObject* (*StartDynamicModuleImportFn)(JSContext*, HandleValue, typedef JSObject* (*StartDynamicModuleImportFn)(JSContext*, HandleObject,
HandleValue); HandleValue);
static const VMFunction StartDynamicModuleImportInfo = static const VMFunction StartDynamicModuleImportInfo =
FunctionInfo<StartDynamicModuleImportFn>(js::StartDynamicModuleImport, FunctionInfo<StartDynamicModuleImportFn>(js::StartDynamicModuleImport,
@@ -5421,15 +5421,14 @@ static const VMFunction StartDynamicModuleImportInfo =
template <typename Handler> template <typename Handler>
bool BaselineCodeGen<Handler>::emit_JSOP_DYNAMIC_IMPORT() { bool BaselineCodeGen<Handler>::emit_JSOP_DYNAMIC_IMPORT() {
RootedValue referencingPrivate(cx, RootedObject referencingScriptSource(cx, script->sourceObject());
FindScriptOrModulePrivateForScript(script));
// Put specifier value in R0. // Put specifier value in R0.
frame.popRegsAndSync(1); frame.popRegsAndSync(1);
prepareVMCall(); prepareVMCall();
pushArg(R0); pushArg(R0);
pushArg(referencingPrivate); pushArg(ImmGCPtr(referencingScriptSource));
if (!callVM(StartDynamicModuleImportInfo)) { if (!callVM(StartDynamicModuleImportInfo)) {
return false; return false;
} }

View File

@@ -2982,7 +2982,7 @@ void CodeGenerator::visitModuleMetadata(LModuleMetadata* lir) {
callVM(GetOrCreateModuleMetaObjectInfo, lir); callVM(GetOrCreateModuleMetaObjectInfo, lir);
} }
typedef JSObject* (*StartDynamicModuleImportFn)(JSContext*, HandleValue, typedef JSObject* (*StartDynamicModuleImportFn)(JSContext*, HandleObject,
HandleValue); HandleValue);
static const VMFunction StartDynamicModuleImportInfo = static const VMFunction StartDynamicModuleImportInfo =
FunctionInfo<StartDynamicModuleImportFn>(js::StartDynamicModuleImport, FunctionInfo<StartDynamicModuleImportFn>(js::StartDynamicModuleImport,
@@ -2990,7 +2990,7 @@ static const VMFunction StartDynamicModuleImportInfo =
void CodeGenerator::visitDynamicImport(LDynamicImport* lir) { void CodeGenerator::visitDynamicImport(LDynamicImport* lir) {
pushArg(ToValue(lir, LDynamicImport::SpecifierIndex)); pushArg(ToValue(lir, LDynamicImport::SpecifierIndex));
pushArg(ToValue(lir, LDynamicImport::ReferencingPrivateIndex)); pushArg(ImmGCPtr(lir->mir()->referencingScriptSource()));
callVM(StartDynamicModuleImportInfo, lir); callVM(StartDynamicModuleImportInfo, lir);
} }

View File

@@ -13675,12 +13675,11 @@ AbortReasonOr<Ok> IonBuilder::jsop_importmeta() {
} }
AbortReasonOr<Ok> IonBuilder::jsop_dynamic_import() { AbortReasonOr<Ok> IonBuilder::jsop_dynamic_import() {
Value referencingPrivate = FindScriptOrModulePrivateForScript(script()); JSObject* referencingScriptSource = script()->sourceObject();
MConstant* ref = constant(referencingPrivate);
MDefinition* specifier = current->pop(); MDefinition* specifier = current->pop();
MDynamicImport* ins = MDynamicImport::New(alloc(), ref, specifier); MDynamicImport* ins = MDynamicImport::New(alloc(), referencingScriptSource, specifier);
current->add(ins); current->add(ins);
current->push(ins); current->push(ins);
return resumeAfter(ins); return resumeAfter(ins);

View File

@@ -2372,8 +2372,7 @@ void LIRGenerator::visitModuleMetadata(MModuleMetadata* ins) {
void LIRGenerator::visitDynamicImport(MDynamicImport* ins) { void LIRGenerator::visitDynamicImport(MDynamicImport* ins) {
LDynamicImport* lir = LDynamicImport* lir =
new (alloc()) LDynamicImport(useBoxAtStart(ins->referencingPrivate()), new (alloc()) LDynamicImport(useBoxAtStart(ins->specifier()));
useBoxAtStart(ins->specifier()));
defineReturn(lir, ins); defineReturn(lir, ins);
assignSafepoint(lir, ins); assignSafepoint(lir, ins);
} }

View File

@@ -6607,18 +6607,26 @@ class MModuleMetadata : public MNullaryInstruction {
} }
}; };
class MDynamicImport : public MBinaryInstruction, public BoxInputsPolicy::Data { class MDynamicImport : public MUnaryInstruction, public BoxInputsPolicy::Data {
explicit MDynamicImport(MDefinition* referencingPrivate, CompilerObject referencingScriptSource_;
explicit MDynamicImport(JSObject* referencingScriptSource,
MDefinition* specifier) MDefinition* specifier)
: MBinaryInstruction(classOpcode, referencingPrivate, specifier) { : MUnaryInstruction(classOpcode, specifier),
referencingScriptSource_(referencingScriptSource) {
setResultType(MIRType::Object); setResultType(MIRType::Object);
} }
public: public:
INSTRUCTION_HEADER(DynamicImport) INSTRUCTION_HEADER(DynamicImport)
TRIVIAL_NEW_WRAPPERS TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, referencingPrivate)) NAMED_OPERANDS((0, specifier))
NAMED_OPERANDS((1, specifier))
JSObject* referencingScriptSource() const { return referencingScriptSource_; }
bool appendRoots(MRootList& roots) const override {
return roots.append(referencingScriptSource_);
}
}; };
struct LambdaFunctionInfo { struct LambdaFunctionInfo {

View File

@@ -3546,17 +3546,14 @@ class LModuleMetadata : public LCallInstructionHelper<1, 0, 0> {
LModuleMetadata() : LCallInstructionHelper(classOpcode) {} LModuleMetadata() : LCallInstructionHelper(classOpcode) {}
}; };
class LDynamicImport : public LCallInstructionHelper<1, 2 * BOX_PIECES, 0> { class LDynamicImport : public LCallInstructionHelper<1, BOX_PIECES, 0> {
public: public:
LIR_HEADER(DynamicImport) LIR_HEADER(DynamicImport)
static const size_t ReferencingPrivateIndex = 0; static const size_t SpecifierIndex = 0;
static const size_t SpecifierIndex = BOX_PIECES;
explicit LDynamicImport(const LBoxAllocation& referencingPrivate, explicit LDynamicImport(const LBoxAllocation& specifier)
const LBoxAllocation& specifier)
: LCallInstructionHelper(classOpcode) { : LCallInstructionHelper(classOpcode) {
setBoxOperand(ReferencingPrivateIndex, referencingPrivate);
setBoxOperand(SpecifierIndex, specifier); setBoxOperand(SpecifierIndex, specifier);
} }

View File

@@ -3439,7 +3439,8 @@ JS::OwningCompileOptions::OwningCompileOptions(JSContext* cx)
: ReadOnlyCompileOptions(), : ReadOnlyCompileOptions(),
elementRoot(cx), elementRoot(cx),
elementAttributeNameRoot(cx), elementAttributeNameRoot(cx),
introductionScriptRoot(cx) {} introductionScriptRoot(cx),
scriptOrModuleRoot(cx) {}
JS::OwningCompileOptions::~OwningCompileOptions() { JS::OwningCompileOptions::~OwningCompileOptions() {
// OwningCompileOptions always owns these, so these casts are okay. // OwningCompileOptions always owns these, so these casts are okay.
@@ -3461,6 +3462,7 @@ bool JS::OwningCompileOptions::copy(JSContext* cx,
setElement(rhs.element()); setElement(rhs.element());
setElementAttributeName(rhs.elementAttributeName()); setElementAttributeName(rhs.elementAttributeName());
setIntroductionScript(rhs.introductionScript()); setIntroductionScript(rhs.introductionScript());
setScriptOrModule(rhs.scriptOrModule());
return setFileAndLine(cx, rhs.filename(), rhs.lineno) && return setFileAndLine(cx, rhs.filename(), rhs.lineno) &&
setSourceMapURL(cx, rhs.sourceMapURL()) && setSourceMapURL(cx, rhs.sourceMapURL()) &&
@@ -3531,7 +3533,8 @@ JS::CompileOptions::CompileOptions(JSContext* cx)
: ReadOnlyCompileOptions(), : ReadOnlyCompileOptions(),
elementRoot(cx), elementRoot(cx),
elementAttributeNameRoot(cx), elementAttributeNameRoot(cx),
introductionScriptRoot(cx) { introductionScriptRoot(cx),
scriptOrModuleRoot(cx) {
strictOption = cx->options().strictMode(); strictOption = cx->options().strictMode();
extraWarningsOption = cx->realm()->behaviors().extraWarnings(cx); extraWarningsOption = cx->realm()->behaviors().extraWarnings(cx);
isProbablySystemCode = cx->realm()->isProbablySystemCode(); isProbablySystemCode = cx->realm()->isProbablySystemCode();
@@ -3721,7 +3724,8 @@ JS_PUBLIC_API bool JS::CompileModule(JSContext* cx,
JS_PUBLIC_API void JS::SetModulePrivate(JSObject* module, JS_PUBLIC_API void JS::SetModulePrivate(JSObject* module,
const JS::Value& value) { const JS::Value& value) {
module->as<ModuleObject>().scriptSourceObject()->setPrivate(value); JSRuntime* rt = module->zone()->runtimeFromMainThread();
module->as<ModuleObject>().scriptSourceObject()->setPrivate(rt, value);
} }
JS_PUBLIC_API JS::Value JS::GetModulePrivate(JSObject* module) { JS_PUBLIC_API JS::Value JS::GetModulePrivate(JSObject* module) {
@@ -3730,7 +3734,8 @@ JS_PUBLIC_API JS::Value JS::GetModulePrivate(JSObject* module) {
JS_PUBLIC_API void JS::SetScriptPrivate(JSScript* script, JS_PUBLIC_API void JS::SetScriptPrivate(JSScript* script,
const JS::Value& value) { const JS::Value& value) {
script->sourceObject()->setPrivate(value); JSRuntime* rt = script->zone()->runtimeFromMainThread();
script->sourceObject()->setPrivate(rt, value);
} }
JS_PUBLIC_API JS::Value JS::GetScriptPrivate(JSScript* script) { JS_PUBLIC_API JS::Value JS::GetScriptPrivate(JSScript* script) {
@@ -3746,19 +3751,16 @@ JS_PUBLIC_API JS::Value JS::GetScriptedCallerPrivate(JSContext* cx) {
return UndefinedValue(); return UndefinedValue();
} }
return FindScriptOrModulePrivateForScript(iter.script()); return iter.script()->sourceObject()->canonicalPrivate();
} }
JS_PUBLIC_API JS::ScriptPrivateFinalizeHook JS::GetScriptPrivateFinalizeHook( JS_PUBLIC_API void JS::SetScriptPrivateReferenceHooks(
JSRuntime* rt) { JSRuntime* rt,
JS::ScriptPrivateReferenceHook addRefHook,
JS::ScriptPrivateReferenceHook releaseHook) {
AssertHeapIsIdle(); AssertHeapIsIdle();
return rt->scriptPrivateFinalizeHook; rt->scriptPrivateAddRefHook = addRefHook;
} rt->scriptPrivateReleaseHook = releaseHook;
JS_PUBLIC_API void JS::SetScriptPrivateFinalizeHook(
JSRuntime* rt, JS::ScriptPrivateFinalizeHook func) {
AssertHeapIsIdle();
rt->scriptPrivateFinalizeHook = func;
} }
JS_PUBLIC_API bool JS::ModuleInstantiate(JSContext* cx, JS_PUBLIC_API bool JS::ModuleInstantiate(JSContext* cx,

View File

@@ -2575,24 +2575,19 @@ extern JS_PUBLIC_API JS::Value GetScriptPrivate(JSScript* script);
extern JS_PUBLIC_API JS::Value GetScriptedCallerPrivate(JSContext* cx); extern JS_PUBLIC_API JS::Value GetScriptedCallerPrivate(JSContext* cx);
/** /**
* A hook that's called whenever a script or module which has a private value * Hooks called when references to a script private value are created or
* set with SetScriptPrivate() or SetModulePrivate() is finalized. This can be * destroyed. This allows use of a reference counted object as the
* used to clean up the private state. The private value is passed as an * script private.
* argument.
*/ */
using ScriptPrivateFinalizeHook = void (*)(JSFreeOp*, const JS::Value&); using ScriptPrivateReferenceHook = void (*)(const JS::Value&);
/**
* Get the script private finalize hook for the runtime.
*/
extern JS_PUBLIC_API ScriptPrivateFinalizeHook
GetScriptPrivateFinalizeHook(JSRuntime* rt);
/** /**
* Set the script private finalize hook for the runtime to the given function. * Set the script private finalize hook for the runtime to the given function.
*/ */
extern JS_PUBLIC_API void SetScriptPrivateFinalizeHook( extern JS_PUBLIC_API void SetScriptPrivateReferenceHooks(
JSRuntime* rt, ScriptPrivateFinalizeHook func); JSRuntime* rt,
ScriptPrivateReferenceHook addRefHook,
ScriptPrivateReferenceHook releaseHook);
/* /*
* Perform the ModuleInstantiate operation on the given source text module * Perform the ModuleInstantiate operation on the given source text module

View File

@@ -3367,23 +3367,6 @@ ModuleObject* js::GetModuleObjectForScript(JSScript* script) {
return nullptr; return nullptr;
} }
Value js::FindScriptOrModulePrivateForScript(JSScript* script) {
MOZ_ASSERT(script);
ScriptSourceObject* sso = script->sourceObject();
while (sso) {
Value value = sso->canonicalPrivate();
if (!value.isUndefined()) {
return value;
}
ScriptSourceObject* parent = sso->unwrappedIntroductionSourceObject();
MOZ_ASSERT(parent != sso);
sso = parent;
}
return UndefinedValue();
}
bool js::GetThisValueForDebuggerMaybeOptimizedOut(JSContext* cx, bool js::GetThisValueForDebuggerMaybeOptimizedOut(JSContext* cx,
AbstractFramePtr frame, AbstractFramePtr frame,
jsbytecode* pc, jsbytecode* pc,

View File

@@ -1149,8 +1149,6 @@ extern bool CreateObjectsForEnvironmentChain(JSContext* cx,
ModuleObject* GetModuleObjectForScript(JSScript* script); ModuleObject* GetModuleObjectForScript(JSScript* script);
Value FindScriptOrModulePrivateForScript(JSScript* script);
ModuleEnvironmentObject* GetModuleEnvironmentForScript(JSScript* script); ModuleEnvironmentObject* GetModuleEnvironmentForScript(JSScript* script);
MOZ_MUST_USE bool GetThisValueForDebuggerMaybeOptimizedOut( MOZ_MUST_USE bool GetThisValueForDebuggerMaybeOptimizedOut(

View File

@@ -4259,14 +4259,14 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
END_CASE(JSOP_IMPORTMETA) END_CASE(JSOP_IMPORTMETA)
CASE(JSOP_DYNAMIC_IMPORT) { CASE(JSOP_DYNAMIC_IMPORT) {
ReservedRooted<Value> referencingPrivate(&rootValue0); ReservedRooted<JSObject*> referencingScriptSource(&rootObject0);
referencingPrivate = FindScriptOrModulePrivateForScript(script); referencingScriptSource = script->sourceObject();
ReservedRooted<Value> specifier(&rootValue1); ReservedRooted<Value> specifier(&rootValue1);
POP_COPY_TO(specifier); POP_COPY_TO(specifier);
JSObject* promise = JSObject* promise =
StartDynamicModuleImport(cx, referencingPrivate, specifier); StartDynamicModuleImport(cx, referencingScriptSource, specifier);
if (!promise) goto error; if (!promise) goto error;
PUSH_OBJECT(*promise); PUSH_OBJECT(*promise);

View File

@@ -1851,7 +1851,8 @@ static bool CreateDynamicFunction(JSContext* cx, const CallArgs& args,
.setFileAndLine(filename, 1) .setFileAndLine(filename, 1)
.setNoScriptRval(false) .setNoScriptRval(false)
.setIntroductionInfo(introducerFilename, introductionType, lineno, .setIntroductionInfo(introducerFilename, introductionType, lineno,
maybeScript, pcOffset); maybeScript, pcOffset)
.setScriptOrModule(maybeScript);
StringBuffer sb(cx); StringBuffer sb(cx);

View File

@@ -1318,15 +1318,8 @@ void ScriptSourceObject::finalize(FreeOp* fop, JSObject* obj) {
ScriptSourceObject* sso = &obj->as<ScriptSourceObject>(); ScriptSourceObject* sso = &obj->as<ScriptSourceObject>();
sso->source()->decref(); sso->source()->decref();
Value value = sso->canonicalPrivate(); // Clear the private value, calling the release hook if necessary.
if (!value.isUndefined()) { sso->setPrivate(fop->runtime(), UndefinedValue());
// The embedding may need to dispose of its private data.
JS::AutoSuppressGCAnalysis suppressGC;
if (JS::ScriptPrivateFinalizeHook hook =
fop->runtime()->scriptPrivateFinalizeHook) {
hook(fop, value);
}
}
} }
void ScriptSourceObject::trace(JSTracer* trc, JSObject* obj) { void ScriptSourceObject::trace(JSTracer* trc, JSObject* obj) {
@@ -1382,8 +1375,6 @@ ScriptSourceObject* ScriptSourceObject::createInternal(JSContext* cx,
obj->initReservedSlot(ELEMENT_SLOT, MagicValue(JS_GENERIC_MAGIC)); obj->initReservedSlot(ELEMENT_SLOT, MagicValue(JS_GENERIC_MAGIC));
obj->initReservedSlot(ELEMENT_PROPERTY_SLOT, MagicValue(JS_GENERIC_MAGIC)); obj->initReservedSlot(ELEMENT_PROPERTY_SLOT, MagicValue(JS_GENERIC_MAGIC));
obj->initReservedSlot(INTRODUCTION_SCRIPT_SLOT, MagicValue(JS_GENERIC_MAGIC)); obj->initReservedSlot(INTRODUCTION_SCRIPT_SLOT, MagicValue(JS_GENERIC_MAGIC));
obj->initReservedSlot(INTRODUCTION_SOURCE_OBJECT_SLOT,
MagicValue(JS_GENERIC_MAGIC));
return obj; return obj;
} }
@@ -1422,8 +1413,6 @@ ScriptSourceObject* ScriptSourceObject::unwrappedCanonical() const {
source->getReservedSlot(ELEMENT_PROPERTY_SLOT).isMagic(JS_GENERIC_MAGIC)); source->getReservedSlot(ELEMENT_PROPERTY_SLOT).isMagic(JS_GENERIC_MAGIC));
MOZ_ASSERT(source->getReservedSlot(INTRODUCTION_SCRIPT_SLOT) MOZ_ASSERT(source->getReservedSlot(INTRODUCTION_SCRIPT_SLOT)
.isMagic(JS_GENERIC_MAGIC)); .isMagic(JS_GENERIC_MAGIC));
MOZ_ASSERT(source->getReservedSlot(INTRODUCTION_SOURCE_OBJECT_SLOT)
.isMagic(JS_GENERIC_MAGIC));
RootedObject element(cx, options.element()); RootedObject element(cx, options.element());
RootedString elementAttributeName(cx, options.elementAttributeName()); RootedString elementAttributeName(cx, options.elementAttributeName());
@@ -1435,19 +1424,24 @@ ScriptSourceObject* ScriptSourceObject::unwrappedCanonical() const {
// introduction script and ScriptSourceObject are in different compartments, // introduction script and ScriptSourceObject are in different compartments,
// we would be creating a cross-compartment script reference, which is // we would be creating a cross-compartment script reference, which is
// forbidden. We can still store a CCW to the script source object though. // forbidden. We can still store a CCW to the script source object though.
RootedValue introdutionScript(cx); RootedValue introductionScript(cx);
RootedValue introdutionSource(cx); if (JSScript* script = options.introductionScript()) {
if (options.introductionScript()) { if (script->compartment() == cx->compartment()) {
if (options.introductionScript()->compartment() == cx->compartment()) { introductionScript.setPrivateGCThing(options.introductionScript());
introdutionScript.setPrivateGCThing(options.introductionScript());
} }
introdutionSource.setObject(*options.introductionScript()->sourceObject()); }
if (!cx->compartment()->wrap(cx, &introdutionSource)) { source->setReservedSlot(INTRODUCTION_SCRIPT_SLOT, introductionScript);
// Set the private value to that of the script or module that this source is
// part of, if any.
RootedValue privateValue(cx);
if (JSScript* script = options.scriptOrModule()) {
privateValue = script->sourceObject()->canonicalPrivate();
if (!JS_WrapValue(cx, &privateValue)) {
return false; return false;
} }
} }
source->setReservedSlot(INTRODUCTION_SCRIPT_SLOT, introdutionScript); source->setPrivate(cx->runtime(), privateValue);
source->setReservedSlot(INTRODUCTION_SOURCE_OBJECT_SLOT, introdutionSource);
return true; return true;
} }
@@ -1476,6 +1470,25 @@ ScriptSourceObject* ScriptSourceObject::unwrappedCanonical() const {
return true; return true;
} }
void ScriptSourceObject::setPrivate(JSRuntime* rt, const Value& value) {
// Update the private value, calling addRef/release hooks if necessary
// to allow the embedding to maintain a reference count for the
// private data.
JS::AutoSuppressGCAnalysis nogc;
Value prevValue = getReservedSlot(PRIVATE_SLOT);
if (!prevValue.isUndefined()) {
if (auto releaseHook = rt->scriptPrivateReleaseHook) {
releaseHook(prevValue);
}
}
setReservedSlot(PRIVATE_SLOT, value);
if (!value.isUndefined()) {
if (auto addRefHook = rt->scriptPrivateAddRefHook) {
addRefHook(value);
}
}
}
/* static */ bool JSScript::loadSource(JSContext* cx, ScriptSource* ss, /* static */ bool JSScript::loadSource(JSContext* cx, ScriptSource* ss,
bool* worked) { bool* worked) {
MOZ_ASSERT(!ss->hasSourceText()); MOZ_ASSERT(!ss->hasSourceText());

View File

@@ -1189,19 +1189,8 @@ class ScriptSourceObject : public NativeObject {
} }
return value.toGCThing()->as<JSScript>(); return value.toGCThing()->as<JSScript>();
} }
ScriptSourceObject* unwrappedIntroductionSourceObject() const {
Value value =
unwrappedCanonical()->getReservedSlot(INTRODUCTION_SOURCE_OBJECT_SLOT);
if (value.isUndefined()) {
return nullptr;
}
return &UncheckedUnwrap(&value.toObject())->as<ScriptSourceObject>();
}
void setPrivate(const Value& value) { void setPrivate(JSRuntime* rt, const Value& value);
MOZ_ASSERT(isCanonical());
setReservedSlot(PRIVATE_SLOT, value);
}
Value canonicalPrivate() const { Value canonicalPrivate() const {
Value value = getReservedSlot(PRIVATE_SLOT); Value value = getReservedSlot(PRIVATE_SLOT);
@@ -1216,7 +1205,6 @@ class ScriptSourceObject : public NativeObject {
ELEMENT_SLOT, ELEMENT_SLOT,
ELEMENT_PROPERTY_SLOT, ELEMENT_PROPERTY_SLOT,
INTRODUCTION_SCRIPT_SLOT, INTRODUCTION_SCRIPT_SLOT,
INTRODUCTION_SOURCE_OBJECT_SLOT,
PRIVATE_SLOT, PRIVATE_SLOT,
RESERVED_SLOTS RESERVED_SLOTS
}; };

View File

@@ -162,7 +162,8 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
moduleResolveHook(), moduleResolveHook(),
moduleMetadataHook(), moduleMetadataHook(),
moduleDynamicImportHook(), moduleDynamicImportHook(),
scriptPrivateFinalizeHook() { scriptPrivateAddRefHook(),
scriptPrivateReleaseHook() {
JS_COUNT_CTOR(JSRuntime); JS_COUNT_CTOR(JSRuntime);
liveRuntimesCount++; liveRuntimesCount++;

View File

@@ -968,8 +968,9 @@ struct JSRuntime : public js::MallocProvider<JSRuntime> {
// module import and can accessed by off-thread parsing. // module import and can accessed by off-thread parsing.
mozilla::Atomic<JS::ModuleDynamicImportHook> moduleDynamicImportHook; mozilla::Atomic<JS::ModuleDynamicImportHook> moduleDynamicImportHook;
// A hook called on script finalization. // Hooks called when script private references are created and destroyed.
js::MainThreadData<JS::ScriptPrivateFinalizeHook> scriptPrivateFinalizeHook; js::MainThreadData<JS::ScriptPrivateReferenceHook> scriptPrivateAddRefHook;
js::MainThreadData<JS::ScriptPrivateReferenceHook> scriptPrivateReleaseHook;
public: public:
#if defined(JS_BUILD_BINAST) #if defined(JS_BUILD_BINAST)