mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-27 17:47:34 +09:00
Merge remote-tracking branch 'origin/master' into custom
This commit is contained in:
commit
1d71489799
18 changed files with 200 additions and 106 deletions
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
28.5.0a2
|
28.6.0a1
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{}
|
{}
|
||||||
|
|
|
||||||
|
|
@ -349,10 +349,17 @@ 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
|
||||||
|
|
|
||||||
172
js/src/jsgc.cpp
172
js/src/jsgc.cpp
|
|
@ -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
|
/* Set scheduleForDestruction based on maybeAlive. */
|
||||||
* during MarkRuntime.
|
|
||||||
*/
|
for (GCCompartmentsIter comp(rt); !comp.done(); comp.next()) {
|
||||||
|
MOZ_ASSERT(!comp->scheduledForDestruction);
|
||||||
/* Propogate maybeAlive to scheduleForDestruction. */
|
if (!comp->maybeAlive && !rt->isAtomsCompartment(comp))
|
||||||
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
|
comp->scheduledForDestruction = true;
|
||||||
if (!c->maybeAlive && !rt->isAtomsCompartment(c))
|
|
||||||
c->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);
|
||||||
}
|
}
|
||||||
|
|
@ -5487,7 +5508,7 @@ gc::AbortReason
|
||||||
gc::IsIncrementalGCUnsafe(JSRuntime* rt)
|
gc::IsIncrementalGCUnsafe(JSRuntime* rt)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!rt->mainThread.suppressGC);
|
MOZ_ASSERT(!rt->mainThread.suppressGC);
|
||||||
|
|
||||||
if (rt->keepAtoms())
|
if (rt->keepAtoms())
|
||||||
return gc::AbortReason::KeepAtomsSet;
|
return gc::AbortReason::KeepAtomsSet;
|
||||||
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
@ -5782,27 +5822,23 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R
|
||||||
do {
|
do {
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -453,6 +454,12 @@ class ArenaList {
|
||||||
check();
|
check();
|
||||||
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 {
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3648,6 +3648,10 @@ PaintedLayerData::AccumulateEventRegions(ContainerState* aState, nsDisplayLayerE
|
||||||
if (alreadyHadRegions) {
|
if (alreadyHadRegions) {
|
||||||
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().
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue