Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit 68eeb82

Browse files
committed
Bug 1449135 part 3 - Remove cooperative scheduling; bake in JSContext* in JIT code. r=luke
1 parent ec31881 commit 68eeb82

47 files changed

Lines changed: 350 additions & 897 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

js/public/RootingAPI.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -874,8 +874,8 @@ class JS_PUBLIC_API(AutoGCRooter)
874874

875875
/* Implemented in gc/RootMarking.cpp. */
876876
inline void trace(JSTracer* trc);
877-
static void traceAll(const js::CooperatingContext& target, JSTracer* trc);
878-
static void traceAllWrappers(const js::CooperatingContext& target, JSTracer* trc);
877+
static void traceAll(JSContext* cx, JSTracer* trc);
878+
static void traceAllWrappers(JSContext* cx, JSTracer* trc);
879879

880880
protected:
881881
AutoGCRooter * const down;

js/src/gc/GC.cpp

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3244,7 +3244,7 @@ GCRuntime::triggerGC(JS::gcreason::Reason reason)
32443244
if (JS::CurrentThreadIsHeapCollecting())
32453245
return false;
32463246

3247-
JS::PrepareForFullGC(rt->activeContextFromOwnThread());
3247+
JS::PrepareForFullGC(rt->mainContextFromOwnThread());
32483248
requestMajorGC(reason);
32493249
return true;
32503250
}
@@ -3341,7 +3341,7 @@ GCRuntime::maybeGC(Zone* zone)
33413341

33423342
#ifdef JS_GC_ZEAL
33433343
if (hasZealMode(ZealMode::Alloc) || hasZealMode(ZealMode::RootsChange)) {
3344-
JS::PrepareForFullGC(rt->activeContextFromOwnThread());
3344+
JS::PrepareForFullGC(rt->mainContextFromOwnThread());
33453345
gc(GC_NORMAL, JS::gcreason::DEBUG_GC);
33463346
return;
33473347
}
@@ -3966,11 +3966,10 @@ GCRuntime::purgeRuntime()
39663966
zone->functionToStringCache().purge();
39673967
}
39683968

3969-
for (const CooperatingContext& target : rt->cooperatingContexts()) {
3970-
freeUnusedLifoBlocksAfterSweeping(&target.context()->tempLifoAlloc());
3971-
target.context()->interpreterStack().purge(rt);
3972-
target.context()->frontendCollectionPool().purge();
3973-
}
3969+
JSContext* cx = rt->mainContextFromOwnThread();
3970+
freeUnusedLifoBlocksAfterSweeping(&cx->tempLifoAlloc());
3971+
cx->interpreterStack().purge(rt);
3972+
cx->frontendCollectionPool().purge();
39743973

39753974
rt->caches().purge();
39763975

@@ -7020,8 +7019,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
70207019
MOZ_FALLTHROUGH;
70217020

70227021
case State::Mark:
7023-
for (const CooperatingContext& target : rt->cooperatingContexts())
7024-
AutoGCRooter::traceAllWrappers(target, &marker);
7022+
AutoGCRooter::traceAllWrappers(rt->mainContextFromOwnThread(), &marker);
70257023

70267024
/* If we needed delayed marking for gray roots, then collect until done. */
70277025
if (isIncremental && !hasValidGrayRootsBuffer()) {
@@ -7468,7 +7466,7 @@ GCRuntime::maybeDoCycleCollection()
74687466
}
74697467
double grayFraction = double(compartmentsGray) / double(compartmentsTotal);
74707468
if (grayFraction > ExcessiveGrayCompartments || compartmentsGray > LimitGrayCompartments)
7471-
callDoCycleCollectionCallback(rt->activeContextFromOwnThread());
7469+
callDoCycleCollectionCallback(rt->mainContextFromOwnThread());
74727470
}
74737471

74747472
void
@@ -7556,7 +7554,7 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R
75567554
repeat = true;
75577555
} else if (rootsRemoved && IsShutdownGC(reason)) {
75587556
/* Need to re-schedule all zones for GC. */
7559-
JS::PrepareForFullGC(rt->activeContextFromOwnThread());
7557+
JS::PrepareForFullGC(rt->mainContextFromOwnThread());
75607558
repeat = true;
75617559
reason = JS::gcreason::ROOTS_REMOVED;
75627560
} else if (shouldRepeatForDeadZone(reason)) {
@@ -7672,7 +7670,7 @@ GCRuntime::startDebugGC(JSGCInvocationKind gckind, SliceBudget& budget)
76727670
{
76737671
MOZ_ASSERT(!isIncrementalGCInProgress());
76747672
if (!ZonesSelected(rt))
7675-
JS::PrepareForFullGC(rt->activeContextFromOwnThread());
7673+
JS::PrepareForFullGC(rt->mainContextFromOwnThread());
76767674
invocationKind = gckind;
76777675
collect(false, budget, JS::gcreason::DEBUG_GC);
76787676
}
@@ -7682,7 +7680,7 @@ GCRuntime::debugGCSlice(SliceBudget& budget)
76827680
{
76837681
MOZ_ASSERT(isIncrementalGCInProgress());
76847682
if (!ZonesSelected(rt))
7685-
JS::PrepareForIncrementalGC(rt->activeContextFromOwnThread());
7683+
JS::PrepareForIncrementalGC(rt->mainContextFromOwnThread());
76867684
collect(false, budget, JS::gcreason::DEBUG_GC);
76877685
}
76887686

@@ -7691,7 +7689,7 @@ void
76917689
js::PrepareForDebugGC(JSRuntime* rt)
76927690
{
76937691
if (!ZonesSelected(rt))
7694-
JS::PrepareForFullGC(rt->activeContextFromOwnThread());
7692+
JS::PrepareForFullGC(rt->mainContextFromOwnThread());
76957693
}
76967694

76977695
void
@@ -7864,10 +7862,7 @@ js::NewCompartment(JSContext* cx, JSPrincipals* principals,
78647862
break;
78657863
}
78667864

7867-
if (group) {
7868-
// Take over ownership of the group while we create the compartment/zone.
7869-
group->enter(cx);
7870-
} else {
7865+
if (!group) {
78717866
MOZ_ASSERT(!zone);
78727867
group = cx->new_<ZoneGroup>(rt);
78737868
if (!group)
@@ -7937,13 +7932,11 @@ js::NewCompartment(JSContext* cx, JSPrincipals* principals,
79377932
if (zoneSpec == JS::SystemZone || zoneSpec == JS::NewZoneInSystemZoneGroup) {
79387933
MOZ_RELEASE_ASSERT(!rt->gc.systemZoneGroup);
79397934
rt->gc.systemZoneGroup = group;
7940-
group->setUseExclusiveLocking();
79417935
}
79427936
}
79437937

79447938
zoneHolder.forget();
79457939
groupHolder.forget();
7946-
group->leave();
79477940
return compartment.forget();
79487941
}
79497942

@@ -7969,7 +7962,7 @@ GCRuntime::mergeCompartments(JSCompartment* source, JSCompartment* target)
79697962
MOZ_ASSERT(source->zone()->compartments().length() == 1);
79707963
MOZ_ASSERT(source->zone()->group()->zones().length() == 1);
79717964

7972-
JSContext* cx = rt->activeContextFromOwnThread();
7965+
JSContext* cx = rt->mainContextFromOwnThread();
79737966

79747967
MOZ_ASSERT(!source->zone()->wasGCStarted());
79757968
JS::AutoAssertNoGC nogc(cx);
@@ -8232,7 +8225,6 @@ js::ReleaseAllJITCode(FreeOp* fop)
82328225
{
82338226
js::CancelOffThreadIonCompile(fop->runtime());
82348227

8235-
JSRuntime::AutoProhibitActiveContextChange apacc(fop->runtime());
82368228
for (ZonesIter zone(fop->runtime(), SkipAtoms); !zone.done(); zone.next()) {
82378229
zone->setPreservingCode(false);
82388230
zone->discardJitCode(fop);

js/src/gc/Nursery.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,7 @@ js::Nursery::collect(JS::gcreason::Reason reason)
747747
for (auto& entry : tenureCounts.entries) {
748748
if (entry.count >= 3000) {
749749
ObjectGroup* group = entry.group;
750-
if (group->canPreTenure() && group->zone()->group()->canEnterWithoutYielding(cx)) {
750+
if (group->canPreTenure()) {
751751
AutoCompartment ac(cx, group);
752752
group->setShouldPreTenure(cx);
753753
pretenureCount++;
@@ -757,7 +757,6 @@ js::Nursery::collect(JS::gcreason::Reason reason)
757757
}
758758
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
759759
if (shouldPretenure && zone->allocNurseryStrings && zone->tenuredStrings >= 30 * 1000) {
760-
JSRuntime::AutoProhibitActiveContextChange apacc(rt);
761760
CancelOffThreadIonCompile(zone);
762761
bool preserving = zone->isPreservingCode();
763762
zone->setPreservingCode(false);

js/src/gc/RootMarking.cpp

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ JS::RootingContext::traceStackRoots(JSTracer* trc)
8080
}
8181

8282
static void
83-
TraceExactStackRoots(const CooperatingContext& target, JSTracer* trc)
83+
TraceExactStackRoots(JSContext* cx, JSTracer* trc)
8484
{
85-
target.context()->traceStackRoots(trc);
85+
cx->traceStackRoots(trc);
8686
}
8787

8888
template <typename T, TraceFunction<T> TraceFn = TraceNullableRoot>
@@ -196,16 +196,16 @@ AutoGCRooter::trace(JSTracer* trc)
196196
}
197197

198198
/* static */ void
199-
AutoGCRooter::traceAll(const CooperatingContext& target, JSTracer* trc)
199+
AutoGCRooter::traceAll(JSContext* cx, JSTracer* trc)
200200
{
201-
for (AutoGCRooter* gcr = target.context()->autoGCRooters_; gcr; gcr = gcr->down)
201+
for (AutoGCRooter* gcr = cx->autoGCRooters_; gcr; gcr = gcr->down)
202202
gcr->trace(trc);
203203
}
204204

205205
/* static */ void
206-
AutoGCRooter::traceAllWrappers(const CooperatingContext& target, JSTracer* trc)
206+
AutoGCRooter::traceAllWrappers(JSContext* cx, JSTracer* trc)
207207
{
208-
for (AutoGCRooter* gcr = target.context()->autoGCRooters_; gcr; gcr = gcr->down) {
208+
for (AutoGCRooter* gcr = cx->autoGCRooters_; gcr; gcr = gcr->down) {
209209
if (gcr->tag_ == WRAPVECTOR || gcr->tag_ == WRAPPER)
210210
gcr->trace(trc);
211211
}
@@ -319,18 +319,17 @@ js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrM
319319
{
320320
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_STACK);
321321

322-
JSContext* cx = TlsContext.get();
323-
for (const CooperatingContext& target : rt->cooperatingContexts()) {
324-
// Trace active interpreter and JIT stack roots.
325-
TraceInterpreterActivations(cx, target, trc);
326-
jit::TraceJitActivations(cx, target, trc);
322+
JSContext* cx = rt->mainContextFromOwnThread();
327323

328-
// Trace legacy C stack roots.
329-
AutoGCRooter::traceAll(target, trc);
324+
// Trace active interpreter and JIT stack roots.
325+
TraceInterpreterActivations(cx, trc);
326+
jit::TraceJitActivations(cx, trc);
330327

331-
// Trace C stack roots.
332-
TraceExactStackRoots(target, trc);
333-
}
328+
// Trace legacy C stack roots.
329+
AutoGCRooter::traceAll(cx, trc);
330+
331+
// Trace C stack roots.
332+
TraceExactStackRoots(cx, trc);
334333

335334
for (RootRange r = rootsHash.ref().all(); !r.empty(); r.popFront()) {
336335
const RootEntry& entry = r.front();
@@ -347,9 +346,8 @@ js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrM
347346
// Trace the shared Intl data.
348347
rt->traceSharedIntlData(trc);
349348

350-
// Trace anything in any of the cooperating threads.
351-
for (const CooperatingContext& target : rt->cooperatingContexts())
352-
target.context()->trace(trc);
349+
// Trace the JSContext.
350+
rt->mainContextFromOwnThread()->trace(trc);
353351

354352
// Trace all compartment roots, but not the compartment itself; it is
355353
// traced via the parent pointer if traceRoots actually traces anything.

js/src/gc/Verifier.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,7 @@ gc::GCRuntime::startVerifyPreBarriers()
181181

182182
if (IsIncrementalGCUnsafe(rt) != AbortReason::None ||
183183
TlsContext.get()->keepAtoms ||
184-
rt->hasHelperThreadZones() ||
185-
rt->cooperatingContexts().length() != 1)
184+
rt->hasHelperThreadZones())
186185
{
187186
return;
188187
}
@@ -334,7 +333,7 @@ gc::GCRuntime::endVerifyPreBarriers()
334333

335334
MOZ_ASSERT(!JS::IsGenerationalGCEnabled(rt));
336335

337-
AutoPrepareForTracing prep(rt->activeContextFromOwnThread());
336+
AutoPrepareForTracing prep(rt->mainContextFromOwnThread());
338337

339338
bool compartmentCreated = false;
340339

js/src/gc/ZoneGroup.cpp

Lines changed: 7 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ namespace js {
1717

1818
ZoneGroup::ZoneGroup(JSRuntime* runtime)
1919
: runtime(runtime),
20-
ownerContext_(TlsContext.get()),
21-
enterCount(1),
20+
helperThreadOwnerContext_(nullptr),
2221
zones_(this),
2322
helperThreadUse(HelperThreadUse::None),
2423
#ifdef DEBUG
@@ -60,51 +59,18 @@ ZoneGroup::~ZoneGroup()
6059
}
6160

6261
void
63-
ZoneGroup::enter(JSContext* cx)
62+
ZoneGroup::setHelperThreadOwnerContext(JSContext* cx)
6463
{
65-
if (ownerContext().context() == cx) {
66-
MOZ_ASSERT(enterCount);
67-
} else {
68-
if (useExclusiveLocking()) {
69-
MOZ_ASSERT(!usedByHelperThread());
70-
while (ownerContext().context() != nullptr) {
71-
cx->yieldToEmbedding();
72-
}
73-
}
74-
MOZ_RELEASE_ASSERT(ownerContext().context() == nullptr);
75-
MOZ_ASSERT(enterCount == 0);
76-
ownerContext_ = CooperatingContext(cx);
77-
if (cx->generationalDisabled)
78-
nursery().disable();
79-
80-
// Finish any Ion compilations in this zone group, in case compilation
81-
// finished for some script in this group while no thread was in this
82-
// group.
83-
jit::AttachFinishedCompilations(this, nullptr);
84-
}
85-
enterCount++;
86-
}
87-
88-
void
89-
ZoneGroup::leave()
90-
{
91-
MOZ_ASSERT(ownedByCurrentThread());
92-
MOZ_ASSERT(enterCount);
93-
if (--enterCount == 0)
94-
ownerContext_ = CooperatingContext(nullptr);
95-
}
96-
97-
bool
98-
ZoneGroup::canEnterWithoutYielding(JSContext* cx)
99-
{
100-
return ownerContext().context() == cx || ownerContext().context() == nullptr;
64+
MOZ_ASSERT_IF(cx, TlsContext.get() == cx);
65+
helperThreadOwnerContext_ = cx;
10166
}
10267

10368
bool
104-
ZoneGroup::ownedByCurrentThread()
69+
ZoneGroup::ownedByCurrentHelperThread()
10570
{
71+
MOZ_ASSERT(usedByHelperThread());
10672
MOZ_ASSERT(TlsContext.get());
107-
return ownerContext().context() == TlsContext.get();
73+
return helperThreadOwnerContext_ == TlsContext.get();
10874
}
10975

11076
ZoneGroup::IonBuilderList&
@@ -156,26 +122,3 @@ ZoneGroup::deleteEmptyZone(Zone* zone)
156122
}
157123

158124
} // namespace js
159-
160-
JS::AutoRelinquishZoneGroups::AutoRelinquishZoneGroups(JSContext* cx)
161-
: cx(cx)
162-
{
163-
MOZ_ASSERT(cx == TlsContext.get());
164-
165-
AutoEnterOOMUnsafeRegion oomUnsafe;
166-
for (ZoneGroupsIter group(cx->runtime()); !group.done(); group.next()) {
167-
while (group->ownerContext().context() == cx) {
168-
group->leave();
169-
if (!enterList.append(group))
170-
oomUnsafe.crash("AutoRelinquishZoneGroups");
171-
}
172-
}
173-
}
174-
175-
JS::AutoRelinquishZoneGroups::~AutoRelinquishZoneGroups()
176-
{
177-
for (size_t i = 0; i < enterList.length(); i++) {
178-
ZoneGroup* group = static_cast<ZoneGroup*>(enterList[i]);
179-
group->enter(cx);
180-
}
181-
}

js/src/gc/ZoneGroup.h

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,24 +33,13 @@ class ZoneGroup
3333
JSRuntime* const runtime;
3434

3535
private:
36-
// The context with exclusive access to this zone group.
37-
UnprotectedData<CooperatingContext> ownerContext_;
38-
39-
// The number of times the context has entered this zone group.
40-
UnprotectedData<size_t> enterCount;
41-
42-
// If this flag is true, then we may need to block before entering this zone
43-
// group. Blocking happens using JSContext::yieldToEmbedding.
44-
UnprotectedData<bool> useExclusiveLocking_;
36+
// The helper thread context with exclusive access to this zone group, if
37+
// usedByHelperThread(), or nullptr when on the main thread.
38+
UnprotectedData<JSContext*> helperThreadOwnerContext_;
4539

4640
public:
47-
CooperatingContext& ownerContext() { return ownerContext_.ref(); }
48-
void* addressOfOwnerContext() { return &ownerContext_.ref().cx; }
49-
50-
void enter(JSContext* cx);
51-
void leave();
52-
bool canEnterWithoutYielding(JSContext* cx);
53-
bool ownedByCurrentThread();
41+
bool ownedByCurrentHelperThread();
42+
void setHelperThreadOwnerContext(JSContext* cx);
5443

5544
// All zones in the group.
5645
private:
@@ -101,10 +90,6 @@ class ZoneGroup
10190
inline bool isCollecting();
10291
inline bool isGCScheduled();
10392

104-
// See the useExclusiveLocking_ field above.
105-
void setUseExclusiveLocking() { useExclusiveLocking_ = true; }
106-
bool useExclusiveLocking() { return useExclusiveLocking_; }
107-
10893
// Delete an empty zone after its contents have been merged.
10994
void deleteEmptyZone(Zone* zone);
11095

0 commit comments

Comments
 (0)