☠☠ backed out by af32792fe260 ☠ ☠ | |
author | Nick Fitzgerald <fitzgen@gmail.com> |
Sat, 08 Aug 2015 15:19:52 -0700 | |
changeset 256979 | 8bf626d3a647f94a8512c831f7f634e8c98acee1 |
parent 256978 | 1a1ad27321de3383031cc3fdf38d042ada6c34ee |
child 256980 | 1ec4867e4e8c0c5acb59a8d8d9b1f85b1b6def90 |
push id | 29197 |
push user | philringnalda@gmail.com |
push date | Sun, 09 Aug 2015 20:35:19 +0000 |
treeherder | mozilla-central@fd69d51a4068 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | terrence |
bugs | 1189490 |
milestone | 42.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -352,25 +352,25 @@ Breakpoint::nextInSite() /*** Debugger hook dispatch **********************************************************************/ 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), - allowUnobservedAsmJS(false), + allocationsLog(cx), trackingAllocationSites(false), allocationSamplingProbability(1.0), - allocationsLogLength(0), maxAllocationsLogLength(DEFAULT_MAX_LOG_LENGTH), allocationsLogOverflowed(false), frames(cx->runtime()), scripts(cx), sources(cx), objects(cx), environments(cx), #ifdef NIGHTLY_BUILD @@ -385,18 +385,18 @@ Debugger::Debugger(JSContext* cx, Native cx->runtime()->debuggerList.insertBack(this); JS_INIT_CLIST(&breakpoints); JS_INIT_CLIST(&onNewGlobalObjectWatchersLink); } Debugger::~Debugger() { MOZ_ASSERT_IF(debuggees.initialized(), debuggees.empty()); - emptyAllocationsLog(); - emptyTenurePromotionsLog(); + allocationsLog.clear(); + tenurePromotionsLog.clear(); /* * Since the inactive state for this link is a singleton cycle, it's always * safe to apply JS_REMOVE_LINK to it, regardless of whether we're in the list or not. * * We don't have to worry about locking here since Debugger is not * background finalized. */ @@ -1696,105 +1696,75 @@ Debugger::slowPathOnIonCompilation(JSCon bool Debugger::isDebuggee(const JSCompartment* compartment) const { MOZ_ASSERT(compartment); return compartment->isDebuggee() && debuggees.has(compartment->maybeGlobal()); } -Debugger::TenurePromotionsEntry::TenurePromotionsEntry(JSRuntime* rt, JSObject& obj, double when) +Debugger::TenurePromotionsLogEntry::TenurePromotionsLogEntry(JSRuntime* rt, JSObject& obj, double when) : className(obj.getClass()->name), when(when), frame(getObjectAllocationSite(obj)), size(JS::ubi::Node(&obj).size(rt->debuggerMallocSizeOf)) { } void Debugger::logTenurePromotion(JSRuntime* rt, JSObject& obj, double when) { - auto* entry = js_new<TenurePromotionsEntry>(rt, obj, when); - if (!entry) + if (!tenurePromotionsLog.emplaceBack(rt, obj, when)) CrashAtUnhandlableOOM("Debugger::logTenurePromotion"); - tenurePromotionsLog.insertBack(entry); - if (tenurePromotionsLogLength >= maxTenurePromotionsLogLength) { - js_delete(tenurePromotionsLog.popFirst()); + if (tenurePromotionsLog.length() > maxTenurePromotionsLogLength) { + if (!tenurePromotionsLog.popFront()) + CrashAtUnhandlableOOM("Debugger::logTenurePromotion"); + MOZ_ASSERT(tenurePromotionsLog.length() == maxTenurePromotionsLogLength); 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_<AllocationSite>(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) { MOZ_ASSERT(trackingAllocationSites); AutoCompartment ac(cx, object); RootedObject wrappedFrame(cx, frame); if (!cx->compartment()->wrap(cx, &wrappedFrame)) return false; - AllocationSite* allocSite = AllocationSite::create(cx, wrappedFrame, when, obj); - if (!allocSite) - return false; - - allocationsLog.insertBack(allocSite); - - if (allocationsLogLength >= maxAllocationsLogLength) { - js_delete(allocationsLog.popFirst()); + 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); + return false; + } + + if (allocationsLog.length() > maxAllocationsLogLength) { + if (!allocationsLog.popFront()) { + ReportOutOfMemory(cx); + return false; + } + MOZ_ASSERT(allocationsLog.length() == maxAllocationsLogLength); 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; + } + + return true; } JSTrapStatus Debugger::firePromiseHook(JSContext* cx, Hook hook, HandleObject promise, MutableHandleValue vp) { MOZ_ASSERT(hook == OnNewPromise || hook == OnPromiseSettled); RootedObject hookObj(cx, getHook(hook)); @@ -2327,17 +2297,17 @@ Debugger::addAllocationsTrackingForAllDe } void Debugger::removeAllocationsTrackingForAllDebuggees() { for (WeakGlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) { Debugger::removeAllocationsTracking(*r.front().get()); } - emptyAllocationsLog(); + allocationsLog.clear(); } /*** Debugger JSObjects **************************************************************************/ void Debugger::markCrossCompartmentEdges(JSTracer* trc) @@ -2346,29 +2316,17 @@ Debugger::markCrossCompartmentEdges(JSTr environments.markCrossCompartmentEdges<DebuggerEnv_trace>(trc); scripts.markCrossCompartmentEdges<DebuggerScript_trace>(trc); sources.markCrossCompartmentEdges<DebuggerSource_trace>(trc); // Because we don't have access to a `cx` inside // `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. - 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"); - } + TenurePromotionsLog::trace(&tenurePromotionsLog, trc); } /* * Ordinarily, WeakMap keys and values are marked because at some point it was * discovered that the WeakMap was live; that is, some object containing the * WeakMap was marked during mark phase. * * However, during zone GC, we have to do something about cross-compartment @@ -2539,27 +2497,18 @@ Debugger::trace(JSTracer* trc) * frames.) */ for (FrameMap::Range r = frames.all(); !r.empty(); r.popFront()) { RelocatablePtrNativeObject& frameobj = r.front().value(); MOZ_ASSERT(MaybeForwarded(frameobj.get())->getPrivate()); TraceEdge(trc, &frameobj, "live Debugger.Frame"); } - /* - * 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); + AllocationsLog::trace(&allocationsLog, trc); + TenurePromotionsLog::trace(&tenurePromotionsLog, trc); /* Trace the weak map from JSScript instances to Debugger.Script objects. */ scripts.trace(trc); /* Trace the referent ->Debugger.Source weak map */ sources.trace(trc); /* Trace the referent -> Debugger.Object weak map. */
--- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -19,16 +19,17 @@ #include "jsweakmap.h" #include "jswrapper.h" #include "gc/Barrier.h" #include "js/Debug.h" #include "js/HashTable.h" #include "vm/GlobalObject.h" #include "vm/SavedStacks.h" +#include "js/TraceableFifo.h" enum JSTrapStatus { JSTRAP_ERROR, JSTRAP_CONTINUE, JSTRAP_RETURN, JSTRAP_THROW, JSTRAP_LIMIT }; @@ -278,82 +279,89 @@ class Debugger : private mozilla::Linked bool isEnabled() const { return enabled; } 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<SavedFrame>()); + }; + + 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<uint64_t> observedGCs; - struct TenurePromotionsEntry : public mozilla::LinkedListElement<TenurePromotionsEntry> - { - TenurePromotionsEntry(JSRuntime* rt, JSObject& obj, double when); - - const char* className; - double when; - RelocatablePtrObject frame; - size_t size; - }; - - using TenurePromotionsLog = mozilla::LinkedList<TenurePromotionsEntry>; + using TenurePromotionsLog = js::TraceableFifo<TenurePromotionsLogEntry>; TenurePromotionsLog tenurePromotionsLog; bool trackingTenurePromotions; - size_t tenurePromotionsLogLength; size_t maxTenurePromotionsLogLength; bool tenurePromotionsLogOverflowed; - struct AllocationSite : public mozilla::LinkedListElement<AllocationSite> - { - AllocationSite(HandleObject frame, double when) - : frame(frame), - when(when), - className(nullptr), - ctorName(nullptr), - size(0) - { - MOZ_ASSERT_IF(frame, UncheckedUnwrap(frame)->is<SavedFrame>()); - }; + using AllocationsLog = js::TraceableFifo<AllocationsLogEntry>; - 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<AllocationSite> AllocationSiteList; - - bool allowUnobservedAsmJS; + AllocationsLog allocationsLog; bool trackingAllocationSites; double allocationSamplingProbability; - AllocationSiteList allocationsLog; - size_t allocationsLogLength; size_t maxAllocationsLogLength; bool allocationsLogOverflowed; static const size_t DEFAULT_MAX_LOG_LENGTH = 5000; 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. */ bool recomputeDebuggeeZoneSet(); /* * Return true if there is an existing object metadata callback for the @@ -498,17 +506,16 @@ class Debugger : private mozilla::Linked MutableHandleValue vp, bool callHook = true); GlobalObject* unwrapDebuggeeArgument(JSContext* cx, const Value& v); static void traceObject(JSTracer* trc, JSObject* obj); void trace(JSTracer* trc); static void finalize(FreeOp* fop, JSObject* obj); void markCrossCompartmentEdges(JSTracer* tracer); - void traceTenurePromotionsLog(JSTracer* trc); static const Class jsclass; static bool getHookImpl(JSContext* cx, CallArgs& args, Debugger& dbg, Hook which); static bool setHookImpl(JSContext* cx, CallArgs& args, Debugger& dbg, Hook which); static Debugger* fromThisValue(JSContext* cx, const CallArgs& ca, const char* fnname); static bool getEnabled(JSContext* cx, unsigned argc, Value* vp); @@ -915,16 +922,30 @@ class Debugger : private mozilla::Linked */ JSObject* wrapSource(JSContext* cx, js::HandleScriptSource source); private: Debugger(const Debugger&) = delete; Debugger & operator=(const Debugger&) = delete; }; +template<> +struct DefaultTracer<Debugger::TenurePromotionsLogEntry> { + static void trace(JSTracer* trc, Debugger::TenurePromotionsLogEntry* e, const char*) { + Debugger::TenurePromotionsLogEntry::trace(e, trc); + } +}; + +template<> +struct DefaultTracer<Debugger::AllocationsLogEntry> { + static void trace(JSTracer* trc, Debugger::AllocationsLogEntry* e, const char*) { + Debugger::AllocationsLogEntry::trace(e, trc); + } +}; + class BreakpointSite { friend class Breakpoint; friend struct ::JSCompartment; friend class ::JSScript; friend class Debugger; public: JSScript* script;
--- a/js/src/vm/DebuggerMemory.cpp +++ b/js/src/vm/DebuggerMemory.cpp @@ -180,70 +180,71 @@ DebuggerMemory::drainAllocationsLog(JSCo Debugger* dbg = memory->getDebugger(); if (!dbg->trackingAllocationSites) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_TRACKING_ALLOCATIONS, "drainAllocationsLog"); return false; } - size_t length = dbg->allocationsLogLength; + size_t length = dbg->allocationsLog.length(); RootedArrayObject result(cx, NewDenseFullyAllocatedArray(cx, length)); if (!result) return false; result->ensureDenseInitializedLength(cx, 0, length); for (size_t i = 0; i < length; i++) { RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx)); if (!obj) return false; - // 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(); + // 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(); - RootedValue frame(cx, ObjectOrNullValue(allocSite->frame)); + RootedValue frame(cx, ObjectOrNullValue(entry.frame)); if (!DefineProperty(cx, obj, cx->names().frame, frame)) return false; - RootedValue timestampValue(cx, NumberValue(allocSite->when)); + RootedValue timestampValue(cx, NumberValue(entry.when)); if (!DefineProperty(cx, obj, cx->names().timestamp, timestampValue)) return false; - RootedString className(cx, Atomize(cx, allocSite->className, strlen(allocSite->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 ctorName(cx, NullValue()); - if (allocSite->ctorName) - ctorName.setString(allocSite->ctorName); + if (entry.ctorName) + ctorName.setString(entry.ctorName); if (!DefineProperty(cx, obj, cx->names().constructor, ctorName)) return false; - RootedValue size(cx, NumberValue(allocSite->size)); + RootedValue size(cx, NumberValue(entry.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 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); + // 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; + } } dbg->allocationsLogOverflowed = false; - dbg->allocationsLogLength = 0; args.rval().setObject(*result); return true; } /* static */ bool DebuggerMemory::getMaxAllocationsLogLength(JSContext* cx, unsigned argc, Value* vp) { THIS_DEBUGGER_MEMORY(cx, argc, vp, "(get maxAllocationsLogLength)", args, memory); @@ -267,19 +268,21 @@ DebuggerMemory::setMaxAllocationsLogLeng "(set maxAllocationsLogLength)'s parameter", "not a positive integer"); return false; } Debugger* dbg = memory->getDebugger(); dbg->maxAllocationsLogLength = max; - while (dbg->allocationsLogLength > dbg->maxAllocationsLogLength) { - js_delete(dbg->allocationsLog.getFirst()); - dbg->allocationsLogLength--; + while (dbg->allocationsLog.length() > dbg->maxAllocationsLogLength) { + if (!dbg->allocationsLog.popFront()) { + ReportOutOfMemory(cx); + return false; + } } args.rval().setUndefined(); return true; } /* static */ bool DebuggerMemory::getAllocationSamplingProbability(JSContext* cx, unsigned argc, Value* vp) @@ -347,67 +350,68 @@ DebuggerMemory::drainTenurePromotionsLog Debugger* dbg = memory->getDebugger(); if (!dbg->trackingTenurePromotions) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_TRACKING_TENURINGS, "drainTenurePromotionsLog"); return false; } - size_t length = dbg->tenurePromotionsLogLength; + size_t length = dbg->tenurePromotionsLog.length(); RootedArrayObject result(cx, NewDenseFullyAllocatedArray(cx, length)); if (!result) return false; result->ensureDenseInitializedLength(cx, 0, length); for (size_t i = 0; i < length; i++) { RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx)); if (!obj) return false; // Don't pop the TenurePromotionsEntry yet. The queue's links are // 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.getFirst(); + auto& entry = dbg->tenurePromotionsLog.front(); - 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). - MOZ_ALWAYS_TRUE(dbg->tenurePromotionsLog.popFirst() == entry); - js_delete(entry); + if (!dbg->tenurePromotionsLog.popFront()) { + ReportOutOfMemory(cx); + return false; + } } dbg->tenurePromotionsLogOverflowed = false; - dbg->tenurePromotionsLogLength = 0; args.rval().setObject(*result); return true; } /* static */ bool DebuggerMemory::getMaxTenurePromotionsLogLength(JSContext* cx, unsigned argc, Value* vp) { THIS_DEBUGGER_MEMORY(cx, argc, vp, "(get maxTenurePromotionsLogLength)", args, memory); @@ -431,19 +435,21 @@ DebuggerMemory::setMaxTenurePromotionsLo "(set maxTenurePromotionsLogLength)'s parameter", "not a positive integer"); return false; } Debugger* dbg = memory->getDebugger(); dbg->maxTenurePromotionsLogLength = max; - while (dbg->tenurePromotionsLogLength > dbg->maxAllocationsLogLength) { - js_delete(dbg->tenurePromotionsLog.getFirst()); - dbg->tenurePromotionsLogLength--; + while (dbg->tenurePromotionsLog.length() > dbg->maxAllocationsLogLength) { + if (!dbg->tenurePromotionsLog.popFront()) { + ReportOutOfMemory(cx); + return false; + } } args.rval().setUndefined(); return true; } /* static */ bool DebuggerMemory::getTenurePromotionsLogOverflowed(JSContext* cx, unsigned argc, Value* vp)