diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 7cbe48d16495..5a6bff5dab95 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -7928,5 +7928,24 @@ CodeGenerator::visitAssertRangeV(LAssertRangeV *ins) return true; } +typedef bool (*RecompileFn)(JSContext *); +static const VMFunction RecompileFnInfo = FunctionInfo(Recompile); + +bool +CodeGenerator::visitRecompileCheck(LRecompileCheck *ins) +{ + Register useCount = ToRegister(ins->scratch()); + + masm.movePtr(ImmPtr(ins->mir()->script()->addressOfUseCount()), useCount); + Address ptr(useCount, 0); + masm.add32(Imm32(1), ptr); + + OutOfLineCode *ool = oolCallVM(RecompileFnInfo, ins, (ArgList()), StoreRegisterTo(useCount)); + masm.branch32(Assembler::Above, ptr, Imm32(ins->mir()->useCount()), ool->entry()); + masm.bind(ool->rejoin()); + + return true; +} + } // namespace jit } // namespace js diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index e522f27da234..5a42247fd604 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -336,6 +336,8 @@ class CodeGenerator : public CodeGeneratorSpecific bool visitAssertRangeF(LAssertRangeF *ins); bool visitAssertRangeV(LAssertRangeV *ins); + bool visitRecompileCheck(LRecompileCheck *ins); + IonScriptCounts *extractUnassociatedScriptCounts() { IonScriptCounts *counts = unassociatedScriptCounts_; unassociatedScriptCounts_ = nullptr; // prevent delete in dtor diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 28b2285a8fdc..c45572433eb7 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -691,6 +691,8 @@ IonBuilder::build() current->add(lazyArguments_); } + insertRecompileCheck(); + if (!traverseBytecode()) return false; @@ -848,6 +850,8 @@ IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi current->add(lazyArguments_); } + insertRecompileCheck(); + if (!traverseBytecode()) return false; @@ -3339,6 +3343,7 @@ IonBuilder::jsop_loophead(jsbytecode *pc) assertValidLoopHeadOp(pc); current->add(MInterruptCheck::New(alloc())); + insertRecompileCheck(); return true; } @@ -5991,6 +5996,15 @@ ClassHasResolveHook(CompileCompartment *comp, const Class *clasp, PropertyName * return true; } +void +IonBuilder::insertRecompileCheck() +{ + if (info().executionMode() != SequentialExecution) + return; + + return; +} + JSObject * IonBuilder::testSingletonProperty(JSObject *obj, PropertyName *name) { diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 2404e147d2df..a844910be45a 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -325,6 +325,8 @@ class IonBuilder : public MIRGenerator bool resumeAfter(MInstruction *ins); bool maybeInsertResume(); + void insertRecompileCheck(); + bool initParameters(); void rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIndex); void rewriteParameters(); diff --git a/js/src/jit/LIR-Common.h b/js/src/jit/LIR-Common.h index 13c803502d6c..7ed29e1ac609 100644 --- a/js/src/jit/LIR-Common.h +++ b/js/src/jit/LIR-Common.h @@ -5768,6 +5768,23 @@ class LAssertRangeV : public LInstructionHelper<0, BOX_PIECES, 3> } }; +class LRecompileCheck : public LInstructionHelper<0, 0, 1> +{ + public: + LIR_HEADER(RecompileCheck) + + LRecompileCheck(const LDefinition &scratch) { + setTemp(0, scratch); + } + + const LDefinition *scratch() { + return getTemp(0); + } + MRecompileCheck *mir() { + return mir_->toRecompileCheck(); + } +}; + } // namespace jit } // namespace js diff --git a/js/src/jit/LOpcodes.h b/js/src/jit/LOpcodes.h index 44d9db360964..2b13b1ad1f66 100644 --- a/js/src/jit/LOpcodes.h +++ b/js/src/jit/LOpcodes.h @@ -280,6 +280,7 @@ _(AsmJSCall) \ _(AsmJSCheckOverRecursed) \ _(CheckInterruptPar) \ + _(RecompileCheck) \ _(AssertRangeI) \ _(AssertRangeD) \ _(AssertRangeF) \ diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 3209d31927ff..6e2800c04241 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -3421,6 +3421,15 @@ LIRGenerator::visitGetDOMMember(MGetDOMMember *ins) return defineBox(lir, ins); } +bool +LIRGenerator::visitRecompileCheck(MRecompileCheck *ins) +{ + LRecompileCheck *lir = new(alloc()) LRecompileCheck(temp()); + if (!add(lir, ins)) + return false; + return assignSafepoint(lir, ins); +} + static void SpewResumePoint(MBasicBlock *block, MInstruction *ins, MResumePoint *resumePoint) { diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index 8302b9f16d68..c2a86f313d4f 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -261,6 +261,7 @@ class LIRGenerator : public LIRGeneratorSpecific bool visitSetDOMProperty(MSetDOMProperty *ins); bool visitGetDOMProperty(MGetDOMProperty *ins); bool visitGetDOMMember(MGetDOMMember *ins); + bool visitRecompileCheck(MRecompileCheck *ins); }; } // namespace jit diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 1cf9adfa4365..cd4cba1d0c7e 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -9204,6 +9204,38 @@ class MHaveSameClass } }; +class MRecompileCheck : public MNullaryInstruction +{ + JSScript *script_; + uint32_t recompileThreshold_; + + MRecompileCheck(JSScript *script_, uint32_t recompileThreshold) + : script_(script_), + recompileThreshold_(recompileThreshold) + { + setGuard(); + } + + public: + INSTRUCTION_HEADER(RecompileCheck); + + static MRecompileCheck *New(TempAllocator &alloc, JSScript *script_, uint32_t useCount) { + return new(alloc) MRecompileCheck(script_, useCount); + } + + JSScript *script() const { + return script_; + } + + uint32_t recompileThreshold() const { + return recompileThreshold_; + } + + AliasSet getAliasSet() const { + return AliasSet::None(); + } +}; + class MAsmJSNeg : public MUnaryInstruction { MAsmJSNeg(MDefinition *op, MIRType type) diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index 12cee893cefa..08b622ba6395 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -211,7 +211,8 @@ namespace jit { _(RestPar) \ _(ForkJoinSlice) \ _(GuardThreadLocalObject) \ - _(CheckInterruptPar) + _(CheckInterruptPar) \ + _(RecompileCheck) // Forward declarations of MIR types. #define FORWARD_DECLARE(op) class M##op; diff --git a/js/src/jit/ParallelSafetyAnalysis.cpp b/js/src/jit/ParallelSafetyAnalysis.cpp index 446e0f159f6c..a4d1e76bb6eb 100644 --- a/js/src/jit/ParallelSafetyAnalysis.cpp +++ b/js/src/jit/ParallelSafetyAnalysis.cpp @@ -311,6 +311,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor UNSAFE_OP(AsmJSParameter) UNSAFE_OP(AsmJSCall) UNSAFE_OP(AsmJSCheckOverRecursed) + DROP_OP(RecompileCheck) // It looks like this could easily be made safe: UNSAFE_OP(ConvertElementsToDoubles)