Merge remote-tracking branch 'origin/master' into custom

This commit is contained in:
Roy Tam 2019-05-03 21:40:08 +08:00
commit 1d71489799
18 changed files with 200 additions and 106 deletions

View file

@ -35,7 +35,7 @@ var gBidiUI = false;
* Determines whether the given url is considered a special URL for new tabs. * Determines whether the given url is considered a special URL for new tabs.
*/ */
function isBlankPageURL(aURL) { function isBlankPageURL(aURL) {
return aURL == "about:blank" || aURL == "about:newtab" || aURL == "about:logopage"; return aURL == "about:blank" || aURL == BROWSER_NEW_TAB_URL || aURL == "about:logopage";
} }
function getBrowserURL() function getBrowserURL()

View file

@ -402,11 +402,18 @@
let promptBox = { let promptBox = {
appendPrompt : function(args, onCloseCallback) { appendPrompt : function(args, onCloseCallback) {
let newPrompt = document.createElementNS(XUL_NS, "tabmodalprompt"); let newPrompt = document.createElementNS(XUL_NS, "tabmodalprompt");
stack.appendChild(newPrompt); // stack.appendChild(newPrompt);
stack.insertBefore(newPrompt, browser.nextSibling);
browser.setAttribute("tabmodalPromptShowing", true); browser.setAttribute("tabmodalPromptShowing", true);
newPrompt.clientTop; // style flush to assure binding is attached newPrompt.clientTop; // style flush to assure binding is attached
let prompts = this.listPrompts();
if (prompts.length > 1) {
// Let's hide ourself behind the current prompt.
newPrompt.hidden = true;
}
let tab = self._getTabForContentWindow(browser.contentWindow); let tab = self._getTabForContentWindow(browser.contentWindow);
newPrompt.init(args, tab, onCloseCallback); newPrompt.init(args, tab, onCloseCallback);
return newPrompt; return newPrompt;
@ -418,6 +425,7 @@
let prompts = this.listPrompts(); let prompts = this.listPrompts();
if (prompts.length) { if (prompts.length) {
let prompt = prompts[prompts.length - 1]; let prompt = prompts[prompts.length - 1];
prompt.hidden = false;
prompt.Dialog.setDefaultFocus(); prompt.Dialog.setDefaultFocus();
} else { } else {
browser.removeAttribute("tabmodalPromptShowing"); browser.removeAttribute("tabmodalPromptShowing");

View file

@ -1 +1 @@
28.5.0a2 28.6.0a1

View file

@ -552,17 +552,23 @@ HTMLCanvasElement::CopyInnerTo(Element* aDest)
HTMLCanvasElement* dest = static_cast<HTMLCanvasElement*>(aDest); HTMLCanvasElement* dest = static_cast<HTMLCanvasElement*>(aDest);
dest->mOriginalCanvas = this; dest->mOriginalCanvas = this;
nsCOMPtr<nsISupports> cxt; // We make sure that the canvas is not zero sized since that would cause
dest->GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(cxt)); // the DrawImage call below to return an error, which would cause printing
RefPtr<CanvasRenderingContext2D> context2d = // to fail.
static_cast<CanvasRenderingContext2D*>(cxt.get()); nsIntSize size = GetWidthHeight();
if (context2d && !mPrintCallback) { if (size.height > 0 && size.width > 0) {
CanvasImageSource source; nsCOMPtr<nsISupports> cxt;
source.SetAsHTMLCanvasElement() = this; dest->GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(cxt));
ErrorResult err; RefPtr<CanvasRenderingContext2D> context2d =
context2d->DrawImage(source, static_cast<CanvasRenderingContext2D*>(cxt.get());
0.0, 0.0, err); if (context2d && !mPrintCallback) {
rv = err.StealNSResult(); CanvasImageSource source;
source.SetAsHTMLCanvasElement() = this;
ErrorResult err;
context2d->DrawImage(source,
0.0, 0.0, err);
rv = err.StealNSResult();
}
} }
} }
return rv; return rv;

View file

@ -61,6 +61,15 @@ IdToObjectMap::find(ObjectId id)
return p->value(); return p->value();
} }
JSObject*
IdToObjectMap::findPreserveColor(ObjectId id)
{
Table::Ptr p = table_.lookup(id);
if (!p)
return nullptr;
return p->value().unbarrieredGet();
}
bool bool
IdToObjectMap::add(ObjectId id, JSObject* obj) IdToObjectMap::add(ObjectId id, JSObject* obj)
{ {

View file

@ -96,6 +96,7 @@ class IdToObjectMap
bool add(ObjectId id, JSObject* obj); bool add(ObjectId id, JSObject* obj);
JSObject* find(ObjectId id); JSObject* find(ObjectId id);
JSObject* findPreserveColor(ObjectId id);
void remove(ObjectId id); void remove(ObjectId id);
void clear(); void clear();

View file

@ -789,7 +789,7 @@ WrapperAnswer::RecvDOMInstanceOf(const ObjectId& objId, const int& prototypeID,
bool bool
WrapperAnswer::RecvDropObject(const ObjectId& objId) WrapperAnswer::RecvDropObject(const ObjectId& objId)
{ {
JSObject* obj = objects_.find(objId); JSObject* obj = objects_.findPreserveColor(objId);
if (obj) { if (obj) {
objectIdMap(objId.hasXrayWaiver()).remove(obj); objectIdMap(objId.hasXrayWaiver()).remove(obj);
objects_.remove(objId); objects_.remove(objId);

View file

@ -652,7 +652,7 @@ ArrayMetaTypeDescr::create(JSContext* cx,
if (!CreateTraceList(cx, obj)) if (!CreateTraceList(cx, obj))
return nullptr; return nullptr;
if (!cx->zone()->typeDescrObjects.put(obj)) { if (!cx->zone()->addTypeDescrObject(cx, obj)) {
ReportOutOfMemory(cx); ReportOutOfMemory(cx);
return nullptr; return nullptr;
} }
@ -993,8 +993,8 @@ StructMetaTypeDescr::create(JSContext* cx,
if (!CreateTraceList(cx, descr)) if (!CreateTraceList(cx, descr))
return nullptr; return nullptr;
if (!cx->zone()->typeDescrObjects.put(descr) || if (!cx->zone()->addTypeDescrObject(cx, descr) ||
!cx->zone()->typeDescrObjects.put(fieldTypeVec)) !cx->zone()->addTypeDescrObject(cx, fieldTypeVec))
{ {
ReportOutOfMemory(cx); ReportOutOfMemory(cx);
return nullptr; return nullptr;
@ -1165,10 +1165,8 @@ DefineSimpleTypeDescr(JSContext* cx,
if (!CreateTraceList(cx, descr)) if (!CreateTraceList(cx, descr))
return false; return false;
if (!cx->zone()->typeDescrObjects.put(descr)) { if (!cx->zone()->addTypeDescrObject(cx, descr))
ReportOutOfMemory(cx);
return false; return false;
}
return true; return true;
} }

View file

@ -900,7 +900,8 @@ class GCRuntime
void requestMajorGC(JS::gcreason::Reason reason); void requestMajorGC(JS::gcreason::Reason reason);
SliceBudget defaultBudget(JS::gcreason::Reason reason, int64_t millis); SliceBudget defaultBudget(JS::gcreason::Reason reason, int64_t millis);
void budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess& lock); void budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget,
AutoLockForExclusiveAccess& lock);
void resetIncrementalGC(AbortReason reason, AutoLockForExclusiveAccess& lock); void resetIncrementalGC(AbortReason reason, AutoLockForExclusiveAccess& lock);
// Assert if the system state is such that we should never // Assert if the system state is such that we should never
@ -915,6 +916,7 @@ class GCRuntime
void collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason) JS_HAZ_GC_CALL; void collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason) JS_HAZ_GC_CALL;
MOZ_MUST_USE bool gcCycle(bool nonincrementalByAPI, SliceBudget& budget, MOZ_MUST_USE bool gcCycle(bool nonincrementalByAPI, SliceBudget& budget,
JS::gcreason::Reason reason); JS::gcreason::Reason reason);
bool shouldRepeatForDeadZone(JS::gcreason::Reason reason);
void incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason reason, void incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason reason,
AutoLockForExclusiveAccess& lock); AutoLockForExclusiveAccess& lock);

View file

@ -478,6 +478,7 @@ js::gc::GCRuntime::bufferGrayRoots()
for (GCZonesIter zone(rt); !zone.done(); zone.next()) for (GCZonesIter zone(rt); !zone.done(); zone.next())
MOZ_ASSERT(zone->gcGrayRoots.empty()); MOZ_ASSERT(zone->gcGrayRoots.empty());
gcstats::AutoPhase ap(stats, gcstats::PHASE_BUFFER_GRAY_ROOTS);
BufferGrayRootsTracer grayBufferer(rt); BufferGrayRootsTracer grayBufferer(rt);
if (JSTraceDataOp op = grayRootTracer.op) if (JSTraceDataOp op = grayRootTracer.op)
@ -540,4 +541,3 @@ GCRuntime::resetBufferedGrayRoots() const
for (GCZonesIter zone(rt); !zone.done(); zone.next()) for (GCZonesIter zone(rt); !zone.done(); zone.next())
zone->gcGrayRoots.clearAndFree(); zone->gcGrayRoots.clearAndFree();
} }

View file

@ -370,6 +370,21 @@ Zone::fixupAfterMovingGC()
fixupInitialShapeTable(); fixupInitialShapeTable();
} }
bool
Zone::addTypeDescrObject(JSContext* cx, HandleObject obj)
{
// Type descriptor objects are always tenured so we don't need post barriers
// on the set.
MOZ_ASSERT(!IsInsideNursery(obj));
if (!typeDescrObjects.put(obj)) {
ReportOutOfMemory(cx);
return false;
}
return true;
}
ZoneList::ZoneList() ZoneList::ZoneList()
: head(nullptr), tail(nullptr) : head(nullptr), tail(nullptr)
{} {}

View file

@ -349,11 +349,18 @@ struct Zone : public JS::shadow::Zone,
// Keep track of all TypeDescr and related objects in this compartment. // Keep track of all TypeDescr and related objects in this compartment.
// This is used by the GC to trace them all first when compacting, since the // This is used by the GC to trace them all first when compacting, since the
// TypedObject trace hook may access these objects. // TypedObject trace hook may access these objects.
using TypeDescrObjectSet = js::GCHashSet<js::HeapPtr<JSObject*>,
js::MovableCellHasher<js::HeapPtr<JSObject*>>, //
// There are no barriers here - the set contains only tenured objects so no
// post-barrier is required, and these are weak references so no pre-barrier
// is required.
using TypeDescrObjectSet = js::GCHashSet<JSObject*,
js::MovableCellHasher<JSObject*>,
js::SystemAllocPolicy>; js::SystemAllocPolicy>;
JS::WeakCache<TypeDescrObjectSet> typeDescrObjects; JS::WeakCache<TypeDescrObjectSet> typeDescrObjects;
bool addTypeDescrObject(JSContext* cx, HandleObject obj);
// Malloc counter to measure memory pressure for GC scheduling. It runs from // Malloc counter to measure memory pressure for GC scheduling. It runs from
// gcMaxMallocBytes down to zero. This counter should be used only when it's // gcMaxMallocBytes down to zero. This counter should be used only when it's

View file

@ -1524,19 +1524,11 @@ GCMarker::delayMarkingChildren(const void* thing)
} }
inline void inline void
ArenaLists::prepareForIncrementalGC(JSRuntime* rt) ArenaLists::prepareForIncrementalGC()
{ {
purge();
for (auto i : AllAllocKinds()) { for (auto i : AllAllocKinds()) {
FreeSpan* span = freeLists[i]; arenaLists[i].moveCursorToEnd();
if (span != &placeholder) {
if (!span->isEmpty()) {
Arena* arena = span->getArena();
arena->allocatedDuringIncremental = true;
rt->gc.marker.delayMarkingArena(arena);
} else {
freeLists[i] = &placeholder;
}
}
} }
} }
@ -2251,7 +2243,7 @@ GCRuntime::updateTypeDescrObjects(MovingTracer* trc, Zone* zone)
{ {
zone->typeDescrObjects.sweep(); zone->typeDescrObjects.sweep();
for (auto r = zone->typeDescrObjects.all(); !r.empty(); r.popFront()) for (auto r = zone->typeDescrObjects.all(); !r.empty(); r.popFront())
UpdateCellPointers(trc, r.front().get()); UpdateCellPointers(trc, r.front());
} }
void void
@ -3579,6 +3571,23 @@ RelazifyFunctions(Zone* zone, AllocKind kind)
} }
} }
static bool
ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason)
{
// Normally we collect all scheduled zones.
if (reason != JS::gcreason::COMPARTMENT_REVIVED)
return zone->isGCScheduled();
// If we are repeating a GC because we noticed dead compartments haven't
// been collected, then only collect zones containing those compartments.
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
if (comp->scheduledForDestruction)
return true;
}
return false;
}
bool bool
GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock) GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock)
{ {
@ -3602,7 +3611,7 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
#endif #endif
/* Set up which zones will be collected. */ /* Set up which zones will be collected. */
if (zone->isGCScheduled()) { if (ShouldCollectZone(zone, reason)) {
if (!zone->isAtomsZone()) { if (!zone->isAtomsZone()) {
any = true; any = true;
zone->setGCState(Zone::Mark); zone->setGCState(Zone::Mark);
@ -3621,7 +3630,7 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) { for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) {
c->marked = false; c->marked = false;
c->scheduledForDestruction = false; c->scheduledForDestruction = false;
c->maybeAlive = false; c->maybeAlive = c->hasBeenEntered() || !c->zone()->isGCScheduled();
if (shouldPreserveJITCode(c, currentTime, reason, canAllocateMoreCode)) if (shouldPreserveJITCode(c, currentTime, reason, canAllocateMoreCode))
c->zone()->setPreservingCode(true); c->zone()->setPreservingCode(true);
} }
@ -3641,6 +3650,7 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
* on. If the value of keepAtoms() changes between GC slices, then we'll * on. If the value of keepAtoms() changes between GC slices, then we'll
* cancel the incremental GC. See IsIncrementalGCSafe. * cancel the incremental GC. See IsIncrementalGCSafe.
*/ */
if (isFull && !rt->keepAtoms()) { if (isFull && !rt->keepAtoms()) {
Zone* atomsZone = rt->atomsCompartment(lock)->zone(); Zone* atomsZone = rt->atomsCompartment(lock)->zone();
if (atomsZone->isGCScheduled()) { if (atomsZone->isGCScheduled()) {
@ -3655,15 +3665,12 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
return false; return false;
/* /*
* At the end of each incremental slice, we call prepareForIncrementalGC, * Ensure that after the start of a collection we don't allocate into any
* which marks objects in all arenas that we're currently allocating * existing arenas, as this can cause unreachable things to be marked.
* into. This can cause leaks if unreachable objects are in these
* arenas. This purge call ensures that we only mark arenas that have had
* allocations after the incremental GC started.
*/ */
if (isIncremental) { if (isIncremental) {
for (GCZonesIter zone(rt); !zone.done(); zone.next()) for (GCZonesIter zone(rt); !zone.done(); zone.next())
zone->arenas.purge(); zone->arenas.prepareForIncrementalGC();
} }
MemProfiler::MarkTenuredStart(rt); MemProfiler::MarkTenuredStart(rt);
@ -3748,12 +3755,10 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
gcstats::AutoPhase ap2(stats, gcstats::PHASE_MARK_ROOTS); gcstats::AutoPhase ap2(stats, gcstats::PHASE_MARK_ROOTS);
if (isIncremental) { if (isIncremental) {
gcstats::AutoPhase ap3(stats, gcstats::PHASE_BUFFER_GRAY_ROOTS);
bufferGrayRoots(); bufferGrayRoots();
markCompartments();
} }
markCompartments();
return true; return true;
} }
@ -3766,9 +3771,14 @@ GCRuntime::markCompartments()
* This code ensures that if a compartment is "dead", then it will be * This code ensures that if a compartment is "dead", then it will be
* collected in this GC. A compartment is considered dead if its maybeAlive * collected in this GC. A compartment is considered dead if its maybeAlive
* flag is false. The maybeAlive flag is set if: * flag is false. The maybeAlive flag is set if:
* (1) the compartment has incoming cross-compartment edges, or * (1) the compartment has been entered (set in beginMarkPhase() above)
* (2) an object in the compartment was marked during root marking, either * (2) the compartment is not being collected (set in beginMarkPhase()
* as a black root or a gray root. * above)
* (3) an object in the compartment was marked during root marking, either
* as a black root or a gray root (set in RootMarking.cpp), or
* (4) the compartment has incoming cross-compartment edges from another
* compartment that has maybeAlive set (set by this method).
*
* If the maybeAlive is false, then we set the scheduledForDestruction flag. * If the maybeAlive is false, then we set the scheduledForDestruction flag.
* At the end of the GC, we look for compartments where * At the end of the GC, we look for compartments where
* scheduledForDestruction is true. These are compartments that were somehow * scheduledForDestruction is true. These are compartments that were somehow
@ -3786,26 +3796,37 @@ GCRuntime::markCompartments()
* allocation and read barriers during JS_TransplantObject and the like. * allocation and read barriers during JS_TransplantObject and the like.
*/ */
/* Set the maybeAlive flag based on cross-compartment edges. */ /* Propagate the maybeAlive flag via cross-compartment edges. */
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) { Vector<JSCompartment*, 0, js::SystemAllocPolicy> workList;
for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next()) {
if (comp->maybeAlive) {
if (!workList.append(comp))
return;
}
}
while (!workList.empty()) {
JSCompartment* comp = workList.popCopy();
for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) {
if (e.front().key().is<JSString*>()) if (e.front().key().is<JSString*>())
continue; continue;
JSCompartment* dest = e.front().mutableKey().compartment(); JSCompartment* dest = e.front().mutableKey().compartment();
if (dest) if (dest && !dest->maybeAlive) {
dest->maybeAlive = true; dest->maybeAlive = true;
if (!workList.append(dest))
return;
}
} }
} }
/*
* For black roots, code in gc/Marking.cpp will already have set maybeAlive
* during MarkRuntime.
*/
/* Propogate maybeAlive to scheduleForDestruction. */ /* Set scheduleForDestruction based on maybeAlive. */
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
if (!c->maybeAlive && !rt->isAtomsCompartment(c)) for (GCCompartmentsIter comp(rt); !comp.done(); comp.next()) {
c->scheduledForDestruction = true; MOZ_ASSERT(!comp->scheduledForDestruction);
if (!comp->maybeAlive && !rt->isAtomsCompartment(comp))
comp->scheduledForDestruction = true;
} }
} }
@ -5306,7 +5327,7 @@ AutoGCSlice::~AutoGCSlice()
for (ZonesIter zone(runtime, WithAtoms); !zone.done(); zone.next()) { for (ZonesIter zone(runtime, WithAtoms); !zone.done(); zone.next()) {
if (zone->isGCMarking()) { if (zone->isGCMarking()) {
zone->setNeedsIncrementalBarrier(true, Zone::UpdateJit); zone->setNeedsIncrementalBarrier(true, Zone::UpdateJit);
zone->arenas.prepareForIncrementalGC(runtime); zone->arenas.purge();
} else { } else {
zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit); zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit);
} }
@ -5498,9 +5519,17 @@ gc::IsIncrementalGCUnsafe(JSRuntime* rt)
} }
void void
GCRuntime::budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess& lock) GCRuntime::budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget,
AutoLockForExclusiveAccess& lock)
{ {
AbortReason unsafeReason = IsIncrementalGCUnsafe(rt); AbortReason unsafeReason = IsIncrementalGCUnsafe(rt);
if (unsafeReason == AbortReason::None) {
if (reason == JS::gcreason::COMPARTMENT_REVIVED)
unsafeReason = gc::AbortReason::CompartmentRevived;
else if (mode != JSGC_MODE_INCREMENTAL)
unsafeReason = gc::AbortReason::ModeChange;
}
if (unsafeReason != AbortReason::None) { if (unsafeReason != AbortReason::None) {
resetIncrementalGC(unsafeReason, lock); resetIncrementalGC(unsafeReason, lock);
budget.makeUnlimited(); budget.makeUnlimited();
@ -5508,12 +5537,7 @@ GCRuntime::budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess&
return; return;
} }
if (mode != JSGC_MODE_INCREMENTAL) {
resetIncrementalGC(AbortReason::ModeChange, lock);
budget.makeUnlimited();
stats.nonincremental(AbortReason::ModeChange);
return;
}
if (isTooMuchMalloc()) { if (isTooMuchMalloc()) {
budget.makeUnlimited(); budget.makeUnlimited();
@ -5672,7 +5696,7 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::
stats.nonincremental(gc::AbortReason::NonIncrementalRequested); stats.nonincremental(gc::AbortReason::NonIncrementalRequested);
budget.makeUnlimited(); budget.makeUnlimited();
} else { } else {
budgetIncrementalGC(budget, session.lock); budgetIncrementalGC(reason, budget, session.lock);
} }
/* The GC was reset, so we need a do-over. */ /* The GC was reset, so we need a do-over. */
@ -5764,6 +5788,22 @@ GCRuntime::checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason)
return true; return true;
} }
bool
GCRuntime::shouldRepeatForDeadZone(JS::gcreason::Reason reason)
{
MOZ_ASSERT_IF(reason == JS::gcreason::COMPARTMENT_REVIVED, !isIncremental);
if (!isIncremental || isIncrementalGCInProgress())
return false;
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
if (c->scheduledForDestruction)
return true;
}
return false;
}
void void
GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason) GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason)
{ {
@ -5783,27 +5823,23 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R
poked = false; poked = false;
bool wasReset = gcCycle(nonincrementalByAPI, budget, reason); bool wasReset = gcCycle(nonincrementalByAPI, budget, reason);
/* Need to re-schedule all zones for GC. */ bool repeatForDeadZone = false;
if (poked && cleanUpEverything) if (poked && cleanUpEverything) {
/* Need to re-schedule all zones for GC. */
JS::PrepareForFullGC(rt->contextFromMainThread()); JS::PrepareForFullGC(rt->contextFromMainThread());
/*
* This code makes an extra effort to collect compartments that we } else if (shouldRepeatForDeadZone(reason) && !wasReset) {
* thought were dead at the start of the GC. See the large comment in /*
* beginMarkPhase. * This code makes an extra effort to collect compartments that we
*/ * thought were dead at the start of the GC. See the large comment
bool repeatForDeadZone = false; * in beginMarkPhase.
if (!nonincrementalByAPI && !isIncrementalGCInProgress()) { */
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { repeatForDeadZone = true;
if (c->scheduledForDestruction) { reason = JS::gcreason::COMPARTMENT_REVIVED;
nonincrementalByAPI = true;
repeatForDeadZone = true;
reason = JS::gcreason::COMPARTMENT_REVIVED;
c->zone()->scheduleGC();
}
}
} }
/* /*
* If we reset an existing GC, we need to start a new one. Also, we * If we reset an existing GC, we need to start a new one. Also, we
* repeat GCs that happen during shutdown (the gcShouldCleanUpEverything * repeat GCs that happen during shutdown (the gcShouldCleanUpEverything

View file

@ -61,7 +61,8 @@ enum class State {
D(ModeChange) \ D(ModeChange) \
D(MallocBytesTrigger) \ D(MallocBytesTrigger) \
D(GCBytesTrigger) \ D(GCBytesTrigger) \
D(ZoneChange) D(ZoneChange) \
D(CompartmentRevived)
enum class AbortReason { enum class AbortReason {
#define MAKE_REASON(name) name, #define MAKE_REASON(name) name,
GC_ABORT_REASONS(MAKE_REASON) GC_ABORT_REASONS(MAKE_REASON)
@ -454,6 +455,12 @@ class ArenaList {
return !*cursorp_; return !*cursorp_;
} }
void moveCursorToEnd() {
while (!isCursorAtEnd()) {
cursorp_ = &(*cursorp_)->next;
}
}
// This can return nullptr. // This can return nullptr.
Arena* arenaAfterCursor() const { Arena* arenaAfterCursor() const {
check(); check();
@ -739,7 +746,7 @@ class ArenaLists
freeLists[i] = &placeholder; freeLists[i] = &placeholder;
} }
inline void prepareForIncrementalGC(JSRuntime* rt); inline void prepareForIncrementalGC();
/* Check if this arena is in use. */ /* Check if this arena is in use. */
bool arenaIsInUse(Arena* arena, AllocKind kind) const { bool arenaIsInUse(Arena* arena, AllocKind kind) const {

View file

@ -185,17 +185,18 @@ WatchpointMap::markAll(JSTracer* trc)
{ {
for (Map::Enum e(map); !e.empty(); e.popFront()) { for (Map::Enum e(map); !e.empty(); e.popFront()) {
Map::Entry& entry = e.front(); Map::Entry& entry = e.front();
WatchKey key = entry.key(); JSObject* object = entry.key().object;
WatchKey prior = key; jsid id = entry.key().id;
MOZ_ASSERT(JSID_IS_STRING(prior.id) || JSID_IS_INT(prior.id) || JSID_IS_SYMBOL(prior.id)); JSObject* priorObject = object;
jsid priorId = id;
MOZ_ASSERT(JSID_IS_STRING(priorId) || JSID_IS_INT(priorId) || JSID_IS_SYMBOL(priorId));
TraceEdge(trc, const_cast<PreBarrieredObject*>(&key.object), TraceManuallyBarrieredEdge(trc, &object, "held Watchpoint object");
"held Watchpoint object"); TraceManuallyBarrieredEdge(trc, &id, "WatchKey::id");
TraceEdge(trc, const_cast<PreBarrieredId*>(&key.id), "WatchKey::id");
TraceEdge(trc, &entry.value().closure, "Watchpoint::closure"); TraceEdge(trc, &entry.value().closure, "Watchpoint::closure");
if (prior.object != key.object || prior.id != key.id) if (priorObject != object || priorId != id)
e.rekeyFront(key); e.rekeyFront(WatchKey(object, id));
} }
} }

View file

@ -3649,6 +3649,10 @@ PaintedLayerData::AccumulateEventRegions(ContainerState* aState, nsDisplayLayerE
mDispatchToContentHitRegion.OrWith(CombinedTouchActionRegion()); mDispatchToContentHitRegion.OrWith(CombinedTouchActionRegion());
} }
// Avoid quadratic performance as a result of the region growing to include
// and arbitrarily large number of rects, which can happen on some pages.
mMaybeHitRegion.SimplifyOutward(8);
// Calculate scaled versions of the bounds of mHitRegion and mMaybeHitRegion // Calculate scaled versions of the bounds of mHitRegion and mMaybeHitRegion
// for quick access in FindPaintedLayerFor(). // for quick access in FindPaintedLayerFor().
mScaledHitRegionBounds = aState->ScaleToOutsidePixels(mHitRegion.GetBounds()); mScaledHitRegionBounds = aState->ScaleToOutsidePixels(mHitRegion.GetBounds());

View file

@ -1096,7 +1096,6 @@ void
nsDisplayListBuilder::MarkFramesForDisplayList(nsIFrame* aDirtyFrame, nsDisplayListBuilder::MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
const nsFrameList& aFrames, const nsFrameList& aFrames,
const nsRect& aDirtyRect) { const nsRect& aDirtyRect) {
mFramesMarkedForDisplay.SetCapacity(mFramesMarkedForDisplay.Length() + aFrames.GetLength());
for (nsIFrame* e : aFrames) { for (nsIFrame* e : aFrames) {
// Skip the AccessibleCaret frame when building no caret. // Skip the AccessibleCaret frame when building no caret.
if (!IsBuildingCaret()) { if (!IsBuildingCaret()) {
@ -1108,6 +1107,7 @@ nsDisplayListBuilder::MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
} }
} }
} }
mFramesMarkedForDisplay.AppendElement(e); mFramesMarkedForDisplay.AppendElement(e);
MarkOutOfFlowFrameForDisplay(aDirtyFrame, e, aDirtyRect); MarkOutOfFlowFrameForDisplay(aDirtyFrame, e, aDirtyRect);
} }

View file

@ -1200,7 +1200,7 @@ private:
PLArenaPool mPool; PLArenaPool mPool;
nsCOMPtr<nsISelection> mBoundingSelection; nsCOMPtr<nsISelection> mBoundingSelection;
AutoTArray<PresShellState,8> mPresShellStates; AutoTArray<PresShellState,8> mPresShellStates;
AutoTArray<nsIFrame*,100> mFramesMarkedForDisplay; AutoTArray<nsIFrame*,400> mFramesMarkedForDisplay;
AutoTArray<ThemeGeometry,2> mThemeGeometries; AutoTArray<ThemeGeometry,2> mThemeGeometries;
nsDisplayTableItem* mCurrentTableItem; nsDisplayTableItem* mCurrentTableItem;
DisplayListClipState mClipState; DisplayListClipState mClipState;