зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1449135 part 3 - Remove cooperative scheduling; bake in JSContext* in JIT code. r=luke
This commit is contained in:
Родитель
ec31881a4a
Коммит
68eeb821cb
|
@ -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();
|
||||
|
|
Загрузка…
Ссылка в новой задаче