--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -8487,17 +8487,17 @@ GenerateFFIIonExit(ModuleCompiler &m, co
masm.loadPtr(Address(callee, offsetof(AsmJSModule::ExitDatum, fun)), callee);
// 2.3. Save callee
masm.storePtr(callee, Address(StackPointer, argOffset));
argOffset += sizeof(size_t);
// 2.4. Load callee executable entry point
masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
- masm.loadBaselineOrIonNoArgCheck(callee, callee, SequentialExecution, nullptr);
+ masm.loadBaselineOrIonNoArgCheck(callee, callee, nullptr);
// 3. Argc
unsigned argc = exit.sig().args().length();
masm.storePtr(ImmWord(uintptr_t(argc)), Address(StackPointer, argOffset));
argOffset += sizeof(size_t);
// 4. |this| value
masm.storeValue(UndefinedValue(), Address(StackPointer, argOffset));
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -180,18 +180,17 @@ Zone::discardJitCode(FreeOp *fop)
/* Mark baseline scripts on the stack as active. */
jit::MarkActiveBaselineScripts(this);
/* Only mark OSI points if code is being discarded. */
jit::InvalidateAll(fop, this);
for (ZoneCellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
- jit::FinishInvalidation<SequentialExecution>(fop, script);
- jit::FinishInvalidation<ParallelExecution>(fop, script);
+ jit::FinishInvalidation(fop, script);
/*
* Discard baseline script if it's not marked as active. Note that
* this also resets the active flag.
*/
jit::FinishDiscardBaselineScript(fop, script);
/*
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -4256,30 +4256,30 @@ ICGetElemNativeCompiler::emitCallScripte
masm.Push(Imm32(0)); // ActualArgc is 0
masm.Push(callee);
masm.Push(callScratch);
regs.add(callScratch);
}
Register code = regs.takeAnyExcluding(ArgumentsRectifierReg);
masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), code);
- masm.loadBaselineOrIonRaw(code, code, SequentialExecution, nullptr);
+ masm.loadBaselineOrIonRaw(code, code, nullptr);
Register scratch = regs.takeAny();
// Handle arguments underflow.
Label noUnderflow;
masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), scratch);
masm.branch32(Assembler::Equal, scratch, Imm32(0), &noUnderflow);
{
// Call the arguments rectifier.
MOZ_ASSERT(ArgumentsRectifierReg != code);
JitCode *argumentsRectifier =
- cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
+ cx->runtime()->jitRuntime()->getArgumentsRectifier();
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
masm.mov(ImmWord(0), ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
@@ -4489,18 +4489,17 @@ ICGetElemNativeCompiler::generateStubCod
} else {
MOZ_ASSERT(acctype_ == ICGetElemNativeStub::ScriptedGetter);
// Load function in scratchReg and ensure that it has a jit script.
masm.loadPtr(Address(BaselineStubReg, ICGetElemNativeGetterStub::offsetOfGetter()),
scratchReg);
masm.branchIfFunctionHasNoScript(scratchReg, popR1 ? &failurePopR1 : &failure);
masm.loadPtr(Address(scratchReg, JSFunction::offsetOfNativeOrScript()), scratchReg);
- masm.loadBaselineOrIonRaw(scratchReg, scratchReg, SequentialExecution,
- popR1 ? &failurePopR1 : &failure);
+ masm.loadBaselineOrIonRaw(scratchReg, scratchReg, popR1 ? &failurePopR1 : &failure);
// At this point, we are guaranteed to successfully complete.
if (popR1)
masm.addPtr(Imm32(sizeof(size_t)), BaselineStackReg);
emitCallScripted(masm, objReg);
}
}
@@ -7416,17 +7415,17 @@ ICGetProp_CallScripted::Compiler::genera
regs.take(callee);
} else {
callee = regs.takeAny();
}
Register code = regs.takeAny();
masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallScripted::offsetOfGetter()), callee);
masm.branchIfFunctionHasNoScript(callee, &failureLeaveStubFrame);
masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), code);
- masm.loadBaselineOrIonRaw(code, code, SequentialExecution, &failureLeaveStubFrame);
+ masm.loadBaselineOrIonRaw(code, code, &failureLeaveStubFrame);
// Getter is called with 0 arguments, just |obj| as thisv.
// Note that we use Push, not push, so that callJit will align the stack
// properly on ARM.
masm.Push(R0);
EmitCreateStubFrameDescriptor(masm, scratch);
masm.Push(Imm32(0)); // ActualArgc is 0
masm.Push(callee);
@@ -7436,17 +7435,17 @@ ICGetProp_CallScripted::Compiler::genera
Label noUnderflow;
masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), scratch);
masm.branch32(Assembler::Equal, scratch, Imm32(0), &noUnderflow);
{
// Call the arguments rectifier.
MOZ_ASSERT(ArgumentsRectifierReg != code);
JitCode *argumentsRectifier =
- cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
+ cx->runtime()->jitRuntime()->getArgumentsRectifier();
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
masm.mov(ImmWord(0), ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
@@ -8788,17 +8787,17 @@ ICSetProp_CallScripted::Compiler::genera
regs.take(callee);
} else {
callee = regs.takeAny();
}
Register code = regs.takeAny();
masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallScripted::offsetOfSetter()), callee);
masm.branchIfFunctionHasNoScript(callee, &failureLeaveStubFrame);
masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), code);
- masm.loadBaselineOrIonRaw(code, code, SequentialExecution, &failureLeaveStubFrame);
+ masm.loadBaselineOrIonRaw(code, code, &failureLeaveStubFrame);
// Setter is called with the new value as the only argument, and |obj| as thisv.
// Note that we use Push, not push, so that callJit will align the stack
// properly on ARM.
// To Push R1, read it off of the stowed values on stack.
// Stack: [ ..., R0, R1, ..STUBFRAME-HEADER.. ]
masm.movePtr(BaselineStackReg, scratch);
@@ -8813,17 +8812,17 @@ ICSetProp_CallScripted::Compiler::genera
Label noUnderflow;
masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), scratch);
masm.branch32(Assembler::BelowOrEqual, scratch, Imm32(1), &noUnderflow);
{
// Call the arguments rectifier.
MOZ_ASSERT(ArgumentsRectifierReg != code);
JitCode *argumentsRectifier =
- cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
+ cx->runtime()->jitRuntime()->getArgumentsRectifier();
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
masm.mov(ImmWord(1), ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
@@ -9755,17 +9754,17 @@ ICCallStubCompiler::guardFunApply(MacroA
failure);
if (checkNative) {
masm.branchIfInterpreted(target, failure);
} else {
masm.branchIfFunctionHasNoScript(target, failure);
Register temp = regs.takeAny();
masm.loadPtr(Address(target, JSFunction::offsetOfNativeOrScript()), temp);
- masm.loadBaselineOrIonRaw(temp, temp, SequentialExecution, failure);
+ masm.loadBaselineOrIonRaw(temp, temp, failure);
regs.add(temp);
}
return target;
}
void
ICCallStubCompiler::pushCallerArguments(MacroAssembler &masm, GeneralRegisterSet regs)
{
@@ -9990,17 +9989,17 @@ ICCallScriptedCompiler::generateStubCode
masm.branchIfFunctionHasNoScript(callee, &failure);
masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
}
// Load the start of the target JitCode.
Register code;
if (!isConstructing_) {
code = regs.takeAny();
- masm.loadBaselineOrIonRaw(callee, code, SequentialExecution, &failure);
+ masm.loadBaselineOrIonRaw(callee, code, &failure);
} else {
Address scriptCode(callee, JSScript::offsetOfBaselineOrIonRaw());
masm.branchPtr(Assembler::Equal, scriptCode, ImmPtr(nullptr), &failure);
}
// We no longer need R1.
regs.add(R1);
@@ -10074,17 +10073,17 @@ ICCallScriptedCompiler::generateStubCode
masm.loadValue(calleeSlot3, R0);
}
callee = masm.extractObject(R0, ExtractTemp0);
regs.add(R0);
regs.takeUnchecked(callee);
masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
code = regs.takeAny();
- masm.loadBaselineOrIonRaw(callee, code, SequentialExecution, &failureLeaveStubFrame);
+ masm.loadBaselineOrIonRaw(callee, code, &failureLeaveStubFrame);
// Release callee register, but don't add ExtractTemp0 back into the pool
// ExtractTemp0 is used later, and if it's allocated to some other register at that
// point, it will get clobbered when used.
if (callee != ExtractTemp0)
regs.add(callee);
if (canUseTailCallReg)
@@ -10118,17 +10117,17 @@ ICCallScriptedCompiler::generateStubCode
masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), callee);
masm.branch32(Assembler::AboveOrEqual, argcReg, callee, &noUnderflow);
{
// Call the arguments rectifier.
MOZ_ASSERT(ArgumentsRectifierReg != code);
MOZ_ASSERT(ArgumentsRectifierReg != argcReg);
JitCode *argumentsRectifier =
- cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
+ cx->runtime()->jitRuntime()->getArgumentsRectifier();
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
masm.mov(argcReg, ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
@@ -10595,28 +10594,28 @@ ICCall_ScriptedApplyArray::Compiler::gen
masm.Push(argcReg);
masm.Push(target);
masm.Push(scratch);
// Load nargs into scratch for underflow check, and then load jitcode pointer into target.
masm.load16ZeroExtend(Address(target, JSFunction::offsetOfNargs()), scratch);
masm.loadPtr(Address(target, JSFunction::offsetOfNativeOrScript()), target);
- masm.loadBaselineOrIonRaw(target, target, SequentialExecution, nullptr);
+ masm.loadBaselineOrIonRaw(target, target, nullptr);
// Handle arguments underflow.
Label noUnderflow;
masm.branch32(Assembler::AboveOrEqual, argcReg, scratch, &noUnderflow);
{
// Call the arguments rectifier.
MOZ_ASSERT(ArgumentsRectifierReg != target);
MOZ_ASSERT(ArgumentsRectifierReg != argcReg);
JitCode *argumentsRectifier =
- cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
+ cx->runtime()->jitRuntime()->getArgumentsRectifier();
masm.movePtr(ImmGCPtr(argumentsRectifier), target);
masm.loadPtr(Address(target, JitCode::offsetOfCode()), target);
masm.mov(argcReg, ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
regs.add(argcReg);
@@ -10696,28 +10695,28 @@ ICCall_ScriptedApplyArguments::Compiler:
masm.loadPtr(Address(argcReg, BaselineFrame::offsetOfNumActualArgs()), argcReg);
masm.Push(argcReg);
masm.Push(target);
masm.Push(scratch);
// Load nargs into scratch for underflow check, and then load jitcode pointer into target.
masm.load16ZeroExtend(Address(target, JSFunction::offsetOfNargs()), scratch);
masm.loadPtr(Address(target, JSFunction::offsetOfNativeOrScript()), target);
- masm.loadBaselineOrIonRaw(target, target, SequentialExecution, nullptr);
+ masm.loadBaselineOrIonRaw(target, target, nullptr);
// Handle arguments underflow.
Label noUnderflow;
masm.branch32(Assembler::AboveOrEqual, argcReg, scratch, &noUnderflow);
{
// Call the arguments rectifier.
MOZ_ASSERT(ArgumentsRectifierReg != target);
MOZ_ASSERT(ArgumentsRectifierReg != argcReg);
JitCode *argumentsRectifier =
- cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
+ cx->runtime()->jitRuntime()->getArgumentsRectifier();
masm.movePtr(ImmGCPtr(argumentsRectifier), target);
masm.loadPtr(Address(target, JitCode::offsetOfCode()), target);
masm.mov(argcReg, ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
regs.add(argcReg);
@@ -10776,17 +10775,17 @@ ICCall_ScriptedFunCall::Compiler::genera
masm.branchTestObjClass(Assembler::NotEqual, callee, regs.getAny(), &JSFunction::class_,
&failure);
masm.branchIfFunctionHasNoScript(callee, &failure);
masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
// Load the start of the target JitCode.
Register code = regs.takeAny();
- masm.loadBaselineOrIonRaw(callee, code, SequentialExecution, &failure);
+ masm.loadBaselineOrIonRaw(callee, code, &failure);
// We no longer need R1.
regs.add(R1);
// Push a stub frame so that we can perform a non-tail call.
enterStubFrame(masm, regs.getAny());
if (canUseTailCallReg)
regs.add(BaselineTailCallReg);
@@ -10829,17 +10828,17 @@ ICCall_ScriptedFunCall::Compiler::genera
masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), callee);
masm.branch32(Assembler::AboveOrEqual, argcReg, callee, &noUnderflow);
{
// Call the arguments rectifier.
MOZ_ASSERT(ArgumentsRectifierReg != code);
MOZ_ASSERT(ArgumentsRectifierReg != argcReg);
JitCode *argumentsRectifier =
- cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
+ cx->runtime()->jitRuntime()->getArgumentsRectifier();
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
masm.mov(argcReg, ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -26,20 +26,17 @@
#include "jit/IonCaches.h"
#include "jit/IonOptimizationLevels.h"
#include "jit/JitcodeMap.h"
#include "jit/JitSpewer.h"
#include "jit/Linker.h"
#include "jit/Lowering.h"
#include "jit/MIRGenerator.h"
#include "jit/MoveEmitter.h"
-#include "jit/ParallelFunctions.h"
-#include "jit/ParallelSafetyAnalysis.h"
#include "jit/RangeAnalysis.h"
-#include "vm/ForkJoin.h"
#include "vm/MatchPairs.h"
#include "vm/RegExpStatics.h"
#include "vm/TraceLogging.h"
#include "jsboolinlines.h"
#include "jit/ExecutionMode-inl.h"
#include "jit/shared/CodeGenerator-shared-inl.h"
@@ -162,20 +159,17 @@ CodeGenerator::CodeGenerator(MIRGenerato
CodeGenerator::~CodeGenerator()
{
MOZ_ASSERT_IF(!gen->compilingAsmJS(), masm.numAsmJSAbsoluteLinks() == 0);
js_delete(scriptCounts_);
}
typedef bool (*StringToNumberFn)(ThreadSafeContext *, JSString *, double *);
-typedef bool (*StringToNumberParFn)(ForkJoinContext *, JSString *, double *);
-static const VMFunctionsModal StringToNumberInfo = VMFunctionsModal(
- FunctionInfo<StringToNumberFn>(StringToNumber),
- FunctionInfo<StringToNumberParFn>(StringToNumberPar));
+static const VMFunction StringToNumberInfo = FunctionInfo<StringToNumberFn>(StringToNumber);
void
CodeGenerator::visitValueToInt32(LValueToInt32 *lir)
{
ValueOperand operand = ToValue(lir, LValueToInt32::Input);
Register output = ToRegister(lir->output());
FloatRegister temp = ToFloatRegister(lir->tempFloat());
@@ -816,40 +810,34 @@ CodeGenerator::emitIntToString(Register
masm.branch32(Assembler::AboveOrEqual, input, Imm32(StaticStrings::INT_STATIC_LIMIT), ool);
// Fast path for small integers.
masm.movePtr(ImmPtr(&GetJitContext()->runtime->staticStrings().intStaticTable), output);
masm.loadPtr(BaseIndex(output, input, ScalePointer), output);
}
typedef JSFlatString *(*IntToStringFn)(ThreadSafeContext *, int);
-typedef JSFlatString *(*IntToStringParFn)(ForkJoinContext *, int);
-static const VMFunctionsModal IntToStringInfo = VMFunctionsModal(
- FunctionInfo<IntToStringFn>(Int32ToString<CanGC>),
- FunctionInfo<IntToStringParFn>(IntToStringPar));
+static const VMFunction IntToStringInfo = FunctionInfo<IntToStringFn>(Int32ToString<CanGC>);
void
CodeGenerator::visitIntToString(LIntToString *lir)
{
Register input = ToRegister(lir->input());
Register output = ToRegister(lir->output());
OutOfLineCode *ool = oolCallVM(IntToStringInfo, lir, (ArgList(), input),
StoreRegisterTo(output));
emitIntToString(input, output, ool->entry());
masm.bind(ool->rejoin());
}
typedef JSString *(*DoubleToStringFn)(ThreadSafeContext *, double);
-typedef JSString *(*DoubleToStringParFn)(ForkJoinContext *, double);
-static const VMFunctionsModal DoubleToStringInfo = VMFunctionsModal(
- FunctionInfo<DoubleToStringFn>(NumberToString<CanGC>),
- FunctionInfo<DoubleToStringParFn>(DoubleToStringPar));
+static const VMFunction DoubleToStringInfo = FunctionInfo<DoubleToStringFn>(NumberToString<CanGC>);
void
CodeGenerator::visitDoubleToString(LDoubleToString *lir)
{
FloatRegister input = ToFloatRegister(lir->input());
Register temp = ToRegister(lir->tempInt());
Register output = ToRegister(lir->output());
@@ -859,20 +847,17 @@ CodeGenerator::visitDoubleToString(LDoub
// Try double to integer conversion and run integer to string code.
masm.convertDoubleToInt32(input, temp, ool->entry(), true);
emitIntToString(temp, output, ool->entry());
masm.bind(ool->rejoin());
}
typedef JSString *(*PrimitiveToStringFn)(JSContext *, HandleValue);
-typedef JSString *(*PrimitiveToStringParFn)(ForkJoinContext *, HandleValue);
-static const VMFunctionsModal PrimitiveToStringInfo = VMFunctionsModal(
- FunctionInfo<PrimitiveToStringFn>(ToStringSlow),
- FunctionInfo<PrimitiveToStringParFn>(PrimitiveToStringPar));
+static const VMFunction PrimitiveToStringInfo = FunctionInfo<PrimitiveToStringFn>(ToStringSlow);
void
CodeGenerator::visitValueToString(LValueToString *lir)
{
ValueOperand input = ToValue(lir, LValueToString::Input);
Register output = ToRegister(lir->output());
OutOfLineCode *ool = oolCallVM(PrimitiveToStringInfo, lir, (ArgList(), input),
@@ -1761,32 +1746,16 @@ CodeGenerator::emitLambdaInit(Register o
masm.store32(Imm32(u.word), Address(output, JSFunction::offsetOfNargs()));
masm.storePtr(ImmGCPtr(info.scriptOrLazyScript),
Address(output, JSFunction::offsetOfNativeOrScript()));
masm.storePtr(scopeChain, Address(output, JSFunction::offsetOfEnvironment()));
masm.storePtr(ImmGCPtr(info.fun->displayAtom()), Address(output, JSFunction::offsetOfAtom()));
}
void
-CodeGenerator::visitLambdaPar(LLambdaPar *lir)
-{
- Register resultReg = ToRegister(lir->output());
- Register cxReg = ToRegister(lir->forkJoinContext());
- Register scopeChainReg = ToRegister(lir->scopeChain());
- Register tempReg1 = ToRegister(lir->getTemp0());
- Register tempReg2 = ToRegister(lir->getTemp1());
- const LambdaFunctionInfo &info = lir->mir()->info();
-
- MOZ_ASSERT(scopeChainReg != resultReg);
-
- emitAllocateGCThingPar(lir, resultReg, cxReg, tempReg1, tempReg2, info.fun);
- emitLambdaInit(resultReg, scopeChainReg, info);
-}
-
-void
CodeGenerator::visitLabel(LLabel *lir)
{
}
void
CodeGenerator::visitNop(LNop *lir)
{
}
@@ -1848,20 +1817,17 @@ class OutOfLineInterruptCheckImplicit :
{ }
void accept(CodeGenerator *codegen) {
codegen->visitOutOfLineInterruptCheckImplicit(this);
}
};
typedef bool (*InterruptCheckFn)(JSContext *);
-typedef bool (*InterruptCheckParFn)(ForkJoinContext *);
-static const VMFunctionsModal InterruptCheckInfo = VMFunctionsModal(
- FunctionInfo<InterruptCheckFn>(InterruptCheck),
- FunctionInfo<InterruptCheckParFn>(InterruptCheckPar));
+static const VMFunction InterruptCheckInfo = FunctionInfo<InterruptCheckFn>(InterruptCheck);
void
CodeGenerator::visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit *ool)
{
#ifdef CHECK_OSIPOINT_REGISTERS
// This is path is entered from the patched back-edge of the loop. This
// means that the JitAtivation flags used for checking the validity of the
// OSI points are not reseted by the path generated by generateBody, so we
@@ -2016,20 +1982,18 @@ CodeGenerator::visitReturn(LReturn *lir)
void
CodeGenerator::visitOsrEntry(LOsrEntry *lir)
{
// Remember the OSR entry offset into the code buffer.
masm.flushBuffer();
setOsrEntryOffset(masm.size());
#ifdef JS_TRACE_LOGGING
- if (gen->info().executionMode() == SequentialExecution) {
- emitTracelogStopEvent(TraceLogger_Baseline);
- emitTracelogStartEvent(TraceLogger_IonMonkey);
- }
+ emitTracelogStopEvent(TraceLogger_Baseline);
+ emitTracelogStartEvent(TraceLogger_IonMonkey);
#endif
// Allocate the full frame for this function
// Note we have a new entry here. So we reset MacroAssembler::framePushed()
// to 0, before reserving the stack.
MOZ_ASSERT(masm.framePushed() == frameSize());
masm.setFramePushed(0);
masm.reserveStack(frameSize());
@@ -2448,40 +2412,16 @@ CodeGenerator::visitMaybeCopyElementsFor
void
CodeGenerator::visitFunctionEnvironment(LFunctionEnvironment *lir)
{
Address environment(ToRegister(lir->function()), JSFunction::offsetOfEnvironment());
masm.loadPtr(environment, ToRegister(lir->output()));
}
void
-CodeGenerator::visitForkJoinContext(LForkJoinContext *lir)
-{
- const Register tempReg = ToRegister(lir->getTempReg());
-
- masm.setupUnalignedABICall(0, tempReg);
- masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ForkJoinContextPar));
- MOZ_ASSERT(ToRegister(lir->output()) == ReturnReg);
-}
-
-void
-CodeGenerator::visitGuardThreadExclusive(LGuardThreadExclusive *lir)
-{
- MOZ_ASSERT(gen->info().executionMode() == ParallelExecution);
-
- const Register tempReg = ToRegister(lir->getTempReg());
- masm.setupUnalignedABICall(2, tempReg);
- masm.passABIArg(ToRegister(lir->forkJoinContext()));
- masm.passABIArg(ToRegister(lir->object()));
- masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ParallelWriteGuard));
-
- bailoutIfFalseBool(ReturnReg, lir->snapshot());
-}
-
-void
CodeGenerator::visitGuardObjectIdentity(LGuardObjectIdentity *guard)
{
Register obj = ToRegister(guard->input());
Assembler::Condition cond =
guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
bailoutCmpPtr(cond, obj, ImmGCPtr(guard->mir()->singleObject()), guard->snapshot());
}
@@ -2664,71 +2604,51 @@ CodeGenerator::visitCallNative(LCallNati
// Misc. temporary registers.
const Register tempReg = ToRegister(call->getTempReg());
DebugOnly<uint32_t> initialStack = masm.framePushed();
masm.checkStackAlignment();
- // Sequential native functions have the signature:
+ // Native functions have the signature:
// bool (*)(JSContext *, unsigned, Value *vp)
- // and parallel native functions have the signature:
- // ParallelResult (*)(ForkJoinContext *, unsigned, Value *vp)
// Where vp[0] is space for an outparam, vp[1] is |this|, and vp[2] onward
// are the function arguments.
// Allocate space for the outparam, moving the StackPointer to what will be &vp[1].
masm.adjustStack(unusedStack);
// Push a Value containing the callee object: natives are allowed to access their callee before
// setitng the return value. The StackPointer is moved to &vp[0].
masm.Push(ObjectValue(*target));
// Preload arguments into registers.
- //
- // Note that for parallel execution, loadContext does an ABI call, so we
- // need to do this before we load the other argument registers, otherwise
- // we'll hose them.
- ExecutionMode executionMode = gen->info().executionMode();
- masm.loadContext(argContextReg, tempReg, executionMode);
+ masm.loadJSContext(argContextReg);
masm.move32(Imm32(call->numStackArgs()), argUintNReg);
masm.movePtr(StackPointer, argVpReg);
masm.Push(argUintNReg);
// Construct native exit frame.
uint32_t safepointOffset;
masm.buildFakeExitFrame(tempReg, &safepointOffset);
- masm.enterFakeExitFrame(argContextReg, tempReg, executionMode,
- NativeExitFrameLayout::Token());
+ masm.enterFakeExitFrame(NativeExitFrameLayout::Token());
markSafepointAt(safepointOffset, call);
// Construct and execute call.
masm.setupUnalignedABICall(3, tempReg);
masm.passABIArg(argContextReg);
masm.passABIArg(argUintNReg);
masm.passABIArg(argVpReg);
-
- switch (executionMode) {
- case SequentialExecution:
- masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, target->native()));
- break;
-
- case ParallelExecution:
- masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, target->parallelNative()));
- break;
-
- default:
- MOZ_CRASH("No such execution mode");
- }
+ masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, target->native()));
// Test for failure.
- masm.branchIfFalseBool(ReturnReg, masm.failureLabel(executionMode));
+ masm.branchIfFalseBool(ReturnReg, masm.failureLabel());
// Load the outparam vp[0] into output register(s).
masm.loadValue(Address(StackPointer, NativeExitFrameLayout::offsetOfResult()), JSReturnOperand);
// The next instruction is removing the footer of the exit frame, so there
// is no need for leaveFakeExitFrame.
// Move the StackPointer back to its original location, unwinding the native exit frame.
@@ -2903,24 +2823,23 @@ CodeGenerator::emitCallInvokeFunction(LI
void
CodeGenerator::visitCallGeneric(LCallGeneric *call)
{
Register calleereg = ToRegister(call->getFunction());
Register objreg = ToRegister(call->getTempObject());
Register nargsreg = ToRegister(call->getNargsReg());
uint32_t unusedStack = StackOffsetOfPassedArg(call->argslot());
- ExecutionMode executionMode = gen->info().executionMode();
Label invoke, thunk, makeCall, end;
// Known-target case is handled by LCallKnown.
MOZ_ASSERT(!call->hasSingleTarget());
// Generate an ArgumentsRectifier.
- JitCode *argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier(executionMode);
+ JitCode *argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier();
masm.checkStackAlignment();
// Guard that calleereg is actually a function object.
masm.loadObjClass(calleereg, nargsreg);
masm.branchPtr(Assembler::NotEqual, nargsreg, ImmPtr(&JSFunction::class_), &invoke);
// Guard that calleereg is an interpreted function with a JSScript.
@@ -2929,17 +2848,17 @@ CodeGenerator::visitCallGeneric(LCallGen
masm.branchIfNotInterpretedConstructor(calleereg, nargsreg, &invoke);
else
masm.branchIfFunctionHasNoScript(calleereg, &invoke);
// Knowing that calleereg is a non-native function, load the JSScript.
masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
// Load script jitcode.
- masm.loadBaselineOrIonRaw(objreg, objreg, executionMode, &invoke);
+ masm.loadBaselineOrIonRaw(objreg, objreg, &invoke);
// Nestle the StackPointer up to the argument vector.
masm.freeStack(unusedStack);
// Construct the IonFramePrefix.
uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS);
masm.Push(Imm32(call->numActualArgs()));
masm.PushCalleeToken(calleereg, call->mir()->isConstructing());
@@ -2967,65 +2886,39 @@ CodeGenerator::visitCallGeneric(LCallGen
// Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
// The return address has already been removed from the Ion frame.
int prefixGarbage = sizeof(JitFrameLayout) - sizeof(void *);
masm.adjustStack(prefixGarbage - unusedStack);
masm.jump(&end);
// Handle uncompiled or native functions.
masm.bind(&invoke);
- switch (executionMode) {
- case SequentialExecution:
- emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack);
- break;
-
- case ParallelExecution:
- emitCallToUncompiledScriptPar(call, calleereg);
- break;
-
- default:
- MOZ_CRASH("No such execution mode");
- }
+ emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack);
masm.bind(&end);
// If the return value of the constructing function is Primitive,
// replace the return value with the Object from CreateThis.
if (call->mir()->isConstructing()) {
Label notPrimitive;
masm.branchTestPrimitive(Assembler::NotEqual, JSReturnOperand, ¬Primitive);
masm.loadValue(Address(StackPointer, unusedStack), JSReturnOperand);
masm.bind(¬Primitive);
}
dropArguments(call->numStackArgs() + 1);
}
-typedef bool (*CallToUncompiledScriptParFn)(ForkJoinContext *, JSObject *);
-static const VMFunction CallToUncompiledScriptParInfo =
- FunctionInfo<CallToUncompiledScriptParFn>(CallToUncompiledScriptPar);
-
-// Generates a call to CallToUncompiledScriptPar() and then bails out.
-// |calleeReg| should contain the JSFunction*.
-void
-CodeGenerator::emitCallToUncompiledScriptPar(LInstruction *lir, Register calleeReg)
-{
- pushArg(calleeReg);
- callVM(CallToUncompiledScriptParInfo, lir);
- masm.assumeUnreachable("CallToUncompiledScriptParInfo always returns false.");
-}
-
void
CodeGenerator::visitCallKnown(LCallKnown *call)
{
Register calleereg = ToRegister(call->getFunction());
Register objreg = ToRegister(call->getTempObject());
uint32_t unusedStack = StackOffsetOfPassedArg(call->argslot());
DebugOnly<JSFunction *> target = call->getSingleTarget();
- ExecutionMode executionMode = gen->info().executionMode();
Label end, uncompiled;
// Native single targets are handled by LCallNative.
MOZ_ASSERT(!target->isNative());
// Missing arguments must have been explicitly appended by the IonBuilder.
MOZ_ASSERT(target->nargs() <= call->numStackArgs());
MOZ_ASSERT_IF(call->mir()->isConstructing(), target->isInterpretedConstructor());
@@ -3036,19 +2929,19 @@ CodeGenerator::visitCallKnown(LCallKnown
// a LazyScript instead of a JSScript.
masm.branchIfFunctionHasNoScript(calleereg, &uncompiled);
// Knowing that calleereg is a non-native function, load the JSScript.
masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
// Load script jitcode.
if (call->mir()->needsArgCheck())
- masm.loadBaselineOrIonRaw(objreg, objreg, executionMode, &uncompiled);
+ masm.loadBaselineOrIonRaw(objreg, objreg, &uncompiled);
else
- masm.loadBaselineOrIonNoArgCheck(objreg, objreg, executionMode, &uncompiled);
+ masm.loadBaselineOrIonNoArgCheck(objreg, objreg, &uncompiled);
// Nestle the StackPointer up to the argument vector.
masm.freeStack(unusedStack);
// Construct the IonFramePrefix.
uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS);
masm.Push(Imm32(call->numActualArgs()));
masm.PushCalleeToken(calleereg, call->mir()->isConstructing());
@@ -3061,28 +2954,17 @@ CodeGenerator::visitCallKnown(LCallKnown
// Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
// The return address has already been removed from the Ion frame.
int prefixGarbage = sizeof(JitFrameLayout) - sizeof(void *);
masm.adjustStack(prefixGarbage - unusedStack);
masm.jump(&end);
// Handle uncompiled functions.
masm.bind(&uncompiled);
- switch (executionMode) {
- case SequentialExecution:
- emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack);
- break;
-
- case ParallelExecution:
- emitCallToUncompiledScriptPar(call, calleereg);
- break;
-
- default:
- MOZ_CRASH("No such execution mode");
- }
+ emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack);
masm.bind(&end);
// If the return value of the constructing function is Primitive,
// replace the return value with the Object from CreateThis.
if (call->mir()->isConstructing()) {
Label notPrimitive;
masm.branchTestPrimitive(Assembler::NotEqual, JSReturnOperand, ¬Primitive);
@@ -3195,17 +3077,16 @@ CodeGenerator::visitApplyArgsGeneric(LAp
}
// Copy the arguments of the current function.
emitPushArguments(apply, copyreg);
masm.checkStackAlignment();
// If the function is known to be uncompilable, only emit the call to InvokeFunction.
- ExecutionMode executionMode = gen->info().executionMode();
if (apply->hasSingleTarget()) {
JSFunction *target = apply->getSingleTarget();
if (target->isNative()) {
emitCallInvokeFunction(apply, copyreg);
emitPopArguments(apply, copyreg);
return;
}
}
@@ -3219,17 +3100,17 @@ CodeGenerator::visitApplyArgsGeneric(LAp
// Native single targets are handled by LCallNative.
MOZ_ASSERT(!apply->getSingleTarget()->isNative());
}
// Knowing that calleereg is a non-native function, load the JSScript.
masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
// Load script jitcode.
- masm.loadBaselineOrIonRaw(objreg, objreg, executionMode, &invoke);
+ masm.loadBaselineOrIonRaw(objreg, objreg, &invoke);
// Call with an Ion frame or a rectifier frame.
{
// Create the frame descriptor.
unsigned pushed = masm.framePushed();
masm.addPtr(Imm32(pushed), copyreg);
masm.makeFrameDescriptor(copyreg, JitFrame_IonJS);
@@ -3252,17 +3133,17 @@ CodeGenerator::visitApplyArgsGeneric(LAp
// underflow.
masm.jump(&rejoin);
// Argument fixup needed. Get ready to call the argumentsRectifier.
{
masm.bind(&underflow);
// Hardcode the address of the argumentsRectifier code.
- JitCode *argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier(executionMode);
+ JitCode *argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier();
MOZ_ASSERT(ArgumentsRectifierReg != objreg);
masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking.
masm.loadPtr(Address(objreg, JitCode::offsetOfCode()), objreg);
masm.movePtr(argcreg, ArgumentsRectifierReg);
}
masm.bind(&rejoin);
@@ -3548,20 +3429,18 @@ CodeGenerator::visitDefFun(LDefFun *lir)
pushArg(ImmGCPtr(lir->mir()->fun()));
pushArg(scopeChain);
pushArg(ImmGCPtr(current->mir()->info().script()));
callVM(DefFunOperationInfo, lir);
}
typedef bool (*CheckOverRecursedFn)(JSContext *);
-typedef bool (*CheckOverRecursedParFn)(ForkJoinContext *);
-static const VMFunctionsModal CheckOverRecursedInfo = VMFunctionsModal(
- FunctionInfo<CheckOverRecursedFn>(CheckOverRecursed),
- FunctionInfo<CheckOverRecursedParFn>(CheckOverRecursedPar));
+static const VMFunction CheckOverRecursedInfo =
+ FunctionInfo<CheckOverRecursedFn>(CheckOverRecursed);
void
CodeGenerator::visitCheckOverRecursedFailure(CheckOverRecursedFailure *ool)
{
// The OOL path is hit if the recursion depth has been exceeded.
// Throw an InternalError for over-recursion.
// LFunctionEnvironment can appear before LCheckOverRecursed, so we have
@@ -3570,52 +3449,16 @@ CodeGenerator::visitCheckOverRecursedFai
saveLive(ool->lir());
callVM(CheckOverRecursedInfo, ool->lir());
restoreLive(ool->lir());
masm.jump(ool->rejoin());
}
-void
-CodeGenerator::visitCheckOverRecursedPar(LCheckOverRecursedPar *lir)
-{
- // See above: unlike visitCheckOverRecursed(), this code runs in
- // parallel mode and hence uses the jitStackLimit from the current
- // thread state. Also, we must check the interrupt flags because
- // on interrupt or abort, only the stack limit for the main thread
- // is reset, not the worker threads. See comment in vm/ForkJoin.h
- // for more details.
-
- Register cxReg = ToRegister(lir->forkJoinContext());
- Register tempReg = ToRegister(lir->getTempReg());
-
- masm.loadPtr(Address(cxReg, offsetof(ForkJoinContext, perThreadData)), tempReg);
- masm.loadPtr(Address(tempReg, PerThreadData::offsetOfJitStackLimit()), tempReg);
-
- // Conditional forward (unlikely) branch to failure.
- CheckOverRecursedFailure *ool = new(alloc()) CheckOverRecursedFailure(lir);
- addOutOfLineCode(ool, lir->mir());
-
- masm.branchPtr(Assembler::BelowOrEqual, StackPointer, tempReg, ool->entry());
- masm.checkInterruptFlagPar(tempReg, ool->entry());
- masm.bind(ool->rejoin());
-}
-
-void
-CodeGenerator::visitInterruptCheckPar(LInterruptCheckPar *lir)
-{
- // First check for cx->shared->interrupt_.
- OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing());
-
- Register tempReg = ToRegister(lir->getTempReg());
- masm.checkInterruptFlagPar(tempReg, ool->entry());
- masm.bind(ool->rejoin());
-}
-
IonScriptCounts *
CodeGenerator::maybeCreateScriptCounts()
{
// If scripts are being profiled, create a new IonScriptCounts for the
// profiling data, which will be attached to the associated JSScript or
// AsmJS module after code generation finishes.
if (!GetJitContext()->runtime->profilingScripts())
return nullptr;
@@ -3768,44 +3611,42 @@ CodeGenerator::emitObjectOrStringResultC
masm.bind(&miss);
masm.assumeUnreachable("MIR instruction returned object with unexpected type");
masm.bind(&ok);
}
// Check that we have a valid GC pointer.
- if (gen->info().executionMode() != ParallelExecution) {
- saveVolatile();
- masm.setupUnalignedABICall(2, temp);
- masm.loadJSContext(temp);
- masm.passABIArg(temp);
- masm.passABIArg(output);
-
- void *callee;
- switch (mir->type()) {
- case MIRType_Object:
- callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidObjectPtr);
- break;
- case MIRType_ObjectOrNull:
- callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidObjectOrNullPtr);
- break;
- case MIRType_String:
- callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidStringPtr);
- break;
- case MIRType_Symbol:
- callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidSymbolPtr);
- break;
- default:
- MOZ_CRASH();
- }
-
- masm.callWithABINoProfiling(callee);
- restoreVolatile();
- }
+ saveVolatile();
+ masm.setupUnalignedABICall(2, temp);
+ masm.loadJSContext(temp);
+ masm.passABIArg(temp);
+ masm.passABIArg(output);
+
+ void *callee;
+ switch (mir->type()) {
+ case MIRType_Object:
+ callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidObjectPtr);
+ break;
+ case MIRType_ObjectOrNull:
+ callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidObjectOrNullPtr);
+ break;
+ case MIRType_String:
+ callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidStringPtr);
+ break;
+ case MIRType_Symbol:
+ callee = JS_FUNC_TO_DATA_PTR(void *, AssertValidSymbolPtr);
+ break;
+ default:
+ MOZ_CRASH();
+ }
+
+ masm.callWithABINoProfiling(callee);
+ restoreVolatile();
masm.bind(&done);
masm.pop(temp);
}
void
CodeGenerator::emitValueResultChecks(LInstruction *lir, MDefinition *mir)
{
@@ -3839,30 +3680,28 @@ CodeGenerator::emitValueResultChecks(LIn
masm.bind(&miss);
masm.assumeUnreachable("MIR instruction returned value with unexpected type");
masm.bind(&ok);
}
// Check that we have a valid GC pointer.
- if (gen->info().executionMode() != ParallelExecution) {
- saveVolatile();
-
- masm.pushValue(output);
- masm.movePtr(StackPointer, temp1);
-
- masm.setupUnalignedABICall(2, temp2);
- masm.loadJSContext(temp2);
- masm.passABIArg(temp2);
- masm.passABIArg(temp1);
- masm.callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, AssertValidValue));
- masm.popValue(output);
- restoreVolatile();
- }
+ saveVolatile();
+
+ masm.pushValue(output);
+ masm.movePtr(StackPointer, temp1);
+
+ masm.setupUnalignedABICall(2, temp2);
+ masm.loadJSContext(temp2);
+ masm.passABIArg(temp2);
+ masm.passABIArg(temp1);
+ masm.callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, AssertValidValue));
+ masm.popValue(output);
+ restoreVolatile();
masm.bind(&done);
masm.pop(temp2);
masm.pop(temp1);
}
void
CodeGenerator::emitDebugResultChecks(LInstruction *ins)
@@ -4008,18 +3847,16 @@ class OutOfLineNewArray : public OutOfLi
typedef ArrayObject *(*NewDenseArrayFn)(ExclusiveContext *, uint32_t, HandleTypeObject,
AllocatingBehaviour);
static const VMFunction NewDenseArrayInfo = FunctionInfo<NewDenseArrayFn>(NewDenseArray);
void
CodeGenerator::visitNewArrayCallVM(LNewArray *lir)
{
- MOZ_ASSERT(gen->info().executionMode() == SequentialExecution);
-
Register objReg = ToRegister(lir->output());
MOZ_ASSERT(!lir->isCall());
saveLive(lir);
JSObject *templateObject = lir->mir()->templateObject();
types::TypeObject *type =
templateObject->hasSingletonType() ? nullptr : templateObject->type();
@@ -4041,19 +3878,16 @@ typedef JSObject *(*NewDerivedTypedObjec
HandleObject owner,
int32_t offset);
static const VMFunction CreateDerivedTypedObjInfo =
FunctionInfo<NewDerivedTypedObjectFn>(CreateDerivedTypedObj);
void
CodeGenerator::visitNewDerivedTypedObject(LNewDerivedTypedObject *lir)
{
- // Not yet made safe for par exec:
- MOZ_ASSERT(gen->info().executionMode() == SequentialExecution);
-
pushArg(ToRegister(lir->offset()));
pushArg(ToRegister(lir->owner()));
pushArg(ToRegister(lir->type()));
callVM(CreateDerivedTypedObjInfo, lir);
}
void
CodeGenerator::visitAtan2D(LAtan2D *lir)
@@ -4083,17 +3917,16 @@ CodeGenerator::visitHypot(LHypot *lir)
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaHypot), MoveOp::DOUBLE);
MOZ_ASSERT(ToFloatRegister(lir->output()) == ReturnDoubleReg);
}
void
CodeGenerator::visitNewArray(LNewArray *lir)
{
- MOZ_ASSERT(gen->info().executionMode() == SequentialExecution);
Register objReg = ToRegister(lir->output());
Register tempReg = ToRegister(lir->temp());
ArrayObject *templateObject = lir->mir()->templateObject();
DebugOnly<uint32_t> count = lir->mir()->count();
MOZ_ASSERT(count < NativeObject::NELEMENTS_LIMIT);
if (lir->mir()->shouldUseVM()) {
@@ -4199,18 +4032,16 @@ static const VMFunction NewInitObjectInf
typedef JSObject *(*NewInitObjectWithClassPrototypeFn)(JSContext *, HandlePlainObject);
static const VMFunction NewInitObjectWithClassPrototypeInfo =
FunctionInfo<NewInitObjectWithClassPrototypeFn>(NewInitObjectWithClassPrototype);
void
CodeGenerator::visitNewObjectVMCall(LNewObject *lir)
{
- MOZ_ASSERT(gen->info().executionMode() == SequentialExecution);
-
Register objReg = ToRegister(lir->output());
MOZ_ASSERT(!lir->isCall());
saveLive(lir);
pushArg(ImmGCPtr(lir->mir()->templateObject()));
// If we're making a new object with a class prototype (that is, an object
@@ -4310,17 +4141,16 @@ ShouldInitFixedSlots(LInstruction *lir,
}
MOZ_CRASH("Shouldn't get here");
}
void
CodeGenerator::visitNewObject(LNewObject *lir)
{
- MOZ_ASSERT(gen->info().executionMode() == SequentialExecution);
Register objReg = ToRegister(lir->output());
Register tempReg = ToRegister(lir->temp());
PlainObject *templateObject = lir->mir()->templateObject();
if (lir->mir()->shouldUseVM()) {
visitNewObjectVMCall(lir);
return;
}
@@ -4437,55 +4267,16 @@ CodeGenerator::visitNewSingletonCallObje
// Objects can only be given singleton types in VM calls. We make the call
// out of line to not bloat inline code, even if (naively) this seems like
// extra work.
masm.jump(ool->entry());
masm.bind(ool->rejoin());
}
-void
-CodeGenerator::visitNewCallObjectPar(LNewCallObjectPar *lir)
-{
- Register resultReg = ToRegister(lir->output());
- Register cxReg = ToRegister(lir->forkJoinContext());
- Register tempReg1 = ToRegister(lir->getTemp0());
- Register tempReg2 = ToRegister(lir->getTemp1());
- CallObject *templateObj = lir->mir()->templateObj();
-
- emitAllocateGCThingPar(lir, resultReg, cxReg, tempReg1, tempReg2, templateObj);
-}
-
-typedef ArrayObject *(*ExtendArrayParFn)(ForkJoinContext*, ArrayObject*, uint32_t);
-static const VMFunction ExtendArrayParInfo =
- FunctionInfo<ExtendArrayParFn>(ExtendArrayPar);
-
-void
-CodeGenerator::visitNewDenseArrayPar(LNewDenseArrayPar *lir)
-{
- Register cxReg = ToRegister(lir->forkJoinContext());
- Register lengthReg = ToRegister(lir->length());
- Register tempReg0 = ToRegister(lir->getTemp0());
- Register tempReg1 = ToRegister(lir->getTemp1());
- Register tempReg2 = ToRegister(lir->getTemp2());
- ArrayObject *templateObj = lir->mir()->templateObject();
-
- emitAllocateGCThingPar(lir, tempReg2, cxReg, tempReg0, tempReg1, templateObj);
-
- // Invoke a C helper to allocate the elements. The helper returns
- // nullptr on allocation error or the array object.
-
- saveLive(lir);
- pushArg(lengthReg);
- pushArg(tempReg2);
- callVM(ExtendArrayParInfo, lir);
- storeResultTo(ToRegister(lir->output()));
- restoreLive(lir);
-}
-
typedef JSObject *(*NewStringObjectFn)(JSContext *, HandleString);
static const VMFunction NewStringObjectInfo = FunctionInfo<NewStringObjectFn>(NewStringObject);
void
CodeGenerator::visitNewStringObject(LNewStringObject *lir)
{
Register input = ToRegister(lir->input());
Register output = ToRegister(lir->output());
@@ -4501,86 +4292,16 @@ CodeGenerator::visitNewStringObject(LNew
masm.loadStringLength(input, temp);
masm.storeValue(JSVAL_TYPE_STRING, input, Address(output, StringObject::offsetOfPrimitiveValue()));
masm.storeValue(JSVAL_TYPE_INT32, temp, Address(output, StringObject::offsetOfLength()));
masm.bind(ool->rejoin());
}
-void
-CodeGenerator::visitNewPar(LNewPar *lir)
-{
- Register objReg = ToRegister(lir->output());
- Register cxReg = ToRegister(lir->forkJoinContext());
- Register tempReg1 = ToRegister(lir->getTemp0());
- Register tempReg2 = ToRegister(lir->getTemp1());
- NativeObject *templateObject = lir->mir()->templateObject();
- emitAllocateGCThingPar(lir, objReg, cxReg, tempReg1, tempReg2, templateObject);
-}
-
-class OutOfLineNewGCThingPar : public OutOfLineCodeBase<CodeGenerator>
-{
-public:
- LInstruction *lir;
- gc::AllocKind allocKind;
- Register objReg;
- Register cxReg;
-
- OutOfLineNewGCThingPar(LInstruction *lir, gc::AllocKind allocKind, Register objReg,
- Register cxReg)
- : lir(lir), allocKind(allocKind), objReg(objReg), cxReg(cxReg)
- {}
-
- void accept(CodeGenerator *codegen) {
- codegen->visitOutOfLineNewGCThingPar(this);
- }
-};
-
-typedef JSObject *(*NewGCThingParFn)(ForkJoinContext *, js::gc::AllocKind allocKind);
-static const VMFunction NewGCThingParInfo =
- FunctionInfo<NewGCThingParFn>(NewGCThingPar);
-
-void
-CodeGenerator::emitAllocateGCThingPar(LInstruction *lir, Register objReg, Register cxReg,
- Register tempReg1, Register tempReg2, NativeObject *templateObj)
-{
- MOZ_ASSERT(lir->mirRaw());
- MOZ_ASSERT(lir->mirRaw()->isInstruction());
-
- gc::AllocKind allocKind = templateObj->asTenured().getAllocKind();
- OutOfLineNewGCThingPar *ool = new(alloc()) OutOfLineNewGCThingPar(lir, allocKind, objReg, cxReg);
- addOutOfLineCode(ool, lir->mirRaw()->toInstruction());
-
- masm.newGCThingPar(objReg, cxReg, tempReg1, tempReg2, templateObj, ool->entry());
- masm.bind(ool->rejoin());
- masm.initGCThing(objReg, tempReg1, templateObj);
-}
-
-void
-CodeGenerator::visitOutOfLineNewGCThingPar(OutOfLineNewGCThingPar *ool)
-{
- // As a fallback for allocation in par. exec. mode, we invoke the
- // C helper NewGCThingPar(), which calls into the GC code. If it
- // returns nullptr, we bail. If returns non-nullptr, we rejoin the
- // original instruction.
- Register out = ool->objReg;
-
- saveVolatile(out);
- masm.setupUnalignedABICall(2, out);
- masm.passABIArg(ool->cxReg);
- masm.move32(Imm32(ool->allocKind), out);
- masm.passABIArg(out);
- masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NewGCThingPar));
- masm.storeCallResult(out);
- restoreVolatile(out);
-
- bailoutTestPtr(Assembler::Zero, out, out, ool->lir->snapshot());
-}
-
typedef bool(*InitElemFn)(JSContext *cx, HandleObject obj,
HandleValue id, HandleValue value);
static const VMFunction InitElemInfo =
FunctionInfo<InitElemFn>(InitElemOperation);
void
CodeGenerator::visitInitElem(LInitElem *lir)
{
@@ -5182,26 +4903,23 @@ CodeGenerator::visitModD(LModD *ins)
if (gen->compilingAsmJS())
masm.callWithABI(AsmJSImm_ModD, MoveOp::DOUBLE);
else
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NumberMod), MoveOp::DOUBLE);
}
typedef bool (*BinaryFn)(JSContext *, MutableHandleValue, MutableHandleValue, MutableHandleValue);
-typedef bool (*BinaryParFn)(ForkJoinContext *, HandleValue, HandleValue, MutableHandleValue);
static const VMFunction AddInfo = FunctionInfo<BinaryFn>(js::AddValues);
static const VMFunction SubInfo = FunctionInfo<BinaryFn>(js::SubValues);
static const VMFunction MulInfo = FunctionInfo<BinaryFn>(js::MulValues);
static const VMFunction DivInfo = FunctionInfo<BinaryFn>(js::DivValues);
static const VMFunction ModInfo = FunctionInfo<BinaryFn>(js::ModValues);
-static const VMFunctionsModal UrshInfo = VMFunctionsModal(
- FunctionInfo<BinaryFn>(js::UrshValues),
- FunctionInfo<BinaryParFn>(UrshValuesPar));
+static const VMFunction UrshInfo = FunctionInfo<BinaryFn>(js::UrshValues);
void
CodeGenerator::visitBinaryV(LBinaryV *lir)
{
pushArg(ToValue(lir, LBinaryV::RhsInput));
pushArg(ToValue(lir, LBinaryV::LhsInput));
switch (lir->jsop()) {
@@ -5230,23 +4948,20 @@ CodeGenerator::visitBinaryV(LBinaryV *li
break;
default:
MOZ_CRASH("Unexpected binary op");
}
}
typedef bool (*StringCompareFn)(JSContext *, HandleString, HandleString, bool *);
-typedef bool (*StringCompareParFn)(ForkJoinContext *, HandleString, HandleString, bool *);
-static const VMFunctionsModal StringsEqualInfo = VMFunctionsModal(
- FunctionInfo<StringCompareFn>(jit::StringsEqual<true>),
- FunctionInfo<StringCompareParFn>(jit::StringsEqualPar));
-static const VMFunctionsModal StringsNotEqualInfo = VMFunctionsModal(
- FunctionInfo<StringCompareFn>(jit::StringsEqual<false>),
- FunctionInfo<StringCompareParFn>(jit::StringsUnequalPar));
+static const VMFunction StringsEqualInfo =
+ FunctionInfo<StringCompareFn>(jit::StringsEqual<true>);
+static const VMFunction StringsNotEqualInfo =
+ FunctionInfo<StringCompareFn>(jit::StringsEqual<false>);
void
CodeGenerator::emitCompareS(LInstruction *lir, JSOp op, Register left, Register right,
Register output)
{
MOZ_ASSERT(lir->isCompareS() || lir->isCompareStrictS());
OutOfLineCode *ool = nullptr;
@@ -5294,41 +5009,24 @@ CodeGenerator::visitCompareS(LCompareS *
Register left = ToRegister(lir->left());
Register right = ToRegister(lir->right());
Register output = ToRegister(lir->output());
emitCompareS(lir, op, left, right, output);
}
typedef bool (*CompareFn)(JSContext *, MutableHandleValue, MutableHandleValue, bool *);
-typedef bool (*CompareParFn)(ForkJoinContext *, MutableHandleValue, MutableHandleValue, bool *);
-static const VMFunctionsModal EqInfo = VMFunctionsModal(
- FunctionInfo<CompareFn>(jit::LooselyEqual<true>),
- FunctionInfo<CompareParFn>(jit::LooselyEqualPar));
-static const VMFunctionsModal NeInfo = VMFunctionsModal(
- FunctionInfo<CompareFn>(jit::LooselyEqual<false>),
- FunctionInfo<CompareParFn>(jit::LooselyUnequalPar));
-static const VMFunctionsModal StrictEqInfo = VMFunctionsModal(
- FunctionInfo<CompareFn>(jit::StrictlyEqual<true>),
- FunctionInfo<CompareParFn>(jit::StrictlyEqualPar));
-static const VMFunctionsModal StrictNeInfo = VMFunctionsModal(
- FunctionInfo<CompareFn>(jit::StrictlyEqual<false>),
- FunctionInfo<CompareParFn>(jit::StrictlyUnequalPar));
-static const VMFunctionsModal LtInfo = VMFunctionsModal(
- FunctionInfo<CompareFn>(jit::LessThan),
- FunctionInfo<CompareParFn>(jit::LessThanPar));
-static const VMFunctionsModal LeInfo = VMFunctionsModal(
- FunctionInfo<CompareFn>(jit::LessThanOrEqual),
- FunctionInfo<CompareParFn>(jit::LessThanOrEqualPar));
-static const VMFunctionsModal GtInfo = VMFunctionsModal(
- FunctionInfo<CompareFn>(jit::GreaterThan),
- FunctionInfo<CompareParFn>(jit::GreaterThanPar));
-static const VMFunctionsModal GeInfo = VMFunctionsModal(
- FunctionInfo<CompareFn>(jit::GreaterThanOrEqual),
- FunctionInfo<CompareParFn>(jit::GreaterThanOrEqualPar));
+static const VMFunction EqInfo = FunctionInfo<CompareFn>(jit::LooselyEqual<true>);
+static const VMFunction NeInfo = FunctionInfo<CompareFn>(jit::LooselyEqual<false>);
+static const VMFunction StrictEqInfo = FunctionInfo<CompareFn>(jit::StrictlyEqual<true>);
+static const VMFunction StrictNeInfo = FunctionInfo<CompareFn>(jit::StrictlyEqual<false>);
+static const VMFunction LtInfo = FunctionInfo<CompareFn>(jit::LessThan);
+static const VMFunction LeInfo = FunctionInfo<CompareFn>(jit::LessThanOrEqual);
+static const VMFunction GtInfo = FunctionInfo<CompareFn>(jit::GreaterThan);
+static const VMFunction GeInfo = FunctionInfo<CompareFn>(jit::GreaterThanOrEqual);
void
CodeGenerator::visitCompareVM(LCompareVM *lir)
{
pushArg(ToValue(lir, LBinaryV::RhsInput));
pushArg(ToValue(lir, LBinaryV::LhsInput));
switch (lir->mir()->jsop()) {
@@ -5579,29 +5277,25 @@ CodeGenerator::visitEmulatesUndefinedAnd
}
Register objreg = ToRegister(lir->input());
testObjectEmulatesUndefined(objreg, equal, unequal, ToRegister(lir->temp()), ool);
}
typedef JSString *(*ConcatStringsFn)(ThreadSafeContext *, HandleString, HandleString);
-typedef JSString *(*ConcatStringsParFn)(ForkJoinContext *, HandleString, HandleString);
-static const VMFunctionsModal ConcatStringsInfo = VMFunctionsModal(
- FunctionInfo<ConcatStringsFn>(ConcatStrings<CanGC>),
- FunctionInfo<ConcatStringsParFn>(ConcatStringsPar));
+static const VMFunction ConcatStringsInfo = FunctionInfo<ConcatStringsFn>(ConcatStrings<CanGC>);
void
CodeGenerator::emitConcat(LInstruction *lir, Register lhs, Register rhs, Register output)
{
OutOfLineCode *ool = oolCallVM(ConcatStringsInfo, lir, (ArgList(), lhs, rhs),
StoreRegisterTo(output));
- ExecutionMode mode = gen->info().executionMode();
- JitCode *stringConcatStub = gen->compartment->jitCompartment()->stringConcatStubNoBarrier(mode);
+ JitCode *stringConcatStub = gen->compartment->jitCompartment()->stringConcatStubNoBarrier();
masm.call(stringConcatStub);
masm.branchTestPtr(Assembler::Zero, output, output, ool->entry());
masm.bind(ool->rejoin());
}
void
CodeGenerator::visitConcat(LConcat *lir)
@@ -5618,36 +5312,16 @@ CodeGenerator::visitConcat(LConcat *lir)
MOZ_ASSERT(ToRegister(lir->temp3()) == CallTempReg2);
MOZ_ASSERT(ToRegister(lir->temp4()) == CallTempReg3);
MOZ_ASSERT(ToRegister(lir->temp5()) == CallTempReg4);
MOZ_ASSERT(output == CallTempReg5);
emitConcat(lir, lhs, rhs, output);
}
-void
-CodeGenerator::visitConcatPar(LConcatPar *lir)
-{
- DebugOnly<Register> cx = ToRegister(lir->forkJoinContext());
- Register lhs = ToRegister(lir->lhs());
- Register rhs = ToRegister(lir->rhs());
- Register output = ToRegister(lir->output());
-
- MOZ_ASSERT(lhs == CallTempReg0);
- MOZ_ASSERT(rhs == CallTempReg1);
- MOZ_ASSERT((Register)cx == CallTempReg4);
- MOZ_ASSERT(ToRegister(lir->temp1()) == CallTempReg0);
- MOZ_ASSERT(ToRegister(lir->temp2()) == CallTempReg1);
- MOZ_ASSERT(ToRegister(lir->temp3()) == CallTempReg2);
- MOZ_ASSERT(ToRegister(lir->temp4()) == CallTempReg3);
- MOZ_ASSERT(output == CallTempReg5);
-
- emitConcat(lir, lhs, rhs, output);
-}
-
static void
CopyStringChars(MacroAssembler &masm, Register to, Register from, Register len,
Register byteOpScratch, size_t fromWidth, size_t toWidth)
{
// Copy |len| char16_t code units from |from| to |to|. Assumes len > 0
// (checked below in debug builds), and when done |to| must point to the
// next available char.
@@ -5698,58 +5372,39 @@ CopyStringCharsMaybeInflate(MacroAssembl
masm.loadStringChars(input, input);
CopyStringChars(masm, destChars, input, temp1, temp2, sizeof(char), sizeof(char16_t));
}
masm.bind(&done);
}
static void
ConcatFatInlineString(MacroAssembler &masm, Register lhs, Register rhs, Register output,
- Register temp1, Register temp2, Register temp3, Register forkJoinContext,
- ExecutionMode mode, Label *failure, Label *failurePopTemps, bool isTwoByte)
+ Register temp1, Register temp2, Register temp3,
+ Label *failure, Label *failurePopTemps, bool isTwoByte)
{
// State: result length in temp2.
// Ensure both strings are linear.
masm.branchIfRope(lhs, failure);
masm.branchIfRope(rhs, failure);
// Allocate a JSFatInlineString.
- switch (mode) {
- case SequentialExecution:
- masm.newGCFatInlineString(output, temp1, failure);
- break;
- case ParallelExecution:
- masm.push(temp1);
- masm.push(temp2);
- masm.newGCFatInlineStringPar(output, forkJoinContext, temp1, temp2, failurePopTemps);
- masm.pop(temp2);
- masm.pop(temp1);
- break;
- default:
- MOZ_CRASH("No such execution mode");
- }
+ masm.newGCFatInlineString(output, temp1, failure);
// Store length and flags.
uint32_t flags = JSString::INIT_FAT_INLINE_FLAGS;
if (!isTwoByte)
flags |= JSString::LATIN1_CHARS_BIT;
masm.store32(Imm32(flags), Address(output, JSString::offsetOfFlags()));
masm.store32(temp2, Address(output, JSString::offsetOfLength()));
// Load chars pointer in temp2.
masm.computeEffectiveAddress(Address(output, JSInlineString::offsetOfInlineStorage()), temp2);
{
- // We use temp3 in this block, which in parallel execution also holds
- // a live ForkJoinContext pointer. If we are compiling for parallel
- // execution, be sure to save and restore the ForkJoinContext.
- if (mode == ParallelExecution)
- masm.push(temp3);
-
// Copy lhs chars. Note that this advances temp2 to point to the next
// char. This also clobbers the lhs register.
if (isTwoByte) {
CopyStringCharsMaybeInflate(masm, lhs, temp2, temp1, temp3);
} else {
masm.loadStringLength(lhs, temp3);
masm.loadStringChars(lhs, lhs);
CopyStringChars(masm, temp2, lhs, temp3, temp1, sizeof(char), sizeof(char));
@@ -5764,19 +5419,16 @@ ConcatFatInlineString(MacroAssembler &ma
CopyStringChars(masm, temp2, rhs, temp3, temp1, sizeof(char), sizeof(char));
}
// Null-terminate.
if (isTwoByte)
masm.store16(Imm32(0), Address(temp2, 0));
else
masm.store8(Imm32(0), Address(temp2, 0));
-
- if (mode == ParallelExecution)
- masm.pop(temp3);
}
masm.ret();
}
typedef JSString *(*SubstringKernelFn)(JSContext *cx, HandleString str, int32_t begin, int32_t len);
static const VMFunction SubstringKernelInfo =
FunctionInfo<SubstringKernelFn>(SubstringKernel);
@@ -5891,32 +5543,27 @@ CodeGenerator::visitSubstr(LSubstr *lir)
masm.storePtr(temp, Address(output, JSString::offsetOfNonInlineChars()));
masm.jump(done);
}
masm.bind(done);
}
JitCode *
-JitCompartment::generateStringConcatStub(JSContext *cx, ExecutionMode mode)
+JitCompartment::generateStringConcatStub(JSContext *cx)
{
MacroAssembler masm(cx);
Register lhs = CallTempReg0;
Register rhs = CallTempReg1;
Register temp1 = CallTempReg2;
Register temp2 = CallTempReg3;
Register temp3 = CallTempReg4;
Register output = CallTempReg5;
- // In parallel execution, we pass in the ForkJoinContext in CallTempReg4, as
- // by the time we need to use the temp3 we no longer have need of the
- // cx.
- Register forkJoinContext = CallTempReg4;
-
Label failure, failurePopTemps;
#ifdef JS_USE_LINK_REGISTER
masm.pushReturnAddress();
#endif
// If lhs is empty, return rhs.
Label leftEmpty;
masm.loadStringLength(lhs, temp1);
masm.branchTest32(Assembler::Zero, temp1, temp1, &leftEmpty);
@@ -5949,30 +5596,17 @@ JitCompartment::generateStringConcatStub
masm.bind(¬Inline);
// Keep AND'ed flags in temp1.
// Ensure result length <= JSString::MAX_LENGTH.
masm.branch32(Assembler::Above, temp2, Imm32(JSString::MAX_LENGTH), &failure);
// Allocate a new rope.
- switch (mode) {
- case SequentialExecution:
- masm.newGCString(output, temp3, &failure);
- break;
- case ParallelExecution:
- masm.push(temp1);
- masm.push(temp2);
- masm.newGCStringPar(output, forkJoinContext, temp1, temp2, &failurePopTemps);
- masm.pop(temp2);
- masm.pop(temp1);
- break;
- default:
- MOZ_CRASH("No such execution mode");
- }
+ masm.newGCString(output, temp3, &failure);
// Store rope length and flags. temp1 still holds the result of AND'ing the
// lhs and rhs flags, so we just have to clear the other flags to get our
// rope flags (Latin1 if both lhs and rhs are Latin1).
static_assert(JSString::ROPE_FLAGS == 0, "Rope flags must be 0");
masm.and32(Imm32(JSString::LATIN1_CHARS_BIT), temp1);
masm.store32(temp1, Address(output, JSString::offsetOfFlags()));
masm.store32(temp2, Address(output, JSString::offsetOfLength()));
@@ -5986,22 +5620,22 @@ JitCompartment::generateStringConcatStub
masm.mov(rhs, output);
masm.ret();
masm.bind(&rightEmpty);
masm.mov(lhs, output);
masm.ret();
masm.bind(&isFatInlineTwoByte);
- ConcatFatInlineString(masm, lhs, rhs, output, temp1, temp2, temp3, forkJoinContext,
- mode, &failure, &failurePopTemps, true);
+ ConcatFatInlineString(masm, lhs, rhs, output, temp1, temp2, temp3,
+ &failure, &failurePopTemps, true);
masm.bind(&isFatInlineLatin1);
- ConcatFatInlineString(masm, lhs, rhs, output, temp1, temp2, temp3, forkJoinContext,
- mode, &failure, &failurePopTemps, false);
+ ConcatFatInlineString(masm, lhs, rhs, output, temp1, temp2, temp3,
+ &failure, &failurePopTemps, false);
masm.bind(&failurePopTemps);
masm.pop(temp2);
masm.pop(temp1);
masm.bind(&failure);
masm.movePtr(ImmPtr(nullptr), output);
masm.ret();
@@ -6520,20 +6154,17 @@ CodeGenerator::visitStoreElementHoleV(LS
else
masm.storeValue(value, BaseIndex(elements, ToRegister(lir->index()), TimesEight));
masm.bind(ool->rejoin());
}
typedef bool (*SetDenseElementFn)(JSContext *, HandleNativeObject, int32_t, HandleValue,
bool strict);
-typedef bool (*SetDenseElementParFn)(ForkJoinContext *, HandleObject, int32_t, HandleValue, bool);
-static const VMFunctionsModal SetDenseElementInfo = VMFunctionsModal(
- FunctionInfo<SetDenseElementFn>(SetDenseElement),
- FunctionInfo<SetDenseElementParFn>(SetDenseElementPar));
+static const VMFunction SetDenseElementInfo = FunctionInfo<SetDenseElementFn>(SetDenseElement);
void
CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool)
{
Register object, elements;
LInstruction *ins = ool->ins();
const LAllocation *index;
MIRType valueType;
@@ -7151,21 +6782,18 @@ void
CodeGenerator::visitRunOncePrologue(LRunOncePrologue *lir)
{
pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
callVM(RunOnceScriptPrologueInfo, lir);
}
typedef JSObject *(*InitRestParameterFn)(JSContext *, uint32_t, Value *, HandleObject,
HandleObject);
-typedef JSObject *(*InitRestParameterParFn)(ForkJoinContext *, uint32_t, Value *,
- HandleObject, HandleArrayObject);
-static const VMFunctionsModal InitRestParameterInfo = VMFunctionsModal(
- FunctionInfo<InitRestParameterFn>(InitRestParameter),
- FunctionInfo<InitRestParameterParFn>(InitRestParameterPar));
+static const VMFunction InitRestParameterInfo =
+ FunctionInfo<InitRestParameterFn>(InitRestParameter);
void
CodeGenerator::emitRest(LInstruction *lir, Register array, Register numActuals,
Register temp0, Register temp1, unsigned numFormals,
JSObject *templateObject, bool saveAndRestore, Register resultreg)
{
// Compute actuals() + numFormals.
size_t actualsOffset = frameSize() + JitFrameLayout::offsetOfActualArgs();
@@ -7217,34 +6845,16 @@ CodeGenerator::visitRest(LRest *lir)
masm.bind(&failAlloc);
masm.movePtr(ImmPtr(nullptr), temp2);
}
masm.bind(&joinAlloc);
emitRest(lir, temp2, numActuals, temp0, temp1, numFormals, templateObject, false, ToRegister(lir->output()));
}
-// LRestPar cannot derive from LCallInstructionHelper because emitAllocateGCThingPar may
-// itself contain a VM call. Thus there's some manual work here and in emitRest().
-
-void
-CodeGenerator::visitRestPar(LRestPar *lir)
-{
- Register numActuals = ToRegister(lir->numActuals());
- Register cx = ToRegister(lir->forkJoinContext());
- Register temp0 = ToRegister(lir->getTemp(0));
- Register temp1 = ToRegister(lir->getTemp(1));
- Register temp2 = ToRegister(lir->getTemp(2));
- unsigned numFormals = lir->mir()->numFormals();
- ArrayObject *templateObject = lir->mir()->templateObject();
-
- emitAllocateGCThingPar(lir, temp2, cx, temp0, temp1, templateObject);
- emitRest(lir, temp2, numActuals, temp0, temp1, numFormals, templateObject, true, ToRegister(lir->output()));
-}
-
bool
CodeGenerator::generateAsmJS(AsmJSFunctionLabels *labels)
{
JitSpew(JitSpew_Codegen, "# Emitting asm.js code");
// AsmJS doesn't do SPS instrumentation.
sps_.disable();
@@ -7334,17 +6944,17 @@ CodeGenerator::generate()
setSkipArgCheckEntryOffset(masm.size());
masm.setFramePushed(0);
if (!generatePrologue())
return false;
masm.bind(&skipPrologue);
#ifdef JS_TRACE_LOGGING
- if (!gen->compilingAsmJS() && gen->info().executionMode() == SequentialExecution) {
+ if (!gen->compilingAsmJS()) {
emitTracelogScriptStart();
emitTracelogStartEvent(TraceLogger_IonMonkey);
}
#endif
#ifdef DEBUG
// Assert that the argument types are correct.
generateArgumentsChecks(/* bailout = */ false);
@@ -7418,29 +7028,24 @@ struct AutoDiscardIonCode
bool
CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
{
RootedScript script(cx, gen->info().script());
ExecutionMode executionMode = gen->info().executionMode();
OptimizationLevel optimizationLevel = gen->optimizationInfo().level();
- MOZ_ASSERT_IF(HasIonScript(script, executionMode), executionMode == SequentialExecution);
-
// We finished the new IonScript. Invalidate the current active IonScript,
// so we can replace it with this new (probably higher optimized) version.
if (HasIonScript(script, executionMode)) {
MOZ_ASSERT(GetIonScript(script, executionMode)->isRecompiling());
// Do a normal invalidate, except don't cancel offThread compilations,
// since that will cancel this compilation too.
- if (!Invalidate(cx, script, SequentialExecution,
- /* resetUses */ false, /* cancelOffThread*/ false))
- {
+ if (!Invalidate(cx, script, /* resetUses */ false, /* cancelOffThread*/ false))
return false;
- }
}
if (scriptCounts_ && !script->hasScriptCounts() && !script->initScriptCounts(cx))
return false;
// Check to make sure we didn't have a mid-build invalidation. If so, we
// will trickle to jit::Compile() and return Method_Skipped.
uint32_t warmUpCount = script->getWarmUpCount();
@@ -7457,45 +7062,36 @@ CodeGenerator::link(JSContext *cx, types
uint32_t scriptFrameSize = frameClass_ == FrameSizeClass::None()
? frameDepth_
: FrameSizeClass::FromDepth(frameDepth_).frameSize();
// We encode safepoints after the OSI-point offsets have been determined.
encodeSafepoints();
- // List of possible scripts that this graph may call. Currently this is
- // only tracked when compiling for parallel execution.
- CallTargetVector callTargets(alloc());
- if (executionMode == ParallelExecution)
- AddPossibleCallees(cx, graph.mir(), callTargets);
-
AutoDiscardIonCode discardIonCode(cx, &recompileInfo);
IonScript *ionScript =
IonScript::New(cx, recompileInfo,
graph.totalSlotCount(), scriptFrameSize,
snapshots_.listSize(), snapshots_.RVATableSize(),
recovers_.size(), bailouts_.length(), graph.numConstants(),
safepointIndices_.length(), osiIndices_.length(),
cacheList_.length(), runtimeData_.length(),
- safepoints_.size(), callTargets.length(),
- patchableBackedges_.length(), optimizationLevel);
+ safepoints_.size(), patchableBackedges_.length(), optimizationLevel);
if (!ionScript)
return false;
discardIonCode.ionScript = ionScript;
// Also, note that creating the code here during an incremental GC will
// trace the code and mark all GC things it refers to. This captures any
// read barriers which were skipped while compiling the script off thread.
Linker linker(masm);
AutoFlushICache afc("IonLink");
- JitCode *code = (executionMode == SequentialExecution)
- ? linker.newCodeForIonScript(cx)
- : linker.newCode<CanGC>(cx, ION_CODE);
+ JitCode *code = linker.newCodeForIonScript(cx);
if (!code)
return false;
// Encode native to bytecode map if profiling is enabled.
if (isNativeToBytecodeMapEnabled()) {
// Generate native-to-bytecode main table.
if (!generateCompactNativeToBytecodeMap(cx, code))
return false;
@@ -7545,22 +7141,16 @@ CodeGenerator::link(JSContext *cx, types
ionScript->setSkipArgCheckEntryOffset(getSkipArgCheckEntryOffset());
// If SPS is enabled, mark IonScript as having been instrumented with SPS
if (sps_.enabled())
ionScript->setHasSPSInstrumentation();
SetIonScript(cx, script, executionMode, ionScript);
- // In parallel execution mode, when we first compile a script, we
- // don't know that its potential callees are compiled, so set a
- // flag warning that the callees may not be fully compiled.
- if (!callTargets.empty())
- ionScript->setHasUncompiledCallTarget();
-
invalidateEpilogueData_.fixup(&masm);
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, invalidateEpilogueData_),
ImmPtr(ionScript),
ImmPtr((void*)-1));
JitSpew(JitSpew_Codegen, "Created IonScript %p (raw %p)",
(void *) ionScript, (void *) code->raw());
@@ -7603,18 +7193,16 @@ CodeGenerator::link(JSContext *cx, types
ionScript->copyOsiIndices(&osiIndices_[0], masm);
if (snapshots_.listSize())
ionScript->copySnapshots(&snapshots_);
MOZ_ASSERT_IF(snapshots_.listSize(), recovers_.size());
if (recovers_.size())
ionScript->copyRecovers(&recovers_);
if (graph.numConstants())
ionScript->copyConstants(graph.constantPool());
- if (callTargets.length() > 0)
- ionScript->copyCallTargetEntries(callTargets.begin());
if (patchableBackedges_.length() > 0)
ionScript->copyPatchableBackedges(cx, code, patchableBackedges_.begin(), masm);
#ifdef JS_TRACE_LOGGING
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
for (uint32_t i = 0; i < patchableTraceLoggers_.length(); i++) {
patchableTraceLoggers_[i].fixup(&masm);
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTraceLoggers_[i]),
@@ -7631,31 +7219,21 @@ CodeGenerator::link(JSContext *cx, types
patchableTLScripts_[i].fixup(&masm);
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLScripts_[i]),
ImmPtr((void *) uintptr_t(textId)),
ImmPtr((void *)0));
}
}
#endif
- switch (executionMode) {
- case SequentialExecution:
- // The correct state for prebarriers is unknown until the end of compilation,
- // since a GC can occur during code generation. All barriers are emitted
- // off-by-default, and are toggled on here if necessary.
- if (cx->zone()->needsIncrementalBarrier())
- ionScript->toggleBarriers(true);
- break;
- case ParallelExecution:
- // We don't run incremental GC during parallel execution; no need to
- // turn on barriers.
- break;
- default:
- MOZ_CRASH("No such execution mode");
- }
+ // The correct state for prebarriers is unknown until the end of compilation,
+ // since a GC can occur during code generation. All barriers are emitted
+ // off-by-default, and are toggled on here if necessary.
+ if (cx->zone()->needsIncrementalBarrier())
+ ionScript->toggleBarriers(true);
// Attach any generated script counts to the script.
if (IonScriptCounts *counts = extractScriptCounts())
script->addIonCounts(counts);
// Make sure that AutoDiscardIonCode does not free the relevant info.
discardIonCode.keepIonCode();
@@ -7748,20 +7326,17 @@ CodeGenerator::visitCallGetElement(LCall
} else {
MOZ_ASSERT(op == JSOP_CALLELEM);
callVM(CallElementInfo, lir);
}
}
typedef bool (*SetObjectElementFn)(JSContext *, HandleObject, HandleValue, HandleValue,
bool strict);
-typedef bool (*SetElementParFn)(ForkJoinContext *, HandleObject, HandleValue, HandleValue, bool);
-static const VMFunctionsModal SetObjectElementInfo = VMFunctionsModal(
- FunctionInfo<SetObjectElementFn>(SetObjectElement),
- FunctionInfo<SetElementParFn>(SetElementPar));
+static const VMFunction SetObjectElementInfo = FunctionInfo<SetObjectElementFn>(SetObjectElement);
void
CodeGenerator::visitCallSetElement(LCallSetElement *lir)
{
pushArg(Imm32(lir->mir()->strict()));
pushArg(ToValue(lir, LCallSetElement::Value));
pushArg(ToValue(lir, LCallSetElement::Index));
pushArg(ToRegister(lir->getOperand(0)));
@@ -7899,82 +7474,42 @@ CodeGenerator::visitNameIC(OutOfLineUpda
masm.jump(ool->rejoin());
}
void
CodeGenerator::addGetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
PropertyName *name, TypedOrValueRegister output,
bool monitoredResult, jsbytecode *profilerLeavePc)
{
- switch (gen->info().executionMode()) {
- case SequentialExecution: {
- GetPropertyIC cache(liveRegs, objReg, name, output, monitoredResult);
- cache.setProfilerLeavePC(profilerLeavePc);
- addCache(ins, allocateCache(cache));
- break;
- }
- case ParallelExecution: {
- GetPropertyParIC cache(objReg, name, output);
- cache.setProfilerLeavePC(profilerLeavePc);
- addCache(ins, allocateCache(cache));
- break;
- }
- default:
- MOZ_CRASH("Bad execution mode");
- }
+ GetPropertyIC cache(liveRegs, objReg, name, output, monitoredResult);
+ cache.setProfilerLeavePC(profilerLeavePc);
+ addCache(ins, allocateCache(cache));
}
void
CodeGenerator::addSetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
PropertyName *name, ConstantOrRegister value, bool strict,
bool needsTypeBarrier, jsbytecode *profilerLeavePc)
{
- switch (gen->info().executionMode()) {
- case SequentialExecution: {
- SetPropertyIC cache(liveRegs, objReg, name, value, strict, needsTypeBarrier);
- cache.setProfilerLeavePC(profilerLeavePc);
- addCache(ins, allocateCache(cache));
- break;
- }
- case ParallelExecution: {
- SetPropertyParIC cache(objReg, name, value, strict, needsTypeBarrier);
- cache.setProfilerLeavePC(profilerLeavePc);
- addCache(ins, allocateCache(cache));
- break;
- }
- default:
- MOZ_CRASH("Bad execution mode");
- }
+ SetPropertyIC cache(liveRegs, objReg, name, value, strict, needsTypeBarrier);
+ cache.setProfilerLeavePC(profilerLeavePc);
+ addCache(ins, allocateCache(cache));
}
void
CodeGenerator::addSetElementCache(LInstruction *ins, Register obj, Register unboxIndex,
Register temp, FloatRegister tempDouble,
FloatRegister tempFloat32, ValueOperand index,
ConstantOrRegister value, bool strict, bool guardHoles,
jsbytecode *profilerLeavePc)
{
- switch (gen->info().executionMode()) {
- case SequentialExecution: {
- SetElementIC cache(obj, unboxIndex, temp, tempDouble, tempFloat32, index, value, strict,
- guardHoles);
- cache.setProfilerLeavePC(profilerLeavePc);
- addCache(ins, allocateCache(cache));
- break;
- }
- case ParallelExecution: {
- SetElementParIC cache(obj, unboxIndex, temp, tempDouble, tempFloat32, index, value, strict,
- guardHoles);
- cache.setProfilerLeavePC(profilerLeavePc);
- addCache(ins, allocateCache(cache));
- break;
- }
- default:
- MOZ_CRASH("Bad execution mode");
- }
+ SetElementIC cache(obj, unboxIndex, temp, tempDouble, tempFloat32, index, value, strict,
+ guardHoles);
+ cache.setProfilerLeavePC(profilerLeavePc);
+ addCache(ins, allocateCache(cache));
}
void
CodeGenerator::visitGetPropertyCacheV(LGetPropertyCacheV *ins)
{
RegisterSet liveRegs = ins->safepoint()->liveRegs();
Register objReg = ToRegister(ins->getOperand(0));
PropertyName *name = ins->mir()->name();
@@ -8020,57 +7555,25 @@ CodeGenerator::visitGetPropertyIC(OutOfL
pushArg(Imm32(ool->getCacheIndex()));
callVM(GetPropertyIC::UpdateInfo, lir);
StoreValueTo(ic->output()).generate(this);
restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
masm.jump(ool->rejoin());
}
-typedef bool (*GetPropertyParICFn)(ForkJoinContext *, size_t, HandleObject, MutableHandleValue);
-const VMFunction GetPropertyParIC::UpdateInfo =
- FunctionInfo<GetPropertyParICFn>(GetPropertyParIC::update);
-
-void
-CodeGenerator::visitGetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<GetPropertyParIC> &ic)
-{
- LInstruction *lir = ool->lir();
- saveLive(lir);
-
- pushArg(ic->object());
- pushArg(Imm32(ool->getCacheIndex()));
- callVM(GetPropertyParIC::UpdateInfo, lir);
- StoreValueTo(ic->output()).generate(this);
- restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
-
- masm.jump(ool->rejoin());
-}
-
void
CodeGenerator::addGetElementCache(LInstruction *ins, Register obj, ConstantOrRegister index,
TypedOrValueRegister output, bool monitoredResult,
bool allowDoubleResult, jsbytecode *profilerLeavePc)
{
- switch (gen->info().executionMode()) {
- case SequentialExecution: {
- RegisterSet liveRegs = ins->safepoint()->liveRegs();
- GetElementIC cache(liveRegs, obj, index, output, monitoredResult, allowDoubleResult);
- cache.setProfilerLeavePC(profilerLeavePc);
- addCache(ins, allocateCache(cache));
- break;
- }
- case ParallelExecution: {
- GetElementParIC cache(obj, index, output, monitoredResult, allowDoubleResult);
- cache.setProfilerLeavePC(profilerLeavePc);
- addCache(ins, allocateCache(cache));
- break;
- }
- default:
- MOZ_CRASH("No such execution mode");
- }
+ RegisterSet liveRegs = ins->safepoint()->liveRegs();
+ GetElementIC cache(liveRegs, obj, index, output, monitoredResult, allowDoubleResult);
+ cache.setProfilerLeavePC(profilerLeavePc);
+ addCache(ins, allocateCache(cache));
}
void
CodeGenerator::visitGetElementCacheV(LGetElementCacheV *ins)
{
Register obj = ToRegister(ins->object());
ConstantOrRegister index = TypedOrValueRegister(ToValue(ins, LGetElementCacheV::Index));
TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
@@ -8164,57 +7667,16 @@ CodeGenerator::visitSetElementIC(OutOfLi
pushArg(ic->object());
pushArg(Imm32(ool->getCacheIndex()));
callVM(SetElementIC::UpdateInfo, lir);
restoreLive(lir);
masm.jump(ool->rejoin());
}
-typedef bool (*SetElementParICFn)(ForkJoinContext *, size_t, HandleObject, HandleValue, HandleValue);
-const VMFunction SetElementParIC::UpdateInfo =
- FunctionInfo<SetElementParICFn>(SetElementParIC::update);
-
-void
-CodeGenerator::visitSetElementParIC(OutOfLineUpdateCache *ool, DataPtr<SetElementParIC> &ic)
-{
- LInstruction *lir = ool->lir();
- saveLive(lir);
-
- pushArg(ic->value());
- pushArg(ic->index());
- pushArg(ic->object());
- pushArg(Imm32(ool->getCacheIndex()));
- callVM(SetElementParIC::UpdateInfo, lir);
- restoreLive(lir);
-
- masm.jump(ool->rejoin());
-}
-
-typedef bool (*GetElementParICFn)(ForkJoinContext *, size_t, HandleObject, HandleValue,
- MutableHandleValue);
-const VMFunction GetElementParIC::UpdateInfo =
- FunctionInfo<GetElementParICFn>(GetElementParIC::update);
-
-void
-CodeGenerator::visitGetElementParIC(OutOfLineUpdateCache *ool, DataPtr<GetElementParIC> &ic)
-{
- LInstruction *lir = ool->lir();
- saveLive(lir);
-
- pushArg(ic->index());
- pushArg(ic->object());
- pushArg(Imm32(ool->getCacheIndex()));
- callVM(GetElementParIC::UpdateInfo, lir);
- StoreValueTo(ic->output()).generate(this);
- restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
-
- masm.jump(ool->rejoin());
-}
-
void
CodeGenerator::visitBindNameCache(LBindNameCache *ins)
{
Register scopeChain = ToRegister(ins->scopeChain());
Register output = ToRegister(ins->output());
BindNameIC cache(scopeChain, ins->mir()->name(), output);
cache.setProfilerLeavePC(ins->mir()->profilerLeavePc());
@@ -8237,21 +7699,17 @@ CodeGenerator::visitBindNameIC(OutOfLine
StoreRegisterTo(ic->outputReg()).generate(this);
restoreLiveIgnore(lir, StoreRegisterTo(ic->outputReg()).clobbered());
masm.jump(ool->rejoin());
}
typedef bool (*SetPropertyFn)(JSContext *, HandleObject,
HandlePropertyName, const HandleValue, bool, jsbytecode *);
-typedef bool (*SetPropertyParFn)(ForkJoinContext *, HandleObject,
- HandlePropertyName, const HandleValue, bool, jsbytecode *);
-static const VMFunctionsModal SetPropertyInfo = VMFunctionsModal(
- FunctionInfo<SetPropertyFn>(SetProperty),
- FunctionInfo<SetPropertyParFn>(SetPropertyPar));
+static const VMFunction SetPropertyInfo = FunctionInfo<SetPropertyFn>(SetProperty);
void
CodeGenerator::visitCallSetProperty(LCallSetProperty *ins)
{
ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LCallSetProperty::Value));
const Register objReg = ToRegister(ins->getOperand(0));
@@ -8344,75 +7802,42 @@ CodeGenerator::visitSetPropertyIC(OutOfL
pushArg(ic->object());
pushArg(Imm32(ool->getCacheIndex()));
callVM(SetPropertyIC::UpdateInfo, lir);
restoreLive(lir);
masm.jump(ool->rejoin());
}
-typedef bool (*SetPropertyParICFn)(ForkJoinContext *, size_t, HandleObject, HandleValue);
-const VMFunction SetPropertyParIC::UpdateInfo =
- FunctionInfo<SetPropertyParICFn>(SetPropertyParIC::update);
-
-void
-CodeGenerator::visitSetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyParIC> &ic)
-{
- LInstruction *lir = ool->lir();
- saveLive(lir);
-
- pushArg(ic->value());
- pushArg(ic->object());
- pushArg(Imm32(ool->getCacheIndex()));
- callVM(SetPropertyParIC::UpdateInfo, lir);
- restoreLive(lir);
-
- masm.jump(ool->rejoin());
-}
-
typedef bool (*ThrowFn)(JSContext *, HandleValue);
static const VMFunction ThrowInfoCodeGen = FunctionInfo<ThrowFn>(js::Throw);
void
CodeGenerator::visitThrow(LThrow *lir)
{
pushArg(ToValue(lir, LThrow::Value));
callVM(ThrowInfoCodeGen, lir);
}
typedef bool (*BitNotFn)(JSContext *, HandleValue, int *p);
-typedef bool (*BitNotParFn)(ForkJoinContext *, HandleValue, int32_t *);
-static const VMFunctionsModal BitNotInfo = VMFunctionsModal(
- FunctionInfo<BitNotFn>(BitNot),
- FunctionInfo<BitNotParFn>(BitNotPar));
+static const VMFunction BitNotInfo = FunctionInfo<BitNotFn>(BitNot);
void
CodeGenerator::visitBitNotV(LBitNotV *lir)
{
pushArg(ToValue(lir, LBitNotV::Input));
callVM(BitNotInfo, lir);
}
typedef bool (*BitopFn)(JSContext *, HandleValue, HandleValue, int *p);
-typedef bool (*BitopParFn)(ForkJoinContext *, HandleValue, HandleValue, int32_t *);
-static const VMFunctionsModal BitAndInfo = VMFunctionsModal(
- FunctionInfo<BitopFn>(BitAnd),
- FunctionInfo<BitopParFn>(BitAndPar));
-static const VMFunctionsModal BitOrInfo = VMFunctionsModal(
- FunctionInfo<BitopFn>(BitOr),
- FunctionInfo<BitopParFn>(BitOrPar));
-static const VMFunctionsModal BitXorInfo = VMFunctionsModal(
- FunctionInfo<BitopFn>(BitXor),
- FunctionInfo<BitopParFn>(BitXorPar));
-static const VMFunctionsModal BitLhsInfo = VMFunctionsModal(
- FunctionInfo<BitopFn>(BitLsh),
- FunctionInfo<BitopParFn>(BitLshPar));
-static const VMFunctionsModal BitRhsInfo = VMFunctionsModal(
- FunctionInfo<BitopFn>(BitRsh),
- FunctionInfo<BitopParFn>(BitRshPar));
+static const VMFunction BitAndInfo = FunctionInfo<BitopFn>(BitAnd);
+static const VMFunction BitOrInfo = FunctionInfo<BitopFn>(BitOr);
+static const VMFunction BitXorInfo = FunctionInfo<BitopFn>(BitXor);
+static const VMFunction BitLhsInfo = FunctionInfo<BitopFn>(BitLsh);
+static const VMFunction BitRhsInfo = FunctionInfo<BitopFn>(BitRsh);
void
CodeGenerator::visitBitOpV(LBitOpV *lir)
{
pushArg(ToValue(lir, LBitOpV::RhsInput));
pushArg(ToValue(lir, LBitOpV::LhsInput));
switch (lir->jsop()) {
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -28,24 +28,21 @@
namespace js {
namespace jit {
class OutOfLineTestObject;
class OutOfLineNewArray;
class OutOfLineNewObject;
class CheckOverRecursedFailure;
-class CheckOverRecursedFailurePar;
-class OutOfLineInterruptCheckPar;
class OutOfLineInterruptCheckImplicit;
class OutOfLineUnboxFloatingPoint;
class OutOfLineStoreElementHole;
class OutOfLineTypeOfV;
class OutOfLineLoadTypedArray;
-class OutOfLineNewGCThingPar;
class OutOfLineUpdateCache;
class OutOfLineCallPostWriteBarrier;
class OutOfLineIsCallable;
class OutOfLineRegExpExec;
class OutOfLineRegExpTest;
class CodeGenerator : public CodeGeneratorSpecific
{
@@ -108,17 +105,16 @@ class CodeGenerator : public CodeGenerat
void visitOutOfLineRegExpExec(OutOfLineRegExpExec *ool);
void visitRegExpTest(LRegExpTest *lir);
void visitOutOfLineRegExpTest(OutOfLineRegExpTest *ool);
void visitRegExpReplace(LRegExpReplace *lir);
void visitStringReplace(LStringReplace *lir);
void visitLambda(LLambda *lir);
void visitLambdaArrow(LLambdaArrow *lir);
void visitLambdaForSingleton(LLambdaForSingleton *lir);
- void visitLambdaPar(LLambdaPar *lir);
void visitPointer(LPointer *lir);
void visitSlots(LSlots *lir);
void visitLoadSlotT(LLoadSlotT *lir);
void visitLoadSlotV(LLoadSlotV *lir);
void visitStoreSlotT(LStoreSlotT *lir);
void visitStoreSlotV(LStoreSlotV *lir);
void visitElements(LElements *lir);
void visitConvertElementsToDoubles(LConvertElementsToDoubles *lir);
@@ -157,20 +153,17 @@ class CodeGenerator : public CodeGenerat
void visitNewArrayDynamicLength(LNewArrayDynamicLength *lir);
void visitNewObjectVMCall(LNewObject *lir);
void visitNewObject(LNewObject *lir);
void visitOutOfLineNewObject(OutOfLineNewObject *ool);
void visitNewTypedObject(LNewTypedObject *lir);
void visitNewDeclEnvObject(LNewDeclEnvObject *lir);
void visitNewCallObject(LNewCallObject *lir);
void visitNewSingletonCallObject(LNewSingletonCallObject *lir);
- void visitNewCallObjectPar(LNewCallObjectPar *lir);
void visitNewStringObject(LNewStringObject *lir);
- void visitNewPar(LNewPar *lir);
- void visitNewDenseArrayPar(LNewDenseArrayPar *lir);
void visitNewDerivedTypedObject(LNewDerivedTypedObject *lir);
void visitInitElem(LInitElem *lir);
void visitInitElemGetterSetter(LInitElemGetterSetter *lir);
void visitMutateProto(LMutateProto *lir);
void visitInitProp(LInitProp *lir);
void visitInitPropGetterSetter(LInitPropGetterSetter *lir);
void visitCreateThis(LCreateThis *lir);
void visitCreateThisWithProto(LCreateThisWithProto *lir);
@@ -226,23 +219,20 @@ class CodeGenerator : public CodeGenerat
void visitCompareStrictS(LCompareStrictS *lir);
void visitCompareVM(LCompareVM *lir);
void visitIsNullOrLikeUndefined(LIsNullOrLikeUndefined *lir);
void visitIsNullOrLikeUndefinedAndBranch(LIsNullOrLikeUndefinedAndBranch *lir);
void visitEmulatesUndefined(LEmulatesUndefined *lir);
void visitEmulatesUndefinedAndBranch(LEmulatesUndefinedAndBranch *lir);
void emitConcat(LInstruction *lir, Register lhs, Register rhs, Register output);
void visitConcat(LConcat *lir);
- void visitConcatPar(LConcatPar *lir);
void visitCharCodeAt(LCharCodeAt *lir);
void visitFromCharCode(LFromCharCode *lir);
void visitStringSplit(LStringSplit *lir);
void visitFunctionEnvironment(LFunctionEnvironment *lir);
- void visitForkJoinContext(LForkJoinContext *lir);
- void visitGuardThreadExclusive(LGuardThreadExclusive *lir);
void visitCallGetProperty(LCallGetProperty *lir);
void visitCallGetElement(LCallGetElement *lir);
void visitCallSetElement(LCallSetElement *lir);
void visitCallInitElementArray(LCallInitElementArray *lir);
void visitThrow(LThrow *lir);
void visitTypeOfV(LTypeOfV *lir);
void visitOutOfLineTypeOfV(OutOfLineTypeOfV *ool);
void visitToIdV(LToIdV *lir);
@@ -286,17 +276,16 @@ class CodeGenerator : public CodeGenerat
void visitSetFrameArgumentT(LSetFrameArgumentT *lir);
void visitSetFrameArgumentC(LSetFrameArgumentC *lir);
void visitSetFrameArgumentV(LSetFrameArgumentV *lir);
void visitRunOncePrologue(LRunOncePrologue *lir);
void emitRest(LInstruction *lir, Register array, Register numActuals,
Register temp0, Register temp1, unsigned numFormals,
JSObject *templateObject, bool saveAndRestore, Register resultreg);
void visitRest(LRest *lir);
- void visitRestPar(LRestPar *lir);
void visitCallSetProperty(LCallSetProperty *ins);
void visitCallDeleteProperty(LCallDeleteProperty *lir);
void visitCallDeleteElement(LCallDeleteElement *lir);
void visitBitNotV(LBitNotV *lir);
void visitBitOpV(LBitOpV *lir);
void emitInstanceOf(LInstruction *ins, JSObject *prototypeObject);
void visitIn(LIn *ins);
void visitInArray(LInArray *ins);
@@ -320,29 +309,23 @@ class CodeGenerator : public CodeGenerat
void visitAsmJSVoidReturn(LAsmJSVoidReturn *ret);
void visitLexicalCheck(LLexicalCheck *ins);
void visitThrowUninitializedLexical(LThrowUninitializedLexical *ins);
void visitDebugger(LDebugger *ins);
void visitCheckOverRecursed(LCheckOverRecursed *lir);
void visitCheckOverRecursedFailure(CheckOverRecursedFailure *ool);
- void visitCheckOverRecursedPar(LCheckOverRecursedPar *lir);
-
- void visitInterruptCheckPar(LInterruptCheckPar *lir);
- void visitOutOfLineInterruptCheckPar(OutOfLineInterruptCheckPar *ool);
-
void visitInterruptCheckImplicit(LInterruptCheckImplicit *ins);
void visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit *ins);
void visitUnboxFloatingPoint(LUnboxFloatingPoint *lir);
void visitOutOfLineUnboxFloatingPoint(OutOfLineUnboxFloatingPoint *ool);
void visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool);
- void visitOutOfLineNewGCThingPar(OutOfLineNewGCThingPar *ool);
void loadJSScriptForBlock(MBasicBlock *block, Register reg);
void loadOutermostJSScript(Register reg);
// Inline caches visitors.
void visitOutOfLineCache(OutOfLineUpdateCache *ool);
void visitGetPropertyCacheV(LGetPropertyCacheV *ins);
void visitGetPropertyCacheT(LGetPropertyCacheT *ins);
@@ -353,23 +336,19 @@ class CodeGenerator : public CodeGenerat
void visitBindNameCache(LBindNameCache *ins);
void visitCallSetProperty(LInstruction *ins);
void visitSetPropertyCacheV(LSetPropertyCacheV *ins);
void visitSetPropertyCacheT(LSetPropertyCacheT *ins);
void visitGetNameCache(LGetNameCache *ins);
void visitCallsiteCloneCache(LCallsiteCloneCache *ins);
void visitGetPropertyIC(OutOfLineUpdateCache *ool, DataPtr<GetPropertyIC> &ic);
- void visitGetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<GetPropertyParIC> &ic);
void visitSetPropertyIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyIC> &ic);
- void visitSetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyParIC> &ic);
void visitGetElementIC(OutOfLineUpdateCache *ool, DataPtr<GetElementIC> &ic);
- void visitGetElementParIC(OutOfLineUpdateCache *ool, DataPtr<GetElementParIC> &ic);
void visitSetElementIC(OutOfLineUpdateCache *ool, DataPtr<SetElementIC> &ic);
- void visitSetElementParIC(OutOfLineUpdateCache *ool, DataPtr<SetElementParIC> &ic);
void visitBindNameIC(OutOfLineUpdateCache *ool, DataPtr<BindNameIC> &ic);
void visitNameIC(OutOfLineUpdateCache *ool, DataPtr<NameIC> &ic);
void visitCallsiteCloneIC(OutOfLineUpdateCache *ool, DataPtr<CallsiteCloneIC> &ic);
void visitAssertRangeI(LAssertRangeI *ins);
void visitAssertRangeD(LAssertRangeD *ins);
void visitAssertRangeF(LAssertRangeF *ins);
void visitAssertRangeV(LAssertRangeV *ins);
@@ -396,22 +375,16 @@ class CodeGenerator : public CodeGenerat
bool needsTypeBarrier, jsbytecode *profilerLeavePc);
void addSetElementCache(LInstruction *ins, Register obj, Register unboxIndex, Register temp,
FloatRegister tempDouble, FloatRegister tempFloat32,
ValueOperand index, ConstantOrRegister value,
bool strict, bool guardHoles, jsbytecode *profilerLeavePc);
bool generateBranchV(const ValueOperand &value, Label *ifTrue, Label *ifFalse, FloatRegister fr);
- void emitAllocateGCThingPar(LInstruction *lir, Register objReg, Register cxReg,
- Register tempReg1, Register tempReg2,
- NativeObject *templateObj);
-
- void emitCallToUncompiledScriptPar(LInstruction *lir, Register calleeReg);
-
void emitLambdaInit(Register resultReg, Register scopeChainReg,
const LambdaFunctionInfo &info);
void emitFilterArgumentsOrEval(LInstruction *lir, Register string, Register temp1,
Register temp2);
IonScriptCounts *maybeCreateScriptCounts();
--- a/js/src/jit/CompileInfo.h
+++ b/js/src/jit/CompileInfo.h
@@ -426,20 +426,16 @@ class CompileInfo
ExecutionMode executionMode() const {
return executionMode_;
}
bool executionModeIsAnalysis() const {
return executionMode_ == DefinitePropertiesAnalysis || executionMode_ == ArgumentsUsageAnalysis;
}
- bool isParallelExecution() const {
- return executionMode_ == ParallelExecution;
- }
-
// Returns true if a slot can be observed out-side the current frame while
// the frame is active on the stack. This implies that these definitions
// would have to be executed and that they cannot be removed even if they
// are unused.
bool isObservableSlot(uint32_t slot) const {
if (isObservableFrameSlot(slot))
return true;
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -28,24 +28,22 @@
#include "jit/JitCommon.h"
#include "jit/JitCompartment.h"
#include "jit/JitSpewer.h"
#include "jit/LICM.h"
#include "jit/LinearScan.h"
#include "jit/LIR.h"
#include "jit/LoopUnroller.h"
#include "jit/Lowering.h"
-#include "jit/ParallelSafetyAnalysis.h"
#include "jit/PerfSpewer.h"
#include "jit/RangeAnalysis.h"
#include "jit/ScalarReplacement.h"
#include "jit/Sink.h"
#include "jit/StupidAllocator.h"
#include "jit/ValueNumbering.h"
-#include "vm/ForkJoin.h"
#include "vm/HelperThreads.h"
#include "vm/TraceLogging.h"
#include "jscompartmentinlines.h"
#include "jsgcinlines.h"
#include "jsinferinlines.h"
#include "jsobjinlines.h"
@@ -149,26 +147,23 @@ jit::InitializeIon()
CheckPerf();
return true;
}
JitRuntime::JitRuntime()
: execAlloc_(nullptr),
ionAlloc_(nullptr),
exceptionTail_(nullptr),
- exceptionTailParallel_(nullptr),
bailoutTail_(nullptr),
enterJIT_(nullptr),
bailoutHandler_(nullptr),
argumentsRectifier_(nullptr),
argumentsRectifierReturnAddr_(nullptr),
- parallelArgumentsRectifier_(nullptr),
invalidator_(nullptr),
debugTrapHandler_(nullptr),
- forkJoinGetSliceStub_(nullptr),
baselineDebugModeOSRHandler_(nullptr),
functionWrappers_(nullptr),
osrTempData_(nullptr),
mutatingBackedgeList_(false),
ionReturnOverride_(MagicValue(JS_ARG_POISON)),
jitcodeGlobalTable_(nullptr)
{
}
@@ -205,26 +200,21 @@ JitRuntime::initialize(JSContext *cx)
functionWrappers_ = cx->new_<VMWrapperMap>(cx);
if (!functionWrappers_ || !functionWrappers_->init())
return false;
JitSpew(JitSpew_Codegen, "# Emitting exception tail stub");
void *handler = JS_FUNC_TO_DATA_PTR(void *, jit::HandleException);
- void *handlerParallel = JS_FUNC_TO_DATA_PTR(void *, jit::HandleParallelFailure);
exceptionTail_ = generateExceptionTailStub(cx, handler);
if (!exceptionTail_)
return false;
- exceptionTailParallel_ = generateExceptionTailStub(cx, handlerParallel);
- if (!exceptionTailParallel_)
- return false;
-
JitSpew(JitSpew_Codegen, "# Emitting bailout tail stub");
bailoutTail_ = generateBailoutTailStub(cx);
if (!bailoutTail_)
return false;
if (cx->runtime()->jitSupportsFloatingPoint) {
JitSpew(JitSpew_Codegen, "# Emitting bailout tables");
@@ -238,41 +228,31 @@ JitRuntime::initialize(JSContext *cx)
break;
bailoutTables_.infallibleAppend((JitCode *)nullptr);
bailoutTables_[id] = generateBailoutTable(cx, id);
if (!bailoutTables_[id])
return false;
}
JitSpew(JitSpew_Codegen, "# Emitting bailout handler");
- bailoutHandler_ = generateBailoutHandler(cx, SequentialExecution);
+ bailoutHandler_ = generateBailoutHandler(cx);
if (!bailoutHandler_)
return false;
- JitSpew(JitSpew_Codegen, "# Emitting parallel bailout handler");
- parallelBailoutHandler_ = generateBailoutHandler(cx, ParallelExecution);
- if (!parallelBailoutHandler_)
- return false;
-
JitSpew(JitSpew_Codegen, "# Emitting invalidator");
invalidator_ = generateInvalidator(cx);
if (!invalidator_)
return false;
}
JitSpew(JitSpew_Codegen, "# Emitting sequential arguments rectifier");
- argumentsRectifier_ = generateArgumentsRectifier(cx, SequentialExecution, &argumentsRectifierReturnAddr_);
+ argumentsRectifier_ = generateArgumentsRectifier(cx, &argumentsRectifierReturnAddr_);
if (!argumentsRectifier_)
return false;
- JitSpew(JitSpew_Codegen, "# Emitting parallel arguments rectifier");
- parallelArgumentsRectifier_ = generateArgumentsRectifier(cx, ParallelExecution, nullptr);
- if (!parallelArgumentsRectifier_)
- return false;
-
JitSpew(JitSpew_Codegen, "# Emitting EnterJIT sequence");
enterJIT_ = generateEnterJIT(cx, EnterJitOptimized);
if (!enterJIT_)
return false;
JitSpew(JitSpew_Codegen, "# Emitting EnterBaselineJIT sequence");
enterBaselineJIT_ = generateEnterJIT(cx, EnterJitBaseline);
if (!enterBaselineJIT_)
@@ -339,28 +319,16 @@ JitRuntime::debugTrapHandler(JSContext *
// be allocated in the atoms compartment.
AutoLockForExclusiveAccess lock(cx);
AutoCompartment ac(cx, cx->runtime()->atomsCompartment());
debugTrapHandler_ = generateDebugTrapHandler(cx);
}
return debugTrapHandler_;
}
-bool
-JitRuntime::ensureForkJoinGetSliceStubExists(JSContext *cx)
-{
- if (!forkJoinGetSliceStub_) {
- JitSpew(JitSpew_Codegen, "# Emitting ForkJoinGetSlice stub");
- AutoLockForExclusiveAccess lock(cx);
- AutoCompartment ac(cx, cx->runtime()->atomsCompartment());
- forkJoinGetSliceStub_ = generateForkJoinGetSliceStub(cx);
- }
- return !!forkJoinGetSliceStub_;
-}
-
uint8_t *
JitRuntime::allocateOsrTempData(size_t size)
{
osrTempData_ = (uint8_t *)js_realloc(osrTempData_, size);
return osrTempData_;
}
void
@@ -400,17 +368,16 @@ JitRuntime::patchIonBackedges(JSRuntime
}
JitCompartment::JitCompartment()
: stubCodes_(nullptr),
baselineCallReturnAddr_(nullptr),
baselineGetPropReturnAddr_(nullptr),
baselineSetPropReturnAddr_(nullptr),
stringConcatStub_(nullptr),
- parallelStringConcatStub_(nullptr),
regExpExecStub_(nullptr),
regExpTestStub_(nullptr),
activeParallelEntryScripts_(nullptr)
{
}
JitCompartment::~JitCompartment()
{
@@ -427,27 +394,21 @@ JitCompartment::initialize(JSContext *cx
return true;
}
bool
JitCompartment::ensureIonStubsExist(JSContext *cx)
{
if (!stringConcatStub_) {
- stringConcatStub_ = generateStringConcatStub(cx, SequentialExecution);
+ stringConcatStub_ = generateStringConcatStub(cx);
if (!stringConcatStub_)
return false;
}
- if (!parallelStringConcatStub_) {
- parallelStringConcatStub_ = generateStringConcatStub(cx, ParallelExecution);
- if (!parallelStringConcatStub_)
- return false;
- }
-
return true;
}
bool
JitCompartment::notifyOfActiveParallelEntryScript(JSContext *cx, HandleScript script)
{
// Fast path. The isParallelEntryScript bit guarantees that the script is
// already in the set.
@@ -485,17 +446,17 @@ jit::FinishOffThreadBuilder(JSContext *c
// Clean the references to the pending IonBuilder, if we just finished it.
if (builder->script()->hasIonScript() && builder->script()->pendingIonBuilder() == builder)
builder->script()->setPendingIonBuilder(cx, nullptr);
if (builder->isInList())
builder->remove();
// Clear the recompiling flag of the old ionScript, since we continue to
// use the old ionScript if recompiling fails.
- if (executionMode == SequentialExecution && builder->script()->hasIonScript())
+ if (builder->script()->hasIonScript())
builder->script()->ionScript()->clearRecompiling();
// Clean up if compilation did not succeed.
if (CompilingOffThread(builder->script(), executionMode)) {
SetIonScript(cx, builder->script(), executionMode,
builder->abortReason() == AbortReason_Disable
? ION_DISABLED_SCRIPT
: nullptr);
@@ -645,19 +606,16 @@ JitCompartment::sweep(FreeOp *fop, JSCom
if (!stubCodes_->lookup(static_cast<uint32_t>(ICStub::GetProp_Fallback)))
baselineGetPropReturnAddr_ = nullptr;
if (!stubCodes_->lookup(static_cast<uint32_t>(ICStub::SetProp_Fallback)))
baselineSetPropReturnAddr_ = nullptr;
if (stringConcatStub_ && !IsJitCodeMarked(&stringConcatStub_))
stringConcatStub_ = nullptr;
- if (parallelStringConcatStub_ && !IsJitCodeMarked(¶llelStringConcatStub_))
- parallelStringConcatStub_ = nullptr;
-
if (regExpExecStub_ && !IsJitCodeMarked(®ExpExecStub_))
regExpExecStub_ = nullptr;
if (regExpTestStub_ && !IsJitCodeMarked(®ExpTestStub_))
regExpTestStub_ = nullptr;
if (activeParallelEntryScripts_) {
for (ScriptSet::Enum e(*activeParallelEntryScripts_); !e.empty(); e.popFront()) {
@@ -840,18 +798,16 @@ IonScript::IonScript()
bailoutEntries_(0),
osiIndexOffset_(0),
osiIndexEntries_(0),
snapshots_(0),
snapshotsListSize_(0),
snapshotsRVATableSize_(0),
constantTable_(0),
constantEntries_(0),
- callTargetList_(0),
- callTargetEntries_(0),
backedgeList_(0),
backedgeEntries_(0),
invalidationCount_(0),
parallelAge_(0),
recompileInfo_(),
osrPcMismatchCounter_(0),
pendingBuilder_(nullptr)
{
@@ -860,18 +816,17 @@ IonScript::IonScript()
IonScript *
IonScript::New(JSContext *cx, types::RecompileInfo recompileInfo,
uint32_t frameSlots, uint32_t frameSize,
size_t snapshotsListSize, size_t snapshotsRVATableSize,
size_t recoversSize, size_t bailoutEntries,
size_t constants, size_t safepointIndices,
size_t osiIndices, size_t cacheEntries,
size_t runtimeSize, size_t safepointsSize,
- size_t callTargetEntries, size_t backedgeEntries,
- OptimizationLevel optimizationLevel)
+ size_t backedgeEntries, OptimizationLevel optimizationLevel)
{
static const int DataAlignment = sizeof(void *);
if (snapshotsListSize >= MAX_BUFFER_SIZE ||
(bailoutEntries >= MAX_BUFFER_SIZE / sizeof(uint32_t)))
{
js_ReportOutOfMemory(cx);
return nullptr;
@@ -884,28 +839,26 @@ IonScript::New(JSContext *cx, types::Rec
size_t paddedRecoversSize = AlignBytes(recoversSize, DataAlignment);
size_t paddedBailoutSize = AlignBytes(bailoutEntries * sizeof(uint32_t), DataAlignment);
size_t paddedConstantsSize = AlignBytes(constants * sizeof(Value), DataAlignment);
size_t paddedSafepointIndicesSize = AlignBytes(safepointIndices * sizeof(SafepointIndex), DataAlignment);
size_t paddedOsiIndicesSize = AlignBytes(osiIndices * sizeof(OsiIndex), DataAlignment);
size_t paddedCacheEntriesSize = AlignBytes(cacheEntries * sizeof(uint32_t), DataAlignment);
size_t paddedRuntimeSize = AlignBytes(runtimeSize, DataAlignment);
size_t paddedSafepointSize = AlignBytes(safepointsSize, DataAlignment);
- size_t paddedCallTargetSize = AlignBytes(callTargetEntries * sizeof(JSScript *), DataAlignment);
size_t paddedBackedgeSize = AlignBytes(backedgeEntries * sizeof(PatchableBackedge), DataAlignment);
size_t bytes = paddedSnapshotsSize +
paddedRecoversSize +
paddedBailoutSize +
paddedConstantsSize +
paddedSafepointIndicesSize+
paddedOsiIndicesSize +
paddedCacheEntriesSize +
paddedRuntimeSize +
paddedSafepointSize +
- paddedCallTargetSize +
paddedBackedgeSize;
IonScript *script = cx->zone()->pod_malloc_with_extra<IonScript, uint8_t>(bytes);
if (!script)
return nullptr;
new (script) IonScript();
uint32_t offsetCursor = sizeof(IonScript);
@@ -941,20 +894,16 @@ IonScript::New(JSContext *cx, types::Rec
script->recovers_ = offsetCursor;
script->recoversSize_ = recoversSize;
offsetCursor += paddedRecoversSize;
script->constantTable_ = offsetCursor;
script->constantEntries_ = constants;
offsetCursor += paddedConstantsSize;
- script->callTargetList_ = offsetCursor;
- script->callTargetEntries_ = callTargetEntries;
- offsetCursor += paddedCallTargetSize;
-
script->backedgeList_ = offsetCursor;
script->backedgeEntries_ = backedgeEntries;
offsetCursor += paddedBackedgeSize;
script->frameSlots_ = frameSlots;
script->frameSize_ = frameSize;
script->recompileInfo_ = recompileInfo;
@@ -969,21 +918,16 @@ IonScript::trace(JSTracer *trc)
if (method_)
MarkJitCode(trc, &method_, "method");
if (deoptTable_)
MarkJitCode(trc, &deoptTable_, "deoptimizationTable");
for (size_t i = 0; i < numConstants(); i++)
gc::MarkValue(trc, &getConstant(i), "constant");
-
- // No write barrier is needed for the call target list, as it's attached
- // at compilation time and is read only.
- for (size_t i = 0; i < callTargetEntries(); i++)
- gc::MarkScriptUnbarriered(trc, &callTargetList()[i], "callTarget");
}
/* static */ void
IonScript::writeBarrierPre(Zone *zone, IonScript *ionScript)
{
if (zone->needsIncrementalBarrier())
ionScript->trace(zone->barrierTracer());
}
@@ -1024,23 +968,16 @@ IonScript::copyBailoutTable(const Snapsh
void
IonScript::copyConstants(const Value *vp)
{
for (size_t i = 0; i < constantEntries_; i++)
constants()[i].init(vp[i]);
}
void
-IonScript::copyCallTargetEntries(JSScript **callTargets)
-{
- for (size_t i = 0; i < callTargetEntries_; i++)
- callTargetList()[i] = callTargets[i];
-}
-
-void
IonScript::copyPatchableBackedges(JSContext *cx, JitCode *code,
PatchableBackedgeInfo *backedges,
MacroAssembler &masm)
{
JitRuntime *jrt = cx->runtime()->jitRuntime();
JitRuntime::AutoMutateBackedges amb(jrt);
for (size_t i = 0; i < backedgeEntries_; i++) {
@@ -1375,31 +1312,16 @@ OptimizeMIR(MIRGenerator *mir)
return false;
IonSpewPass("Apply types");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("Apply types"))
return false;
}
- // Parallel Safety Analysis. Note that this may delete blocks containing
- // instructions pointed to by the dependency() field of instructions which
- // are not deleted, leaving them dangling. This is ok, since we'll rerun
- // AliasAnalysis, which recomputes them, before they're needed.
- if (graph.entryBlock()->info().executionMode() == ParallelExecution) {
- AutoTraceLog log(logger, TraceLogger_ParallelSafetyAnalysis);
- ParallelSafetyAnalysis analysis(mir, graph);
- if (!analysis.analyze())
- return false;
- IonSpewPass("Parallel Safety Analysis");
- AssertExtendedGraphCoherency(graph);
- if (mir->shouldCancel("Parallel Safety Analysis"))
- return false;
- }
-
ValueNumberer gvn(mir, graph);
if (!gvn.init())
return false;
// Alias analysis is required for LICM and GVN so that we don't move
// loads across stores.
if (mir->optimizationInfo().licmEnabled() ||
mir->optimizationInfo().gvnEnabled())
@@ -1762,19 +1684,17 @@ AttachFinishedCompilations(JSContext *cx
break;
}
}
if (!builder)
break;
// Try to defer linking if the script is on the stack, to postpone
// invalidating them.
- if (builder->info().executionMode() == SequentialExecution &&
- builder->script()->hasIonScript())
- {
+ if (builder->script()->hasIonScript()) {
bool onStack = false;
for (JitActivationIterator iter(cx->runtime()); !iter.done(); ++iter) {
for (JitFrameIterator it(iter); !it.done(); ++it) {
if (!it.isIonJS())
continue;
if (it.checkInvalidation())
continue;
@@ -1870,18 +1790,17 @@ TrackPropertiesForSingletonScopes(JSCont
if (scope->is<CallObject>() && scope->hasSingletonType())
TrackAllProperties(cx, scope);
}
}
static AbortReason
IonCompile(JSContext *cx, JSScript *script,
BaselineFrame *baselineFrame, jsbytecode *osrPc, bool constructing,
- ExecutionMode executionMode, bool recompile,
- OptimizationLevel optimizationLevel)
+ bool recompile, OptimizationLevel optimizationLevel)
{
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, script);
AutoTraceLog logScript(logger, event);
AutoTraceLog logCompile(logger, TraceLogger_IonCompilation);
MOZ_ASSERT(optimizationLevel > Optimization_DontCompile);
@@ -1906,33 +1825,26 @@ IonCompile(JSContext *cx, JSScript *scri
types::AutoEnterAnalysis enter(cx);
if (!cx->compartment()->ensureJitCompartmentExists(cx))
return AbortReason_Alloc;
if (!cx->compartment()->jitCompartment()->ensureIonStubsExist(cx))
return AbortReason_Alloc;
- if (executionMode == ParallelExecution &&
- LIRGenerator::allowInlineForkJoinGetSlice() &&
- !cx->runtime()->jitRuntime()->ensureForkJoinGetSliceStubExists(cx))
- {
- return AbortReason_Alloc;
- }
-
MIRGraph *graph = alloc->new_<MIRGraph>(temp);
if (!graph)
return AbortReason_Alloc;
InlineScriptTree *inlineScriptTree = InlineScriptTree::New(temp, nullptr, nullptr, script);
if (!inlineScriptTree)
return AbortReason_Alloc;
CompileInfo *info = alloc->new_<CompileInfo>(script, script->functionNonDelazifying(), osrPc,
- constructing, executionMode,
+ constructing, SequentialExecution,
script->needsArgsObj(), inlineScriptTree);
if (!info)
return AbortReason_Alloc;
BaselineInspector *inspector = alloc->new_<BaselineInspector>(script);
if (!inspector)
return AbortReason_Alloc;
@@ -1953,25 +1865,23 @@ IonCompile(JSContext *cx, JSScript *scri
IonBuilder *builder = alloc->new_<IonBuilder>((JSContext *) nullptr,
CompileCompartment::get(cx->compartment()),
options, temp, graph, constraints,
inspector, info, optimizationInfo,
baselineFrameInspector);
if (!builder)
return AbortReason_Alloc;
- MOZ_ASSERT(recompile == HasIonScript(builder->script(), executionMode));
- MOZ_ASSERT(CanIonCompile(builder->script(), executionMode));
+ MOZ_ASSERT(recompile == builder->script()->hasIonScript());
+ MOZ_ASSERT(CanIonCompile(builder->script(), SequentialExecution));
RootedScript builderScript(cx, builder->script());
- if (recompile) {
- MOZ_ASSERT(executionMode == SequentialExecution);
+ if (recompile)
builderScript->ionScript()->setRecompiling();
- }
#ifdef DEBUG
IonSpewFunction ionSpewFunction(graph, builderScript);
#endif
bool succeeded = builder->build();
builder->clearForBackEnd();
@@ -1988,17 +1898,17 @@ IonCompile(JSContext *cx, JSScript *scri
}
}
return reason;
}
// If possible, compile the script off thread.
if (OffThreadCompilationAvailable(cx)) {
if (!recompile)
- SetIonScript(cx, builderScript, executionMode, ION_COMPILING_SCRIPT);
+ builderScript->setIonScript(cx, ION_COMPILING_SCRIPT);
JitSpew(JitSpew_IonLogs, "Can't log script %s:%d. (Compiled on background thread.)",
builderScript->filename(), builderScript->lineno());
if (!StartOffThreadIonCompile(cx, builder)) {
JitSpew(JitSpew_IonAbort, "Unable to start off-thread ion compilation.");
return AbortReason_Alloc;
}
@@ -2100,35 +2010,28 @@ CanIonCompileScript(JSContext *cx, JSScr
{
if (!script->canIonCompile() || !CheckScript(cx, script, osr))
return false;
return CheckScriptSize(cx, script) == Method_Compiled;
}
static OptimizationLevel
-GetOptimizationLevel(HandleScript script, jsbytecode *pc, ExecutionMode executionMode)
+GetOptimizationLevel(HandleScript script, jsbytecode *pc)
{
- if (executionMode == ParallelExecution)
- return Optimization_Normal;
-
- MOZ_ASSERT(executionMode == SequentialExecution);
-
return js_IonOptimizations.levelForScript(script, pc);
}
static MethodStatus
Compile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode *osrPc,
- bool constructing, ExecutionMode executionMode, bool forceRecompile = false)
+ bool constructing, bool forceRecompile = false)
{
MOZ_ASSERT(jit::IsIonEnabled(cx));
MOZ_ASSERT(jit::IsBaselineEnabled(cx));
MOZ_ASSERT_IF(osrPc != nullptr, LoopEntryCanIonOsr(osrPc));
- MOZ_ASSERT_IF(executionMode == ParallelExecution, !osrFrame && !osrPc);
- MOZ_ASSERT_IF(executionMode == ParallelExecution, !HasIonScript(script, executionMode));
if (!script->hasBaselineScript())
return Method_Skipped;
if (script->isDebuggee() || (osrFrame && osrFrame->isDebuggee())) {
JitSpew(JitSpew_IonAbort, "debugging");
return Method_Skipped;
}
@@ -2140,21 +2043,21 @@ Compile(JSContext *cx, HandleScript scri
MethodStatus status = CheckScriptSize(cx, script);
if (status != Method_Compiled) {
JitSpew(JitSpew_IonAbort, "Aborted compilation of %s:%d", script->filename(), script->lineno());
return status;
}
bool recompile = false;
- OptimizationLevel optimizationLevel = GetOptimizationLevel(script, osrPc, executionMode);
+ OptimizationLevel optimizationLevel = GetOptimizationLevel(script, osrPc);
if (optimizationLevel == Optimization_DontCompile)
return Method_Skipped;
- IonScript *scriptIon = GetIonScript(script, executionMode);
+ IonScript *scriptIon = script->maybeIonScript();
if (scriptIon) {
if (!scriptIon->method())
return Method_CantCompile;
// Don't recompile/overwrite higher optimized code,
// with a lower optimization level.
if (optimizationLevel <= scriptIon->optimizationLevel() && !forceRecompile)
return Method_Compiled;
@@ -2164,31 +2067,31 @@ Compile(JSContext *cx, HandleScript scri
return Method_Compiled;
if (osrPc)
scriptIon->resetOsrPcMismatchCounter();
recompile = true;
}
- AbortReason reason = IonCompile(cx, script, osrFrame, osrPc, constructing, executionMode,
+ AbortReason reason = IonCompile(cx, script, osrFrame, osrPc, constructing,
recompile, optimizationLevel);
if (reason == AbortReason_Error)
return Method_Error;
if (reason == AbortReason_Disable)
return Method_CantCompile;
if (reason == AbortReason_Alloc) {
js_ReportOutOfMemory(cx);
return Method_Error;
}
// Compilation succeeded or we invalidated right away or an inlining/alloc abort
- if (HasIonScript(script, executionMode))
+ if (script->hasIonScript())
return Method_Compiled;
return Method_Skipped;
}
} // namespace jit
} // namespace js
// Decide if a transition from interpreter execution to Ion code should occur.
@@ -2234,17 +2137,17 @@ jit::CanEnterAtBranch(JSContext *cx, JSS
// Attempt compilation.
// - Returns Method_Compiled if the right ionscript is present
// (Meaning it was present or a sequantial compile finished)
// - Returns Method_Skipped if pc doesn't match
// (This means a background thread compilation with that pc could have started or not.)
RootedScript rscript(cx, script);
MethodStatus status = Compile(cx, rscript, osrFrame, pc, osrFrame->isConstructing(),
- SequentialExecution, force);
+ force);
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(cx, script);
return status;
}
// Return the compilation was skipped when the osr pc wasn't adjusted.
// This can happen when there was still an IonScript available and a
@@ -2304,18 +2207,17 @@ jit::CanEnter(JSContext *cx, RunState &s
if (js_JitOptions.eagerCompilation && !rscript->hasBaselineScript()) {
MethodStatus status = CanEnterBaselineMethod(cx, state);
if (status != Method_Compiled)
return status;
}
// Attempt compilation. Returns Method_Compiled if already compiled.
bool constructing = state.isInvoke() && state.asInvoke()->constructing();
- MethodStatus status =
- Compile(cx, rscript, nullptr, nullptr, constructing, SequentialExecution);
+ MethodStatus status = Compile(cx, rscript, nullptr, nullptr, constructing);
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(cx, rscript);
return status;
}
return Method_Compiled;
}
@@ -2331,18 +2233,17 @@ jit::CompileFunctionForBaseline(JSContex
// Mark as forbidden if frame can't be handled.
if (!CheckFrame(frame)) {
ForbidCompilation(cx, script);
return Method_CantCompile;
}
// Attempt compilation. Returns Method_Compiled if already compiled.
- MethodStatus status =
- Compile(cx, script, frame, nullptr, frame->isConstructing(), SequentialExecution);
+ MethodStatus status = Compile(cx, script, frame, nullptr, frame->isConstructing());
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(cx, script);
return status;
}
return Method_Compiled;
}
@@ -2350,71 +2251,27 @@ jit::CompileFunctionForBaseline(JSContex
MethodStatus
jit::Recompile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode *osrPc,
bool constructing, bool force)
{
MOZ_ASSERT(script->hasIonScript());
if (script->ionScript()->isRecompiling())
return Method_Compiled;
- MethodStatus status =
- Compile(cx, script, osrFrame, osrPc, constructing, SequentialExecution, force);
+ MethodStatus status = Compile(cx, script, osrFrame, osrPc, constructing, force);
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(cx, script);
return status;
}
return Method_Compiled;
}
MethodStatus
-jit::CanEnterInParallel(JSContext *cx, HandleScript script)
-{
- // Skip if the script has been disabled.
- //
- // Note: We return Method_Skipped in this case because the other
- // CanEnter() methods do so. However, ForkJoin.cpp detects this
- // condition differently treats it more like an error.
- if (!script->canParallelIonCompile())
- return Method_Skipped;
-
- // Skip if the script is being compiled off thread.
- if (script->isParallelIonCompilingOffThread())
- return Method_Skipped;
-
- MethodStatus status = Compile(cx, script, nullptr, nullptr, false, ParallelExecution);
- if (status != Method_Compiled) {
- if (status == Method_CantCompile)
- ForbidCompilation(cx, script, ParallelExecution);
- return status;
- }
-
- // This can GC, so afterward, script->parallelIon is
- // not guaranteed to be valid.
- if (!cx->runtime()->jitRuntime()->enterIon())
- return Method_Error;
-
- // Subtle: it is possible for GC to occur during
- // compilation of one of the invoked functions, which
- // would cause the earlier functions (such as the
- // kernel itself) to be collected. In this event, we
- // give up and fallback to sequential for now.
- if (!script->hasParallelIonScript()) {
- parallel::Spew(
- parallel::SpewCompile,
- "Script %p:%s:%u was garbage-collected or invalidated",
- script.get(), script->filename(), script->lineno());
- return Method_Skipped;
- }
-
- return Method_Compiled;
-}
-
-MethodStatus
jit::CanEnterUsingFastInvoke(JSContext *cx, HandleScript script, uint32_t numActualArgs)
{
MOZ_ASSERT(jit::IsIonEnabled(cx));
// Skip if the code is expected to result in a bailout.
if (!script->hasIonScript() || script->ionScript()->bailoutExpected())
return Method_Skipped;
@@ -2800,27 +2657,19 @@ jit::Invalidate(types::TypeZone &types,
continue;
SetIonScript(nullptr, script, executionMode, nullptr);
ionScript->decrementInvalidationCount(fop);
co->invalidate();
numInvalidations--;
// Wait for the scripts to get warm again before doing another
- // compile, unless either:
- // (1) we are recompiling *because* a script got hot;
- // (resetUses is false); or,
- // (2) we are invalidating a parallel script. This is because
- // the warmUpCounter only applies to sequential uses. Parallel
- // execution *requires* ion, and so we don't limit it to
- // methods with a high usage count (though we do check that
- // the warmUpCount is at least 1 when compiling the transitive
- // closure of potential callees, to avoid compiling things
- // that are never run at all).
- if (resetUses && executionMode != ParallelExecution)
+ // compile, unless we are recompiling *because* a script got hot
+ // (resetUses is false).
+ if (resetUses)
script->resetWarmUpCounter();
}
// Make sure we didn't leak references by invalidating the same IonScript
// multiple times in the above loop.
MOZ_ASSERT(!numInvalidations);
}
@@ -2839,18 +2688,17 @@ jit::IonScript::invalidate(JSContext *cx
types::RecompileInfoVector list;
if (!list.append(recompileInfo()))
return false;
Invalidate(cx, list, resetUses, true);
return true;
}
bool
-jit::Invalidate(JSContext *cx, JSScript *script, ExecutionMode mode, bool resetUses,
- bool cancelOffThread)
+jit::Invalidate(JSContext *cx, JSScript *script, bool resetUses, bool cancelOffThread)
{
MOZ_ASSERT(script->hasIonScript());
if (cx->runtime()->spsProfiler.enabled()) {
// Register invalidation with profiler.
// Format of event payload string:
// "<filename>:<lineno>"
@@ -2866,135 +2714,70 @@ jit::Invalidate(JSContext *cx, JSScript
// Construct the descriptive string.
JS_snprintf(buf, len, "Invalidate %s:%u", filename, (unsigned int)script->lineno());
cx->runtime()->spsProfiler.markEvent(buf);
js_free(buf);
}
types::RecompileInfoVector scripts;
-
- switch (mode) {
- case SequentialExecution:
- MOZ_ASSERT(script->hasIonScript());
- if (!scripts.append(script->ionScript()->recompileInfo()))
- return false;
- break;
- case ParallelExecution:
- MOZ_ASSERT(script->hasParallelIonScript());
- if (!scripts.append(script->parallelIonScript()->recompileInfo()))
- return false;
- break;
- default:
- MOZ_CRASH("No such execution mode");
- }
+ MOZ_ASSERT(script->hasIonScript());
+ if (!scripts.append(script->ionScript()->recompileInfo()))
+ return false;
Invalidate(cx, scripts, resetUses, cancelOffThread);
return true;
}
-bool
-jit::Invalidate(JSContext *cx, JSScript *script, bool resetUses, bool cancelOffThread)
-{
- return Invalidate(cx, script, SequentialExecution, resetUses, cancelOffThread);
-}
-
static void
FinishInvalidationOf(FreeOp *fop, JSScript *script, IonScript *ionScript)
{
types::TypeZone &types = script->zone()->types;
// Note: If the script is about to be swept, the compiler output may have
// already been destroyed.
if (types::CompilerOutput *output = ionScript->recompileInfo().compilerOutput(types))
output->invalidate();
// If this script has Ion code on the stack, invalidated() will return
// true. In this case we have to wait until destroying it.
if (!ionScript->invalidated())
jit::IonScript::Destroy(fop, ionScript);
}
-template <ExecutionMode mode>
void
jit::FinishInvalidation(FreeOp *fop, JSScript *script)
{
- // In all cases, nullptr out script->ion or script->parallelIon to avoid
- // re-entry.
- switch (mode) {
- case SequentialExecution:
- if (script->hasIonScript()) {
- IonScript *ion = script->ionScript();
- script->setIonScript(nullptr, nullptr);
- FinishInvalidationOf(fop, script, ion);
- }
- return;
-
- case ParallelExecution:
- if (script->hasParallelIonScript()) {
- IonScript *parallelIon = script->parallelIonScript();
- script->setParallelIonScript(nullptr);
- FinishInvalidationOf(fop, script, parallelIon);
- }
- return;
-
- default:
- MOZ_CRASH("bad execution mode");
+ // In all cases, nullptr out script->ion to avoid re-entry.
+ if (script->hasIonScript()) {
+ IonScript *ion = script->ionScript();
+ script->setIonScript(nullptr, nullptr);
+ FinishInvalidationOf(fop, script, ion);
}
}
-template void
-jit::FinishInvalidation<SequentialExecution>(FreeOp *fop, JSScript *script);
-
-template void
-jit::FinishInvalidation<ParallelExecution>(FreeOp *fop, JSScript *script);
-
void
jit::ForbidCompilation(JSContext *cx, JSScript *script)
{
- ForbidCompilation(cx, script, SequentialExecution);
-}
-
-void
-jit::ForbidCompilation(JSContext *cx, JSScript *script, ExecutionMode mode)
-{
- JitSpew(JitSpew_IonAbort, "Disabling Ion mode %d compilation of script %s:%d",
- mode, script->filename(), script->lineno());
+ JitSpew(JitSpew_IonAbort, "Disabling Ion compilation of script %s:%d",
+ script->filename(), script->lineno());
CancelOffThreadIonCompile(cx->compartment(), script);
- switch (mode) {
- case SequentialExecution:
- if (script->hasIonScript()) {
- // It is only safe to modify script->ion if the script is not currently
- // running, because JitFrameIterator needs to tell what ionScript to
- // use (either the one on the JSScript, or the one hidden in the
- // breadcrumbs Invalidation() leaves). Therefore, if invalidation
- // fails, we cannot disable the script.
- if (!Invalidate(cx, script, mode, false))
- return;
- }
-
- script->setIonScript(cx, ION_DISABLED_SCRIPT);
- return;
-
- case ParallelExecution:
- if (script->hasParallelIonScript()) {
- if (!Invalidate(cx, script, mode, false))
- return;
- }
-
- script->setParallelIonScript(ION_DISABLED_SCRIPT);
- return;
-
- default:
- MOZ_CRASH("No such execution mode");
+ if (script->hasIonScript()) {
+ // It is only safe to modify script->ion if the script is not currently
+ // running, because JitFrameIterator needs to tell what ionScript to
+ // use (either the one on the JSScript, or the one hidden in the
+ // breadcrumbs Invalidation() leaves). Therefore, if invalidation
+ // fails, we cannot disable the script.
+ if (!Invalidate(cx, script, false))
+ return;
}
- MOZ_CRASH("No such execution mode");
+ script->setIonScript(cx, ION_DISABLED_SCRIPT);
}
AutoFlushICache *
PerThreadData::autoFlushICache() const
{
return autoFlushICache_;
}
@@ -3134,57 +2917,45 @@ AutoFlushICache::~AutoFlushICache()
#endif
}
void
jit::PurgeCaches(JSScript *script)
{
if (script->hasIonScript())
script->ionScript()->purgeCaches();
-
- if (script->hasParallelIonScript())
- script->parallelIonScript()->purgeCaches();
}
size_t
jit::SizeOfIonData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf)
{
size_t result = 0;
if (script->hasIonScript())
result += script->ionScript()->sizeOfIncludingThis(mallocSizeOf);
- if (script->hasParallelIonScript())
- result += script->parallelIonScript()->sizeOfIncludingThis(mallocSizeOf);
-
return result;
}
void
jit::DestroyJitScripts(FreeOp *fop, JSScript *script)
{
if (script->hasIonScript())
jit::IonScript::Destroy(fop, script->ionScript());
- if (script->hasParallelIonScript())
- jit::IonScript::Destroy(fop, script->parallelIonScript());
-
if (script->hasBaselineScript())
jit::BaselineScript::Destroy(fop, script->baselineScript());
}
void
jit::TraceJitScripts(JSTracer* trc, JSScript *script)
{
if (script->hasIonScript())
jit::IonScript::Trace(trc, script->ionScript());
- if (script->hasParallelIonScript())
- jit::IonScript::Trace(trc, script->parallelIonScript());
-
if (script->hasBaselineScript())
jit::BaselineScript::Trace(trc, script->baselineScript());
}
bool
jit::JitSupportsFloatingPoint()
{
return js::jit::MacroAssembler::SupportsFloatingPoint();
--- a/js/src/jit/Ion.h
+++ b/js/src/jit/Ion.h
@@ -83,18 +83,16 @@ void SetJitContext(JitContext *ctx);
bool CanIonCompileScript(JSContext *cx, JSScript *script, bool osr);
MethodStatus CanEnterAtBranch(JSContext *cx, JSScript *script,
BaselineFrame *frame, jsbytecode *pc);
MethodStatus CanEnter(JSContext *cx, RunState &state);
MethodStatus CompileFunctionForBaseline(JSContext *cx, HandleScript script, BaselineFrame *frame);
MethodStatus CanEnterUsingFastInvoke(JSContext *cx, HandleScript script, uint32_t numActualArgs);
-MethodStatus CanEnterInParallel(JSContext *cx, HandleScript script);
-
MethodStatus
Recompile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode *osrPc,
bool constructing, bool force);
enum JitExecStatus
{
// The method call had to be aborted due to a stack limit check. This
// error indicates that Ion never attempted to clean up frames.
@@ -124,18 +122,16 @@ JitExecStatus IonCannon(JSContext *cx, R
JitExecStatus FastInvoke(JSContext *cx, HandleFunction fun, CallArgs &args);
// Walk the stack and invalidate active Ion frames for the invalid scripts.
void Invalidate(types::TypeZone &types, FreeOp *fop,
const types::RecompileInfoVector &invalid, bool resetUses = true,
bool cancelOffThread = true);
void Invalidate(JSContext *cx, const types::RecompileInfoVector &invalid, bool resetUses = true,
bool cancelOffThread = true);
-bool Invalidate(JSContext *cx, JSScript *script, ExecutionMode mode, bool resetUses = true,
- bool cancelOffThread = true);
bool Invalidate(JSContext *cx, JSScript *script, bool resetUses = true,
bool cancelOffThread = true);
void ToggleBarriers(JS::Zone *zone, bool needs);
class IonBuilder;
class MIRGenerator;
class LIRGraph;
@@ -189,17 +185,16 @@ NumLocalsAndArgs(JSScript *script)
{
size_t num = 1 /* this */ + script->nfixed();
if (JSFunction *fun = script->functionNonDelazifying())
num += fun->nargs();
return num;
}
void ForbidCompilation(JSContext *cx, JSScript *script);
-void ForbidCompilation(JSContext *cx, JSScript *script, ExecutionMode mode);
void PurgeCaches(JSScript *script);
size_t SizeOfIonData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf);
void DestroyJitScripts(FreeOp *fop, JSScript *script);
void TraceJitScripts(JSTracer* trc, JSScript *script);
bool JitSupportsFloatingPoint();
bool JitSupportsSimd();
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -2060,17 +2060,16 @@ IsResumableMIRType(MIRType type)
case MIRType_MagicIsConstructing:
case MIRType_ObjectOrNull:
case MIRType_None:
case MIRType_Slots:
case MIRType_Elements:
case MIRType_Pointer:
case MIRType_Shape:
case MIRType_TypeObject:
- case MIRType_ForkJoinContext:
case MIRType_Float32x4:
case MIRType_Int32x4:
case MIRType_Doublex2:
return false;
}
MOZ_CRASH("Unknown MIRType.");
}
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -6257,21 +6257,16 @@ IonBuilder::jsop_initprop(PropertyName *
bool needsBarrier = true;
if (obj->resultTypeSet() &&
!obj->resultTypeSet()->propertyNeedsBarrier(constraints(), NameToId(name)))
{
needsBarrier = false;
}
- // In parallel execution, we never require write barriers. See
- // forkjoin.cpp for more information.
- if (info().executionMode() == ParallelExecution)
- needsBarrier = false;
-
if (templateObject->isFixedSlot(shape->slot())) {
MStoreFixedSlot *store = MStoreFixedSlot::New(alloc(), obj, shape->slot(), value);
if (needsBarrier)
store->setNeedsBarrier();
current->add(store);
return resumeAfter(store);
}
@@ -7143,17 +7138,17 @@ jit::TypeSetIncludes(types::TypeSet *typ
}
// Whether a write of the given value may need a post-write barrier for GC purposes.
bool
jit::NeedsPostBarrier(CompileInfo &info, MDefinition *value)
{
if (!GetJitContext()->runtime->gcNursery().exists())
return false;
- return info.executionMode() != ParallelExecution && value->mightBeType(MIRType_Object);
+ return value->mightBeType(MIRType_Object);
}
bool
IonBuilder::setStaticName(JSObject *staticObject, PropertyName *name)
{
jsid id = NameToId(name);
MOZ_ASSERT(staticObject->is<GlobalObject>() || staticObject->is<CallObject>());
@@ -7952,20 +7947,16 @@ IonBuilder::getElemTryCache(bool *emitte
BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), obj,
nullptr, types);
// Always add a barrier if the index might be a string or symbol, so that
// the cache can attach stubs for particular properties.
if (index->mightBeType(MIRType_String) || index->mightBeType(MIRType_Symbol))
barrier = BarrierKind::TypeSet;
- // See note about always needing a barrier in jsop_getprop.
- if (needsToMonitorMissingProperties(types))
- barrier = BarrierKind::TypeSet;
-
MInstruction *ins = MGetElementCache::New(alloc(), obj, index, barrier == BarrierKind::TypeSet);
current->add(ins);
current->push(ins);
if (!resumeAfter(ins))
return false;
@@ -8025,24 +8016,18 @@ IonBuilder::jsop_getelem_dense(MDefiniti
// Note: to help GVN, use the original MElements instruction and not
// MConvertElementsToDoubles as operand. This is fine because converting
// elements to double does not change the initialized length.
MInitializedLength *initLength = MInitializedLength::New(alloc(), elements);
current->add(initLength);
// If we can load the element as a definite double, make sure to check that
// the array has been converted to homogenous doubles first.
- //
- // NB: We disable this optimization in parallel execution mode
- // because it is inherently not threadsafe (how do you convert the
- // array atomically when there might be concurrent readers)?
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
- ExecutionMode executionMode = info().executionMode();
bool loadDouble =
- executionMode == SequentialExecution &&
barrier == BarrierKind::NoBarrier &&
loopDepth_ &&
!readOutOfBounds &&
!needsHoleCheck &&
knownType == MIRType_Double &&
objTypes &&
objTypes->convertDoubleElements(constraints()) == types::TemporaryTypeSet::AlwaysConvertToDoubles;
if (loadDouble)
@@ -8067,47 +8052,16 @@ IonBuilder::jsop_getelem_dense(MDefiniti
current->add(load);
// If maybeUndefined was true, the typeset must have undefined, and
// then either additional types or a barrier. This means we should
// never have a typed version of LoadElementHole.
MOZ_ASSERT(knownType == MIRType_Value);
}
- // If the array is being converted to doubles, but we've observed
- // just int, substitute a type set of int+double into the observed
- // type set. The reason for this is that, in the
- // interpreter+baseline, such arrays may consist of mixed
- // ints/doubles, but when we enter ion code, we will be coercing
- // all inputs to doubles. Therefore, the type barrier checking for
- // just int is highly likely (*almost* guaranteed) to fail sooner
- // or later. Essentially, by eagerly coercing to double, ion is
- // making the observed types outdated. To compensate for this, we
- // substitute a broader observed type set consisting of both ints
- // and doubles. There is perhaps a tradeoff here, so we limit this
- // optimization to parallel code, where it is needed to prevent
- // perpetual bailouts in some extreme cases. (Bug 977853)
- //
- // NB: we have not added a MConvertElementsToDoubles MIR, so we
- // cannot *assume* the result is a double.
- if (executionMode == ParallelExecution &&
- barrier != BarrierKind::NoBarrier &&
- types->getKnownMIRType() == MIRType_Int32 &&
- objTypes &&
- objTypes->convertDoubleElements(constraints()) == types::TemporaryTypeSet::AlwaysConvertToDoubles)
- {
- // Note: double implies int32 as well for typesets
- LifoAlloc *lifoAlloc = alloc().lifoAlloc();
- types = lifoAlloc->new_<types::TemporaryTypeSet>(lifoAlloc, types::Type::DoubleType());
- if (!types)
- return false;
-
- barrier = BarrierKind::NoBarrier; // Don't need a barrier anymore
- }
-
if (knownType != MIRType_Value)
load->setResultType(knownType);
current->push(load);
return pushTypeBarrier(load, types, barrier);
}
void
@@ -10020,42 +9974,32 @@ IonBuilder::getPropTryCache(bool *emitte
return true;
}
// Since getters have no guaranteed return values, we must barrier in order to be
// able to attach stubs for them.
if (inspector->hasSeenAccessedGetter(pc))
barrier = BarrierKind::TypeSet;
- if (needsToMonitorMissingProperties(types))
- barrier = BarrierKind::TypeSet;
-
// Caches can read values from prototypes, so update the barrier to
// reflect such possible values.
if (barrier != BarrierKind::TypeSet) {
BarrierKind protoBarrier =
PropertyReadOnPrototypeNeedsTypeBarrier(constraints(), obj, name, types);
if (protoBarrier != BarrierKind::NoBarrier) {
MOZ_ASSERT(barrier <= protoBarrier);
barrier = protoBarrier;
}
}
MGetPropertyCache *load = MGetPropertyCache::New(alloc(), obj, name,
barrier == BarrierKind::TypeSet);
// Try to mark the cache as idempotent.
- //
- // In parallel execution, idempotency of caches is ignored, since we
- // repeat the entire ForkJoin workload if we bail out. Note that it's
- // overly restrictive to mark everything as idempotent, because we can
- // treat non-idempotent caches in parallel as repeatable.
- if (obj->type() == MIRType_Object && !invalidatedIdempotentCache() &&
- info().executionMode() != ParallelExecution)
- {
+ if (obj->type() == MIRType_Object && !invalidatedIdempotentCache()) {
if (PropertyReadIsIdempotent(constraints(), obj, name))
load->setIdempotent();
}
// When we are in the context of making a call from the value returned from
// a property, we query the typeObject for the given property name to fill
// the InlinePropertyTable of the GetPropertyCache. This information is
// then used in inlineCallsite and inlineCalls, if the "this" definition is
@@ -10158,27 +10102,16 @@ IonBuilder::getPropTryInnerize(bool *emi
if (!getPropTryCache(emitted, inner, name, barrier, types) || *emitted)
return *emitted;
MOZ_ASSERT(*emitted == false);
return true;
}
bool
-IonBuilder::needsToMonitorMissingProperties(types::TemporaryTypeSet *types)
-{
- // GetPropertyParIC and GetElementParIC cannot safely call
- // TypeScript::Monitor to ensure that the observed type set contains
- // undefined. To account for possible missing properties, which property
- // types do not track, we must always insert a type barrier.
- return info().executionMode() == ParallelExecution &&
- !types->hasType(types::Type::UndefinedType());
-}
-
-bool
IonBuilder::jsop_setprop(PropertyName *name)
{
MDefinition *value = current->pop();
MDefinition *obj = current->pop();
bool emitted = false;
// Always use a call if we are doing the definite properties analysis and
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -434,17 +434,16 @@ class IonBuilder
bool getPropTryComplexPropOfTypedObject(bool *emitted, MDefinition *typedObj,
int32_t fieldOffset,
TypedObjectPrediction fieldTypeReprs,
size_t fieldIndex);
bool getPropTryInnerize(bool *emitted, MDefinition *obj, PropertyName *name,
types::TemporaryTypeSet *types);
bool getPropTryCache(bool *emitted, MDefinition *obj, PropertyName *name,
BarrierKind barrier, types::TemporaryTypeSet *types);
- bool needsToMonitorMissingProperties(types::TemporaryTypeSet *types);
// jsop_setprop() helpers.
bool setPropTryCommonSetter(bool *emitted, MDefinition *obj,
PropertyName *name, MDefinition *value);
bool setPropTryCommonDOMSetter(bool *emitted, MDefinition *obj,
MDefinition *value, JSFunction *setter,
bool isDOM);
bool setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
@@ -765,28 +764,22 @@ class IonBuilder
// Array intrinsics.
InliningStatus inlineUnsafePutElements(CallInfo &callInfo);
bool inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base);
bool inlineUnsafeSetTypedArrayElement(CallInfo &callInfo, uint32_t base,
ScalarTypeDescr::Type arrayType);
bool inlineUnsafeSetTypedObjectArrayElement(CallInfo &callInfo, uint32_t base,
ScalarTypeDescr::Type arrayType);
- InliningStatus inlineNewDenseArray(CallInfo &callInfo);
- InliningStatus inlineNewDenseArrayForSequentialExecution(CallInfo &callInfo);
- InliningStatus inlineNewDenseArrayForParallelExecution(CallInfo &callInfo);
// Slot intrinsics.
InliningStatus inlineUnsafeSetReservedSlot(CallInfo &callInfo);
InliningStatus inlineUnsafeGetReservedSlot(CallInfo &callInfo,
MIRType knownValueType);
- // ForkJoin intrinsics
- InliningStatus inlineForkJoinGetSlice(CallInfo &callInfo);
-
// TypedArray intrinsics.
InliningStatus inlineIsTypedArray(CallInfo &callInfo);
InliningStatus inlineTypedArrayLength(CallInfo &callInfo);
// TypedObject intrinsics and natives.
InliningStatus inlineObjectIsTypeDescr(CallInfo &callInfo);
InliningStatus inlineSetTypedObjectOffset(CallInfo &callInfo);
bool elementAccessIsTypedObjectArrayOfScalarType(MDefinition* obj, MDefinition* id,
@@ -803,17 +796,16 @@ class IonBuilder
InliningStatus inlineHasClass(CallInfo &callInfo, const Class *clasp,
const Class *clasp2 = nullptr,
const Class *clasp3 = nullptr,
const Class *clasp4 = nullptr);
InliningStatus inlineIsConstructing(CallInfo &callInfo);
InliningStatus inlineSubstringKernel(CallInfo &callInfo);
// Testing functions.
- InliningStatus inlineForceSequentialOrInParallelSection(CallInfo &callInfo);
InliningStatus inlineBailout(CallInfo &callInfo);
InliningStatus inlineAssertFloat32(CallInfo &callInfo);
// Bind function.
InliningStatus inlineBoundFunction(CallInfo &callInfo, JSFunction *target);
// Main inlining functions
InliningStatus inlineNativeCall(CallInfo &callInfo, JSFunction *target);
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -16,17 +16,16 @@
#include "jit/Ion.h"
#include "jit/JitcodeMap.h"
#include "jit/JitSpewer.h"
#include "jit/Linker.h"
#include "jit/Lowering.h"
#ifdef JS_ION_PERF
# include "jit/PerfSpewer.h"
#endif
-#include "jit/ParallelFunctions.h"
#include "jit/VMFunctions.h"
#include "vm/Shape.h"
#include "jit/JitFrames-inl.h"
#include "vm/Interpreter-inl.h"
#include "vm/Shape-inl.h"
using namespace js;
@@ -391,19 +390,17 @@ IonCache::attachStub(MacroAssembler &mas
// Update the success path to continue after the IC initial jump.
attacher.patchRejoinJump(masm, code);
// Replace the STUB_ADDR constant by the address of the generated stub, such
// as it can be kept alive even if the cache is flushed (see
// MarkJitExitFrame).
attacher.patchStubCodePointer(masm, code);
- // Update the failure path. Note it is this patch that makes the stub
- // accessible for parallel ICs so it should not be moved unless you really
- // know what is going on.
+ // Update the failure path.
attacher.patchNextStubJump(masm, code);
}
bool
IonCache::linkAndAttachStub(JSContext *cx, MacroAssembler &masm, StubAttacher &attacher,
IonScript *ion, const char *attachKind)
{
Rooted<JitCode *> code(cx);
@@ -1200,18 +1197,18 @@ CanAttachNativeGetProp(typename GetPropC
// proxies, IonBuilder can innerize and pass us the inner window (the global),
// see IonBuilder::getPropTryInnerize. This is fine for native getters because
// IsCacheableGetPropCallNative checks they can handle both the inner and
// outer object, but scripted getters would need a similar mechanism.
if (cache.allowGetters() &&
(IsCacheableGetPropCallNative(obj, holder, shape) ||
IsCacheableGetPropCallPropertyOp(obj, holder, shape)))
{
- // Don't enable getter call if cache is parallel or idempotent, since
- // they can be effectful. This is handled by allowGetters()
+ // Don't enable getter call if cache is idempotent, since they can be
+ // effectful. This is handled by allowGetters()
return GetPropertyIC::CanAttachCallGetter;
}
return GetPropertyIC::CanAttachNone;
}
bool
GetPropertyIC::allowArrayLength(Context cx, HandleObject obj) const
@@ -1795,164 +1792,16 @@ GetPropertyIC::reset()
RepatchIonCache::reset();
hasTypedArrayLengthStub_ = false;
hasSharedTypedArrayLengthStub_ = false;
hasStrictArgumentsLengthStub_ = false;
hasNormalArgumentsLengthStub_ = false;
hasGenericProxyStub_ = false;
}
-bool
-ParallelIonCache::initStubbedShapes(JSContext *cx)
-{
- MOZ_ASSERT(isAllocated());
- if (!stubbedShapes_) {
- stubbedShapes_ = cx->new_<ShapeSet>(cx);
- return stubbedShapes_ && stubbedShapes_->init();
- }
- return true;
-}
-
-bool
-ParallelIonCache::hasOrAddStubbedShape(LockedJSContext &cx, Shape *shape, bool *alreadyStubbed)
-{
- // Check if we have already stubbed the current object to avoid
- // attaching a duplicate stub.
- if (!initStubbedShapes(cx))
- return false;
- ShapeSet::AddPtr p = stubbedShapes_->lookupForAdd(shape);
- if ((*alreadyStubbed = !!p))
- return true;
- return stubbedShapes_->add(p, shape);
-}
-
-void
-ParallelIonCache::reset()
-{
- DispatchIonCache::reset();
- if (stubbedShapes_)
- stubbedShapes_->clear();
-}
-
-void
-ParallelIonCache::destroy()
-{
- DispatchIonCache::destroy();
- js_delete(stubbedShapes_);
-}
-
-void
-GetPropertyParIC::reset()
-{
- ParallelIonCache::reset();
- hasTypedArrayLengthStub_ = false;
- hasSharedTypedArrayLengthStub_ = false;
-}
-
-bool
-GetPropertyParIC::attachReadSlot(LockedJSContext &cx, IonScript *ion, HandleObject obj,
- HandleNativeObject holder, HandleShape shape)
-{
- // Ready to generate the read slot stub.
- DispatchStubPrepender attacher(*this);
- MacroAssembler masm(cx, ion);
- GenerateReadSlot(cx, ion, masm, attacher, obj, holder, shape, object(), output());
-
- return linkAndAttachStub(cx, masm, attacher, ion, "parallel reading");
-}
-
-bool
-GetPropertyParIC::attachArrayLength(LockedJSContext &cx, IonScript *ion, HandleObject obj)
-{
- MacroAssembler masm(cx, ion);
- DispatchStubPrepender attacher(*this);
- if (!GenerateArrayLength(cx, masm, attacher, obj, object(), output()))
- return false;
-
- return linkAndAttachStub(cx, masm, attacher, ion, "parallel array length");
-}
-
-bool
-GetPropertyParIC::attachTypedArrayLength(LockedJSContext &cx, IonScript *ion, HandleObject obj)
-{
- MacroAssembler masm(cx, ion);
- DispatchStubPrepender attacher(*this);
- GenerateTypedArrayLength(cx, masm, attacher, AnyTypedArrayLayout(obj), object(), output());
-
- setHasTypedArrayLengthStub(obj);
- return linkAndAttachStub(cx, masm, attacher, ion, "parallel typed array length");
-}
-
-bool
-GetPropertyParIC::update(ForkJoinContext *cx, size_t cacheIndex,
- HandleObject obj, MutableHandleValue vp)
-{
- IonScript *ion = GetTopJitJSScript(cx)->parallelIonScript();
- GetPropertyParIC &cache = ion->getCache(cacheIndex).toGetPropertyPar();
-
- // Grab the property early, as the pure path is fast anyways and doesn't
- // need a lock. If we can't do it purely, bail out of parallel execution.
- if (!GetPropertyPure(cx, obj, NameToId(cache.name()), vp.address()))
- return false;
-
- // Avoid unnecessary locking if cannot attach stubs.
- if (!cache.canAttachStub())
- return true;
-
- {
- // Lock the context before mutating the cache. Ideally we'd like to do
- // finer-grained locking, with one lock per cache. However, generating
- // new jitcode uses a global ExecutableAllocator tied to the runtime.
- LockedJSContext ncx(cx);
-
- if (cache.canAttachStub()) {
- bool alreadyStubbed;
- if (!cache.hasOrAddStubbedShape(ncx, obj->lastProperty(), &alreadyStubbed))
- return cx->setPendingAbortFatal(ParallelBailoutOutOfMemory);
- if (alreadyStubbed)
- return true;
-
- // See note about the stub limit in GetPropertyCache.
- bool attachedStub = false;
-
- {
- RootedShape shape(ncx);
- RootedNativeObject holder(ncx);
- RootedPropertyName name(ncx, cache.name());
-
- GetPropertyIC::NativeGetPropCacheability canCache =
- CanAttachNativeGetProp(ncx, cache, obj, name, &holder, &shape);
-
- if (canCache == GetPropertyIC::CanAttachReadSlot) {
- if (!cache.attachReadSlot(ncx, ion, obj, holder, shape))
- return cx->setPendingAbortFatal(ParallelBailoutOutOfMemory);
- attachedStub = true;
- }
-
- if (!attachedStub && canCache == GetPropertyIC::CanAttachArrayLength) {
- if (!cache.attachArrayLength(ncx, ion, obj))
- return cx->setPendingAbortFatal(ParallelBailoutOutOfMemory);
- attachedStub = true;
- }
- }
-
- if (!attachedStub && !cache.hasAnyTypedArrayLengthStub(obj) &&
- IsAnyTypedArray(obj) && cx->names().length == cache.name() &&
- (cache.output().type() == MIRType_Value || cache.output().type() == MIRType_Int32))
- {
- if (!cache.attachTypedArrayLength(ncx, ion, obj))
- return cx->setPendingAbortFatal(ParallelBailoutOutOfMemory);
- attachedStub = true;
- }
- }
- }
-
- return true;
-}
-
void
IonCache::disable()
{
reset();
this->disabled_ = 1;
}
void
@@ -2904,122 +2753,16 @@ SetPropertyIC::update(JSContext *cx, siz
void
SetPropertyIC::reset()
{
RepatchIonCache::reset();
hasGenericProxyStub_ = false;
}
-bool
-SetPropertyParIC::update(ForkJoinContext *cx, size_t cacheIndex, HandleObject obj,
- HandleValue value)
-{
- MOZ_ASSERT(cx->isThreadLocal(obj));
-
- IonScript *ion = GetTopJitJSScript(cx)->parallelIonScript();
- SetPropertyParIC &cache = ion->getCache(cacheIndex).toSetPropertyPar();
-
- RootedValue v(cx, value);
- RootedId id(cx, AtomToId(cache.name()));
-
- if (!obj->isNative())
- return false;
- RootedNativeObject nobj(cx, &obj->as<NativeObject>());
-
- // Avoid unnecessary locking if cannot attach stubs.
- if (!cache.canAttachStub()) {
- return baseops::SetPropertyHelper<ParallelExecution>(
- cx, nobj, nobj, id, baseops::Qualified, &v, cache.strict());
- }
-
- SetPropertyIC::NativeSetPropCacheability canCache = SetPropertyIC::CanAttachNone;
- bool attachedStub = false;
-
- {
- // See note about locking context in GetPropertyParIC::update.
- LockedJSContext ncx(cx);
-
- if (cache.canAttachStub()) {
- bool alreadyStubbed;
- if (!cache.hasOrAddStubbedShape(ncx, nobj->lastProperty(), &alreadyStubbed))
- return cx->setPendingAbortFatal(ParallelBailoutOutOfMemory);
- if (alreadyStubbed) {
- return baseops::SetPropertyHelper<ParallelExecution>(
- cx, nobj, nobj, id, baseops::Qualified, &v, cache.strict());
- }
-
- // If the object has a lazy type, we need to de-lazify it, but
- // this is not safe in parallel.
- if (nobj->hasLazyType())
- return false;
-
- {
- RootedShape shape(cx);
- RootedNativeObject holder(cx);
- bool checkTypeset;
- canCache = CanAttachNativeSetProp(cx, nobj, id, cache.value(), cache.needsTypeBarrier(),
- &holder, &shape, &checkTypeset);
-
- if (canCache == SetPropertyIC::CanAttachSetSlot) {
- if (!cache.attachSetSlot(ncx, ion, nobj, shape, checkTypeset))
- return cx->setPendingAbortFatal(ParallelBailoutOutOfMemory);
- attachedStub = true;
- }
- }
- }
- }
-
- uint32_t oldSlots = nobj->numDynamicSlots();
- RootedShape oldShape(cx, nobj->lastProperty());
- RootedTypeObject oldType(cx, nobj->type());
-
- if (!baseops::SetPropertyHelper<ParallelExecution>(cx, nobj, nobj, id, baseops::Qualified, &v,
- cache.strict()))
- {
- return false;
- }
-
- bool checkTypeset;
- if (!attachedStub && canCache == SetPropertyIC::MaybeCanAttachAddSlot &&
- IsPropertyAddInlineable(nobj, id,
- cache.value(), oldSlots, oldShape, cache.needsTypeBarrier(),
- &checkTypeset))
- {
- LockedJSContext ncx(cx);
- if (cache.canAttachStub() && !cache.attachAddSlot(ncx, ion, nobj, oldShape, oldType, checkTypeset))
- return cx->setPendingAbortFatal(ParallelBailoutOutOfMemory);
- }
-
- return true;
-}
-
-bool
-SetPropertyParIC::attachSetSlot(LockedJSContext &cx, IonScript *ion, HandleNativeObject obj,
- HandleShape shape, bool checkTypeset)
-{
- MacroAssembler masm(cx, ion);
- DispatchStubPrepender attacher(*this);
- GenerateSetSlot(cx, masm, attacher, obj, shape, object(), value(), needsTypeBarrier(),
- checkTypeset);
- return linkAndAttachStub(cx, masm, attacher, ion, "parallel setting");
-}
-
-bool
-SetPropertyParIC::attachAddSlot(LockedJSContext &cx, IonScript *ion, HandleNativeObject obj,
- HandleShape oldShape, HandleTypeObject oldType, bool checkTypeset)
-{
- MOZ_ASSERT_IF(!needsTypeBarrier(), !checkTypeset);
-
- MacroAssembler masm(cx, ion);
- DispatchStubPrepender attacher(*this);
- GenerateAddSlot(cx, masm, attacher, obj, oldShape, oldType, object(), value(), checkTypeset);
- return linkAndAttachStub(cx, masm, attacher, ion, "parallel adding");
-}
-
const size_t GetElementIC::MAX_FAILED_UPDATES = 16;
/* static */ bool
GetElementIC::canAttachGetProp(JSObject *obj, const Value &idval, jsid id)
{
uint32_t dummy;
return obj->isNative() &&
idval.isString() &&
@@ -3894,201 +3637,16 @@ SetElementIC::update(JSContext *cx, size
void
SetElementIC::reset()
{
RepatchIonCache::reset();
hasDenseStub_ = false;
}
bool
-SetElementParIC::attachDenseElement(LockedJSContext &cx, IonScript *ion, HandleObject obj,
- const Value &idval)
-{
- MacroAssembler masm(cx, ion);
- DispatchStubPrepender attacher(*this);
- if (!GenerateSetDenseElement(cx, masm, attacher, obj, idval,
- guardHoles(), object(), index(),
- value(), tempToUnboxIndex(),
- temp()))
- {
- return false;
- }
-
- const char *message = guardHoles() ?
- "parallel dense array (holes)" :
- "parallel dense array";
-
- return linkAndAttachStub(cx, masm, attacher, ion, message);
-}
-
-bool
-SetElementParIC::attachTypedArrayElement(LockedJSContext &cx, IonScript *ion,
- HandleObject tarr)
-{
- MacroAssembler masm(cx, ion);
- DispatchStubPrepender attacher(*this);
- if (!GenerateSetTypedArrayElement(cx, masm, attacher, tarr,
- object(), index(), value(),
- tempToUnboxIndex(), temp(), tempDouble(), tempFloat32()))
- {
- return false;
- }
-
- return linkAndAttachStub(cx, masm, attacher, ion, "parallel typed array");
-}
-
-bool
-SetElementParIC::update(ForkJoinContext *cx, size_t cacheIndex, HandleObject obj,
- HandleValue idval, HandleValue value)
-{
- IonScript *ion = GetTopJitJSScript(cx)->parallelIonScript();
- SetElementParIC &cache = ion->getCache(cacheIndex).toSetElementPar();
-
- // Avoid unnecessary locking if cannot attach stubs.
- if (!cache.canAttachStub())
- return SetElementPar(cx, obj, idval, value, cache.strict());
-
- {
- LockedJSContext ncx(cx);
-
- if (cache.canAttachStub()) {
- bool alreadyStubbed;
- if (!cache.hasOrAddStubbedShape(ncx, obj->lastProperty(), &alreadyStubbed))
- return cx->setPendingAbortFatal(ParallelBailoutOutOfMemory);
- if (alreadyStubbed)
- return SetElementPar(cx, obj, idval, value, cache.strict());
-
- bool attachedStub = false;
- if (IsDenseElementSetInlineable(obj, idval)) {
- if (!cache.attachDenseElement(ncx, ion, obj, idval))
- return cx->setPendingAbortFatal(ParallelBailoutOutOfMemory);
- attachedStub = true;
- }
- if (!attachedStub && IsTypedArrayElementSetInlineable(obj, idval, value)) {
- if (!cache.attachTypedArrayElement(ncx, ion, obj))
- return cx->setPendingAbortFatal(ParallelBailoutOutOfMemory);
- }
- }
- }
-
- return SetElementPar(cx, obj, idval, value, cache.strict());
-}
-
-bool
-GetElementParIC::attachReadSlot(LockedJSContext &cx, IonScript *ion, HandleObject obj,
- const Value &idval, HandlePropertyName name, HandleNativeObject holder,
- HandleShape shape)
-{
- MacroAssembler masm(cx, ion);
- DispatchStubPrepender attacher(*this);
-
- // Guard on the index value.
- Label failures;
- ValueOperand val = index().reg().valueReg();
- masm.branchTestValue(Assembler::NotEqual, val, idval, &failures);
-
- GenerateReadSlot(cx, ion, masm, attacher, obj, holder, shape, object(), output(),
- &failures);
-
- return linkAndAttachStub(cx, masm, attacher, ion, "parallel getelem reading");
-}
-
-bool
-GetElementParIC::attachDenseElement(LockedJSContext &cx, IonScript *ion, HandleObject obj,
- const Value &idval)
-{
- MacroAssembler masm(cx, ion);
- DispatchStubPrepender attacher(*this);
- if (!GenerateDenseElement(cx, masm, attacher, obj, idval, object(), index(), output()))
- return false;
-
- return linkAndAttachStub(cx, masm, attacher, ion, "parallel dense element");
-}
-
-bool
-GetElementParIC::attachTypedArrayElement(LockedJSContext &cx, IonScript *ion,
- HandleObject tarr, const Value &idval)
-{
- MacroAssembler masm(cx, ion);
- DispatchStubPrepender attacher(*this);
- GenerateGetTypedArrayElement(cx, masm, attacher, tarr, idval, object(), index(), output(),
- allowDoubleResult());
- return linkAndAttachStub(cx, masm, attacher, ion, "parallel typed array");
-}
-
-bool
-GetElementParIC::update(ForkJoinContext *cx, size_t cacheIndex, HandleObject obj,
- HandleValue idval, MutableHandleValue vp)
-{
- IonScript *ion = GetTopJitJSScript(cx)->parallelIonScript();
- GetElementParIC &cache = ion->getCache(cacheIndex).toGetElementPar();
-
- // Try to get the element early, as the pure path doesn't need a lock. If
- // we can't do it purely, bail out of parallel execution.
- if (!GetObjectElementOperationPure(cx, obj, idval, vp.address()))
- return false;
-
- // Avoid unnecessary locking if cannot attach stubs.
- if (!cache.canAttachStub())
- return true;
-
- {
- // See note about locking context in GetPropertyParIC::update.
- LockedJSContext ncx(cx);
-
- if (cache.canAttachStub()) {
- bool alreadyStubbed;
- if (!cache.hasOrAddStubbedShape(ncx, obj->lastProperty(), &alreadyStubbed))
- return cx->setPendingAbortFatal(ParallelBailoutOutOfMemory);
- if (alreadyStubbed)
- return true;
-
- jsid id;
- if (!ValueToIdPure(idval, &id))
- return false;
-
- bool attachedStub = false;
- if (cache.monitoredResult() &&
- GetElementIC::canAttachGetProp(obj, idval, id))
- {
- RootedShape shape(ncx);
- RootedNativeObject holder(ncx);
- RootedPropertyName name(ncx, JSID_TO_ATOM(id)->asPropertyName());
-
- GetPropertyIC::NativeGetPropCacheability canCache =
- CanAttachNativeGetProp(ncx, cache, obj, name, &holder, &shape);
-
- if (canCache == GetPropertyIC::CanAttachReadSlot)
- {
- if (!cache.attachReadSlot(ncx, ion, obj, idval, name, holder, shape))
- return cx->setPendingAbortFatal(ParallelBailoutOutOfMemory);
- attachedStub = true;
- }
- }
- if (!attachedStub &&
- GetElementIC::canAttachDenseElement(obj, idval))
- {
- if (!cache.attachDenseElement(ncx, ion, obj, idval))
- return cx->setPendingAbortFatal(ParallelBailoutOutOfMemory);
- attachedStub = true;
- }
- if (!attachedStub &&
- GetElementIC::canAttachTypedArrayElement(obj, idval, cache.output()))
- {
- if (!cache.attachTypedArrayElement(ncx, ion, obj, idval))
- return cx->setPendingAbortFatal(ParallelBailoutOutOfMemory);
- attachedStub = true;
- }
- }
- }
-
- return true;
-}
-
-bool
BindNameIC::attachGlobal(JSContext *cx, HandleScript outerScript, IonScript *ion,
HandleObject scopeChain)
{
MOZ_ASSERT(scopeChain->is<GlobalObject>());
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
RepatchStubAppender attacher(*this);
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -26,21 +26,17 @@ class LInstruction;
#define IONCACHE_KIND_LIST(_) \
_(GetProperty) \
_(SetProperty) \
_(GetElement) \
_(SetElement) \
_(BindName) \
_(Name) \
- _(CallsiteClone) \
- _(GetPropertyPar) \
- _(GetElementPar) \
- _(SetPropertyPar) \
- _(SetElementPar)
+ _(CallsiteClone)
// Forward declarations of Cache kinds.
#define FORWARD_DECLARE(kind) class kind##IC;
IONCACHE_KIND_LIST(FORWARD_DECLARE)
#undef FORWARD_DECLARE
class IonCacheVisitor
{
@@ -415,17 +411,18 @@ class RepatchIonCache : public IonCache
// jump to the previous stub on failure conditions, then overwrite the
// firstStub_ pointer with the newly generated stub.
//
// This style does not patch the already executing instruction stream, does
// not need to worry about cache coherence of cached jump addresses, and does
// not have to worry about aligning the exit jumps to ensure atomic patching,
// at the expense of an extra memory read to load the very first stub.
//
-// ICs that need to work in parallel execution need to be dispatch style.
+// ICs that need to work in parallel execution need to be dispatch
+// style. Since PJS's removal, nothing else yet uses this style of ICs.
//
// Control flow Pointers Memory load
// =======# ----. .----> ******
// # | | *
// #======> \-----/ *******
//
// Initial state:
//
@@ -1074,294 +1071,16 @@ class CallsiteCloneIC : public RepatchIo
}
bool attach(JSContext *cx, HandleScript outerScript, IonScript *ion,
HandleFunction original, HandleFunction clone);
static JSObject *update(JSContext *cx, size_t cacheIndex, HandleObject callee);
};
-class ParallelIonCache : public DispatchIonCache
-{
- protected:
- // A set of all objects that are stubbed. Used to detect duplicates in
- // parallel execution.
- ShapeSet *stubbedShapes_;
-
- ParallelIonCache()
- : stubbedShapes_(nullptr)
- {
- }
-
- bool initStubbedShapes(JSContext *cx);
-
- public:
- void reset();
- void destroy();
-
- bool hasOrAddStubbedShape(LockedJSContext &cx, Shape *shape, bool *alreadyStubbed);
-};
-
-class GetPropertyParIC : public ParallelIonCache
-{
- protected:
- Register object_;
- PropertyName *name_;
- TypedOrValueRegister output_;
- bool hasTypedArrayLengthStub_ : 1;
- bool hasSharedTypedArrayLengthStub_ : 1;
-
- public:
- GetPropertyParIC(Register object, PropertyName *name, TypedOrValueRegister output)
- : object_(object),
- name_(name),
- output_(output),
- hasTypedArrayLengthStub_(false),
- hasSharedTypedArrayLengthStub_(false)
- {
- }
-
- CACHE_HEADER(GetPropertyPar)
-
-#ifdef JS_CODEGEN_X86
- // x86 lacks a general purpose scratch register for dispatch caches and
- // must be given one manually.
- void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
-#endif
-
- void reset();
-
- Register object() const {
- return object_;
- }
- PropertyName *name() const {
- return name_;
- }
- TypedOrValueRegister output() const {
- return output_;
- }
- bool hasAnyTypedArrayLengthStub(HandleObject obj) const {
- return obj->is<TypedArrayObject>() ? hasTypedArrayLengthStub_ : hasSharedTypedArrayLengthStub_;
- }
-
- void setHasTypedArrayLengthStub(HandleObject obj) {
- if (obj->is<TypedArrayObject>()) {
- MOZ_ASSERT(!hasTypedArrayLengthStub_);
- hasTypedArrayLengthStub_ = true;
- } else {
- MOZ_ASSERT(!hasSharedTypedArrayLengthStub_);
- hasSharedTypedArrayLengthStub_ = true;
- }
- }
-
- // CanAttachNativeGetProp Helpers
- typedef LockedJSContext & Context;
- bool canMonitorSingletonUndefinedSlot(HandleObject, HandleShape) const { return true; }
- bool allowGetters() const { return false; }
- bool allowArrayLength(Context, HandleObject) const { return true; }
-
- bool attachReadSlot(LockedJSContext &cx, IonScript *ion,
- HandleObject obj, HandleNativeObject holder,
- HandleShape shape);
- bool attachArrayLength(LockedJSContext &cx, IonScript *ion, HandleObject obj);
- bool attachTypedArrayLength(LockedJSContext &cx, IonScript *ion, HandleObject obj);
-
- static bool update(ForkJoinContext *cx, size_t cacheIndex, HandleObject obj,
- MutableHandleValue vp);
-};
-
-class GetElementParIC : public ParallelIonCache
-{
- protected:
- Register object_;
- ConstantOrRegister index_;
- TypedOrValueRegister output_;
-
- bool monitoredResult_ : 1;
- bool allowDoubleResult_ : 1;
-
- public:
- GetElementParIC(Register object, ConstantOrRegister index,
- TypedOrValueRegister output, bool monitoredResult, bool allowDoubleResult)
- : object_(object),
- index_(index),
- output_(output),
- monitoredResult_(monitoredResult),
- allowDoubleResult_(allowDoubleResult)
- {
- }
-
- CACHE_HEADER(GetElementPar)
-
-#ifdef JS_CODEGEN_X86
- // x86 lacks a general purpose scratch register for dispatch caches and
- // must be given one manually.
- void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
-#endif
-
- Register object() const {
- return object_;
- }
- ConstantOrRegister index() const {
- return index_;
- }
- TypedOrValueRegister output() const {
- return output_;
- }
- bool monitoredResult() const {
- return monitoredResult_;
- }
- bool allowDoubleResult() const {
- return allowDoubleResult_;
- }
-
- // CanAttachNativeGetProp Helpers
- typedef LockedJSContext & Context;
- bool canMonitorSingletonUndefinedSlot(HandleObject, HandleShape) const { return true; }
- bool allowGetters() const { return false; }
- bool allowArrayLength(Context, HandleObject) const { return false; }
-
- bool attachReadSlot(LockedJSContext &cx, IonScript *ion, HandleObject obj, const Value &idval,
- HandlePropertyName name, HandleNativeObject holder, HandleShape shape);
- bool attachDenseElement(LockedJSContext &cx, IonScript *ion, HandleObject obj,
- const Value &idval);
- bool attachTypedArrayElement(LockedJSContext &cx, IonScript *ion, HandleObject tarr,
- const Value &idval);
-
- static bool update(ForkJoinContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
- MutableHandleValue vp);
-
-};
-
-class SetPropertyParIC : public ParallelIonCache
-{
- protected:
- Register object_;
- PropertyName *name_;
- ConstantOrRegister value_;
- bool strict_;
- bool needsTypeBarrier_;
-
- public:
- SetPropertyParIC(Register object, PropertyName *name, ConstantOrRegister value,
- bool strict, bool needsTypeBarrier)
- : object_(object),
- name_(name),
- value_(value),
- strict_(strict),
- needsTypeBarrier_(needsTypeBarrier)
- {
- }
-
- CACHE_HEADER(SetPropertyPar)
-
-#ifdef JS_CODEGEN_X86
- // x86 lacks a general purpose scratch register for dispatch caches and
- // must be given one manually.
- void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
-#endif
-
- Register object() const {
- return object_;
- }
- PropertyName *name() const {
- return name_;
- }
- ConstantOrRegister value() const {
- return value_;
- }
- bool strict() const {
- return strict_;
- }
- bool needsTypeBarrier() const {
- return needsTypeBarrier_;
- }
-
- bool attachSetSlot(LockedJSContext &cx, IonScript *ion, HandleNativeObject obj, HandleShape shape,
- bool checkTypeset);
- bool attachAddSlot(LockedJSContext &cx, IonScript *ion, HandleNativeObject obj,
- HandleShape oldShape, HandleTypeObject oldType, bool checkTypeset);
-
- static bool update(ForkJoinContext *cx, size_t cacheIndex, HandleObject obj,
- HandleValue value);
-};
-
-class SetElementParIC : public ParallelIonCache
-{
- protected:
- Register object_;
- Register tempToUnboxIndex_;
- Register temp_;
- FloatRegister tempDouble_;
- FloatRegister tempFloat32_;
- ValueOperand index_;
- ConstantOrRegister value_;
- bool strict_;
- bool guardHoles_;
-
- public:
- SetElementParIC(Register object, Register tempToUnboxIndex, Register temp,
- FloatRegister tempDouble, FloatRegister tempFloat32, ValueOperand index, ConstantOrRegister value,
- bool strict, bool guardHoles)
- : object_(object),
- tempToUnboxIndex_(tempToUnboxIndex),
- temp_(temp),
- tempDouble_(tempDouble),
- tempFloat32_(tempFloat32),
- index_(index),
- value_(value),
- strict_(strict),
- guardHoles_(guardHoles)
- {
- }
-
- CACHE_HEADER(SetElementPar)
-
-#ifdef JS_CODEGEN_X86
- // x86 lacks a general purpose scratch register for dispatch caches and
- // must be given one manually.
- void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
-#endif
-
- Register object() const {
- return object_;
- }
- Register tempToUnboxIndex() const {
- return tempToUnboxIndex_;
- }
- Register temp() const {
- return temp_;
- }
- FloatRegister tempDouble() const {
- return tempDouble_;
- }
- FloatRegister tempFloat32() const {
- return tempFloat32_;
- }
- ValueOperand index() const {
- return index_;
- }
- ConstantOrRegister value() const {
- return value_;
- }
- bool strict() const {
- return strict_;
- }
- bool guardHoles() const {
- return guardHoles_;
- }
-
- bool attachDenseElement(LockedJSContext &cx, IonScript *ion, HandleObject obj,
- const Value &idval);
- bool attachTypedArrayElement(LockedJSContext &cx, IonScript *ion, HandleObject tarr);
-
- static bool update(ForkJoinContext *cx, size_t cacheIndex, HandleObject obj,
- HandleValue idval, HandleValue value);
-};
-
#undef CACHE_HEADER
// Implement cache casts now that the compiler can see the inheritance.
#define CACHE_CASTS(ickind) \
ickind##IC &IonCache::to##ickind() \
{ \
MOZ_ASSERT(is##ickind()); \
return *static_cast<ickind##IC *>(this); \
--- a/js/src/jit/IonCode.h
+++ b/js/src/jit/IonCode.h
@@ -251,22 +251,16 @@ struct IonScript
// List of instructions needed to recover stack frames.
uint32_t recovers_;
uint32_t recoversSize_;
// Constant table for constants stored in snapshots.
uint32_t constantTable_;
uint32_t constantEntries_;
- // List of scripts that we call.
- //
- // Currently this is only non-nullptr for parallel IonScripts.
- uint32_t callTargetList_;
- uint32_t callTargetEntries_;
-
// List of patchable backedges which are threaded into the runtime's list.
uint32_t backedgeList_;
uint32_t backedgeEntries_;
// Number of references from invalidation records.
uint32_t invalidationCount_;
// If this is a parallel script, the number of major GC collections it has
@@ -328,19 +322,16 @@ struct IonScript
return (OsiIndex *) &bottomBuffer()[osiIndexOffset_];
}
uint32_t *cacheIndex() {
return (uint32_t *) &bottomBuffer()[cacheIndex_];
}
uint8_t *runtimeData() {
return &bottomBuffer()[runtimeData_];
}
- JSScript **callTargetList() {
- return (JSScript **) &bottomBuffer()[callTargetList_];
- }
PatchableBackedge *backedgeList() {
return (PatchableBackedge *) &bottomBuffer()[backedgeList_];
}
private:
void trace(JSTracer *trc);
public:
@@ -349,18 +340,17 @@ struct IonScript
static IonScript *New(JSContext *cx, types::RecompileInfo recompileInfo,
uint32_t frameLocals, uint32_t frameSize,
size_t snapshotsListSize, size_t snapshotsRVATableSize,
size_t recoversSize, size_t bailoutEntries,
size_t constants, size_t safepointIndexEntries,
size_t osiIndexEntries, size_t cacheEntries,
size_t runtimeSize, size_t safepointsSize,
- size_t callTargetEntries, size_t backedgeEntries,
- OptimizationLevel optimizationLevel);
+ size_t backedgeEntries, OptimizationLevel optimizationLevel);
static void Trace(JSTracer *trc, IonScript *script);
static void Destroy(FreeOp *fop, IonScript *script);
static inline size_t offsetOfMethod() {
return offsetof(IonScript, method_);
}
static inline size_t offsetOfOsrEntryOffset() {
return offsetof(IonScript, osrEntryOffset_);
@@ -485,19 +475,16 @@ struct IonScript
return recoversSize_;
}
const uint8_t *safepoints() const {
return reinterpret_cast<const uint8_t *>(this) + safepointsStart_;
}
size_t safepointsSize() const {
return safepointsSize_;
}
- size_t callTargetEntries() const {
- return callTargetEntries_;
- }
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
return mallocSizeOf(this);
}
PreBarrieredValue &getConstant(size_t index) {
MOZ_ASSERT(index < numConstants());
return constants()[index];
}
size_t numConstants() const {
@@ -547,17 +534,16 @@ struct IonScript
void copyRecovers(const RecoverWriter *writer);
void copyBailoutTable(const SnapshotOffset *table);
void copyConstants(const Value *vp);
void copySafepointIndices(const SafepointIndex *firstSafepointIndex, MacroAssembler &masm);
void copyOsiIndices(const OsiIndex *firstOsiIndex, MacroAssembler &masm);
void copyRuntimeData(const uint8_t *data);
void copyCacheEntries(const uint32_t *caches, MacroAssembler &masm);
void copySafepoints(const SafepointWriter *writer);
- void copyCallTargetEntries(JSScript **callTargets);
void copyPatchableBackedges(JSContext *cx, JitCode *code,
PatchableBackedgeInfo *backedges,
MacroAssembler &masm);
bool invalidated() const {
return invalidationCount_ != 0;
}
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -376,18 +376,17 @@ enum MIRType
MIRType_Value,
MIRType_ObjectOrNull,
MIRType_None, // Invalid, used as a placeholder.
MIRType_Slots, // A slots vector
MIRType_Elements, // An elements vector
MIRType_Pointer, // An opaque pointer that receives no special treatment
MIRType_Shape, // A Shape pointer.
MIRType_TypeObject, // A TypeObject pointer.
- MIRType_ForkJoinContext, // js::ForkJoinContext*
- MIRType_Last = MIRType_ForkJoinContext,
+ MIRType_Last = MIRType_TypeObject,
MIRType_Float32x4 = MIRType_Float32 | (2 << VECTOR_SCALE_SHIFT),
MIRType_Int32x4 = MIRType_Int32 | (2 << VECTOR_SCALE_SHIFT),
MIRType_Doublex2 = MIRType_Double | (1 << VECTOR_SCALE_SHIFT)
};
static inline MIRType
MIRTypeFromValueType(JSValueType type)
{
@@ -491,18 +490,16 @@ StringFromMIRType(MIRType type)
case MIRType_None:
return "None";
case MIRType_Slots:
return "Slots";
case MIRType_Elements:
return "Elements";
case MIRType_Pointer:
return "Pointer";
- case MIRType_ForkJoinContext:
- return "ForkJoinContext";
case MIRType_Int32x4:
return "Int32x4";
case MIRType_Float32x4:
return "Float32x4";
default:
MOZ_CRASH("Unknown MIRType.");
}
}
--- a/js/src/jit/JitCompartment.h
+++ b/js/src/jit/JitCompartment.h
@@ -149,44 +149,37 @@ class JitRuntime
// All accesses on this allocator must be protected by the runtime's
// interrupt lock, as the executable memory may be protected() when
// requesting an interrupt to force a fault in the Ion code and avoid the
// need for explicit interrupt checks.
ExecutableAllocator *ionAlloc_;
// Shared exception-handler tail.
JitCode *exceptionTail_;
- JitCode *exceptionTailParallel_;
// Shared post-bailout-handler tail.
JitCode *bailoutTail_;
// Trampoline for entering JIT code. Contains OSR prologue.
JitCode *enterJIT_;
// Trampoline for entering baseline JIT code.
JitCode *enterBaselineJIT_;
// Vector mapping frame class sizes to bailout tables.
Vector<JitCode*, 4, SystemAllocPolicy> bailoutTables_;
// Generic bailout table; used if the bailout table overflows.
JitCode *bailoutHandler_;
- // Bailout handler for parallel execution.
- JitCode *parallelBailoutHandler_;
-
// Argument-rectifying thunk, in the case of insufficient arguments passed
// to a function call site.
JitCode *argumentsRectifier_;
void *argumentsRectifierReturnAddr_;
- // Arguments-rectifying thunk which loads |parallelIon| instead of |ion|.
- JitCode *parallelArgumentsRectifier_;
-
// Thunk that invalides an (Ion compiled) caller on the Ion stack.
JitCode *invalidator_;
// Thunk that calls the GC pre barrier.
JitCode *valuePreBarrier_;
JitCode *stringPreBarrier_;
JitCode *objectPreBarrier_;
JitCode *shapePreBarrier_;
@@ -197,19 +190,16 @@ class JitRuntime
JitCode *freeStub_;
// Thunk called to finish compilation of an IonScript.
JitCode *lazyLinkStub_;
// Thunk used by the debugger for breakpoint and step mode.
JitCode *debugTrapHandler_;
- // Stub used to inline the ForkJoinGetSlice intrinsic.
- JitCode *forkJoinGetSliceStub_;
-
// Thunk used to fix up on-stack recompile of baseline scripts.
JitCode *baselineDebugModeOSRHandler_;
void *baselineDebugModeOSRHandlerNoFrameRegPopAddr_;
// Map VMFunction addresses to the JitCode of the wrapper.
typedef WeakCache<const VMFunction *, JitCode *> VMWrapperMap;
VMWrapperMap *functionWrappers_;
@@ -242,25 +232,24 @@ class JitRuntime
// Global table of jitcode native address => bytecode address mappings.
JitcodeGlobalTable *jitcodeGlobalTable_;
private:
JitCode *generateLazyLinkStub(JSContext *cx);
JitCode *generateExceptionTailStub(JSContext *cx, void *handler);
JitCode *generateBailoutTailStub(JSContext *cx);
JitCode *generateEnterJIT(JSContext *cx, EnterJitType type);
- JitCode *generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void **returnAddrOut);
+ JitCode *generateArgumentsRectifier(JSContext *cx, void **returnAddrOut);
JitCode *generateBailoutTable(JSContext *cx, uint32_t frameClass);
- JitCode *generateBailoutHandler(JSContext *cx, ExecutionMode mode);
+ JitCode *generateBailoutHandler(JSContext *cx);
JitCode *generateInvalidator(JSContext *cx);
JitCode *generatePreBarrier(JSContext *cx, MIRType type);
JitCode *generateMallocStub(JSContext *cx);
JitCode *generateFreeStub(JSContext *cx);
JitCode *generateDebugTrapHandler(JSContext *cx);
- JitCode *generateForkJoinGetSliceStub(JSContext *cx);
JitCode *generateBaselineDebugModeOSRHandler(JSContext *cx, uint32_t *noFrameRegPopOffsetOut);
JitCode *generateVMWrapper(JSContext *cx, const VMFunction &f);
ExecutableAllocator *createIonAlloc(JSContext *cx);
public:
JitRuntime();
~JitRuntime();
@@ -317,43 +306,32 @@ class JitRuntime
void patchIonBackedges(JSRuntime *rt, BackedgeTarget target);
JitCode *getVMWrapper(const VMFunction &f) const;
JitCode *debugTrapHandler(JSContext *cx);
JitCode *getBaselineDebugModeOSRHandler(JSContext *cx);
void *getBaselineDebugModeOSRHandlerAddress(JSContext *cx, bool popFrameReg);
- JitCode *getGenericBailoutHandler(ExecutionMode mode) const {
- switch (mode) {
- case SequentialExecution: return bailoutHandler_;
- case ParallelExecution: return parallelBailoutHandler_;
- default: MOZ_CRASH("No such execution mode");
- }
+ JitCode *getGenericBailoutHandler() const {
+ return bailoutHandler_;
}
JitCode *getExceptionTail() const {
return exceptionTail_;
}
- JitCode *getExceptionTailParallel() const {
- return exceptionTailParallel_;
- }
JitCode *getBailoutTail() const {
return bailoutTail_;
}
JitCode *getBailoutTable(const FrameSizeClass &frameClass) const;
- JitCode *getArgumentsRectifier(ExecutionMode mode) const {
- switch (mode) {
- case SequentialExecution: return argumentsRectifier_;
- case ParallelExecution: return parallelArgumentsRectifier_;
- default: MOZ_CRASH("No such execution mode");
- }
+ JitCode *getArgumentsRectifier() const {
+ return argumentsRectifier_;
}
void *getArgumentsRectifierReturnAddr() const {
return argumentsRectifierReturnAddr_;
}
JitCode *getInvalidationThunk() const {
return invalidator_;
@@ -385,21 +363,16 @@ class JitRuntime
JitCode *freeStub() const {
return freeStub_;
}
JitCode *lazyLinkStub() const {
return lazyLinkStub_;
}
- bool ensureForkJoinGetSliceStubExists(JSContext *cx);
- JitCode *forkJoinGetSliceStub() const {
- return forkJoinGetSliceStub_;
- }
-
bool hasIonReturnOverride() const {
return !ionReturnOverride_.isMagic(JS_ARG_POISON);
}
js::Value takeIonReturnOverride() {
js::Value v = ionReturnOverride_;
ionReturnOverride_ = js::MagicValue(JS_ARG_POISON);
return v;
}
@@ -454,28 +427,27 @@ class JitCompartment
// Stubs to concatenate two strings inline, or perform RegExp calls inline.
// These bake in zone and compartment specific pointers and can't be stored
// in JitRuntime. These are weak pointers, but are not declared as
// ReadBarriered since they are only read from during Ion compilation,
// which may occur off thread and whose barriers are captured during
// CodeGenerator::link.
JitCode *stringConcatStub_;
- JitCode *parallelStringConcatStub_;
JitCode *regExpExecStub_;
JitCode *regExpTestStub_;
// Set of JSScripts invoked by ForkJoin (i.e. the entry script). These
// scripts are marked if their respective parallel IonScripts' age is less
// than a certain amount. See IonScript::parallelAge_.
typedef HashSet<PreBarrieredScript, DefaultHasher<PreBarrieredScript>, SystemAllocPolicy>
ScriptSet;
ScriptSet *activeParallelEntryScripts_;
- JitCode *generateStringConcatStub(JSContext *cx, ExecutionMode mode);
+ JitCode *generateStringConcatStub(JSContext *cx);
JitCode *generateRegExpExecStub(JSContext *cx);
JitCode *generateRegExpTestStub(JSContext *cx);
public:
JitCode *getStubCode(uint32_t key) {
ICStubCodeMap::AddPtr p = stubCodes_->lookupForAdd(key);
if (p)
return p->value();
@@ -528,22 +500,18 @@ class JitCompartment
bool initialize(JSContext *cx);
// Initialize code stubs only used by Ion, not Baseline.
bool ensureIonStubsExist(JSContext *cx);
void mark(JSTracer *trc, JSCompartment *compartment);
void sweep(FreeOp *fop, JSCompartment *compartment);
- JitCode *stringConcatStubNoBarrier(ExecutionMode mode) const {
- switch (mode) {
- case SequentialExecution: return stringConcatStub_;
- case ParallelExecution: return parallelStringConcatStub_;
- default: MOZ_CRASH("No such execution mode");
- }
+ JitCode *stringConcatStubNoBarrier() const {
+ return stringConcatStub_;
}
JitCode *regExpExecStubNoBarrier() const {
return regExpExecStub_;
}
bool ensureRegExpExecStubExists(JSContext *cx) {
if (regExpExecStub_)
@@ -561,17 +529,16 @@ class JitCompartment
return true;
regExpTestStub_ = generateRegExpTestStub(cx);
return regExpTestStub_ != nullptr;
}
};
// Called from JSCompartment::discardJitCode().
void InvalidateAll(FreeOp *fop, JS::Zone *zone);
-template <ExecutionMode mode>
void FinishInvalidation(FreeOp *fop, JSScript *script);
// On windows systems, really large frames need to be incrementally touched.
// The following constant defines the minimum increment of the touch.
#ifdef XP_WIN
const unsigned WINDOWS_BIG_FRAME_TOUCH_INCREMENT = 4096 - 1;
#endif
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -16,17 +16,16 @@
#include "jit/BaselineFrame.h"
#include "jit/BaselineIC.h"
#include "jit/BaselineJIT.h"
#include "jit/Ion.h"
#include "jit/JitcodeMap.h"
#include "jit/JitCompartment.h"
#include "jit/JitSpewer.h"
#include "jit/MacroAssembler.h"
-#include "jit/ParallelFunctions.h"
#include "jit/PcScriptCache.h"
#include "jit/Recover.h"
#include "jit/Safepoints.h"
#include "jit/Snapshots.h"
#include "jit/VMFunctions.h"
#include "vm/ArgumentsObject.h"
#include "vm/Debugger.h"
#include "vm/ForkJoin.h"
@@ -868,39 +867,16 @@ HandleException(ResumeFromException *rfe
js_ReportOverRecursed(cx);
}
}
rfe->stackPointer = iter.fp();
}
void
-HandleParallelFailure(ResumeFromException *rfe)
-{
- parallel::Spew(parallel::SpewBailouts, "Bailing from VM reentry");
-
- ForkJoinContext *cx = ForkJoinContext::current();
- JitFrameIterator frameIter(cx);
-
- // Advance to the first Ion frame so we can pull out the BailoutKind.
- while (!frameIter.isIonJS())
- ++frameIter;
- SnapshotIterator snapIter(frameIter);
-
- cx->bailoutRecord->setIonBailoutKind(snapIter.bailoutKind());
- while (!frameIter.done())
- ++frameIter;
-
- rfe->kind = ResumeFromException::RESUME_ENTRY_FRAME;
-
- MOZ_ASSERT(frameIter.done());
- rfe->stackPointer = frameIter.fp();
-}
-
-void
EnsureExitFrame(CommonFrameLayout *frame)
{
if (frame->prevType() == JitFrame_Unwound_IonJS ||
frame->prevType() == JitFrame_Unwound_BaselineJS ||
frame->prevType() == JitFrame_Unwound_BaselineStub ||
frame->prevType() == JitFrame_Unwound_Rectifier)
{
// Already an exit frame, nothing to do.
--- a/js/src/jit/JitFrames.h
+++ b/js/src/jit/JitFrames.h
@@ -264,17 +264,16 @@ struct ResumeFromException
// Value to push when resuming into a |finally| block.
Value exception;
BaselineBailoutInfo *bailoutInfo;
};
void HandleException(ResumeFromException *rfe);
-void HandleParallelFailure(ResumeFromException *rfe);
void EnsureExitFrame(CommonFrameLayout *frame);
void MarkJitActivations(PerThreadData *ptd, JSTracer *trc);
void MarkIonCompilerRoots(JSTracer *trc);
JSCompartment *
TopmostIonActivationCompartment(JSRuntime *rt);
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -796,84 +796,16 @@ class LNewTypedObject : public LInstruct
return getTemp(0);
}
MNewTypedObject *mir() const {
return mir_->toNewTypedObject();
}
};
-class LNewPar : public LInstructionHelper<1, 1, 2>
-{
- public:
- LIR_HEADER(NewPar);
-
- LNewPar(const LAllocation &cx, const LDefinition &temp1, const LDefinition &temp2) {
- setOperand(0, cx);
- setTemp(0, temp1);
- setTemp(1, temp2);
- }
-
- MNewPar *mir() const {
- return mir_->toNewPar();
- }
-
- const LAllocation *forkJoinContext() {
- return getOperand(0);
- }
-
- const LDefinition *getTemp0() {
- return getTemp(0);
- }
-
- const LDefinition *getTemp1() {
- return getTemp(1);
- }
-};
-
-class LNewDenseArrayPar : public LInstructionHelper<1, 2, 3>
-{
- public:
- LIR_HEADER(NewDenseArrayPar);
-
- LNewDenseArrayPar(const LAllocation &cx, const LAllocation &length,
- const LDefinition &temp1, const LDefinition &temp2, const LDefinition &temp3)
- {
- setOperand(0, cx);
- setOperand(1, length);
- setTemp(0, temp1);
- setTemp(1, temp2);
- setTemp(2, temp3);
- }
-
- MNewDenseArrayPar *mir() const {
- return mir_->toNewDenseArrayPar();
- }
-
- const LAllocation *forkJoinContext() {
- return getOperand(0);
- }
-
- const LAllocation *length() {
- return getOperand(1);
- }
-
- const LDefinition *getTemp0() {
- return getTemp(0);
- }
-
- const LDefinition *getTemp1() {
- return getTemp(1);
- }
-
- const LDefinition *getTemp2() {
- return getTemp(2);
- }
-};
-
// Allocates a new DeclEnvObject.
//
// This instruction generates two possible instruction sets:
// (1) An inline allocation of the call object is attempted.
// (2) Otherwise, a callVM create a new object.
//
class LNewDeclEnvObject : public LInstructionHelper<1, 0, 1>
{
@@ -940,50 +872,16 @@ class LNewSingletonCallObject : public L
}
MNewCallObjectBase *mir() const {
MOZ_ASSERT(mir_->isNewCallObject() || mir_->isNewRunOnceCallObject());
return static_cast<MNewCallObjectBase *>(mir_);
}
};
-class LNewCallObjectPar : public LInstructionHelper<1, 1, 2>
-{
- LNewCallObjectPar(const LAllocation &cx, const LDefinition &temp1, const LDefinition &temp2) {
- setOperand(0, cx);
- setTemp(0, temp1);
- setTemp(1, temp2);
- }
-
-public:
- LIR_HEADER(NewCallObjectPar);
-
- static LNewCallObjectPar *New(TempAllocator &alloc, const LAllocation &cx,
- const LDefinition &temp1, const LDefinition &temp2)
- {
- return new(alloc) LNewCallObjectPar(cx, temp1, temp2);
- }
-
- const LAllocation *forkJoinContext() {
- return getOperand(0);
- }
-
- const MNewCallObjectPar *mir() const {
- return mir_->toNewCallObjectPar();
- }
-
- const LDefinition *getTemp0() {
- return getTemp(0);
- }
-
- const LDefinition *getTemp1() {
- return getTemp(1);
- }
-};
-
class LNewDerivedTypedObject : public LCallInstructionHelper<1, 3, 0>
{
public:
LIR_HEADER(NewDerivedTypedObject);
LNewDerivedTypedObject(const LAllocation &type,
const LAllocation &owner,
const LAllocation &offset) {
@@ -1143,39 +1041,16 @@ class LCheckOverRecursed : public LInstr
LCheckOverRecursed()
{ }
MCheckOverRecursed *mir() const {
return mir_->toCheckOverRecursed();
}
};
-class LCheckOverRecursedPar : public LInstructionHelper<0, 1, 1>
-{
- public:
- LIR_HEADER(CheckOverRecursedPar);
-
- LCheckOverRecursedPar(const LAllocation &cx, const LDefinition &tempReg) {
- setOperand(0, cx);
- setTemp(0, tempReg);
- }
-
- const LAllocation *forkJoinContext() {
- return getOperand(0);
- }
-
- const LDefinition *getTempReg() {
- return getTemp(0);
- }
-
- MCheckOverRecursedPar *mir() const {
- return mir_->toCheckOverRecursedPar();
- }
-};
-
class LAsmJSInterruptCheck : public LInstructionHelper<0, 0, 0>
{
Label *interruptExit_;
const CallSiteDesc &funcDesc_;
public:
LIR_HEADER(AsmJSInterruptCheck);
@@ -1223,38 +1098,16 @@ class LInterruptCheckImplicit : public L
void setOolEntry(Label *oolEntry) {
oolEntry_ = oolEntry;
}
MInterruptCheck *mir() const {
return mir_->toInterruptCheck();
}
};
-class LInterruptCheckPar : public LInstructionHelper<0, 1, 1>
-{
- public:
- LIR_HEADER(InterruptCheckPar);
-
- LInterruptCheckPar(const LAllocation &cx, const LDefinition &tempReg) {
- setOperand(0, cx);
- setTemp(0, tempReg);
- }
-
- const LAllocation *forkJoinContext() {
- return getOperand(0);
- }
-
- const LDefinition *getTempReg() {
- return getTemp(0);
- }
- MInterruptCheckPar *mir() const {
- return mir_->toInterruptCheckPar();
- }
-};
-
class LDefVar : public LCallInstructionHelper<0, 1, 0>
{
public:
LIR_HEADER(DefVar)
explicit LDefVar(const LAllocation &scopeChain)
{
setOperand(0, scopeChain);
@@ -3374,57 +3227,16 @@ class LConcat : public LInstructionHelpe
const LDefinition *temp4() {
return this->getTemp(3);
}
const LDefinition *temp5() {
return this->getTemp(4);
}
};
-class LConcatPar : public LInstructionHelper<1, 3, 4>
-{
- public:
- LIR_HEADER(ConcatPar)
-
- LConcatPar(const LAllocation &cx, const LAllocation &lhs, const LAllocation &rhs,
- const LDefinition &temp1, const LDefinition &temp2, const LDefinition &temp3,
- const LDefinition &temp4)
- {
- setOperand(0, cx);
- setOperand(1, lhs);
- setOperand(2, rhs);
- setTemp(0, temp1);
- setTemp(1, temp2);
- setTemp(2, temp3);
- setTemp(3, temp4);
- }
-
- const LAllocation *forkJoinContext() {
- return this->getOperand(0);
- }
- const LAllocation *lhs() {
- return this->getOperand(1);
- }
- const LAllocation *rhs() {
- return this->getOperand(2);
- }
- const LDefinition *temp1() {
- return this->getTemp(0);
- }
- const LDefinition *temp2() {
- return this->getTemp(1);
- }
- const LDefinition *temp3() {
- return this->getTemp(2);
- }
- const LDefinition *temp4() {
- return this->getTemp(3);
- }
-};
-
// Get uint16 character code from a string.
class LCharCodeAt : public LInstructionHelper<1, 2, 0>
{
public:
LIR_HEADER(CharCodeAt)
LCharCodeAt(const LAllocation &str, const LAllocation &index) {
setOperand(0, str);
@@ -4086,46 +3898,16 @@ class LLambdaArrow : public LInstruction
const LDefinition *temp() {
return getTemp(0);
}
const MLambdaArrow *mir() const {
return mir_->toLambdaArrow();
}
};
-class LLambdaPar : public LInstructionHelper<1, 2, 2>
-{
- public:
- LIR_HEADER(LambdaPar);
-
- LLambdaPar(const LAllocation &cx, const LAllocation &scopeChain,
- const LDefinition &temp1, const LDefinition &temp2)
- {
- setOperand(0, cx);
- setOperand(1, scopeChain);
- setTemp(0, temp1);
- setTemp(1, temp2);
- }
- const LAllocation *forkJoinContext() {
- return getOperand(0);
- }
- const LAllocation *scopeChain() {
- return getOperand(1);
- }
- const MLambdaPar *mir() const {
- return mir_->toLambdaPar();
- }
- const LDefinition *getTemp0() {
- return getTemp(0);
- }
- const LDefinition *getTemp1() {
- return getTemp(1);
- }
-};
-
// Load the "slots" member out of a JSObject.
// Input: JSObject pointer
// Output: slots pointer
class LSlots : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(Slots)
@@ -5298,27 +5080,23 @@ class LGetPropertyCacheV : public LInstr
}
const MGetPropertyCache *mir() const {
return mir_->toGetPropertyCache();
}
};
// Patchable jump to stubs generated for a GetProperty cache, which loads a
// value of a known type, possibly into an FP register.
-class LGetPropertyCacheT : public LInstructionHelper<1, 1, 1>
+class LGetPropertyCacheT : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(GetPropertyCacheT)
- LGetPropertyCacheT(const LAllocation &object, const LDefinition &temp) {
+ explicit LGetPropertyCacheT(const LAllocation &object) {
setOperand(0, object);
- setTemp(0, temp);
- }
- const LDefinition *temp() {
- return getTemp(0);
}
const MGetPropertyCache *mir() const {
return mir_->toGetPropertyCache();
}
};
// Emit code to load a boxed value from an object's slots if its shape matches
// one of the shapes observed by the baseline IC, else bails out.
@@ -5436,39 +5214,34 @@ class LGetElementCacheV : public LInstru
const LAllocation *object() {
return getOperand(0);
}
const MGetElementCache *mir() const {
return mir_->toGetElementCache();
}
};
-class LGetElementCacheT : public LInstructionHelper<1, 2, 1>
+class LGetElementCacheT : public LInstructionHelper<1, 2, 0>
{
public:
LIR_HEADER(GetElementCacheT)
- LGetElementCacheT(const LAllocation &object, const LAllocation &index,
- const LDefinition &temp) {
+ LGetElementCacheT(const LAllocation &object, const LAllocation &index) {
setOperand(0, object);
setOperand(1, index);
- setTemp(0, temp);
}
const LAllocation *object() {
return getOperand(0);
}
const LAllocation *index() {
return getOperand(1);
}
const LDefinition *output() {
return getDef(0);
}
- const LDefinition *temp() {
- return getTemp(0);
- }
const MGetElementCache *mir() const {
return mir_->toGetElementCache();
}
};
class LBindNameCache : public LInstructionHelper<1, 1, 0>
{
public:
@@ -5673,62 +5446,16 @@ class LFunctionEnvironment : public LIns
explicit LFunctionEnvironment(const LAllocation &function) {
setOperand(0, function);
}
const LAllocation *function() {
return getOperand(0);
}
};
-class LForkJoinContext : public LCallInstructionHelper<1, 0, 1>
-{
- public:
- LIR_HEADER(ForkJoinContext);
-
- explicit LForkJoinContext(const LDefinition &temp1) {
- setTemp(0, temp1);
- }
-
- const LDefinition *getTempReg() {
- return getTemp(0);
- }
-};
-
-class LForkJoinGetSlice : public LInstructionHelper<1, 1, 4>
-{
- public:
- LIR_HEADER(ForkJoinGetSlice);
-
- LForkJoinGetSlice(const LAllocation &cx,
- const LDefinition &temp1, const LDefinition &temp2,
- const LDefinition &temp3, const LDefinition &temp4) {
- setOperand(0, cx);
- setTemp(0, temp1);
- setTemp(1, temp2);
- setTemp(2, temp3);
- setTemp(3, temp4);
- }
-
- const LAllocation *forkJoinContext() {
- return getOperand(0);
- }
- const LDefinition *temp1() {
- return getTemp(0);
- }
- const LDefinition *temp2() {
- return getTemp(1);
- }
- const LDefinition *temp3() {
- return getTemp(2);
- }
- const LDefinition *temp4() {
- return getTemp(3);
- }
-};
-
class LCallGetProperty : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
{
public:
LIR_HEADER(CallGetProperty)
static const size_t Value = 0;
MCallGetProperty *mir() const {
@@ -5816,72 +5543,60 @@ class LCallDeleteElement : public LCallI
MDeleteElement *mir() const {
return mir_->toDeleteElement();
}
};
// Patchable jump to stubs generated for a SetProperty cache, which stores a
// boxed value.
-class LSetPropertyCacheV : public LInstructionHelper<0, 1 + BOX_PIECES, 2>
+class LSetPropertyCacheV : public LInstructionHelper<0, 1 + BOX_PIECES, 1>
{
public:
LIR_HEADER(SetPropertyCacheV)
- LSetPropertyCacheV(const LAllocation &object, const LDefinition &slots,
- const LDefinition &temp) {
+ LSetPropertyCacheV(const LAllocation &object, const LDefinition &slots) {
setOperand(0, object);
setTemp(0, slots);
- setTemp(1, temp);
}
static const size_t Value = 1;
const MSetPropertyCache *mir() const {
return mir_->toSetPropertyCache();
}
-
- const LDefinition *tempForDispatchCache() {
- return getTemp(1);
- }
};
// Patchable jump to stubs generated for a SetProperty cache, which stores a
// value of a known type.
-class LSetPropertyCacheT : public LInstructionHelper<0, 2, 2>
+class LSetPropertyCacheT : public LInstructionHelper<0, 2, 1>
{
MIRType valueType_;
public:
LIR_HEADER(SetPropertyCacheT)
LSetPropertyCacheT(const LAllocation &object, const LDefinition &slots,
- const LAllocation &value, const LDefinition &temp,
- MIRType valueType)
+ const LAllocation &value, MIRType valueType)
: valueType_(valueType)
{
setOperand(0, object);
setOperand(1, value);
setTemp(0, slots);
- setTemp(1, temp);
}
const MSetPropertyCache *mir() const {
return mir_->toSetPropertyCache();
}
MIRType valueType() {
return valueType_;
}
const char *extraName() const {
return StringFromMIRType(valueType_);
}
-
- const LDefinition *tempForDispatchCache() {
- return getTemp(1);
- }
};
class LSetElementCacheV : public LInstructionHelper<0, 1 + 2 * BOX_PIECES, 4>
{
public:
LIR_HEADER(SetElementCacheV);
static const size_t Index = 1;
@@ -6179,65 +5894,16 @@ class LRest : public LCallInstructionHel
const LAllocation *numActuals() {
return getOperand(0);
}
MRest *mir() const {
return mir_->toRest();
}
};
-class LRestPar : public LInstructionHelper<1, 2, 3>
-{
- public:
- LIR_HEADER(RestPar);
-
- LRestPar(const LAllocation &cx, const LAllocation &numActuals,
- const LDefinition &temp1, const LDefinition &temp2, const LDefinition &temp3)
- {
- setOperand(0, cx);
- setOperand(1, numActuals);
- setTemp(0, temp1);
- setTemp(1, temp2);
- setTemp(2, temp3);
- }
- const LAllocation *forkJoinContext() {
- return getOperand(0);
- }
- const LAllocation *numActuals() {
- return getOperand(1);
- }
- MRestPar *mir() const {
- return mir_->toRestPar();
- }
-};
-
-class LGuardThreadExclusive : public LCallInstructionHelper<0, 2, 1>
-{
- public:
- LIR_HEADER(GuardThreadExclusive);
-
- LGuardThreadExclusive(const LAllocation &cx, const LAllocation &object, const LDefinition &temp1) {
- setOperand(0, cx);
- setOperand(1, object);
- setTemp(0, temp1);
- }
-
- const LAllocation *forkJoinContext() {
- return getOperand(0);
- }
-
- const LAllocation *object() {
- return getOperand(1);
- }
-
- const LDefinition *getTempReg() {
- return getTemp(0);
- }
-};
-
class LGuardShapePolymorphic : public LInstructionHelper<0, 1, 1>
{
public:
LIR_HEADER(GuardShapePolymorphic)
LGuardShapePolymorphic(const LAllocation &in, const LDefinition &temp) {
setOperand(0, in);
setTemp(0, temp);
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -564,18 +564,16 @@ class LDefinition
case MIRType_Value:
return LDefinition::BOX;
#endif
case MIRType_Slots:
case MIRType_Elements:
return LDefinition::SLOTS;
case MIRType_Pointer:
return LDefinition::GENERAL;
- case MIRType_ForkJoinContext:
- return LDefinition::GENERAL;
case MIRType_Int32x4:
return LDefinition::INT32X4;
case MIRType_Float32x4:
return LDefinition::FLOAT32X4;
default:
MOZ_CRASH("unexpected type");
}
}
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -50,27 +50,23 @@
_(NewArrayDynamicLength) \
_(ArraySplice) \
_(NewObject) \
_(NewTypedObject) \
_(NewDeclEnvObject) \
_(NewCallObject) \
_(NewSingletonCallObject) \
_(NewStringObject) \
- _(NewPar) \
- _(NewDenseArrayPar) \
- _(NewCallObjectPar) \
_(NewDerivedTypedObject) \
_(InitElem) \
_(InitElemGetterSetter) \
_(MutateProto) \
_(InitProp) \
_(InitPropGetterSetter) \
_(CheckOverRecursed) \
- _(CheckOverRecursedPar) \
_(DefVar) \
_(DefFun) \
_(CallKnown) \
_(CallGeneric) \
_(CallNative) \
_(ApplyArgsGeneric) \
_(Bail) \
_(Unreachable) \
@@ -151,17 +147,16 @@
_(AddI) \
_(SubI) \
_(MulI) \
_(MathD) \
_(MathF) \
_(ModD) \
_(BinaryV) \
_(Concat) \
- _(ConcatPar) \
_(CharCodeAt) \
_(FromCharCode) \
_(StringSplit) \
_(Int32ToDouble) \
_(Float32ToDouble) \
_(DoubleToFloat32) \
_(Int32ToFloat32) \
_(ValueToDouble) \
@@ -188,32 +183,30 @@
_(RegExpExec) \
_(RegExpTest) \
_(RegExpReplace) \
_(StringReplace) \
_(Substr) \
_(Lambda) \
_(LambdaArrow) \
_(LambdaForSingleton) \
- _(LambdaPar) \
_(Slots) \
_(Elements) \
_(ConvertElementsToDoubles) \
_(MaybeToDoubleElement) \
_(MaybeCopyElementsForWrite) \
_(LoadSlotV) \
_(LoadSlotT) \
_(StoreSlotV) \
_(StoreSlotT) \
_(GuardShape) \
_(GuardShapePolymorphic) \
_(GuardObjectType) \
_(GuardObjectIdentity) \
_(GuardClass) \
- _(GuardThreadExclusive) \
_(TypeBarrierV) \
_(TypeBarrierO) \
_(MonitorTypes) \
_(PostWriteBarrierO) \
_(PostWriteBarrierV) \
_(InitializedLength) \
_(SetInitializedLength) \
_(BoundsCheck) \
@@ -247,18 +240,16 @@
_(ClampIToUint8) \
_(ClampDToUint8) \
_(ClampVToUint8) \
_(LoadFixedSlotV) \
_(LoadFixedSlotT) \
_(StoreFixedSlotV) \
_(StoreFixedSlotT) \
_(FunctionEnvironment) \
- _(ForkJoinContext) \
- _(ForkJoinGetSlice) \
_(GetPropertyCacheV) \
_(GetPropertyCacheT) \
_(GetPropertyPolymorphicV) \
_(GetPropertyPolymorphicT) \
_(GetElementCacheV) \
_(GetElementCacheT) \
_(BindNameCache) \
_(CallGetProperty) \
@@ -292,17 +283,16 @@
_(StringLength) \
_(ArgumentsLength) \
_(GetFrameArgument) \
_(SetFrameArgumentT) \
_(SetFrameArgumentC) \
_(SetFrameArgumentV) \
_(RunOncePrologue) \
_(Rest) \
- _(RestPar) \
_(TypeOfV) \
_(ToIdV) \
_(Floor) \
_(FloorF) \
_(Ceil) \
_(CeilF) \
_(Round) \
_(RoundF) \
@@ -331,17 +321,16 @@
_(AsmJSLoadFFIFunc) \
_(AsmJSParameter) \
_(AsmJSReturn) \
_(AsmJSVoidReturn) \
_(AsmJSPassStackArg) \
_(AsmJSCall) \
_(AsmJSCompareExchangeHeap) \
_(AsmJSAtomicBinopHeap) \
- _(InterruptCheckPar) \
_(RecompileCheck) \
_(MemoryBarrier) \
_(AssertRangeI) \
_(AssertRangeD) \
_(AssertRangeF) \
_(AssertRangeV) \
_(LexicalCheck) \
_(ThrowUninitializedLexical) \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -126,25 +126,16 @@ void
LIRGenerator::visitCheckOverRecursed(MCheckOverRecursed *ins)
{
LCheckOverRecursed *lir = new(alloc()) LCheckOverRecursed();
add(lir, ins);
assignSafepoint(lir, ins);
}
void
-LIRGenerator::visitCheckOverRecursedPar(MCheckOverRecursedPar *ins)
-{
- LCheckOverRecursedPar *lir =
- new(alloc()) LCheckOverRecursedPar(useRegister(ins->forkJoinContext()), temp());
- add(lir, ins);
- assignSafepoint(lir, ins);
-}
-
-void
LIRGenerator::visitDefVar(MDefVar *ins)
{
LDefVar *lir = new(alloc()) LDefVar(useRegisterAtStart(ins->scopeChain()));
add(lir, ins);
assignSafepoint(lir, ins);
}
void
@@ -238,25 +229,16 @@ LIRGenerator::visitNewDerivedTypedObject
new(alloc()) LNewDerivedTypedObject(useRegisterAtStart(ins->type()),
useRegisterAtStart(ins->owner()),
useRegisterAtStart(ins->offset()));
defineReturn(lir, ins);
assignSafepoint(lir, ins);
}
void
-LIRGenerator::visitNewCallObjectPar(MNewCallObjectPar *ins)
-{
- const LAllocation &parThreadContext = useRegister(ins->forkJoinContext());
- LNewCallObjectPar *lir = LNewCallObjectPar::New(alloc(), parThreadContext, temp(), temp());
- define(lir, ins);
- assignSafepoint(lir, ins);
-}
-
-void
LIRGenerator::visitNewStringObject(MNewStringObject *ins)
{
MOZ_ASSERT(ins->input()->type() == MIRType_String);
LNewStringObject *lir = new(alloc()) LNewStringObject(useRegister(ins->input()), temp());
define(lir, ins);
assignSafepoint(lir, ins);
}
@@ -1595,38 +1577,16 @@ LIRGenerator::visitConcat(MConcat *ins)
tempFixed(CallTempReg2),
tempFixed(CallTempReg3),
tempFixed(CallTempReg4));
defineFixed(lir, ins, LAllocation(AnyRegister(CallTempReg5)));
assignSafepoint(lir, ins);
}
void
-LIRGenerator::visitConcatPar(MConcatPar *ins)
-{
- MDefinition *cx = ins->forkJoinContext();
- MDefinition *lhs = ins->lhs();
- MDefinition *rhs = ins->rhs();
-
- MOZ_ASSERT(lhs->type() == MIRType_String);
- MOZ_ASSERT(rhs->type() == MIRType_String);
- MOZ_ASSERT(ins->type() == MIRType_String);
-
- LConcatPar *lir = new(alloc()) LConcatPar(useFixed(cx, CallTempReg4),
- useFixedAtStart(lhs, CallTempReg0),
- useFixedAtStart(rhs, CallTempReg1),
- tempFixed(CallTempReg0),
- tempFixed(CallTempReg1),
- tempFixed(CallTempReg2),
- tempFixed(CallTempReg3));
- defineFixed(lir, ins, LAllocation(AnyRegister(CallTempReg5)));
- assignSafepoint(lir, ins);
-}
-
-void
LIRGenerator::visitCharCodeAt(MCharCodeAt *ins)
{
MDefinition *str = ins->getOperand(0);
MDefinition *idx = ins->getOperand(1);
MOZ_ASSERT(str->type() == MIRType_String);
MOZ_ASSERT(idx->type() == MIRType_Int32);
@@ -2167,28 +2127,16 @@ LIRGenerator::visitLambdaArrow(MLambdaAr
LLambdaArrow *lir = new(alloc()) LLambdaArrow(useRegister(ins->scopeChain()), temp());
useBox(lir, LLambdaArrow::ThisValue, ins->thisDef());
define(lir, ins);
assignSafepoint(lir, ins);
}
void
-LIRGenerator::visitLambdaPar(MLambdaPar *ins)
-{
- MOZ_ASSERT(!ins->info().singletonType);
- MOZ_ASSERT(!ins->info().useNewTypeForClone);
- LLambdaPar *lir = new(alloc()) LLambdaPar(useRegister(ins->forkJoinContext()),
- useRegister(ins->scopeChain()),
- temp(), temp());
- define(lir, ins);
- assignSafepoint(lir, ins);
-}
-
-void
LIRGenerator::visitSlots(MSlots *ins)
{
define(new(alloc()) LSlots(useRegisterAtStart(ins->object())), ins);
}
void
LIRGenerator::visitElements(MElements *ins)
{
@@ -2249,39 +2197,16 @@ LIRGenerator::visitLoadSlot(MLoadSlot *i
void
LIRGenerator::visitFunctionEnvironment(MFunctionEnvironment *ins)
{
define(new(alloc()) LFunctionEnvironment(useRegisterAtStart(ins->function())), ins);
}
void
-LIRGenerator::visitForkJoinContext(MForkJoinContext *ins)
-{
- LForkJoinContext *lir = new(alloc()) LForkJoinContext(tempFixed(CallTempReg0));
- defineReturn(lir, ins);
-}
-
-void
-LIRGenerator::visitGuardThreadExclusive(MGuardThreadExclusive *ins)
-{
- // FIXME (Bug 956281) -- For now, we always generate the most
- // general form of write guard check. we could employ TI feedback
- // to optimize this if we know that the object being tested is a
- // typed object or know that it is definitely NOT a typed object.
- LGuardThreadExclusive *lir =
- new(alloc()) LGuardThreadExclusive(useFixed(ins->forkJoinContext(), CallTempReg0),
- useFixed(ins->object(), CallTempReg1),
- tempFixed(CallTempReg2));
- lir->setMir(ins);
- assignSnapshot(lir, Bailout_GuardThreadExclusive);
- add(lir, ins);
-}
-
-void
LIRGenerator::visitInterruptCheck(MInterruptCheck *ins)
{
// Implicit interrupt checks require asm.js signal handlers to be installed.
LInstructionHelper<0, 0, 0> *lir;
if (GetJitContext()->runtime->canUseSignalHandlers())
lir = new(alloc()) LInterruptCheckImplicit();
else
lir = new(alloc()) LInterruptCheck();
@@ -2295,50 +2220,16 @@ LIRGenerator::visitAsmJSInterruptCheck(M
gen->setPerformsCall();
LAsmJSInterruptCheck *lir = new(alloc()) LAsmJSInterruptCheck(ins->interruptExit(),
ins->funcDesc());
add(lir, ins);
}
void
-LIRGenerator::visitInterruptCheckPar(MInterruptCheckPar *ins)
-{
- LInterruptCheckPar *lir =
- new(alloc()) LInterruptCheckPar(useRegister(ins->forkJoinContext()), temp());
- add(lir, ins);
- assignSafepoint(lir, ins);
-}
-
-void
-LIRGenerator::visitNewPar(MNewPar *ins)
-{
- LNewPar *lir = new(alloc()) LNewPar(useRegister(ins->forkJoinContext()), temp(), temp());
- define(lir, ins);
- assignSafepoint(lir, ins);
-}
-
-void
-LIRGenerator::visitNewDenseArrayPar(MNewDenseArrayPar *ins)
-{
- MOZ_ASSERT(ins->forkJoinContext()->type() == MIRType_ForkJoinContext);
- MOZ_ASSERT(ins->length()->type() == MIRType_Int32);
- MOZ_ASSERT(ins->type() == MIRType_Object);
-
- LNewDenseArrayPar *lir =
- new(alloc()) LNewDenseArrayPar(useRegister(ins->forkJoinContext()),
- useRegister(ins->length()),
- temp(),
- temp(),
- temp());
- define(lir, ins);
- assignSafepoint(lir, ins);
-}
-
-void
LIRGenerator::visitStoreSlot(MStoreSlot *ins)
{
LInstruction *lir;
switch (ins->value()->type()) {
case MIRType_Value:
lir = new(alloc()) LStoreSlotV(useRegister(ins->slots()));
useBox(lir, LStoreSlotV::Value, ins->value());
@@ -3150,18 +3041,17 @@ void
LIRGenerator::visitGetPropertyCache(MGetPropertyCache *ins)
{
MOZ_ASSERT(ins->object()->type() == MIRType_Object);
if (ins->type() == MIRType_Value) {
LGetPropertyCacheV *lir = new(alloc()) LGetPropertyCacheV(useRegister(ins->object()));
defineBox(lir, ins);
assignSafepoint(lir, ins);
} else {
- LGetPropertyCacheT *lir = new(alloc()) LGetPropertyCacheT(useRegister(ins->object()),
- tempForDispatchCache(ins->type()));
+ LGetPropertyCacheT *lir = new(alloc()) LGetPropertyCacheT(useRegister(ins->object()));
define(lir, ins);
assignSafepoint(lir, ins);
}
}
void
LIRGenerator::visitGetPropertyPolymorphic(MGetPropertyPolymorphic *ins)
{
@@ -3211,18 +3101,17 @@ LIRGenerator::visitGetElementCache(MGetE
MOZ_ASSERT(ins->index()->type() == MIRType_Value);
LGetElementCacheV *lir = new(alloc()) LGetElementCacheV(useRegister(ins->object()));
useBox(lir, LGetElementCacheV::Index, ins->index());
defineBox(lir, ins);
assignSafepoint(lir, ins);
} else {
MOZ_ASSERT(ins->index()->type() == MIRType_Int32);
LGetElementCacheT *lir = new(alloc()) LGetElementCacheT(useRegister(ins->object()),
- useRegister(ins->index()),
- tempForDispatchCache(ins->type()));
+ useRegister(ins->index()));
define(lir, ins);
assignSafepoint(lir, ins);
}
}
void
LIRGenerator::visitBindNameCache(MBindNameCache *ins)
{
@@ -3368,25 +3257,24 @@ LIRGenerator::visitDeleteElement(MDelete
assignSafepoint(lir, ins);
}
void
LIRGenerator::visitSetPropertyCache(MSetPropertyCache *ins)
{
LUse obj = useRegisterAtStart(ins->object());
LDefinition slots = tempCopy(ins->object(), 0);
- LDefinition dispatchTemp = tempForDispatchCache();
LInstruction *lir;
if (ins->value()->type() == MIRType_Value) {
- lir = new(alloc()) LSetPropertyCacheV(obj, slots, dispatchTemp);
+ lir = new(alloc()) LSetPropertyCacheV(obj, slots);
useBox(lir, LSetPropertyCacheV::Value, ins->value());
} else {
LAllocation value = useRegisterOrConstant(ins->value());
- lir = new(alloc()) LSetPropertyCacheT(obj, slots, value, dispatchTemp, ins->value()->type());
+ lir = new(alloc()) LSetPropertyCacheT(obj, slots, value, ins->value()->type());
}
add(lir, ins);
assignSafepoint(lir, ins);
}
void
LIRGenerator::visitSetElementCache(MSetElementCache *ins)
@@ -3539,30 +3427,16 @@ LIRGenerator::visitRest(MRest *ins)
tempFixed(CallTempReg1),
tempFixed(CallTempReg2),
tempFixed(CallTempReg3));
defineReturn(lir, ins);
assignSafepoint(lir, ins);
}
void
-LIRGenerator::visitRestPar(MRestPar *ins)
-{
- MOZ_ASSERT(ins->numActuals()->type() == MIRType_Int32);
-
- LRestPar *lir = new(alloc()) LRestPar(useRegister(ins->forkJoinContext()),
- useRegister(ins->numActuals()),
- temp(),
- temp(),
- temp());
- define(lir, ins);
- assignSafepoint(lir, ins);
-}
-
-void
LIRGenerator::visitThrow(MThrow *ins)
{
MDefinition *value = ins->getOperand(0);
MOZ_ASSERT(value->type() == MIRType_Value);
LThrow *lir = new(alloc()) LThrow;
useBoxAtStart(lir, LThrow::Value, value);
add(lir, ins);
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -75,26 +75,22 @@ class LIRGenerator : public LIRGenerator
void visitNewArrayDynamicLength(MNewArrayDynamicLength *ins);
void visitNewObject(MNewObject *ins);
void visitNewTypedObject(MNewTypedObject *ins);
void visitNewDeclEnvObject(MNewDeclEnvObject *ins);
void visitNewCallObject(MNewCallObject *ins);
void visitNewRunOnceCallObject(MNewRunOnceCallObject *ins);
void visitNewStringObject(MNewStringObject *ins);
void visitNewDerivedTypedObject(MNewDerivedTypedObject *ins);
- void visitNewPar(MNewPar *ins);
- void visitNewCallObjectPar(MNewCallObjectPar *ins);
- void visitNewDenseArrayPar(MNewDenseArrayPar *ins);
void visitInitElem(MInitElem *ins);
void visitInitElemGetterSetter(MInitElemGetterSetter *ins);
void visitMutateProto(MMutateProto *ins);
void visitInitProp(MInitProp *ins);
void visitInitPropGetterSetter(MInitPropGetterSetter *ins);
void visitCheckOverRecursed(MCheckOverRecursed *ins);
- void visitCheckOverRecursedPar(MCheckOverRecursedPar *ins);
void visitDefVar(MDefVar *ins);
void visitDefFun(MDefFun *ins);
void visitCreateThisWithTemplate(MCreateThisWithTemplate *ins);
void visitCreateThisWithProto(MCreateThisWithProto *ins);
void visitCreateThis(MCreateThis *ins);
void visitCreateArgumentsObject(MCreateArgumentsObject *ins);
void visitGetArgumentsObjectArg(MGetArgumentsObjectArg *ins);
void visitSetArgumentsObjectArg(MSetArgumentsObjectArg *ins);
@@ -137,17 +133,16 @@ class LIRGenerator : public LIRGenerator
void visitRandom(MRandom *ins);
void visitMathFunction(MMathFunction *ins);
void visitAdd(MAdd *ins);
void visitSub(MSub *ins);
void visitMul(MMul *ins);
void visitDiv(MDiv *ins);
void visitMod(MMod *ins);
void visitConcat(MConcat *ins);
- void visitConcatPar(MConcatPar *ins);
void visitCharCodeAt(MCharCodeAt *ins);
void visitFromCharCode(MFromCharCode *ins);
void visitStringSplit(MStringSplit *ins);
void visitStart(MStart *start);
void visitOsrEntry(MOsrEntry *entry);
void visitNop(MNop *nop);
void visitLimitedTruncate(MLimitedTruncate *nop);
void visitOsrValue(MOsrValue *value);
@@ -162,30 +157,26 @@ class LIRGenerator : public LIRGenerator
void visitToObjectOrNull(MToObjectOrNull *convert);
void visitRegExp(MRegExp *ins);
void visitRegExpExec(MRegExpExec *ins);
void visitRegExpTest(MRegExpTest *ins);
void visitRegExpReplace(MRegExpReplace *ins);
void visitStringReplace(MStringReplace *ins);
void visitLambda(MLambda *ins);
void visitLambdaArrow(MLambdaArrow *ins);
- void visitLambdaPar(MLambdaPar *ins);
void visitSlots(MSlots *ins);
void visitElements(MElements *ins);
void visitConstantElements(MConstantElements *ins);
void visitConvertElementsToDoubles(MConvertElementsToDoubles *ins);
void visitMaybeToDoubleElement(MMaybeToDoubleElement *ins);
void visitMaybeCopyElementsForWrite(MMaybeCopyElementsForWrite *ins);
void visitLoadSlot(MLoadSlot *ins);
void visitFunctionEnvironment(MFunctionEnvironment *ins);
- void visitForkJoinContext(MForkJoinContext *ins);
- void visitGuardThreadExclusive(MGuardThreadExclusive *ins);
void visitInterruptCheck(MInterruptCheck *ins);
void visitAsmJSInterruptCheck(MAsmJSInterruptCheck *ins);
- void visitInterruptCheckPar(MInterruptCheckPar *ins);
void visitStoreSlot(MStoreSlot *ins);
void visitFilterTypeSet(MFilterTypeSet *ins);
void visitTypeBarrier(MTypeBarrier *ins);
void visitMonitorTypes(MMonitorTypes *ins);
void visitPostWriteBarrier(MPostWriteBarrier *ins);
void visitArrayLength(MArrayLength *ins);
void visitSetArrayLength(MSetArrayLength *ins);
void visitTypedArrayLength(MTypedArrayLength *ins);
@@ -247,17 +238,16 @@ class LIRGenerator : public LIRGenerator
void visitIsNoIter(MIsNoIter *ins);
void visitIteratorEnd(MIteratorEnd *ins);
void visitStringLength(MStringLength *ins);
void visitArgumentsLength(MArgumentsLength *ins);
void visitGetFrameArgument(MGetFrameArgument *ins);
void visitSetFrameArgument(MSetFrameArgument *ins);
void visitRunOncePrologue(MRunOncePrologue *ins);
void visitRest(MRest *ins);
- void visitRestPar(MRestPar *ins);
void visitThrow(MThrow *ins);
void visitIn(MIn *ins);
void visitInArray(MInArray *ins);
void visitInstanceOf(MInstanceOf *ins);
void visitCallInstanceOf(MCallInstanceOf *ins);
void visitProfilerStackOp(MProfilerStackOp *ins);
void visitIsCallable(MIsCallable *ins);
void visitIsObject(MIsObject *ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -161,40 +161,31 @@ IonBuilder::inlineNativeCall(CallInfo &c
if (native == regexp_exec && !CallResultEscapes(pc))
return inlineRegExpTest(callInfo);
if (native == regexp_test)
return inlineRegExpTest(callInfo);
// Array intrinsics.
if (native == intrinsic_UnsafePutElements)
return inlineUnsafePutElements(callInfo);
- if (native == intrinsic_NewDenseArray)
- return inlineNewDenseArray(callInfo);
// Slot intrinsics.
if (native == intrinsic_UnsafeSetReservedSlot)
return inlineUnsafeSetReservedSlot(callInfo);
if (native == intrinsic_UnsafeGetReservedSlot)
return inlineUnsafeGetReservedSlot(callInfo, MIRType_Value);
if (native == intrinsic_UnsafeGetObjectFromReservedSlot)
return inlineUnsafeGetReservedSlot(callInfo, MIRType_Object);
if (native == intrinsic_UnsafeGetInt32FromReservedSlot)
return inlineUnsafeGetReservedSlot(callInfo, MIRType_Int32);
if (native == intrinsic_UnsafeGetStringFromReservedSlot)
return inlineUnsafeGetReservedSlot(callInfo, MIRType_String);
if (native == intrinsic_UnsafeGetBooleanFromReservedSlot)
return inlineUnsafeGetReservedSlot(callInfo, MIRType_Boolean);
- // Parallel intrinsics.
- if (native == intrinsic_ShouldForceSequential ||
- native == intrinsic_InParallelSection)
- return inlineForceSequentialOrInParallelSection(callInfo);
- if (native == intrinsic_ForkJoinGetSlice)
- return inlineForkJoinGetSlice(callInfo);
-
// Utility intrinsics.
if (native == intrinsic_IsCallable)
return inlineIsCallable(callInfo);
if (native == intrinsic_ToObject)
return inlineToObject(callInfo);
if (native == intrinsic_IsObject)
return inlineIsObject(callInfo);
if (native == intrinsic_ToInteger)
@@ -237,18 +228,16 @@ IonBuilder::inlineNativeCall(CallInfo &c
return inlineHasClass(callInfo,
&ScalarTypeDescr::class_, &ReferenceTypeDescr::class_);
if (native == intrinsic_TypeDescrIsArrayType)
return inlineHasClass(callInfo, &ArrayTypeDescr::class_);
if (native == intrinsic_SetTypedObjectOffset)
return inlineSetTypedObjectOffset(callInfo);
// Testing Functions
- if (native == testingFunc_inParallelSection)
- return inlineForceSequentialOrInParallelSection(callInfo);
if (native == testingFunc_bailout)
return inlineBailout(callInfo);
if (native == testingFunc_assertFloat32)
return inlineAssertFloat32(callInfo);
// Bound function
if (native == js::CallOrConstructBoundFunction)
return inlineBoundFunction(callInfo, target);
@@ -1772,139 +1761,16 @@ IonBuilder::inlineUnsafeSetTypedObjectAr
if (!jsop_setelem_typed_object(arrayType, SetElem_Unsafe, true, obj, id, elem))
return false;
return true;
}
IonBuilder::InliningStatus
-IonBuilder::inlineForceSequentialOrInParallelSection(CallInfo &callInfo)
-{
- if (callInfo.constructing())
- return InliningStatus_NotInlined;
-
- ExecutionMode executionMode = info().executionMode();
- switch (executionMode) {
- case ParallelExecution: {
- // During Parallel Exec, we always force sequential, so
- // replace with true. This permits UCE to eliminate the
- // entire path as dead, which is important.
- callInfo.setImplicitlyUsedUnchecked();
- MConstant *ins = MConstant::New(alloc(), BooleanValue(true));
- current->add(ins);
- current->push(ins);
- return InliningStatus_Inlined;
- }
-
- default:
- // In sequential mode, leave as is, because we'd have to
- // access the "in warmup" flag of the runtime.
- return InliningStatus_NotInlined;
- }
-
- MOZ_CRASH("Invalid execution mode");
-}
-
-IonBuilder::InliningStatus
-IonBuilder::inlineForkJoinGetSlice(CallInfo &callInfo)
-{
- if (info().executionMode() != ParallelExecution)
- return InliningStatus_NotInlined;
-
- // Assert the way the function is used instead of testing, as it is a
- // self-hosted function which must be used in a particular fashion.
- MOZ_ASSERT(callInfo.argc() == 1 && !callInfo.constructing());
- MOZ_ASSERT(callInfo.getArg(0)->type() == MIRType_Int32);
-
- // Test this, as we might have not executed the native despite knowing the
- // target here.
- if (getInlineReturnType() != MIRType_Int32)
- return InliningStatus_NotInlined;
-
- callInfo.setImplicitlyUsedUnchecked();
-
- switch (info().executionMode()) {
- case ParallelExecution:
- if (LIRGenerator::allowInlineForkJoinGetSlice()) {
- MForkJoinGetSlice *getSlice = MForkJoinGetSlice::New(alloc(),
- graph().forkJoinContext());
- current->add(getSlice);
- current->push(getSlice);
- return InliningStatus_Inlined;
- }
- return InliningStatus_NotInlined;
-
- default:
- // ForkJoinGetSlice acts as identity for sequential execution.
- current->push(callInfo.getArg(0));
- return InliningStatus_Inlined;
- }
-
- MOZ_CRASH("Invalid execution mode");
-}
-
-IonBuilder::InliningStatus
-IonBuilder::inlineNewDenseArray(CallInfo &callInfo)
-{
- if (callInfo.constructing() || callInfo.argc() != 1)
- return InliningStatus_NotInlined;
-
- // For now, in seq. mode we just call the C function. In
- // par. mode we use inlined MIR.
- ExecutionMode executionMode = info().executionMode();
- switch (executionMode) {
- case ParallelExecution:
- return inlineNewDenseArrayForParallelExecution(callInfo);
- default:
- return inlineNewDenseArrayForSequentialExecution(callInfo);
- }
-
- MOZ_CRASH("unknown ExecutionMode");
-}
-
-IonBuilder::InliningStatus
-IonBuilder::inlineNewDenseArrayForSequentialExecution(CallInfo &callInfo)
-{
- // not yet implemented; in seq. mode the C function is not so bad
- return InliningStatus_NotInlined;
-}
-
-IonBuilder::InliningStatus
-IonBuilder::inlineNewDenseArrayForParallelExecution(CallInfo &callInfo)
-{
- // Create the new parallel array object. Parallel arrays have specially
- // constructed type objects, so we can only perform the inlining if we
- // already have one of these type objects.
- types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet();
- if (returnTypes->getKnownMIRType() != MIRType_Object)
- return InliningStatus_NotInlined;
- if (returnTypes->unknownObject() || returnTypes->getObjectCount() != 1)
- return InliningStatus_NotInlined;
- if (callInfo.getArg(0)->type() != MIRType_Int32)
- return InliningStatus_NotInlined;
- types::TypeObject *typeObject = returnTypes->getTypeObject(0);
-
- NativeObject *templateObject = inspector->getTemplateObjectForNative(pc, intrinsic_NewDenseArray);
- if (!templateObject || templateObject->type() != typeObject)
- return InliningStatus_NotInlined;
-
- callInfo.setImplicitlyUsedUnchecked();
-
- MNewDenseArrayPar *newObject = MNewDenseArrayPar::New(alloc(),
- graph().forkJoinContext(),
- callInfo.getArg(0),
- &templateObject->as<ArrayObject>());
- current->add(newObject);
- current->push(newObject);
-
- return InliningStatus_Inlined;
-}
-
-IonBuilder::InliningStatus
IonBuilder::inlineHasClass(CallInfo &callInfo,
const Class *clasp1, const Class *clasp2,
const Class *clasp3, const Class *clasp4)
{
if (callInfo.constructing() || callInfo.argc() != 1)
return InliningStatus_NotInlined;
if (callInfo.getArg(0)->type() != MIRType_Object)
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -2266,27 +2266,16 @@ MBinaryArithInstruction::inferFallback(B
{
// Try to specialize based on what baseline observed in practice.
specialization_ = inspector->expectedBinaryArithSpecialization(pc);
if (specialization_ != MIRType_None) {
setResultType(specialization_);
return;
}
- // In parallel execution, for now anyhow, we *only* support adding
- // and manipulating numbers (not strings or objects). So no
- // matter what we can specialize to double...if the result ought
- // to have been something else, we'll fail in the various type
- // guards that get inserted later.
- if (block()->info().executionMode() == ParallelExecution) {
- specialization_ = MIRType_Double;
- setResultType(MIRType_Double);
- return;
- }
-
// If we can't specialize because we have no type information at all for
// the lhs or rhs, mark the binary instruction as having no possible types
// either to avoid degrading subsequent analysis.
if (getOperand(0)->emptyResultTypeSet() || getOperand(1)->emptyResultTypeSet()) {
LifoAlloc *alloc = GetJitContext()->temp->lifoAlloc();
types::TemporaryTypeSet *types = alloc->new_<types::TemporaryTypeSet>();
if (types)
setResultTypeSet(types);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -2831,50 +2831,16 @@ class MNewObject
bool writeRecoverData(CompactBufferWriter &writer) const;
bool canRecoverOnBailout() const {
// The template object can safely be used in the recover instruction
// because it can never be mutated by any other function execution.
return true;
}
};
-// Could be allocating either a new array or a new object.
-class MNewPar
- : public MUnaryInstruction,
- public NoTypePolicy::Data
-{
- AlwaysTenuredNativeObject templateObject_;
-
- MNewPar(MDefinition *cx, NativeObject *templateObject)
- : MUnaryInstruction(cx),
- templateObject_(templateObject)
- {
- setResultType(MIRType_Object);
- }
-
- public:
- INSTRUCTION_HEADER(NewPar);
-
- static MNewPar *New(TempAllocator &alloc, MDefinition *cx, NativeObject *templateObject) {
- return new(alloc) MNewPar(cx, templateObject);
- }
-
- MDefinition *forkJoinContext() const {
- return getOperand(0);
- }
-
- NativeObject *templateObject() const {
- return templateObject_;
- }
-
- AliasSet getAliasSet() const {
- return AliasSet::None();
- }
-};
-
class MNewTypedObject : public MNullaryInstruction
{
AlwaysTenured<InlineTypedObject *> templateObject_;
gc::InitialHeap initialHeap_;
MNewTypedObject(types::CompilerConstraintList *constraints,
InlineTypedObject *templateObject,
gc::InitialHeap initialHeap)
@@ -6070,56 +6036,16 @@ class MConcat
bool writeRecoverData(CompactBufferWriter &writer) const;
bool canRecoverOnBailout() const {
return true;
}
ALLOW_CLONE(MConcat)
};
-class MConcatPar
- : public MTernaryInstruction,
- public NoTypePolicy::Data
-{
- MConcatPar(MDefinition *cx, MDefinition *left, MDefinition *right)
- : MTernaryInstruction(cx, left, right)
- {
- // Type analysis has already run, before replacing with the parallel
- // variant.
- MOZ_ASSERT(left->type() == MIRType_String && right->type() == MIRType_String);
-
- setMovable();
- setResultType(MIRType_String);
- }
-
- public:
- INSTRUCTION_HEADER(ConcatPar)
-
- static MConcatPar *New(TempAllocator &alloc, MDefinition *cx, MConcat *concat) {
- return new(alloc) MConcatPar(cx, concat->lhs(), concat->rhs());
- }
-
- MDefinition *forkJoinContext() const {
- return getOperand(0);
- }
- MDefinition *lhs() const {
- return getOperand(1);
- }
- MDefinition *rhs() const {
- return getOperand(2);
- }
-
- bool congruentTo(const MDefinition *ins) const {
- return congruentIfOperandsEqual(ins);
- }
- AliasSet getAliasSet() const {
- return AliasSet::None();
- }
-};
-
class MCharCodeAt
: public MBinaryInstruction,
public MixPolicy<StringPolicy<0>, IntPolicy<1> >::Data
{
MCharCodeAt(MDefinition *str, MDefinition *index)
: MBinaryInstruction(str, index)
{
setMovable();
@@ -6623,69 +6549,16 @@ class MCheckOverRecursed
public:
INSTRUCTION_HEADER(CheckOverRecursed)
static MCheckOverRecursed *New(TempAllocator &alloc) {
return new(alloc) MCheckOverRecursed();
}
};
-// Check the current frame for over-recursion past the global stack limit.
-// Uses the per-thread recursion limit.
-class MCheckOverRecursedPar
- : public MUnaryInstruction,
- public NoTypePolicy::Data
-{
- explicit MCheckOverRecursedPar(MDefinition *cx)
- : MUnaryInstruction(cx)
- {
- setResultType(MIRType_None);
- setGuard();
- setMovable();
- }
-
- public:
- INSTRUCTION_HEADER(CheckOverRecursedPar);
-
- static MCheckOverRecursedPar *New(TempAllocator &alloc, MDefinition *cx) {
- return new(alloc) MCheckOverRecursedPar(cx);
- }
-
- MDefinition *forkJoinContext() const {
- return getOperand(0);
- }
-};
-
-// Check for an interrupt (or rendezvous) in parallel mode.
-class MInterruptCheckPar
- : public MUnaryInstruction,
- public NoTypePolicy::Data
-{
- explicit MInterruptCheckPar(MDefinition *cx)
- : MUnaryInstruction(cx)
- {
- setResultType(MIRType_None);
- setGuard();
- }
-
- public:
- INSTRUCTION_HEADER(InterruptCheckPar);
-
- static MInterruptCheckPar *New(TempAllocator &alloc, MDefinition *cx) {
- return new(alloc) MInterruptCheckPar(cx);
- }
-
- MDefinition *forkJoinContext() const {
- return getOperand(0);
- }
- AliasSet getAliasSet() const {
- return AliasSet::None();
- }
-};
-
// Check whether we need to fire the interrupt handler.
class MInterruptCheck : public MNullaryInstruction
{
MInterruptCheck() {
setGuard();
}
public:
@@ -7191,53 +7064,16 @@ class MLambdaArrow
MDefinition *thisDef() const {
return getOperand(1);
}
const LambdaFunctionInfo &info() const {
return info_;
}
};
-class MLambdaPar
- : public MBinaryInstruction,
- public SingleObjectPolicy::Data
-{
- LambdaFunctionInfo info_;
-
- MLambdaPar(MDefinition *cx, MDefinition *scopeChain, JSFunction *fun,
- types::TemporaryTypeSet *resultTypes, const LambdaFunctionInfo &info)
- : MBinaryInstruction(cx, scopeChain), info_(info)
- {
- MOZ_ASSERT(!info_.singletonType);
- MOZ_ASSERT(!info_.useNewTypeForClone);
- setResultType(MIRType_Object);
- setResultTypeSet(resultTypes);
- }
-
- public:
- INSTRUCTION_HEADER(LambdaPar);
-
- static MLambdaPar *New(TempAllocator &alloc, MDefinition *cx, MLambda *lambda) {
- return new(alloc) MLambdaPar(cx, lambda->scopeChain(), lambda->info().fun,
- lambda->resultTypeSet(), lambda->info());
- }
-
- MDefinition *forkJoinContext() const {
- return getOperand(0);
- }
-
- MDefinition *scopeChain() const {
- return getOperand(1);
- }
-
- const LambdaFunctionInfo &info() const {
- return info_;
- }
-};
-
// Returns obj->slots.
class MSlots
: public MUnaryInstruction,
public SingleObjectPolicy::Data
{
explicit MSlots(MDefinition *object)
: MUnaryInstruction(object)
{
@@ -9997,73 +9833,16 @@ class MFunctionEnvironment
MDefinition *foldsTo(TempAllocator &alloc);
// A function's environment is fixed.
AliasSet getAliasSet() const {
return AliasSet::None();
}
};
-// Loads the current js::ForkJoinContext*.
-// Only applicable in ParallelExecution.
-class MForkJoinContext
- : public MNullaryInstruction
-{
- MForkJoinContext()
- : MNullaryInstruction()
- {
- setResultType(MIRType_ForkJoinContext);
- }
-
- public:
- INSTRUCTION_HEADER(ForkJoinContext);
-
- static MForkJoinContext *New(TempAllocator &alloc) {
- return new(alloc) MForkJoinContext();
- }
-
- AliasSet getAliasSet() const {
- // Indicate that this instruction reads nothing, stores nothing.
- // (For all intents and purposes)
- return AliasSet::None();
- }
-
- bool possiblyCalls() const {
- return true;
- }
-};
-
-// Calls the ForkJoinGetSlice stub, used for inlining the eponymous intrinsic.
-// Only applicable in ParallelExecution.
-class MForkJoinGetSlice
- : public MUnaryInstruction,
- public NoTypePolicy::Data
-{
- explicit MForkJoinGetSlice(MDefinition *cx)
- : MUnaryInstruction(cx)
- {
- setResultType(MIRType_Int32);
- }
-
- public:
- INSTRUCTION_HEADER(ForkJoinGetSlice);
-
- static MForkJoinGetSlice *New(TempAllocator &alloc, MDefinition *cx) {
- return new(alloc) MForkJoinGetSlice(cx);
- }
-
- MDefinition *forkJoinContext() {
- return getOperand(0);
- }
-
- bool possiblyCalls() const {
- return true;
- }
-};
-
// Store to vp[slot] (slots that are not inline in an object).
class MStoreSlot
: public MBinaryInstruction,
public MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >::Data
{
uint32_t slot_;
MIRType slotType_;
bool needsBarrier_;
@@ -11318,92 +11097,16 @@ class MRest
AliasSet getAliasSet() const {
return AliasSet::None();
}
bool possiblyCalls() const {
return true;
}
};
-class MRestPar
- : public MBinaryInstruction,
- public MRestCommon,
- public IntPolicy<1>::Data
-{
- MRestPar(MDefinition *cx, MDefinition *numActuals, unsigned numFormals,
- ArrayObject *templateObject, types::TemporaryTypeSet *resultTypes)
- : MBinaryInstruction(cx, numActuals),
- MRestCommon(numFormals, templateObject)
- {
- setResultType(MIRType_Object);
- setResultTypeSet(resultTypes);
- }
-
- public:
- INSTRUCTION_HEADER(RestPar);
-
- static MRestPar *New(TempAllocator &alloc, MDefinition *cx, MRest *rest) {
- return new(alloc) MRestPar(cx, rest->numActuals(), rest->numFormals(),
- rest->templateObject(), rest->resultTypeSet());
- }
-
- MDefinition *forkJoinContext() const {
- return getOperand(0);
- }
- MDefinition *numActuals() const {
- return getOperand(1);
- }
-
- AliasSet getAliasSet() const {
- return AliasSet::None();
- }
- bool possiblyCalls() const {
- return true;
- }
-};
-
-// Guard on an object being safe for writes by current parallel cx.
-// Must be either thread-local or else a handle into the destination array.
-class MGuardThreadExclusive
- : public MBinaryInstruction,
- public ObjectPolicy<1>::Data
-{
- MGuardThreadExclusive(MDefinition *cx, MDefinition *obj)
- : MBinaryInstruction(cx, obj)
- {
- setResultType(MIRType_None);
- setGuard();
- }
-
- public:
- INSTRUCTION_HEADER(GuardThreadExclusive);
-
- static MGuardThreadExclusive *New(TempAllocator &alloc, MDefinition *cx, MDefinition *obj) {
- return new(alloc) MGuardThreadExclusive(cx, obj);
- }
- MDefinition *forkJoinContext() const {
- return getOperand(0);
- }
- MDefinition *object() const {
- return getOperand(1);
- }
- BailoutKind bailoutKind() const {
- return Bailout_GuardThreadExclusive;
- }
- bool congruentTo(const MDefinition *ins) const {
- return congruentIfOperandsEqual(ins);
- }
- AliasSet getAliasSet() const {
- return AliasSet::None();
- }
- bool possiblyCalls() const {
- return true;
- }
-};
-
class MFilterTypeSet
: public MUnaryInstruction,
public FilterTypeSetPolicy::Data
{
MFilterTypeSet(MDefinition *def, types::TemporaryTypeSet *types)
: MUnaryInstruction(def)
{
MOZ_ASSERT(!types->unknown());
@@ -11641,49 +11344,16 @@ class MNewRunOnceCallObject : public MNe
static MNewRunOnceCallObject *
New(TempAllocator &alloc, CallObject *templateObj)
{
return new(alloc) MNewRunOnceCallObject(templateObj);
}
};
-class MNewCallObjectPar
- : public MUnaryInstruction,
- public NoTypePolicy::Data
-{
- AlwaysTenured<CallObject*> templateObj_;
-
- MNewCallObjectPar(MDefinition *cx, CallObject *templateObj)
- : MUnaryInstruction(cx),
- templateObj_(templateObj)
- {
- setResultType(MIRType_Object);
- }
-
- public:
- INSTRUCTION_HEADER(NewCallObjectPar);
-
- static MNewCallObjectPar *New(TempAllocator &alloc, MDefinition *cx, MNewCallObjectBase *callObj) {
- return new(alloc) MNewCallObjectPar(cx, callObj->templateObject());
- }
-
- MDefinition *forkJoinContext() const {
- return getOperand(0);
- }
-
- CallObject *templateObj() const {
- return templateObj_;
- }
-
- AliasSet getAliasSet() const {
- return AliasSet::None();
- }
-};
-
class MNewStringObject :
public MUnaryInstruction,
public ConvertToStringPolicy<0>::Data
{
AlwaysTenuredObject templateObj_;
MNewStringObject(MDefinition *input, JSObject *templateObj)
: MUnaryInstruction(input),
@@ -11759,63 +11429,16 @@ class MEnclosingScope : public MLoadFixe
}
AliasSet getAliasSet() const {
// ScopeObject reserved slots are immutable.
return AliasSet::None();
}
};
-// Creates a dense array of the given length.
-//
-// Note: the template object should be an *empty* dense array!
-class MNewDenseArrayPar
- : public MBinaryInstruction,
- public NoTypePolicy::Data
-{
- AlwaysTenured<ArrayObject*> templateObject_;
-
- MNewDenseArrayPar(MDefinition *cx, MDefinition *length, ArrayObject *templateObject)
- : MBinaryInstruction(cx, length),
- templateObject_(templateObject)
- {
- MOZ_ASSERT(length->type() == MIRType_Int32);
- setResultType(MIRType_Object);
- }
-
- public:
- INSTRUCTION_HEADER(NewDenseArrayPar);
-
- static MNewDenseArrayPar *New(TempAllocator &alloc, MDefinition *cx, MDefinition *length,
- ArrayObject *templateObject)
- {
- return new(alloc) MNewDenseArrayPar(cx, length, templateObject);
- }
-
- MDefinition *forkJoinContext() const {
- return getOperand(0);
- }
-
- MDefinition *length() const {
- return getOperand(1);
- }
-
- ArrayObject *templateObject() const {
- return templateObject_;
- }
-
- bool possiblyCalls() const {
- return true;
- }
-
- AliasSet getAliasSet() const {
- return AliasSet::None();
- }
-};
-
// This is an element of a spaghetti stack which is used to represent the memory
// context which has to be restored in case of a bailout.
struct MStoreToRecover : public TempObject, public InlineSpaghettiStackNode<MStoreToRecover>
{
MDefinition *operand;
explicit MStoreToRecover(MDefinition *operand)
: operand(operand)
--- a/js/src/jit/MIRGraph.cpp
+++ b/js/src/jit/MIRGraph.cpp
@@ -197,47 +197,16 @@ MIRGraph::removeBlockIncludingPhis(MBasi
void
MIRGraph::unmarkBlocks()
{
for (MBasicBlockIterator i(blocks_.begin()); i != blocks_.end(); i++)
i->unmark();
}
-MDefinition *
-MIRGraph::forkJoinContext()
-{
- // Search the entry block to find a ForkJoinContext instruction. If we do
- // not find one, add one after the Start instruction.
- //
- // Note: the original design used a field in MIRGraph to cache the
- // forkJoinContext rather than searching for it again. However, this
- // could become out of date due to DCE. Given that we do not generally
- // have to search very far to find the ForkJoinContext instruction if it
- // exists, and that we don't look for it that often, I opted to simply
- // eliminate the cache and search anew each time, so that it is that much
- // easier to keep the IR coherent. - nmatsakis
-
- MBasicBlock *entry = entryBlock();
- MOZ_ASSERT(entry->info().executionMode() == ParallelExecution);
-
- MInstruction *start = nullptr;
- for (MInstructionIterator ins(entry->begin()); ins != entry->end(); ins++) {
- if (ins->isForkJoinContext())
- return *ins;
- else if (ins->isStart())
- start = *ins;
- }
- MOZ_ASSERT(start);
-
- MForkJoinContext *cx = MForkJoinContext::New(alloc());
- entry->insertAfter(start, cx);
- return cx;
-}
-
MBasicBlock *
MBasicBlock::New(MIRGraph &graph, BytecodeAnalysis *analysis, CompileInfo &info,
MBasicBlock *pred, const BytecodeSite *site, Kind kind)
{
MOZ_ASSERT(site->pc() != nullptr);
MBasicBlock *block = new(graph.alloc()) MBasicBlock(graph, info, site, kind);
if (!block->init())
@@ -802,17 +771,16 @@ MBasicBlock::safeInsertTop(MDefinition *
// Beta nodes and interrupt checks are required to be located at the
// beginnings of basic blocks, so we must insert new instructions after any
// such instructions.
MInstructionIterator insertIter = !ins || ins->isPhi()
? begin()
: begin(ins->toInstruction());
while (insertIter->isBeta() ||
insertIter->isInterruptCheck() ||
- insertIter->isInterruptCheckPar() ||
insertIter->isConstant() ||
(!(ignore & IgnoreRecover) && insertIter->isRecoveredOnBailout()))
{
insertIter++;
}
return *insertIter;
}
--- a/js/src/jit/MIRGraph.h
+++ b/js/src/jit/MIRGraph.h
@@ -802,22 +802,16 @@ class MIRGraph
bool hasTryBlock() const {
return hasTryBlock_;
}
void setHasTryBlock() {
hasTryBlock_ = true;
}
- // The per-thread context. So as not to modify the calling convention for
- // parallel code, we obtain the current ForkJoinContext from thread-local
- // storage. This helper method will lazilly insert an MForkJoinContext
- // instruction in the entry block and return the definition.
- MDefinition *forkJoinContext();
-
void dump(FILE *fp);
void dump();
};
class MDefinitionIterator
{
friend class MBasicBlock;
friend class MNodeIterator;
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -86,17 +86,16 @@ namespace jit {
_(Random) \
_(MathFunction) \
_(Add) \
_(Sub) \
_(Mul) \
_(Div) \
_(Mod) \
_(Concat) \
- _(ConcatPar) \
_(CharCodeAt) \
_(FromCharCode) \
_(StringSplit) \
_(Substr) \
_(Return) \
_(Throw) \
_(Box) \
_(Unbox) \
@@ -242,27 +241,17 @@ namespace jit {
_(AsmJSStoreGlobalVar) \
_(AsmJSLoadFuncPtr) \
_(AsmJSLoadFFIFunc) \
_(AsmJSReturn) \
_(AsmJSParameter) \
_(AsmJSVoidReturn) \
_(AsmJSPassStackArg) \
_(AsmJSCall) \
- _(CheckOverRecursedPar) \
- _(NewCallObjectPar) \
- _(NewPar) \
- _(NewDenseArrayPar) \
_(NewDerivedTypedObject) \
- _(LambdaPar) \
- _(RestPar) \
- _(ForkJoinContext) \
- _(ForkJoinGetSlice) \
- _(GuardThreadExclusive) \
- _(InterruptCheckPar) \
_(RecompileCheck) \
_(MemoryBarrier) \
_(AsmJSCompareExchangeHeap) \
_(AsmJSAtomicBinopHeap) \
_(UnknownValue) \
_(LexicalCheck) \
_(ThrowUninitializedLexical) \
_(Debugger)
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -13,19 +13,17 @@
#include "gc/GCTrace.h"
#include "jit/AtomicOp.h"
#include "jit/Bailouts.h"
#include "jit/BaselineFrame.h"
#include "jit/BaselineIC.h"
#include "jit/BaselineJIT.h"
#include "jit/Lowering.h"
#include "jit/MIR.h"
-#include "jit/ParallelFunctions.h"
#include "js/Conversions.h"
-#include "vm/ForkJoin.h"
#include "vm/TraceLogging.h"
#include "jsgcinlines.h"
#include "jsinferinlines.h"
#include "jsobjinlines.h"
#include "vm/Interpreter-inl.h"
using namespace js;
@@ -831,96 +829,16 @@ MacroAssembler::newGCString(Register res
void
MacroAssembler::newGCFatInlineString(Register result, Register temp, Label *fail)
{
allocateNonObject(result, temp, js::gc::FINALIZE_FAT_INLINE_STRING, fail);
}
void
-MacroAssembler::newGCThingPar(Register result, Register cx, Register tempReg1, Register tempReg2,
- gc::AllocKind allocKind, Label *fail)
-{
- return newGCTenuredThingPar(result, cx, tempReg1, tempReg2, allocKind, fail);
-}
-
-void
-MacroAssembler::newGCTenuredThingPar(Register result, Register cx,
- Register tempReg1, Register tempReg2,
- gc::AllocKind allocKind, Label *fail)
-{
- // Similar to ::newGCThing(), except that it allocates from a custom
- // Allocator in the ForkJoinContext*, rather than being hardcoded to the
- // compartment allocator. This requires two temporary registers.
- //
- // Subtle: I wanted to reuse `result` for one of the temporaries, but the
- // register allocator was assigning it to the same register as `cx`.
- // Then we overwrite that register which messed up the OOL code.
-
- uint32_t thingSize = (uint32_t)gc::Arena::thingSize(allocKind);
-
- // Load the allocator:
- // tempReg1 = (Allocator*) forkJoinCx->allocator()
- loadPtr(Address(cx, ThreadSafeContext::offsetOfAllocator()),
- tempReg1);
-
- // Get a pointer to the relevant free list:
- // tempReg1 = (FreeList*) &tempReg1->arenas.freeLists[(allocKind)]
- uint32_t offset = (offsetof(Allocator, arenas) +
- js::gc::ArenaLists::getFreeListOffset(allocKind));
- addPtr(Imm32(offset), tempReg1);
-
- // Load first item on the list
- // tempReg2 = tempReg1->head.first
- loadPtr(Address(tempReg1, gc::FreeList::offsetOfFirst()), tempReg2);
-
- // Check whether bump-allocation is possible.
- // if tempReg1->head.last <= tempReg2, fail
- branchPtr(Assembler::BelowOrEqual,
- Address(tempReg1, gc::FreeList::offsetOfLast()),
- tempReg2,
- fail);
-
- // If so, take |first| and advance pointer by thingSize bytes.
- // result = tempReg2;
- // tempReg2 += thingSize;
- movePtr(tempReg2, result);
- addPtr(Imm32(thingSize), tempReg2);
-
- // Update |first|.
- // tempReg1->head.first = tempReg2;
- storePtr(tempReg2, Address(tempReg1, gc::FreeList::offsetOfFirst()));
-}
-
-void
-MacroAssembler::newGCThingPar(Register result, Register cx, Register tempReg1, Register tempReg2,
- NativeObject *templateObject, Label *fail)
-{
- gc::AllocKind allocKind = templateObject->asTenured().getAllocKind();
- MOZ_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
- MOZ_ASSERT(!templateObject->numDynamicSlots());
-
- newGCThingPar(result, cx, tempReg1, tempReg2, allocKind, fail);
-}
-
-void
-MacroAssembler::newGCStringPar(Register result, Register cx, Register tempReg1, Register tempReg2,
- Label *fail)
-{
- newGCTenuredThingPar(result, cx, tempReg1, tempReg2, js::gc::FINALIZE_STRING, fail);
-}
-
-void
-MacroAssembler::newGCFatInlineStringPar(Register result, Register cx, Register tempReg1,
- Register tempReg2, Label *fail)
-{
- newGCTenuredThingPar(result, cx, tempReg1, tempReg2, js::gc::FINALIZE_FAT_INLINE_STRING, fail);
-}
-
-void
MacroAssembler::copySlotsFromTemplate(Register obj, const NativeObject *templateObj,
uint32_t start, uint32_t end)
{
uint32_t nfixed = Min(templateObj->numFixedSlots(), end);
for (unsigned i = start; i < nfixed; i++)
storeValue(templateObj->getFixedSlot(i), Address(obj, NativeObject::getFixedSlotOffset(i)));
}
@@ -1198,41 +1116,25 @@ MacroAssembler::loadStringChar(Register
jump(&done);
bind(&isLatin1);
load8ZeroExtend(BaseIndex(output, index, TimesOne), output);
bind(&done);
}
-void
-MacroAssembler::checkInterruptFlagPar(Register tempReg, Label *fail)
-{
- movePtr(ImmPtr(GetJitContext()->runtime->addressOfInterruptParUint32()), tempReg);
- branch32(Assembler::NonZero, Address(tempReg, 0), Imm32(0), fail);
-}
-
// Save an exit frame (which must be aligned to the stack pointer) to
// PerThreadData::jitTop of the main thread.
void
MacroAssembler::linkExitFrame()
{
AbsoluteAddress jitTop(GetJitContext()->runtime->addressOfJitTop());
storePtr(StackPointer, jitTop);
}
-// Save an exit frame to the thread data of the current thread, given a
-// register that holds a PerThreadData *.
-void
-MacroAssembler::linkParallelExitFrame(Register pt)
-{
- Address jitTop(pt, offsetof(PerThreadData, jitTop));
- storePtr(StackPointer, jitTop);
-}
-
static void
ReportOverRecursed(JSContext *cx)
{
js_ReportOverRecursed(cx);
}
void
MacroAssembler::generateBailoutTail(Register scratch, Register bailoutInfo)
@@ -1379,181 +1281,49 @@ MacroAssembler::generateBailoutTail(Regi
addPtr(Imm32(ExitFrameLayout::SizeWithFooter()), StackPointer);
jump(jitcodeReg);
}
}
}
void
-MacroAssembler::loadBaselineOrIonRaw(Register script, Register dest, ExecutionMode mode,
- Label *failure)
+MacroAssembler::loadBaselineOrIonRaw(Register script, Register dest, Label *failure)
{
- if (mode == SequentialExecution) {
- loadPtr(Address(script, JSScript::offsetOfBaselineOrIonRaw()), dest);
- if (failure)
- branchTestPtr(Assembler::Zero, dest, dest, failure);
- } else {
- loadPtr(Address(script, JSScript::offsetOfParallelIonScript()), dest);
- if (failure)
- branchPtr(Assembler::BelowOrEqual, dest, ImmPtr(ION_COMPILING_SCRIPT), failure);
- loadPtr(Address(dest, IonScript::offsetOfMethod()), dest);
- loadPtr(Address(dest, JitCode::offsetOfCode()), dest);
- }
+ loadPtr(Address(script, JSScript::offsetOfBaselineOrIonRaw()), dest);
+ if (failure)
+ branchTestPtr(Assembler::Zero, dest, dest, failure);
}
void
-MacroAssembler::loadBaselineOrIonNoArgCheck(Register script, Register dest, ExecutionMode mode,
- Label *failure)
+MacroAssembler::loadBaselineOrIonNoArgCheck(Register script, Register dest, Label *failure)
{
- if (mode == SequentialExecution) {
- loadPtr(Address(script, JSScript::offsetOfBaselineOrIonSkipArgCheck()), dest);
- if (failure)
- branchTestPtr(Assembler::Zero, dest, dest, failure);
- } else {
- // Find second register to get the offset to skip argument check
- Register offset = script;
- if (script == dest) {
- GeneralRegisterSet regs(GeneralRegisterSet::All());
- regs.take(dest);
- offset = regs.takeAny();
- }
-
- loadPtr(Address(script, JSScript::offsetOfParallelIonScript()), dest);
- if (failure)
- branchPtr(Assembler::BelowOrEqual, dest, ImmPtr(ION_COMPILING_SCRIPT), failure);
-
- Push(offset);
- load32(Address(script, IonScript::offsetOfSkipArgCheckEntryOffset()), offset);
-
- loadPtr(Address(dest, IonScript::offsetOfMethod()), dest);
- loadPtr(Address(dest, JitCode::offsetOfCode()), dest);
- addPtr(offset, dest);
-
- Pop(offset);
- }
+ loadPtr(Address(script, JSScript::offsetOfBaselineOrIonSkipArgCheck()), dest);
+ if (failure)
+ branchTestPtr(Assembler::Zero, dest, dest, failure);
}
void
MacroAssembler::loadBaselineFramePtr(Register framePtr, Register dest)
{
if (framePtr != dest)
movePtr(framePtr, dest);
subPtr(Imm32(BaselineFrame::Size()), dest);
}
void
-MacroAssembler::loadForkJoinContext(Register cx, Register scratch)
-{
- // Load the current ForkJoinContext *. If we need a parallel exit frame,
- // chances are we are about to do something very slow anyways, so just
- // call ForkJoinContextPar again instead of using the cached version.
- setupUnalignedABICall(0, scratch);
- callWithABI(JS_FUNC_TO_DATA_PTR(void *, ForkJoinContextPar));
- if (ReturnReg != cx)
- movePtr(ReturnReg, cx);
-}
-
-void
-MacroAssembler::loadContext(Register cxReg, Register scratch, ExecutionMode executionMode)
-{
- switch (executionMode) {
- case SequentialExecution:
- // The scratch register is not used for sequential execution.
- loadJSContext(cxReg);
- break;
- case ParallelExecution:
- loadForkJoinContext(cxReg, scratch);
- break;
- default:
- MOZ_CRASH("No such execution mode");
- }
-}
-
-void
-MacroAssembler::enterParallelExitFrameAndLoadContext(const VMFunction *f, Register cx,
- Register scratch)
-{
- loadForkJoinContext(cx, scratch);
- // Load the PerThreadData from from the cx.
- loadPtr(Address(cx, offsetof(ForkJoinContext, perThreadData)), scratch);
- linkParallelExitFrame(scratch);
- // Push the ioncode.
- exitCodePatch_ = PushWithPatch(ImmWord(-1));
- // Push the VMFunction pointer, to mark arguments.
- Push(ImmPtr(f));
-}
-
-void
-MacroAssembler::enterFakeParallelExitFrame(Register cx, Register scratch,
- JitCode *codeVal)
-{
- // Load the PerThreadData from from the cx.
- loadPtr(Address(cx, offsetof(ForkJoinContext, perThreadData)), scratch);
- linkParallelExitFrame(scratch);
- Push(ImmPtr(codeVal));
- Push(ImmPtr(nullptr));
-}
-
-void
-MacroAssembler::enterExitFrameAndLoadContext(const VMFunction *f, Register cxReg, Register scratch,
- ExecutionMode executionMode)
-{
- switch (executionMode) {
- case SequentialExecution:
- // The scratch register is not used for sequential execution.
- enterExitFrame(f);
- loadJSContext(cxReg);
- break;
- case ParallelExecution:
- enterParallelExitFrameAndLoadContext(f, cxReg, scratch);
- break;
- default:
- MOZ_CRASH("No such execution mode");
- }
-}
-
-void
-MacroAssembler::enterFakeExitFrame(Register cxReg, Register scratch,
- ExecutionMode executionMode,
- JitCode *codeVal)
-{
- switch (executionMode) {
- case SequentialExecution:
- // The cx and scratch registers are not used for sequential execution.
- enterFakeExitFrame(codeVal);
- break;
- case ParallelExecution:
- enterFakeParallelExitFrame(cxReg, scratch, codeVal);
- break;
- default:
- MOZ_CRASH("No such execution mode");
- }
-}
-
-void
-MacroAssembler::handleFailure(ExecutionMode executionMode)
+MacroAssembler::handleFailure()
{
// Re-entry code is irrelevant because the exception will leave the
// running function and never come back
if (sps_)
sps_->skipNextReenter();
leaveSPSFrame();
- JitCode *excTail;
- switch (executionMode) {
- case SequentialExecution:
- excTail = GetJitContext()->runtime->jitRuntime()->getExceptionTail();
- break;
- case ParallelExecution:
- excTail = GetJitContext()->runtime->jitRuntime()->getExceptionTailParallel();
- break;
- default:
- MOZ_CRASH("No such execution mode");
- }
+ JitCode *excTail = GetJitContext()->runtime->jitRuntime()->getExceptionTail();
jump(excTail);
// Doesn't actually emit code, but balances the leave()
if (sps_)
sps_->reenter(*this, InvalidReg);
}
#ifdef DEBUG
@@ -2142,23 +1912,19 @@ MacroAssembler::convertTypedOrValueToInt
default:
MOZ_CRASH("Bad MIRType");
}
}
void
MacroAssembler::finish()
{
- if (sequentialFailureLabel_.used()) {
- bind(&sequentialFailureLabel_);
- handleFailure(SequentialExecution);
- }
- if (parallelFailureLabel_.used()) {
- bind(¶llelFailureLabel_);
- handleFailure(ParallelExecution);
+ if (failureLabel_.used()) {
+ bind(&failureLabel_);
+ handleFailure();
}
MacroAssemblerSpecific::finish();
}
void
MacroAssembler::branchIfNotInterpretedConstructor(Register fun, Register scratch, Label *label)
{
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -193,18 +193,17 @@ class MacroAssembler : public MacroAssem
// This field is used to manage profiling instrumentation output. If
// provided and enabled, then instrumentation will be emitted around call
// sites. The IonInstrumentation instance is hosted inside of
// CodeGeneratorShared and is the manager of when instrumentation is
// actually emitted or not. If nullptr, then no instrumentation is emitted.
IonInstrumentation *sps_;
// Labels for handling exceptions and failures.
- NonAssertingLabel sequentialFailureLabel_;
- NonAssertingLabel parallelFailureLabel_;
+ NonAssertingLabel failureLabel_;
public:
// If instrumentation should be emitted, then the sps parameter should be
// provided, but otherwise it can be safely omitted to prevent all
// instrumentation from being emitted.
MacroAssembler()
: sps_(nullptr)
{
@@ -825,46 +824,29 @@ class MacroAssembler : public MacroAssem
void newGCThing(Register result, Register temp, NativeObject *templateObj,
gc::InitialHeap initialHeap, Label *fail);
void initGCThing(Register obj, Register temp, JSObject *templateObj,
bool initFixedSlots = true);
void newGCString(Register result, Register temp, Label *fail);
void newGCFatInlineString(Register result, Register temp, Label *fail);
- void newGCThingPar(Register result, Register cx, Register tempReg1, Register tempReg2,
- gc::AllocKind allocKind, Label *fail);
- void newGCTenuredThingPar(Register result, Register cx, Register tempReg1, Register tempReg2,
- gc::AllocKind allocKind, Label *fail);
- void newGCThingPar(Register result, Register cx, Register tempReg1, Register tempReg2,
- NativeObject *templateObject, Label *fail);
- void newGCStringPar(Register result, Register cx, Register tempReg1, Register tempReg2,
- Label *fail);
- void newGCFatInlineStringPar(Register result, Register cx, Register tempReg1, Register tempReg2,
- Label *fail);
-
-
// Compares two strings for equality based on the JSOP.
// This checks for identical pointers, atoms and length and fails for everything else.
void compareStrings(JSOp op, Register left, Register right, Register result,
Label *fail);
- // Checks the flags that signal that parallel code may need to interrupt or
- // abort. Branches to fail in that case.
- void checkInterruptFlagPar(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.
// This is a reference to a patch location where the JitCode* will be written.
private:
CodeOffsetLabel exitCodePatch_;
private:
void linkExitFrame();
- void linkParallelExitFrame(Register pt);
public:
void enterExitFrame(const VMFunction *f = nullptr) {
linkExitFrame();
// Push the ioncode. (Bailout or VM wrapper)
exitCodePatch_ = PushWithPatch(ImmWord(-1));
// Push VMFunction pointer, to mark arguments.
Push(ImmPtr(f));
@@ -879,30 +861,16 @@ class MacroAssembler : public MacroAssem
}
void loadThreadPool(Register pool) {
// JitRuntimes are tied to JSRuntimes and there is one ThreadPool per
// JSRuntime, so we can hardcode the ThreadPool address here.
movePtr(ImmPtr(GetJitContext()->runtime->addressOfThreadPool()), pool);
}
- void loadForkJoinContext(Register cx, Register scratch);
- void loadContext(Register cxReg, Register scratch, ExecutionMode executionMode);
-
- void enterParallelExitFrameAndLoadContext(const VMFunction *f, Register cx,
- Register scratch);
-
- void enterExitFrameAndLoadContext(const VMFunction *f, Register cxReg, Register scratch,
- ExecutionMode executionMode);
-
- void enterFakeParallelExitFrame(Register cx, Register scratch, JitCode *codeVal);
-
- void enterFakeExitFrame(Register cxReg, Register scratch, ExecutionMode executionMode,
- JitCode *codeVal);
-
void leaveExitFrame() {
freeStack(ExitFooterFrame::Size());
}
bool hasEnteredExitFrame() const {
return exitCodePatch_.offset() != 0;
}
@@ -1164,41 +1132,37 @@ class MacroAssembler : public MacroAssem
loadPtr(AbsoluteAddress(p->addressOfSizePointer()), temp);
add32(Imm32(-1), Address(temp, 0));
}
static const char enterJitLabel[];
void spsMarkJit(SPSProfiler *p, Register framePtr, Register temp);
void spsUnmarkJit(SPSProfiler *p, Register temp);
- void loadBaselineOrIonRaw(Register script, Register dest, ExecutionMode mode, Label *failure);
- void loadBaselineOrIonNoArgCheck(Register callee, Register dest, ExecutionMode mode, Label *failure);
+ void loadBaselineOrIonRaw(Register script, Register dest, Label *failure);
+ void loadBaselineOrIonNoArgCheck(Register callee, Register dest, Label *failure);
void loadBaselineFramePtr(Register framePtr, Register dest);
void pushBaselineFramePtr(Register framePtr, Register scratch) {
loadBaselineFramePtr(framePtr, scratch);
push(scratch);
}
private:
- void handleFailure(ExecutionMode executionMode);
+ void handleFailure();
public:
Label *exceptionLabel() {
// Exceptions are currently handled the same way as sequential failures.
- return &sequentialFailureLabel_;
+ return &failureLabel_;
}
- Label *failureLabel(ExecutionMode executionMode) {
- switch (executionMode) {
- case SequentialExecution: return &sequentialFailureLabel_;
- case ParallelExecution: return ¶llelFailureLabel_;
- default: MOZ_CRASH("Unexpected execution mode");
- }
+ Label *failureLabel() {
+ return &failureLabel_;
}
void finish();
void assumeUnreachable(const char *output);
void printf(const char *output);
void printf(const char *output, Register value);
deleted file mode 100644
--- a/js/src/jit/ParallelFunctions.cpp
+++ /dev/null
@@ -1,620 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "jit/ParallelFunctions.h"
-
-#include "builtin/TypedObject.h"
-#include "jit/arm/Simulator-arm.h"
-#include "jit/mips/Simulator-mips.h"
-#include "jit/RematerializedFrame.h"
-#include "vm/ArrayObject.h"
-
-#include "jsgcinlines.h"
-#include "jsobjinlines.h"
-
-#include "vm/NativeObject-inl.h"
-
-using namespace js;
-using namespace jit;
-
-using mozilla::IsInRange;
-
-using JS::AutoCheckCannotGC;
-
-using parallel::Spew;
-using parallel::SpewOps;
-using parallel::SpewBailouts;
-
-// Load the current thread context.
-ForkJoinContext *
-jit::ForkJoinContextPar()
-{
- return ForkJoinContext::current();
-}
-
-// NewGCThingPar() is called in place of NewGCThing() when executing
-// parallel code. It uses the ArenaLists for the current thread and
-// allocates from there.
-JSObject *
-jit::NewGCThingPar(ForkJoinContext *cx, gc::AllocKind allocKind)
-{
- MOZ_ASSERT(ForkJoinContext::current() == cx);
- return js::NewGCObject<NoGC>(cx, allocKind, 0, gc::TenuredHeap);
-}
-
-bool
-jit::ParallelWriteGuard(ForkJoinContext *cx, JSObject *object)
-{
- // Implements the most general form of the write guard, which is
- // suitable for writes to any object O. There are two cases to
- // consider and test for:
- //
- // 1. Writes to thread-local memory are safe. Thread-local memory
- // is defined as memory allocated by the current thread.
- // The definition of the PJS API guarantees that such memory
- // cannot have escaped to other parallel threads.
- //
- // 2. Writes into the output buffer are safe. Some PJS operations
- // supply an out pointer into the final target buffer. The design
- // of the API ensures that this out pointer is always pointing
- // at a fresh region of the buffer that is not accessible to
- // other threads. Thus, even though this output buffer has not
- // been created by the current thread, it is writable.
- //
- // There are some subtleties to consider:
- //
- // A. Typed objects and typed arrays are just views onto a base buffer.
- // For the purposes of guarding parallel writes, it is not important
- // whether the *view* is thread-local -- what matters is whether
- // the *underlying buffer* is thread-local.
- //
- // B. With regard to the output buffer, we have to be careful
- // because of the potential for sequential iterations to be
- // intermingled with parallel ones. During a sequential
- // iteration, the out pointer could escape into global
- // variables and so forth, and thus be used during later
- // parallel operations. However, those out pointers must be
- // pointing to distinct regions of the final output buffer than
- // the ones that are currently being written, so there is no
- // harm done in letting them be read (but not written).
- //
- // In order to be able to distinguish escaped out pointers from
- // prior iterations and the proper out pointers from the
- // current iteration, we always track a *target memory region*
- // (which is a span of bytes within the output buffer) and not
- // just the output buffer itself.
-
- MOZ_ASSERT(ForkJoinContext::current() == cx);
-
- if (object->is<TypedObject>()) {
- TypedObject &typedObj = object->as<TypedObject>();
-
- // Note: check target region based on `typedObj`, not the owner.
- // This is because `typedObj` may point to some subregion of the
- // owner and we only care if that *subregion* is within the
- // target region, not the entire owner.
- if (IsInTargetRegion(cx, &typedObj))
- return true;
-
- // Check whether the object which owns the memory is thread-local.
- if (typedObj.is<OutlineTypedObject>())
- return cx->isThreadLocal(&typedObj.as<OutlineTypedObject>().owner());
- return cx->isThreadLocal(&typedObj);
- }
-
- // For other kinds of writable objects, must be thread-local.
- return cx->isThreadLocal(object);
-}
-
-// Check that |object| (which must be a typed typedObj) maps
-// to memory in the target region.
-//
-// For efficiency, we assume that all handles which the user has
-// access to are either entirely within the target region or entirely
-// without, but not straddling the target region nor encompassing
-// it. This invariant is maintained by the PJS APIs, where the target
-// region and handles are always elements of the same output array.
-bool
-jit::IsInTargetRegion(ForkJoinContext *cx, TypedObject *typedObj)
-{
- MOZ_ASSERT(typedObj->is<TypedObject>()); // in case JIT supplies something bogus
- uint8_t *typedMem = typedObj->typedMem();
- return typedMem >= cx->targetRegionStart &&
- typedMem < cx->targetRegionEnd;
-}
-
-bool
-jit::CheckOverRecursedPar(ForkJoinContext *cx)
-{
- MOZ_ASSERT(ForkJoinContext::current() == cx);
- int stackDummy_;
-
- // In PJS, unlike sequential execution, we don't overwrite the stack limit
- // on interrupt, but we do still call into this routine if the interrupt
- // flag is set, so we still need to double check.
-
-#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
- if (Simulator::Current()->overRecursed()) {
- cx->bailoutRecord->joinCause(ParallelBailoutOverRecursed);
- return false;
- }
-#endif
-
- if (!JS_CHECK_STACK_SIZE(cx->perThreadData->jitStackLimit(), &stackDummy_)) {
- cx->bailoutRecord->joinCause(ParallelBailoutOverRecursed);
- return false;
- }
-
- return InterruptCheckPar(cx);
-}
-
-bool
-jit::InterruptCheckPar(ForkJoinContext *cx)
-{
- MOZ_ASSERT(ForkJoinContext::current() == cx);
- bool result = cx->check();
- if (!result) {
- cx->bailoutRecord->joinCause(ParallelBailoutInterrupt);
- return false;
- }
- return true;
-}
-
-ArrayObject *
-jit::ExtendArrayPar(ForkJoinContext *cx, ArrayObject *array, uint32_t length)
-{
- NativeObject::EnsureDenseResult res =
- array->ensureDenseElementsPreservePackedFlag(cx, 0, length);
- if (res != NativeObject::ED_OK)
- return nullptr;
- return array;
-}
-
-bool
-jit::SetPropertyPar(ForkJoinContext *cx, HandleObject obj, HandlePropertyName name,
- HandleValue value, bool strict, jsbytecode *pc)
-{
- MOZ_ASSERT(cx->isThreadLocal(obj));
-
- if (*pc == JSOP_SETALIASEDVAR) {
- // See comment in jit::SetProperty.
- Shape *shape = obj->as<NativeObject>().lookupPure(name);
- MOZ_ASSERT(shape && shape->hasSlot());
- return obj->as<NativeObject>().setSlotIfHasType(shape, value);
- }
-
- // Fail early on hooks.
- if (obj->getOps()->setProperty)
- return TP_RETRY_SEQUENTIALLY;
-
- RootedValue v(cx, value);
- RootedId id(cx, NameToId(name));
- return baseops::SetPropertyHelper<ParallelExecution>(cx,
- obj.as<NativeObject>(),
- obj.as<NativeObject>(),
- id, baseops::Qualified, &v,
- strict);
-}
-
-bool
-jit::SetElementPar(ForkJoinContext *cx, HandleObject obj, HandleValue index, HandleValue value,
- bool strict)
-{
- RootedId id(cx);
- if (!ValueToIdPure(index, id.address()))
- return false;
-
- if (!obj->isNative())
- return false;
-
- // SetObjectElementOperation, the sequential version, has several checks
- // for certain deoptimizing behaviors, such as marking having written to
- // holes and non-indexed element accesses. We don't do that here, as we
- // can't modify any TI state anyways. If we need to add a new type, we
- // would bail out.
- RootedValue v(cx, value);
- return baseops::SetPropertyHelper<ParallelExecution>(cx,
- obj.as<NativeObject>(),
- obj.as<NativeObject>(),
- id, baseops::Qualified, &v,
- strict);
-}
-
-bool
-jit::SetDenseElementPar(ForkJoinContext *cx, HandleObject obj, int32_t index, HandleValue value,
- bool strict)
-{
- RootedValue indexVal(cx, Int32Value(index));
- return SetElementPar(cx, obj, indexVal, value, strict);
-}
-
-JSString *
-jit::ConcatStringsPar(ForkJoinContext *cx, HandleString left, HandleString right)
-{
- return ConcatStrings<NoGC>(cx, left, right);
-}
-
-JSFlatString *
-jit::IntToStringPar(ForkJoinContext *cx, int i)
-{
- return Int32ToString<NoGC>(cx, i);
-}
-
-JSString *
-jit::DoubleToStringPar(ForkJoinContext *cx, double d)
-{
- return NumberToString<NoGC>(cx, d);
-}
-
-JSString *
-jit::PrimitiveToStringPar(ForkJoinContext *cx, HandleValue input)
-{
- // All other cases are handled in assembly.
- MOZ_ASSERT(input.isDouble() || input.isInt32());
-
- if (input.isInt32())
- return Int32ToString<NoGC>(cx, input.toInt32());
-
- return NumberToString<NoGC>(cx, input.toDouble());
-}
-
-bool
-jit::StringToNumberPar(ForkJoinContext *cx, JSString *str, double *out)
-{
- return StringToNumber(cx, str, out);
-}
-
-#define PAR_RELATIONAL_OP(OP, EXPECTED) \
-do { \
- /* Optimize for two int-tagged operands (typical loop control). */ \
- if (lhs.isInt32() && rhs.isInt32()) { \
- *res = (lhs.toInt32() OP rhs.toInt32()) == EXPECTED; \
- } else if (lhs.isNumber() && rhs.isNumber()) { \
- double l = lhs.toNumber(), r = rhs.toNumber(); \
- *res = (l OP r) == EXPECTED; \
- } else if (lhs.isBoolean() && rhs.isBoolean()) { \
- int l = lhs.toBoolean() ? 1 : 0; \
- int r = rhs.toBoolean() ? 1 : 0; \
- *res = (l OP r) == EXPECTED; \
- } else if (lhs.isBoolean() && rhs.isNumber()) { \
- double l = lhs.toBoolean() ? 1.0 : 0.0; \
- double r = rhs.toNumber(); \
- *res = (l OP r) == EXPECTED; \
- } else if (lhs.isNumber() && rhs.isBoolean()) { \
- double l = lhs.toNumber(); \
- double r = rhs.toBoolean() ? 1.0 : 0.0; \
- *res = (l OP r) == EXPECTED; \
- } else { \
- int32_t vsZero; \
- if (!CompareMaybeStringsPar(cx, lhs, rhs, &vsZero)) \
- return false; \
- *res = (vsZero OP 0) == EXPECTED; \
- } \
- return true; \
-} while(0)
-
-static bool
-CompareStringsPar(ForkJoinContext *cx, JSString *left, JSString *right, int32_t *res)
-{
- ScopedThreadSafeStringInspector leftInspector(left);
- ScopedThreadSafeStringInspector rightInspector(right);
- AutoCheckCannotGC nogc;
- if (!leftInspector.ensureChars(cx, nogc) || !rightInspector.ensureChars(cx, nogc))
- return false;
-
- if (leftInspector.hasLatin1Chars()) {
- if (rightInspector.hasLatin1Chars()) {
- *res = CompareChars(leftInspector.latin1Chars(), left->length(),
- rightInspector.latin1Chars(), right->length());
- } else {
- *res = CompareChars(leftInspector.latin1Chars(), left->length(),
- rightInspector.twoByteChars(), right->length());
- }
- } else {
- if (rightInspector.hasLatin1Chars()) {
- *res = CompareChars(leftInspector.twoByteChars(), left->length(),
- rightInspector.latin1Chars(), right->length());
- } else {
- *res = CompareChars(leftInspector.twoByteChars(), left->length(),
- rightInspector.twoByteChars(), right->length());
- }
- }
-
- return true;
-}
-
-static bool
-CompareMaybeStringsPar(ForkJoinContext *cx, HandleValue v1, HandleValue v2, int32_t *res)
-{
- if (!v1.isString())
- return false;
- if (!v2.isString())
- return false;
- return CompareStringsPar(cx, v1.toString(), v2.toString(), res);
-}
-
-template<bool Equal>
-bool
-LooselyEqualImplPar(ForkJoinContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
-{
- PAR_RELATIONAL_OP(==, Equal);
-}
-
-bool
-js::jit::LooselyEqualPar(ForkJoinContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
-{
- return LooselyEqualImplPar<true>(cx, lhs, rhs, res);
-}
-
-bool
-js::jit::LooselyUnequalPar(ForkJoinContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
-{
- return LooselyEqualImplPar<false>(cx, lhs, rhs, res);
-}
-
-template<bool Equal>
-bool
-StrictlyEqualImplPar(ForkJoinContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
-{
- if (lhs.isNumber()) {
- if (rhs.isNumber()) {
- *res = (lhs.toNumber() == rhs.toNumber()) == Equal;
- return true;
- }
- } else if (lhs.isBoolean()) {
- if (rhs.isBoolean()) {
- *res = (lhs.toBoolean() == rhs.toBoolean()) == Equal;
- return true;
- }
- } else if (lhs.isNull()) {
- if (rhs.isNull()) {
- *res = Equal;
- return true;
- }
- } else if (lhs.isUndefined()) {
- if (rhs.isUndefined()) {
- *res = Equal;
- return true;
- }
- } else if (lhs.isObject()) {
- if (rhs.isObject()) {
- *res = (lhs.toObjectOrNull() == rhs.toObjectOrNull()) == Equal;
- return true;
- }
- } else if (lhs.isString()) {
- if (rhs.isString())
- return LooselyEqualImplPar<Equal>(cx, lhs, rhs, res);
- }
-
- *res = !Equal;
- return true;
-}
-
-bool
-js::jit::StrictlyEqualPar(ForkJoinContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
-{
- return StrictlyEqualImplPar<true>(cx, lhs, rhs, res);
-}
-
-bool
-js::jit::StrictlyUnequalPar(ForkJoinContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
-{
- return StrictlyEqualImplPar<false>(cx, lhs, rhs, res);
-}
-
-bool
-js::jit::LessThanPar(ForkJoinContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
-{
- PAR_RELATIONAL_OP(<, true);
-}
-
-bool
-js::jit::LessThanOrEqualPar(ForkJoinContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
-{
- PAR_RELATIONAL_OP(<=, true);
-}
-
-bool
-js::jit::GreaterThanPar(ForkJoinContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
-{
- PAR_RELATIONAL_OP(>, true);
-}
-
-bool
-js::jit::GreaterThanOrEqualPar(ForkJoinContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
-{
- PAR_RELATIONAL_OP(>=, true);
-}
-
-template<bool Equal>
-bool
-StringsEqualImplPar(ForkJoinContext *cx, HandleString lhs, HandleString rhs, bool *res)
-{
- int32_t vsZero;
- bool ret = CompareStringsPar(cx, lhs, rhs, &vsZero);
- if (ret != true)
- return ret;
- *res = (vsZero == 0) == Equal;
- return true;
-}
-
-bool
-js::jit::StringsEqualPar(ForkJoinContext *cx, HandleString v1, HandleString v2, bool *res)
-{
- return StringsEqualImplPar<true>(cx, v1, v2, res);
-}
-
-bool
-js::jit::StringsUnequalPar(ForkJoinContext *cx, HandleString v1, HandleString v2, bool *res)
-{
- return StringsEqualImplPar<false>(cx, v1, v2, res);
-}
-
-bool
-jit::BitNotPar(ForkJoinContext *cx, HandleValue in, int32_t *out)
-{
- if (in.isObject())
- return false;
- int i;
- if (!NonObjectToInt32(cx, in, &i))
- return false;
- *out = ~i;
- return true;
-}
-
-#define BIT_OP(OP) \
- JS_BEGIN_MACRO \
- int32_t left, right; \
- if (lhs.isObject() || rhs.isObject()) \
- return false; \
- if (!NonObjectToInt32(cx, lhs, &left) || \
- !NonObjectToInt32(cx, rhs, &right)) \
- { \
- return false; \
- } \
- *out = (OP); \
- return true; \
- JS_END_MACRO
-
-bool
-jit::BitXorPar(ForkJoinContext *cx, HandleValue lhs, HandleValue rhs, int32_t *out)
-{
- BIT_OP(left ^ right);
-}
-
-bool
-jit::BitOrPar(ForkJoinContext *cx, HandleValue lhs, HandleValue rhs, int32_t *out)
-{
- BIT_OP(left | right);
-}
-
-bool
-jit::BitAndPar(ForkJoinContext *cx, HandleValue lhs, HandleValue rhs, int32_t *out)
-{
- BIT_OP(left & right);
-}
-
-bool
-jit::BitLshPar(ForkJoinContext *cx, HandleValue lhs, HandleValue rhs, int32_t *out)
-{
- BIT_OP(uint32_t(left) << (right & 31));
-}
-
-bool
-jit::BitRshPar(ForkJoinContext *cx, HandleValue lhs, HandleValue rhs, int32_t *out)
-{
- BIT_OP(left >> (right & 31));
-}
-
-#undef BIT_OP
-
-bool
-jit::UrshValuesPar(ForkJoinContext *cx, HandleValue lhs, HandleValue rhs,
- MutableHandleValue out)
-{
- uint32_t left;
- int32_t right;
- if (lhs.isObject() || rhs.isObject())
- return false;
- if (!NonObjectToUint32(cx, lhs, &left) || !NonObjectToInt32(cx, rhs, &right))
- return false;
- left >>= right & 31;
- out.setNumber(uint32_t(left));
- return true;
-}
-
-void
-jit::BailoutPar(BailoutStack *sp, uint8_t **entryFramePointer)
-{
- parallel::Spew(parallel::SpewBailouts, "Bailing");
-
- ForkJoinContext *cx = ForkJoinContext::current();
-
- // We don't have an exit frame.
- MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
- IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(CommonFrameLayout), 0, 0x1000),
- "Fake jitTop pointer should be within the first page.");
- cx->perThreadData->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
-
- JitActivationIterator jitActivations(cx->perThreadData);
- BailoutFrameInfo bailoutData(jitActivations, sp);
- JitFrameIterator frameIter(jitActivations);
- SnapshotIterator snapIter(frameIter);
-
- cx->bailoutRecord->setIonBailoutKind(snapIter.bailoutKind());
- while (!frameIter.done())
- ++frameIter;
-
- MOZ_ASSERT(frameIter.done());
- *entryFramePointer = frameIter.fp();
-}
-
-bool
-jit::CallToUncompiledScriptPar(ForkJoinContext *cx, JSObject *obj)
-{
-#ifdef DEBUG
- static const int max_bound_function_unrolling = 5;
-
- if (!obj->is<JSFunction>()) {
- Spew(SpewBailouts, "Call to non-function");
- return false;
- }
-
- JSFunction *func = &obj->as<JSFunction>();
- if (func->hasScript()) {
- JSScript *script = func->nonLazyScript();
- Spew(SpewBailouts, "Call to uncompiled script: %p:%s:%d",
- script, script->filename(), script->lineno());
- } else if (func->isInterpretedLazy()) {
- Spew(SpewBailouts, "Call to uncompiled lazy script");
- } else if (func->isBoundFunction()) {
- int depth = 0;
- JSFunction *target = &func->getBoundFunctionTarget()->as<JSFunction>();
- while (depth < max_bound_function_unrolling) {
- if (target->hasScript())
- break;
- if (target->isBoundFunction())
- target = &target->getBoundFunctionTarget()->as<JSFunction>();
- depth--;
- }
- if (target->hasScript()) {
- JSScript *script = target->nonLazyScript();
- Spew(SpewBailouts, "Call to bound function leading (depth: %d) to script: %p:%s:%d",
- depth, script, script->filename(), script->lineno());
- } else {
- Spew(SpewBailouts, "Call to bound function (excessive depth: %d)", depth);
- }
- } else {
- MOZ_ASSERT(func->isNative());
- Spew(SpewBailouts, "Call to native function");
- }
-#endif
-
- return false;
-}
-
-JSObject *
-jit::InitRestParameterPar(ForkJoinContext *cx, uint32_t length, Value *rest,
- HandleObject templateObj, HandleArrayObject res)
-{
- // In parallel execution, we should always have succeeded in allocation
- // before this point. We can do the allocation here like in the sequential
- // path, but duplicating the initGCThing logic is too tedious.
- MOZ_ASSERT(res);
- MOZ_ASSERT(!res->getDenseInitializedLength());
- MOZ_ASSERT(res->type() == templateObj->type());
-
- if (length > 0) {
- NativeObject::EnsureDenseResult edr =
- res->ensureDenseElementsPreservePackedFlag(cx, 0, length);
- if (edr != NativeObject::ED_OK)
- return nullptr;
- res->initDenseElementsUnbarriered(0, rest, length);
- res->setLengthInt32(length);
- }
-
- return res;
-}
deleted file mode 100644
--- a/js/src/jit/ParallelFunctions.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef jit_ParallelFunctions_h
-#define jit_ParallelFunctions_h
-
-#include "gc/Heap.h"
-#include "vm/ForkJoin.h"
-
-namespace js {
-
-class TypedObject; // subclass of JSObject* defined in builtin/TypedObject.h
-
-namespace jit {
-
-ForkJoinContext *ForkJoinContextPar();
-JSObject *NewGCThingPar(ForkJoinContext *cx, gc::AllocKind allocKind);
-bool ParallelWriteGuard(ForkJoinContext *cx, JSObject *object);
-bool IsInTargetRegion(ForkJoinContext *cx, TypedObject *object);
-bool CheckOverRecursedPar(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
-// generation.
-ArrayObject *ExtendArrayPar(ForkJoinContext *cx, ArrayObject *array, uint32_t length);
-
-// Set properties and elements on thread local objects.
-bool SetPropertyPar(ForkJoinContext *cx, HandleObject obj, HandlePropertyName name,
- HandleValue value, bool strict, jsbytecode *pc);
-bool SetElementPar(ForkJoinContext *cx, HandleObject obj, HandleValue index,
- HandleValue value, bool strict);
-bool SetDenseElementPar(ForkJoinContext *cx, HandleObject obj, int32_t index,
- HandleValue value, bool strict);
-
-// String related parallel functions. These tend to call existing VM functions
-// that take a ThreadSafeContext.
-JSString *ConcatStringsPar(ForkJoinContext *cx, HandleString left, HandleString right);
-JSFlatString *IntToStringPar(ForkJoinContext *cx, int i);
-JSString *DoubleToStringPar(ForkJoinContext *cx, double d);
-JSString *PrimitiveToStringPar(ForkJoinContext *cx, HandleValue input);
-bool StringToNumberPar(ForkJoinContext *cx, JSString *str, double *out);
-
-// Binary and unary operator functions on values. These tend to return
-// RETRY_SEQUENTIALLY if the values are objects.
-bool StrictlyEqualPar(ForkJoinContext *cx, MutableHandleValue v1, MutableHandleValue v2, bool *);
-bool StrictlyUnequalPar(ForkJoinContext *cx, MutableHandleValue v1, MutableHandleValue v2, bool *);
-bool LooselyEqualPar(ForkJoinContext *cx, MutableHandleValue v1, MutableHandleValue v2, bool *);
-bool LooselyUnequalPar(ForkJoinContext *cx, MutableHandleValue v1, MutableHandleValue v2, bool *);
-bool LessThanPar(ForkJoinContext *cx, MutableHandleValue v1, MutableHandleValue v2, bool *);
-bool LessThanOrEqualPar(ForkJoinContext *cx, MutableHandleValue v1, MutableHandleValue v2, bool *);
-bool GreaterThanPar(ForkJoinContext *cx, MutableHandleValue v1, MutableHandleValue v2, bool *);
-bool GreaterThanOrEqualPar(ForkJoinContext *cx, MutableHandleValue v1, MutableHandleValue v2, bool *);
-
-bool StringsEqualPar(ForkJoinContext *cx, HandleString v1, HandleString v2, bool *);
-bool StringsUnequalPar(ForkJoinContext *cx, HandleString v1, HandleString v2, bool *);
-
-bool BitNotPar(ForkJoinContext *cx, HandleValue in, int32_t *out);
-bool BitXorPar(ForkJoinContext *cx, HandleValue lhs, HandleValue rhs, int32_t *out);
-bool BitOrPar(ForkJoinContext *cx, HandleValue lhs, HandleValue rhs, int32_t *out);
-bool BitAndPar(ForkJoinContext *cx, HandleValue lhs, HandleValue rhs, int32_t *out);
-bool BitLshPar(ForkJoinContext *cx, HandleValue lhs, HandleValue rhs, int32_t *out);
-bool BitRshPar(ForkJoinContext *cx, HandleValue lhs, HandleValue rhs, int32_t *out);
-
-bool UrshValuesPar(ForkJoinContext *cx, HandleValue lhs, HandleValue rhs, MutableHandleValue out);
-
-// Make a new rest parameter in parallel.
-JSObject *InitRestParameterPar(ForkJoinContext *cx, uint32_t length, Value *rest,
- HandleObject templateObj, HandleArrayObject res);
-
-// Abort and debug tracing functions.
-void BailoutPar(BailoutStack *sp, uint8_t **entryFramePointer);
-bool CallToUncompiledScriptPar(ForkJoinContext *cx, JSObject *obj);
-
-} // namespace jit
-} // namespace js
-
-#endif /* jit_ParallelFunctions_h */
deleted file mode 100644
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ /dev/null
@@ -1,913 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "jit/ParallelSafetyAnalysis.h"
-
-#include "jit/Ion.h"
-#include "jit/IonAnalysis.h"
-#include "jit/JitSpewer.h"
-#include "jit/MIR.h"
-#include "jit/MIRGenerator.h"
-#include "jit/MIRGraph.h"
-
-#include "jsinferinlines.h"
-#include "jsobjinlines.h"
-
-using namespace js;
-using namespace jit;
-
-using parallel::Spew;
-using parallel::SpewMIR;
-using parallel::SpewCompile;
-
-#define SAFE_OP(op) \
- virtual void visit##op(M##op *prop) { }
-
-#define CUSTOM_OP(op) \
- virtual void visit##op(M##op *prop);
-
-#define DROP_OP(op) \
- virtual void visit##op(M##op *ins) { \
- MBasicBlock *block = ins->block(); \
- block->discard(ins); \
- }
-
-#define PERMIT(T) (1 << T)
-
-#define PERMIT_INT32 (PERMIT(MIRType_Int32))
-#define PERMIT_NUMERIC (PERMIT(MIRType_Int32) | PERMIT(MIRType_Double))
-
-#define SPECIALIZED_OP(op, flags) \
- virtual void visit##op(M##op *ins) { \
- visitSpecializedInstruction(ins, ins->specialization(), flags); \
- }
-
-#define UNSAFE_OP(op) \
- virtual void visit##op(M##op *ins) { \
- SpewMIR(ins, "Unsafe"); \
- markUnsafe(); \
- }
-
-#define WRITE_GUARDED_OP(op, obj) \
- virtual void visit##op(M##op *prop) { \
- insertWriteGuard(prop, prop->obj()); \
- }
-
-#define MAYBE_WRITE_GUARDED_OP(op, obj) \
- virtual void visit##op(M##op *prop) { \
- if (!prop->racy()) \
- insertWriteGuard(prop, prop->obj()); \
- }
-
-class ParallelSafetyVisitor : public MDefinitionVisitor
-{
- MIRGraph &graph_;
- bool unsafe_;
- MDefinition *cx_;
-
- void insertWriteGuard(MInstruction *writeInstruction, MDefinition *valueBeingWritten);
-
- void replaceWithNewPar(MInstruction *newInstruction, NativeObject *templateObject);
- void replace(MInstruction *oldInstruction, MInstruction *replacementInstruction);
-
- void visitSpecializedInstruction(MInstruction *ins, MIRType spec, uint32_t flags);
-
- // Intended for use in a visitXyz() instruction.
- void markUnsafe() {
- MOZ_ASSERT(!unsafe_);
- unsafe_ = true;
- }
-
- TempAllocator &alloc() const {
- return graph_.alloc();
- }
-
- public:
- explicit ParallelSafetyVisitor(MIRGraph &graph)
- : graph_(graph),
- unsafe_(false),
- cx_(nullptr)
- { }
-
- void clearUnsafe() { unsafe_ = false; }
- bool unsafe() { return unsafe_; }
- MDefinition *ForkJoinContext() {
- if (!cx_)
- cx_ = graph_.forkJoinContext();
- return cx_;
- }
-
- bool convertToBailout(MInstructionIterator &iter);
-
- // I am taking the policy of blacklisting everything that's not
- // obviously safe for now. We can loosen as we need.
-
- SAFE_OP(Constant)
- SAFE_OP(SimdValueX4)
- SAFE_OP(SimdSplatX4)
- SAFE_OP(SimdConstant)
- SAFE_OP(SimdConvert)
- SAFE_OP(SimdReinterpretCast)
- SAFE_OP(SimdExtractElement)
- SAFE_OP(SimdInsertElement)
- SAFE_OP(SimdSignMask)
- SAFE_OP(SimdSwizzle)
- SAFE_OP(SimdShuffle)
- SAFE_OP(SimdUnaryArith)
- SAFE_OP(SimdBinaryComp)
- SAFE_OP(SimdBinaryArith)
- SAFE_OP(SimdBinaryBitwise)
- SAFE_OP(SimdShift)
- SAFE_OP(SimdSelect)
- UNSAFE_OP(CloneLiteral)
- SAFE_OP(Parameter)
- SAFE_OP(Callee)
- SAFE_OP(IsConstructing)
- SAFE_OP(TableSwitch)
- SAFE_OP(Goto)
- SAFE_OP(Test)
- SAFE_OP(GotoWithFake)
- SAFE_OP(Compare)
- SAFE_OP(Phi)
- SAFE_OP(Beta)
- UNSAFE_OP(OsrValue)
- UNSAFE_OP(OsrScopeChain)
- UNSAFE_OP(OsrReturnValue)
- UNSAFE_OP(OsrArgumentsObject)
- UNSAFE_OP(ReturnFromCtor)
- CUSTOM_OP(CheckOverRecursed)
- UNSAFE_OP(DefVar)
- UNSAFE_OP(DefFun)
- UNSAFE_OP(CreateThis)
- CUSTOM_OP(CreateThisWithTemplate)
- UNSAFE_OP(CreateThisWithProto)
- UNSAFE_OP(CreateArgumentsObject)
- UNSAFE_OP(GetArgumentsObjectArg)
- UNSAFE_OP(SetArgumentsObjectArg)
- UNSAFE_OP(ComputeThis)
- UNSAFE_OP(LoadArrowThis)
- CUSTOM_OP(Call)
- UNSAFE_OP(ApplyArgs)
- UNSAFE_OP(ArraySplice)
- SAFE_OP(Bail)
- SAFE_OP(Unreachable)
- UNSAFE_OP(AssertFloat32)
- UNSAFE_OP(GetDynamicName)
- UNSAFE_OP(FilterArgumentsOrEval)
- UNSAFE_OP(CallDirectEval)
- SAFE_OP(BitNot)
- SAFE_OP(TypeOf)
- UNSAFE_OP(ToId)
- SAFE_OP(BitAnd)
- SAFE_OP(BitOr)
- SAFE_OP(BitXor)
- SAFE_OP(Lsh)
- SAFE_OP(Rsh)
- SAFE_OP(Ursh)
- SPECIALIZED_OP(MinMax, PERMIT_NUMERIC)
- SAFE_OP(Abs)
- SAFE_OP(Clz)
- SAFE_OP(Sqrt)
- UNSAFE_OP(Atan2)
- UNSAFE_OP(Hypot)
- CUSTOM_OP(MathFunction)
- SPECIALIZED_OP(Add, PERMIT_NUMERIC)
- SPECIALIZED_OP(Sub, PERMIT_NUMERIC)
- SPECIALIZED_OP(Mul, PERMIT_NUMERIC)
- SPECIALIZED_OP(Div, PERMIT_NUMERIC)
- SPECIALIZED_OP(Mod, PERMIT_NUMERIC)
- CUSTOM_OP(Concat)
- SAFE_OP(ConcatPar)
- UNSAFE_OP(CharCodeAt)
- UNSAFE_OP(FromCharCode)
- UNSAFE_OP(StringSplit)
- SAFE_OP(Return)
- CUSTOM_OP(Throw)
- SAFE_OP(Box) // Boxing just creates a JSVal, doesn't alloc.
- SAFE_OP(Unbox)
- SAFE_OP(GuardObject)
- SAFE_OP(ToDouble)
- SAFE_OP(ToFloat32)
- SAFE_OP(ToInt32)
- SAFE_OP(TruncateToInt32)
- SAFE_OP(MaybeToDoubleElement)
- CUSTOM_OP(ToString)
- UNSAFE_OP(ToObjectOrNull)
- CUSTOM_OP(NewArray)
- UNSAFE_OP(NewArrayCopyOnWrite)
- UNSAFE_OP(NewArrayDynamicLength)
- UNSAFE_OP(NewTypedObject)
- CUSTOM_OP(NewObject)
- CUSTOM_OP(NewCallObject)
- CUSTOM_OP(NewRunOnceCallObject)
- CUSTOM_OP(NewDerivedTypedObject)
- SAFE_OP(ObjectState)
- SAFE_OP(ArrayState)
- UNSAFE_OP(InitElem)
- UNSAFE_OP(InitElemGetterSetter)
- UNSAFE_OP(MutateProto)
- UNSAFE_OP(InitProp)
- UNSAFE_OP(InitPropGetterSetter)
- SAFE_OP(Start)
- UNSAFE_OP(OsrEntry)
- SAFE_OP(Nop)
- SAFE_OP(LimitedTruncate)
- UNSAFE_OP(RegExp)
- CUSTOM_OP(Lambda)
- UNSAFE_OP(LambdaArrow)
- SAFE_OP(Slots)
- SAFE_OP(Elements)
- SAFE_OP(ConstantElements)
- SAFE_OP(LoadSlot)
- WRITE_GUARDED_OP(StoreSlot, slots)
- SAFE_OP(FunctionEnvironment) // just a load of func env ptr
- SAFE_OP(FilterTypeSet)
- SAFE_OP(TypeBarrier) // causes a bailout if the type is not found: a-ok with us
- SAFE_OP(MonitorTypes) // causes a bailout if the type is not found: a-ok with us
- UNSAFE_OP(PostWriteBarrier)
- SAFE_OP(GetPropertyCache)
- SAFE_OP(GetPropertyPolymorphic)
- UNSAFE_OP(SetPropertyPolymorphic)
- SAFE_OP(GetElementCache)
- WRITE_GUARDED_OP(SetElementCache, object)
- UNSAFE_OP(BindNameCache)
- SAFE_OP(GuardShape)
- SAFE_OP(GuardShapePolymorphic)
- SAFE_OP(GuardObjectType)
- SAFE_OP(GuardObjectIdentity)
- SAFE_OP(GuardClass)
- SAFE_OP(AssertRange)
- SAFE_OP(ArrayLength)
- WRITE_GUARDED_OP(SetArrayLength, elements)
- SAFE_OP(TypedArrayLength)
- SAFE_OP(TypedArrayElements)
- SAFE_OP(TypedObjectDescr)
- SAFE_OP(TypedObjectElements)
- SAFE_OP(SetTypedObjectOffset)
- SAFE_OP(InitializedLength)
- WRITE_GUARDED_OP(SetInitializedLength, elements)
- SAFE_OP(Not)
- SAFE_OP(BoundsCheck)
- SAFE_OP(BoundsCheckLower)
- SAFE_OP(LoadElement)
- SAFE_OP(LoadElementHole)
- SAFE_OP(LoadUnboxedObjectOrNull)
- SAFE_OP(LoadUnboxedString)
- MAYBE_WRITE_GUARDED_OP(StoreElement, elements)
- WRITE_GUARDED_OP(StoreElementHole, elements)
- UNSAFE_OP(StoreUnboxedObjectOrNull)
- UNSAFE_OP(StoreUnboxedString)
- UNSAFE_OP(ArrayPopShift)
- UNSAFE_OP(ArrayPush)
- SAFE_OP(LoadTypedArrayElement)
- SAFE_OP(LoadTypedArrayElementHole)
- SAFE_OP(LoadTypedArrayElementStatic)
- MAYBE_WRITE_GUARDED_OP(StoreTypedArrayElement, elements)
- WRITE_GUARDED_OP(StoreTypedArrayElementHole, elements)
- UNSAFE_OP(StoreTypedArrayElementStatic)
- UNSAFE_OP(ClampToUint8)
- SAFE_OP(LoadFixedSlot)
- WRITE_GUARDED_OP(StoreFixedSlot, object)
- UNSAFE_OP(CallGetProperty)
- UNSAFE_OP(GetNameCache)
- UNSAFE_OP(CallGetIntrinsicValue)
- UNSAFE_OP(CallsiteCloneCache)
- UNSAFE_OP(CallGetElement)
- WRITE_GUARDED_OP(CallSetElement, object)
- UNSAFE_OP(CallInitElementArray)
- WRITE_GUARDED_OP(CallSetProperty, object)
- UNSAFE_OP(DeleteProperty)
- UNSAFE_OP(DeleteElement)
- WRITE_GUARDED_OP(SetPropertyCache, object)
- UNSAFE_OP(IteratorStart)
- UNSAFE_OP(IteratorMore)
- UNSAFE_OP(IsNoIter)
- UNSAFE_OP(IteratorEnd)
- SAFE_OP(StringLength)
- SAFE_OP(ArgumentsLength)
- SAFE_OP(GetFrameArgument)
- UNSAFE_OP(SetFrameArgument)
- UNSAFE_OP(RunOncePrologue)
- CUSTOM_OP(Rest)
- SAFE_OP(RestPar)
- SAFE_OP(Floor)
- SAFE_OP(Ceil)
- SAFE_OP(Round)
- UNSAFE_OP(InstanceOf)
- CUSTOM_OP(InterruptCheck)
- UNSAFE_OP(AsmJSInterruptCheck)
- SAFE_OP(ForkJoinContext)
- SAFE_OP(ForkJoinGetSlice)
- SAFE_OP(NewPar)
- SAFE_OP(NewDenseArrayPar)
- SAFE_OP(NewCallObjectPar)
- SAFE_OP(LambdaPar)
- UNSAFE_OP(ArrayConcat)
- UNSAFE_OP(ArrayJoin)
- UNSAFE_OP(GetDOMProperty)
- UNSAFE_OP(GetDOMMember)
- UNSAFE_OP(SetDOMProperty)
- UNSAFE_OP(NewStringObject)
- UNSAFE_OP(Random)
- SAFE_OP(Pow)
- SAFE_OP(PowHalf)
- UNSAFE_OP(RegExpTest)
- UNSAFE_OP(RegExpExec)
- UNSAFE_OP(RegExpReplace)
- UNSAFE_OP(StringReplace)
- UNSAFE_OP(CallInstanceOf)
- UNSAFE_OP(ProfilerStackOp)
- UNSAFE_OP(GuardString)
- UNSAFE_OP(Substr)
- UNSAFE_OP(NewDeclEnvObject)
- UNSAFE_OP(In)
- UNSAFE_OP(InArray)
- SAFE_OP(GuardThreadExclusive)
- SAFE_OP(InterruptCheckPar)
- SAFE_OP(CheckOverRecursedPar)
- SAFE_OP(FunctionDispatch)
- SAFE_OP(TypeObjectDispatch)
- SAFE_OP(IsCallable)
- SAFE_OP(IsObject)
- SAFE_OP(HasClass)
- UNSAFE_OP(EffectiveAddress)
- UNSAFE_OP(AsmJSUnsignedToDouble)
- UNSAFE_OP(AsmJSUnsignedToFloat32)
- UNSAFE_OP(AsmJSNeg)
- UNSAFE_OP(AsmJSLoadHeap)
- UNSAFE_OP(AsmJSStoreHeap)
- UNSAFE_OP(AsmJSLoadGlobalVar)
- UNSAFE_OP(AsmJSStoreGlobalVar)
- UNSAFE_OP(AsmJSLoadFuncPtr)
- UNSAFE_OP(AsmJSLoadFFIFunc)
- UNSAFE_OP(AsmJSReturn)
- UNSAFE_OP(AsmJSVoidReturn)
- UNSAFE_OP(AsmJSPassStackArg)
- UNSAFE_OP(AsmJSParameter)
- UNSAFE_OP(AsmJSCall)
- DROP_OP(RecompileCheck)
- UNSAFE_OP(CompareExchangeTypedArrayElement)
- UNSAFE_OP(AtomicTypedArrayElementBinop)
- UNSAFE_OP(MemoryBarrier)
- UNSAFE_OP(AsmJSCompareExchangeHeap)
- UNSAFE_OP(AsmJSAtomicBinopHeap)
- UNSAFE_OP(UnknownValue)
- UNSAFE_OP(LexicalCheck)
- UNSAFE_OP(ThrowUninitializedLexical)
- UNSAFE_OP(Debugger)
-
- // It looks like these could easily be made safe:
- UNSAFE_OP(ConvertElementsToDoubles)
- UNSAFE_OP(MaybeCopyElementsForWrite)
-};
-
-static void
-TransplantResumePoint(MInstruction *oldInstruction, MInstruction *replacementInstruction)
-{
- MOZ_ASSERT(!oldInstruction->isDiscarded());
- if (oldInstruction->resumePoint())
- replacementInstruction->stealResumePoint(oldInstruction);
-}
-
-bool
-ParallelSafetyAnalysis::analyze()
-{
- // Walk the basic blocks in a DFS. When we encounter a block with an
- // unsafe instruction, then we know that this block will bailout when
- // executed. Therefore, we replace the block.
- //
- // We don't need a worklist, though, because the graph is sorted
- // in RPO. Therefore, we just use the marked flags to tell us
- // when we visited some predecessor of the current block.
- ParallelSafetyVisitor visitor(graph_);
- graph_.entryBlock()->mark(); // Note: in par. exec., we never enter from OSR.
- uint32_t marked = 0;
- for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) {
- if (mir_->shouldCancel("ParallelSafetyAnalysis"))
- return false;
-
- if (block->isMarked()) {
- // Count the number of reachable blocks.
- marked++;
-
- // Iterate through and transform the instructions. Stop
- // if we encounter an inherently unsafe operation, in
- // which case we will transform this block into a bailout
- // block.
- MInstruction *ins = nullptr;
- MInstructionIterator iter(block->begin());
- while (iter != block->end() && !visitor.unsafe()) {
- if (mir_->shouldCancel("ParallelSafetyAnalysis"))
- return false;
-
- // We may be removing or replacing the current
- // instruction, so advance `iter` now. Remember the
- // last instr. we looked at for use later if it should
- // prove unsafe.
- ins = *iter++;
-
- ins->accept(&visitor);
- }
-
- if (!visitor.unsafe()) {
- // Block consists of only safe instructions. Visit its successors.
- for (uint32_t i = 0; i < block->numSuccessors(); i++)
- block->getSuccessor(i)->markUnchecked();
- } else {
- // Block contains an unsafe instruction. That means that once
- // we enter this block, we are guaranteed to bailout.
-
- // If this is the entry block, then there is no point
- // in even trying to execute this function as it will
- // always bailout.
- if (*block == graph_.entryBlock()) {
- Spew(SpewCompile, "Entry block contains unsafe MIR");
- mir_->disable();
- return false;
- }
-
- // Otherwise, create a replacement that will. We seek back one
- // position on the instruction iterator, as we will be
- // discarding all instructions starting at the unsafe
- // instruction.
- if (!visitor.convertToBailout(--iter))
- return false;
- }
- }
- }
-
- Spew(SpewCompile, "Safe");
- IonSpewPass("ParallelSafetyAnalysis");
-
- // Sweep away any unmarked blocks. Note that this doesn't preserve
- // AliasAnalysis dependencies, but we're not expected to at this point.
- if (!RemoveUnmarkedBlocks(mir_, graph_, marked))
- return false;
- IonSpewPass("UCEAfterParallelSafetyAnalysis");
- AssertExtendedGraphCoherency(graph_);
-
- return true;
-}
-
-bool
-ParallelSafetyVisitor::convertToBailout(MInstructionIterator &iter)
-{
- // We expect iter to be settled on the unsafe instruction.
- MInstruction *ins = *iter;
- MBasicBlock *block = ins->block();
- MOZ_ASSERT(unsafe()); // `block` must have contained unsafe items
- MOZ_ASSERT(block->isMarked()); // `block` must have been reachable to get here
-
- clearUnsafe();
-
- // Allocate a new bailout instruction.
- MBail *bail = MBail::New(graph_.alloc(), Bailout_ParallelUnsafe);
-
- // Discard the rest of the block and sever its link to its successors in
- // the CFG.
- for (size_t i = 0; i < block->numSuccessors(); i++)
- block->getSuccessor(i)->removePredecessor(block);
- block->discardAllInstructionsStartingAt(iter);
-
- // No more successors are reachable, so the current block can no longer be
- // the parent of an inlined function.
- if (block->outerResumePoint())
- block->clearOuterResumePoint();
-
- // End the block in a bail.
- block->add(bail);
- block->end(MUnreachable::New(alloc()));
- return true;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// Memory allocation
-//
-// Simple memory allocation opcodes---those which ultimately compile
-// down to a (possibly inlined) invocation of NewGCThing()---are
-// replaced with MNewPar, which is supplied with the thread context.
-// These allocations will take place using per-helper-thread arenas.
-
-void
-ParallelSafetyVisitor::visitCreateThisWithTemplate(MCreateThisWithTemplate *ins)
-{
- replaceWithNewPar(ins, ins->templateObject());
-}
-
-void
-ParallelSafetyVisitor::visitNewCallObject(MNewCallObject *ins)
-{
- if (ins->templateObject()->hasDynamicSlots()) {
- SpewMIR(ins, "call with dynamic slots");
- markUnsafe();
- } else {
- replace(ins, MNewCallObjectPar::New(alloc(), ForkJoinContext(), ins));
- }
-}
-
-void
-ParallelSafetyVisitor::visitNewRunOnceCallObject(MNewRunOnceCallObject *ins)
-{
- if (ins->templateObject()->hasDynamicSlots()) {
- SpewMIR(ins, "call with dynamic slots");
- markUnsafe();
- } else {
- replace(ins, MNewCallObjectPar::New(alloc(), ForkJoinContext(), ins));
- }
-}
-
-void
-ParallelSafetyVisitor::visitLambda(MLambda *ins)
-{
- if (ins->info().singletonType || ins->info().useNewTypeForClone) {
- // slow path: bail on parallel execution.
- markUnsafe();
- } else {
- // fast path: replace with LambdaPar op
- replace(ins, MLambdaPar::New(alloc(), ForkJoinContext(), ins));
- }
-}
-
-void
-ParallelSafetyVisitor::visitNewObject(MNewObject *newInstruction)
-{
- if (newInstruction->shouldUseVM()) {
- SpewMIR(newInstruction, "should use VM");
- markUnsafe();
- } else {
- replaceWithNewPar(newInstruction, newInstruction->templateObject());
- }
-}
-
-void
-ParallelSafetyVisitor::visitNewArray(MNewArray *newInstruction)
-{
- if (newInstruction->shouldUseVM()) {
- SpewMIR(newInstruction, "should use VM");
- markUnsafe();
- } else {
- replaceWithNewPar(newInstruction, newInstruction->templateObject());
- }
-}
-
-void
-ParallelSafetyVisitor::visitNewDerivedTypedObject(MNewDerivedTypedObject *ins)
-{
- // FIXME(Bug 984090) -- There should really be a parallel-safe
- // version of NewDerivedTypedObject. However, until that is
- // implemented, let's just ignore those with 0 uses, since they
- // will be stripped out by DCE later.
- if (!ins->hasUses())
- return;
-
- SpewMIR(ins, "visitNewDerivedTypedObject");
- markUnsafe();
-}
-
-void
-ParallelSafetyVisitor::visitRest(MRest *ins)
-{
- replace(ins, MRestPar::New(alloc(), ForkJoinContext(), ins));
-}
-
-void
-ParallelSafetyVisitor::visitMathFunction(MMathFunction *ins)
-{
- replace(ins, MMathFunction::New(alloc(), ins->input(), ins->function(), nullptr));
-}
-
-void
-ParallelSafetyVisitor::visitConcat(MConcat *ins)
-{
- replace(ins, MConcatPar::New(alloc(), ForkJoinContext(), ins));
-}
-
-void
-ParallelSafetyVisitor::visitToString(MToString *ins)
-{
- MIRType inputType = ins->input()->type();
- if (inputType != MIRType_Int32 && inputType != MIRType_Double)
- markUnsafe();
-}
-
-void
-ParallelSafetyVisitor::replaceWithNewPar(MInstruction *newInstruction,
- NativeObject *templateObject)
-{
- replace(newInstruction, MNewPar::New(alloc(), ForkJoinContext(), templateObject));
-}
-
-void
-ParallelSafetyVisitor::replace(MInstruction *oldInstruction,
- MInstruction *replacementInstruction)
-{
- TransplantResumePoint(oldInstruction, replacementInstruction);
-
- MBasicBlock *block = oldInstruction->block();
- block->insertBefore(oldInstruction, replacementInstruction);
- oldInstruction->replaceAllUsesWith(replacementInstruction);
- block->discard(oldInstruction);
-
- // We may have replaced a specialized Float32 instruction by its
- // non-specialized version, so just retry to specialize it. This relies on
- // the fact that Phis' types don't change during the ParallelSafetyAnalysis;
- // otherwise we'd have to run the entire TypeAnalyzer Float32 analysis once
- // instructions have been replaced.
- if (replacementInstruction->isFloat32Commutative() &&
- replacementInstruction->type() != MIRType_Float32)
- {
- replacementInstruction->trySpecializeFloat32(alloc());
- }
- MOZ_ASSERT(oldInstruction->type() == replacementInstruction->type());
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// Write Guards
-//
-// We only want to permit writes to locally guarded objects.
-// Furthermore, we want to avoid PICs and other non-thread-safe things
-// (though perhaps we should support PICs at some point). If we
-// cannot determine the origin of an object, we can insert a write
-// guard which will check whether the object was allocated from the
-// per-thread-arena or not.
-
-void
-ParallelSafetyVisitor::insertWriteGuard(MInstruction *writeInstruction,
- MDefinition *valueBeingWritten)
-{
- // Many of the write operations do not take the JS object
- // but rather something derived from it, such as the elements.
- // So we need to identify the JS object:
- MDefinition *object;
- switch (valueBeingWritten->type()) {
- case MIRType_Object:
- object = valueBeingWritten;
- break;
-
- case MIRType_Slots:
- switch (valueBeingWritten->op()) {
- case MDefinition::Op_Slots:
- object = valueBeingWritten->toSlots()->object();
- break;
-
- default:
- SpewMIR(writeInstruction, "cannot insert write guard for %s",
- valueBeingWritten->opName());
- markUnsafe();
- return;
- }
- break;
-
- case MIRType_Elements:
- switch (valueBeingWritten->op()) {
- case MDefinition::Op_Elements:
- object = valueBeingWritten->toElements()->object();
- break;
-
- case MDefinition::Op_TypedArrayElements:
- object = valueBeingWritten->toTypedArrayElements()->object();
- break;
-
- case MDefinition::Op_TypedObjectElements:
- object = valueBeingWritten->toTypedObjectElements()->object();
- break;
-
- default:
- SpewMIR(writeInstruction, "cannot insert write guard for %s",
- valueBeingWritten->opName());
- markUnsafe();
- return;
- }
- break;
-
- default:
- SpewMIR(writeInstruction, "cannot insert write guard for MIR Type %d",
- valueBeingWritten->type());
- markUnsafe();
- return;
- }
-
- if (object->isUnbox())
- object = object->toUnbox()->input();
-
- switch (object->op()) {
- case MDefinition::Op_NewPar:
- // MNewPar will always be creating something thread-local, omit the guard
- SpewMIR(writeInstruction, "write to NewPar prop does not require guard");
- return;
- default:
- break;
- }
-
- MBasicBlock *block = writeInstruction->block();
- MGuardThreadExclusive *writeGuard =
- MGuardThreadExclusive::New(alloc(), ForkJoinContext(), object);
- block->insertBefore(writeInstruction, writeGuard);
- writeGuard->typePolicy()->adjustInputs(alloc(), writeGuard);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// Calls
-//
-// We only support calls to interpreted functions that that have already been
-// Ion compiled. If a function has no IonScript, we bail out.
-
-void
-ParallelSafetyVisitor::visitCall(MCall *ins)
-{
- // DOM? Scary.
- if (ins->isCallDOMNative()) {
- SpewMIR(ins, "call to dom function");
- markUnsafe();
- return;
- }
-
- JSFunction *target = ins->getSingleTarget();
- if (target) {
- // Non-parallel native? Scary
- if (target->isNative() && !target->hasParallelNative()) {
- SpewMIR(ins, "call to non-parallel native function");
- markUnsafe();
- }
- return;
- }
-
- if (ins->isConstructing()) {
- SpewMIR(ins, "call to unknown constructor");
- markUnsafe();
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// Stack limit, interrupts
-//
-// In sequential Ion code, the stack limit is stored in the JSRuntime.
-// We store it in the thread context. We therefore need a separate
-// instruction to access it, one parameterized by the thread context.
-// Similar considerations apply to checking for interrupts.
-
-void
-ParallelSafetyVisitor::visitCheckOverRecursed(MCheckOverRecursed *ins)
-{
- replace(ins, MCheckOverRecursedPar::New(alloc(), ForkJoinContext()));
-}
-
-void
-ParallelSafetyVisitor::visitInterruptCheck(MInterruptCheck *ins)
-{
- replace(ins, MInterruptCheckPar::New(alloc(), ForkJoinContext()));
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// Specialized ops
-//
-// Some ops, like +, can be specialized to ints/doubles. Anything
-// else is terrifying.
-//
-// TODO---Eventually, we should probably permit arbitrary + but bail
-// if the operands are not both integers/floats.
-
-void
-ParallelSafetyVisitor::visitSpecializedInstruction(MInstruction *ins, MIRType spec,
- uint32_t flags)
-{
- uint32_t flag = 1 << spec;
- if (flags & flag)
- return;
-
- SpewMIR(ins, "specialized to unacceptable type %d", spec);
- markUnsafe();
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// Throw
-
-void
-ParallelSafetyVisitor::visitThrow(MThrow *thr)
-{
- MBasicBlock *block = thr->block();
- MOZ_ASSERT(block->lastIns() == thr);
- MBail *bail = MBail::New(alloc(), Bailout_ParallelUnsafe);
- block->discardLastIns();
- block->add(bail);
- block->end(MUnreachable::New(alloc()));
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Callee extraction
-//
-// See comments in header file.
-
-static bool
-GetPossibleCallees(JSContext *cx, HandleScript script, jsbytecode *pc,
- types::TemporaryTypeSet *calleeTypes, CallTargetVector &targets);
-
-static bool
-AddCallTarget(HandleScript script, CallTargetVector &targets);
-
-bool
-jit::AddPossibleCallees(JSContext *cx, MIRGraph &graph, CallTargetVector &targets)
-{
- for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
- for (MInstructionIterator ins(block->begin()); ins != block->end(); ins++)
- {
- if (!ins->isCall())
- continue;
-
- MCall *callIns = ins->toCall();
-
- RootedFunction target(cx, callIns->getSingleTarget());
- if (target) {
- MOZ_ASSERT_IF(!target->isInterpreted(), target->hasParallelNative());
-
- if (target->isInterpreted()) {
- RootedScript script(cx, target->getOrCreateScript(cx));
- if (!script || !AddCallTarget(script, targets))
- return false;
- }
-
- continue;
- }
-
- types::TemporaryTypeSet *calleeTypes = callIns->getFunction()->resultTypeSet();
- RootedScript script(cx, callIns->block()->info().script());
- if (!GetPossibleCallees(cx,
- script,
- callIns->resumePoint()->pc(),
- calleeTypes,
- targets))
- return false;
- }
- }
-
- return true;
-}
-
-static bool
-GetPossibleCallees(JSContext *cx,
- HandleScript script,
- jsbytecode *pc,
- types::TemporaryTypeSet *calleeTypes,
- CallTargetVector &targets)
-{
- if (!calleeTypes || calleeTypes->baseFlags() != 0)
- return true;
-
- unsigned objCount = calleeTypes->getObjectCount();
-
- if (objCount == 0)
- return true;
-
- RootedFunction rootedFun(cx);
- RootedScript rootedScript(cx);
- for (unsigned i = 0; i < objCount; i++) {
- JSObject *obj = calleeTypes->getSingleObject(i);
- if (obj && obj->is<JSFunction>()) {
- rootedFun = &obj->as<JSFunction>();
- } else {
- types::TypeObject *typeObj = calleeTypes->getTypeObject(i);
- if (!typeObj)
- continue;
- rootedFun = typeObj->interpretedFunction;
- if (!rootedFun)
- continue;
- }
-
- if (!rootedFun->isInterpreted())
- continue;
-
- rootedScript = rootedFun->getOrCreateScript(cx);
- if (!rootedScript)
- return false;
-
- if (rootedScript->shouldCloneAtCallsite()) {
- rootedFun = CloneFunctionAtCallsite(cx, rootedFun, script, pc);
- if (!rootedFun)
- return false;
- rootedScript = rootedFun->nonLazyScript();
- }
-
- // check if this call target is already known
- if (!AddCallTarget(rootedScript, targets))
- return false;
- }
-
- return true;
-}
-
-static bool
-AddCallTarget(HandleScript script, CallTargetVector &targets)
-{
- for (size_t i = 0; i < targets.length(); i++) {
- if (targets[i] == script)
- return true;
- }
-
- if (!targets.append(script))
- return false;
-
- return true;
-}
deleted file mode 100644
--- a/js/src/jit/ParallelSafetyAnalysis.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef jit_ParallelSafetyAnalysis_h
-#define jit_ParallelSafetyAnalysis_h
-
-#include "jit/MIR.h"
-
-namespace js {
-
-class InterpreterFrame;
-
-namespace jit {
-
-class MIRGraph;
-class AutoDestroyAllocator;
-
-// Determines whether a function is compatible for parallel execution.
-// Removes basic blocks containing unsafe MIR operations from the
-// graph and replaces them with MBail blocks.
-class ParallelSafetyAnalysis
-{
- MIRGenerator *mir_;
- MIRGraph &graph_;
-
- public:
- ParallelSafetyAnalysis(MIRGenerator *mir,
- MIRGraph &graph)
- : mir_(mir),
- graph_(graph)
- {}
-
- bool analyze();
-};
-
-// Code to collect list of possible call targets by scraping through
-// TI and baseline data. Used to permit speculative transitive
-// compilation in vm/ForkJoin.
-//
-// This code may clone scripts and thus may invoke the GC. Hence only
-// run from the link phase, which executes on the main thread.
-typedef Vector<JSScript *, 4, JitAllocPolicy> CallTargetVector;
-bool AddPossibleCallees(JSContext *cx, MIRGraph &graph, CallTargetVector &targets);
-
-} // namespace jit
-} // namespace js
-
-#endif /* jit_ParallelSafetyAnalysis_h */
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -10,17 +10,16 @@
#include "jspubtd.h"
#include "jit/CompileInfo.h"
#include "jit/JitFrames.h"
namespace js {
class DeclEnvObject;
-class ForkJoinContext;
class StaticWithObject;
class InlineTypedObject;
namespace jit {
enum DataType {
Type_Void,
Type_Bool,
@@ -463,19 +462,16 @@ template <> struct OutParamToRootType<Mu
template <class> struct MatchContext { };
template <> struct MatchContext<JSContext *> {
static const ExecutionMode execMode = SequentialExecution;
};
template <> struct MatchContext<ExclusiveContext *> {
static const ExecutionMode execMode = SequentialExecution;
};
-template <> struct MatchContext<ForkJoinContext *> {
- static const ExecutionMode execMode = ParallelExecution;
-};
template <> struct MatchContext<ThreadSafeContext *> {
// ThreadSafeContext functions can be called from either mode, but for
// calling from parallel they should be wrapped first, so we default to
// SequentialExecution here.
static const ExecutionMode execMode = SequentialExecution;
};
#define FOR_EACH_ARGS_1(Macro, Sep, Last) Macro(1) Last(1)
--- a/js/src/jit/arm/Bailouts-arm.cpp
+++ b/js/src/jit/arm/Bailouts-arm.cpp
@@ -74,20 +74,17 @@ BailoutFrameInfo::BailoutFrameInfo(const
: machine_(bailout->machine())
{
uint8_t *sp = bailout->parentStackPointer();
framePointer_ = sp + bailout->frameSize();
topFrameSize_ = framePointer_ - sp;
JSScript *script = ScriptFromCalleeToken(((JitFrameLayout *) framePointer_)->calleeToken());
JitActivation *activation = activations.activation()->asJit();
- if (activation->cx()->isForkJoinContext())
- topIonScript_ = script->parallelIonScript();
- else
- topIonScript_ = script->ionScript();
+ topIonScript_ = script->ionScript();
attachOnJitActivation(activations);
if (bailout->frameClass() == FrameSizeClass::None()) {
snapshotOffset_ = bailout->snapshotOffset();
return;
}
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -55,20 +55,18 @@ CodeGeneratorARM::generatePrologue()
bool
CodeGeneratorARM::generateEpilogue()
{
MOZ_ASSERT(!gen->compilingAsmJS());
masm.bind(&returnLabel_);
#ifdef JS_TRACE_LOGGING
- if (gen->info().executionMode() == SequentialExecution) {
- emitTracelogStopEvent(TraceLogger_IonMonkey);
- emitTracelogScriptStop();
- }
+ emitTracelogStopEvent(TraceLogger_IonMonkey);
+ emitTracelogScriptStop();
#endif
masm.freeStack(frameSize());
MOZ_ASSERT(masm.framePushed() == 0);
masm.pop(pc);
masm.flushBuffer();
return true;
}
@@ -145,17 +143,17 @@ CodeGeneratorARM::generateOutOfLineCode(
if (deoptLabel_.used()) {
// All non-table-based bailouts will go here.
masm.bind(&deoptLabel_);
// Push the frame size, so the handler can recover the IonScript.
masm.ma_mov(Imm32(frameSize()), lr);
- JitCode *handler = gen->jitRuntime()->getGenericBailoutHandler(gen->info().executionMode());
+ JitCode *handler = gen->jitRuntime()->getGenericBailoutHandler();
masm.branch(handler);
}
return true;
}
void
CodeGeneratorARM::bailoutIf(Assembler::Condition condition, LSnapshot *snapshot)
@@ -2181,28 +2179,16 @@ CodeGeneratorARM::visitNegD(LNegD *ins)
void
CodeGeneratorARM::visitNegF(LNegF *ins)
{
FloatRegister input = ToFloatRegister(ins->input());
masm.ma_vneg_f32(input, ToFloatRegister(ins->output()));
}
void
-CodeGeneratorARM::visitForkJoinGetSlice(LForkJoinGetSlice *ins)
-{
- MOZ_CRASH("NYI");
-}
-
-JitCode *
-JitRuntime::generateForkJoinGetSliceStub(JSContext *cx)
-{
- MOZ_CRASH("NYI");
-}
-
-void
CodeGeneratorARM::memoryBarrier(MemoryBarrierBits barrier)
{
// On ARMv6 the optional argument (BarrierST, etc) is ignored.
if (barrier == (MembarStoreStore|MembarSynchronizing))
masm.ma_dsb(masm.BarrierST);
else if (barrier & MembarSynchronizing)
masm.ma_dsb();
else if (barrier == MembarStoreStore)
--- a/js/src/jit/arm/CodeGenerator-arm.h
+++ b/js/src/jit/arm/CodeGenerator-arm.h
@@ -209,18 +209,16 @@ class CodeGeneratorARM : public CodeGene
void visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap *ins);
void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap *ins);
void visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins);
void visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins);
void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr *ins);
void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc *ins);
void visitAsmJSPassStackArg(LAsmJSPassStackArg *ins);
- void visitForkJoinGetSlice(LForkJoinGetSlice *ins);
-
void visitMemoryBarrier(LMemoryBarrier *ins);
void generateInvalidateEpilogue();
protected:
void visitEffectiveAddress(LEffectiveAddress *ins);
void visitUDiv(LUDiv *ins);
void visitUMod(LUMod *ins);
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -546,22 +546,16 @@ LIRGeneratorARM::lowerTruncateFToInt32(M
void
LIRGeneratorARM::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins)
{
MOZ_CRASH("NYI");
}
void
-LIRGeneratorARM::visitForkJoinGetSlice(MForkJoinGetSlice *ins)
-{
- MOZ_CRASH("NYI");
-}
-
-void
LIRGeneratorARM::visitSimdBinaryArith(MSimdBinaryArith *ins)
{
MOZ_CRASH("NYI");
}
void
LIRGeneratorARM::visitSimdSelect(MSimdSelect *ins)
{
--- a/js/src/jit/arm/Lowering-arm.h
+++ b/js/src/jit/arm/Lowering-arm.h
@@ -33,22 +33,16 @@ class LIRGeneratorARM : public LIRGenera
LDefinition tempByteOpRegister();
inline LDefinition tempToUnbox() {
return LDefinition::BogusTemp();
}
bool needTempForPostBarrier() { return false; }
- // x64 has a scratch register, so no need for another temp for dispatch
- // ICs.
- LDefinition tempForDispatchCache(MIRType outputType = MIRType_None) {
- return LDefinition::BogusTemp();
- }
-
void lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock *block, size_t lirIndex);
void defineUntypedPhi(MPhi *phi, size_t lirIndex);
void lowerForShift(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir, MDefinition *lhs,
MDefinition *rhs);
void lowerUrshD(MUrsh *mir);
void lowerForALU(LInstructionHelper<1, 1, 0> *ins, MDefinition *mir,
MDefinition *input);
@@ -101,17 +95,16 @@ class LIRGeneratorARM : public LIRGenera
void visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins);
void visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins);
void visitAsmJSLoadHeap(MAsmJSLoadHeap *ins);
void visitAsmJSStoreHeap(MAsmJSStoreHeap *ins);
void visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins);
void visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap *ins);
void visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap *ins);
void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins);
- void visitForkJoinGetSlice(MForkJoinGetSlice *ins);
void visitSimdBinaryArith(MSimdBinaryArith *ins);
void visitSimdSelect(MSimdSelect *ins);
void visitSimdSplatX4(MSimdSplatX4 *ins);
void visitSimdValueX4(MSimdValueX4 *ins);
void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins);
void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins);
void visitSubstr(MSubstr *ins);
};
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -10,21 +10,18 @@
#include "jit/Bailouts.h"
#include "jit/JitCompartment.h"
#include "jit/JitFrames.h"
#include "jit/JitSpewer.h"
#include "jit/Linker.h"
#ifdef JS_ION_PERF
# include "jit/PerfSpewer.h"
#endif
-#include "jit/ParallelFunctions.h"
#include "jit/VMFunctions.h"
-#include "jit/ExecutionMode-inl.h"
-
using namespace js;
using namespace js::jit;
static const FloatRegisterSet NonVolatileFloatRegs =
FloatRegisterSet((1ULL << FloatRegisters::d8) |
(1ULL << FloatRegisters::d9) |
(1ULL << FloatRegisters::d10) |
(1ULL << FloatRegisters::d11) |
@@ -411,17 +408,17 @@ JitRuntime::generateInvalidator(JSContex
#ifdef JS_ION_PERF
writePerfSpewerJitCodeProfile(code, "Invalidator");
#endif
return code;
}
JitCode *
-JitRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void **returnAddrOut)
+JitRuntime::generateArgumentsRectifier(JSContext *cx, void **returnAddrOut)
{
MacroAssembler masm(cx);
masm.pushReturnAddress();
// ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
// Including |this|, there are (|nargs| + 1) arguments to copy.
MOZ_ASSERT(ArgumentsRectifierReg == r8);
@@ -477,17 +474,17 @@ JitRuntime::generateArgumentsRectifier(J
masm.ma_push(r0); // actual arguments.
masm.ma_push(r1); // callee token
masm.ma_push(r6); // frame descriptor.
// Call the target function.
// Note that this code assumes the function is JITted.
masm.andPtr(Imm32(CalleeTokenMask), r1);
masm.ma_ldr(DTRAddr(r1, DtrOffImm(JSFunction::offsetOfNativeOrScript())), r3);
- masm.loadBaselineOrIonRaw(r3, r3, mode, nullptr);
+ masm.loadBaselineOrIonRaw(r3, r3, nullptr);
masm.ma_callJitHalfPush(r3);
uint32_t returnOffset = masm.currentOffset();
// arg1
// ...
// argN
// num actual args
@@ -637,43 +634,16 @@ GenerateBailoutThunk(JSContext *cx, Macr
, sp);
}
// Jump to shared bailout tail. The BailoutInfo pointer has to be in r2.
JitCode *bailoutTail = cx->runtime()->jitRuntime()->getBailoutTail();
masm.branch(bailoutTail);
}
-static void
-GenerateParallelBailoutThunk(MacroAssembler &masm, uint32_t frameClass)
-{
- // As GenerateBailoutThunk, except we return an error immediately. We do the
- // bailout dance so that we can walk the stack and have accurate reporting
- // of frame information.
-
- PushBailoutFrame(masm, frameClass, r0);
-
- // Parallel bailout is like parallel failure in that we unwind all the way
- // to the entry frame. Reserve space for the frame pointer of the entry
- // frame.
- const int sizeOfEntryFramePointer = sizeof(uint8_t *) * 2;
- masm.reserveStack(sizeOfEntryFramePointer);
- masm.mov(sp, r1);
-
- masm.setupAlignedABICall(2);
- masm.passABIArg(r0);
- masm.passABIArg(r1);
- masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, BailoutPar));
-
- // Get the frame pointer of the entry frame and return.
- masm.moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
- masm.ma_ldr(Address(sp, 0), sp);
- masm.as_dtr(IsLoad, 32, PostIndex, pc, DTRAddr(sp, DtrOffImm(4)));
-}
-
JitCode *
JitRuntime::generateBailoutTable(JSContext *cx, uint32_t frameClass)
{
MacroAssembler masm(cx);
{
// Emit the table without any pools being inserted.
Label bailout;
@@ -692,30 +662,20 @@ JitRuntime::generateBailoutTable(JSConte
#ifdef JS_ION_PERF
writePerfSpewerJitCodeProfile(code, "BailoutTable");
#endif
return code;
}
JitCode *
-JitRuntime::generateBailoutHandler(JSContext *cx, ExecutionMode mode)
+JitRuntime::generateBailoutHandler(JSContext *cx)
{
MacroAssembler masm(cx);
-
- switch (mode) {
- case SequentialExecution:
- GenerateBailoutThunk(cx, masm, NO_FRAME_SIZE_CLASS_ID);
- break;
- case ParallelExecution:
- GenerateParallelBailoutThunk(masm, NO_FRAME_SIZE_CLASS_ID);
- break;
- default:
- MOZ_CRASH("No such execution mode");
- }
+ GenerateBailoutThunk(cx, masm, NO_FRAME_SIZE_CLASS_ID);
Linker linker(masm);
AutoFlushICache afc("BailoutHandler");
JitCode *code = linker.newCode<NoGC>(cx, OTHER_CODE);
#ifdef JS_ION_PERF
writePerfSpewerJitCodeProfile(code, "BailoutHandler");
#endif
@@ -748,17 +708,18 @@ JitRuntime::generateVMWrapper(JSContext
// +8 [args] + argPadding
// +0 ExitFrame
//
// We're aligned to an exit frame, so link it up.
// If it isn't a tail call, then the return address needs to be saved
if (f.expectTailCall == NonTailCall)
masm.pushReturnAddress();
- masm.enterExitFrameAndLoadContext(&f, cxreg, regs.getAny(), f.executionMode);
+ masm.enterExitFrame(&f);
+ masm.loadJSContext(cxreg);
// Save the base of the argument set stored on the stack.
Register argsBase = InvalidReg;
if (f.explicitArgs) {
argsBase = r5;
regs.take(argsBase);
masm.ma_add(sp, Imm32(ExitFrameLayout::SizeWithFooter()), argsBase);
}
@@ -836,20 +797,20 @@ JitRuntime::generateVMWrapper(JSContext
if (outReg != InvalidReg)
masm.passABIArg(outReg);
masm.callWithABI(f.wrapped);
// Test for failure.
switch (f.failType()) {
case Type_Object:
- masm.branchTestPtr(Assembler::Zero, r0, r0, masm.failureLabel(f.executionMode));
+ masm.branchTestPtr(Assembler::Zero, r0, r0, masm.failureLabel());
break;
case Type_Bool:
- masm.branchIfFalseBool(r0, masm.failureLabel(f.executionMode));
+ masm.branchIfFalseBool(r0, masm.failureLabel());
break;
default:
MOZ_CRASH("unknown failure kind");
}
// Load the outparam and free any allocated stack.
switch (f.outParam) {
case Type_Handle:
--- a/js/src/jit/mips/Bailouts-mips.cpp
+++ b/js/src/jit/mips/Bailouts-mips.cpp
@@ -17,20 +17,17 @@ BailoutFrameInfo::BailoutFrameInfo(const
: machine_(bailout->machine())
{
uint8_t *sp = bailout->parentStackPointer();
framePointer_ = sp + bailout->frameSize();
topFrameSize_ = framePointer_ - sp;
JSScript *script = ScriptFromCalleeToken(((JitFrameLayout *) framePointer_)->calleeToken());
JitActivation *activation = activations.activation()->asJit();
- if (activation->cx()->isForkJoinContext())
- topIonScript_ = script->parallelIonScript();
- else
- topIonScript_ = script->ionScript();
+ topIonScript_ = script->ionScript();
attachOnJitActivation(activations);
if (bailout->frameClass() == FrameSizeClass::None()) {
snapshotOffset_ = bailout->snapshotOffset();
return;
}
--- a/js/src/jit/mips/CodeGenerator-mips.cpp
+++ b/js/src/jit/mips/CodeGenerator-mips.cpp
@@ -163,17 +163,17 @@ CodeGeneratorMIPS::generateOutOfLineCode
masm.bind(&deoptLabel_);
// Push the frame size, so the handler can recover the IonScript.
// Frame size is stored in 'ra' and pushed by GenerateBailoutThunk
// We have to use 'ra' because generateBailoutTable will implicitly do
// the same.
masm.move32(Imm32(frameSize()), ra);
- JitCode *handler = gen->jitRuntime()->getGenericBailoutHandler(gen->info().executionMode());
+ JitCode *handler = gen->jitRuntime()->getGenericBailoutHandler();
masm.branch(handler);
}
return true;
}
void
@@ -2146,20 +2146,8 @@ CodeGeneratorMIPS::visitNegD(LNegD *ins)
void
CodeGeneratorMIPS::visitNegF(LNegF *ins)
{
FloatRegister input = ToFloatRegister(ins->input());
FloatRegister output = ToFloatRegister(ins->output());
masm.as_negs(output, input);
}
-
-void
-CodeGeneratorMIPS::visitForkJoinGetSlice(LForkJoinGetSlice *ins)
-{
- MOZ_CRASH("NYI");
-}
-
-JitCode *
-JitRuntime::generateForkJoinGetSliceStub(JSContext *cx)
-{
- MOZ_CRASH("NYI");
-}
--- a/js/src/jit/mips/CodeGenerator-mips.h
+++ b/js/src/jit/mips/CodeGenerator-mips.h
@@ -259,18 +259,16 @@ class CodeGeneratorMIPS : public CodeGen
void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap *ins);
void visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins);
void visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins);
void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr *ins);
void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc *ins);
void visitAsmJSPassStackArg(LAsmJSPassStackArg *ins);
- void visitForkJoinGetSlice(LForkJoinGetSlice *ins);
-
void generateInvalidateEpilogue();
protected:
void visitEffectiveAddress(LEffectiveAddress *ins);
void visitUDiv(LUDiv *ins);
void visitUMod(LUMod *ins);
public:
--- a/js/src/jit/mips/Lowering-mips.cpp
+++ b/js/src/jit/mips/Lowering-mips.cpp
@@ -536,22 +536,16 @@ LIRGeneratorMIPS::visitSubstr(MSubstr *i
void
LIRGeneratorMIPS::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins)
{
MOZ_CRASH("NYI");
}
void
-LIRGeneratorMIPS::visitForkJoinGetSlice(MForkJoinGetSlice *ins)
-{
- MOZ_CRASH("NYI");
-}
-
-void
LIRGeneratorMIPS::visitSimdBinaryArith(MSimdBinaryArith *ins)
{
MOZ_CRASH("NYI");
}
void
LIRGeneratorMIPS::visitSimdSelect(MSimdSelect *ins)
{
--- a/js/src/jit/mips/Lowering-mips.h
+++ b/js/src/jit/mips/Lowering-mips.h
@@ -33,22 +33,16 @@ class LIRGeneratorMIPS : public LIRGener
LDefinition tempByteOpRegister();
inline LDefinition tempToUnbox() {
return LDefinition::BogusTemp();
}
bool needTempForPostBarrier() { return false; }
- // MIPS has a scratch register, so no need for another temp for dispatch
- // ICs.
- LDefinition tempForDispatchCache(MIRType outputType = MIRType_None) {
- return LDefinition::BogusTemp();
- }
-
void lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock *block, size_t lirIndex);
void defineUntypedPhi(MPhi *phi, size_t lirIndex);
void lowerForShift(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir, MDefinition *lhs,
MDefinition *rhs);
void lowerUrshD(MUrsh *mir);
void lowerForALU(LInstructionHelper<1, 1, 0> *ins, MDefinition *mir,
MDefinition *input);
@@ -101,17 +95,16 @@ class LIRGeneratorMIPS : public LIRGener
void visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins);
void visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins);
void visitAsmJSLoadHeap(MAsmJSLoadHeap *ins);
void visitAsmJSStoreHeap(MAsmJSStoreHeap *ins);
void visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap *ins);
void visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap *ins);
void visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins);
void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins);
- void visitForkJoinGetSlice(MForkJoinGetSlice *ins);
void visitSimdBinaryArith(MSimdBinaryArith *ins);
void visitSimdSelect(MSimdSelect *ins);
void visitSimdSplatX4(MSimdSplatX4 *ins);
void visitSimdValueX4(MSimdValueX4 *ins);
void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins);
void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins);
void visitSubstr(MSubstr *ins);
};
--- a/js/src/jit/mips/Trampoline-mips.cpp
+++ b/js/src/jit/mips/Trampoline-mips.cpp
@@ -11,21 +11,18 @@
#include "jit/JitFrames.h"
#include "jit/JitSpewer.h"
#include "jit/Linker.h"
#include "jit/mips/Bailouts-mips.h"
#include "jit/mips/BaselineHelpers-mips.h"
#ifdef JS_ION_PERF
# include "jit/PerfSpewer.h"
#endif
-#include "jit/ParallelFunctions.h"
#include "jit/VMFunctions.h"
-#include "jit/ExecutionMode-inl.h"
-
using namespace js;
using namespace js::jit;
static_assert(sizeof(uintptr_t) == sizeof(uint32_t), "Not 64-bit clean.");
struct EnterJITRegs
{
double f30;
@@ -381,17 +378,17 @@ JitRuntime::generateInvalidator(JSContex
#ifdef JS_ION_PERF
writePerfSpewerJitCodeProfile(code, "Invalidator");
#endif
return code;
}
JitCode *
-JitRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void **returnAddrOut)
+JitRuntime::generateArgumentsRectifier(JSContext *cx, void **returnAddrOut)
{
MacroAssembler masm(cx);
// ArgumentsRectifierReg contains the |nargs| pushed onto the current
// frame. Including |this|, there are (|nargs| + 1) arguments to copy.
MOZ_ASSERT(ArgumentsRectifierReg == s3);
Register numActArgsReg = t6;
@@ -470,17 +467,17 @@ JitRuntime::generateArgumentsRectifier(J
masm.storePtr(calleeTokenReg, Address(StackPointer, sizeof(uintptr_t)));
// Push frame descriptor.
masm.storePtr(t0, Address(StackPointer, 0));
// Call the target function.
// Note that this code assumes the function is JITted.
masm.andPtr(Imm32(CalleeTokenMask), calleeTokenReg);
masm.loadPtr(Address(calleeTokenReg, JSFunction::offsetOfNativeOrScript()), t1);
- masm.loadBaselineOrIonRaw(t1, t1, mode, nullptr);
+ masm.loadBaselineOrIonRaw(t1, t1, nullptr);
masm.ma_callJitHalfPush(t1);
uint32_t returnOffset = masm.currentOffset();
// arg1
// ...
// argN
// num actual args
@@ -613,42 +610,16 @@ GenerateBailoutThunk(JSContext *cx, Macr
masm.addPtr(Imm32(bailoutDataSize + bailoutInfoOutParamSize + frameSize), StackPointer);
}
// Jump to shared bailout tail. The BailoutInfo pointer has to be in a2.
JitCode *bailoutTail = cx->runtime()->jitRuntime()->getBailoutTail();
masm.branch(bailoutTail);
}
-static void
-GenerateParallelBailoutThunk(MacroAssembler &masm, uint32_t frameClass)
-{
- // As GenerateBailoutThunk, except we return an error immediately. We do
- // the bailout dance so that we can walk the stack and have accurate
- // reporting of frame information.
-
- PushBailoutFrame(masm, frameClass, a0);
-
- // Parallel bailout is like parallel failure in that we unwind all the way
- // to the entry frame. Reserve space for the frame pointer of the entry frame.
- const int sizeOfEntryFramePointer = sizeof(uint8_t *) * 2;
- masm.reserveStack(sizeOfEntryFramePointer);
- masm.movePtr(sp, a1);
-
- masm.setupAlignedABICall(2);
- masm.passABIArg(a0);
- masm.passABIArg(a1);
- masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, BailoutPar));
-
- // Get the frame pointer of the entry frame and return.
- masm.moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
- masm.loadPtr(Address(sp, 0), sp);
- masm.ret();