mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
Bug 1693590
- Use a WeakMap to store DebugScripts associated with a JSScript r=sfink,jimb
This changes Zone::debugScriptMap to be a WeakMap rather than having its entries marked from BaseScript::traceChildren. This simplifies script marking and removes some code from Zone.cpp. Unfortunately it does also adds a couple of complications: 1) We need to wrap DebugScript in a JSObject so we can use it as a WeakMap value. That leads to: 2) We need to do a bunch of extra rooting whenever we might create a DebugScript. I tried making WeakMaps allow non-GC thing values but that also got complicated as marking relies on comparing the mark state of the key to that of the value (and the map) and this would require tracing the value and then combining the mark state of child pointers. Differential Revision: https://phabricator.services.mozilla.com/D105789
This commit is contained in:
parent
80ca2b2a02
commit
b13581aa72
@ -18,6 +18,7 @@ namespace js {
|
||||
// active Debuggers.
|
||||
|
||||
class AbstractGeneratorObject;
|
||||
class DebugScriptMap;
|
||||
class PromiseObject;
|
||||
|
||||
/**
|
||||
@ -101,8 +102,8 @@ class DebugAPI {
|
||||
// Trace all debugger-owned GC things unconditionally, during a moving GC.
|
||||
static void traceAllForMovingGC(JSTracer* trc);
|
||||
|
||||
// Trace debugging information for a JSScript.
|
||||
static void traceDebugScript(JSTracer* trc, JSScript* script);
|
||||
// Trace the debug script map. Called as part of tracing a zone's roots.
|
||||
static void traceDebugScriptMap(JSTracer* trc, DebugScriptMap* map);
|
||||
|
||||
static void traceFromRealm(JSTracer* trc, Realm* realm);
|
||||
|
||||
@ -115,8 +116,11 @@ class DebugAPI {
|
||||
// Add sweep group edges due to the presence of any debuggers.
|
||||
[[nodiscard]] static bool findSweepGroupEdges(JSRuntime* rt);
|
||||
|
||||
// Destroy the debugging information associated with a script.
|
||||
static void destroyDebugScript(JSFreeOp* fop, JSScript* script);
|
||||
// Remove the debugging information associated with a script.
|
||||
static void removeDebugScript(JSFreeOp* fop, JSScript* script);
|
||||
|
||||
// Delete a Zone's debug script map. Called when a zone is destroyed.
|
||||
static void deleteDebugScriptMap(DebugScriptMap* map);
|
||||
|
||||
// Validate the debugging information in a script after a moving GC>
|
||||
#ifdef JSGC_HASH_TABLE_CHECKS
|
||||
|
@ -37,23 +37,80 @@
|
||||
#include "gc/WeakMap-inl.h" // for WeakMap::remove
|
||||
#include "vm/BytecodeIterator-inl.h" // for AllBytecodesIterable
|
||||
#include "vm/JSContext-inl.h" // for JSContext::check
|
||||
#include "vm/JSObject-inl.h" // for NewObjectWithGivenProto
|
||||
#include "vm/JSScript-inl.h" // for JSScript::hasBaselineScript
|
||||
#include "vm/Realm-inl.h" // for AutoRealm::AutoRealm
|
||||
|
||||
namespace js {
|
||||
|
||||
const JSClass DebugScriptObject::class_ = {
|
||||
"DebugScriptObject", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
|
||||
&classOps_, JS_NULL_CLASS_SPEC};
|
||||
|
||||
const JSClassOps DebugScriptObject::classOps_ = {
|
||||
nullptr, // addProperty
|
||||
nullptr, // delProperty
|
||||
nullptr, // enumerate
|
||||
nullptr, // newEnumerate
|
||||
nullptr, // resolve
|
||||
nullptr, // mayResolve
|
||||
DebugScriptObject::finalize, // finalize
|
||||
nullptr, // call
|
||||
nullptr, // hasInstance
|
||||
nullptr, // construct
|
||||
DebugScriptObject::trace, // trace
|
||||
};
|
||||
|
||||
/* static */
|
||||
DebugScript* DebugScript::get(JSScript* script) {
|
||||
MOZ_ASSERT(script->hasDebugScript());
|
||||
DebugScriptMap* map = script->zone()->debugScriptMap.get();
|
||||
MOZ_ASSERT(map);
|
||||
DebugScriptMap::Ptr p = map->lookup(script);
|
||||
MOZ_ASSERT(p);
|
||||
return p->value().get();
|
||||
DebugScriptObject* DebugScriptObject::create(JSContext* cx,
|
||||
UniqueDebugScript debugScript,
|
||||
size_t nbytes) {
|
||||
auto* object = NewObjectWithGivenProto<DebugScriptObject>(cx, nullptr);
|
||||
if (!object) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
object->setPrivate(debugScript.release());
|
||||
AddCellMemory(object, nbytes, MemoryUse::ScriptDebugScript);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
DebugScript* DebugScriptObject::debugScript() const {
|
||||
return static_cast<DebugScript*>(getPrivate());
|
||||
}
|
||||
|
||||
/* static */
|
||||
DebugScript* DebugScript::getOrCreate(JSContext* cx, JSScript* script) {
|
||||
void DebugScriptObject::trace(JSTracer* trc, JSObject* obj) {
|
||||
DebugScript* debugScript = obj->as<DebugScriptObject>().debugScript();
|
||||
if (debugScript) {
|
||||
debugScript->trace(trc);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void DebugScriptObject::finalize(JSFreeOp* fop, JSObject* obj) {
|
||||
DebugScriptObject* object = &obj->as<DebugScriptObject>();
|
||||
DebugScript* debugScript = object->debugScript();
|
||||
if (debugScript) {
|
||||
debugScript->delete_(fop, object);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
DebugScript* DebugScript::get(JSScript* script) {
|
||||
MOZ_ASSERT(script->hasDebugScript());
|
||||
DebugScriptMap* map = script->zone()->debugScriptMap;
|
||||
MOZ_ASSERT(map);
|
||||
DebugScriptMap::Ptr p = map->lookupUnbarriered(script);
|
||||
MOZ_ASSERT(p);
|
||||
return p->value().get()->as<DebugScriptObject>().debugScript();
|
||||
}
|
||||
|
||||
/* static */
|
||||
DebugScript* DebugScript::getOrCreate(JSContext* cx, HandleScript script) {
|
||||
cx->check(script);
|
||||
|
||||
if (script->hasDebugScript()) {
|
||||
return get(script);
|
||||
}
|
||||
@ -65,27 +122,35 @@ DebugScript* DebugScript::getOrCreate(JSContext* cx, JSScript* script) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
debug->codeLength = script->length();
|
||||
|
||||
Rooted<DebugScriptObject*> object(
|
||||
cx, DebugScriptObject::create(cx, std::move(debug), nbytes));
|
||||
if (!object) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Create zone's debugScriptMap if necessary. */
|
||||
if (!script->zone()->debugScriptMap) {
|
||||
auto map = cx->make_unique<DebugScriptMap>();
|
||||
Zone* zone = script->zone();
|
||||
MOZ_ASSERT(cx->zone() == zone);
|
||||
if (!zone->debugScriptMap) {
|
||||
DebugScriptMap* map = cx->new_<DebugScriptMap>(cx);
|
||||
if (!map) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
script->zone()->debugScriptMap = std::move(map);
|
||||
zone->debugScriptMap = map;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(script->hasBytecode());
|
||||
|
||||
DebugScript* borrowed = debug.get();
|
||||
if (!script->zone()->debugScriptMap->putNew(script, std::move(debug))) {
|
||||
if (!zone->debugScriptMap->putNew(script.get(), object.get())) {
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// It is safe to set this: we can't fail after this point.
|
||||
script->setHasDebugScript(true);
|
||||
AddCellMemory(script, nbytes, MemoryUse::ScriptDebugScript);
|
||||
|
||||
/*
|
||||
* Ensure that any Interpret() instances running on this script have
|
||||
@ -98,7 +163,7 @@ DebugScript* DebugScript::getOrCreate(JSContext* cx, JSScript* script) {
|
||||
}
|
||||
}
|
||||
|
||||
return borrowed;
|
||||
return object->debugScript();
|
||||
}
|
||||
|
||||
/* static */
|
||||
@ -110,7 +175,7 @@ JSBreakpointSite* DebugScript::getBreakpointSite(JSScript* script,
|
||||
|
||||
/* static */
|
||||
JSBreakpointSite* DebugScript::getOrCreateBreakpointSite(JSContext* cx,
|
||||
JSScript* script,
|
||||
HandleScript script,
|
||||
jsbytecode* pc) {
|
||||
AutoRealm ar(cx, script);
|
||||
|
||||
@ -150,7 +215,7 @@ void DebugScript::destroyBreakpointSite(JSFreeOp* fop, JSScript* script,
|
||||
|
||||
debug->numSites--;
|
||||
if (!debug->needed()) {
|
||||
DebugAPI::destroyDebugScript(fop, script);
|
||||
DebugAPI::removeDebugScript(fop, script);
|
||||
}
|
||||
|
||||
if (script->hasBaselineScript()) {
|
||||
@ -194,7 +259,7 @@ uint32_t DebugScript::getStepperCount(JSScript* script) {
|
||||
#endif // DEBUG
|
||||
|
||||
/* static */
|
||||
bool DebugScript::incrementStepperCount(JSContext* cx, JSScript* script) {
|
||||
bool DebugScript::incrementStepperCount(JSContext* cx, HandleScript script) {
|
||||
cx->check(script);
|
||||
MOZ_ASSERT(cx->realm()->isDebuggee());
|
||||
|
||||
@ -230,14 +295,14 @@ void DebugScript::decrementStepperCount(JSFreeOp* fop, JSScript* script) {
|
||||
}
|
||||
|
||||
if (!debug->needed()) {
|
||||
DebugAPI::destroyDebugScript(fop, script);
|
||||
DebugAPI::removeDebugScript(fop, script);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool DebugScript::incrementGeneratorObserverCount(JSContext* cx,
|
||||
JSScript* script) {
|
||||
HandleScript script) {
|
||||
cx->check(script);
|
||||
MOZ_ASSERT(cx->realm()->isDebuggee());
|
||||
|
||||
@ -270,19 +335,12 @@ void DebugScript::decrementGeneratorObserverCount(JSFreeOp* fop,
|
||||
debug->generatorObserverCount--;
|
||||
|
||||
if (!debug->needed()) {
|
||||
DebugAPI::destroyDebugScript(fop, script);
|
||||
DebugAPI::removeDebugScript(fop, script);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void DebugAPI::traceDebugScript(JSTracer* trc, JSScript* script) {
|
||||
MOZ_ASSERT(script->hasDebugScript());
|
||||
DebugScript::get(script)->trace(trc, script);
|
||||
}
|
||||
|
||||
void DebugScript::trace(JSTracer* trc, JSScript* owner) {
|
||||
size_t length = owner->length();
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
void DebugScript::trace(JSTracer* trc) {
|
||||
for (size_t i = 0; i < codeLength; i++) {
|
||||
JSBreakpointSite* site = breakpoints[i];
|
||||
if (site) {
|
||||
site->trace(trc);
|
||||
@ -291,31 +349,34 @@ void DebugScript::trace(JSTracer* trc, JSScript* owner) {
|
||||
}
|
||||
|
||||
/* static */
|
||||
void DebugAPI::destroyDebugScript(JSFreeOp* fop, JSScript* script) {
|
||||
void DebugAPI::removeDebugScript(JSFreeOp* fop, JSScript* script) {
|
||||
if (script->hasDebugScript()) {
|
||||
DebugScriptMap* map = script->zone()->debugScriptMap.get();
|
||||
if (IsAboutToBeFinalizedUnbarriered(&script)) {
|
||||
// The script is dying and all breakpoint data will be cleaned up.
|
||||
return;
|
||||
}
|
||||
|
||||
DebugScriptMap* map = script->zone()->debugScriptMap;
|
||||
MOZ_ASSERT(map);
|
||||
DebugScriptMap::Ptr p = map->lookup(script);
|
||||
DebugScriptMap::Ptr p = map->lookupUnbarriered(script);
|
||||
MOZ_ASSERT(p);
|
||||
DebugScript* debug = p->value().release();
|
||||
map->remove(p);
|
||||
script->setHasDebugScript(false);
|
||||
|
||||
debug->delete_(fop, script);
|
||||
// The DebugScript will be destroyed at the next GC when its owning
|
||||
// DebugScriptObject dies.
|
||||
}
|
||||
}
|
||||
|
||||
void DebugScript::delete_(JSFreeOp* fop, JSScript* owner) {
|
||||
size_t length = owner->length();
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
void DebugScript::delete_(JSFreeOp* fop, DebugScriptObject* owner) {
|
||||
for (size_t i = 0; i < codeLength; i++) {
|
||||
JSBreakpointSite* site = breakpoints[i];
|
||||
if (site) {
|
||||
site->delete_(fop);
|
||||
}
|
||||
}
|
||||
|
||||
fop->free_(owner, this, allocSize(owner->length()),
|
||||
MemoryUse::ScriptDebugScript);
|
||||
fop->free_(owner, this, allocSize(codeLength), MemoryUse::ScriptDebugScript);
|
||||
}
|
||||
|
||||
#ifdef JSGC_HASH_TABLE_CHECKS
|
||||
@ -341,4 +402,12 @@ bool DebugAPI::hasBreakpointsAtSlow(JSScript* script, jsbytecode* pc) {
|
||||
return !!site;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void DebugAPI::traceDebugScriptMap(JSTracer* trc, DebugScriptMap* map) {
|
||||
map->trace(trc);
|
||||
}
|
||||
|
||||
/* static */
|
||||
void DebugAPI::deleteDebugScriptMap(DebugScriptMap* map) { js_delete(map); }
|
||||
|
||||
} // namespace js
|
||||
|
@ -14,6 +14,9 @@
|
||||
#include "jsapi.h"
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "gc/WeakMap.h"
|
||||
#include "vm/NativeObject.h"
|
||||
|
||||
namespace JS {
|
||||
class JS_PUBLIC_API Realm;
|
||||
}
|
||||
@ -22,11 +25,13 @@ namespace js {
|
||||
|
||||
class JSBreakpointSite;
|
||||
class Debugger;
|
||||
class DebugScriptObject;
|
||||
|
||||
// DebugScript manages the internal debugger state for a JSScript, which may be
|
||||
// associated with multiple Debuggers.
|
||||
class DebugScript {
|
||||
friend class DebugAPI;
|
||||
friend class DebugScriptObject;
|
||||
|
||||
/*
|
||||
* If this is a generator script, this is the number of Debugger.Frames
|
||||
@ -48,17 +53,22 @@ class DebugScript {
|
||||
*/
|
||||
uint32_t stepperCount;
|
||||
|
||||
/*
|
||||
* The size of the script as reported by BaseScript::length. This is the
|
||||
* length of the DebugScript::breakpoints array, below.
|
||||
*/
|
||||
size_t codeLength;
|
||||
|
||||
/*
|
||||
* Number of breakpoint sites at opcodes in the script. This is the number
|
||||
* of populated entries in DebugScript::breakpoints, below.
|
||||
* of populated entries in DebugScript::breakpoints.
|
||||
*/
|
||||
uint32_t numSites;
|
||||
|
||||
/*
|
||||
* Breakpoints set in our script. For speed and simplicity, this array is
|
||||
* parallel to script->code(): the JSBreakpointSite for the opcode at
|
||||
* script->code()[offset] is debugScript->breakpoints[offset]. Naturally,
|
||||
* this array's true length is script->length().
|
||||
* script->code()[offset] is debugScript->breakpoints[offset].
|
||||
*/
|
||||
JSBreakpointSite* breakpoints[1];
|
||||
|
||||
@ -75,16 +85,16 @@ class DebugScript {
|
||||
codeLength * sizeof(JSBreakpointSite*);
|
||||
}
|
||||
|
||||
void trace(JSTracer* trc, JSScript* owner);
|
||||
void delete_(JSFreeOp* fop, JSScript* owner);
|
||||
void trace(JSTracer* trc);
|
||||
void delete_(JSFreeOp* fop, DebugScriptObject* owner);
|
||||
|
||||
static DebugScript* get(JSScript* script);
|
||||
static DebugScript* getOrCreate(JSContext* cx, JSScript* script);
|
||||
static DebugScript* getOrCreate(JSContext* cx, HandleScript script);
|
||||
|
||||
public:
|
||||
static JSBreakpointSite* getBreakpointSite(JSScript* script, jsbytecode* pc);
|
||||
static JSBreakpointSite* getOrCreateBreakpointSite(JSContext* cx,
|
||||
JSScript* script,
|
||||
HandleScript script,
|
||||
jsbytecode* pc);
|
||||
static void destroyBreakpointSite(JSFreeOp* fop, JSScript* script,
|
||||
jsbytecode* pc);
|
||||
@ -103,7 +113,7 @@ class DebugScript {
|
||||
* Only incrementing is fallible, as it could allocate a DebugScript.
|
||||
*/
|
||||
[[nodiscard]] static bool incrementStepperCount(JSContext* cx,
|
||||
JSScript* script);
|
||||
HandleScript script);
|
||||
static void decrementStepperCount(JSFreeOp* fop, JSScript* script);
|
||||
|
||||
/*
|
||||
@ -112,11 +122,38 @@ class DebugScript {
|
||||
*
|
||||
* Only incrementing is fallible, as it could allocate a DebugScript.
|
||||
*/
|
||||
[[nodiscard]] static bool incrementGeneratorObserverCount(JSContext* cx,
|
||||
JSScript* script);
|
||||
[[nodiscard]] static bool incrementGeneratorObserverCount(
|
||||
JSContext* cx, HandleScript script);
|
||||
static void decrementGeneratorObserverCount(JSFreeOp* fop, JSScript* script);
|
||||
};
|
||||
|
||||
using UniqueDebugScript = js::UniquePtr<DebugScript, JS::FreePolicy>;
|
||||
|
||||
// A JSObject that wraps a DebugScript, so we can use it as the value in a
|
||||
// WeakMap. This object owns the DebugScript and is responsible for deleting it.
|
||||
class DebugScriptObject : public NativeObject {
|
||||
public:
|
||||
static const JSClass class_;
|
||||
|
||||
static DebugScriptObject* create(JSContext* cx, UniqueDebugScript debugScript,
|
||||
size_t nbytes);
|
||||
|
||||
DebugScript* debugScript() const;
|
||||
|
||||
private:
|
||||
static const JSClassOps classOps_;
|
||||
|
||||
static void trace(JSTracer* trc, JSObject* obj);
|
||||
static void finalize(JSFreeOp* fop, JSObject* obj);
|
||||
};
|
||||
|
||||
// A weak map from JSScripts to DebugScriptObjects.
|
||||
class DebugScriptMap
|
||||
: public WeakMap<HeapPtr<JSScript*>, HeapPtr<DebugScriptObject*>> {
|
||||
public:
|
||||
explicit DebugScriptMap(JSContext* cx) : WeakMap(cx) {}
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* dbg_DebugScript_h */
|
||||
|
@ -1256,7 +1256,7 @@ bool DebugAPI::slowPathOnNewGenerator(JSContext* cx, AbstractFramePtr frame,
|
||||
|
||||
AutoRealm ar(cx, frameObj);
|
||||
|
||||
if (!frameObj->setGeneratorInfo(cx, genObj)) {
|
||||
if (!DebuggerFrame::setGeneratorInfo(cx, frameObj, genObj)) {
|
||||
// This leaves `genObj` and `frameObj` unassociated. It's OK
|
||||
// because we won't pause again with this generator on the stack:
|
||||
// the caller will immediately discard `genObj` and unwind `frame`.
|
||||
|
@ -238,7 +238,8 @@ DebuggerFrame* DebuggerFrame::create(
|
||||
JSContext* cx, HandleObject proto, HandleNativeObject debugger,
|
||||
const FrameIter* maybeIter,
|
||||
Handle<AbstractGeneratorObject*> maybeGenerator) {
|
||||
DebuggerFrame* frame = NewObjectWithGivenProto<DebuggerFrame>(cx, proto);
|
||||
RootedDebuggerFrame frame(cx,
|
||||
NewObjectWithGivenProto<DebuggerFrame>(cx, proto));
|
||||
if (!frame) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -255,7 +256,7 @@ DebuggerFrame* DebuggerFrame::create(
|
||||
}
|
||||
|
||||
if (maybeGenerator) {
|
||||
if (!frame->setGeneratorInfo(cx, maybeGenerator)) {
|
||||
if (!DebuggerFrame::setGeneratorInfo(cx, frame, maybeGenerator)) {
|
||||
frame->freeFrameIterData(cx->runtime()->defaultFreeOp());
|
||||
return nullptr;
|
||||
}
|
||||
@ -316,6 +317,12 @@ class DebuggerFrame::GeneratorInfo {
|
||||
: unwrappedGenerator_(ObjectValue(*unwrappedGenerator)),
|
||||
generatorScript_(generatorScript) {}
|
||||
|
||||
// Trace a rooted instance of this class, e.g. a Rooted<GeneratorInfo>.
|
||||
void trace(JSTracer* tracer) {
|
||||
TraceRoot(tracer, &unwrappedGenerator_, "Debugger.Frame generator object");
|
||||
TraceRoot(tracer, &generatorScript_, "Debugger.Frame generator script");
|
||||
}
|
||||
// Trace a GeneratorInfo from a DebuggerFrame object.
|
||||
void trace(JSTracer* tracer, DebuggerFrame& frameObj) {
|
||||
TraceCrossCompartmentEdge(tracer, &frameObj, &unwrappedGenerator_,
|
||||
"Debugger.Frame generator object");
|
||||
@ -349,19 +356,20 @@ JSScript* js::DebuggerFrame::generatorScript() const {
|
||||
}
|
||||
#endif
|
||||
|
||||
bool DebuggerFrame::setGeneratorInfo(JSContext* cx,
|
||||
/* static */
|
||||
bool DebuggerFrame::setGeneratorInfo(JSContext* cx, HandleDebuggerFrame frame,
|
||||
Handle<AbstractGeneratorObject*> genObj) {
|
||||
cx->check(this);
|
||||
cx->check(frame);
|
||||
|
||||
MOZ_ASSERT(!hasGeneratorInfo());
|
||||
MOZ_ASSERT(!frame->hasGeneratorInfo());
|
||||
MOZ_ASSERT(!genObj->isClosed());
|
||||
|
||||
// When we initialize the generator information, we do not need to adjust
|
||||
// the stepper increment, because either it was already incremented when
|
||||
// the step hook was added, or we're setting this into on a new DebuggerFrame
|
||||
// that has not yet had the chance for a hook to be added to it.
|
||||
MOZ_ASSERT_IF(onStepHandler(), frameIterData());
|
||||
MOZ_ASSERT_IF(!frameIterData(), !onStepHandler());
|
||||
MOZ_ASSERT_IF(frame->onStepHandler(), frame->frameIterData());
|
||||
MOZ_ASSERT_IF(!frame->frameIterData(), !frame->onStepHandler());
|
||||
|
||||
// There are two relations we must establish:
|
||||
//
|
||||
@ -370,7 +378,8 @@ bool DebuggerFrame::setGeneratorInfo(JSContext* cx,
|
||||
// 2) The generator's script's observer count must be bumped.
|
||||
|
||||
RootedScript script(cx, genObj->callee().nonLazyScript());
|
||||
auto info = cx->make_unique<GeneratorInfo>(genObj, script);
|
||||
Rooted<UniquePtr<GeneratorInfo>> info(
|
||||
cx, cx->make_unique<GeneratorInfo>(genObj, script));
|
||||
if (!info) {
|
||||
return false;
|
||||
}
|
||||
@ -389,7 +398,7 @@ bool DebuggerFrame::setGeneratorInfo(JSContext* cx,
|
||||
return false;
|
||||
}
|
||||
|
||||
InitReservedSlot(this, GENERATOR_INFO_SLOT, info.release(),
|
||||
InitReservedSlot(frame, GENERATOR_INFO_SLOT, info.release(),
|
||||
MemoryUse::DebuggerFrameGeneratorInfo);
|
||||
return true;
|
||||
}
|
||||
@ -761,9 +770,14 @@ DebuggerFrameImplementation DebuggerFrame::getImplementation(
|
||||
*/
|
||||
/* static */
|
||||
bool DebuggerFrame::setOnStepHandler(JSContext* cx, HandleDebuggerFrame frame,
|
||||
OnStepHandler* handler) {
|
||||
UniquePtr<OnStepHandler> handlerArg) {
|
||||
// Handler has never been successfully associated with the frame so allow
|
||||
// UniquePtr to delete it rather than calling drop() if we return early from
|
||||
// this method..
|
||||
Rooted<UniquePtr<OnStepHandler>> handler(cx, std::move(handlerArg));
|
||||
|
||||
OnStepHandler* prior = frame->onStepHandler();
|
||||
if (handler == prior) {
|
||||
if (handler.get() == prior) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -802,8 +816,9 @@ bool DebuggerFrame::setOnStepHandler(JSContext* cx, HandleDebuggerFrame frame,
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
frame->setReservedSlot(ONSTEP_HANDLER_SLOT, PrivateValue(handler));
|
||||
handler->hold(frame);
|
||||
frame->setReservedSlot(ONSTEP_HANDLER_SLOT,
|
||||
PrivateValue(handler.get().release()));
|
||||
} else {
|
||||
frame->setReservedSlot(ONSTEP_HANDLER_SLOT, UndefinedValue());
|
||||
}
|
||||
@ -814,7 +829,8 @@ bool DebuggerFrame::setOnStepHandler(JSContext* cx, HandleDebuggerFrame frame,
|
||||
bool DebuggerFrame::incrementStepperCounter(JSContext* cx,
|
||||
AbstractFramePtr referent) {
|
||||
if (!referent.isWasmDebugFrame()) {
|
||||
return incrementStepperCounter(cx, referent.script());
|
||||
RootedScript script(cx, referent.script());
|
||||
return incrementStepperCounter(cx, script);
|
||||
}
|
||||
|
||||
wasm::Instance* instance = referent.asWasmDebugFrame()->instance();
|
||||
@ -827,7 +843,8 @@ bool DebuggerFrame::incrementStepperCounter(JSContext* cx,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebuggerFrame::incrementStepperCounter(JSContext* cx, JSScript* script) {
|
||||
bool DebuggerFrame::incrementStepperCounter(JSContext* cx,
|
||||
HandleScript script) {
|
||||
// Single stepping toggled off->on.
|
||||
AutoRealm ar(cx, script);
|
||||
// Ensure observability *before* incrementing the step mode count.
|
||||
@ -1770,18 +1787,15 @@ bool DebuggerFrame::CallData::onStepSetter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptedOnStepHandler* handler = nullptr;
|
||||
UniquePtr<ScriptedOnStepHandler> handler;
|
||||
if (!args[0].isUndefined()) {
|
||||
handler = cx->new_<ScriptedOnStepHandler>(&args[0].toObject());
|
||||
handler = cx->make_unique<ScriptedOnStepHandler>(&args[0].toObject());
|
||||
if (!handler) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!DebuggerFrame::setOnStepHandler(cx, frame, handler)) {
|
||||
// Handler has never been successfully associated with the frame so just
|
||||
// delete it rather than calling drop().
|
||||
js_delete(handler);
|
||||
if (!DebuggerFrame::setOnStepHandler(cx, frame, std::move(handler))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -178,7 +178,7 @@ class DebuggerFrame : public NativeObject {
|
||||
HandleDebuggerFrame frame);
|
||||
[[nodiscard]] static bool setOnStepHandler(JSContext* cx,
|
||||
HandleDebuggerFrame frame,
|
||||
OnStepHandler* handler);
|
||||
UniquePtr<OnStepHandler> handler);
|
||||
|
||||
[[nodiscard]] static JS::Result<Completion> eval(
|
||||
JSContext* cx, HandleDebuggerFrame frame,
|
||||
@ -225,8 +225,9 @@ class DebuggerFrame : public NativeObject {
|
||||
* association while the call is on the stack, and the relationships are easy
|
||||
* to discern.
|
||||
*/
|
||||
[[nodiscard]] bool setGeneratorInfo(JSContext* cx,
|
||||
Handle<AbstractGeneratorObject*> genObj);
|
||||
[[nodiscard]] static bool setGeneratorInfo(
|
||||
JSContext* cx, HandleDebuggerFrame frame,
|
||||
Handle<AbstractGeneratorObject*> genObj);
|
||||
|
||||
/*
|
||||
* Undo the effects of a prior call to setGenerator.
|
||||
@ -274,7 +275,8 @@ class DebuggerFrame : public NativeObject {
|
||||
|
||||
[[nodiscard]] bool incrementStepperCounter(JSContext* cx,
|
||||
AbstractFramePtr referent);
|
||||
[[nodiscard]] bool incrementStepperCounter(JSContext* cx, JSScript* script);
|
||||
[[nodiscard]] bool incrementStepperCounter(JSContext* cx,
|
||||
HandleScript script);
|
||||
void decrementStepperCounter(JSFreeOp* fop, JSScript* script);
|
||||
void decrementStepperCounter(JSFreeOp* fop, AbstractFramePtr referent);
|
||||
|
||||
|
@ -1230,17 +1230,6 @@ void BaseScript::traceChildren(JSTracer* trc) {
|
||||
data_->trace(trc);
|
||||
}
|
||||
|
||||
// Scripts with bytecode may have optional data stored in per-runtime or
|
||||
// per-zone maps. Note that a failed compilation must not have entries since
|
||||
// the script itself will not be marked as having bytecode.
|
||||
if (hasBytecode()) {
|
||||
JSScript* script = this->asJSScript();
|
||||
|
||||
if (hasDebugScript()) {
|
||||
DebugAPI::traceDebugScript(trc, script);
|
||||
}
|
||||
}
|
||||
|
||||
if (trc->isMarkingTracer()) {
|
||||
GCMarker::fromTracer(trc)->markImplicitEdges(this);
|
||||
}
|
||||
|
@ -449,9 +449,10 @@ class AssertNoRootsTracer final : public JS::CallbackTracer {
|
||||
}
|
||||
|
||||
public:
|
||||
// This skips tracking WeakMap entries because they are not roots.
|
||||
explicit AssertNoRootsTracer(JSRuntime* rt)
|
||||
: JS::CallbackTracer(rt, JS::TracerKind::Callback,
|
||||
JS::WeakMapTraceAction::TraceKeysAndValues) {}
|
||||
JS::WeakMapTraceAction::Skip) {}
|
||||
};
|
||||
#endif // DEBUG
|
||||
|
||||
|
@ -172,7 +172,8 @@ inline void TraceRoot(JSTracer* trc, T* thingp, const char* name) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void TraceRoot(JSTracer* trc, WeakHeapPtr<T>* thingp, const char* name) {
|
||||
inline void TraceRoot(JSTracer* trc, const HeapPtr<T>* thingp,
|
||||
const char* name) {
|
||||
TraceRoot(trc, thingp->unbarrieredAddress(), name);
|
||||
}
|
||||
|
||||
|
@ -200,9 +200,12 @@ JS::Zone::Zone(JSRuntime* rt, Kind kind)
|
||||
|
||||
Zone::~Zone() {
|
||||
MOZ_ASSERT(helperThreadUse_ == HelperThreadUse::None);
|
||||
MOZ_ASSERT(gcWeakMapList().isEmpty());
|
||||
MOZ_ASSERT_IF(regExps_.ref(), regExps().empty());
|
||||
|
||||
DebugAPI::deleteDebugScriptMap(debugScriptMap);
|
||||
|
||||
MOZ_ASSERT(gcWeakMapList().isEmpty());
|
||||
|
||||
JSRuntime* rt = runtimeFromAnyThread();
|
||||
if (this == rt->gc.systemZone) {
|
||||
MOZ_ASSERT(isSystemZone());
|
||||
@ -806,6 +809,11 @@ void Zone::traceScriptTableRoots(JSTracer* trc) {
|
||||
MOZ_ASSERT(script == r.front().key(), "const_cast is only a work-around");
|
||||
}
|
||||
}
|
||||
|
||||
// Trace the debugger's DebugScript weak map.
|
||||
if (debugScriptMap) {
|
||||
DebugAPI::traceDebugScriptMap(trc, debugScriptMap);
|
||||
}
|
||||
}
|
||||
|
||||
void Zone::fixupScriptMapsAfterMovingGC(JSTracer* trc) {
|
||||
@ -832,16 +840,6 @@ void Zone::fixupScriptMapsAfterMovingGC(JSTracer* trc) {
|
||||
}
|
||||
}
|
||||
|
||||
if (debugScriptMap) {
|
||||
for (DebugScriptMap::Enum e(*debugScriptMap); !e.empty(); e.popFront()) {
|
||||
BaseScript* script = e.front().key();
|
||||
if (!IsAboutToBeFinalizedUnbarriered(&script) &&
|
||||
script != e.front().key()) {
|
||||
e.rekeyFront(script);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_VTUNE
|
||||
if (scriptVTuneIdMap) {
|
||||
for (ScriptVTuneIdMap::Enum e(*scriptVTuneIdMap); !e.empty();
|
||||
@ -891,18 +889,6 @@ void Zone::checkScriptMapsAfterMovingGC() {
|
||||
}
|
||||
}
|
||||
|
||||
if (debugScriptMap) {
|
||||
for (auto r = debugScriptMap->all(); !r.empty(); r.popFront()) {
|
||||
BaseScript* script = r.front().key();
|
||||
MOZ_ASSERT(script->zone() == this);
|
||||
CheckGCThingAfterMovingGC(script);
|
||||
DebugScript* ds = r.front().value().get();
|
||||
DebugAPI::checkDebugScriptAfterMovingGC(ds);
|
||||
auto ptr = debugScriptMap->lookup(script);
|
||||
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
|
||||
}
|
||||
}
|
||||
|
||||
# ifdef MOZ_VTUNE
|
||||
if (scriptVTuneIdMap) {
|
||||
for (auto r = scriptVTuneIdMap->all(); !r.empty(); r.popFront()) {
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
namespace js {
|
||||
|
||||
class DebugScriptMap;
|
||||
class RegExpZone;
|
||||
class WeakRefObject;
|
||||
|
||||
@ -219,7 +220,7 @@ class Zone : public js::ZoneAllocator, public js::gc::GraphNodeBase<JS::Zone> {
|
||||
// JSScript.
|
||||
js::UniquePtr<js::ScriptCountsMap> scriptCountsMap;
|
||||
js::UniquePtr<js::ScriptLCovMap> scriptLCovMap;
|
||||
js::UniquePtr<js::DebugScriptMap> debugScriptMap;
|
||||
js::MainThreadData<js::DebugScriptMap*> debugScriptMap;
|
||||
#ifdef MOZ_VTUNE
|
||||
js::UniquePtr<js::ScriptVTuneIdMap> scriptVTuneIdMap;
|
||||
#endif
|
||||
|
@ -634,8 +634,6 @@ void js::BaseScript::finalize(JSFreeOp* fop) {
|
||||
}
|
||||
|
||||
script->destroyScriptCounts();
|
||||
|
||||
DebugAPI::destroyDebugScript(fop, script);
|
||||
}
|
||||
|
||||
fop->runtime()->geckoProfiler().onScriptFinalized(this);
|
||||
|
@ -178,10 +178,6 @@ using ScriptFinalWarmUpCountMap =
|
||||
DefaultHasher<BaseScript*>, SystemAllocPolicy>;
|
||||
#endif
|
||||
|
||||
using UniqueDebugScript = js::UniquePtr<DebugScript, JS::FreePolicy>;
|
||||
using DebugScriptMap = HashMap<BaseScript*, UniqueDebugScript,
|
||||
DefaultHasher<BaseScript*>, SystemAllocPolicy>;
|
||||
|
||||
class ScriptSource;
|
||||
|
||||
struct ScriptSourceChunk {
|
||||
|
Loading…
Reference in New Issue
Block a user