From 53412618bec8940957be045f32dd2c7a41080227 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 2 Oct 2017 16:42:38 -0700 Subject: [PATCH] Bug 903519 - Disable nursery strings in a Zone if too many get tenured, r=sfink --HG-- extra : rebase_source : 8ffe985d04ef182a7c4900172c6b8bd422ca4879 extra : intermediate-source : 2d3891634ce0a8e76af0e7227ff36ebbeae124d2 extra : source : bb2cc298a15583b524102372d42f722aae5d505a --- js/src/gc/Allocator.cpp | 6 ++++- js/src/gc/Nursery.cpp | 43 ++++++++++++++++++++++++---------- js/src/gc/Zone.cpp | 2 ++ js/src/gc/Zone.h | 3 +++ js/src/jit/CompileWrappers.cpp | 4 +++- js/src/jit/JitCompartment.h | 7 ++++++ js/src/vm/HelperThreads.cpp | 3 +++ js/src/vm/HelperThreads.h | 7 ++++++ 8 files changed, 61 insertions(+), 14 deletions(-) diff --git a/js/src/gc/Allocator.cpp b/js/src/gc/Allocator.cpp index 4f0c870aecc0..a76a1d98d782 100644 --- a/js/src/gc/Allocator.cpp +++ b/js/src/gc/Allocator.cpp @@ -182,7 +182,11 @@ js::AllocateString(JSContext* cx, InitialHeap heap) if (!rt->gc.checkAllocatorState(cx, kind)) return nullptr; - if (cx->nursery().isEnabled() && heap != TenuredHeap && cx->nursery().canAllocateStrings()) { + if (cx->nursery().isEnabled() && + heap != TenuredHeap && + cx->nursery().canAllocateStrings() && + cx->zone()->allocNurseryStrings) + { auto str = static_cast(rt->gc.tryNewNurseryString(cx, size, kind)); if (str) return str; diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index c9ea726b6a6f..b45bdb9f628d 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -738,21 +738,40 @@ js::Nursery::collect(JS::gcreason::Reason reason) bool validPromotionRate; const float promotionRate = calcPromotionRate(&validPromotionRate); uint32_t pretenureCount = 0; - if (validPromotionRate) { - if (promotionRate > 0.8 || IsFullStoreBufferReason(reason)) { - JSContext* cx = TlsContext.get(); - for (auto& entry : tenureCounts.entries) { - if (entry.count >= 3000) { - ObjectGroup* group = entry.group; - if (group->canPreTenure() && group->zone()->group()->canEnterWithoutYielding(cx)) { - AutoCompartment ac(cx, group); - group->setShouldPreTenure(cx); - pretenureCount++; - } + bool shouldPretenure = (validPromotionRate && promotionRate > 0.6) || + IsFullStoreBufferReason(reason); + + if (shouldPretenure) { + JSContext* cx = TlsContext.get(); + for (auto& entry : tenureCounts.entries) { + if (entry.count >= 3000) { + ObjectGroup* group = entry.group; + if (group->canPreTenure() && group->zone()->group()->canEnterWithoutYielding(cx)) { + AutoCompartment ac(cx, group); + group->setShouldPreTenure(cx); + pretenureCount++; } } } } + for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) { + if (shouldPretenure && zone->allocNurseryStrings && zone->tenuredStrings >= 30 * 1000) { + JSRuntime::AutoProhibitActiveContextChange apacc(rt); + CancelOffThreadIonCompile(zone); + bool preserving = zone->isPreservingCode(); + zone->setPreservingCode(false); + zone->discardJitCode(rt->defaultFreeOp()); + zone->setPreservingCode(preserving); + for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) { + if (jit::JitCompartment* jitComp = c->jitCompartment()) { + jitComp->discardStubs(); + jitComp->stringsCanBeInNursery = false; + } + } + zone->allocNurseryStrings = false; + } + zone->tenuredStrings = 0; + } endProfile(ProfileKey::Pretenure); // We ignore gcMaxBytes when allocating for minor collection. However, if we @@ -1086,7 +1105,7 @@ js::Nursery::setStartPosition() void js::Nursery::maybeResizeNursery(JS::gcreason::Reason reason) { - static const double GrowThreshold = 0.05; + static const double GrowThreshold = 0.03; static const double ShrinkThreshold = 0.01; unsigned newMaxNurseryChunks; diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index d87fa958bbcd..97772f9e4126 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -46,6 +46,8 @@ JS::Zone::Zone(JSRuntime* rt, ZoneGroup* group) usage(&rt->gc.usage), threshold(), gcDelayBytes(0), + tenuredStrings(group, 0), + allocNurseryStrings(group, true), propertyTree_(group, this), baseShapes_(group, this), initialShapes_(group, this), diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index a7151a6c2595..dbef131a3b50 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -482,6 +482,9 @@ struct Zone : public JS::shadow::Zone, // the current GC. js::UnprotectedData gcDelayBytes; + js::ZoneGroupData tenuredStrings; + js::ZoneGroupData allocNurseryStrings; + private: // Shared Shape property tree. js::ZoneGroupData propertyTree_; diff --git a/js/src/jit/CompileWrappers.cpp b/js/src/jit/CompileWrappers.cpp index ce6d813a3143..743d8f4aac59 100644 --- a/js/src/jit/CompileWrappers.cpp +++ b/js/src/jit/CompileWrappers.cpp @@ -205,7 +205,9 @@ CompileZone::addressOfStringNurseryCurrentEnd() bool CompileZone::canNurseryAllocateStrings() { - return nurseryExists() && zone()->group()->nursery().canAllocateStrings(); + return nurseryExists() && + zone()->group()->nursery().canAllocateStrings() && + zone()->allocNurseryStrings; } bool diff --git a/js/src/jit/JitCompartment.h b/js/src/jit/JitCompartment.h index 5b92fc96212b..c7404bd4fe7c 100644 --- a/js/src/jit/JitCompartment.h +++ b/js/src/jit/JitCompartment.h @@ -610,6 +610,13 @@ class JitCompartment return stringConcatStub_; } + void discardStubs() { + stringConcatStub_ = nullptr; + regExpMatcherStub_ = nullptr; + regExpSearcherStub_ = nullptr; + regExpTesterStub_ = nullptr; + } + JitCode* regExpMatcherStubNoBarrier() const { return regExpMatcherStub_; } diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index dadb1839f8cc..b00c1bc65404 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -219,6 +219,7 @@ GetSelectorRuntime(const CompilationSelector& selector) { JSRuntime* match(JSScript* script) { return script->runtimeFromActiveCooperatingThread(); } JSRuntime* match(JSCompartment* comp) { return comp->runtimeFromActiveCooperatingThread(); } + JSRuntime* match(Zone* zone) { return zone->runtimeFromActiveCooperatingThread(); } JSRuntime* match(ZonesInState zbs) { return zbs.runtime; } JSRuntime* match(JSRuntime* runtime) { return runtime; } JSRuntime* match(AllCompilations all) { return nullptr; } @@ -235,6 +236,7 @@ JitDataStructuresExist(const CompilationSelector& selector) { bool match(JSScript* script) { return !!script->compartment()->jitCompartment(); } bool match(JSCompartment* comp) { return !!comp->jitCompartment(); } + bool match(Zone* zone) { return !!zone->jitZone(); } bool match(ZonesInState zbs) { return zbs.runtime->hasJitRuntime(); } bool match(JSRuntime* runtime) { return runtime->hasJitRuntime(); } bool match(AllCompilations all) { return true; } @@ -253,6 +255,7 @@ IonBuilderMatches(const CompilationSelector& selector, jit::IonBuilder* builder) bool match(JSScript* script) { return script == builder_->script(); } bool match(JSCompartment* comp) { return comp == builder_->script()->compartment(); } + bool match(Zone* zone) { return zone == builder_->script()->zone(); } bool match(JSRuntime* runtime) { return runtime == builder_->script()->runtimeFromAnyThread(); } bool match(AllCompilations all) { return true; } bool match(ZonesInState zbs) { diff --git a/js/src/vm/HelperThreads.h b/js/src/vm/HelperThreads.h index 6f630b8ec57f..623b8afe706d 100644 --- a/js/src/vm/HelperThreads.h +++ b/js/src/vm/HelperThreads.h @@ -519,6 +519,7 @@ struct CompilationsUsingNursery { JSRuntime* runtime; }; using CompilationSelector = mozilla::Variant