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 42e20bac8f
commit f731989df0
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); }
void LoadedScript::AssociateWithScript(JSScript* aScript) {
// Set a JSScript's private value to point to this object and
// increment our reference count. This is decremented by
// HostFinalizeTopLevelScript() below when the JSScript dies.
// Set a JSScript's private value to point to this object. The JS engine will
// increment our reference count by calling HostAddRefTopLevelScript(). This
// is decremented by HostReleaseTopLevelScript() below when the JSScript dies.
MOZ_ASSERT(JS::GetScriptPrivate(aScript).isUndefined());
JS::SetScriptPrivate(aScript, JS::PrivateValue(this));
AddRef();
}
void HostFinalizeTopLevelScript(JSFreeOp* aFop, 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());
inline void CheckModuleScriptPrivate(LoadedScript* script, const JS::Value& aPrivate) {
#ifdef DEBUG
if (script->IsModuleScript()) {
JSObject* module = script->AsModuleScript()->mModuleRecord.unbarrieredGet();
MOZ_ASSERT_IF(module, JS::GetModulePrivate(module) == aPrivate);
}
#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();
}
@ -125,7 +136,6 @@ void ModuleScript::UnlinkModuleRecord() {
MOZ_ASSERT(JS::GetModulePrivate(mModuleRecord).toPrivate() == this);
JS::SetModulePrivate(mModuleRecord, JS::UndefinedValue());
mModuleRecord = nullptr;
Release();
}
}
@ -141,14 +151,14 @@ void ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord) {
mModuleRecord = aModuleRecord;
// Make module's host defined field point to this object and
// increment our reference count. This is decremented by
// UnlinkModuleRecord() above.
// Make module's host defined field point to this object. The JS engine will
// increment our reference count by calling HostAddRefTopLevelScript(). This
// is decremented when the field is cleared in UnlinkModuleRecord() above or
// when the module record dies.
MOZ_ASSERT(JS::GetModulePrivate(mModuleRecord).isUndefined());
JS::SetModulePrivate(mModuleRecord, JS::PrivateValue(this));
HoldJSObjects(this);
AddRef();
}
void ModuleScript::SetParseError(const JS::Value& aError) {

View File

@ -19,7 +19,8 @@ namespace dom {
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 ModuleScript;
@ -89,7 +90,7 @@ class ModuleScript final : public LoadedScript {
void UnlinkModuleRecord();
friend void HostFinalizeTopLevelScript(JSFreeOp*, const JS::Value&);
friend void CheckModuleScriptPrivate(LoadedScript*, const JS::Value&);
};
ClassicScript* LoadedScript::AsClassicScript() {

View File

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

View File

@ -145,6 +145,15 @@ class JS_PUBLIC_API TransitiveCompileOptions {
virtual JSString* elementAttributeName() 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:
void operator=(const TransitiveCompileOptions&) = delete;
};
@ -202,9 +211,10 @@ class JS_PUBLIC_API ReadOnlyCompileOptions : public TransitiveCompileOptions {
const char* filename() const { return filename_; }
const char* introducerFilename() const { return introducerFilename_; }
const char16_t* sourceMapURL() const { return sourceMapURL_; }
virtual JSObject* element() const override = 0;
virtual JSString* elementAttributeName() const override = 0;
virtual JSScript* introductionScript() const override = 0;
JSObject* element() const override = 0;
JSString* elementAttributeName() const override = 0;
JSScript* introductionScript() const override = 0;
JSScript* scriptOrModule() const override = 0;
private:
void operator=(const ReadOnlyCompileOptions&) = delete;
@ -227,6 +237,7 @@ class JS_PUBLIC_API OwningCompileOptions final : public ReadOnlyCompileOptions {
PersistentRooted<JSObject*> elementRoot;
PersistentRooted<JSString*> elementAttributeNameRoot;
PersistentRooted<JSScript*> introductionScriptRoot;
PersistentRooted<JSScript*> scriptOrModuleRoot;
public:
// A minimal constructor, for use with OwningCompileOptions::copy.
@ -240,6 +251,9 @@ class JS_PUBLIC_API OwningCompileOptions final : public ReadOnlyCompileOptions {
JSScript* introductionScript() const override {
return introductionScriptRoot;
}
JSScript* scriptOrModule() const override {
return scriptOrModuleRoot;
}
/** Set this to a copy of |rhs|. Return false on OOM. */
bool copy(JSContext* cx, const ReadOnlyCompileOptions& rhs);
@ -272,6 +286,11 @@ class JS_PUBLIC_API OwningCompileOptions final : public ReadOnlyCompileOptions {
return *this;
}
OwningCompileOptions& setScriptOrModule(JSScript* s) {
scriptOrModuleRoot = s;
return *this;
}
OwningCompileOptions& setMutedErrors(bool mute) {
mutedErrors_ = mute;
return *this;
@ -361,6 +380,7 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
Rooted<JSObject*> elementRoot;
Rooted<JSString*> elementAttributeNameRoot;
Rooted<JSScript*> introductionScriptRoot;
Rooted<JSScript*> scriptOrModuleRoot;
public:
explicit CompileOptions(JSContext* cx);
@ -369,7 +389,8 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
: ReadOnlyCompileOptions(),
elementRoot(cx),
elementAttributeNameRoot(cx),
introductionScriptRoot(cx) {
introductionScriptRoot(cx),
scriptOrModuleRoot(cx) {
copyPODOptions(rhs);
filename_ = rhs.filename();
@ -378,13 +399,15 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
elementRoot = rhs.element();
elementAttributeNameRoot = rhs.elementAttributeName();
introductionScriptRoot = rhs.introductionScript();
scriptOrModuleRoot = rhs.scriptOrModule();
}
CompileOptions(JSContext* cx, const TransitiveCompileOptions& rhs)
: ReadOnlyCompileOptions(),
elementRoot(cx),
elementAttributeNameRoot(cx),
introductionScriptRoot(cx) {
introductionScriptRoot(cx),
scriptOrModuleRoot(cx) {
copyPODTransitiveOptions(rhs);
filename_ = rhs.filename();
@ -393,6 +416,7 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
elementRoot = rhs.element();
elementAttributeNameRoot = rhs.elementAttributeName();
introductionScriptRoot = rhs.introductionScript();
scriptOrModuleRoot = rhs.scriptOrModule();
}
JSObject* element() const override { return elementRoot; }
@ -405,6 +429,10 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
return introductionScriptRoot;
}
JSScript* scriptOrModule() const override {
return scriptOrModuleRoot;
}
CompileOptions& setFile(const char* f) {
filename_ = f;
return *this;
@ -441,6 +469,11 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
return *this;
}
CompileOptions& setScriptOrModule(JSScript* s) {
scriptOrModuleRoot = s;
return *this;
}
CompileOptions& setMutedErrors(bool mute) {
mutedErrors_ = mute;
return *this;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3439,7 +3439,8 @@ JS::OwningCompileOptions::OwningCompileOptions(JSContext* cx)
: ReadOnlyCompileOptions(),
elementRoot(cx),
elementAttributeNameRoot(cx),
introductionScriptRoot(cx) {}
introductionScriptRoot(cx),
scriptOrModuleRoot(cx) {}
JS::OwningCompileOptions::~OwningCompileOptions() {
// OwningCompileOptions always owns these, so these casts are okay.
@ -3461,6 +3462,7 @@ bool JS::OwningCompileOptions::copy(JSContext* cx,
setElement(rhs.element());
setElementAttributeName(rhs.elementAttributeName());
setIntroductionScript(rhs.introductionScript());
setScriptOrModule(rhs.scriptOrModule());
return setFileAndLine(cx, rhs.filename(), rhs.lineno) &&
setSourceMapURL(cx, rhs.sourceMapURL()) &&
@ -3531,7 +3533,8 @@ JS::CompileOptions::CompileOptions(JSContext* cx)
: ReadOnlyCompileOptions(),
elementRoot(cx),
elementAttributeNameRoot(cx),
introductionScriptRoot(cx) {
introductionScriptRoot(cx),
scriptOrModuleRoot(cx) {
strictOption = cx->options().strictMode();
extraWarningsOption = cx->realm()->behaviors().extraWarnings(cx);
isProbablySystemCode = cx->realm()->isProbablySystemCode();
@ -3721,7 +3724,8 @@ JS_PUBLIC_API bool JS::CompileModule(JSContext* cx,
JS_PUBLIC_API void JS::SetModulePrivate(JSObject* module,
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) {
@ -3730,7 +3734,8 @@ JS_PUBLIC_API JS::Value JS::GetModulePrivate(JSObject* module) {
JS_PUBLIC_API void JS::SetScriptPrivate(JSScript* script,
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) {
@ -3746,19 +3751,16 @@ JS_PUBLIC_API JS::Value JS::GetScriptedCallerPrivate(JSContext* cx) {
return UndefinedValue();
}
return FindScriptOrModulePrivateForScript(iter.script());
return iter.script()->sourceObject()->canonicalPrivate();
}
JS_PUBLIC_API JS::ScriptPrivateFinalizeHook JS::GetScriptPrivateFinalizeHook(
JSRuntime* rt) {
JS_PUBLIC_API void JS::SetScriptPrivateReferenceHooks(
JSRuntime* rt,
JS::ScriptPrivateReferenceHook addRefHook,
JS::ScriptPrivateReferenceHook releaseHook) {
AssertHeapIsIdle();
return rt->scriptPrivateFinalizeHook;
}
JS_PUBLIC_API void JS::SetScriptPrivateFinalizeHook(
JSRuntime* rt, JS::ScriptPrivateFinalizeHook func) {
AssertHeapIsIdle();
rt->scriptPrivateFinalizeHook = func;
rt->scriptPrivateAddRefHook = addRefHook;
rt->scriptPrivateReleaseHook = releaseHook;
}
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);
/**
* A hook that's called whenever a script or module which has a private value
* set with SetScriptPrivate() or SetModulePrivate() is finalized. This can be
* used to clean up the private state. The private value is passed as an
* argument.
* Hooks called when references to a script private value are created or
* destroyed. This allows use of a reference counted object as the
* script private.
*/
using ScriptPrivateFinalizeHook = void (*)(JSFreeOp*, const JS::Value&);
/**
* Get the script private finalize hook for the runtime.
*/
extern JS_PUBLIC_API ScriptPrivateFinalizeHook
GetScriptPrivateFinalizeHook(JSRuntime* rt);
using ScriptPrivateReferenceHook = void (*)(const JS::Value&);
/**
* Set the script private finalize hook for the runtime to the given function.
*/
extern JS_PUBLIC_API void SetScriptPrivateFinalizeHook(
JSRuntime* rt, ScriptPrivateFinalizeHook func);
extern JS_PUBLIC_API void SetScriptPrivateReferenceHooks(
JSRuntime* rt,
ScriptPrivateReferenceHook addRefHook,
ScriptPrivateReferenceHook releaseHook);
/*
* Perform the ModuleInstantiate operation on the given source text module

View File

@ -3367,23 +3367,6 @@ ModuleObject* js::GetModuleObjectForScript(JSScript* script) {
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,
AbstractFramePtr frame,
jsbytecode* pc,

View File

@ -1149,8 +1149,6 @@ extern bool CreateObjectsForEnvironmentChain(JSContext* cx,
ModuleObject* GetModuleObjectForScript(JSScript* script);
Value FindScriptOrModulePrivateForScript(JSScript* script);
ModuleEnvironmentObject* GetModuleEnvironmentForScript(JSScript* script);
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)
CASE(JSOP_DYNAMIC_IMPORT) {
ReservedRooted<Value> referencingPrivate(&rootValue0);
referencingPrivate = FindScriptOrModulePrivateForScript(script);
ReservedRooted<JSObject*> referencingScriptSource(&rootObject0);
referencingScriptSource = script->sourceObject();
ReservedRooted<Value> specifier(&rootValue1);
POP_COPY_TO(specifier);
JSObject* promise =
StartDynamicModuleImport(cx, referencingPrivate, specifier);
StartDynamicModuleImport(cx, referencingScriptSource, specifier);
if (!promise) goto error;
PUSH_OBJECT(*promise);

View File

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

View File

@ -1318,15 +1318,8 @@ void ScriptSourceObject::finalize(FreeOp* fop, JSObject* obj) {
ScriptSourceObject* sso = &obj->as<ScriptSourceObject>();
sso->source()->decref();
Value value = sso->canonicalPrivate();
if (!value.isUndefined()) {
// The embedding may need to dispose of its private data.
JS::AutoSuppressGCAnalysis suppressGC;
if (JS::ScriptPrivateFinalizeHook hook =
fop->runtime()->scriptPrivateFinalizeHook) {
hook(fop, value);
}
}
// Clear the private value, calling the release hook if necessary.
sso->setPrivate(fop->runtime(), UndefinedValue());
}
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_PROPERTY_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;
}
@ -1422,8 +1413,6 @@ ScriptSourceObject* ScriptSourceObject::unwrappedCanonical() const {
source->getReservedSlot(ELEMENT_PROPERTY_SLOT).isMagic(JS_GENERIC_MAGIC));
MOZ_ASSERT(source->getReservedSlot(INTRODUCTION_SCRIPT_SLOT)
.isMagic(JS_GENERIC_MAGIC));
MOZ_ASSERT(source->getReservedSlot(INTRODUCTION_SOURCE_OBJECT_SLOT)
.isMagic(JS_GENERIC_MAGIC));
RootedObject element(cx, options.element());
RootedString elementAttributeName(cx, options.elementAttributeName());
@ -1435,19 +1424,24 @@ ScriptSourceObject* ScriptSourceObject::unwrappedCanonical() const {
// introduction script and ScriptSourceObject are in different compartments,
// we would be creating a cross-compartment script reference, which is
// forbidden. We can still store a CCW to the script source object though.
RootedValue introdutionScript(cx);
RootedValue introdutionSource(cx);
if (options.introductionScript()) {
if (options.introductionScript()->compartment() == cx->compartment()) {
introdutionScript.setPrivateGCThing(options.introductionScript());
RootedValue introductionScript(cx);
if (JSScript* script = options.introductionScript()) {
if (script->compartment() == cx->compartment()) {
introductionScript.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;
}
}
source->setReservedSlot(INTRODUCTION_SCRIPT_SLOT, introdutionScript);
source->setReservedSlot(INTRODUCTION_SOURCE_OBJECT_SLOT, introdutionSource);
source->setPrivate(cx->runtime(), privateValue);
return true;
}
@ -1476,6 +1470,25 @@ ScriptSourceObject* ScriptSourceObject::unwrappedCanonical() const {
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,
bool* worked) {
MOZ_ASSERT(!ss->hasSourceText());

View File

@ -1189,19 +1189,8 @@ class ScriptSourceObject : public NativeObject {
}
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) {
MOZ_ASSERT(isCanonical());
setReservedSlot(PRIVATE_SLOT, value);
}
void setPrivate(JSRuntime* rt, const Value& value);
Value canonicalPrivate() const {
Value value = getReservedSlot(PRIVATE_SLOT);
@ -1216,7 +1205,6 @@ class ScriptSourceObject : public NativeObject {
ELEMENT_SLOT,
ELEMENT_PROPERTY_SLOT,
INTRODUCTION_SCRIPT_SLOT,
INTRODUCTION_SOURCE_OBJECT_SLOT,
PRIVATE_SLOT,
RESERVED_SLOTS
};

View File

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

View File

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