diff --git a/js/src/jit/BacktrackingAllocator.cpp b/js/src/jit/BacktrackingAllocator.cpp index 04078cb20c..a7889c9dd1 100644 --- a/js/src/jit/BacktrackingAllocator.cpp +++ b/js/src/jit/BacktrackingAllocator.cpp @@ -588,18 +588,11 @@ BacktrackingAllocator::buildLivenessInfo() if (!callRanges.insert(callRange)) return false; } - DebugOnly hasDoubleDef = false; - DebugOnly hasFloat32Def = false; for (size_t i = 0; i < ins->numDefs(); i++) { LDefinition* def = ins->getDef(i); if (def->isBogusTemp()) continue; -#ifdef DEBUG - if (def->type() == LDefinition::DOUBLE) - hasDoubleDef = true; - if (def->type() == LDefinition::FLOAT32) - hasFloat32Def = true; -#endif + CodePosition from = outputOf(*ins); if (def->policy() == LDefinition::MUST_REUSE_INPUT) { @@ -644,8 +637,7 @@ BacktrackingAllocator::buildLivenessInfo() } } - CodePosition to = - ins->isCall() ? outputOf(*ins) : outputOf(*ins).next(); + CodePosition to = ins->isCall() ? outputOf(*ins) : outputOf(*ins).next(); if (!vreg(temp).addInitialRange(alloc(), from, to)) return false; diff --git a/js/src/jit/LIR.h b/js/src/jit/LIR.h index b88ebc046f..4eb45e30a8 100644 --- a/js/src/jit/LIR.h +++ b/js/src/jit/LIR.h @@ -1179,6 +1179,18 @@ class LCallInstructionHelper : public LInstructionHelper } }; +template +class LBinaryCallInstructionHelper : public LCallInstructionHelper +{ + public: + const LAllocation* lhs() { + return this->getOperand(0); + } + const LAllocation* rhs() { + return this->getOperand(1); + } +}; + class LRecoverInfo : public TempObject { public: diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 0180e8518c..e977300210 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -3636,10 +3636,9 @@ LIRGenerator::visitGetNameCache(MGetNameCache* ins) { MOZ_ASSERT(ins->envObj()->type() == MIRType::Object); - // Set the performs-call flag so that we don't omit the overrecursed check. - // This is necessary because the cache can attach a scripted getter stub - // that calls this script recursively. - gen->setPerformsCall(); + // Emit an overrecursed check: this is necessary because the cache can + // attach a scripted getter stub that calls this script recursively. + gen->setNeedsOverrecursedCheck(); LGetNameCache* lir = new(alloc()) LGetNameCache(useRegister(ins->envObj())); defineBox(lir, ins); @@ -3654,6 +3653,24 @@ LIRGenerator::visitCallGetIntrinsicValue(MCallGetIntrinsicValue* ins) assignSafepoint(lir, ins); } +void +LIRGenerator::visitGetPropSuperCache(MGetPropSuperCache* ins) +{ + MDefinition* obj = ins->object(); + MDefinition* receiver = ins->receiver(); + MDefinition* id = ins->idval(); + + gen->setNeedsOverrecursedCheck(); + + bool useConstId = id->type() == MIRType::String || id->type() == MIRType::Symbol; + + auto* lir = new(alloc()) LGetPropSuperCacheV(useRegister(obj), + useBoxOrTyped(receiver), + useBoxOrTypedOrConstant(id, useConstId)); + defineBox(lir, ins); + assignSafepoint(lir, ins); +} + void LIRGenerator::visitGetPropertyCache(MGetPropertyCache* ins) { @@ -3666,10 +3683,9 @@ LIRGenerator::visitGetPropertyCache(MGetPropertyCache* ins) id->type() == MIRType::Value); if (ins->monitoredResult()) { - // Set the performs-call flag so that we don't omit the overrecursed - // check. This is necessary because the cache can attach a scripted - // getter stub that calls this script recursively. - gen->setPerformsCall(); + // Emit an overrecursed check: this is necessary because the cache can + // attach a scripted getter stub that calls this script recursively. + gen->setNeedsOverrecursedCheck(); } // If this is a GETPROP, the id is a constant string. Allow passing it as a @@ -3933,10 +3949,9 @@ LIRGenerator::visitSetPropertyCache(MSetPropertyCache* ins) bool useConstId = id->type() == MIRType::String || id->type() == MIRType::Symbol; bool useConstValue = IsNonNurseryConstant(ins->value()); - // Set the performs-call flag so that we don't omit the overrecursed check. - // This is necessary because the cache can attach a scripted setter stub - // that calls this script recursively. - gen->setPerformsCall(); + // Emit an overrecursed check: this is necessary because the cache can + // attach a scripted setter stub that calls this script recursively. + gen->setNeedsOverrecursedCheck(); // If the index might be an integer, we need some extra temp registers for // the dense and typed array element stubs. @@ -4117,8 +4132,30 @@ LIRGenerator::visitIn(MIn* ins) MOZ_ASSERT(lhs->type() == MIRType::Value); MOZ_ASSERT(rhs->type() == MIRType::Object); - LIn* lir = new(alloc()) LIn(useBoxAtStart(lhs), useRegisterAtStart(rhs)); - defineReturn(lir, ins); + LInCache* lir = new(alloc()) LInCache(useBoxOrTyped(lhs), useRegister(rhs), temp()); + define(lir, ins); + assignSafepoint(lir, ins); +} + +void +LIRGenerator::visitHasOwnCache(MHasOwnCache* ins) +{ + MDefinition* value = ins->value(); + MOZ_ASSERT(value->type() == MIRType::Object || value->type() == MIRType::Value); + + MDefinition* id = ins->idval(); + MOZ_ASSERT(id->type() == MIRType::String || + id->type() == MIRType::Symbol || + id->type() == MIRType::Int32 || + id->type() == MIRType::Value); + + // Emit an overrecursed check: this is necessary because the cache can + // attach a scripted getter stub that calls this script recursively. + gen->setNeedsOverrecursedCheck(); + + LHasOwnCache* lir = new(alloc()) LHasOwnCache(useBoxOrTyped(value), useBoxOrTyped(id)); + + define(lir, ins); assignSafepoint(lir, ins); } @@ -4386,7 +4423,6 @@ LIRGenerator::visitWasmStackArg(MWasmStackArg* ins) void LIRGenerator::visitWasmCall(MWasmCall* ins) { - gen->setPerformsCall(); LAllocation* args = gen->allocate(ins->numOperands()); if (!args) { @@ -4633,8 +4669,11 @@ LIRGenerator::visitInstruction(MInstruction* ins) return false; ins->accept(this); - if (ins->possiblyCalls()) - gen->setPerformsCall(); + if (ins->possiblyCalls()) { + gen->setNeedsStaticStackAlignment(); + gen->setNeedsOverrecursedCheck(); + } + if (ins->resumePoint()) updateResumeState(ins); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index b84d075202..699842abf3 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -6139,6 +6139,10 @@ class MMod : public MBinaryArithInstruction unsigned_ == ins->toMod()->isUnsigned(); } + bool possiblyCalls() const override { + return type() == MIRType::Double; + } + ALLOW_CLONE(MMod) }; diff --git a/js/src/jit/MIRGenerator.h b/js/src/jit/MIRGenerator.h index 53e1155be9..dc175d8032 100644 --- a/js/src/jit/MIRGenerator.h +++ b/js/src/jit/MIRGenerator.h @@ -141,12 +141,19 @@ class MIRGenerator uint32_t minWasmHeapLength() const { return minWasmHeapLength_; } - void setPerformsCall() { - performsCall_ = true; + void setNeedsOverrecursedCheck() { + needsOverrecursedCheck_ = true; } - bool performsCall() const { - return performsCall_; + bool needsOverrecursedCheck() const { + return needsOverrecursedCheck_; } + void setNeedsStaticStackAlignment() { + needsStaticStackAlignment_ = true; + } + bool needsStaticStackAlignment() const { + return needsOverrecursedCheck_; + } + bool modifiesFrameArguments() const { return modifiesFrameArguments_; @@ -176,7 +183,8 @@ class MIRGenerator mozilla::Atomic cancelBuild_; uint32_t wasmMaxStackArgBytes_; - bool performsCall_; + bool needsOverrecursedCheck_; + bool needsStaticStackAlignment_; // Keep track of whether frame arguments are modified during execution. // RegAlloc needs to know this as spilling values back to their register diff --git a/js/src/jit/MIRGraph.cpp b/js/src/jit/MIRGraph.cpp index 3cba074096..12034958b3 100644 --- a/js/src/jit/MIRGraph.cpp +++ b/js/src/jit/MIRGraph.cpp @@ -31,7 +31,8 @@ MIRGenerator::MIRGenerator(CompileCompartment* compartment, const JitCompileOpti pauseBuild_(nullptr), cancelBuild_(false), wasmMaxStackArgBytes_(0), - performsCall_(false), + needsOverrecursedCheck_(false), + needsStaticStackAlignment_(false), modifiesFrameArguments_(false), instrumentedProfiling_(false), instrumentedProfilingIsCached_(false), diff --git a/js/src/jit/arm/CodeGenerator-arm.cpp b/js/src/jit/arm/CodeGenerator-arm.cpp index 1d62cc26ae..463f789004 100644 --- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -776,7 +776,8 @@ CodeGeneratorARM::visitSoftModI(LSoftModI* ins) Label done; // Save the lhs in case we end up with a 0 that should be a -0.0 because lhs < 0. - MOZ_ASSERT(callTemp.code() > r3.code() && callTemp.code() < r12.code()); + MOZ_ASSERT(callTemp != lhs); + MOZ_ASSERT(callTemp != rhs); masm.ma_mov(lhs, callTemp); @@ -812,6 +813,8 @@ CodeGeneratorARM::visitSoftModI(LSoftModI* ins) masm.callWithABI(wasm::SymbolicAddress::aeabi_idivmod); else masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, __aeabi_idivmod)); + MOZ_ASSERT(r1 != output); + masm.move32(r1, output); // If X%Y == 0 and X < 0, then we *actually* wanted to return -0.0 if (mir->canBeNegativeDividend()) { @@ -820,7 +823,7 @@ CodeGeneratorARM::visitSoftModI(LSoftModI* ins) } else { MOZ_ASSERT(mir->fallible()); // See if X < 0 - masm.as_cmp(r1, Imm8(0)); + masm.as_cmp(output, Imm8(0)); masm.ma_b(&done, Assembler::NotEqual); masm.as_cmp(callTemp, Imm8(0)); bailoutIf(Assembler::Signed, ins->snapshot()); @@ -2874,9 +2877,7 @@ CodeGeneratorARM::visitSoftUDivOrMod(LSoftUDivOrMod* ins) MOZ_ASSERT(lhs == r0); MOZ_ASSERT(rhs == r1); - MOZ_ASSERT(ins->mirRaw()->isDiv() || ins->mirRaw()->isMod()); - MOZ_ASSERT_IF(ins->mirRaw()->isDiv(), output == r0); - MOZ_ASSERT_IF(ins->mirRaw()->isMod(), output == r1); + MOZ_ASSERT(output == r0); Label done; MDiv* div = ins->mir()->isDiv() ? ins->mir()->toDiv() : nullptr; @@ -2892,6 +2893,10 @@ CodeGeneratorARM::visitSoftUDivOrMod(LSoftUDivOrMod* ins) masm.callWithABI(wasm::SymbolicAddress::aeabi_uidivmod); else masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, __aeabi_uidivmod)); + if (mod) { + MOZ_ASSERT(output == r0, "output should not be r1 for mod"); + masm.move32(r1, output); + } // uidivmod returns the quotient in r0, and the remainder in r1. if (div && !div->canTruncateRemainder()) { diff --git a/js/src/jit/arm/LIR-arm.h b/js/src/jit/arm/LIR-arm.h index 8b41b2bd60..4ab1841ace 100644 --- a/js/src/jit/arm/LIR-arm.h +++ b/js/src/jit/arm/LIR-arm.h @@ -189,29 +189,15 @@ class LUDivOrModI64 : public LCallInstructionHelper +// divide instruction, implemented as a C++ native call. +class LSoftDivI : public LBinaryCallInstructionHelper<1, 0> { public: LIR_HEADER(SoftDivI); - LSoftDivI(const LAllocation& lhs, const LAllocation& rhs, - const LDefinition& temp1, const LDefinition& temp2, const LDefinition& temp3) { + LSoftDivI(const LAllocation& lhs, const LAllocation& rhs) { setOperand(0, lhs); setOperand(1, rhs); - setTemp(0, temp1); - setTemp(1, temp2); - setTemp(2, temp3); } MDiv* mir() const { @@ -267,25 +253,21 @@ class LModI : public LBinaryMath<1> } }; -class LSoftModI : public LBinaryMath<4> +class LSoftModI : public LBinaryCallInstructionHelper<1, 1> { public: LIR_HEADER(SoftModI); LSoftModI(const LAllocation& lhs, const LAllocation& rhs, - const LDefinition& temp1, const LDefinition& temp2, const LDefinition& temp3, - const LDefinition& callTemp) + const LDefinition& temp) { setOperand(0, lhs); setOperand(1, rhs); - setTemp(0, temp1); - setTemp(1, temp2); - setTemp(2, temp3); - setTemp(3, callTemp); + setTemp(0, temp); } const LDefinition* callTemp() { - return getTemp(3); + return getTemp(0); } MMod* mir() const { @@ -464,18 +446,14 @@ class LUMod : public LBinaryMath<0> } }; -class LSoftUDivOrMod : public LBinaryMath<3> +class LSoftUDivOrMod : public LBinaryCallInstructionHelper<1, 0> { public: LIR_HEADER(SoftUDivOrMod); - LSoftUDivOrMod(const LAllocation& lhs, const LAllocation& rhs, const LDefinition& temp1, - const LDefinition& temp2, const LDefinition& temp3) { + LSoftUDivOrMod(const LAllocation& lhs, const LAllocation& rhs) { setOperand(0, lhs); setOperand(1, rhs); - setTemp(0, temp1); - setTemp(1, temp2); - setTemp(2, temp3); } MInstruction* mir() { @@ -580,8 +558,7 @@ class LWasmTruncateToInt64 : public LCallInstructionHelper public: LIR_HEADER(WasmTruncateToInt64); - LWasmTruncateToInt64(const LAllocation& in) - { + LWasmTruncateToInt64(const LAllocation& in) { setOperand(0, in); } diff --git a/js/src/jit/arm/Lowering-arm.cpp b/js/src/jit/arm/Lowering-arm.cpp index 22bf3bc668..cea15817fc 100644 --- a/js/src/jit/arm/Lowering-arm.cpp +++ b/js/src/jit/arm/Lowering-arm.cpp @@ -350,11 +350,11 @@ LIRGeneratorARM::lowerDivI(MDiv* div) return; } - LSoftDivI* lir = new(alloc()) LSoftDivI(useFixedAtStart(div->lhs(), r0), useFixedAtStart(div->rhs(), r1), - tempFixed(r1), tempFixed(r2), tempFixed(r3)); + LSoftDivI* lir = new(alloc()) LSoftDivI(useFixedAtStart(div->lhs(), r0), + useFixedAtStart(div->rhs(), r1)); if (div->fallible()) assignSnapshot(lir, Bailout_DoubleOutput); - defineFixed(lir, div, LAllocation(AnyRegister(r0))); + defineReturn(lir, div); } void @@ -402,12 +402,12 @@ LIRGeneratorARM::lowerModI(MMod* mod) return; } - LSoftModI* lir = new(alloc()) LSoftModI(useFixedAtStart(mod->lhs(), r0), useFixedAtStart(mod->rhs(), r1), - tempFixed(r0), tempFixed(r2), tempFixed(r3), - temp(LDefinition::GENERAL)); + LSoftModI* lir = new(alloc()) LSoftModI(useFixedAtStart(mod->lhs(), r0), + useFixedAtStart(mod->rhs(), r1), + temp()); if (mod->fallible()) assignSnapshot(lir, Bailout_DoubleOutput); - defineFixed(lir, mod, LAllocation(AnyRegister(r1))); + defineReturn(lir, mod); } void diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index 8f06d91bb3..a62c96c0bf 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -88,7 +88,7 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator* gen, LIRGraph* graph, Mac static_assert(!SupportsSimd, "we need padding so that local slots are SIMD-aligned and " "the stack must be kept SIMD-aligned too."); - if (gen->performsCall()) { + if (gen->needsStaticStackAlignment()) { // An MWasmCall does not align the stack pointer at calls sites but // instead relies on the a priori stack adjustment. This must be the // last adjustment of frameDepth_. @@ -1471,7 +1471,7 @@ CodeGeneratorShared::omitOverRecursedCheck() const // stack overflow check. Note that the actual number here is somewhat // arbitrary, and codegen actually uses small bounded amounts of // additional stack space in some cases too. - return frameSize() < 64 && !gen->performsCall(); + return frameSize() < 64 && !gen->needsOverrecursedCheck(); } void diff --git a/js/src/jit/shared/Lowering-shared-inl.h b/js/src/jit/shared/Lowering-shared-inl.h index 95e315614e..6582c196eb 100644 --- a/js/src/jit/shared/Lowering-shared-inl.h +++ b/js/src/jit/shared/Lowering-shared-inl.h @@ -64,7 +64,8 @@ LIRGeneratorShared::define(details::LInstructionFixedDefsTempsHelper<1, X>* lir, } template void -LIRGeneratorShared::defineFixed(LInstructionHelper<1, X, Y>* lir, MDefinition* mir, const LAllocation& output) +LIRGeneratorShared::defineFixed(LInstructionHelper<1, X, Y>* lir, MDefinition* mir, + const LAllocation& output) { LDefinition::Type type = LDefinition::TypeFrom(mir->type()); @@ -233,6 +234,7 @@ LIRGeneratorShared::defineReturn(LInstruction* lir, MDefinition* mir) lir->setMir(mir); MOZ_ASSERT(lir->isCall()); + gen->setNeedsStaticStackAlignment(); uint32_t vreg = getVirtualRegister();