mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 14:55:47 +00:00
Bug 1461938 part 23 - Move debugModeBits from JSCompartment to JS::Realm. r=luke
This commit is contained in:
parent
eea98b6d64
commit
4975a53b6d
@ -164,7 +164,7 @@ mozilla::Atomic<uint64_t> gIDGenerator(0);
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
ShouldCaptureDebugInfo(JSContext* cx)
|
||||
{
|
||||
return cx->options().asyncStack() || cx->compartment()->isDebuggee();
|
||||
return cx->options().asyncStack() || cx->realm()->isDebuggee();
|
||||
}
|
||||
|
||||
class PromiseDebugInfo : public NativeObject
|
||||
@ -3067,8 +3067,8 @@ IsPromiseThenOrCatchRetValImplicitlyUsed(JSContext* cx)
|
||||
if (!cx->options().asyncStack())
|
||||
return false;
|
||||
|
||||
// If devtools is opened, the current compartment will become debuggee.
|
||||
if (cx->compartment()->isDebuggee())
|
||||
// If devtools is opened, the current realm will become debuggee.
|
||||
if (cx->realm()->isDebuggee())
|
||||
return true;
|
||||
|
||||
// There are 2 profilers, and they can be independently enabled.
|
||||
|
@ -8014,13 +8014,13 @@ GCRuntime::mergeCompartments(JSCompartment* source, JSCompartment* target)
|
||||
|
||||
sourceRealm->clearTables();
|
||||
source->zone()->clearTables();
|
||||
source->unsetIsDebuggee();
|
||||
sourceRealm->unsetIsDebuggee();
|
||||
|
||||
// The delazification flag indicates the presence of LazyScripts in a
|
||||
// compartment for the Debugger API, so if the source compartment created
|
||||
// LazyScripts, the flag must be propagated to the target compartment.
|
||||
if (source->needsDelazificationForDebugger())
|
||||
target->scheduleDelazificationForDebugger();
|
||||
// realm for the Debugger API, so if the source realm created LazyScripts,
|
||||
// the flag must be propagated to the target realm.
|
||||
if (sourceRealm->needsDelazificationForDebugger())
|
||||
targetRealm->scheduleDelazificationForDebugger();
|
||||
|
||||
// Release any relocated arenas which we may be holding on to as they might
|
||||
// be in the source zone
|
||||
|
@ -986,7 +986,7 @@ InitFromBailout(JSContext* cx, size_t frameNo,
|
||||
// possible nothing was pushed before we threw. We can't drop
|
||||
// iterators, however, so read them out. They will be closed by
|
||||
// HandleExceptionBaseline.
|
||||
MOZ_ASSERT(cx->compartment()->isDebuggee());
|
||||
MOZ_ASSERT(cx->realm()->isDebuggee());
|
||||
if (iter.moreFrames() || HasLiveStackValueAtDepth(script, pc, i + 1)) {
|
||||
v = iter.read();
|
||||
} else {
|
||||
|
@ -104,7 +104,7 @@ BaselineCompiler::compile()
|
||||
// When code coverage is only enabled for optimizations, or when a Debugger
|
||||
// set the collectCoverageInfo flag, we have to create the ScriptCounts if
|
||||
// they do not exist.
|
||||
if (!script->hasScriptCounts() && cx->compartment()->collectCoverage()) {
|
||||
if (!script->hasScriptCounts() && cx->realm()->collectCoverage()) {
|
||||
if (!script->initScriptCounts(cx))
|
||||
return Method_Error;
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ static void
|
||||
HandleExceptionIon(JSContext* cx, const InlineFrameIterator& frame, ResumeFromException* rfe,
|
||||
bool* overrecursed)
|
||||
{
|
||||
if (cx->compartment()->isDebuggee()) {
|
||||
if (cx->realm()->isDebuggee()) {
|
||||
// We need to bail when there is a catchable exception, and we are the
|
||||
// debuggee of a Debugger with a live onExceptionUnwind hook, or if a
|
||||
// Debugger has observed this frame (e.g., for onPop).
|
||||
@ -652,7 +652,7 @@ HandleException(ResumeFromException* rfe)
|
||||
bool invalidated = frame.checkInvalidation(&ionScript);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (logger && cx->compartment()->isDebuggee() && logger->enabled()) {
|
||||
if (logger && cx->realm()->isDebuggee() && logger->enabled()) {
|
||||
logger->disable(/* force = */ true,
|
||||
"Forcefully disabled tracelogger, due to "
|
||||
"throwing an exception with an active Debugger "
|
||||
|
@ -1136,7 +1136,7 @@ bool
|
||||
GlobalHasLiveOnDebuggerStatement(JSContext* cx)
|
||||
{
|
||||
AutoUnsafeCallWithABI unsafe;
|
||||
return cx->compartment()->isDebuggee() &&
|
||||
return cx->realm()->isDebuggee() &&
|
||||
Debugger::hasLiveHook(cx->global(), Debugger::OnDebuggerStatement);
|
||||
}
|
||||
|
||||
@ -1191,7 +1191,7 @@ bool
|
||||
DebugLeaveLexicalEnv(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
|
||||
{
|
||||
MOZ_ASSERT(frame->script()->baselineScript()->hasDebugInstrumentation());
|
||||
if (cx->compartment()->isDebuggee())
|
||||
if (cx->realm()->isDebuggee())
|
||||
DebugEnvironments::onPopLexical(cx, frame, pc);
|
||||
return true;
|
||||
}
|
||||
|
@ -4069,7 +4069,7 @@ JS::CompileOptions::CompileOptions(JSContext* cx)
|
||||
werrorOption = cx->options().werror();
|
||||
if (!cx->options().asmJS())
|
||||
asmJSOption = AsmJSOption::Disabled;
|
||||
else if (cx->compartment()->debuggerObservesAsmJS())
|
||||
else if (cx->realm()->debuggerObservesAsmJS())
|
||||
asmJSOption = AsmJSOption::DisabledByDebugger;
|
||||
else
|
||||
asmJSOption = AsmJSOption::Enabled;
|
||||
|
@ -36,7 +36,7 @@ js::Debugger::fromJSObject(const JSObject* obj)
|
||||
/* static */ inline bool
|
||||
js::Debugger::checkNoExecute(JSContext* cx, HandleScript script)
|
||||
{
|
||||
if (!cx->compartment()->isDebuggee() || !cx->noExecuteDebuggerTop)
|
||||
if (!cx->realm()->isDebuggee() || !cx->noExecuteDebuggerTop)
|
||||
return true;
|
||||
return slowPathCheckNoExecute(cx, script);
|
||||
}
|
||||
@ -53,7 +53,7 @@ js::Debugger::onEnterFrame(JSContext* cx, AbstractFramePtr frame)
|
||||
/* static */ js::ResumeMode
|
||||
js::Debugger::onDebuggerStatement(JSContext* cx, AbstractFramePtr frame)
|
||||
{
|
||||
if (!cx->compartment()->isDebuggee())
|
||||
if (!cx->realm()->isDebuggee())
|
||||
return ResumeMode::Continue;
|
||||
return slowPathOnDebuggerStatement(cx, frame);
|
||||
}
|
||||
@ -61,7 +61,7 @@ js::Debugger::onDebuggerStatement(JSContext* cx, AbstractFramePtr frame)
|
||||
/* static */ js::ResumeMode
|
||||
js::Debugger::onExceptionUnwind(JSContext* cx, AbstractFramePtr frame)
|
||||
{
|
||||
if (!cx->compartment()->isDebuggee())
|
||||
if (!cx->realm()->isDebuggee())
|
||||
return ResumeMode::Continue;
|
||||
return slowPathOnExceptionUnwind(cx, frame);
|
||||
}
|
||||
@ -69,21 +69,21 @@ js::Debugger::onExceptionUnwind(JSContext* cx, AbstractFramePtr frame)
|
||||
/* static */ void
|
||||
js::Debugger::onNewWasmInstance(JSContext* cx, Handle<WasmInstanceObject*> wasmInstance)
|
||||
{
|
||||
if (cx->compartment()->isDebuggee())
|
||||
if (cx->realm()->isDebuggee())
|
||||
slowPathOnNewWasmInstance(cx, wasmInstance);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
js::Debugger::onNewPromise(JSContext* cx, Handle<PromiseObject*> promise)
|
||||
{
|
||||
if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
|
||||
if (MOZ_UNLIKELY(cx->realm()->isDebuggee()))
|
||||
slowPathPromiseHook(cx, Debugger::OnNewPromise, promise);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
js::Debugger::onPromiseSettled(JSContext* cx, Handle<PromiseObject*> promise)
|
||||
{
|
||||
if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
|
||||
if (MOZ_UNLIKELY(cx->realm()->isDebuggee()))
|
||||
slowPathPromiseHook(cx, Debugger::OnPromiseSettled, promise);
|
||||
}
|
||||
|
||||
|
@ -278,25 +278,25 @@ ValueToIdentifier(JSContext* cx, HandleValue v, MutableHandleId id)
|
||||
return true;
|
||||
}
|
||||
|
||||
class AutoRestoreCompartmentDebugMode
|
||||
class js::AutoRestoreRealmDebugMode
|
||||
{
|
||||
JSCompartment* comp_;
|
||||
Realm* realm_;
|
||||
unsigned bits_;
|
||||
|
||||
public:
|
||||
explicit AutoRestoreCompartmentDebugMode(JSCompartment* comp)
|
||||
: comp_(comp), bits_(comp->debugModeBits)
|
||||
explicit AutoRestoreRealmDebugMode(Realm* realm)
|
||||
: realm_(realm), bits_(realm->debugModeBits_)
|
||||
{
|
||||
MOZ_ASSERT(comp_);
|
||||
MOZ_ASSERT(realm_);
|
||||
}
|
||||
|
||||
~AutoRestoreCompartmentDebugMode() {
|
||||
if (comp_)
|
||||
comp_->debugModeBits = bits_;
|
||||
~AutoRestoreRealmDebugMode() {
|
||||
if (realm_)
|
||||
realm_->debugModeBits_ = bits_;
|
||||
}
|
||||
|
||||
void release() {
|
||||
comp_ = nullptr;
|
||||
realm_ = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
@ -418,7 +418,7 @@ class MOZ_RAII js::LeaveDebuggeeNoExecute
|
||||
/* static */ bool
|
||||
Debugger::slowPathCheckNoExecute(JSContext* cx, HandleScript script)
|
||||
{
|
||||
MOZ_ASSERT(cx->compartment()->isDebuggee());
|
||||
MOZ_ASSERT(cx->realm()->isDebuggee());
|
||||
MOZ_ASSERT(cx->noExecuteDebuggerTop);
|
||||
return EnterDebuggeeNoExecute::reportIfFoundInStack(cx, script);
|
||||
}
|
||||
@ -2367,35 +2367,36 @@ Debugger::slowPathPromiseHook(JSContext* cx, Hook hook, Handle<PromiseObject*> p
|
||||
|
||||
/*** Debugger code invalidation for observing execution ******************************************/
|
||||
|
||||
class MOZ_RAII ExecutionObservableCompartments : public Debugger::ExecutionObservableSet
|
||||
class MOZ_RAII ExecutionObservableRealms : public Debugger::ExecutionObservableSet
|
||||
{
|
||||
HashSet<JSCompartment*> compartments_;
|
||||
HashSet<Realm*> realms_;
|
||||
HashSet<Zone*> zones_;
|
||||
|
||||
public:
|
||||
explicit ExecutionObservableCompartments(JSContext* cx
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: compartments_(cx),
|
||||
explicit ExecutionObservableRealms(JSContext* cx
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: realms_(cx),
|
||||
zones_(cx)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
bool init() { return compartments_.init() && zones_.init(); }
|
||||
bool add(JSCompartment* comp) { return compartments_.put(comp) && zones_.put(comp->zone()); }
|
||||
bool init() { return realms_.init() && zones_.init(); }
|
||||
bool add(Realm* realm) { return realms_.put(realm) && zones_.put(realm->zone()); }
|
||||
|
||||
typedef HashSet<JSCompartment*>::Range CompartmentRange;
|
||||
const HashSet<JSCompartment*>* compartments() const { return &compartments_; }
|
||||
using RealmRange = HashSet<Realm*>::Range;
|
||||
const HashSet<Realm*>* realms() const { return &realms_; }
|
||||
|
||||
const HashSet<Zone*>* zones() const override { return &zones_; }
|
||||
bool shouldRecompileOrInvalidate(JSScript* script) const override {
|
||||
return script->hasBaselineScript() && compartments_.has(script->compartment());
|
||||
return script->hasBaselineScript() && realms_.has(script->realm());
|
||||
}
|
||||
bool shouldMarkAsDebuggee(FrameIter& iter) const override {
|
||||
// AbstractFramePtr can't refer to non-remateralized Ion frames or
|
||||
// non-debuggee wasm frames, so if iter refers to one such, we know we
|
||||
// don't match.
|
||||
return iter.hasUsableAbstractFramePtr() && compartments_.has(iter.compartment());
|
||||
return iter.hasUsableAbstractFramePtr() &&
|
||||
realms_.has(JS::GetRealmForCompartment(iter.compartment()));
|
||||
}
|
||||
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
@ -2743,12 +2744,13 @@ Debugger::ensureExecutionObservabilityOfFrame(JSContext* cx, AbstractFramePtr fr
|
||||
/* static */ bool
|
||||
Debugger::ensureExecutionObservabilityOfCompartment(JSContext* cx, JSCompartment* comp)
|
||||
{
|
||||
if (comp->debuggerObservesAllExecution())
|
||||
Realm* realm = JS::GetRealmForCompartment(comp);
|
||||
if (realm->debuggerObservesAllExecution())
|
||||
return true;
|
||||
ExecutionObservableCompartments obs(cx);
|
||||
if (!obs.init() || !obs.add(comp))
|
||||
ExecutionObservableRealms obs(cx);
|
||||
if (!obs.init() || !obs.add(realm))
|
||||
return false;
|
||||
comp->updateDebuggerObservesAllExecution();
|
||||
realm->updateDebuggerObservesAllExecution();
|
||||
return updateExecutionObservability(cx, obs, Observing);
|
||||
}
|
||||
|
||||
@ -2796,28 +2798,28 @@ Debugger::observesCoverage() const
|
||||
bool
|
||||
Debugger::updateObservesAllExecutionOnDebuggees(JSContext* cx, IsObserving observing)
|
||||
{
|
||||
ExecutionObservableCompartments obs(cx);
|
||||
ExecutionObservableRealms obs(cx);
|
||||
if (!obs.init())
|
||||
return false;
|
||||
|
||||
for (WeakGlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
|
||||
GlobalObject* global = r.front();
|
||||
JSCompartment* comp = global->compartment();
|
||||
JS::Realm* realm = global->realm();
|
||||
|
||||
if (comp->debuggerObservesAllExecution() == observing)
|
||||
if (realm->debuggerObservesAllExecution() == observing)
|
||||
continue;
|
||||
|
||||
// It's expensive to eagerly invalidate and recompile a compartment,
|
||||
// so add the compartment to the set only if we are observing.
|
||||
if (observing && !obs.add(comp))
|
||||
// It's expensive to eagerly invalidate and recompile a realm,
|
||||
// so add the realm to the set only if we are observing.
|
||||
if (observing && !obs.add(realm))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!updateExecutionObservability(cx, obs, observing))
|
||||
return false;
|
||||
|
||||
typedef ExecutionObservableCompartments::CompartmentRange CompartmentRange;
|
||||
for (CompartmentRange r = obs.compartments()->all(); !r.empty(); r.popFront())
|
||||
using RealmRange = ExecutionObservableRealms::RealmRange;
|
||||
for (RealmRange r = obs.realms()->all(); !r.empty(); r.popFront())
|
||||
r.front()->updateDebuggerObservesAllExecution();
|
||||
|
||||
return true;
|
||||
@ -2826,21 +2828,21 @@ Debugger::updateObservesAllExecutionOnDebuggees(JSContext* cx, IsObserving obser
|
||||
bool
|
||||
Debugger::updateObservesCoverageOnDebuggees(JSContext* cx, IsObserving observing)
|
||||
{
|
||||
ExecutionObservableCompartments obs(cx);
|
||||
ExecutionObservableRealms obs(cx);
|
||||
if (!obs.init())
|
||||
return false;
|
||||
|
||||
for (WeakGlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
|
||||
GlobalObject* global = r.front();
|
||||
JSCompartment* comp = global->compartment();
|
||||
Realm* realm = global->realm();
|
||||
|
||||
if (comp->debuggerObservesCoverage() == observing)
|
||||
if (realm->debuggerObservesCoverage() == observing)
|
||||
continue;
|
||||
|
||||
// Invalidate and recompile a compartment to add or remove PCCounts
|
||||
// Invalidate and recompile a realm to add or remove PCCounts
|
||||
// increments. We have to eagerly invalidate, as otherwise we might have
|
||||
// dangling pointers to freed PCCounts.
|
||||
if (!obs.add(comp))
|
||||
if (!obs.add(realm))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2860,10 +2862,10 @@ Debugger::updateObservesCoverageOnDebuggees(JSContext* cx, IsObserving observing
|
||||
if (!updateExecutionObservability(cx, obs, observing))
|
||||
return false;
|
||||
|
||||
// All compartments can safely be toggled, and all scripts will be
|
||||
// recompiled. Thus we can update each compartment accordingly.
|
||||
typedef ExecutionObservableCompartments::CompartmentRange CompartmentRange;
|
||||
for (CompartmentRange r = obs.compartments()->all(); !r.empty(); r.popFront())
|
||||
// All realms can safely be toggled, and all scripts will be recompiled.
|
||||
// Thus we can update each realm accordingly.
|
||||
using RealmRange = ExecutionObservableRealms::RealmRange;
|
||||
for (RealmRange r = obs.realms()->all(); !r.empty(); r.popFront())
|
||||
r.front()->updateDebuggerObservesCoverage();
|
||||
|
||||
return true;
|
||||
@ -2874,12 +2876,12 @@ Debugger::updateObservesAsmJSOnDebuggees(IsObserving observing)
|
||||
{
|
||||
for (WeakGlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
|
||||
GlobalObject* global = r.front();
|
||||
JSCompartment* comp = global->compartment();
|
||||
Realm* realm = global->realm();
|
||||
|
||||
if (comp->debuggerObservesAsmJS() == observing)
|
||||
if (realm->debuggerObservesAsmJS() == observing)
|
||||
continue;
|
||||
|
||||
comp->updateDebuggerObservesAsmJS();
|
||||
realm->updateDebuggerObservesAsmJS();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2888,12 +2890,12 @@ Debugger::updateObservesBinarySourceDebuggees(IsObserving observing)
|
||||
{
|
||||
for (WeakGlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
|
||||
GlobalObject* global = r.front();
|
||||
JSCompartment* comp = global->compartment();
|
||||
Realm* realm = global->realm();
|
||||
|
||||
if (comp->debuggerObservesBinarySource() == observing)
|
||||
if (realm->debuggerObservesBinarySource() == observing)
|
||||
continue;
|
||||
|
||||
comp->updateDebuggerObservesBinarySource();
|
||||
realm->updateDebuggerObservesBinarySource();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3594,8 +3596,8 @@ Debugger::setAllowUnobservedAsmJS(JSContext* cx, unsigned argc, Value* vp)
|
||||
|
||||
for (WeakGlobalObjectSet::Range r = dbg->debuggees.all(); !r.empty(); r.popFront()) {
|
||||
GlobalObject* global = r.front();
|
||||
JSCompartment* comp = global->compartment();
|
||||
comp->updateDebuggerObservesAsmJS();
|
||||
Realm* realm = global->realm();
|
||||
realm->updateDebuggerObservesAsmJS();
|
||||
}
|
||||
|
||||
args.rval().setUndefined();
|
||||
@ -3620,8 +3622,8 @@ Debugger::setAllowWasmBinarySource(JSContext* cx, unsigned argc, Value* vp)
|
||||
|
||||
for (WeakGlobalObjectSet::Range r = dbg->debuggees.all(); !r.empty(); r.popFront()) {
|
||||
GlobalObject* global = r.front();
|
||||
JSCompartment* comp = global->compartment();
|
||||
comp->updateDebuggerObservesBinarySource();
|
||||
Realm* realm = global->realm();
|
||||
realm->updateDebuggerObservesBinarySource();
|
||||
}
|
||||
|
||||
args.rval().setUndefined();
|
||||
@ -3769,17 +3771,17 @@ Debugger::removeDebuggee(JSContext* cx, unsigned argc, Value* vp)
|
||||
if (!global)
|
||||
return false;
|
||||
|
||||
ExecutionObservableCompartments obs(cx);
|
||||
ExecutionObservableRealms obs(cx);
|
||||
if (!obs.init())
|
||||
return false;
|
||||
|
||||
if (dbg->debuggees.has(global)) {
|
||||
dbg->removeDebuggeeGlobal(cx->runtime()->defaultFreeOp(), global, nullptr);
|
||||
|
||||
// Only update the compartment if there are no Debuggers left, as it's
|
||||
// expensive to check if no other Debugger has a live script or frame hook
|
||||
// on any of the current on-stack debuggee frames.
|
||||
if (global->getDebuggers()->empty() && !obs.add(global->compartment()))
|
||||
// Only update the realm if there are no Debuggers left, as it's
|
||||
// expensive to check if no other Debugger has a live script or frame
|
||||
// hook on any of the current on-stack debuggee frames.
|
||||
if (global->getDebuggers()->empty() && !obs.add(global->realm()))
|
||||
return false;
|
||||
if (!updateExecutionObservability(cx, obs, NotObserving))
|
||||
return false;
|
||||
@ -3794,7 +3796,7 @@ Debugger::removeAllDebuggees(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_DEBUGGER(cx, argc, vp, "removeAllDebuggees", args, dbg);
|
||||
|
||||
ExecutionObservableCompartments obs(cx);
|
||||
ExecutionObservableRealms obs(cx);
|
||||
if (!obs.init())
|
||||
return false;
|
||||
|
||||
@ -3803,7 +3805,7 @@ Debugger::removeAllDebuggees(JSContext* cx, unsigned argc, Value* vp)
|
||||
dbg->removeDebuggeeGlobal(cx->runtime()->defaultFreeOp(), global, &e);
|
||||
|
||||
// See note about adding to the observable set in removeDebuggee.
|
||||
if (global->getDebuggers()->empty() && !obs.add(global->compartment()))
|
||||
if (global->getDebuggers()->empty() && !obs.add(global->realm()))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -3888,8 +3890,7 @@ Debugger::clearAllBreakpoints(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_DEBUGGER(cx, argc, vp, "clearAllBreakpoints", args, dbg);
|
||||
for (WeakGlobalObjectSet::Range r = dbg->debuggees.all(); !r.empty(); r.popFront())
|
||||
r.front()->compartment()->clearBreakpointsIn(cx->runtime()->defaultFreeOp(),
|
||||
dbg, nullptr);
|
||||
r.front()->realm()->clearBreakpointsIn(cx->runtime()->defaultFreeOp(), dbg, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3975,25 +3976,24 @@ Debugger::addDebuggeeGlobal(JSContext* cx, Handle<GlobalObject*> global)
|
||||
* then adding global would create a cycle. (Typically nobody is debugging
|
||||
* the debugger, in which case we zip through this code without looping.)
|
||||
*/
|
||||
Vector<JSCompartment*> visited(cx);
|
||||
if (!visited.append(object->compartment()))
|
||||
Vector<Realm*> visited(cx);
|
||||
if (!visited.append(object->realm()))
|
||||
return false;
|
||||
for (size_t i = 0; i < visited.length(); i++) {
|
||||
JSCompartment* c = visited[i];
|
||||
if (c == debuggeeRealm) {
|
||||
Realm* realm = visited[i];
|
||||
if (realm == debuggeeRealm) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_LOOP);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find all compartments containing debuggers debugging c's global
|
||||
* object. Add those compartments to visited.
|
||||
* Find all realms containing debuggers debugging realm's global object.
|
||||
* Add those realms to visited.
|
||||
*/
|
||||
if (c->isDebuggee()) {
|
||||
Realm* realm = JS::GetRealmForCompartment(c);
|
||||
if (realm->isDebuggee()) {
|
||||
GlobalObject::DebuggerVector* v = realm->maybeGlobal()->getDebuggers();
|
||||
for (auto p = v->begin(); p != v->end(); p++) {
|
||||
JSCompartment* next = (*p)->object->compartment();
|
||||
Realm* next = (*p)->object->realm();
|
||||
if (Find(visited, next) == visited.end() && !visited.append(next))
|
||||
return false;
|
||||
}
|
||||
@ -4008,8 +4008,8 @@ Debugger::addDebuggeeGlobal(JSContext* cx, Handle<GlobalObject*> global)
|
||||
* 3. it must be in zone->getDebuggers(),
|
||||
* 4. the debuggee's zone must be in this->debuggeeZones,
|
||||
* 5. if we are tracking allocations, the SavedStacksMetadataBuilder must be
|
||||
* installed for this compartment, and
|
||||
* 6. JSCompartment::isDebuggee()'s bit must be set.
|
||||
* installed for this realm, and
|
||||
* 6. Realm::isDebuggee()'s bit must be set.
|
||||
*
|
||||
* All six indications must be kept consistent.
|
||||
*/
|
||||
@ -4073,7 +4073,7 @@ Debugger::addDebuggeeGlobal(JSContext* cx, Handle<GlobalObject*> global)
|
||||
});
|
||||
|
||||
// (6)
|
||||
AutoRestoreCompartmentDebugMode debugModeGuard(debuggeeRealm);
|
||||
AutoRestoreRealmDebugMode debugModeGuard(debuggeeRealm);
|
||||
debuggeeRealm->setIsDebuggee();
|
||||
debuggeeRealm->updateDebuggerObservesAsmJS();
|
||||
debuggeeRealm->updateDebuggerObservesBinarySource();
|
||||
@ -4178,11 +4178,11 @@ Debugger::removeDebuggeeGlobal(FreeOp* fop, GlobalObject* global,
|
||||
nextbp = bp->nextInDebugger();
|
||||
switch (bp->site->type()) {
|
||||
case BreakpointSite::Type::JS:
|
||||
if (bp->site->asJS()->script->compartment() == global->compartment())
|
||||
if (bp->site->asJS()->script->realm() == global->realm())
|
||||
bp->destroy(fop);
|
||||
break;
|
||||
case BreakpointSite::Type::Wasm:
|
||||
if (bp->asWasm()->wasmInstance->compartment() == global->compartment())
|
||||
if (bp->asWasm()->wasmInstance->realm() == global->realm())
|
||||
bp->destroy(fop);
|
||||
break;
|
||||
}
|
||||
@ -4191,18 +4191,18 @@ Debugger::removeDebuggeeGlobal(FreeOp* fop, GlobalObject* global,
|
||||
|
||||
/*
|
||||
* If we are tracking allocation sites, we need to remove the object
|
||||
* metadata callback from this global's compartment.
|
||||
* metadata callback from this global's realm.
|
||||
*/
|
||||
if (trackingAllocationSites)
|
||||
Debugger::removeAllocationsTracking(*global);
|
||||
|
||||
if (global->getDebuggers()->empty()) {
|
||||
global->compartment()->unsetIsDebuggee();
|
||||
global->realm()->unsetIsDebuggee();
|
||||
} else {
|
||||
global->compartment()->updateDebuggerObservesAllExecution();
|
||||
global->compartment()->updateDebuggerObservesAsmJS();
|
||||
global->compartment()->updateDebuggerObservesBinarySource();
|
||||
global->compartment()->updateDebuggerObservesCoverage();
|
||||
global->realm()->updateDebuggerObservesAllExecution();
|
||||
global->realm()->updateDebuggerObservesAsmJS();
|
||||
global->realm()->updateDebuggerObservesBinarySource();
|
||||
global->realm()->updateDebuggerObservesCoverage();
|
||||
}
|
||||
}
|
||||
|
||||
@ -4584,7 +4584,8 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery
|
||||
// everything.
|
||||
for (auto r = compartments.all(); !r.empty(); r.popFront()) {
|
||||
JSCompartment* comp = r.front();
|
||||
if (!comp->ensureDelazifyScriptsForDebugger(cx))
|
||||
Realm* realm = JS::GetRealmForCompartment(comp);
|
||||
if (!realm->ensureDelazifyScriptsForDebugger(cx))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -1806,7 +1806,7 @@ Debugger::onNewScript(JSContext* cx, HandleScript script)
|
||||
if (script->hideScriptFromDebugger())
|
||||
return;
|
||||
|
||||
if (script->compartment()->isDebuggee())
|
||||
if (script->realm()->isDebuggee())
|
||||
slowPathOnNewScript(cx, script);
|
||||
}
|
||||
|
||||
|
@ -2510,7 +2510,7 @@ DebugEnvironments::checkHashTablesAfterMovingGC()
|
||||
static bool
|
||||
CanUseDebugEnvironmentMaps(JSContext* cx)
|
||||
{
|
||||
return cx->compartment()->isDebuggee();
|
||||
return cx->realm()->isDebuggee();
|
||||
}
|
||||
|
||||
DebugEnvironments*
|
||||
@ -2893,7 +2893,7 @@ DebugEnvironments::updateLiveEnvironments(JSContext* cx)
|
||||
|
||||
if (frame.prevUpToDate())
|
||||
return true;
|
||||
MOZ_ASSERT(frame.environmentChain()->compartment()->isDebuggee());
|
||||
MOZ_ASSERT(frame.environmentChain()->realm()->isDebuggee());
|
||||
frame.setPrevUpToDate();
|
||||
}
|
||||
|
||||
|
@ -1045,18 +1045,18 @@ PopEnvironment(JSContext* cx, EnvironmentIter& ei)
|
||||
case ScopeKind::Catch:
|
||||
case ScopeKind::NamedLambda:
|
||||
case ScopeKind::StrictNamedLambda:
|
||||
if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
|
||||
if (MOZ_UNLIKELY(cx->realm()->isDebuggee()))
|
||||
DebugEnvironments::onPopLexical(cx, ei);
|
||||
if (ei.scope().hasEnvironment())
|
||||
ei.initialFrame().popOffEnvironmentChain<LexicalEnvironmentObject>();
|
||||
break;
|
||||
case ScopeKind::With:
|
||||
if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
|
||||
if (MOZ_UNLIKELY(cx->realm()->isDebuggee()))
|
||||
DebugEnvironments::onPopWith(ei.initialFrame());
|
||||
ei.initialFrame().popOffEnvironmentChain<WithEnvironmentObject>();
|
||||
break;
|
||||
case ScopeKind::Function:
|
||||
if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
|
||||
if (MOZ_UNLIKELY(cx->realm()->isDebuggee()))
|
||||
DebugEnvironments::onPopCall(cx, ei.initialFrame());
|
||||
if (ei.scope().hasEnvironment())
|
||||
ei.initialFrame().popOffEnvironmentChain<CallObject>();
|
||||
@ -1064,7 +1064,7 @@ PopEnvironment(JSContext* cx, EnvironmentIter& ei)
|
||||
case ScopeKind::FunctionBodyVar:
|
||||
case ScopeKind::ParameterExpressionVar:
|
||||
case ScopeKind::StrictEval:
|
||||
if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
|
||||
if (MOZ_UNLIKELY(cx->realm()->isDebuggee()))
|
||||
DebugEnvironments::onPopVar(cx, ei);
|
||||
if (ei.scope().hasEnvironment())
|
||||
ei.initialFrame().popOffEnvironmentChain<VarEnvironmentObject>();
|
||||
@ -1815,7 +1815,7 @@ Interpret(JSContext* cx, RunState& state)
|
||||
#define INIT_COVERAGE() \
|
||||
JS_BEGIN_MACRO \
|
||||
if (!script->hasScriptCounts()) { \
|
||||
if (cx->compartment()->collectCoverageForDebug()) { \
|
||||
if (cx->realm()->collectCoverageForDebug()) { \
|
||||
if (!script->initScriptCounts(cx)) \
|
||||
goto error; \
|
||||
} \
|
||||
@ -1935,7 +1935,7 @@ CASE(EnableInterruptsPseudoOpcode)
|
||||
bool moreInterrupts = false;
|
||||
jsbytecode op = *REGS.pc;
|
||||
|
||||
if (!script->hasScriptCounts() && cx->compartment()->collectCoverageForDebug()) {
|
||||
if (!script->hasScriptCounts() && cx->realm()->collectCoverageForDebug()) {
|
||||
if (!script->initScriptCounts(cx))
|
||||
goto error;
|
||||
}
|
||||
@ -3980,7 +3980,7 @@ CASE(JSOP_POPLEXICALENV)
|
||||
MOZ_ASSERT(scope->as<LexicalScope>().hasEnvironment());
|
||||
#endif
|
||||
|
||||
if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
|
||||
if (MOZ_UNLIKELY(cx->realm()->isDebuggee()))
|
||||
DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
|
||||
|
||||
// Pop block from scope chain.
|
||||
@ -3997,14 +3997,14 @@ CASE(JSOP_DEBUGLEAVELEXICALENV)
|
||||
// FIXME: This opcode should not be necessary. The debugger shouldn't need
|
||||
// help from bytecode to do its job. See bug 927782.
|
||||
|
||||
if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
|
||||
if (MOZ_UNLIKELY(cx->realm()->isDebuggee()))
|
||||
DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
|
||||
}
|
||||
END_CASE(JSOP_DEBUGLEAVELEXICALENV)
|
||||
|
||||
CASE(JSOP_FRESHENLEXICALENV)
|
||||
{
|
||||
if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
|
||||
if (MOZ_UNLIKELY(cx->realm()->isDebuggee()))
|
||||
DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
|
||||
|
||||
if (!REGS.fp()->freshenLexicalEnvironment(cx))
|
||||
@ -4014,7 +4014,7 @@ END_CASE(JSOP_FRESHENLEXICALENV)
|
||||
|
||||
CASE(JSOP_RECREATELEXICALENV)
|
||||
{
|
||||
if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
|
||||
if (MOZ_UNLIKELY(cx->realm()->isDebuggee()))
|
||||
DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
|
||||
|
||||
if (!REGS.fp()->recreateLexicalEnvironment(cx))
|
||||
@ -4040,7 +4040,7 @@ CASE(JSOP_POPVARENV)
|
||||
MOZ_ASSERT(scope->as<VarScope>().hasEnvironment());
|
||||
#endif
|
||||
|
||||
if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
|
||||
if (MOZ_UNLIKELY(cx->realm()->isDebuggee()))
|
||||
DebugEnvironments::onPopVar(cx, REGS.fp(), REGS.pc);
|
||||
|
||||
REGS.fp()->popOffEnvironmentChain<VarEnvironmentObject>();
|
||||
|
@ -54,7 +54,6 @@ JSCompartment::JSCompartment(Zone* zone)
|
||||
lazyArrayBuffers(nullptr),
|
||||
nonSyntacticLexicalEnvironments_(nullptr),
|
||||
gcIncomingGrayPointers(nullptr),
|
||||
debugModeBits(0),
|
||||
validAccessPtr(nullptr),
|
||||
randomKeyGenerator_(runtime_->forkRandomKeyGenerator()),
|
||||
debugEnvs(nullptr),
|
||||
@ -1071,9 +1070,9 @@ AddInnerLazyFunctionsFromScript(JSScript* script, AutoObjectVector& lazyFunction
|
||||
}
|
||||
|
||||
static bool
|
||||
AddLazyFunctionsForCompartment(JSContext* cx, AutoObjectVector& lazyFunctions, AllocKind kind)
|
||||
AddLazyFunctionsForRealm(JSContext* cx, AutoObjectVector& lazyFunctions, AllocKind kind)
|
||||
{
|
||||
// Find all live root lazy functions in the compartment: those which have a
|
||||
// Find all live root lazy functions in the realm: those which have a
|
||||
// non-lazy enclosing script, and which do not have an uncompiled enclosing
|
||||
// script. The last condition is so that we don't compile lazy scripts
|
||||
// whose enclosing scripts failed to compile, indicating that the lazy
|
||||
@ -1090,7 +1089,7 @@ AddLazyFunctionsForCompartment(JSContext* cx, AutoObjectVector& lazyFunctions, A
|
||||
// are about to be finalized. GC things referenced by objects that are
|
||||
// about to be finalized (e.g., in slots) may already be freed.
|
||||
if (gc::IsAboutToBeFinalizedUnbarriered(&fun) ||
|
||||
fun->compartment() != cx->compartment())
|
||||
fun->realm() != cx->realm())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -1108,16 +1107,16 @@ AddLazyFunctionsForCompartment(JSContext* cx, AutoObjectVector& lazyFunctions, A
|
||||
}
|
||||
|
||||
static bool
|
||||
CreateLazyScriptsForCompartment(JSContext* cx)
|
||||
CreateLazyScriptsForRealm(JSContext* cx)
|
||||
{
|
||||
AutoObjectVector lazyFunctions(cx);
|
||||
|
||||
if (!AddLazyFunctionsForCompartment(cx, lazyFunctions, AllocKind::FUNCTION))
|
||||
if (!AddLazyFunctionsForRealm(cx, lazyFunctions, AllocKind::FUNCTION))
|
||||
return false;
|
||||
|
||||
// Methods, for instance {get method() {}}, are extended functions that can
|
||||
// be relazified, so we need to handle those as well.
|
||||
if (!AddLazyFunctionsForCompartment(cx, lazyFunctions, AllocKind::FUNCTION_EXTENDED))
|
||||
if (!AddLazyFunctionsForRealm(cx, lazyFunctions, AllocKind::FUNCTION_EXTENDED))
|
||||
return false;
|
||||
|
||||
// Create scripts for each lazy function, updating the list of functions to
|
||||
@ -1145,17 +1144,17 @@ CreateLazyScriptsForCompartment(JSContext* cx)
|
||||
}
|
||||
|
||||
bool
|
||||
JSCompartment::ensureDelazifyScriptsForDebugger(JSContext* cx)
|
||||
Realm::ensureDelazifyScriptsForDebugger(JSContext* cx)
|
||||
{
|
||||
AutoRealmUnchecked ar(cx, this);
|
||||
if (needsDelazificationForDebugger() && !CreateLazyScriptsForCompartment(cx))
|
||||
if (needsDelazificationForDebugger() && !CreateLazyScriptsForRealm(cx))
|
||||
return false;
|
||||
debugModeBits &= ~DebuggerNeedsDelazification;
|
||||
debugModeBits_ &= ~DebuggerNeedsDelazification;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::updateDebuggerObservesFlag(unsigned flag)
|
||||
Realm::updateDebuggerObservesFlag(unsigned flag)
|
||||
{
|
||||
MOZ_ASSERT(isDebuggee());
|
||||
MOZ_ASSERT(flag == DebuggerObservesAllExecution ||
|
||||
@ -1163,10 +1162,9 @@ JSCompartment::updateDebuggerObservesFlag(unsigned flag)
|
||||
flag == DebuggerObservesAsmJS ||
|
||||
flag == DebuggerObservesBinarySource);
|
||||
|
||||
Realm* realm = JS::GetRealmForCompartment(this);
|
||||
GlobalObject* global = zone()->runtimeFromMainThread()->gc.isForegroundSweeping()
|
||||
? realm->unsafeUnbarrieredMaybeGlobal()
|
||||
: realm->maybeGlobal();
|
||||
? unsafeUnbarrieredMaybeGlobal()
|
||||
: maybeGlobal();
|
||||
const GlobalObject::DebuggerVector* v = global->getDebuggers();
|
||||
for (auto p = v->begin(); p != v->end(); p++) {
|
||||
Debugger* dbg = *p;
|
||||
@ -1175,25 +1173,25 @@ JSCompartment::updateDebuggerObservesFlag(unsigned flag)
|
||||
flag == DebuggerObservesAsmJS ? dbg->observesAsmJS() :
|
||||
dbg->observesBinarySource())
|
||||
{
|
||||
debugModeBits |= flag;
|
||||
debugModeBits_ |= flag;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
debugModeBits &= ~flag;
|
||||
debugModeBits_ &= ~flag;
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::unsetIsDebuggee()
|
||||
Realm::unsetIsDebuggee()
|
||||
{
|
||||
if (isDebuggee()) {
|
||||
debugModeBits &= ~DebuggerObservesMask;
|
||||
debugModeBits_ &= ~DebuggerObservesMask;
|
||||
DebugEnvironments::onCompartmentUnsetIsDebuggee(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::updateDebuggerObservesCoverage()
|
||||
Realm::updateDebuggerObservesCoverage()
|
||||
{
|
||||
bool previousState = debuggerObservesCoverage();
|
||||
updateDebuggerObservesFlag(DebuggerObservesCoverage);
|
||||
@ -1215,26 +1213,25 @@ JSCompartment::updateDebuggerObservesCoverage()
|
||||
if (collectCoverage())
|
||||
return;
|
||||
|
||||
Realm* realm = JS::GetRealmForCompartment(this);
|
||||
realm->clearScriptCounts();
|
||||
realm->clearScriptNames();
|
||||
clearScriptCounts();
|
||||
clearScriptNames();
|
||||
}
|
||||
|
||||
bool
|
||||
JSCompartment::collectCoverage() const
|
||||
Realm::collectCoverage() const
|
||||
{
|
||||
return collectCoverageForPGO() ||
|
||||
collectCoverageForDebug();
|
||||
}
|
||||
|
||||
bool
|
||||
JSCompartment::collectCoverageForPGO() const
|
||||
Realm::collectCoverageForPGO() const
|
||||
{
|
||||
return !JitOptions.disablePgo;
|
||||
}
|
||||
|
||||
bool
|
||||
JSCompartment::collectCoverageForDebug() const
|
||||
Realm::collectCoverageForDebug() const
|
||||
{
|
||||
return debuggerObservesCoverage() ||
|
||||
runtimeFromAnyThread()->profilingScripts ||
|
||||
@ -1262,10 +1259,10 @@ Realm::clearScriptNames()
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::clearBreakpointsIn(FreeOp* fop, js::Debugger* dbg, HandleObject handler)
|
||||
Realm::clearBreakpointsIn(FreeOp* fop, js::Debugger* dbg, HandleObject handler)
|
||||
{
|
||||
for (auto script = zone()->cellIter<JSScript>(); !script.done(); script.next()) {
|
||||
if (script->compartment() == this && script->hasAnyBreakpointsOrStepMode())
|
||||
if (script->realm() == this && script->hasAnyBreakpointsOrStepMode())
|
||||
script->clearBreakpointsIn(fop, dbg, handler);
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ namespace gc {
|
||||
template <typename Node, typename Derived> class ComponentFinder;
|
||||
} // namespace gc
|
||||
|
||||
class AutoRestoreRealmDebugMode;
|
||||
class GlobalObject;
|
||||
class LexicalEnvironmentObject;
|
||||
class MapObject;
|
||||
@ -660,26 +661,6 @@ struct JSCompartment
|
||||
JSObject* gcIncomingGrayPointers;
|
||||
|
||||
private:
|
||||
enum {
|
||||
IsDebuggee = 1 << 0,
|
||||
DebuggerObservesAllExecution = 1 << 1,
|
||||
DebuggerObservesAsmJS = 1 << 2,
|
||||
DebuggerObservesCoverage = 1 << 3,
|
||||
DebuggerObservesBinarySource = 1 << 4,
|
||||
DebuggerNeedsDelazification = 1 << 5
|
||||
};
|
||||
|
||||
unsigned debugModeBits;
|
||||
friend class AutoRestoreCompartmentDebugMode;
|
||||
|
||||
static const unsigned DebuggerObservesMask = IsDebuggee |
|
||||
DebuggerObservesAllExecution |
|
||||
DebuggerObservesCoverage |
|
||||
DebuggerObservesAsmJS |
|
||||
DebuggerObservesBinarySource;
|
||||
|
||||
void updateDebuggerObservesFlag(unsigned flag);
|
||||
|
||||
bool getNonWrapperObjectForCurrentCompartment(JSContext* cx, js::MutableHandleObject obj);
|
||||
bool getOrCreateWrapper(JSContext* cx, js::HandleObject existing, js::MutableHandleObject obj);
|
||||
|
||||
@ -788,118 +769,6 @@ struct JSCompartment
|
||||
return offsetof(JSCompartment, regExps);
|
||||
}
|
||||
|
||||
//
|
||||
// The Debugger observes execution on a frame-by-frame basis. The
|
||||
// invariants of JSCompartment's debug mode bits, JSScript::isDebuggee,
|
||||
// InterpreterFrame::isDebuggee, and BaselineFrame::isDebuggee are
|
||||
// enumerated below.
|
||||
//
|
||||
// 1. When a compartment's isDebuggee() == true, relazification and lazy
|
||||
// parsing are disabled.
|
||||
//
|
||||
// Whether AOT wasm is disabled is togglable by the Debugger API. By
|
||||
// default it is disabled. See debuggerObservesAsmJS below.
|
||||
//
|
||||
// 2. When a compartment's debuggerObservesAllExecution() == true, all of
|
||||
// the compartment's scripts are considered debuggee scripts.
|
||||
//
|
||||
// 3. A script is considered a debuggee script either when, per above, its
|
||||
// compartment is observing all execution, or if it has breakpoints set.
|
||||
//
|
||||
// 4. A debuggee script always pushes a debuggee frame.
|
||||
//
|
||||
// 5. A debuggee frame calls all slow path Debugger hooks in the
|
||||
// Interpreter and Baseline. A debuggee frame implies that its script's
|
||||
// BaselineScript, if extant, has been compiled with debug hook calls.
|
||||
//
|
||||
// 6. A debuggee script or a debuggee frame (i.e., during OSR) ensures
|
||||
// that the compiled BaselineScript is compiled with debug hook calls
|
||||
// when attempting to enter Baseline.
|
||||
//
|
||||
// 7. A debuggee script or a debuggee frame (i.e., during OSR) does not
|
||||
// attempt to enter Ion.
|
||||
//
|
||||
// Note that a debuggee frame may exist without its script being a
|
||||
// debuggee script. e.g., Debugger.Frame.prototype.eval only marks the
|
||||
// frame in which it is evaluating as a debuggee frame.
|
||||
//
|
||||
|
||||
// True if this compartment's global is a debuggee of some Debugger
|
||||
// object.
|
||||
bool isDebuggee() const { return !!(debugModeBits & IsDebuggee); }
|
||||
void setIsDebuggee() { debugModeBits |= IsDebuggee; }
|
||||
void unsetIsDebuggee();
|
||||
|
||||
// True if this compartment's global is a debuggee of some Debugger
|
||||
// object with a live hook that observes all execution; e.g.,
|
||||
// onEnterFrame.
|
||||
bool debuggerObservesAllExecution() const {
|
||||
static const unsigned Mask = IsDebuggee | DebuggerObservesAllExecution;
|
||||
return (debugModeBits & Mask) == Mask;
|
||||
}
|
||||
void updateDebuggerObservesAllExecution() {
|
||||
updateDebuggerObservesFlag(DebuggerObservesAllExecution);
|
||||
}
|
||||
|
||||
// True if this compartment's global is a debuggee of some Debugger object
|
||||
// whose allowUnobservedAsmJS flag is false.
|
||||
//
|
||||
// Note that since AOT wasm functions cannot bail out, this flag really
|
||||
// means "observe wasm from this point forward". We cannot make
|
||||
// already-compiled wasm code observable to Debugger.
|
||||
bool debuggerObservesAsmJS() const {
|
||||
static const unsigned Mask = IsDebuggee | DebuggerObservesAsmJS;
|
||||
return (debugModeBits & Mask) == Mask;
|
||||
}
|
||||
void updateDebuggerObservesAsmJS() {
|
||||
updateDebuggerObservesFlag(DebuggerObservesAsmJS);
|
||||
}
|
||||
|
||||
bool debuggerObservesBinarySource() const {
|
||||
static const unsigned Mask = IsDebuggee | DebuggerObservesBinarySource;
|
||||
return (debugModeBits & Mask) == Mask;
|
||||
}
|
||||
|
||||
void updateDebuggerObservesBinarySource() {
|
||||
updateDebuggerObservesFlag(DebuggerObservesBinarySource);
|
||||
}
|
||||
|
||||
// True if this compartment's global is a debuggee of some Debugger object
|
||||
// whose collectCoverageInfo flag is true.
|
||||
bool debuggerObservesCoverage() const {
|
||||
static const unsigned Mask = DebuggerObservesCoverage;
|
||||
return (debugModeBits & Mask) == Mask;
|
||||
}
|
||||
void updateDebuggerObservesCoverage();
|
||||
|
||||
// The code coverage can be enabled either for each compartment, with the
|
||||
// Debugger API, or for the entire runtime.
|
||||
bool collectCoverage() const;
|
||||
bool collectCoverageForDebug() const;
|
||||
bool collectCoverageForPGO() const;
|
||||
|
||||
bool needsDelazificationForDebugger() const {
|
||||
return debugModeBits & DebuggerNeedsDelazification;
|
||||
}
|
||||
|
||||
/*
|
||||
* Schedule the compartment to be delazified. Called from
|
||||
* LazyScript::Create.
|
||||
*/
|
||||
void scheduleDelazificationForDebugger() { debugModeBits |= DebuggerNeedsDelazification; }
|
||||
|
||||
/*
|
||||
* If we scheduled delazification for turning on debug mode, delazify all
|
||||
* scripts.
|
||||
*/
|
||||
bool ensureDelazifyScriptsForDebugger(JSContext* cx);
|
||||
|
||||
void clearBreakpointsIn(js::FreeOp* fop, js::Debugger* dbg, JS::HandleObject handler);
|
||||
|
||||
private:
|
||||
void sweepBreakpoints(js::FreeOp* fop);
|
||||
|
||||
public:
|
||||
/* Bookkeeping information for debug scope objects. */
|
||||
js::DebugEnvironments* debugEnvs;
|
||||
|
||||
@ -967,6 +836,22 @@ class JS::Realm : public JSCompartment
|
||||
|
||||
unsigned enterRealmDepth_ = 0;
|
||||
|
||||
enum {
|
||||
IsDebuggee = 1 << 0,
|
||||
DebuggerObservesAllExecution = 1 << 1,
|
||||
DebuggerObservesAsmJS = 1 << 2,
|
||||
DebuggerObservesCoverage = 1 << 3,
|
||||
DebuggerObservesBinarySource = 1 << 4,
|
||||
DebuggerNeedsDelazification = 1 << 5
|
||||
};
|
||||
static const unsigned DebuggerObservesMask = IsDebuggee |
|
||||
DebuggerObservesAllExecution |
|
||||
DebuggerObservesCoverage |
|
||||
DebuggerObservesAsmJS |
|
||||
DebuggerObservesBinarySource;
|
||||
unsigned debugModeBits_ = 0;
|
||||
friend class js::AutoRestoreRealmDebugMode;
|
||||
|
||||
bool isAtomsRealm_ = false;
|
||||
bool isSelfHostingRealm_ = false;
|
||||
bool marked_ = true;
|
||||
@ -998,6 +883,10 @@ class JS::Realm : public JSCompartment
|
||||
bool firedOnNewGlobalObject = false;
|
||||
#endif
|
||||
|
||||
private:
|
||||
void updateDebuggerObservesFlag(unsigned flag);
|
||||
|
||||
public:
|
||||
Realm(JS::Zone* zone, const JS::RealmOptions& options);
|
||||
~Realm();
|
||||
|
||||
@ -1230,6 +1119,111 @@ class JS::Realm : public JSCompartment
|
||||
|
||||
js::ArgumentsObject* getOrCreateArgumentsTemplateObject(JSContext* cx, bool mapped);
|
||||
js::ArgumentsObject* maybeArgumentsTemplateObject(bool mapped) const;
|
||||
|
||||
//
|
||||
// The Debugger observes execution on a frame-by-frame basis. The
|
||||
// invariants of Realm's debug mode bits, JSScript::isDebuggee,
|
||||
// InterpreterFrame::isDebuggee, and BaselineFrame::isDebuggee are
|
||||
// enumerated below.
|
||||
//
|
||||
// 1. When a realm's isDebuggee() == true, relazification and lazy
|
||||
// parsing are disabled.
|
||||
//
|
||||
// Whether AOT wasm is disabled is togglable by the Debugger API. By
|
||||
// default it is disabled. See debuggerObservesAsmJS below.
|
||||
//
|
||||
// 2. When a realm's debuggerObservesAllExecution() == true, all of
|
||||
// the realm's scripts are considered debuggee scripts.
|
||||
//
|
||||
// 3. A script is considered a debuggee script either when, per above, its
|
||||
// realm is observing all execution, or if it has breakpoints set.
|
||||
//
|
||||
// 4. A debuggee script always pushes a debuggee frame.
|
||||
//
|
||||
// 5. A debuggee frame calls all slow path Debugger hooks in the
|
||||
// Interpreter and Baseline. A debuggee frame implies that its script's
|
||||
// BaselineScript, if extant, has been compiled with debug hook calls.
|
||||
//
|
||||
// 6. A debuggee script or a debuggee frame (i.e., during OSR) ensures
|
||||
// that the compiled BaselineScript is compiled with debug hook calls
|
||||
// when attempting to enter Baseline.
|
||||
//
|
||||
// 7. A debuggee script or a debuggee frame (i.e., during OSR) does not
|
||||
// attempt to enter Ion.
|
||||
//
|
||||
// Note that a debuggee frame may exist without its script being a
|
||||
// debuggee script. e.g., Debugger.Frame.prototype.eval only marks the
|
||||
// frame in which it is evaluating as a debuggee frame.
|
||||
//
|
||||
|
||||
// True if this realm's global is a debuggee of some Debugger
|
||||
// object.
|
||||
bool isDebuggee() const { return !!(debugModeBits_ & IsDebuggee); }
|
||||
void setIsDebuggee() { debugModeBits_ |= IsDebuggee; }
|
||||
void unsetIsDebuggee();
|
||||
|
||||
// True if this compartment's global is a debuggee of some Debugger
|
||||
// object with a live hook that observes all execution; e.g.,
|
||||
// onEnterFrame.
|
||||
bool debuggerObservesAllExecution() const {
|
||||
static const unsigned Mask = IsDebuggee | DebuggerObservesAllExecution;
|
||||
return (debugModeBits_ & Mask) == Mask;
|
||||
}
|
||||
void updateDebuggerObservesAllExecution() {
|
||||
updateDebuggerObservesFlag(DebuggerObservesAllExecution);
|
||||
}
|
||||
|
||||
// True if this realm's global is a debuggee of some Debugger object
|
||||
// whose allowUnobservedAsmJS flag is false.
|
||||
//
|
||||
// Note that since AOT wasm functions cannot bail out, this flag really
|
||||
// means "observe wasm from this point forward". We cannot make
|
||||
// already-compiled wasm code observable to Debugger.
|
||||
bool debuggerObservesAsmJS() const {
|
||||
static const unsigned Mask = IsDebuggee | DebuggerObservesAsmJS;
|
||||
return (debugModeBits_ & Mask) == Mask;
|
||||
}
|
||||
void updateDebuggerObservesAsmJS() {
|
||||
updateDebuggerObservesFlag(DebuggerObservesAsmJS);
|
||||
}
|
||||
|
||||
bool debuggerObservesBinarySource() const {
|
||||
static const unsigned Mask = IsDebuggee | DebuggerObservesBinarySource;
|
||||
return (debugModeBits_ & Mask) == Mask;
|
||||
}
|
||||
|
||||
void updateDebuggerObservesBinarySource() {
|
||||
updateDebuggerObservesFlag(DebuggerObservesBinarySource);
|
||||
}
|
||||
|
||||
// True if this realm's global is a debuggee of some Debugger object
|
||||
// whose collectCoverageInfo flag is true.
|
||||
bool debuggerObservesCoverage() const {
|
||||
static const unsigned Mask = DebuggerObservesCoverage;
|
||||
return (debugModeBits_ & Mask) == Mask;
|
||||
}
|
||||
void updateDebuggerObservesCoverage();
|
||||
|
||||
// The code coverage can be enabled either for each realm, with the
|
||||
// Debugger API, or for the entire runtime.
|
||||
bool collectCoverage() const;
|
||||
bool collectCoverageForDebug() const;
|
||||
bool collectCoverageForPGO() const;
|
||||
|
||||
bool needsDelazificationForDebugger() const {
|
||||
return debugModeBits_ & DebuggerNeedsDelazification;
|
||||
}
|
||||
|
||||
// Schedule the realm to be delazified. Called from LazyScript::Create.
|
||||
void scheduleDelazificationForDebugger() {
|
||||
debugModeBits_ |= DebuggerNeedsDelazification;
|
||||
}
|
||||
|
||||
// If we scheduled delazification for turning on debug mode, delazify all
|
||||
// scripts.
|
||||
bool ensureDelazifyScriptsForDebugger(JSContext* cx);
|
||||
|
||||
void clearBreakpointsIn(js::FreeOp* fop, js::Debugger* dbg, JS::HandleObject handler);
|
||||
};
|
||||
|
||||
namespace js {
|
||||
|
@ -3798,7 +3798,7 @@ bool
|
||||
JSScript::incrementStepModeCount(JSContext* cx)
|
||||
{
|
||||
assertSameCompartment(cx, this);
|
||||
MOZ_ASSERT(cx->compartment()->isDebuggee());
|
||||
MOZ_ASSERT(cx->realm()->isDebuggee());
|
||||
|
||||
if (!ensureHasDebugScript(cx))
|
||||
return false;
|
||||
@ -4259,7 +4259,7 @@ LazyScript::CreateRaw(JSContext* cx, HandleFunction fun,
|
||||
if (!res)
|
||||
return nullptr;
|
||||
|
||||
cx->compartment()->scheduleDelazificationForDebugger();
|
||||
cx->realm()->scheduleDelazificationForDebugger();
|
||||
|
||||
return new (res) LazyScript(fun, *sourceObject, table.forget(), packed, sourceStart, sourceEnd,
|
||||
toStringStart, lineno, column);
|
||||
|
@ -460,7 +460,7 @@ HandleInterrupt(JSContext* cx, bool invokeCallback)
|
||||
if (!stop) {
|
||||
// Debugger treats invoking the interrupt callback as a "step", so
|
||||
// invoke the onStep handler.
|
||||
if (cx->compartment()->isDebuggee()) {
|
||||
if (cx->realm()->isDebuggee()) {
|
||||
ScriptFrameIter iter(cx);
|
||||
if (!iter.done() &&
|
||||
cx->compartment() == iter.compartment() &&
|
||||
|
@ -1657,7 +1657,7 @@ jit::JitActivation::removeRematerializedFramesFromDebugger(JSContext* cx, uint8_
|
||||
// Ion bailout can fail due to overrecursion and OOM. In such cases we
|
||||
// cannot honor any further Debugger hooks on the frame, and need to
|
||||
// ensure that its Debugger.Frame entry is cleaned up.
|
||||
if (!cx->compartment()->isDebuggee() || !rematerializedFrames_)
|
||||
if (!cx->realm()->isDebuggee() || !rematerializedFrames_)
|
||||
return;
|
||||
if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top)) {
|
||||
for (uint32_t i = 0; i < p->value().length(); i++)
|
||||
|
@ -103,7 +103,7 @@ CompileArgs::initFromContext(JSContext* cx, ScriptedCaller&& scriptedCaller)
|
||||
// additional memory and permanently stay in baseline code, so we try to
|
||||
// only enable it when a developer actually cares: when the debugger tab
|
||||
// is open.
|
||||
debugEnabled = cx->compartment()->debuggerObservesAsmJS();
|
||||
debugEnabled = cx->realm()->debuggerObservesAsmJS();
|
||||
|
||||
this->scriptedCaller = Move(scriptedCaller);
|
||||
return assumptions.initBuildIdFromContext(cx);
|
||||
|
@ -1281,13 +1281,13 @@ Module::instantiate(JSContext* cx,
|
||||
// To support viewing the source of an instance (Instance::createText), the
|
||||
// instance must hold onto a ref of the bytecode (keeping it alive). This
|
||||
// wastes memory for most users, so we try to only save the source when a
|
||||
// developer actually cares: when the compartment is debuggable (which is
|
||||
// true when the web console is open), has code compiled with debug flag
|
||||
// developer actually cares: when the realm is debuggable (which is true
|
||||
// when the web console is open), has code compiled with debug flag
|
||||
// enabled or a names section is present (since this going to be stripped
|
||||
// for non-developer builds).
|
||||
|
||||
const ShareableBytes* maybeBytecode = nullptr;
|
||||
if (cx->compartment()->isDebuggee() || metadata().debugEnabled ||
|
||||
if (cx->realm()->isDebuggee() || metadata().debugEnabled ||
|
||||
!metadata().funcNames.empty())
|
||||
{
|
||||
maybeBytecode = bytecode_.get();
|
||||
@ -1297,7 +1297,7 @@ Module::instantiate(JSContext* cx,
|
||||
// provides the lazily created source text for the program, even if that
|
||||
// text is a placeholder message when debugging is not enabled.
|
||||
|
||||
bool binarySource = cx->compartment()->debuggerObservesBinarySource();
|
||||
bool binarySource = cx->realm()->debuggerObservesBinarySource();
|
||||
auto debug = cx->make_unique<DebugState>(code, maybeBytecode, binarySource);
|
||||
if (!debug)
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user