зеркало из 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 startTask(GCParallelTask& task, gcstats::PhaseKind phase, AutoLockHelperThreadState& locked);
|
||||||
void joinTask(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:
|
private:
|
||||||
enum IncrementalResult
|
enum IncrementalResult
|
||||||
|
@ -1096,7 +1097,10 @@ class GCRuntime
|
||||||
UnprotectedData<ZoneGroup*> systemZoneGroup;
|
UnprotectedData<ZoneGroup*> systemZoneGroup;
|
||||||
|
|
||||||
// List of all zone groups (protected by the GC lock).
|
// 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.
|
// The unique atoms zone, which has no zone group.
|
||||||
WriteOnceData<Zone*> atomsZone;
|
WriteOnceData<Zone*> atomsZone;
|
||||||
|
|
|
@ -73,6 +73,8 @@ JS::Zone::Zone(JSRuntime* rt, ZoneGroup* group)
|
||||||
|
|
||||||
Zone::~Zone()
|
Zone::~Zone()
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(compartments_.ref().empty());
|
||||||
|
|
||||||
JSRuntime* rt = runtimeFromAnyThread();
|
JSRuntime* rt = runtimeFromAnyThread();
|
||||||
if (this == rt->gc.systemZone)
|
if (this == rt->gc.systemZone)
|
||||||
rt->gc.systemZone = nullptr;
|
rt->gc.systemZone = nullptr;
|
||||||
|
@ -87,7 +89,8 @@ Zone::~Zone()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Zone::init(bool isSystemArg)
|
bool
|
||||||
|
Zone::init(bool isSystemArg)
|
||||||
{
|
{
|
||||||
isSystem = isSystemArg;
|
isSystem = isSystemArg;
|
||||||
return uniqueIds().init() &&
|
return uniqueIds().init() &&
|
||||||
|
@ -376,6 +379,21 @@ Zone::addTypeDescrObject(JSContext* cx, HandleObject obj)
|
||||||
return true;
|
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()
|
ZoneList::ZoneList()
|
||||||
: head(nullptr), tail(nullptr)
|
: head(nullptr), tail(nullptr)
|
||||||
{}
|
{}
|
||||||
|
|
|
@ -161,6 +161,7 @@ struct Zone : public JS::shadow::Zone,
|
||||||
explicit Zone(JSRuntime* rt, js::ZoneGroup* group);
|
explicit Zone(JSRuntime* rt, js::ZoneGroup* group);
|
||||||
~Zone();
|
~Zone();
|
||||||
MOZ_MUST_USE bool init(bool isSystem);
|
MOZ_MUST_USE bool init(bool isSystem);
|
||||||
|
void destroy(js::FreeOp *fop);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
js::ZoneGroup* const group_;
|
js::ZoneGroup* const group_;
|
||||||
|
@ -622,6 +623,9 @@ struct Zone : public JS::shadow::Zone,
|
||||||
keepShapeTables_ = b;
|
keepShapeTables_ = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete an empty compartment after its contents have been merged.
|
||||||
|
void deleteEmptyCompartment(JSCompartment* comp);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
js::ZoneGroupData<js::jit::JitZone*> jitZone_;
|
js::ZoneGroupData<js::jit::JitZone*> jitZone_;
|
||||||
|
|
||||||
|
@ -654,8 +658,8 @@ class ZoneGroupsIter
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ZoneGroupsIter(JSRuntime* rt) : iterMarker(&rt->gc) {
|
explicit ZoneGroupsIter(JSRuntime* rt) : iterMarker(&rt->gc) {
|
||||||
it = rt->gc.groups.ref().begin();
|
it = rt->gc.groups().begin();
|
||||||
end = rt->gc.groups.ref().end();
|
end = rt->gc.groups().end();
|
||||||
|
|
||||||
if (!done() && (*it)->usedByHelperThread)
|
if (!done() && (*it)->usedByHelperThread)
|
||||||
next();
|
next();
|
||||||
|
|
|
@ -130,4 +130,20 @@ ZoneGroup::ionLazyLinkListAdd(jit::IonBuilder* builder)
|
||||||
ionLazyLinkListSize_++;
|
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
|
} // namespace js
|
||||||
|
|
|
@ -76,6 +76,9 @@ class ZoneGroup
|
||||||
// See the useExclusiveLocking field above.
|
// See the useExclusiveLocking field above.
|
||||||
void setUseExclusiveLocking() { useExclusiveLocking = true; }
|
void setUseExclusiveLocking() { useExclusiveLocking = true; }
|
||||||
|
|
||||||
|
// Delete an empty zone after its contents have been merged.
|
||||||
|
void deleteEmptyZone(Zone* zone);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
private:
|
private:
|
||||||
// The number of possible bailing places encounters before forcefully bailing
|
// The number of possible bailing places encounters before forcefully bailing
|
||||||
|
|
|
@ -863,6 +863,7 @@ struct JSCompartment
|
||||||
~JSCompartment();
|
~JSCompartment();
|
||||||
|
|
||||||
MOZ_MUST_USE bool init(JSContext* maybecx);
|
MOZ_MUST_USE bool init(JSContext* maybecx);
|
||||||
|
void destroy(js::FreeOp* fop);
|
||||||
|
|
||||||
MOZ_MUST_USE inline bool wrap(JSContext* cx, JS::MutableHandleValue vp);
|
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 (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||||
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
|
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
|
||||||
js_delete(comp.get());
|
js_delete(comp.get());
|
||||||
|
zone->compartments().clear();
|
||||||
js_delete(zone.get());
|
js_delete(zone.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
groups.ref().clear();
|
groups().clear();
|
||||||
|
|
||||||
FreeChunkPool(rt, fullChunks_.ref());
|
FreeChunkPool(rt, fullChunks_.ref());
|
||||||
FreeChunkPool(rt, availableChunks_.ref());
|
FreeChunkPool(rt, availableChunks_.ref());
|
||||||
|
@ -3483,6 +3484,25 @@ JS::Zone::sweepUniqueIds(js::FreeOp* fop)
|
||||||
uniqueIds().sweep();
|
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
|
* 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
|
* compartment. If we know we're deleting the entire zone, then
|
||||||
|
@ -3495,8 +3515,9 @@ JS::Zone::sweepUniqueIds(js::FreeOp* fop)
|
||||||
void
|
void
|
||||||
Zone::sweepCompartments(FreeOp* fop, bool keepAtleastOne, bool destroyingRuntime)
|
Zone::sweepCompartments(FreeOp* fop, bool keepAtleastOne, bool destroyingRuntime)
|
||||||
{
|
{
|
||||||
JSRuntime* rt = runtimeFromActiveCooperatingThread();
|
MOZ_ASSERT(!compartments().empty());
|
||||||
JSDestroyCompartmentCallback callback = rt->destroyCompartmentCallback;
|
|
||||||
|
mozilla::DebugOnly<JSRuntime*> rt = runtimeFromActiveCooperatingThread();
|
||||||
|
|
||||||
JSCompartment** read = compartments().begin();
|
JSCompartment** read = compartments().begin();
|
||||||
JSCompartment** end = compartments().end();
|
JSCompartment** end = compartments().end();
|
||||||
|
@ -3512,12 +3533,7 @@ Zone::sweepCompartments(FreeOp* fop, bool keepAtleastOne, bool destroyingRuntime
|
||||||
*/
|
*/
|
||||||
bool dontDelete = read == end && !foundOne && keepAtleastOne;
|
bool dontDelete = read == end && !foundOne && keepAtleastOne;
|
||||||
if ((!comp->marked && !dontDelete) || destroyingRuntime) {
|
if ((!comp->marked && !dontDelete) || destroyingRuntime) {
|
||||||
if (callback)
|
comp->destroy(fop);
|
||||||
callback(fop, comp);
|
|
||||||
if (comp->principals())
|
|
||||||
JS_DropPrincipals(TlsContext.get(), comp->principals());
|
|
||||||
js_delete(comp);
|
|
||||||
rt->gc.stats().sweptCompartment();
|
|
||||||
} else {
|
} else {
|
||||||
*write++ = comp;
|
*write++ = comp;
|
||||||
foundOne = true;
|
foundOne = true;
|
||||||
|
@ -3530,6 +3546,8 @@ Zone::sweepCompartments(FreeOp* fop, bool keepAtleastOne, bool destroyingRuntime
|
||||||
void
|
void
|
||||||
GCRuntime::sweepZones(FreeOp* fop, ZoneGroup* group, bool destroyingRuntime)
|
GCRuntime::sweepZones(FreeOp* fop, ZoneGroup* group, bool destroyingRuntime)
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(!group->zones().empty());
|
||||||
|
|
||||||
Zone** read = group->zones().begin();
|
Zone** read = group->zones().begin();
|
||||||
Zone** end = group->zones().end();
|
Zone** end = group->zones().end();
|
||||||
Zone** write = read;
|
Zone** write = read;
|
||||||
|
@ -3558,8 +3576,7 @@ GCRuntime::sweepZones(FreeOp* fop, ZoneGroup* group, bool destroyingRuntime)
|
||||||
zone->sweepCompartments(fop, false, destroyingRuntime);
|
zone->sweepCompartments(fop, false, destroyingRuntime);
|
||||||
MOZ_ASSERT(zone->compartments().empty());
|
MOZ_ASSERT(zone->compartments().empty());
|
||||||
MOZ_ASSERT_IF(arenasEmptyAtShutdown, zone->typeDescrObjects().empty());
|
MOZ_ASSERT_IF(arenasEmptyAtShutdown, zone->typeDescrObjects().empty());
|
||||||
fop->delete_(zone);
|
zone->destroy(fop);
|
||||||
stats().sweptZone();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
zone->sweepCompartments(fop, true, destroyingRuntime);
|
zone->sweepCompartments(fop, true, destroyingRuntime);
|
||||||
|
@ -3580,8 +3597,8 @@ GCRuntime::sweepZoneGroups(FreeOp* fop, bool destroyingRuntime)
|
||||||
|
|
||||||
assertBackgroundSweepingFinished();
|
assertBackgroundSweepingFinished();
|
||||||
|
|
||||||
ZoneGroup** read = groups.ref().begin();
|
ZoneGroup** read = groups().begin();
|
||||||
ZoneGroup** end = groups.ref().end();
|
ZoneGroup** end = groups().end();
|
||||||
ZoneGroup** write = read;
|
ZoneGroup** write = read;
|
||||||
|
|
||||||
while (read < end) {
|
while (read < end) {
|
||||||
|
@ -3595,7 +3612,7 @@ GCRuntime::sweepZoneGroups(FreeOp* fop, bool destroyingRuntime)
|
||||||
*write++ = group;
|
*write++ = group;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
groups.ref().shrinkTo(write - groups.ref().begin());
|
groups().shrinkTo(write - groups().begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -7367,7 +7384,7 @@ js::NewCompartment(JSContext* cx, JSPrincipals* principals,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groupHolder) {
|
if (groupHolder) {
|
||||||
if (!rt->gc.groups.ref().append(group)) {
|
if (!rt->gc.groups().append(group)) {
|
||||||
ReportOutOfMemory(cx);
|
ReportOutOfMemory(cx);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -7397,6 +7414,10 @@ gc::MergeCompartments(JSCompartment* source, JSCompartment* target)
|
||||||
MOZ_ASSERT(source->creationOptions().addonIdOrNull() ==
|
MOZ_ASSERT(source->creationOptions().addonIdOrNull() ==
|
||||||
target->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();
|
JSContext* cx = source->runtimeFromActiveCooperatingThread()->activeContextFromOwnThread();
|
||||||
|
|
||||||
MOZ_ASSERT(!source->zone()->wasGCStarted());
|
MOZ_ASSERT(!source->zone()->wasGCStarted());
|
||||||
|
@ -7489,6 +7510,32 @@ gc::MergeCompartments(JSCompartment* source, JSCompartment* target)
|
||||||
|
|
||||||
source->scriptNameMap->clear();
|
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
|
void
|
||||||
|
|
|
@ -1598,9 +1598,10 @@ GlobalHelperThreadState::mergeParseTaskCompartment(JSContext* cx, ParseTask* par
|
||||||
JS::AutoAssertNoGC nogc(cx);
|
JS::AutoAssertNoGC nogc(cx);
|
||||||
|
|
||||||
LeaveParseTaskZone(cx->runtime(), parseTask);
|
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
|
// Generator functions don't have Function.prototype as prototype but a
|
||||||
// different function object, so the IdentifyStandardPrototype trick
|
// different function object, so the IdentifyStandardPrototype trick
|
||||||
// below won't work. Just special-case it.
|
// below won't work. Just special-case it.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче