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