diff --git a/js/src/ds/Fifo.h b/js/src/ds/Fifo.h deleted file mode 100644 index de482e7a240f..000000000000 --- a/js/src/ds/Fifo.h +++ /dev/null @@ -1,154 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef js_Fifo_h -#define js_Fifo_h - -#include "mozilla/Move.h" - -#include "js/Vector.h" - -namespace js { - -// A first-in-first-out queue container type. Fifo calls constructors and -// destructors of all elements added so non-PODs may be used safely. |Fifo| -// stores the first |MinInlineCapacity| elements in-place before resorting to -// dynamic allocation. -// -// T requirements: -// - Either movable or copyable. -// MinInlineCapacity requirements: -// - Must be even. -// AllocPolicy: -// - see "Allocation policies" in AllocPolicy.h -template -class Fifo -{ - static_assert(MinInlineCapacity % 2 == 0, "MinInlineCapacity must be even!"); - - protected: - // An element A is "younger" than an element B if B was inserted into the - // |Fifo| before A was. - // - // Invariant 1: Every element within |front_| is younger than every element - // within |rear_|. - // Invariant 2: Entries within |front_| are sorted from younger to older. - // Invariant 3: Entries within |rear_| are sorted from older to younger. - // Invariant 4: If the |Fifo| is not empty, then |front_| is not empty. - Vector front_; - Vector rear_; - - private: - // Maintain invariants after adding or removing entries. - bool fixup() { - if (!front_.empty()) - return true; - - if (!front_.reserve(rear_.length())) - return false; - - while (!rear_.empty()) { - front_.infallibleAppend(mozilla::Move(rear_.back())); - rear_.popBack(); - } - - return true; - } - - public: - explicit Fifo(AllocPolicy alloc = AllocPolicy()) - : front_(alloc) - , rear_(alloc) - { } - - Fifo(Fifo&& rhs) - : front_(mozilla::Move(rhs.front_)) - , rear_(mozilla::Move(rhs.rear_)) - { } - - Fifo& operator=(Fifo&& rhs) { - MOZ_ASSERT(&rhs != this, "self-move disallowed"); - this->~Fifo(); - new (this) Fifo(mozilla::Move(rhs)); - return *this; - } - - Fifo(const Fifo&) = delete; - Fifo& operator=(const Fifo&) = delete; - - size_t length() const { - MOZ_ASSERT_IF(rear_.length() > 0, front_.length() > 0); // Invariant 4. - return front_.length() + rear_.length(); - } - - bool empty() const { - MOZ_ASSERT_IF(rear_.length() > 0, front_.length() > 0); // Invariant 4. - return front_.empty(); - } - - // Push an element to the back of the queue. This method can take either a - // |const T&| or a |T&&|. - template - bool pushBack(U&& u) { - if (!rear_.append(mozilla::Forward(u))) - return false; - if (!fixup()) { - rear_.popBack(); - return false; - } - return true; - } - - // Construct a T in-place at the back of the queue. - template - bool emplaceBack(Args&&... args) { - if (!rear_.emplaceBack(mozilla::Forward(args)...)) - return false; - if (!fixup()) { - rear_.popBack(); - return false; - } - return true; - } - - // Access the element at the front of the queue. - T& front() { - MOZ_ASSERT(!empty()); - return front_.back(); - } - const T& front() const { - MOZ_ASSERT(!empty()); - return front_.back(); - } - - // Remove the front element from the queue. - bool popFront() { - MOZ_ASSERT(!empty()); - T t(mozilla::Move(front())); - front_.popBack(); - if (!fixup()) { - // Attempt to remain in a valid state by reinserting the element - // back at the front. If we can't remain in a valid state in the - // face of OOMs, crash. - if (!front_.append(mozilla::Move(t))) - CrashAtUnhandlableOOM("js::Fifo::popFront"); - return false; - } - return true; - } - - // Clear all elements from the queue. - void clear() { - front_.clear(); - rear_.clear(); - } -}; - -} // namespace js - -#endif /* js_Fifo_h */ diff --git a/js/src/ds/TraceableFifo.h b/js/src/ds/TraceableFifo.h deleted file mode 100644 index 7edcf2975fe2..000000000000 --- a/js/src/ds/TraceableFifo.h +++ /dev/null @@ -1,130 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef js_TraceableFifo_h -#define js_TraceableFifo_h - -#include "ds/Fifo.h" -#include "js/RootingAPI.h" - -namespace js { - -template struct DefaultTracer; - -// A TraceableFifo is a Fifo with an additional trace method that knows how to -// visit all of the items stored in the Fifo. For Fifos that contain GC things, -// this is usually more convenient than manually iterating and marking the -// contents. -// -// Most types of GC pointers as keys and values can be traced with no extra -// infrastructure. For structs and non-gc-pointer members, ensure that there is -// a specialization of DefaultTracer with an appropriate trace method -// available to handle the custom type. -// -// Note that although this Fifo's trace will deal correctly with moved items, it -// does not itself know when to barrier or trace items. To function properly it -// must either be used with Rooted, or barriered and traced manually. -template > -class TraceableFifo - : public js::Fifo, - public JS::Traceable -{ - using Base = js::Fifo; - - public: - explicit TraceableFifo(AllocPolicy alloc = AllocPolicy()) : Base(alloc) {} - - TraceableFifo(TraceableFifo&& rhs) : Base(mozilla::Move(rhs)) { } - TraceableFifo& operator=(TraceableFifo&& rhs) { return Base::operator=(mozilla::Move(rhs)); } - - TraceableFifo(const TraceableFifo&) = delete; - TraceableFifo& operator=(const TraceableFifo&) = delete; - - static void trace(TraceableFifo* tf, JSTracer* trc) { - for (size_t i = 0; i < tf->front_.length(); ++i) - TraceFunc::trace(trc, &tf->front_[i], "fifo element"); - for (size_t i = 0; i < tf->rear_.length(); ++i) - TraceFunc::trace(trc, &tf->rear_[i], "fifo element"); - } -}; - -template -class TraceableFifoOperations -{ - using TF = TraceableFifo; - const TF& fifo() const { return static_cast(this)->extract(); } - - public: - size_t length() const { return fifo().length(); } - bool empty() const { return fifo().empty(); } - const T& front() const { return fifo().front(); } -}; - -template -class MutableTraceableFifoOperations - : public TraceableFifoOperations -{ - using TF = TraceableFifo; - TF& fifo() { return static_cast(this)->extract(); } - - public: - T& front() { return fifo().front(); } - - template bool pushBack(U&& u) { return fifo().pushBack(mozilla::Forward(u)); } - template bool emplaceBack(Args&&... args) { - return fifo().emplaceBack(mozilla::Forward(args...)); - } - - bool popFront() { return fifo().popFront(); } - void clear() { fifo().clear(); } -}; - -template -class RootedBase> - : public MutableTraceableFifoOperations>, A,B,C,D> -{ - using TF = TraceableFifo; - - friend class TraceableFifoOperations, A,B,C,D>; - const TF& extract() const { return *static_cast*>(this)->address(); } - - friend class MutableTraceableFifoOperations, A,B,C,D>; - TF& extract() { return *static_cast*>(this)->address(); } -}; - -template -class MutableHandleBase> - : public MutableTraceableFifoOperations>, A,B,C,D> -{ - using TF = TraceableFifo; - - friend class TraceableFifoOperations, A,B,C,D>; - const TF& extract() const { - return *static_cast*>(this)->address(); - } - - friend class MutableTraceableFifoOperations, A,B,C,D>; - TF& extract() { return *static_cast*>(this)->address(); } -}; - -template -class HandleBase> - : public TraceableFifoOperations>, A,B,C,D> -{ - using TF = TraceableFifo; - - friend class TraceableFifoOperations, A,B,C,D>; - const TF& extract() const { - return *static_cast*>(this)->address(); - } -}; - -} // namespace js - -#endif // js_TraceableFifo_h diff --git a/js/src/jsapi-tests/testGCExactRooting.cpp b/js/src/jsapi-tests/testGCExactRooting.cpp index d6b7709364d5..32982b623702 100644 --- a/js/src/jsapi-tests/testGCExactRooting.cpp +++ b/js/src/jsapi-tests/testGCExactRooting.cpp @@ -5,7 +5,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "ds/TraceableFifo.h" #include "js/RootingAPI.h" #include "js/TraceableHashTable.h" #include "js/TraceableVector.h" @@ -277,47 +276,6 @@ receiveMutableHandleToShapeVector(JS::MutableHandle> han } END_TEST(testGCRootedVector) -BEGIN_TEST(testTraceableFifo) -{ - using ShapeFifo = TraceableFifo; - JS::Rooted shapes(cx, ShapeFifo(cx)); - CHECK(shapes.empty()); - - for (size_t i = 0; i < 10; ++i) { - RootedObject obj(cx, JS_NewObject(cx, nullptr)); - RootedValue val(cx, UndefinedValue()); - // Construct a unique property name to ensure that the object creates a - // new shape. - char buffer[2]; - buffer[0] = 'a' + i; - buffer[1] = '\0'; - CHECK(JS_SetProperty(cx, obj, buffer, val)); - CHECK(shapes.pushBack(obj->as().lastProperty())); - } - - CHECK(shapes.length() == 10); - - JS_GC(rt); - JS_GC(rt); - - for (size_t i = 0; i < 10; ++i) { - // Check the shape to ensure it did not get collected. - char buffer[2]; - buffer[0] = 'a' + i; - buffer[1] = '\0'; - bool match; - CHECK(JS_StringEqualsAscii(cx, JSID_TO_STRING(shapes.front()->propid()), buffer, &match)); - CHECK(match); - CHECK(shapes.popFront()); - } - - CHECK(shapes.empty()); - return true; -} -END_TEST(testTraceableFifo) - -using ShapeVec = TraceableVector; - static bool FillVector(JSContext* cx, MutableHandle shapes) { diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 42abbc81c95b..412b7b0e57d7 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -357,15 +357,15 @@ Debugger::Debugger(JSContext* cx, NativeObject* dbg) : object(dbg), uncaughtExceptionHook(nullptr), enabled(true), - allowUnobservedAsmJS(false), observedGCs(cx), - tenurePromotionsLog(cx), trackingTenurePromotions(false), + tenurePromotionsLogLength(0), maxTenurePromotionsLogLength(DEFAULT_MAX_LOG_LENGTH), tenurePromotionsLogOverflowed(false), - allocationsLog(cx), + allowUnobservedAsmJS(false), trackingAllocationSites(false), allocationSamplingProbability(1.0), + allocationsLogLength(0), maxAllocationsLogLength(DEFAULT_MAX_LOG_LENGTH), allocationsLogOverflowed(false), frames(cx->runtime()), @@ -390,8 +390,8 @@ Debugger::Debugger(JSContext* cx, NativeObject* dbg) Debugger::~Debugger() { MOZ_ASSERT_IF(debuggees.initialized(), debuggees.empty()); - allocationsLog.clear(); - tenurePromotionsLog.clear(); + emptyAllocationsLog(); + emptyTenurePromotionsLog(); /* * Since the inactive state for this link is a singleton cycle, it's always @@ -1701,7 +1701,7 @@ Debugger::isDebuggee(const JSCompartment* compartment) const return compartment->isDebuggee() && debuggees.has(compartment->maybeGlobal()); } -Debugger::TenurePromotionsLogEntry::TenurePromotionsLogEntry(JSRuntime* rt, JSObject& obj, double when) +Debugger::TenurePromotionsEntry::TenurePromotionsEntry(JSRuntime* rt, JSObject& obj, double when) : className(obj.getClass()->name), when(when), frame(getObjectAllocationSite(obj)), @@ -1712,17 +1712,43 @@ Debugger::TenurePromotionsLogEntry::TenurePromotionsLogEntry(JSRuntime* rt, JSOb void Debugger::logTenurePromotion(JSRuntime* rt, JSObject& obj, double when) { - if (!tenurePromotionsLog.emplaceBack(rt, obj, when)) + auto* entry = js_new(rt, obj, when); + if (!entry) CrashAtUnhandlableOOM("Debugger::logTenurePromotion"); - if (tenurePromotionsLog.length() > maxTenurePromotionsLogLength) { - if (!tenurePromotionsLog.popFront()) - CrashAtUnhandlableOOM("Debugger::logTenurePromotion"); - MOZ_ASSERT(tenurePromotionsLog.length() == maxTenurePromotionsLogLength); + tenurePromotionsLog.insertBack(entry); + if (tenurePromotionsLogLength >= maxTenurePromotionsLogLength) { + js_delete(tenurePromotionsLog.popFirst()); tenurePromotionsLogOverflowed = true; + } else { + tenurePromotionsLogLength++; } } +/* static */ Debugger::AllocationSite* +Debugger::AllocationSite::create(JSContext* cx, HandleObject frame, double when, HandleObject obj) +{ + assertSameCompartment(cx, frame); + + RootedAtom ctorName(cx); + { + AutoCompartment ac(cx, obj); + if (!obj->constructorDisplayAtom(cx, &ctorName)) + return nullptr; + } + + AllocationSite* allocSite = cx->new_(frame, when); + if (!allocSite) + return nullptr; + + allocSite->className = obj->getClass()->name; + allocSite->ctorName = ctorName.get(); + allocSite->size = JS::ubi::Node(obj.get()).size(cx->runtime()->debuggerMallocSizeOf); + + return allocSite; +} + + bool Debugger::appendAllocationSite(JSContext* cx, HandleObject obj, HandleSavedFrame frame, double when) @@ -1734,33 +1760,38 @@ Debugger::appendAllocationSite(JSContext* cx, HandleObject obj, HandleSavedFrame if (!cx->compartment()->wrap(cx, &wrappedFrame)) return false; - RootedAtom ctorName(cx); - { - AutoCompartment ac(cx, obj); - if (!obj->constructorDisplayAtom(cx, &ctorName)) - return false; - } - - auto className = obj->getClass()->name; - auto size = JS::ubi::Node(obj.get()).size(cx->runtime()->debuggerMallocSizeOf); - - if (!allocationsLog.emplaceBack(wrappedFrame, when, className, ctorName, size)) { - ReportOutOfMemory(cx); + AllocationSite* allocSite = AllocationSite::create(cx, wrappedFrame, when, obj); + if (!allocSite) return false; - } - if (allocationsLog.length() > maxAllocationsLogLength) { - if (!allocationsLog.popFront()) { - ReportOutOfMemory(cx); - return false; - } - MOZ_ASSERT(allocationsLog.length() == maxAllocationsLogLength); + allocationsLog.insertBack(allocSite); + + if (allocationsLogLength >= maxAllocationsLogLength) { + js_delete(allocationsLog.popFirst()); allocationsLogOverflowed = true; + } else { + allocationsLogLength++; } return true; } +void +Debugger::emptyAllocationsLog() +{ + while (!allocationsLog.isEmpty()) + js_delete(allocationsLog.popFirst()); + allocationsLogLength = 0; +} + +void +Debugger::emptyTenurePromotionsLog() +{ + while (!tenurePromotionsLog.isEmpty()) + js_delete(tenurePromotionsLog.popFirst()); + tenurePromotionsLogLength = 0; +} + JSTrapStatus Debugger::firePromiseHook(JSContext* cx, Hook hook, HandleObject promise, MutableHandleValue vp) { @@ -2301,7 +2332,7 @@ Debugger::removeAllocationsTrackingForAllDebuggees() for (WeakGlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) { Debugger::removeAllocationsTracking(*r.front().get()); } - allocationsLog.clear(); + emptyAllocationsLog(); } @@ -2320,7 +2351,19 @@ Debugger::markCrossCompartmentEdges(JSTracer* trc) // `Debugger::logTenurePromotion`, we can't hold onto CCWs inside the log, // and instead have unwrapped cross-compartment edges. We need to be sure to // mark those here. - TenurePromotionsLog::trace(&tenurePromotionsLog, trc); + traceTenurePromotionsLog(trc); +} + +/* + * Trace every entry in the promoted to tenured heap log. + */ +void +Debugger::traceTenurePromotionsLog(JSTracer* trc) +{ + for (TenurePromotionsEntry* e = tenurePromotionsLog.getFirst(); e; e = e->getNext()) { + if (e->frame) + TraceEdge(trc, &e->frame, "Debugger::tenurePromotionsLog SavedFrame"); + } } /* @@ -2501,8 +2544,17 @@ Debugger::trace(JSTracer* trc) TraceEdge(trc, &frameobj, "live Debugger.Frame"); } - AllocationsLog::trace(&allocationsLog, trc); - TenurePromotionsLog::trace(&tenurePromotionsLog, trc); + /* + * Mark every allocation site in our allocation log. + */ + for (AllocationSite* s = allocationsLog.getFirst(); s; s = s->getNext()) { + if (s->frame) + TraceEdge(trc, &s->frame, "allocation log SavedFrame"); + if (s->ctorName) + TraceEdge(trc, &s->ctorName, "allocation log constructor name"); + } + + traceTenurePromotionsLog(trc); /* Trace the weak map from JSScript instances to Debugger.Script objects. */ scripts.trace(trc); diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index b18def3b78ec..7b20d77e0cea 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -19,7 +19,6 @@ #include "jsweakmap.h" #include "jswrapper.h" -#include "ds/TraceableFifo.h" #include "gc/Barrier.h" #include "js/Debug.h" #include "js/HashTable.h" @@ -284,72 +283,63 @@ class Debugger : private mozilla::LinkedListElement void logTenurePromotion(JSRuntime* rt, JSObject& obj, double when); static JSObject* getObjectAllocationSite(JSObject& obj); - struct TenurePromotionsLogEntry : public JS::Traceable - { - TenurePromotionsLogEntry(JSRuntime* rt, JSObject& obj, double when); - - const char* className; - double when; - RelocatablePtrObject frame; - size_t size; - - static void trace(TenurePromotionsLogEntry* e, JSTracer* trc) { - if (e->frame) - TraceEdge(trc, &e->frame, "Debugger::TenurePromotionsLogEntry::frame"); - } - }; - - struct AllocationsLogEntry : public JS::Traceable - { - AllocationsLogEntry(HandleObject frame, double when, const char* className, - HandleAtom ctorName, size_t size) - : frame(frame), - when(when), - className(className), - ctorName(ctorName), - size(size) - { - MOZ_ASSERT_IF(frame, UncheckedUnwrap(frame)->is()); - }; - - RelocatablePtrObject frame; - double when; - const char* className; - RelocatablePtrAtom ctorName; - size_t size; - - static void trace(AllocationsLogEntry* e, JSTracer* trc) { - if (e->frame) - TraceEdge(trc, &e->frame, "Debugger::AllocationsLogEntry::frame"); - if (e->ctorName) - TraceEdge(trc, &e->ctorName, "Debugger::AllocationsLogEntry::ctorName"); - } - }; - private: HeapPtrNativeObject object; /* The Debugger object. Strong reference. */ WeakGlobalObjectSet debuggees; /* Debuggee globals. Cross-compartment weak references. */ JS::ZoneSet debuggeeZones; /* Set of zones that we have debuggees in. */ js::HeapPtrObject uncaughtExceptionHook; /* Strong reference. */ bool enabled; - bool allowUnobservedAsmJS; JSCList breakpoints; /* Circular list of all js::Breakpoints in this debugger */ // The set of GC numbers for which one or more of this Debugger's observed // debuggees participated in. js::HashSet observedGCs; - using TenurePromotionsLog = js::TraceableFifo; + struct TenurePromotionsEntry : public mozilla::LinkedListElement + { + TenurePromotionsEntry(JSRuntime* rt, JSObject& obj, double when); + + const char* className; + double when; + RelocatablePtrObject frame; + size_t size; + }; + + using TenurePromotionsLog = mozilla::LinkedList; TenurePromotionsLog tenurePromotionsLog; bool trackingTenurePromotions; + size_t tenurePromotionsLogLength; size_t maxTenurePromotionsLogLength; bool tenurePromotionsLogOverflowed; - using AllocationsLog = js::TraceableFifo; + struct AllocationSite : public mozilla::LinkedListElement + { + AllocationSite(HandleObject frame, double when) + : frame(frame), + when(when), + className(nullptr), + ctorName(nullptr), + size(0) + { + MOZ_ASSERT_IF(frame, UncheckedUnwrap(frame)->is()); + }; - AllocationsLog allocationsLog; + static AllocationSite* create(JSContext* cx, HandleObject frame, double when, + HandleObject obj); + + RelocatablePtrObject frame; + double when; + const char* className; + RelocatablePtrAtom ctorName; + size_t size; + }; + typedef mozilla::LinkedList AllocationSiteList; + + bool allowUnobservedAsmJS; bool trackingAllocationSites; double allocationSamplingProbability; + AllocationSiteList allocationsLog; + size_t allocationsLogLength; size_t maxAllocationsLogLength; bool allocationsLogOverflowed; @@ -357,6 +347,8 @@ class Debugger : private mozilla::LinkedListElement bool appendAllocationSite(JSContext* cx, HandleObject obj, HandleSavedFrame frame, double when); + void emptyAllocationsLog(); + void emptyTenurePromotionsLog(); /* * Recompute the set of debuggee zones based on the set of debuggee globals. @@ -511,6 +503,7 @@ class Debugger : private mozilla::LinkedListElement void trace(JSTracer* trc); static void finalize(FreeOp* fop, JSObject* obj); void markCrossCompartmentEdges(JSTracer* tracer); + void traceTenurePromotionsLog(JSTracer* trc); static const Class jsclass; @@ -927,20 +920,6 @@ class Debugger : private mozilla::LinkedListElement Debugger & operator=(const Debugger&) = delete; }; -template<> -struct DefaultTracer { - static void trace(JSTracer* trc, Debugger::TenurePromotionsLogEntry* e, const char*) { - Debugger::TenurePromotionsLogEntry::trace(e, trc); - } -}; - -template<> -struct DefaultTracer { - static void trace(JSTracer* trc, Debugger::AllocationsLogEntry* e, const char*) { - Debugger::AllocationsLogEntry::trace(e, trc); - } -}; - class BreakpointSite { friend class Breakpoint; friend struct ::JSCompartment; diff --git a/js/src/vm/DebuggerMemory.cpp b/js/src/vm/DebuggerMemory.cpp index 2ee25fdb7d78..08c1ec82f094 100644 --- a/js/src/vm/DebuggerMemory.cpp +++ b/js/src/vm/DebuggerMemory.cpp @@ -185,7 +185,7 @@ DebuggerMemory::drainAllocationsLog(JSContext* cx, unsigned argc, Value* vp) return false; } - size_t length = dbg->allocationsLog.length(); + size_t length = dbg->allocationsLogLength; RootedArrayObject result(cx, NewDenseFullyAllocatedArray(cx, length)); if (!result) @@ -197,21 +197,21 @@ DebuggerMemory::drainAllocationsLog(JSContext* cx, unsigned argc, Value* vp) if (!obj) return false; - // Don't pop the AllocationsLogEntry yet. The queue's links are followed - // by the GC to find the AllocationsLogEntry, but are not barriered, so - // we must edit them with great care. Use the queue entry in place, and - // then pop and delete together. - Debugger::AllocationsLogEntry& entry = dbg->allocationsLog.front(); + // Don't pop the AllocationSite yet. The queue's links are followed by + // the GC to find the AllocationSite, but are not barriered, so we must + // edit them with great care. Use the queue entry in place, and then + // pop and delete together. + Debugger::AllocationSite* allocSite = dbg->allocationsLog.getFirst(); - RootedValue frame(cx, ObjectOrNullValue(entry.frame)); + RootedValue frame(cx, ObjectOrNullValue(allocSite->frame)); if (!DefineProperty(cx, obj, cx->names().frame, frame)) return false; - RootedValue timestampValue(cx, NumberValue(entry.when)); + RootedValue timestampValue(cx, NumberValue(allocSite->when)); if (!DefineProperty(cx, obj, cx->names().timestamp, timestampValue)) return false; - RootedString className(cx, Atomize(cx, entry.className, strlen(entry.className))); + RootedString className(cx, Atomize(cx, allocSite->className, strlen(allocSite->className))); if (!className) return false; RootedValue classNameValue(cx, StringValue(className)); @@ -219,27 +219,26 @@ DebuggerMemory::drainAllocationsLog(JSContext* cx, unsigned argc, Value* vp) return false; RootedValue ctorName(cx, NullValue()); - if (entry.ctorName) - ctorName.setString(entry.ctorName); + if (allocSite->ctorName) + ctorName.setString(allocSite->ctorName); if (!DefineProperty(cx, obj, cx->names().constructor, ctorName)) return false; - RootedValue size(cx, NumberValue(entry.size)); + RootedValue size(cx, NumberValue(allocSite->size)); if (!DefineProperty(cx, obj, cx->names().size, size)) return false; result->setDenseElement(i, ObjectValue(*obj)); - // Pop the front queue entry, and delete it immediately, so that the GC - // sees the AllocationsLogEntry's RelocatablePtr barriers run atomically - // with the change to the graph (the queeue link). - if (!dbg->allocationsLog.popFront()) { - ReportOutOfMemory(cx); - return false; - } + // Pop the front queue entry, and delete it immediately, so that + // the GC sees the AllocationSite's RelocatablePtr barriers run + // atomically with the change to the graph (the queue link). + MOZ_ALWAYS_TRUE(dbg->allocationsLog.popFirst() == allocSite); + js_delete(allocSite); } dbg->allocationsLogOverflowed = false; + dbg->allocationsLogLength = 0; args.rval().setObject(*result); return true; } @@ -273,11 +272,9 @@ DebuggerMemory::setMaxAllocationsLogLength(JSContext* cx, unsigned argc, Value* Debugger* dbg = memory->getDebugger(); dbg->maxAllocationsLogLength = max; - while (dbg->allocationsLog.length() > dbg->maxAllocationsLogLength) { - if (!dbg->allocationsLog.popFront()) { - ReportOutOfMemory(cx); - return false; - } + while (dbg->allocationsLogLength > dbg->maxAllocationsLogLength) { + js_delete(dbg->allocationsLog.getFirst()); + dbg->allocationsLogLength--; } args.rval().setUndefined(); @@ -355,7 +352,7 @@ DebuggerMemory::drainTenurePromotionsLog(JSContext* cx, unsigned argc, Value* vp return false; } - size_t length = dbg->tenurePromotionsLog.length(); + size_t length = dbg->tenurePromotionsLogLength; RootedArrayObject result(cx, NewDenseFullyAllocatedArray(cx, length)); if (!result) @@ -371,42 +368,41 @@ DebuggerMemory::drainTenurePromotionsLog(JSContext* cx, unsigned argc, Value* vp // followed by the GC to find the TenurePromotionsEntry, but are not // barriered, so we must edit them with great care. Use the queue entry // in place, and then pop and delete together. - auto& entry = dbg->tenurePromotionsLog.front(); + auto* entry = dbg->tenurePromotionsLog.getFirst(); - RootedValue frame(cx, ObjectOrNullValue(entry.frame)); + RootedValue frame(cx, ObjectOrNullValue(entry->frame)); if (!cx->compartment()->wrap(cx, &frame) || !DefineProperty(cx, obj, cx->names().frame, frame)) { return false; } - RootedValue timestampValue(cx, NumberValue(entry.when)); + RootedValue timestampValue(cx, NumberValue(entry->when)); if (!DefineProperty(cx, obj, cx->names().timestamp, timestampValue)) return false; - RootedString className(cx, Atomize(cx, entry.className, strlen(entry.className))); + RootedString className(cx, Atomize(cx, entry->className, strlen(entry->className))); if (!className) return false; RootedValue classNameValue(cx, StringValue(className)); if (!DefineProperty(cx, obj, cx->names().class_, classNameValue)) return false; - RootedValue sizeValue(cx, NumberValue(entry.size)); + RootedValue sizeValue(cx, NumberValue(entry->size)); if (!DefineProperty(cx, obj, cx->names().size, sizeValue)) return false; result->setDenseElement(i, ObjectValue(*obj)); - // Pop the front queue entry, and delete it immediately, so that the GC - // sees the TenurePromotionsEntry's RelocatablePtr barriers run + // Pop the front queue entry, and delete it immediately, so that + // the GC sees the TenurePromotionsEntry's RelocatablePtr barriers run // atomically with the change to the graph (the queue link). - if (!dbg->tenurePromotionsLog.popFront()) { - ReportOutOfMemory(cx); - return false; - } + MOZ_ALWAYS_TRUE(dbg->tenurePromotionsLog.popFirst() == entry); + js_delete(entry); } dbg->tenurePromotionsLogOverflowed = false; + dbg->tenurePromotionsLogLength = 0; args.rval().setObject(*result); return true; } @@ -440,11 +436,9 @@ DebuggerMemory::setMaxTenurePromotionsLogLength(JSContext* cx, unsigned argc, Va Debugger* dbg = memory->getDebugger(); dbg->maxTenurePromotionsLogLength = max; - while (dbg->tenurePromotionsLog.length() > dbg->maxAllocationsLogLength) { - if (!dbg->tenurePromotionsLog.popFront()) { - ReportOutOfMemory(cx); - return false; - } + while (dbg->tenurePromotionsLogLength > dbg->maxAllocationsLogLength) { + js_delete(dbg->tenurePromotionsLog.getFirst()); + dbg->tenurePromotionsLogLength--; } args.rval().setUndefined();