author | Shu-yu Guo <shu@rfrn.org> |
Wed, 07 Jan 2015 01:18:42 -0800 | |
changeset 222596 | 7584b643e7e9e44c450c186e2631bed91fea5850 |
parent 222595 | eab4b3520c509ec440cc648d795964b06b353d01 |
child 222597 | 2ba42b1966bc18e2911ef1552acf859dfecf8579 |
push id | 28068 |
push user | cbook@mozilla.com |
push date | Thu, 08 Jan 2015 13:16:34 +0000 |
treeherder | mozilla-central@2880e05d5e32 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | lth |
bugs | 1118038 |
milestone | 37.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- 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)