mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 949296 - Ignore DontStopIon interrupt triggers during ForkJoin. (r=nmatsakis)
This commit is contained in:
parent
c6165cfa30
commit
488bdb76a7
@ -17,6 +17,5 @@ function test() {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Bug 949296. Broken due to all interrupt triggers aborting PJS.
|
||||
//if (getBuildConfiguration().parallelJS)
|
||||
// test();
|
||||
if (getBuildConfiguration().parallelJS)
|
||||
test();
|
||||
|
@ -275,7 +275,7 @@ CanEnterBaselineJIT(JSContext *cx, HandleScript script, bool osr)
|
||||
// parallel execution. We want to avoid the situation of OSRing during
|
||||
// warmup and only gathering type information for the loop, and not the
|
||||
// rest of the function.
|
||||
if (IsJSDEnabled(cx) || cx->runtime()->parallelWarmup > 0) {
|
||||
if (IsJSDEnabled(cx) || cx->runtime()->forkJoinWarmup > 0) {
|
||||
if (osr)
|
||||
return Method_Skipped;
|
||||
} else if (script->incUseCount() <= js_JitOptions.baselineUsesBeforeCompile) {
|
||||
|
@ -2851,7 +2851,7 @@ CodeGenerator::visitCheckOverRecursedPar(LCheckOverRecursedPar *lir)
|
||||
if (!addOutOfLineCode(ool))
|
||||
return false;
|
||||
masm.branchPtr(Assembler::BelowOrEqual, StackPointer, tempReg, ool->entry());
|
||||
masm.checkInterruptFlagsPar(tempReg, ool->entry());
|
||||
masm.checkInterruptFlagPar(tempReg, ool->entry());
|
||||
masm.bind(ool->rejoin());
|
||||
|
||||
return true;
|
||||
@ -2886,41 +2886,36 @@ CodeGenerator::visitCheckOverRecursedFailurePar(CheckOverRecursedFailurePar *ool
|
||||
}
|
||||
|
||||
// Out-of-line path to report over-recursed error and fail.
|
||||
class OutOfLineCheckInterruptPar : public OutOfLineCodeBase<CodeGenerator>
|
||||
class OutOfLineInterruptCheckPar : public OutOfLineCodeBase<CodeGenerator>
|
||||
{
|
||||
public:
|
||||
LCheckInterruptPar *const lir;
|
||||
LInterruptCheckPar *const lir;
|
||||
|
||||
OutOfLineCheckInterruptPar(LCheckInterruptPar *lir)
|
||||
OutOfLineInterruptCheckPar(LInterruptCheckPar *lir)
|
||||
: lir(lir)
|
||||
{ }
|
||||
|
||||
bool accept(CodeGenerator *codegen) {
|
||||
return codegen->visitOutOfLineCheckInterruptPar(this);
|
||||
return codegen->visitOutOfLineInterruptCheckPar(this);
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
CodeGenerator::visitCheckInterruptPar(LCheckInterruptPar *lir)
|
||||
CodeGenerator::visitInterruptCheckPar(LInterruptCheckPar *lir)
|
||||
{
|
||||
// First check for cx->shared->interrupt_.
|
||||
OutOfLineCheckInterruptPar *ool = new(alloc()) OutOfLineCheckInterruptPar(lir);
|
||||
OutOfLineInterruptCheckPar *ool = new(alloc()) OutOfLineInterruptCheckPar(lir);
|
||||
if (!addOutOfLineCode(ool))
|
||||
return false;
|
||||
|
||||
// We must check two flags:
|
||||
// - runtime->interrupt
|
||||
// - runtime->parallelAbort
|
||||
// See vm/ForkJoin.h for discussion on why we use this design.
|
||||
|
||||
Register tempReg = ToRegister(lir->getTempReg());
|
||||
masm.checkInterruptFlagsPar(tempReg, ool->entry());
|
||||
masm.checkInterruptFlagPar(tempReg, ool->entry());
|
||||
masm.bind(ool->rejoin());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitOutOfLineCheckInterruptPar(OutOfLineCheckInterruptPar *ool)
|
||||
CodeGenerator::visitOutOfLineInterruptCheckPar(OutOfLineInterruptCheckPar *ool)
|
||||
{
|
||||
OutOfLinePropagateAbortPar *bail = oolPropagateAbortPar(ool->lir);
|
||||
if (!bail)
|
||||
@ -2929,7 +2924,7 @@ CodeGenerator::visitOutOfLineCheckInterruptPar(OutOfLineCheckInterruptPar *ool)
|
||||
// Avoid saving/restoring the temp register since we will put the
|
||||
// ReturnReg into it below and we don't want to clobber that
|
||||
// during PopRegsInMask():
|
||||
LCheckInterruptPar *lir = ool->lir;
|
||||
LInterruptCheckPar *lir = ool->lir;
|
||||
Register tempReg = ToRegister(lir->getTempReg());
|
||||
RegisterSet saveSet(lir->safepoint()->liveRegs());
|
||||
saveSet.takeUnchecked(tempReg);
|
||||
@ -2938,7 +2933,7 @@ CodeGenerator::visitOutOfLineCheckInterruptPar(OutOfLineCheckInterruptPar *ool)
|
||||
masm.movePtr(ToRegister(ool->lir->forkJoinContext()), CallTempReg0);
|
||||
masm.setupUnalignedABICall(1, CallTempReg1);
|
||||
masm.passABIArg(CallTempReg0);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, CheckInterruptPar));
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, InterruptCheckPar));
|
||||
masm.movePtr(ReturnReg, tempReg);
|
||||
masm.PopRegsInMask(saveSet);
|
||||
masm.branchIfFalseBool(tempReg, bail->entry());
|
||||
|
@ -30,7 +30,7 @@ class OutOfLineNewArray;
|
||||
class OutOfLineNewObject;
|
||||
class CheckOverRecursedFailure;
|
||||
class CheckOverRecursedFailurePar;
|
||||
class OutOfLineCheckInterruptPar;
|
||||
class OutOfLineInterruptCheckPar;
|
||||
class OutOfLineInterruptCheckImplicit;
|
||||
class OutOfLineUnboxFloatingPoint;
|
||||
class OutOfLineStoreElementHole;
|
||||
@ -291,8 +291,8 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
bool visitCheckOverRecursedPar(LCheckOverRecursedPar *lir);
|
||||
bool visitCheckOverRecursedFailurePar(CheckOverRecursedFailurePar *ool);
|
||||
|
||||
bool visitCheckInterruptPar(LCheckInterruptPar *lir);
|
||||
bool visitOutOfLineCheckInterruptPar(OutOfLineCheckInterruptPar *ool);
|
||||
bool visitInterruptCheckPar(LInterruptCheckPar *lir);
|
||||
bool visitOutOfLineInterruptCheckPar(OutOfLineInterruptCheckPar *ool);
|
||||
|
||||
bool visitInterruptCheckImplicit(LInterruptCheckImplicit *ins);
|
||||
bool visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit *ins);
|
||||
|
@ -71,6 +71,14 @@ CompileRuntime::addressOfInterrupt()
|
||||
return &runtime()->interrupt;
|
||||
}
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
const void *
|
||||
CompileRuntime::addressOfInterruptPar()
|
||||
{
|
||||
return &runtime()->interruptPar;
|
||||
}
|
||||
#endif
|
||||
|
||||
const JitRuntime *
|
||||
CompileRuntime::jitRuntime()
|
||||
{
|
||||
|
@ -52,6 +52,10 @@ class CompileRuntime
|
||||
|
||||
const void *addressOfInterrupt();
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
const void *addressOfInterruptPar();
|
||||
#endif
|
||||
|
||||
const JitRuntime *jitRuntime();
|
||||
|
||||
// Compilation does not occur off thread when the SPS profiler is enabled.
|
||||
|
@ -433,6 +433,7 @@ jit::TriggerOperationCallbackForIonCode(JSRuntime *rt,
|
||||
break;
|
||||
|
||||
case JSRuntime::TriggerCallbackAnyThreadDontStopIon:
|
||||
case JSRuntime::TriggerCallbackAnyThreadForkJoin:
|
||||
// When the trigger does not require Ion code to be interrupted,
|
||||
// nothing more needs to be done.
|
||||
break;
|
||||
|
@ -875,11 +875,14 @@ MacroAssembler::compareStrings(JSOp op, Register left, Register right, Register
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::checkInterruptFlagsPar(const Register &tempReg,
|
||||
Label *fail)
|
||||
MacroAssembler::checkInterruptFlagPar(const Register &tempReg, Label *fail)
|
||||
{
|
||||
movePtr(ImmPtr(GetIonContext()->runtime->addressOfInterrupt()), tempReg);
|
||||
#ifdef JS_THREADSAFE
|
||||
movePtr(ImmPtr(GetIonContext()->runtime->addressOfInterruptPar()), tempReg);
|
||||
branch32(Assembler::NonZero, Address(tempReg, 0), Imm32(0), fail);
|
||||
#else
|
||||
MOZ_ASSUME_UNREACHABLE("JSRuntime::interruptPar doesn't exist on non-threadsafe builds.");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -797,7 +797,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
|
||||
// Checks the flags that signal that parallel code may need to interrupt or
|
||||
// abort. Branches to fail in that case.
|
||||
void checkInterruptFlagsPar(const Register &tempReg, Label *fail);
|
||||
void checkInterruptFlagPar(const Register &tempReg, Label *fail);
|
||||
|
||||
// If the JitCode that created this assembler needs to transition into the VM,
|
||||
// we want to store the JitCode on the stack in order to mark it during a GC.
|
||||
|
@ -737,12 +737,12 @@ class LInterruptCheckImplicit : public LInstructionHelper<0, 0, 0>
|
||||
}
|
||||
};
|
||||
|
||||
class LCheckInterruptPar : public LInstructionHelper<0, 1, 1>
|
||||
class LInterruptCheckPar : public LInstructionHelper<0, 1, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(CheckInterruptPar);
|
||||
LIR_HEADER(InterruptCheckPar);
|
||||
|
||||
LCheckInterruptPar(const LAllocation &cx, const LDefinition &tempReg) {
|
||||
LInterruptCheckPar(const LAllocation &cx, const LDefinition &tempReg) {
|
||||
setOperand(0, cx);
|
||||
setTemp(0, tempReg);
|
||||
}
|
||||
|
@ -285,7 +285,7 @@
|
||||
_(AsmJSPassStackArg) \
|
||||
_(AsmJSCall) \
|
||||
_(AsmJSCheckOverRecursed) \
|
||||
_(CheckInterruptPar) \
|
||||
_(InterruptCheckPar) \
|
||||
_(RecompileCheck) \
|
||||
_(AssertRangeI) \
|
||||
_(AssertRangeD) \
|
||||
|
@ -2140,10 +2140,10 @@ LIRGenerator::visitInterruptCheck(MInterruptCheck *ins)
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitCheckInterruptPar(MCheckInterruptPar *ins)
|
||||
LIRGenerator::visitInterruptCheckPar(MInterruptCheckPar *ins)
|
||||
{
|
||||
LCheckInterruptPar *lir =
|
||||
new(alloc()) LCheckInterruptPar(useRegister(ins->forkJoinContext()), temp());
|
||||
LInterruptCheckPar *lir =
|
||||
new(alloc()) LInterruptCheckPar(useRegister(ins->forkJoinContext()), temp());
|
||||
if (!add(lir, ins))
|
||||
return false;
|
||||
if (!assignSafepoint(lir, ins))
|
||||
|
@ -164,7 +164,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
bool visitForkJoinContext(MForkJoinContext *ins);
|
||||
bool visitGuardThreadExclusive(MGuardThreadExclusive *ins);
|
||||
bool visitInterruptCheck(MInterruptCheck *ins);
|
||||
bool visitCheckInterruptPar(MCheckInterruptPar *ins);
|
||||
bool visitInterruptCheckPar(MInterruptCheckPar *ins);
|
||||
bool visitStoreSlot(MStoreSlot *ins);
|
||||
bool visitTypeBarrier(MTypeBarrier *ins);
|
||||
bool visitMonitorTypes(MMonitorTypes *ins);
|
||||
|
@ -4747,9 +4747,9 @@ class MCheckOverRecursedPar : public MUnaryInstruction
|
||||
};
|
||||
|
||||
// Check for an interrupt (or rendezvous) in parallel mode.
|
||||
class MCheckInterruptPar : public MUnaryInstruction
|
||||
class MInterruptCheckPar : public MUnaryInstruction
|
||||
{
|
||||
MCheckInterruptPar(MDefinition *cx)
|
||||
MInterruptCheckPar(MDefinition *cx)
|
||||
: MUnaryInstruction(cx)
|
||||
{
|
||||
setResultType(MIRType_None);
|
||||
@ -4758,10 +4758,10 @@ class MCheckInterruptPar : public MUnaryInstruction
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(CheckInterruptPar);
|
||||
INSTRUCTION_HEADER(InterruptCheckPar);
|
||||
|
||||
static MCheckInterruptPar *New(TempAllocator &alloc, MDefinition *cx) {
|
||||
return new(alloc) MCheckInterruptPar(cx);
|
||||
static MInterruptCheckPar *New(TempAllocator &alloc, MDefinition *cx) {
|
||||
return new(alloc) MInterruptCheckPar(cx);
|
||||
}
|
||||
|
||||
MDefinition *forkJoinContext() const {
|
||||
|
@ -213,7 +213,7 @@ namespace jit {
|
||||
_(RestPar) \
|
||||
_(ForkJoinContext) \
|
||||
_(GuardThreadExclusive) \
|
||||
_(CheckInterruptPar) \
|
||||
_(InterruptCheckPar) \
|
||||
_(RecompileCheck)
|
||||
|
||||
// Forward declarations of MIR types.
|
||||
|
@ -208,11 +208,11 @@ jit::CheckOverRecursedPar(ForkJoinContext *cx)
|
||||
return false;
|
||||
}
|
||||
|
||||
return CheckInterruptPar(cx);
|
||||
return InterruptCheckPar(cx);
|
||||
}
|
||||
|
||||
bool
|
||||
jit::CheckInterruptPar(ForkJoinContext *cx)
|
||||
jit::InterruptCheckPar(ForkJoinContext *cx)
|
||||
{
|
||||
JS_ASSERT(ForkJoinContext::current() == cx);
|
||||
bool result = cx->check();
|
||||
|
@ -21,7 +21,7 @@ JSObject *NewGCThingPar(ForkJoinContext *cx, gc::AllocKind allocKind);
|
||||
bool ParallelWriteGuard(ForkJoinContext *cx, JSObject *object);
|
||||
bool IsInTargetRegion(ForkJoinContext *cx, TypedDatum *object);
|
||||
bool CheckOverRecursedPar(ForkJoinContext *cx);
|
||||
bool CheckInterruptPar(ForkJoinContext *cx);
|
||||
bool InterruptCheckPar(ForkJoinContext *cx);
|
||||
|
||||
// Extends the given array with `length` new holes. Returns nullptr on
|
||||
// failure or else `array`, which is convenient during code
|
||||
|
@ -291,7 +291,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
|
||||
UNSAFE_OP(In)
|
||||
UNSAFE_OP(InArray)
|
||||
SAFE_OP(GuardThreadExclusive)
|
||||
SAFE_OP(CheckInterruptPar)
|
||||
SAFE_OP(InterruptCheckPar)
|
||||
SAFE_OP(CheckOverRecursedPar)
|
||||
SAFE_OP(FunctionDispatch)
|
||||
SAFE_OP(TypeObjectDispatch)
|
||||
@ -746,7 +746,7 @@ ParallelSafetyVisitor::visitCheckOverRecursed(MCheckOverRecursed *ins)
|
||||
bool
|
||||
ParallelSafetyVisitor::visitInterruptCheck(MInterruptCheck *ins)
|
||||
{
|
||||
return replace(ins, MCheckInterruptPar::New(alloc(), ForkJoinContext()));
|
||||
return replace(ins, MInterruptCheckPar::New(alloc(), ForkJoinContext()));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -951,7 +951,7 @@ CodeGeneratorShared::labelForBackedgeWithImplicitCheck(MBasicBlock *mir)
|
||||
} else {
|
||||
// The interrupt check should be the first instruction in the
|
||||
// loop header other than the initial label and move groups.
|
||||
JS_ASSERT(iter->isInterruptCheck() || iter->isCheckInterruptPar());
|
||||
JS_ASSERT(iter->isInterruptCheck() || iter->isInterruptCheckPar());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -1019,6 +1019,10 @@ js_InvokeOperationCallback(JSContext *cx)
|
||||
js::gc::GCIfNeeded(cx);
|
||||
|
||||
#ifdef JS_ION
|
||||
#ifdef JS_THREADSAFE
|
||||
rt->interruptPar = false;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A worker thread may have set the callback after finishing an Ion
|
||||
* compilation.
|
||||
|
@ -174,7 +174,7 @@ ExecuteSequentially(JSContext *cx, HandleValue funVal)
|
||||
return false;
|
||||
args.setCallee(funVal);
|
||||
args.setThis(UndefinedValue());
|
||||
args[0].setBoolean(!!cx->runtime()->parallelWarmup);
|
||||
args[0].setBoolean(!!cx->runtime()->forkJoinWarmup);
|
||||
return fig.invoke(cx);
|
||||
}
|
||||
|
||||
@ -389,7 +389,7 @@ class ForkJoinShared : public ParallelJob, public Monitor
|
||||
void requestZoneGC(JS::Zone *zone, JS::gcreason::Reason reason);
|
||||
|
||||
// Requests that computation abort.
|
||||
void setAbortFlag(bool fatal);
|
||||
void setAbortFlagAndTriggerOperationCallback(bool fatal);
|
||||
|
||||
// Set the fatal flag for the next abort.
|
||||
void setPendingAbortFatal() { fatal_ = true; }
|
||||
@ -407,8 +407,8 @@ class AutoEnterWarmup
|
||||
JSRuntime *runtime_;
|
||||
|
||||
public:
|
||||
AutoEnterWarmup(JSRuntime *runtime) : runtime_(runtime) { runtime_->parallelWarmup++; }
|
||||
~AutoEnterWarmup() { runtime_->parallelWarmup--; }
|
||||
AutoEnterWarmup(JSRuntime *runtime) : runtime_(runtime) { runtime_->forkJoinWarmup++; }
|
||||
~AutoEnterWarmup() { runtime_->forkJoinWarmup--; }
|
||||
};
|
||||
|
||||
class AutoSetForkJoinContext
|
||||
@ -841,18 +841,8 @@ ForkJoinOperation::compileForParallelExecution(ExecutionStatus *status)
|
||||
}
|
||||
}
|
||||
|
||||
if (allScriptsPresent) {
|
||||
// For testing modes, we want to make sure that all off thread
|
||||
// compilation tasks are finished, so we don't race with
|
||||
// off-main-thread-compilation setting an interrupt flag while we
|
||||
// are in the middle of a test, causing unexpected bailouts.
|
||||
if (mode_ != ForkJoinModeNormal) {
|
||||
StopAllOffThreadCompilations(cx_->compartment());
|
||||
if (!js_HandleExecutionInterrupt(cx_))
|
||||
return fatalError(status);
|
||||
}
|
||||
if (allScriptsPresent)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Spew(SpewCompile, "Compilation complete (final worklist length %d)",
|
||||
@ -1406,7 +1396,7 @@ ForkJoinShared::execute()
|
||||
// Sometimes a GC request occurs *just before* we enter into the
|
||||
// parallel section. Rather than enter into the parallel section
|
||||
// and then abort, we just check here and abort early.
|
||||
if (cx_->runtime()->interrupt)
|
||||
if (cx_->runtime()->interruptPar)
|
||||
return TP_RETRY_SEQUENTIALLY;
|
||||
|
||||
AutoLockMonitor lock(*this);
|
||||
@ -1464,7 +1454,7 @@ ForkJoinShared::executeFromWorker(uint32_t workerId, uintptr_t stackLimit)
|
||||
{
|
||||
PerThreadData thisThread(cx_->runtime());
|
||||
if (!thisThread.init()) {
|
||||
setAbortFlag(true);
|
||||
setAbortFlagAndTriggerOperationCallback(true);
|
||||
return false;
|
||||
}
|
||||
TlsPerThreadData.set(&thisThread);
|
||||
@ -1526,7 +1516,7 @@ ForkJoinShared::executePortion(PerThreadData *perThread, uint32_t workerId)
|
||||
// and fallback.
|
||||
Spew(SpewOps, "Down (Script no longer present)");
|
||||
cx.bailoutRecord->setCause(ParallelBailoutMainScriptNotPresent);
|
||||
setAbortFlag(false);
|
||||
setAbortFlagAndTriggerOperationCallback(false);
|
||||
} else {
|
||||
ParallelIonInvoke<2> fii(cx_->runtime(), fun_, 1);
|
||||
|
||||
@ -1535,7 +1525,7 @@ ForkJoinShared::executePortion(PerThreadData *perThread, uint32_t workerId)
|
||||
bool ok = fii.invoke(perThread);
|
||||
JS_ASSERT(ok == !cx.bailoutRecord->topScript);
|
||||
if (!ok)
|
||||
setAbortFlag(false);
|
||||
setAbortFlagAndTriggerOperationCallback(false);
|
||||
}
|
||||
|
||||
Spew(SpewOps, "Down");
|
||||
@ -1544,7 +1534,7 @@ ForkJoinShared::executePortion(PerThreadData *perThread, uint32_t workerId)
|
||||
bool
|
||||
ForkJoinShared::check(ForkJoinContext &cx)
|
||||
{
|
||||
JS_ASSERT(cx_->runtime()->interrupt);
|
||||
JS_ASSERT(cx_->runtime()->interruptPar);
|
||||
|
||||
if (abort_)
|
||||
return false;
|
||||
@ -1555,14 +1545,14 @@ ForkJoinShared::check(ForkJoinContext &cx)
|
||||
if (cx.isMainThread() || !threadPool_->isMainThreadActive()) {
|
||||
JS_ASSERT(!cx_->runtime()->gcIsNeeded);
|
||||
|
||||
if (cx_->runtime()->interrupt) {
|
||||
if (cx_->runtime()->interruptPar) {
|
||||
// The GC Needed flag should not be set during parallel
|
||||
// execution. Instead, one of the requestGC() or
|
||||
// requestZoneGC() methods should be invoked.
|
||||
JS_ASSERT(!cx_->runtime()->gcIsNeeded);
|
||||
|
||||
cx.bailoutRecord->setCause(ParallelBailoutInterrupt);
|
||||
setAbortFlag(false);
|
||||
setAbortFlagAndTriggerOperationCallback(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1571,16 +1561,16 @@ ForkJoinShared::check(ForkJoinContext &cx)
|
||||
}
|
||||
|
||||
void
|
||||
ForkJoinShared::setAbortFlag(bool fatal)
|
||||
ForkJoinShared::setAbortFlagAndTriggerOperationCallback(bool fatal)
|
||||
{
|
||||
AutoLockMonitor lock(*this);
|
||||
|
||||
abort_ = true;
|
||||
fatal_ = fatal_ || fatal;
|
||||
|
||||
// Note: DontStopIon here avoids the expensive memory protection needed to
|
||||
// Note: The ForkJoin trigger here avoids the expensive memory protection needed to
|
||||
// interrupt Ion code compiled for sequential execution.
|
||||
cx_->runtime()->triggerOperationCallback(JSRuntime::TriggerCallbackAnyThreadDontStopIon);
|
||||
cx_->runtime()->triggerOperationCallback(JSRuntime::TriggerCallbackAnyThreadForkJoin);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1681,7 +1671,7 @@ ForkJoinContext::hasAcquiredJSContext() const
|
||||
bool
|
||||
ForkJoinContext::check()
|
||||
{
|
||||
if (runtime()->interrupt)
|
||||
if (runtime()->interruptPar)
|
||||
return shared->check(*this);
|
||||
else
|
||||
return true;
|
||||
@ -1692,7 +1682,7 @@ ForkJoinContext::requestGC(JS::gcreason::Reason reason)
|
||||
{
|
||||
shared->requestGC(reason);
|
||||
bailoutRecord->setCause(ParallelBailoutRequestedGC);
|
||||
shared->setAbortFlag(false);
|
||||
shared->setAbortFlagAndTriggerOperationCallback(false);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1700,7 +1690,7 @@ ForkJoinContext::requestZoneGC(JS::Zone *zone, JS::gcreason::Reason reason)
|
||||
{
|
||||
shared->requestZoneGC(zone, reason);
|
||||
bailoutRecord->setCause(ParallelBailoutRequestedZoneGC);
|
||||
shared->setAbortFlag(false);
|
||||
shared->setAbortFlagAndTriggerOperationCallback(false);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -2145,6 +2135,14 @@ js::ParallelTestsShouldPass(JSContext *cx)
|
||||
cx->runtime()->gcZeal() == 0;
|
||||
}
|
||||
|
||||
void
|
||||
js::TriggerOperationCallbackForForkJoin(JSRuntime *rt,
|
||||
JSRuntime::OperationCallbackTrigger trigger)
|
||||
{
|
||||
if (trigger != JSRuntime::TriggerCallbackAnyThreadDontStopIon)
|
||||
rt->interruptPar = true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intrinsic_SetForkJoinTargetRegion(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
|
@ -465,6 +465,9 @@ bool InExclusiveParallelSection();
|
||||
|
||||
bool ParallelTestsShouldPass(JSContext *cx);
|
||||
|
||||
void TriggerOperationCallbackForForkJoin(JSRuntime *rt,
|
||||
JSRuntime::OperationCallbackTrigger trigger);
|
||||
|
||||
bool intrinsic_SetForkJoinTargetRegion(JSContext *cx, unsigned argc, Value *vp);
|
||||
extern const JSJitInfo intrinsic_SetForkJoinTargetRegionInfo;
|
||||
|
||||
|
@ -120,6 +120,9 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
|
||||
),
|
||||
mainThread(this),
|
||||
interrupt(0),
|
||||
#if defined(JS_THREADSAFE) && defined(JS_ION)
|
||||
interruptPar(false),
|
||||
#endif
|
||||
handlingSignal(false),
|
||||
operationCallback(nullptr),
|
||||
#ifdef JS_THREADSAFE
|
||||
@ -293,7 +296,7 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
|
||||
threadPool(this),
|
||||
defaultJSContextCallback(nullptr),
|
||||
ctypesActivityCallback(nullptr),
|
||||
parallelWarmup(0),
|
||||
forkJoinWarmup(0),
|
||||
ionReturnOverride_(MagicValue(JS_ARG_POISON)),
|
||||
useHelperThreads_(useHelperThreads),
|
||||
parallelIonCompilationEnabled_(true),
|
||||
@ -654,6 +657,10 @@ JSRuntime::triggerOperationCallback(OperationCallbackTrigger trigger)
|
||||
interrupt = 1;
|
||||
|
||||
#ifdef JS_ION
|
||||
#ifdef JS_THREADSAFE
|
||||
TriggerOperationCallbackForForkJoin(this, trigger);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* asm.js and, optionally, normal Ion code use memory protection and signal
|
||||
* handlers to halt running code.
|
||||
|
@ -689,6 +689,15 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||
int32_t interrupt;
|
||||
#endif
|
||||
|
||||
#if defined(JS_THREADSAFE) && defined(JS_ION)
|
||||
/*
|
||||
* If non-zero, ForkJoin should service an interrupt. This is a separate
|
||||
* flag from |interrupt| because we cannot use the mprotect trick with PJS
|
||||
* code and ignore the TriggerCallbackAnyThreadDontStopIon trigger.
|
||||
*/
|
||||
mozilla::Atomic<bool, mozilla::Relaxed> interruptPar;
|
||||
#endif
|
||||
|
||||
/* Set when handling a signal for a thread associated with this runtime. */
|
||||
bool handlingSignal;
|
||||
|
||||
@ -1627,9 +1636,9 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||
|
||||
js::CTypesActivityCallback ctypesActivityCallback;
|
||||
|
||||
// Non-zero if this is a parallel warmup execution. See
|
||||
// js::parallel::Do() for more information.
|
||||
uint32_t parallelWarmup;
|
||||
// Non-zero if this is a ForkJoin warmup execution. See
|
||||
// js::ForkJoin() for more information.
|
||||
uint32_t forkJoinWarmup;
|
||||
|
||||
private:
|
||||
// In certain cases, we want to optimize certain opcodes to typed instructions,
|
||||
@ -1722,7 +1731,8 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||
enum OperationCallbackTrigger {
|
||||
TriggerCallbackMainThread,
|
||||
TriggerCallbackAnyThread,
|
||||
TriggerCallbackAnyThreadDontStopIon
|
||||
TriggerCallbackAnyThreadDontStopIon,
|
||||
TriggerCallbackAnyThreadForkJoin
|
||||
};
|
||||
|
||||
void triggerOperationCallback(OperationCallbackTrigger trigger);
|
||||
|
@ -605,7 +605,7 @@ js::intrinsic_ShouldForceSequential(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
#ifdef JS_THREADSAFE
|
||||
args.rval().setBoolean(cx->runtime()->parallelWarmup ||
|
||||
args.rval().setBoolean(cx->runtime()->forkJoinWarmup ||
|
||||
InParallelSection());
|
||||
#else
|
||||
args.rval().setBoolean(true);
|
||||
|
Loading…
Reference in New Issue
Block a user