зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1366340 - Delete parsing zones immediately after their contents are merged r=sfink
This commit is contained in:
Родитель
4266b7c35e
Коммит
6063f3db71
|
@ -937,7 +937,8 @@ class GCRuntime
|
|||
void startTask(GCParallelTask& task, gcstats::PhaseKind phase, AutoLockHelperThreadState& locked);
|
||||
void joinTask(GCParallelTask& task, gcstats::PhaseKind phase, AutoLockHelperThreadState& locked);
|
||||
|
||||
private:
|
||||
// Delete an empty zone group after its contents have been merged.
|
||||
void deleteEmptyZoneGroup(ZoneGroup* group);
|
||||
|
||||
private:
|
||||
enum IncrementalResult
|
||||
|
@ -1096,7 +1097,10 @@ class GCRuntime
|
|||
UnprotectedData<ZoneGroup*> systemZoneGroup;
|
||||
|
||||
// List of all zone groups (protected by the GC lock).
|
||||
ActiveThreadOrGCTaskData<ZoneGroupVector> groups;
|
||||
private:
|
||||
ActiveThreadOrGCTaskData<ZoneGroupVector> groups_;
|
||||
public:
|
||||
ZoneGroupVector& groups() { return groups_.ref(); }
|
||||
|
||||
// The unique atoms zone, which has no zone group.
|
||||
WriteOnceData<Zone*> atomsZone;
|
||||
|
|
|
@ -73,6 +73,8 @@ JS::Zone::Zone(JSRuntime* rt, ZoneGroup* group)
|
|||
|
||||
Zone::~Zone()
|
||||
{
|
||||
MOZ_ASSERT(compartments_.ref().empty());
|
||||
|
||||
JSRuntime* rt = runtimeFromAnyThread();
|
||||
if (this == rt->gc.systemZone)
|
||||
rt->gc.systemZone = nullptr;
|
||||
|
@ -87,7 +89,8 @@ Zone::~Zone()
|
|||
#endif
|
||||
}
|
||||
|
||||
bool Zone::init(bool isSystemArg)
|
||||
bool
|
||||
Zone::init(bool isSystemArg)
|
||||
{
|
||||
isSystem = isSystemArg;
|
||||
return uniqueIds().init() &&
|
||||
|
@ -376,6 +379,21 @@ Zone::addTypeDescrObject(JSContext* cx, HandleObject obj)
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Zone::deleteEmptyCompartment(JSCompartment* comp)
|
||||
{
|
||||
MOZ_ASSERT(comp->zone() == this);
|
||||
MOZ_ASSERT(arenas.checkEmptyArenaLists());
|
||||
for (auto& i : compartments()) {
|
||||
if (i == comp) {
|
||||
compartments().erase(&i);
|
||||
comp->destroy(runtimeFromActiveCooperatingThread()->defaultFreeOp());
|
||||
return;
|
||||
}
|
||||
}
|
||||
MOZ_CRASH("Compartment not found");
|
||||
}
|
||||
|
||||
ZoneList::ZoneList()
|
||||
: head(nullptr), tail(nullptr)
|
||||
{}
|
||||
|
|
|
@ -161,6 +161,7 @@ struct Zone : public JS::shadow::Zone,
|
|||
explicit Zone(JSRuntime* rt, js::ZoneGroup* group);
|
||||
~Zone();
|
||||
MOZ_MUST_USE bool init(bool isSystem);
|
||||
void destroy(js::FreeOp *fop);
|
||||
|
||||
private:
|
||||
js::ZoneGroup* const group_;
|
||||
|
@ -622,6 +623,9 @@ struct Zone : public JS::shadow::Zone,
|
|||
keepShapeTables_ = b;
|
||||
}
|
||||
|
||||
// Delete an empty compartment after its contents have been merged.
|
||||
void deleteEmptyCompartment(JSCompartment* comp);
|
||||
|
||||
private:
|
||||
js::ZoneGroupData<js::jit::JitZone*> jitZone_;
|
||||
|
||||
|
@ -654,8 +658,8 @@ class ZoneGroupsIter
|
|||
|
||||
public:
|
||||
explicit ZoneGroupsIter(JSRuntime* rt) : iterMarker(&rt->gc) {
|
||||
it = rt->gc.groups.ref().begin();
|
||||
end = rt->gc.groups.ref().end();
|
||||
it = rt->gc.groups().begin();
|
||||
end = rt->gc.groups().end();
|
||||
|
||||
if (!done() && (*it)->usedByHelperThread)
|
||||
next();
|
||||
|
|
|
@ -130,4 +130,20 @@ ZoneGroup::ionLazyLinkListAdd(jit::IonBuilder* builder)
|
|||
ionLazyLinkListSize_++;
|
||||
}
|
||||
|
||||
void
|
||||
ZoneGroup::deleteEmptyZone(Zone* zone)
|
||||
{
|
||||
MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime));
|
||||
MOZ_ASSERT(zone->group() == this);
|
||||
MOZ_ASSERT(zone->compartments().empty());
|
||||
for (auto& i : zones()) {
|
||||
if (i == zone) {
|
||||
zones().erase(&i);
|
||||
zone->destroy(runtime->defaultFreeOp());
|
||||
return;
|
||||
}
|
||||
}
|
||||
MOZ_CRASH("Zone not found");
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
|
|
@ -76,6 +76,9 @@ class ZoneGroup
|
|||
// See the useExclusiveLocking field above.
|
||||
void setUseExclusiveLocking() { useExclusiveLocking = true; }
|
||||
|
||||
// Delete an empty zone after its contents have been merged.
|
||||
void deleteEmptyZone(Zone* zone);
|
||||
|
||||
#ifdef DEBUG
|
||||
private:
|
||||
// The number of possible bailing places encounters before forcefully bailing
|
||||
|
|
|
@ -863,6 +863,7 @@ struct JSCompartment
|
|||
~JSCompartment();
|
||||
|
||||
MOZ_MUST_USE bool init(JSContext* maybecx);
|
||||
void destroy(js::FreeOp* fop);
|
||||
|
||||
MOZ_MUST_USE inline bool wrap(JSContext* cx, JS::MutableHandleValue vp);
|
||||
|
||||
|
|
|
@ -1220,11 +1220,12 @@ GCRuntime::finish()
|
|||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
|
||||
js_delete(comp.get());
|
||||
zone->compartments().clear();
|
||||
js_delete(zone.get());
|
||||
}
|
||||
}
|
||||
|
||||
groups.ref().clear();
|
||||
groups().clear();
|
||||
|
||||
FreeChunkPool(rt, fullChunks_.ref());
|
||||
FreeChunkPool(rt, availableChunks_.ref());
|
||||
|
@ -3483,6 +3484,25 @@ JS::Zone::sweepUniqueIds(js::FreeOp* fop)
|
|||
uniqueIds().sweep();
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::destroy(FreeOp* fop)
|
||||
{
|
||||
JSRuntime* rt = fop->runtime();
|
||||
if (auto callback = rt->destroyCompartmentCallback)
|
||||
callback(fop, this);
|
||||
if (principals())
|
||||
JS_DropPrincipals(TlsContext.get(), principals());
|
||||
fop->delete_(this);
|
||||
rt->gc.stats().sweptCompartment();
|
||||
}
|
||||
|
||||
void
|
||||
Zone::destroy(FreeOp* fop)
|
||||
{
|
||||
fop->delete_(this);
|
||||
fop->runtime()->gc.stats().sweptZone();
|
||||
}
|
||||
|
||||
/*
|
||||
* It's simpler if we preserve the invariant that every zone has at least one
|
||||
* compartment. If we know we're deleting the entire zone, then
|
||||
|
@ -3495,8 +3515,9 @@ JS::Zone::sweepUniqueIds(js::FreeOp* fop)
|
|||
void
|
||||
Zone::sweepCompartments(FreeOp* fop, bool keepAtleastOne, bool destroyingRuntime)
|
||||
{
|
||||
JSRuntime* rt = runtimeFromActiveCooperatingThread();
|
||||
JSDestroyCompartmentCallback callback = rt->destroyCompartmentCallback;
|
||||
MOZ_ASSERT(!compartments().empty());
|
||||
|
||||
mozilla::DebugOnly<JSRuntime*> rt = runtimeFromActiveCooperatingThread();
|
||||
|
||||
JSCompartment** read = compartments().begin();
|
||||
JSCompartment** end = compartments().end();
|
||||
|
@ -3512,12 +3533,7 @@ Zone::sweepCompartments(FreeOp* fop, bool keepAtleastOne, bool destroyingRuntime
|
|||
*/
|
||||
bool dontDelete = read == end && !foundOne && keepAtleastOne;
|
||||
if ((!comp->marked && !dontDelete) || destroyingRuntime) {
|
||||
if (callback)
|
||||
callback(fop, comp);
|
||||
if (comp->principals())
|
||||
JS_DropPrincipals(TlsContext.get(), comp->principals());
|
||||
js_delete(comp);
|
||||
rt->gc.stats().sweptCompartment();
|
||||
comp->destroy(fop);
|
||||
} else {
|
||||
*write++ = comp;
|
||||
foundOne = true;
|
||||
|
@ -3530,6 +3546,8 @@ Zone::sweepCompartments(FreeOp* fop, bool keepAtleastOne, bool destroyingRuntime
|
|||
void
|
||||
GCRuntime::sweepZones(FreeOp* fop, ZoneGroup* group, bool destroyingRuntime)
|
||||
{
|
||||
MOZ_ASSERT(!group->zones().empty());
|
||||
|
||||
Zone** read = group->zones().begin();
|
||||
Zone** end = group->zones().end();
|
||||
Zone** write = read;
|
||||
|
@ -3558,8 +3576,7 @@ GCRuntime::sweepZones(FreeOp* fop, ZoneGroup* group, bool destroyingRuntime)
|
|||
zone->sweepCompartments(fop, false, destroyingRuntime);
|
||||
MOZ_ASSERT(zone->compartments().empty());
|
||||
MOZ_ASSERT_IF(arenasEmptyAtShutdown, zone->typeDescrObjects().empty());
|
||||
fop->delete_(zone);
|
||||
stats().sweptZone();
|
||||
zone->destroy(fop);
|
||||
continue;
|
||||
}
|
||||
zone->sweepCompartments(fop, true, destroyingRuntime);
|
||||
|
@ -3580,8 +3597,8 @@ GCRuntime::sweepZoneGroups(FreeOp* fop, bool destroyingRuntime)
|
|||
|
||||
assertBackgroundSweepingFinished();
|
||||
|
||||
ZoneGroup** read = groups.ref().begin();
|
||||
ZoneGroup** end = groups.ref().end();
|
||||
ZoneGroup** read = groups().begin();
|
||||
ZoneGroup** end = groups().end();
|
||||
ZoneGroup** write = read;
|
||||
|
||||
while (read < end) {
|
||||
|
@ -3595,7 +3612,7 @@ GCRuntime::sweepZoneGroups(FreeOp* fop, bool destroyingRuntime)
|
|||
*write++ = group;
|
||||
}
|
||||
}
|
||||
groups.ref().shrinkTo(write - groups.ref().begin());
|
||||
groups().shrinkTo(write - groups().begin());
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -7367,7 +7384,7 @@ js::NewCompartment(JSContext* cx, JSPrincipals* principals,
|
|||
}
|
||||
|
||||
if (groupHolder) {
|
||||
if (!rt->gc.groups.ref().append(group)) {
|
||||
if (!rt->gc.groups().append(group)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -7397,6 +7414,10 @@ gc::MergeCompartments(JSCompartment* source, JSCompartment* target)
|
|||
MOZ_ASSERT(source->creationOptions().addonIdOrNull() ==
|
||||
target->creationOptions().addonIdOrNull());
|
||||
|
||||
MOZ_ASSERT(!source->hasBeenEntered());
|
||||
MOZ_ASSERT(source->zone()->compartments().length() == 1);
|
||||
MOZ_ASSERT(source->zone()->group()->zones().length() == 1);
|
||||
|
||||
JSContext* cx = source->runtimeFromActiveCooperatingThread()->activeContextFromOwnThread();
|
||||
|
||||
MOZ_ASSERT(!source->zone()->wasGCStarted());
|
||||
|
@ -7489,6 +7510,32 @@ gc::MergeCompartments(JSCompartment* source, JSCompartment* target)
|
|||
|
||||
source->scriptNameMap->clear();
|
||||
}
|
||||
|
||||
// The source compartment is now completely empty, and is the only
|
||||
// compartment in its zone, which is the only zone in its group. Delete
|
||||
// compartment, zone and group without waiting for this to be cleaned up by
|
||||
// a full GC.
|
||||
|
||||
Zone* sourceZone = source->zone();
|
||||
ZoneGroup* sourceGroup = sourceZone->group();
|
||||
sourceZone->deleteEmptyCompartment(source);
|
||||
sourceGroup->deleteEmptyZone(sourceZone);
|
||||
cx->runtime()->gc.deleteEmptyZoneGroup(sourceGroup);
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::deleteEmptyZoneGroup(ZoneGroup* group)
|
||||
{
|
||||
MOZ_ASSERT(group->zones().empty());
|
||||
MOZ_ASSERT(groups().length() > 1);
|
||||
for (auto& i : groups()) {
|
||||
if (i == group) {
|
||||
groups().erase(&i);
|
||||
js_delete(group);
|
||||
return;
|
||||
}
|
||||
}
|
||||
MOZ_CRASH("ZoneGroup not found");
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1598,9 +1598,10 @@ GlobalHelperThreadState::mergeParseTaskCompartment(JSContext* cx, ParseTask* par
|
|||
JS::AutoAssertNoGC nogc(cx);
|
||||
|
||||
LeaveParseTaskZone(cx->runtime(), parseTask);
|
||||
AutoCompartment ac(cx, parseTask->parseGlobal);
|
||||
|
||||
{
|
||||
AutoCompartment ac(cx, parseTask->parseGlobal);
|
||||
|
||||
// Generator functions don't have Function.prototype as prototype but a
|
||||
// different function object, so the IdentifyStandardPrototype trick
|
||||
// below won't work. Just special-case it.
|
||||
|
|
Загрузка…
Ссылка в новой задаче