Bug 1449135 part 3 - Remove cooperative scheduling; bake in JSContext* in JIT code. r=luke

This commit is contained in:
Jan de Mooij 2018-03-27 18:00:27 +02:00
Родитель ec31881a4a
Коммит 68eeb821cb
47 изменённых файлов: 349 добавлений и 896 удалений

Просмотреть файл

@ -874,8 +874,8 @@ class JS_PUBLIC_API(AutoGCRooter)
/* Implemented in gc/RootMarking.cpp. */
inline void trace(JSTracer* trc);
static void traceAll(const js::CooperatingContext& target, JSTracer* trc);
static void traceAllWrappers(const js::CooperatingContext& target, JSTracer* trc);
static void traceAll(JSContext* cx, JSTracer* trc);
static void traceAllWrappers(JSContext* cx, JSTracer* trc);
protected:
AutoGCRooter * const down;

Просмотреть файл

@ -3244,7 +3244,7 @@ GCRuntime::triggerGC(JS::gcreason::Reason reason)
if (JS::CurrentThreadIsHeapCollecting())
return false;
JS::PrepareForFullGC(rt->activeContextFromOwnThread());
JS::PrepareForFullGC(rt->mainContextFromOwnThread());
requestMajorGC(reason);
return true;
}
@ -3341,7 +3341,7 @@ GCRuntime::maybeGC(Zone* zone)
#ifdef JS_GC_ZEAL
if (hasZealMode(ZealMode::Alloc) || hasZealMode(ZealMode::RootsChange)) {
JS::PrepareForFullGC(rt->activeContextFromOwnThread());
JS::PrepareForFullGC(rt->mainContextFromOwnThread());
gc(GC_NORMAL, JS::gcreason::DEBUG_GC);
return;
}
@ -3966,11 +3966,10 @@ GCRuntime::purgeRuntime()
zone->functionToStringCache().purge();
}
for (const CooperatingContext& target : rt->cooperatingContexts()) {
freeUnusedLifoBlocksAfterSweeping(&target.context()->tempLifoAlloc());
target.context()->interpreterStack().purge(rt);
target.context()->frontendCollectionPool().purge();
}
JSContext* cx = rt->mainContextFromOwnThread();
freeUnusedLifoBlocksAfterSweeping(&cx->tempLifoAlloc());
cx->interpreterStack().purge(rt);
cx->frontendCollectionPool().purge();
rt->caches().purge();
@ -7020,8 +7019,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
MOZ_FALLTHROUGH;
case State::Mark:
for (const CooperatingContext& target : rt->cooperatingContexts())
AutoGCRooter::traceAllWrappers(target, &marker);
AutoGCRooter::traceAllWrappers(rt->mainContextFromOwnThread(), &marker);
/* If we needed delayed marking for gray roots, then collect until done. */
if (isIncremental && !hasValidGrayRootsBuffer()) {
@ -7468,7 +7466,7 @@ GCRuntime::maybeDoCycleCollection()
}
double grayFraction = double(compartmentsGray) / double(compartmentsTotal);
if (grayFraction > ExcessiveGrayCompartments || compartmentsGray > LimitGrayCompartments)
callDoCycleCollectionCallback(rt->activeContextFromOwnThread());
callDoCycleCollectionCallback(rt->mainContextFromOwnThread());
}
void
@ -7556,7 +7554,7 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R
repeat = true;
} else if (rootsRemoved && IsShutdownGC(reason)) {
/* Need to re-schedule all zones for GC. */
JS::PrepareForFullGC(rt->activeContextFromOwnThread());
JS::PrepareForFullGC(rt->mainContextFromOwnThread());
repeat = true;
reason = JS::gcreason::ROOTS_REMOVED;
} else if (shouldRepeatForDeadZone(reason)) {
@ -7672,7 +7670,7 @@ GCRuntime::startDebugGC(JSGCInvocationKind gckind, SliceBudget& budget)
{
MOZ_ASSERT(!isIncrementalGCInProgress());
if (!ZonesSelected(rt))
JS::PrepareForFullGC(rt->activeContextFromOwnThread());
JS::PrepareForFullGC(rt->mainContextFromOwnThread());
invocationKind = gckind;
collect(false, budget, JS::gcreason::DEBUG_GC);
}
@ -7682,7 +7680,7 @@ GCRuntime::debugGCSlice(SliceBudget& budget)
{
MOZ_ASSERT(isIncrementalGCInProgress());
if (!ZonesSelected(rt))
JS::PrepareForIncrementalGC(rt->activeContextFromOwnThread());
JS::PrepareForIncrementalGC(rt->mainContextFromOwnThread());
collect(false, budget, JS::gcreason::DEBUG_GC);
}
@ -7691,7 +7689,7 @@ void
js::PrepareForDebugGC(JSRuntime* rt)
{
if (!ZonesSelected(rt))
JS::PrepareForFullGC(rt->activeContextFromOwnThread());
JS::PrepareForFullGC(rt->mainContextFromOwnThread());
}
void
@ -7864,10 +7862,7 @@ js::NewCompartment(JSContext* cx, JSPrincipals* principals,
break;
}
if (group) {
// Take over ownership of the group while we create the compartment/zone.
group->enter(cx);
} else {
if (!group) {
MOZ_ASSERT(!zone);
group = cx->new_<ZoneGroup>(rt);
if (!group)
@ -7937,13 +7932,11 @@ js::NewCompartment(JSContext* cx, JSPrincipals* principals,
if (zoneSpec == JS::SystemZone || zoneSpec == JS::NewZoneInSystemZoneGroup) {
MOZ_RELEASE_ASSERT(!rt->gc.systemZoneGroup);
rt->gc.systemZoneGroup = group;
group->setUseExclusiveLocking();
}
}
zoneHolder.forget();
groupHolder.forget();
group->leave();
return compartment.forget();
}
@ -7969,7 +7962,7 @@ GCRuntime::mergeCompartments(JSCompartment* source, JSCompartment* target)
MOZ_ASSERT(source->zone()->compartments().length() == 1);
MOZ_ASSERT(source->zone()->group()->zones().length() == 1);
JSContext* cx = rt->activeContextFromOwnThread();
JSContext* cx = rt->mainContextFromOwnThread();
MOZ_ASSERT(!source->zone()->wasGCStarted());
JS::AutoAssertNoGC nogc(cx);
@ -8232,7 +8225,6 @@ js::ReleaseAllJITCode(FreeOp* fop)
{
js::CancelOffThreadIonCompile(fop->runtime());
JSRuntime::AutoProhibitActiveContextChange apacc(fop->runtime());
for (ZonesIter zone(fop->runtime(), SkipAtoms); !zone.done(); zone.next()) {
zone->setPreservingCode(false);
zone->discardJitCode(fop);

Просмотреть файл

@ -747,7 +747,7 @@ js::Nursery::collect(JS::gcreason::Reason reason)
for (auto& entry : tenureCounts.entries) {
if (entry.count >= 3000) {
ObjectGroup* group = entry.group;
if (group->canPreTenure() && group->zone()->group()->canEnterWithoutYielding(cx)) {
if (group->canPreTenure()) {
AutoCompartment ac(cx, group);
group->setShouldPreTenure(cx);
pretenureCount++;
@ -757,7 +757,6 @@ js::Nursery::collect(JS::gcreason::Reason reason)
}
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);

Просмотреть файл

@ -80,9 +80,9 @@ JS::RootingContext::traceStackRoots(JSTracer* trc)
}
static void
TraceExactStackRoots(const CooperatingContext& target, JSTracer* trc)
TraceExactStackRoots(JSContext* cx, JSTracer* trc)
{
target.context()->traceStackRoots(trc);
cx->traceStackRoots(trc);
}
template <typename T, TraceFunction<T> TraceFn = TraceNullableRoot>
@ -196,16 +196,16 @@ AutoGCRooter::trace(JSTracer* trc)
}
/* static */ void
AutoGCRooter::traceAll(const CooperatingContext& target, JSTracer* trc)
AutoGCRooter::traceAll(JSContext* cx, JSTracer* trc)
{
for (AutoGCRooter* gcr = target.context()->autoGCRooters_; gcr; gcr = gcr->down)
for (AutoGCRooter* gcr = cx->autoGCRooters_; gcr; gcr = gcr->down)
gcr->trace(trc);
}
/* static */ void
AutoGCRooter::traceAllWrappers(const CooperatingContext& target, JSTracer* trc)
AutoGCRooter::traceAllWrappers(JSContext* cx, JSTracer* trc)
{
for (AutoGCRooter* gcr = target.context()->autoGCRooters_; gcr; gcr = gcr->down) {
for (AutoGCRooter* gcr = cx->autoGCRooters_; gcr; gcr = gcr->down) {
if (gcr->tag_ == WRAPVECTOR || gcr->tag_ == WRAPPER)
gcr->trace(trc);
}
@ -319,18 +319,17 @@ js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrM
{
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_STACK);
JSContext* cx = TlsContext.get();
for (const CooperatingContext& target : rt->cooperatingContexts()) {
// Trace active interpreter and JIT stack roots.
TraceInterpreterActivations(cx, target, trc);
jit::TraceJitActivations(cx, target, trc);
JSContext* cx = rt->mainContextFromOwnThread();
// Trace legacy C stack roots.
AutoGCRooter::traceAll(target, trc);
// Trace active interpreter and JIT stack roots.
TraceInterpreterActivations(cx, trc);
jit::TraceJitActivations(cx, trc);
// Trace C stack roots.
TraceExactStackRoots(target, trc);
}
// Trace legacy C stack roots.
AutoGCRooter::traceAll(cx, trc);
// Trace C stack roots.
TraceExactStackRoots(cx, trc);
for (RootRange r = rootsHash.ref().all(); !r.empty(); r.popFront()) {
const RootEntry& entry = r.front();
@ -347,9 +346,8 @@ js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrM
// Trace the shared Intl data.
rt->traceSharedIntlData(trc);
// Trace anything in any of the cooperating threads.
for (const CooperatingContext& target : rt->cooperatingContexts())
target.context()->trace(trc);
// Trace the JSContext.
rt->mainContextFromOwnThread()->trace(trc);
// Trace all compartment roots, but not the compartment itself; it is
// traced via the parent pointer if traceRoots actually traces anything.

Просмотреть файл

@ -181,8 +181,7 @@ gc::GCRuntime::startVerifyPreBarriers()
if (IsIncrementalGCUnsafe(rt) != AbortReason::None ||
TlsContext.get()->keepAtoms ||
rt->hasHelperThreadZones() ||
rt->cooperatingContexts().length() != 1)
rt->hasHelperThreadZones())
{
return;
}
@ -334,7 +333,7 @@ gc::GCRuntime::endVerifyPreBarriers()
MOZ_ASSERT(!JS::IsGenerationalGCEnabled(rt));
AutoPrepareForTracing prep(rt->activeContextFromOwnThread());
AutoPrepareForTracing prep(rt->mainContextFromOwnThread());
bool compartmentCreated = false;

Просмотреть файл

@ -17,8 +17,7 @@ namespace js {
ZoneGroup::ZoneGroup(JSRuntime* runtime)
: runtime(runtime),
ownerContext_(TlsContext.get()),
enterCount(1),
helperThreadOwnerContext_(nullptr),
zones_(this),
helperThreadUse(HelperThreadUse::None),
#ifdef DEBUG
@ -60,51 +59,18 @@ ZoneGroup::~ZoneGroup()
}
void
ZoneGroup::enter(JSContext* cx)
ZoneGroup::setHelperThreadOwnerContext(JSContext* cx)
{
if (ownerContext().context() == cx) {
MOZ_ASSERT(enterCount);
} else {
if (useExclusiveLocking()) {
MOZ_ASSERT(!usedByHelperThread());
while (ownerContext().context() != nullptr) {
cx->yieldToEmbedding();
}
}
MOZ_RELEASE_ASSERT(ownerContext().context() == nullptr);
MOZ_ASSERT(enterCount == 0);
ownerContext_ = CooperatingContext(cx);
if (cx->generationalDisabled)
nursery().disable();
// Finish any Ion compilations in this zone group, in case compilation
// finished for some script in this group while no thread was in this
// group.
jit::AttachFinishedCompilations(this, nullptr);
}
enterCount++;
}
void
ZoneGroup::leave()
{
MOZ_ASSERT(ownedByCurrentThread());
MOZ_ASSERT(enterCount);
if (--enterCount == 0)
ownerContext_ = CooperatingContext(nullptr);
MOZ_ASSERT_IF(cx, TlsContext.get() == cx);
helperThreadOwnerContext_ = cx;
}
bool
ZoneGroup::canEnterWithoutYielding(JSContext* cx)
{
return ownerContext().context() == cx || ownerContext().context() == nullptr;
}
bool
ZoneGroup::ownedByCurrentThread()
ZoneGroup::ownedByCurrentHelperThread()
{
MOZ_ASSERT(usedByHelperThread());
MOZ_ASSERT(TlsContext.get());
return ownerContext().context() == TlsContext.get();
return helperThreadOwnerContext_ == TlsContext.get();
}
ZoneGroup::IonBuilderList&
@ -156,26 +122,3 @@ ZoneGroup::deleteEmptyZone(Zone* zone)
}
} // namespace js
JS::AutoRelinquishZoneGroups::AutoRelinquishZoneGroups(JSContext* cx)
: cx(cx)
{
MOZ_ASSERT(cx == TlsContext.get());
AutoEnterOOMUnsafeRegion oomUnsafe;
for (ZoneGroupsIter group(cx->runtime()); !group.done(); group.next()) {
while (group->ownerContext().context() == cx) {
group->leave();
if (!enterList.append(group))
oomUnsafe.crash("AutoRelinquishZoneGroups");
}
}
}
JS::AutoRelinquishZoneGroups::~AutoRelinquishZoneGroups()
{
for (size_t i = 0; i < enterList.length(); i++) {
ZoneGroup* group = static_cast<ZoneGroup*>(enterList[i]);
group->enter(cx);
}
}

Просмотреть файл

@ -33,24 +33,13 @@ class ZoneGroup
JSRuntime* const runtime;
private:
// The context with exclusive access to this zone group.
UnprotectedData<CooperatingContext> ownerContext_;
// The number of times the context has entered this zone group.
UnprotectedData<size_t> enterCount;
// If this flag is true, then we may need to block before entering this zone
// group. Blocking happens using JSContext::yieldToEmbedding.
UnprotectedData<bool> useExclusiveLocking_;
// The helper thread context with exclusive access to this zone group, if
// usedByHelperThread(), or nullptr when on the main thread.
UnprotectedData<JSContext*> helperThreadOwnerContext_;
public:
CooperatingContext& ownerContext() { return ownerContext_.ref(); }
void* addressOfOwnerContext() { return &ownerContext_.ref().cx; }
void enter(JSContext* cx);
void leave();
bool canEnterWithoutYielding(JSContext* cx);
bool ownedByCurrentThread();
bool ownedByCurrentHelperThread();
void setHelperThreadOwnerContext(JSContext* cx);
// All zones in the group.
private:
@ -101,10 +90,6 @@ class ZoneGroup
inline bool isCollecting();
inline bool isGCScheduled();
// See the useExclusiveLocking_ field above.
void setUseExclusiveLocking() { useExclusiveLocking_ = true; }
bool useExclusiveLocking() { return useExclusiveLocking_; }
// Delete an empty zone after its contents have been merged.
void deleteEmptyZone(Zone* zone);

Просмотреть файл

@ -167,9 +167,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only)
// avoid failing repeatedly when the regex code is called from Ion JIT code,
// see bug 1208819.
Label stack_ok;
void* context_addr = cx->zone()->group()->addressOfOwnerContext();
masm.loadPtr(AbsoluteAddress(context_addr), temp0);
Address limit_addr(temp0, offsetof(JSContext, jitStackLimitNoInterrupt));
AbsoluteAddress limit_addr(cx->addressOfJitStackLimitNoInterrupt());
masm.branchStackPtrRhs(Assembler::Below, limit_addr, &stack_ok);
// Exit with an exception. There is not enough space on the stack
@ -284,9 +282,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only)
}
// Initialize backtrack stack pointer.
size_t baseOffset = offsetof(JSContext, regexpStack) + RegExpStack::offsetOfBase();
masm.loadPtr(AbsoluteAddress(context_addr), backtrack_stack_pointer);
masm.loadPtr(Address(backtrack_stack_pointer, baseOffset), backtrack_stack_pointer);
masm.loadPtr(AbsoluteAddress(cx->regexpStack.ref().addressOfBase()), backtrack_stack_pointer);
masm.storePtr(backtrack_stack_pointer,
Address(masm.getStackPointer(), offsetof(FrameData, backtrackStackBase)));
@ -491,10 +487,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only)
Address backtrackStackBaseAddress(temp2, offsetof(FrameData, backtrackStackBase));
masm.subPtr(backtrackStackBaseAddress, backtrack_stack_pointer);
void* context_addr = cx->zone()->group()->addressOfOwnerContext();
size_t baseOffset = offsetof(JSContext, regexpStack) + RegExpStack::offsetOfBase();
masm.loadPtr(AbsoluteAddress(context_addr), temp1);
masm.loadPtr(Address(temp1, baseOffset), temp1);
masm.loadPtr(AbsoluteAddress(cx->regexpStack.ref().addressOfBase()), temp1);
masm.storePtr(temp1, backtrackStackBaseAddress);
masm.addPtr(temp1, backtrack_stack_pointer);
@ -575,10 +568,8 @@ NativeRegExpMacroAssembler::Backtrack()
// Check for an interrupt.
Label noInterrupt;
void* contextAddr = cx->zone()->group()->addressOfOwnerContext();
masm.loadPtr(AbsoluteAddress(contextAddr), temp0);
masm.branch32(Assembler::Equal,
Address(temp0, offsetof(JSContext, interruptRegExpJit_)),
AbsoluteAddress(cx->addressOfInterruptRegExpJit()),
Imm32(0),
&noInterrupt);
masm.movePtr(ImmWord(RegExpRunStatus_Error), temp0);
@ -1145,11 +1136,10 @@ NativeRegExpMacroAssembler::CheckBacktrackStackLimit()
JitSpew(SPEW_PREFIX "CheckBacktrackStackLimit");
Label no_stack_overflow;
void* context_addr = cx->zone()->group()->addressOfOwnerContext();
size_t limitOffset = offsetof(JSContext, regexpStack) + RegExpStack::offsetOfLimit();
masm.loadPtr(AbsoluteAddress(context_addr), temp1);
masm.branchPtr(Assembler::AboveOrEqual, Address(temp1, limitOffset),
backtrack_stack_pointer, &no_stack_overflow);
masm.branchPtr(Assembler::AboveOrEqual,
AbsoluteAddress(cx->regexpStack.ref().addressOfLimit()),
backtrack_stack_pointer,
&no_stack_overflow);
// Copy the stack pointer before the call() instruction modifies it.
masm.moveStackPtrTo(temp2);

Просмотреть файл

@ -82,6 +82,9 @@ class RegExpStack
static size_t offsetOfBase() { return offsetof(RegExpStack, base_); }
static size_t offsetOfLimit() { return offsetof(RegExpStack, limit_); }
void* addressOfBase() { return &base_; }
void* addressOfLimit() { return &limit_; }
void* base() { return base_; }
void* limit() { return limit_; }

Просмотреть файл

@ -553,10 +553,8 @@ BaselineCompiler::emitStackCheck(bool earlyCheck)
&forceCall);
}
void* contextAddr = cx->zone()->group()->addressOfOwnerContext();
masm.loadPtr(AbsoluteAddress(contextAddr), R0.scratchReg());
masm.branchPtr(Assembler::BelowOrEqual,
Address(R0.scratchReg(), offsetof(JSContext, jitStackLimit)), R1.scratchReg(),
AbsoluteAddress(cx->addressOfJitStackLimit()), R1.scratchReg(),
&skipCall);
if (!earlyCheck && needsEarlyStackCheck())
@ -702,10 +700,8 @@ BaselineCompiler::emitInterruptCheck()
frame.syncStack(0);
Label done;
void* context = cx->zone()->group()->addressOfOwnerContext();
masm.loadPtr(AbsoluteAddress(context), R0.scratchReg());
masm.branch32(Assembler::Equal,
Address(R0.scratchReg(), offsetof(JSContext, interrupt_)), Imm32(0),
AbsoluteAddress(cx->addressOfInterrupt()), Imm32(0),
&done);
prepareVMCall();

Просмотреть файл

@ -344,7 +344,7 @@ SpewPatchStubFrame(ICStub* oldStub, ICStub* newStub)
}
static void
PatchBaselineFramesForDebugMode(JSContext* cx, const CooperatingContext& target,
PatchBaselineFramesForDebugMode(JSContext* cx,
const Debugger::ExecutionObservableSet& obs,
const ActivationIterator& activation,
DebugModeOSREntryVector& entries, size_t* start)
@ -420,7 +420,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const CooperatingContext& target,
uint8_t* retAddr = bl->returnAddressForIC(bl->icEntryFromPCOffset(pcOffset));
SpewPatchBaselineFrame(prev->returnAddress(), retAddr, script, kind, pc);
DebugModeOSRVolatileJitFrameIter::forwardLiveIterators(
target, prev->returnAddress(), retAddr);
cx, prev->returnAddress(), retAddr);
prev->setReturnAddress(retAddr);
entryIndex++;
break;
@ -449,7 +449,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const CooperatingContext& target,
SpewPatchBaselineFrameFromExceptionHandler(prev->returnAddress(), retAddr,
script, pc);
DebugModeOSRVolatileJitFrameIter::forwardLiveIterators(
target, prev->returnAddress(), retAddr);
cx, prev->returnAddress(), retAddr);
prev->setReturnAddress(retAddr);
entryIndex++;
break;
@ -850,15 +850,13 @@ jit::RecompileOnStackBaselineScriptsForDebugMode(JSContext* cx,
// frames.
Vector<DebugModeOSREntry> entries(cx);
for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
for (ActivationIterator iter(cx, target); !iter.done(); ++iter) {
if (iter->isJit()) {
if (!CollectJitStackScripts(cx, obs, iter, entries))
return false;
} else if (iter->isInterpreter()) {
if (!CollectInterpreterStackScripts(cx, obs, iter, entries))
return false;
}
for (ActivationIterator iter(cx); !iter.done(); ++iter) {
if (iter->isJit()) {
if (!CollectJitStackScripts(cx, obs, iter, entries))
return false;
} else if (iter->isInterpreter()) {
if (!CollectInterpreterStackScripts(cx, obs, iter, entries))
return false;
}
}
@ -907,13 +905,11 @@ jit::RecompileOnStackBaselineScriptsForDebugMode(JSContext* cx,
}
size_t processed = 0;
for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
for (ActivationIterator iter(cx, target); !iter.done(); ++iter) {
if (iter->isJit())
PatchBaselineFramesForDebugMode(cx, target, obs, iter, entries, &processed);
else if (iter->isInterpreter())
SkipInterpreterFrameEntries(obs, iter, &processed);
}
for (ActivationIterator iter(cx); !iter.done(); ++iter) {
if (iter->isJit())
PatchBaselineFramesForDebugMode(cx, obs, iter, entries, &processed);
else if (iter->isInterpreter())
SkipInterpreterFrameEntries(obs, iter, &processed);
}
MOZ_ASSERT(processed == entries.length());
@ -1182,10 +1178,10 @@ JitRuntime::generateBaselineDebugModeOSRHandler(JSContext* cx, uint32_t* noFrame
}
/* static */ void
DebugModeOSRVolatileJitFrameIter::forwardLiveIterators(const CooperatingContext& cx,
DebugModeOSRVolatileJitFrameIter::forwardLiveIterators(JSContext* cx,
uint8_t* oldAddr, uint8_t* newAddr)
{
DebugModeOSRVolatileJitFrameIter* iter;
for (iter = cx.context()->liveVolatileJitFrameIter_; iter; iter = iter->prev)
for (iter = cx->liveVolatileJitFrameIter_; iter; iter = iter->prev)
iter->asJSJit().exchangeReturnAddressIfMatch(oldAddr, newAddr);
}

Просмотреть файл

@ -105,7 +105,7 @@ class DebugModeOSRVolatileJitFrameIter : public JitFrameIter
*stack = prev;
}
static void forwardLiveIterators(const CooperatingContext& target,
static void forwardLiveIterators(JSContext* cx,
uint8_t* oldAddr, uint8_t* newAddr);
};

Просмотреть файл

@ -1218,10 +1218,8 @@ jit::MarkActiveBaselineScripts(Zone* zone)
if (zone->isAtomsZone())
return;
JSContext* cx = TlsContext.get();
for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
for (JitActivationIterator iter(cx, target); !iter.done(); ++iter) {
if (iter->compartment()->zone() == zone)
MarkActiveBaselineScripts(cx, iter);
}
for (JitActivationIterator iter(cx); !iter.done(); ++iter) {
if (iter->compartment()->zone() == zone)
MarkActiveBaselineScripts(cx, iter);
}
}

Просмотреть файл

@ -5262,13 +5262,9 @@ CodeGenerator::visitCheckOverRecursed(LCheckOverRecursed* lir)
CheckOverRecursedFailure* ool = new(alloc()) CheckOverRecursedFailure(lir);
addOutOfLineCode(ool, lir->mir());
Register temp = ToRegister(lir->temp());
// Conditional forward (unlikely) branch to failure.
const void* contextAddr = gen->compartment->zone()->addressOfJSContext();
masm.loadPtr(AbsoluteAddress(contextAddr), temp);
masm.branchStackPtrRhs(Assembler::AboveOrEqual,
Address(temp, offsetof(JSContext, jitStackLimit)), ool->entry());
const void* limitAddr = gen->runtime->addressOfJitStackLimit();
masm.branchStackPtrRhs(Assembler::AboveOrEqual, AbsoluteAddress(limitAddr), ool->entry());
masm.bind(ool->rejoin());
}
@ -12917,12 +12913,8 @@ CodeGenerator::visitInterruptCheck(LInterruptCheck* lir)
OutOfLineCode* ool = oolCallVM(InterruptCheckInfo, lir, ArgList(), StoreNothing());
Register temp = ToRegister(lir->temp());
const void* contextAddr = gen->compartment->zone()->addressOfJSContext();
masm.loadPtr(AbsoluteAddress(contextAddr), temp);
masm.branch32(Assembler::NotEqual, Address(temp, offsetof(JSContext, interrupt_)),
Imm32(0), ool->entry());
const void* interruptAddr = gen->runtime->addressOfInterrupt();
masm.branch32(Assembler::NotEqual, AbsoluteAddress(interruptAddr), Imm32(0), ool->entry());
masm.bind(ool->rejoin());
}

Просмотреть файл

@ -102,9 +102,21 @@ CompileRuntime::wellKnownSymbols()
}
const void*
CompileRuntime::addressOfActiveJSContext()
CompileRuntime::mainContextPtr()
{
return runtime()->addressOfActiveContext();
return runtime()->mainContextFromAnyThread();
}
const void*
CompileRuntime::addressOfJitStackLimit()
{
return runtime()->mainContextFromAnyThread()->addressOfJitStackLimit();
}
const void*
CompileRuntime::addressOfInterrupt()
{
return runtime()->mainContextFromAnyThread()->addressOfInterrupt();
}
#ifdef DEBUG
@ -159,12 +171,6 @@ CompileZone::addressOfIonBailAfter()
}
#endif
const void*
CompileZone::addressOfJSContext()
{
return zone()->group()->addressOfOwnerContext();
}
const void*
CompileZone::addressOfNeedsIncrementalBarrier()
{

Просмотреть файл

@ -46,7 +46,10 @@ class CompileRuntime
const Value& NaNValue();
const Value& positiveInfinityValue();
const WellKnownSymbols& wellKnownSymbols();
const void* addressOfActiveJSContext();
const void* mainContextPtr();
const void* addressOfJitStackLimit();
const void* addressOfInterrupt();
#ifdef DEBUG
bool isInsideNursery(gc::Cell* cell);
@ -72,7 +75,6 @@ class CompileZone
const void* addressOfIonBailAfter();
#endif
const void* addressOfJSContext();
const void* addressOfNeedsIncrementalBarrier();
const void* addressOfFreeList(gc::AllocKind allocKind);
const void* addressOfNurseryPosition();

Просмотреть файл

@ -305,7 +305,7 @@ ExecutableAllocator::reprotectPool(JSRuntime* rt, ExecutablePool* pool, Protecti
{
// Don't race with reprotectAll called from the signal handler.
MOZ_ASSERT(rt->jitRuntime()->preventBackedgePatching() ||
rt->activeContext()->handlingJitInterrupt());
rt->mainContextFromAnyThread()->handlingJitInterrupt());
char* start = pool->m_allocation.pages;
if (!ReprotectRegion(start, pool->m_freePtr - start, protection))

Просмотреть файл

@ -2944,12 +2944,10 @@ jit::InvalidateAll(FreeOp* fop, Zone* zone)
if (zone->isAtomsZone())
return;
JSContext* cx = TlsContext.get();
for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
for (JitActivationIterator iter(cx, target); !iter.done(); ++iter) {
if (iter->compartment()->zone() == zone) {
JitSpew(JitSpew_IonInvalidate, "Invalidating all frames for GC");
InvalidateActivation(fop, iter, true);
}
for (JitActivationIterator iter(cx); !iter.done(); ++iter) {
if (iter->compartment()->zone() == zone) {
JitSpew(JitSpew_IonInvalidate, "Invalidating all frames for GC");
InvalidateActivation(fop, iter, true);
}
}
}
@ -2992,18 +2990,9 @@ jit::Invalidate(TypeZone& types, FreeOp* fop,
return;
}
// This method can be called both during GC and during the course of normal
// script execution. In the former case this class will already be on the
// stack, and in the latter case the invalidations will all be on the
// current thread's stack, but the assertion under ActivationIterator can't
// tell that this is a thread local use of the iterator.
JSRuntime::AutoProhibitActiveContextChange apacc(fop->runtime());
JSContext* cx = TlsContext.get();
for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
for (JitActivationIterator iter(cx, target); !iter.done(); ++iter)
InvalidateActivation(fop, iter, false);
}
for (JitActivationIterator iter(cx); !iter.done(); ++iter)
InvalidateActivation(fop, iter, false);
// Drop the references added above. If a script was never active, its
// IonScript will be immediately destroyed. Otherwise, it will be held live
@ -3355,9 +3344,8 @@ jit::JitSupportsAtomics()
static void
RedirectIonBackedgesToInterruptCheck(JSContext* cx)
{
// Jitcode may only be modified on the runtime's active thread.
if (cx != cx->runtime()->activeContext())
return;
// Jitcode may only be modified on the runtime's main thread.
MOZ_ASSERT(cx == cx->runtime()->mainContextFromAnyThread());
// The faulting thread is suspended so we can access cx fields that can
// normally only be accessed by the cx's active thread.

Просмотреть файл

@ -1301,9 +1301,9 @@ TraceJitActivation(JSTracer* trc, JitActivation* activation)
}
void
TraceJitActivations(JSContext* cx, const CooperatingContext& target, JSTracer* trc)
TraceJitActivations(JSContext* cx, JSTracer* trc)
{
for (JitActivationIterator activations(cx, target); !activations.done(); ++activations)
for (JitActivationIterator activations(cx); !activations.done(); ++activations)
TraceJitActivation(trc, activations->asJit());
}
@ -1312,12 +1312,10 @@ UpdateJitActivationsForMinorGC(JSRuntime* rt)
{
MOZ_ASSERT(JS::CurrentThreadIsHeapMinorCollecting());
JSContext* cx = TlsContext.get();
for (const CooperatingContext& target : rt->cooperatingContexts()) {
for (JitActivationIterator activations(cx, target); !activations.done(); ++activations) {
for (OnlyJSJitFrameIter iter(activations); !iter.done(); ++iter) {
if (iter.frame().type() == JitFrame_IonJS)
UpdateIonJSFrameForMinorGC(iter.frame());
}
for (JitActivationIterator activations(cx); !activations.done(); ++activations) {
for (OnlyJSJitFrameIter iter(activations); !iter.done(); ++iter) {
if (iter.frame().type() == JitFrame_IonJS)
UpdateIonJSFrameForMinorGC(iter.frame());
}
}
}

Просмотреть файл

@ -285,7 +285,7 @@ void HandleException(ResumeFromException* rfe);
void EnsureBareExitFrame(JitActivation* act, JitFrameLayout* frame);
void TraceJitActivations(JSContext* cx, const CooperatingContext& target, JSTracer* trc);
void TraceJitActivations(JSContext* cx, JSTracer* trc);
void UpdateJitActivationsForMinorGC(JSRuntime* rt);

Просмотреть файл

@ -184,7 +184,7 @@ LIRGenerator::visitTableSwitch(MTableSwitch* tableswitch)
void
LIRGenerator::visitCheckOverRecursed(MCheckOverRecursed* ins)
{
LCheckOverRecursed* lir = new(alloc()) LCheckOverRecursed(temp());
LCheckOverRecursed* lir = new(alloc()) LCheckOverRecursed();
add(lir, ins);
assignSafepoint(lir, ins);
}
@ -2733,7 +2733,7 @@ LIRGenerator::visitHomeObjectSuperBase(MHomeObjectSuperBase* ins)
void
LIRGenerator::visitInterruptCheck(MInterruptCheck* ins)
{
LInstruction* lir = new(alloc()) LInterruptCheck(temp());
LInstruction* lir = new(alloc()) LInterruptCheck();
add(lir, ins);
assignSafepoint(lir, ins);
}

Просмотреть файл

@ -1778,19 +1778,7 @@ void
MacroAssembler::loadJSContext(Register dest)
{
JitContext* jcx = GetJitContext();
CompileCompartment* compartment = jcx->compartment;
if (compartment->zone()->isAtomsZone()) {
// If we are in the atoms zone then we are generating a runtime wide
// trampoline which can run in any zone. Load the context which is
// currently running using cooperative scheduling in the runtime.
// (This will need to be fixed when we have preemptive scheduling,
// bug 1323066).
loadPtr(AbsoluteAddress(jcx->runtime->addressOfActiveJSContext()), dest);
} else {
// If we are in a specific zone then the current context will be stored
// in the containing zone group.
loadPtr(AbsoluteAddress(compartment->zone()->addressOfJSContext()), dest);
}
movePtr(ImmPtr(jcx->runtime->mainContextPtr()), dest);
}
void

Просмотреть файл

@ -2118,6 +2118,18 @@ MacroAssemblerCompat::branchStackPtrRhs(Condition cond, Address lhs, Label* labe
B(label, Assembler::InvertCondition(cond));
}
void
MacroAssemblerCompat::branchStackPtrRhs(Condition cond, AbsoluteAddress lhs, Label* label)
{
vixl::UseScratchRegisterScope temps(this);
const ARMRegister scratch = temps.AcquireX();
movePtr(ImmPtr(lhs.addr), scratch.asUnsized());
// Cmp disallows SP as the rhs, so flip the operands and invert the
// condition.
Cmp(GetStackPointer64(), scratch);
B(label, Assembler::InvertCondition(cond));
}
// If source is a double, load into dest.
// If source is int32, convert to double and store in dest.
// Else, branch to failure.

Просмотреть файл

@ -986,6 +986,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
inline void branchTestStackPtr(Condition cond, Imm32 rhs, Label* label);
inline void branchStackPtr(Condition cond, Register rhs, Label* label);
inline void branchStackPtrRhs(Condition cond, Address lhs, Label* label);
inline void branchStackPtrRhs(Condition cond, AbsoluteAddress lhs, Label* label);
void testPtr(Register lhs, Register rhs) {
Tst(ARMRegister(lhs, 64), Operand(ARMRegister(rhs, 64)));

Просмотреть файл

@ -1481,20 +1481,14 @@ class LInitPropGetterSetter : public LCallInstructionHelper<0, 2, 0>
}
};
class LCheckOverRecursed : public LInstructionHelper<0, 0, 1>
class LCheckOverRecursed : public LInstructionHelper<0, 0, 0>
{
public:
LIR_HEADER(CheckOverRecursed)
explicit LCheckOverRecursed(const LDefinition& temp)
LCheckOverRecursed()
: LInstructionHelper(classOpcode)
{
setTemp(0, temp);
}
const LDefinition* temp() {
return getTemp(0);
}
{}
MCheckOverRecursed* mir() const {
return mir_->toCheckOverRecursed();
@ -1617,7 +1611,7 @@ class LRotateI64 : public details::RotateBase<INT64_PIECES, INT64_PIECES + 1, 1>
LAllocation* count() { return getOperand(Count); }
};
class LInterruptCheck : public LInstructionHelper<0, 0, 1>
class LInterruptCheck : public LInstructionHelper<0, 0, 0>
{
Label* oolEntry_;
@ -1629,13 +1623,11 @@ class LInterruptCheck : public LInstructionHelper<0, 0, 1>
public:
LIR_HEADER(InterruptCheck)
explicit LInterruptCheck(const LDefinition& temp)
LInterruptCheck()
: LInstructionHelper(classOpcode),
oolEntry_(nullptr),
implicit_(false)
{
setTemp(0, temp);
}
{}
Label* oolEntry() {
MOZ_ASSERT(implicit_);
@ -1652,15 +1644,10 @@ class LInterruptCheck : public LInstructionHelper<0, 0, 1>
void setImplicit() {
implicit_ = true;
setTemp(0, LDefinition::BogusTemp());
}
bool implicit() const {
return implicit_;
}
const LDefinition* temp() {
return getTemp(0);
}
};
class LWasmInterruptCheck : public LInstructionHelper<0, 1, 0>

Просмотреть файл

@ -486,21 +486,18 @@ JS_PUBLIC_API(JSContext*)
JS_NewCooperativeContext(JSContext* siblingContext)
{
MOZ_CRASH("Cooperative scheduling is unsupported");
return NewCooperativeContext(siblingContext);
}
JS_PUBLIC_API(void)
JS_YieldCooperativeContext(JSContext* cx)
{
MOZ_CRASH("Cooperative scheduling is unsupported");
YieldCooperativeContext(cx);
}
JS_PUBLIC_API(void)
JS_ResumeCooperativeContext(JSContext* cx)
{
MOZ_CRASH("Cooperative scheduling is unsupported");
ResumeCooperativeContext(cx);
}
JS_PUBLIC_API(void)
@ -582,15 +579,6 @@ JS_GetRuntime(JSContext* cx)
return cx->runtime();
}
JS_PUBLIC_API(void)
JS::SetSingleThreadedExecutionCallbacks(JSContext* cx,
BeginSingleThreadedExecutionCallback begin,
EndSingleThreadedExecutionCallback end)
{
cx->runtime()->beginSingleThreadedExecutionCallback = begin;
cx->runtime()->endSingleThreadedExecutionCallback = end;
}
JS_PUBLIC_API(JS::ContextOptions&)
JS::ContextOptionsRef(JSContext* cx)
{

Просмотреть файл

@ -865,23 +865,6 @@ JS_ResumeCooperativeContext(JSContext* cx);
extern JS_PUBLIC_API(JSContext*)
JS_NewCooperativeContext(JSContext* siblingContext);
namespace JS {
// Class to relinquish exclusive access to all zone groups in use by this
// thread. This allows other cooperative threads to enter the zone groups
// and modify their contents.
struct AutoRelinquishZoneGroups
{
explicit AutoRelinquishZoneGroups(JSContext* cx);
~AutoRelinquishZoneGroups();
private:
JSContext* cx;
mozilla::Vector<void*> enterList;
};
} // namespace JS
// Destroy a context allocated with JS_NewContext or JS_NewCooperativeContext.
// The context must be the current active context in the runtime, and after
// this call the runtime will have no active context.
@ -909,31 +892,6 @@ JS_EndRequest(JSContext* cx);
extern JS_PUBLIC_API(void)
JS_SetFutexCanWait(JSContext* cx);
namespace JS {
// Single threaded execution callbacks are used to notify API clients that a
// feature is in use on a context's runtime that is not yet compatible with
// cooperatively multithreaded execution.
//
// Between a call to BeginSingleThreadedExecutionCallback and a corresponding
// call to EndSingleThreadedExecutionCallback, only one thread at a time may
// enter compartments in the runtime. The begin callback may yield as necessary
// to permit other threads to finish up what they're doing, while the end
// callback may not yield or otherwise operate on the runtime (it may be called
// during GC).
//
// These callbacks may be left unspecified for runtimes which only ever have a
// single context.
typedef void (*BeginSingleThreadedExecutionCallback)(JSContext* cx);
typedef void (*EndSingleThreadedExecutionCallback)(JSContext* cx);
extern JS_PUBLIC_API(void)
SetSingleThreadedExecutionCallbacks(JSContext* cx,
BeginSingleThreadedExecutionCallback begin,
EndSingleThreadedExecutionCallback end);
} // namespace JS
namespace js {
void

Просмотреть файл

@ -1270,7 +1270,7 @@ js::GetAnyCompartmentInZone(JS::Zone* zone)
void
JS::ObjectPtr::finalize(JSRuntime* rt)
{
if (IsIncrementalBarrierNeeded(rt->activeContextFromOwnThread()))
if (IsIncrementalBarrierNeeded(rt->mainContextFromOwnThread()))
IncrementalPreWriteBarrier(value);
value = nullptr;
}
@ -1544,8 +1544,7 @@ js::SetCooperativeYieldCallback(JSContext* cx, YieldCallback callback)
JS_FRIEND_API(bool)
js::SystemZoneAvailable(JSContext* cx)
{
CooperatingContext& owner = cx->runtime()->gc.systemZoneGroup->ownerContext();
return owner.context() == nullptr;
return true;
}
static LogCtorDtor sLogCtor = nullptr;

Просмотреть файл

@ -93,8 +93,6 @@ class AutoTraceSession;
class StoreBuffer;
} // namespace gc
class CooperatingContext;
inline JSCompartment* GetContextCompartment(const JSContext* cx);
inline JS::Zone* GetContextZone(const JSContext* cx);

Просмотреть файл

@ -5464,25 +5464,12 @@ HasCopyOnWriteElements(JSContext* cx, unsigned argc, Value* vp)
return true;
}
// Set the profiling stack for each cooperating context in a runtime.
static bool
EnsureAllContextProfilingStacks(JSContext* cx)
{
for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
ShellContext* sc = GetShellContext(target.context());
if (!EnsureGeckoProfilingStackInstalled(target.context(), sc))
return false;
}
return true;
}
static bool
EnableGeckoProfiling(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (!EnsureAllContextProfilingStacks(cx))
if (!EnsureGeckoProfilingStackInstalled(cx, GetShellContext(cx)))
return false;
cx->runtime()->geckoProfiler().enableSlowAssertions(false);
@ -5509,7 +5496,7 @@ EnableGeckoProfilingWithSlowAssertions(JSContext* cx, unsigned argc, Value* vp)
cx->runtime()->geckoProfiler().enable(false);
}
if (!EnsureAllContextProfilingStacks(cx))
if (!EnsureGeckoProfilingStackInstalled(cx, GetShellContext(cx)))
return false;
cx->runtime()->geckoProfiler().enableSlowAssertions(true);

Просмотреть файл

@ -79,7 +79,7 @@ CheckZoneGroup<Helper>::check() const
JSContext* cx = TlsContext.get();
if (group) {
if (group->usedByHelperThread()) {
MOZ_ASSERT(group->ownedByCurrentThread());
MOZ_ASSERT(group->ownedByCurrentHelperThread());
} else {
// This check is disabled on windows for the same reason as in
// CheckActiveThread.

Просмотреть файл

@ -718,9 +718,9 @@ Debugger::~Debugger()
if (onNewGlobalObjectWatchersLink.mPrev ||
onNewGlobalObjectWatchersLink.mNext ||
cx->runtime()->onNewGlobalObjectWatchers().begin() == JSRuntime::WatchersList::Iterator(this))
{
cx->runtime()->onNewGlobalObjectWatchers().remove(this);
cx->runtime()->endSingleThreadedExecution(cx);
}
}
bool
@ -2611,24 +2611,22 @@ UpdateExecutionObservabilityOfScriptsInZone(JSContext* cx, Zone* zone,
//
// Mark active baseline scripts in the observable set so that they don't
// get discarded. They will be recompiled.
for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
for (JitActivationIterator actIter(cx, target); !actIter.done(); ++actIter) {
if (actIter->compartment()->zone() != zone)
continue;
for (JitActivationIterator actIter(cx); !actIter.done(); ++actIter) {
if (actIter->compartment()->zone() != zone)
continue;
for (OnlyJSJitFrameIter iter(actIter); !iter.done(); ++iter) {
const jit::JSJitFrameIter& frame = iter.frame();
switch (frame.type()) {
case JitFrame_BaselineJS:
MarkBaselineScriptActiveIfObservable(frame.script(), obs);
break;
case JitFrame_IonJS:
MarkBaselineScriptActiveIfObservable(frame.script(), obs);
for (InlineFrameIterator inlineIter(cx, &frame); inlineIter.more(); ++inlineIter)
MarkBaselineScriptActiveIfObservable(inlineIter.script(), obs);
break;
default:;
}
for (OnlyJSJitFrameIter iter(actIter); !iter.done(); ++iter) {
const jit::JSJitFrameIter& frame = iter.frame();
switch (frame.type()) {
case JitFrame_BaselineJS:
MarkBaselineScriptActiveIfObservable(frame.script(), obs);
break;
case JitFrame_IonJS:
MarkBaselineScriptActiveIfObservable(frame.script(), obs);
for (InlineFrameIterator inlineIter(cx, &frame); inlineIter.more(); ++inlineIter)
MarkBaselineScriptActiveIfObservable(inlineIter.script(), obs);
break;
default:;
}
}
}
@ -3939,24 +3937,11 @@ Debugger::construct(JSContext* cx, unsigned argc, Value* vp)
obj->setReservedSlot(slot, proto->getReservedSlot(slot));
obj->setReservedSlot(JSSLOT_DEBUG_MEMORY_INSTANCE, NullValue());
// Debuggers currently require single threaded execution. A debugger may be
// used to debug content in other zone groups, and may be used to observe
// all activity in the runtime via hooks like OnNewGlobalObject.
if (!cx->runtime()->beginSingleThreadedExecution(cx)) {
JS_ReportErrorASCII(cx, "Cannot ensure single threaded execution in Debugger");
return false;
}
Debugger* debugger;
{
/* Construct the underlying C++ object. */
auto dbg = cx->make_unique<Debugger>(cx, obj.get());
if (!dbg) {
JS::AutoSuppressGCAnalysis nogc; // Suppress warning about |dbg|.
cx->runtime()->endSingleThreadedExecution(cx);
return false;
}
if (!dbg->init(cx))
if (!dbg || !dbg->init(cx))
return false;
debugger = dbg.release();

Просмотреть файл

@ -42,7 +42,6 @@ class MOZ_RAII AutoSuppressProfilerSampling
private:
JSContext* cx_;
bool previouslyEnabled_;
JSRuntime::AutoProhibitActiveContextChange prohibitContextChange_;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};

Просмотреть файл

@ -88,13 +88,8 @@ GetTopProfilingJitFrame(Activation* act)
void
GeckoProfilerRuntime::enable(bool enabled)
{
#ifdef DEBUG
// All cooperating contexts must have profile stacks installed before the
// profiler can be enabled. Cooperating threads created while the profiler
// is enabled must have stacks set before they execute any JS.
for (const CooperatingContext& target : rt->cooperatingContexts())
MOZ_ASSERT(target.context()->geckoProfiler().installed());
#endif
JSContext* cx = rt->mainContextFromAnyThread();
MOZ_ASSERT(cx->geckoProfiler().installed());
if (enabled_ == enabled)
return;
@ -112,12 +107,10 @@ GeckoProfilerRuntime::enable(bool enabled)
rt->jitRuntime()->getJitcodeGlobalTable()->setAllEntriesAsExpired();
rt->setProfilerSampleBufferRangeStart(0);
// Ensure that lastProfilingFrame is null for all threads before 'enabled' becomes true.
for (const CooperatingContext& target : rt->cooperatingContexts()) {
if (target.context()->jitActivation) {
target.context()->jitActivation->setLastProfilingFrame(nullptr);
target.context()->jitActivation->setLastProfilingCallSite(nullptr);
}
// Ensure that lastProfilingFrame is null for the main thread.
if (cx->jitActivation) {
cx->jitActivation->setLastProfilingFrame(nullptr);
cx->jitActivation->setLastProfilingCallSite(nullptr);
}
enabled_ = enabled;
@ -132,28 +125,26 @@ GeckoProfilerRuntime::enable(bool enabled)
/* Update lastProfilingFrame to point to the top-most JS jit-frame currently on
* stack.
*/
for (const CooperatingContext& target : rt->cooperatingContexts()) {
if (target.context()->jitActivation) {
// Walk through all activations, and set their lastProfilingFrame appropriately.
if (enabled) {
Activation* act = target.context()->activation();
void* lastProfilingFrame = GetTopProfilingJitFrame(act);
if (cx->jitActivation) {
// Walk through all activations, and set their lastProfilingFrame appropriately.
if (enabled) {
Activation* act = cx->activation();
void* lastProfilingFrame = GetTopProfilingJitFrame(act);
jit::JitActivation* jitActivation = target.context()->jitActivation;
while (jitActivation) {
jitActivation->setLastProfilingFrame(lastProfilingFrame);
jitActivation->setLastProfilingCallSite(nullptr);
jit::JitActivation* jitActivation = cx->jitActivation;
while (jitActivation) {
jitActivation->setLastProfilingFrame(lastProfilingFrame);
jitActivation->setLastProfilingCallSite(nullptr);
jitActivation = jitActivation->prevJitActivation();
lastProfilingFrame = GetTopProfilingJitFrame(jitActivation);
}
} else {
jit::JitActivation* jitActivation = target.context()->jitActivation;
while (jitActivation) {
jitActivation->setLastProfilingFrame(nullptr);
jitActivation->setLastProfilingCallSite(nullptr);
jitActivation = jitActivation->prevJitActivation();
}
jitActivation = jitActivation->prevJitActivation();
lastProfilingFrame = GetTopProfilingJitFrame(jitActivation);
}
} else {
jit::JitActivation* jitActivation = cx->jitActivation;
while (jitActivation) {
jitActivation->setLastProfilingFrame(nullptr);
jitActivation->setLastProfilingCallSite(nullptr);
jitActivation = jitActivation->prevJitActivation();
}
}
}
@ -431,12 +422,8 @@ ProfileEntry::script() const
// If profiling is supressed then we can't trust the script pointers to be
// valid as they could be in the process of being moved by a compacting GC
// (although it's still OK to get the runtime from them).
//
// We only need to check the active context here, as
// AutoSuppressProfilerSampling prohibits the runtime's active context from
// being changed while it exists.
JSContext* cx = script->runtimeFromAnyThread()->activeContext();
if (!cx || !cx->isProfilerSamplingEnabled())
JSContext* cx = script->runtimeFromAnyThread()->mainContextFromAnyThread();
if (!cx->isProfilerSamplingEnabled())
return nullptr;
MOZ_ASSERT(!IsForwarded(script));
@ -490,8 +477,7 @@ js::RegisterContextProfilingEventMarker(JSContext* cx, void (*fn)(const char*))
AutoSuppressProfilerSampling::AutoSuppressProfilerSampling(JSContext* cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: cx_(cx),
previouslyEnabled_(cx->isProfilerSamplingEnabled()),
prohibitContextChange_(cx->runtime())
previouslyEnabled_(cx->isProfilerSamplingEnabled())
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (previouslyEnabled_)

Просмотреть файл

@ -7,6 +7,7 @@
#include "vm/HelperThreads.h"
#include "mozilla/Maybe.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/Unused.h"
#include "builtin/Promise.h"
@ -1829,19 +1830,16 @@ HelperThread::handleIonWorkload(AutoLockHelperThreadState& locked)
FinishOffThreadIonCompile(builder, locked);
// Ping any thread currently operating on the compiled script's zone group
// so that the compiled code can be incorporated at the next interrupt
// callback. Don't interrupt Ion code for this, as this incorporation can
// be delayed indefinitely without affecting performance as long as the
// active thread is actually executing Ion code.
// Ping the main thread so that the compiled code can be incorporated at the
// next interrupt callback. Don't interrupt Ion code for this, as this
// incorporation can be delayed indefinitely without affecting performance
// as long as the main thread is actually executing Ion code.
//
// This must happen before the current task is reset. DestroyContext
// cancels in progress Ion compilations before destroying its target
// context, and after we reset the current task we are no longer considered
// to be Ion compiling.
JSContext* target = builder->script()->zoneFromAnyThread()->group()->ownerContext().context();
if (target)
target->requestInterrupt(JSContext::RequestInterruptCanWait);
rt->mainContextFromAnyThread()->requestInterrupt(JSContext::RequestInterruptCanWait);
currentTask.reset();
@ -1920,6 +1918,13 @@ HelperThread::handleParseWorkload(AutoLockHelperThreadState& locked)
AutoSetContextRuntime ascr(task->parseGlobal->runtimeFromAnyThread());
JSContext* cx = TlsContext.get();
ZoneGroup* zoneGroup = task->parseGlobal->zoneFromAnyThread()->group();
zoneGroup->setHelperThreadOwnerContext(cx);
auto resetOwnerContext = mozilla::MakeScopeExit([&] {
zoneGroup->setHelperThreadOwnerContext(nullptr);
});
AutoCompartment ac(cx, task->parseGlobal);
task->parse(cx);

Просмотреть файл

@ -58,7 +58,6 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options =
#endif
global_(nullptr),
enterCompartmentDepth(0),
globalHolds(0),
performanceMonitoring(runtime_),
data(nullptr),
realmData(nullptr),

Просмотреть файл

@ -634,7 +634,6 @@ struct JSCompartment
js::ReadBarrieredGlobalObject global_;
unsigned enterCompartmentDepth;
unsigned globalHolds;
public:
js::PerformanceGroupHolder performanceMonitoring;
@ -647,14 +646,7 @@ struct JSCompartment
}
bool hasBeenEntered() const { return !!enterCompartmentDepth; }
void holdGlobal() {
globalHolds++;
}
void releaseGlobal() {
MOZ_ASSERT(globalHolds > 0);
globalHolds--;
}
bool shouldTraceGlobal() const { return globalHolds > 0 || hasBeenEntered(); }
bool shouldTraceGlobal() const { return hasBeenEntered(); }
JS::Zone* zone() { return zone_; }
const JS::Zone* zone() const { return zone_; }

Просмотреть файл

@ -479,9 +479,6 @@ JSContext::enterNonAtomsCompartment(JSCompartment* c)
enterCompartmentDepth_++;
MOZ_ASSERT(!c->zone()->isAtomsZone());
c->holdGlobal();
enterZoneGroup(c->zone()->group());
c->releaseGlobal();
c->enter();
setCompartment(c, nullptr);
@ -526,11 +523,8 @@ JSContext::leaveCompartment(
// compartment.
JSCompartment* startingCompartment = compartment_;
setCompartment(oldCompartment, maybeLock);
if (startingCompartment) {
if (startingCompartment)
startingCompartment->leave();
if (!startingCompartment->zone()->isAtomsZone())
leaveZoneGroup(startingCompartment->zone()->group());
}
}
inline void
@ -551,29 +545,15 @@ JSContext::setCompartment(JSCompartment* comp,
MOZ_ASSERT_IF(compartment_, compartment_->hasBeenEntered());
MOZ_ASSERT_IF(comp, comp->hasBeenEntered());
// This context must have exclusive access to the zone's group.
// This thread must have exclusive access to the zone.
MOZ_ASSERT_IF(comp && !comp->zone()->isAtomsZone(),
comp->zone()->group()->ownedByCurrentThread());
CurrentThreadCanAccessZone(comp->zone()));
compartment_ = comp;
zone_ = comp ? comp->zone() : nullptr;
arenas_ = zone_ ? &zone_->arenas : nullptr;
}
inline void
JSContext::enterZoneGroup(js::ZoneGroup* group)
{
MOZ_ASSERT(this == js::TlsContext.get());
group->enter(this);
}
inline void
JSContext::leaveZoneGroup(js::ZoneGroup* group)
{
MOZ_ASSERT(this == js::TlsContext.get());
group->leave();
}
inline JSScript*
JSContext::currentScript(jsbytecode** ppc,
MaybeAllowCrossCompartment allowCrossCompartment) const

Просмотреть файл

@ -178,39 +178,6 @@ js::NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRun
return cx;
}
JSContext*
js::NewCooperativeContext(JSContext* siblingContext)
{
MOZ_RELEASE_ASSERT(!TlsContext.get());
JSRuntime* runtime = siblingContext->runtime();
JSContext* cx = js_new<JSContext>(runtime, JS::ContextOptions());
if (!cx || !cx->init(ContextKind::Cooperative)) {
js_delete(cx);
return nullptr;
}
runtime->setNewbornActiveContext(cx);
return cx;
}
void
js::YieldCooperativeContext(JSContext* cx)
{
MOZ_ASSERT(cx == TlsContext.get());
MOZ_ASSERT(cx->runtime()->activeContext() == cx);
cx->runtime()->setActiveContext(nullptr);
}
void
js::ResumeCooperativeContext(JSContext* cx)
{
MOZ_ASSERT(cx == TlsContext.get());
MOZ_ASSERT(cx->runtime()->activeContext() == nullptr);
cx->runtime()->setActiveContext(cx);
}
static void
FreeJobQueueHandling(JSContext* cx)
{
@ -243,29 +210,14 @@ js::DestroyContext(JSContext* cx)
FreeJobQueueHandling(cx);
if (cx->runtime()->cooperatingContexts().length() == 1) {
// Flush promise tasks executing in helper threads early, before any parts
// of the JSRuntime that might be visible to helper threads are torn down.
cx->runtime()->offThreadPromiseState.ref().shutdown(cx);
// Flush promise tasks executing in helper threads early, before any parts
// of the JSRuntime that might be visible to helper threads are torn down.
cx->runtime()->offThreadPromiseState.ref().shutdown(cx);
// Destroy the runtime along with its last context.
cx->runtime()->destroyRuntime();
js_delete(cx->runtime());
js_delete_poison(cx);
} else {
DebugOnly<bool> found = false;
for (size_t i = 0; i < cx->runtime()->cooperatingContexts().length(); i++) {
CooperatingContext& target = cx->runtime()->cooperatingContexts()[i];
if (cx == target.context()) {
cx->runtime()->cooperatingContexts().erase(&target);
found = true;
break;
}
}
MOZ_ASSERT(found);
cx->runtime()->deleteActiveContext(cx);
}
// Destroy the runtime along with its last context.
cx->runtime()->destroyRuntime();
js_delete(cx->runtime());
js_delete_poison(cx);
}
void

Просмотреть файл

@ -223,9 +223,6 @@ struct JSContext : public JS::RootingContext,
inline void leaveCompartment(JSCompartment* oldCompartment,
const js::AutoLockForExclusiveAccess* maybeLock = nullptr);
inline void enterZoneGroup(js::ZoneGroup* group);
inline void leaveZoneGroup(js::ZoneGroup* group);
void setHelperThread(js::HelperThread* helperThread);
js::HelperThread* helperThread() const { return helperThread_; }
@ -858,6 +855,19 @@ struct JSContext : public JS::RootingContext,
return handlingJitInterrupt_;
}
void* addressOfInterrupt() {
return &interrupt_;
}
void* addressOfInterruptRegExpJit() {
return &interruptRegExpJit_;
}
void* addressOfJitStackLimit() {
return &jitStackLimit;
}
void* addressOfJitStackLimitNoInterrupt() {
return &jitStackLimitNoInterrupt;
}
/* Futex state, used by Atomics.wait() and Atomics.wake() on the Atomics object */
js::FutexThread fx;
@ -935,10 +945,10 @@ JSContext::boolToResult(bool ok)
}
inline JSContext*
JSRuntime::activeContextFromOwnThread()
JSRuntime::mainContextFromOwnThread()
{
MOZ_ASSERT(activeContext() == js::TlsContext.get());
return activeContext();
MOZ_ASSERT(mainContextFromAnyThread() == js::TlsContext.get());
return mainContextFromAnyThread();
}
namespace js {
@ -986,15 +996,6 @@ struct MOZ_RAII AutoResolving {
extern JSContext*
NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRuntime);
extern JSContext*
NewCooperativeContext(JSContext* siblingContext);
extern void
YieldCooperativeContext(JSContext* cx);
extern void
ResumeCooperativeContext(JSContext* cx);
extern void
DestroyContext(JSContext* cx);

Просмотреть файл

@ -4128,27 +4128,24 @@ JSScript::argumentsOptimizationFailed(JSContext* cx, HandleScript script)
* assumption of !script->needsArgsObj();
* - type inference data for the script assuming script->needsArgsObj
*/
JSRuntime::AutoProhibitActiveContextChange apacc(cx->runtime());
for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
for (AllScriptFramesIter i(cx, target); !i.done(); ++i) {
/*
* We cannot reliably create an arguments object for Ion activations of
* this script. To maintain the invariant that "script->needsArgsObj
* implies fp->hasArgsObj", the Ion bail mechanism will create an
* arguments object right after restoring the BaselineFrame and before
* entering Baseline code (in jit::FinishBailoutToBaseline).
*/
if (i.isIon())
continue;
AbstractFramePtr frame = i.abstractFramePtr();
if (frame.isFunctionFrame() && frame.script() == script) {
/* We crash on OOM since cleaning up here would be complicated. */
AutoEnterOOMUnsafeRegion oomUnsafe;
ArgumentsObject* argsobj = ArgumentsObject::createExpected(cx, frame);
if (!argsobj)
oomUnsafe.crash("JSScript::argumentsOptimizationFailed");
SetFrameArgumentsObject(cx, frame, script, argsobj);
}
for (AllScriptFramesIter i(cx); !i.done(); ++i) {
/*
* We cannot reliably create an arguments object for Ion activations of
* this script. To maintain the invariant that "script->needsArgsObj
* implies fp->hasArgsObj", the Ion bail mechanism will create an
* arguments object right after restoring the BaselineFrame and before
* entering Baseline code (in jit::FinishBailoutToBaseline).
*/
if (i.isIon())
continue;
AbstractFramePtr frame = i.abstractFramePtr();
if (frame.isFunctionFrame() && frame.script() == script) {
/* We crash on OOM since cleaning up here would be complicated. */
AutoEnterOOMUnsafeRegion oomUnsafe;
ArgumentsObject* argsobj = ArgumentsObject::createExpected(cx, frame);
if (!argsobj)
oomUnsafe.crash("JSScript::argumentsOptimizationFailed");
SetFrameArgumentsObject(cx, frame, script, argsobj);
}
}

Просмотреть файл

@ -92,12 +92,7 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
updateChildRuntimeCount(parentRuntime),
initialized_(false),
#endif
activeContext_(nullptr),
activeContextChangeProhibited_(0),
singleThreadedExecutionRequired_(0),
startingSingleThreadedExecution_(false),
beginSingleThreadedExecutionCallback(nullptr),
endSingleThreadedExecutionCallback(nullptr),
mainContext_(nullptr),
profilerSampleBufferRangeStart_(0),
telemetryCallback(nullptr),
consumeStreamCallback(nullptr),
@ -211,9 +206,7 @@ JSRuntime::init(JSContext* cx, uint32_t maxbytes, uint32_t maxNurseryBytes)
if (CanUseExtraThreads() && !EnsureHelperThreadsInitialized())
return false;
activeContext_ = cx;
if (!cooperatingContexts().append(cx))
return false;
mainContext_ = cx;
defaultFreeOp_ = js_new<js::FreeOp>(this);
if (!defaultFreeOp_)
@ -348,89 +341,6 @@ JSRuntime::destroyRuntime()
#endif
}
static void
CheckCanChangeActiveContext(JSRuntime* rt)
{
// The runtime might not currently have an active context, in which case
// the accesses below to ActiveThreadData data would not normally be
// allowed. Suppress protected data checks so these accesses will be
// tolerated --- if the active context is null then we're about to set it
// to the current thread.
AutoNoteSingleThreadedRegion anstr;
MOZ_RELEASE_ASSERT(!rt->activeContextChangeProhibited());
MOZ_RELEASE_ASSERT(!rt->activeContext() || rt->gc.canChangeActiveContext(rt->activeContext()));
if (rt->singleThreadedExecutionRequired()) {
for (ZoneGroupsIter group(rt); !group.done(); group.next())
MOZ_RELEASE_ASSERT(group->ownerContext().context() == nullptr);
}
}
void
JSRuntime::setActiveContext(JSContext* cx)
{
CheckCanChangeActiveContext(this);
MOZ_ASSERT_IF(cx, cx->isCooperativelyScheduled());
activeContext_ = cx;
}
void
JSRuntime::setNewbornActiveContext(JSContext* cx)
{
CheckCanChangeActiveContext(this);
activeContext_ = cx;
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!cooperatingContexts().append(cx))
oomUnsafe.crash("Add cooperating context");
}
void
JSRuntime::deleteActiveContext(JSContext* cx)
{
CheckCanChangeActiveContext(this);
MOZ_ASSERT(cx == activeContext());
js_delete_poison(cx);
activeContext_ = nullptr;
}
bool
JSRuntime::beginSingleThreadedExecution(JSContext* cx)
{
if (singleThreadedExecutionRequired_ == 0) {
if (startingSingleThreadedExecution_)
return false;
startingSingleThreadedExecution_ = true;
if (beginSingleThreadedExecutionCallback)
beginSingleThreadedExecutionCallback(cx);
MOZ_ASSERT(startingSingleThreadedExecution_);
startingSingleThreadedExecution_ = false;
}
singleThreadedExecutionRequired_++;
for (ZoneGroupsIter group(this); !group.done(); group.next()) {
MOZ_RELEASE_ASSERT(group->ownedByCurrentThread() ||
group->ownerContext().context() == nullptr);
}
return true;
}
void
JSRuntime::endSingleThreadedExecution(JSContext* cx)
{
MOZ_ASSERT(singleThreadedExecutionRequired_);
if (--singleThreadedExecutionRequired_ == 0) {
if (endSingleThreadedExecutionCallback)
endSingleThreadedExecutionCallback(cx);
}
}
void
JSRuntime::addTelemetry(int id, uint32_t sample, const char* key)
{
@ -474,17 +384,15 @@ JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Runtim
rtSizes->atomsTable += permanentAtoms->sizeOfIncludingThis(mallocSizeOf);
}
for (const CooperatingContext& target : cooperatingContexts()) {
JSContext* cx = target.context();
rtSizes->contexts += mallocSizeOf(cx);
rtSizes->contexts += cx->sizeOfExcludingThis(mallocSizeOf);
rtSizes->temporary += cx->tempLifoAlloc().sizeOfExcludingThis(mallocSizeOf);
rtSizes->interpreterStack += cx->interpreterStack().sizeOfExcludingThis(mallocSizeOf);
JSContext* cx = mainContextFromAnyThread();
rtSizes->contexts += mallocSizeOf(cx);
rtSizes->contexts += cx->sizeOfExcludingThis(mallocSizeOf);
rtSizes->temporary += cx->tempLifoAlloc().sizeOfExcludingThis(mallocSizeOf);
rtSizes->interpreterStack += cx->interpreterStack().sizeOfExcludingThis(mallocSizeOf);
#ifdef JS_TRACE_LOGGING
if (cx->traceLogger)
rtSizes->tracelogger += cx->traceLogger->sizeOfIncludingThis(mallocSizeOf);
if (cx->traceLogger)
rtSizes->tracelogger += cx->traceLogger->sizeOfIncludingThis(mallocSizeOf);
#endif
}
if (MathCache* cache = caches().maybeGetMathCache())
rtSizes->mathCache += cache->sizeOfIncludingThis(mallocSizeOf);
@ -629,7 +537,7 @@ JSRuntime::setDefaultLocale(const char* locale)
if (!locale)
return false;
resetDefaultLocale();
defaultLocale = JS_strdup(activeContextFromOwnThread(), locale);
defaultLocale = JS_strdup(mainContextFromOwnThread(), locale);
return defaultLocale != nullptr;
}
@ -652,7 +560,7 @@ JSRuntime::getDefaultLocale()
if (!locale || !strcmp(locale, "C"))
locale = "und";
char* lang = JS_strdup(activeContextFromOwnThread(), locale);
char* lang = JS_strdup(mainContextFromOwnThread(), locale);
if (!lang)
return nullptr;
@ -908,7 +816,7 @@ JSRuntime::clearUsedByHelperThread(Zone* zone)
bool
js::CurrentThreadCanAccessRuntime(const JSRuntime* rt)
{
return rt->activeContext() == TlsContext.get();
return rt->mainContextFromAnyThread() == TlsContext.get();
}
bool
@ -916,7 +824,7 @@ js::CurrentThreadCanAccessZone(Zone* zone)
{
// Helper thread zones can only be used by their owning thread.
if (zone->usedByHelperThread())
return zone->group()->ownedByCurrentThread();
return zone->group()->ownedByCurrentHelperThread();
// Other zones can only be accessed by the runtime's active context.
return CurrentThreadCanAccessRuntime(zone->runtime_);

Просмотреть файл

@ -105,33 +105,18 @@ class Simulator;
// JS Engine Threading
//
// Multiple threads may interact with a JS runtime. JS has run-to-completion
// semantics, which means that scripts cannot observe changes in behavior
// due to activities performed on other threads (there is an exception to this
// for shared array buffers and related APIs).
//
// The main way we ensure that run-to-completion semantics are preserved is
// by dividing content into zone groups. Pieces of web content will be in the
// the same zone group if they have the same tab/origin or can otherwise
// observe changes in each other via Window.opener and so forth. When a thread
// executes JS in a zone group, it acquires that group --- including exclusive
// access to most of the group's content --- and does not relinquish control of
// the zone group until the script finishes executing.
//
// Threads interacting with a runtime are divided into two categories:
//
// - Cooperating threads are capable of running JS. At most one cooperating
// thread may be |active| at a time in a runtime, but they may yield control
// to each other so that their execution is interleaved. As described above,
// each thread owns the zone groups it is operating on so that this
// interleaving does not cause observable changes in a script's behavior.
// - The main thread is capable of running JS. There's at most one main thread
// per runtime.
//
// - Helper threads do not run JS, and are controlled or triggered by activity
// in the cooperating threads. Helper threads may have exclusive access to
// zone groups created for them, for parsing and similar tasks, but their
// activities do not cause observable changes in script behaviors. Activity
// on helper threads may be referred to as happening 'off thread' or on a
// background thread in some parts of the VM.
// on the main thread (or main threads, since all runtimes in a process share
// helper threads). Helper threads may have exclusive access to zone groups
// created for them, for parsing and similar tasks, but their activities do
// not cause observable changes in script behaviors. Activity on helper
// threads may be referred to as happening 'off thread' or on a background
// thread in some parts of the VM.
} /* namespace js */
@ -278,69 +263,15 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
js::WriteOnceData<bool> initialized_;
#endif
// The context for the thread which currently has exclusive access to most
// contents of the runtime. When execution on the runtime is cooperatively
// scheduled, this is the thread which is currently running.
mozilla::Atomic<JSContext*, mozilla::ReleaseAcquire> activeContext_;
// All contexts participating in cooperative scheduling. All threads other
// than |activeContext_| are suspended.
js::ActiveThreadData<js::Vector<js::CooperatingContext, 4, js::SystemAllocPolicy>> cooperatingContexts_;
// Count of AutoProhibitActiveContextChange instances on the active context.
js::ActiveThreadData<size_t> activeContextChangeProhibited_;
// Count of beginSingleThreadedExecution() calls that have occurred with no
// matching endSingleThreadedExecution().
js::ActiveThreadData<size_t> singleThreadedExecutionRequired_;
// Whether some thread has called beginSingleThreadedExecution() and we are
// in the associated callback (which may execute JS on other threads).
js::ActiveThreadData<bool> startingSingleThreadedExecution_;
// The JSContext* for the runtime's main thread. Immutable after this is set
// in JSRuntime::init.
JSContext* mainContext_;
public:
JSContext* activeContext() const { return activeContext_; }
const void* addressOfActiveContext() { return &activeContext_; }
JSContext* mainContextFromAnyThread() const { return mainContext_; }
const void* addressOfMainContext() { return &mainContext_; }
void setActiveContext(JSContext* cx);
void setNewbornActiveContext(JSContext* cx);
void deleteActiveContext(JSContext* cx);
inline JSContext* activeContextFromOwnThread();
js::Vector<js::CooperatingContext, 4, js::SystemAllocPolicy>& cooperatingContexts() {
return cooperatingContexts_.ref();
}
class MOZ_RAII AutoProhibitActiveContextChange
{
JSRuntime* rt;
public:
explicit AutoProhibitActiveContextChange(JSRuntime* rt)
: rt(rt)
{
rt->activeContextChangeProhibited_++;
}
~AutoProhibitActiveContextChange()
{
rt->activeContextChangeProhibited_--;
}
};
bool activeContextChangeProhibited() { return activeContextChangeProhibited_; }
bool singleThreadedExecutionRequired() { return singleThreadedExecutionRequired_; }
js::ActiveThreadData<JS::BeginSingleThreadedExecutionCallback> beginSingleThreadedExecutionCallback;
js::ActiveThreadData<JS::EndSingleThreadedExecutionCallback> endSingleThreadedExecutionCallback;
// Ensure there is only a single thread interacting with this runtime.
// beginSingleThreadedExecution() returns false if some context has already
// started forcing this runtime to be single threaded. Calls to these
// functions must be balanced.
bool beginSingleThreadedExecution(JSContext* cx);
void endSingleThreadedExecution(JSContext* cx);
inline JSContext* mainContextFromOwnThread();
/*
* The start of the range stored in the profiler sample buffer, as measured

Просмотреть файл

@ -404,7 +404,7 @@ SavedFrame::finalize(FreeOp* fop, JSObject* obj)
JSPrincipals* p = obj->as<SavedFrame>().getPrincipals();
if (p) {
JSRuntime* rt = obj->runtimeFromActiveCooperatingThread();
JS_DropPrincipals(rt->activeContextFromOwnThread(), p);
JS_DropPrincipals(rt->mainContextFromOwnThread(), p);
}
}

Просмотреть файл

@ -406,9 +406,9 @@ TraceInterpreterActivation(JSTracer* trc, InterpreterActivation* act)
}
void
js::TraceInterpreterActivations(JSContext* cx, const CooperatingContext& target, JSTracer* trc)
js::TraceInterpreterActivations(JSContext* cx, JSTracer* trc)
{
for (ActivationIterator iter(cx, target); !iter.done(); ++iter) {
for (ActivationIterator iter(cx); !iter.done(); ++iter) {
Activation* act = iter.activation();
if (act->isInterpreter())
TraceInterpreterActivation(trc, act->asInterpreter());
@ -735,19 +735,6 @@ FrameIter::Data::Data(JSContext* cx, DebuggerEvalOption debuggerEvalOption,
{
}
FrameIter::Data::Data(JSContext* cx, const CooperatingContext& target,
DebuggerEvalOption debuggerEvalOption)
: cx_(cx),
debuggerEvalOption_(debuggerEvalOption),
principals_(nullptr),
state_(DONE),
pc_(nullptr),
interpFrames_(nullptr),
activations_(cx, target),
ionInlineFrameNo_(0)
{
}
FrameIter::Data::Data(const FrameIter::Data& other)
: cx_(other.cx_),
debuggerEvalOption_(other.debuggerEvalOption_),
@ -761,16 +748,6 @@ FrameIter::Data::Data(const FrameIter::Data& other)
{
}
FrameIter::FrameIter(JSContext* cx, const CooperatingContext& target,
DebuggerEvalOption debuggerEvalOption)
: data_(cx, target, debuggerEvalOption),
ionInlineFrames_(cx, (js::jit::JSJitFrameIter*) nullptr)
{
// settleOnActivation can only GC if principals are given.
JS::AutoSuppressGCAnalysis nogc;
settleOnActivation();
}
FrameIter::FrameIter(JSContext* cx, DebuggerEvalOption debuggerEvalOption)
: data_(cx, debuggerEvalOption, nullptr),
ionInlineFrames_(cx, (js::jit::JSJitFrameIter*) nullptr)
@ -1810,22 +1787,6 @@ ActivationIterator::ActivationIterator(JSContext* cx)
MOZ_ASSERT(cx == TlsContext.get());
}
ActivationIterator::ActivationIterator(JSContext* cx, const CooperatingContext& target)
{
MOZ_ASSERT(cx == TlsContext.get());
// If target was specified --- even if it is the same as cx itself --- then
// we must be in a scope where changes of the active context are prohibited.
// Otherwise our state would be corrupted if the target thread resumed
// execution while we are iterating over its state.
MOZ_ASSERT(cx->runtime()->activeContextChangeProhibited() ||
!cx->runtime()->gc.canChangeActiveContext(cx));
// Tolerate a null target context, in case we are iterating over the
// activations for a zone group that is not in use by any thread.
activation_ = target.context() ? target.context()->activation_.ref() : nullptr;
}
ActivationIterator&
ActivationIterator::operator++()
{

Просмотреть файл

@ -913,24 +913,7 @@ class InterpreterStack
}
};
// CooperatingContext is a wrapper for a JSContext that is participating in
// cooperative scheduling and may be different from the current thread. It is
// in place to make it clearer when we might be operating on another thread,
// and harder to accidentally pass in another thread's context to an API that
// expects the current thread's context.
class CooperatingContext
{
JSContext* cx;
public:
explicit CooperatingContext(JSContext* cx) : cx(cx) {}
JSContext* context() const { return cx; }
// For &cx. The address should not be taken for other CooperatingContexts.
friend class ZoneGroup;
};
void TraceInterpreterActivations(JSContext* cx, const CooperatingContext& target, JSTracer* trc);
void TraceInterpreterActivations(JSContext* cx, JSTracer* trc);
/*****************************************************************************/
@ -1606,11 +1589,6 @@ class ActivationIterator
public:
explicit ActivationIterator(JSContext* cx);
// ActivationIterator can be used to iterate over a different thread's
// activations, for use by the GC, invalidation, and other operations that
// don't have a user-visible effect on the target thread's JS behavior.
ActivationIterator(JSContext* cx, const CooperatingContext& target);
ActivationIterator& operator++();
Activation* operator->() const {
@ -1852,12 +1830,6 @@ class JitActivationIterator : public ActivationIterator
settle();
}
JitActivationIterator(JSContext* cx, const CooperatingContext& target)
: ActivationIterator(cx, target)
{
settle();
}
JitActivationIterator& operator++() {
ActivationIterator::operator++();
settle();
@ -2048,13 +2020,11 @@ class FrameIter
unsigned ionInlineFrameNo_;
Data(JSContext* cx, DebuggerEvalOption debuggerEvalOption, JSPrincipals* principals);
Data(JSContext* cx, const CooperatingContext& target, DebuggerEvalOption debuggerEvalOption);
Data(const Data& other);
};
explicit FrameIter(JSContext* cx,
DebuggerEvalOption = FOLLOW_DEBUGGER_EVAL_PREV_LINK);
FrameIter(JSContext* cx, const CooperatingContext&, DebuggerEvalOption);
FrameIter(JSContext* cx, DebuggerEvalOption, JSPrincipals*);
FrameIter(const FrameIter& iter);
MOZ_IMPLICIT FrameIter(const Data& data);
@ -2221,14 +2191,6 @@ class ScriptFrameIter : public FrameIter
settle();
}
ScriptFrameIter(JSContext* cx,
const CooperatingContext& target,
DebuggerEvalOption debuggerEvalOption)
: FrameIter(cx, target, debuggerEvalOption)
{
settle();
}
ScriptFrameIter(JSContext* cx,
DebuggerEvalOption debuggerEvalOption,
JSPrincipals* prin)
@ -2351,10 +2313,6 @@ class AllScriptFramesIter : public ScriptFrameIter
explicit AllScriptFramesIter(JSContext* cx)
: ScriptFrameIter(cx, ScriptFrameIter::IGNORE_DEBUGGER_EVAL_PREV_LINK)
{}
explicit AllScriptFramesIter(JSContext* cx, const CooperatingContext& target)
: ScriptFrameIter(cx, target, ScriptFrameIter::IGNORE_DEBUGGER_EVAL_PREV_LINK)
{}
};
/* Popular inline definitions. */

Просмотреть файл

@ -3979,92 +3979,89 @@ TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* g
RootedFunction function(cx, this->function());
Vector<uint32_t, 32> pcOffsets(cx);
JSRuntime::AutoProhibitActiveContextChange apacc(cx->runtime());
for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
for (AllScriptFramesIter iter(cx, target); !iter.done(); ++iter) {
{
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!pcOffsets.append(iter.script()->pcToOffset(iter.pc())))
oomUnsafe.crash("rollbackPartiallyInitializedObjects");
}
for (AllScriptFramesIter iter(cx); !iter.done(); ++iter) {
{
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!pcOffsets.append(iter.script()->pcToOffset(iter.pc())))
oomUnsafe.crash("rollbackPartiallyInitializedObjects");
}
if (!iter.isConstructing() || !iter.matchCallee(cx, function))
continue;
if (!iter.isConstructing() || !iter.matchCallee(cx, function))
continue;
// Derived class constructors initialize their this-binding later and
// we shouldn't run the definite properties analysis on them.
MOZ_ASSERT(!iter.script()->isDerivedClassConstructor());
// Derived class constructors initialize their this-binding later and
// we shouldn't run the definite properties analysis on them.
MOZ_ASSERT(!iter.script()->isDerivedClassConstructor());
Value thisv = iter.thisArgument(cx);
if (!thisv.isObject() ||
thisv.toObject().hasLazyGroup() ||
thisv.toObject().group() != group)
{
continue;
}
Value thisv = iter.thisArgument(cx);
if (!thisv.isObject() ||
thisv.toObject().hasLazyGroup() ||
thisv.toObject().group() != group)
{
continue;
}
if (thisv.toObject().is<UnboxedPlainObject>()) {
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!UnboxedPlainObject::convertToNative(cx, &thisv.toObject()))
oomUnsafe.crash("rollbackPartiallyInitializedObjects");
}
if (thisv.toObject().is<UnboxedPlainObject>()) {
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!UnboxedPlainObject::convertToNative(cx, &thisv.toObject()))
oomUnsafe.crash("rollbackPartiallyInitializedObjects");
}
// Found a matching frame.
RootedPlainObject obj(cx, &thisv.toObject().as<PlainObject>());
// Found a matching frame.
RootedPlainObject obj(cx, &thisv.toObject().as<PlainObject>());
// Whether all identified 'new' properties have been initialized.
bool finished = false;
// Whether all identified 'new' properties have been initialized.
bool finished = false;
// If not finished, number of properties that have been added.
uint32_t numProperties = 0;
// If not finished, number of properties that have been added.
uint32_t numProperties = 0;
// Whether the current SETPROP is within an inner frame which has
// finished entirely.
bool pastProperty = false;
// Whether the current SETPROP is within an inner frame which has
// finished entirely.
bool pastProperty = false;
// Index in pcOffsets of the outermost frame.
int callDepth = pcOffsets.length() - 1;
// Index in pcOffsets of the outermost frame.
int callDepth = pcOffsets.length() - 1;
// Index in pcOffsets of the frame currently being checked for a SETPROP.
int setpropDepth = callDepth;
// Index in pcOffsets of the frame currently being checked for a SETPROP.
int setpropDepth = callDepth;
for (Initializer* init = initializerList;; init++) {
if (init->kind == Initializer::SETPROP) {
if (!pastProperty && pcOffsets[setpropDepth] < init->offset) {
// Have not yet reached this setprop.
break;
}
// This setprop has executed, reset state for the next one.
numProperties++;
pastProperty = false;
setpropDepth = callDepth;
} else if (init->kind == Initializer::SETPROP_FRAME) {
if (!pastProperty) {
if (pcOffsets[setpropDepth] < init->offset) {
// Have not yet reached this inner call.
break;
} else if (pcOffsets[setpropDepth] > init->offset) {
// Have advanced past this inner call.
pastProperty = true;
} else if (setpropDepth == 0) {
// Have reached this call but not yet in it.
break;
} else {
// Somewhere inside this inner call.
setpropDepth--;
}
}
} else {
MOZ_ASSERT(init->kind == Initializer::DONE);
finished = true;
for (Initializer* init = initializerList;; init++) {
if (init->kind == Initializer::SETPROP) {
if (!pastProperty && pcOffsets[setpropDepth] < init->offset) {
// Have not yet reached this setprop.
break;
}
// This setprop has executed, reset state for the next one.
numProperties++;
pastProperty = false;
setpropDepth = callDepth;
} else if (init->kind == Initializer::SETPROP_FRAME) {
if (!pastProperty) {
if (pcOffsets[setpropDepth] < init->offset) {
// Have not yet reached this inner call.
break;
} else if (pcOffsets[setpropDepth] > init->offset) {
// Have advanced past this inner call.
pastProperty = true;
} else if (setpropDepth == 0) {
// Have reached this call but not yet in it.
break;
} else {
// Somewhere inside this inner call.
setpropDepth--;
}
}
} else {
MOZ_ASSERT(init->kind == Initializer::DONE);
finished = true;
break;
}
}
if (!finished) {
(void) NativeObject::rollbackProperties(cx, obj, numProperties);
found = true;
}
if (!finished) {
(void) NativeObject::rollbackProperties(cx, obj, numProperties);
found = true;
}
}
@ -4619,7 +4616,6 @@ AutoClearTypeInferenceStateOnOOM::~AutoClearTypeInferenceStateOnOOM()
if (oom) {
JSRuntime* rt = zone->runtimeFromActiveCooperatingThread();
js::CancelOffThreadIonCompile(rt);
JSRuntime::AutoProhibitActiveContextChange apacc(rt);
zone->setPreservingCode(false);
zone->discardJitCode(rt->defaultFreeOp(), /* discardBaselineCode = */ false);
zone->types.clearAllNewScriptsOnOOM();