From 3f2efbd1b904cdc9358ed328235502e338b020bf Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Fri, 23 Nov 2018 12:34:48 +0100 Subject: V4: Generate labels for backward jumps When analyzing the bytecode from top-to-bottom in a single pass, we don't know when a jump back to previously seen code occurs. For example, in the baseline JIT we would already have generated code for some bytecode when we see a jump back (like at the end of a loop body), and we can't go back and insert a label to jump to. As JavaScript has no goto's, the only backward jumps are at the end of loops, so there are very few cases where we need to actually generate labels. This was previously handled by analyzing the bytecode twice: once to collect all jump targets, and then second pass over the bytecode to do the actual JITting (which would use the jump targets to insert labels). We can now do that with one single pass. So the trade-off is to store 4 bytes more per function plus 4 bytes for each loop, instead of having to analyze all functions only to find where all jumps are each time that function is JITted. Change-Id: I3abfcb69f65851a397dbd4a9762ea5e9e57495f6 Reviewed-by: Ulf Hermann --- src/qml/jit/qv4assemblercommon_p.h | 3 ++- src/qml/jit/qv4baselineassembler.cpp | 21 ++++++++++++++------- src/qml/jit/qv4baselineassembler_p.h | 14 +++++++------- src/qml/jit/qv4baselinejit.cpp | 20 +++++++++++--------- src/qml/jit/qv4baselinejit_p.h | 5 +---- 5 files changed, 35 insertions(+), 28 deletions(-) (limited to 'src/qml/jit') diff --git a/src/qml/jit/qv4assemblercommon_p.h b/src/qml/jit/qv4assemblercommon_p.h index 8f4d3238c4..3e70457bd8 100644 --- a/src/qml/jit/qv4assemblercommon_p.h +++ b/src/qml/jit/qv4assemblercommon_p.h @@ -670,7 +670,8 @@ public: void addLabelForOffset(int offset) { - labelForOffset.insert(offset, label()); + if (!labelForOffset.contains(offset)) + labelForOffset.insert(offset, label()); } void addJumpToOffset(const Jump &jump, int offset) diff --git a/src/qml/jit/qv4baselineassembler.cpp b/src/qml/jit/qv4baselineassembler.cpp index 9663754cbf..987f366256 100644 --- a/src/qml/jit/qv4baselineassembler.cpp +++ b/src/qml/jit/qv4baselineassembler.cpp @@ -1382,28 +1382,31 @@ void BaselineAssembler::cmpStrictNotEqual(int lhs) pasm()->setAccumulatorTag(QV4::Value::ValueTypeInternal::Boolean); } -void BaselineAssembler::jump(int offset) +int BaselineAssembler::jump(int offset) { pasm()->addJumpToOffset(pasm()->jump(), offset); + return offset; } -void BaselineAssembler::jumpTrue(int offset) +int BaselineAssembler::jumpTrue(int offset) { pasm()->toBoolean([this, offset](PlatformAssembler::RegisterID resultReg) { auto jump = pasm()->branch32(PlatformAssembler::NotEqual, TrustedImm32(0), resultReg); pasm()->addJumpToOffset(jump, offset); }); + return offset; } -void BaselineAssembler::jumpFalse(int offset) +int BaselineAssembler::jumpFalse(int offset) { pasm()->toBoolean([this, offset](PlatformAssembler::RegisterID resultReg) { auto jump = pasm()->branch32(PlatformAssembler::Equal, TrustedImm32(0), resultReg); pasm()->addJumpToOffset(jump, offset); }); + return offset; } -void BaselineAssembler::jumpNoException(int offset) +int BaselineAssembler::jumpNoException(int offset) { auto jump = pasm()->branch32( PlatformAssembler::Equal, @@ -1411,11 +1414,13 @@ void BaselineAssembler::jumpNoException(int offset) offsetof(EngineBase, hasException)), TrustedImm32(0)); pasm()->addJumpToOffset(jump, offset); + return offset; } -void BaselineAssembler::jumpNotUndefined(int offset) +int BaselineAssembler::jumpNotUndefined(int offset) { pasm()->jumpNotUndefined(offset); + return offset; } void BaselineAssembler::prepareCallWithArgCount(int argc) @@ -1539,10 +1544,11 @@ void BaselineAssembler::setException() noException.link(pasm()); } -void BaselineAssembler::setUnwindHandler(int offset) +int BaselineAssembler::setUnwindHandler(int offset) { auto l = pasm()->storePtrWithPatch(TrustedImmPtr(nullptr), pasm()->exceptionHandlerAddress()); pasm()->addEHTarget(l, offset); + return offset; } @@ -1568,12 +1574,13 @@ void JIT::BaselineAssembler::unwindDispatch() noUnwind.link(pasm()); } -void JIT::BaselineAssembler::unwindToLabel(int level, int offset) +int JIT::BaselineAssembler::unwindToLabel(int level, int offset) { auto l = pasm()->storePtrWithPatch(TrustedImmPtr(nullptr), Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLabel))); pasm()->addEHTarget(l, offset); pasm()->store32(TrustedImm32(level), Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLevel))); gotoCatchException(); + return offset; } void BaselineAssembler::pushCatchContext(int index, int name) diff --git a/src/qml/jit/qv4baselineassembler_p.h b/src/qml/jit/qv4baselineassembler_p.h index dbefa42784..c39d002bf9 100644 --- a/src/qml/jit/qv4baselineassembler_p.h +++ b/src/qml/jit/qv4baselineassembler_p.h @@ -135,11 +135,11 @@ public: void cmpStrictNotEqual(int lhs); // jumps - void jump(int offset); - void jumpTrue(int offset); - void jumpFalse(int offset); - void jumpNoException(int offset); - void jumpNotUndefined(int offset); + Q_REQUIRED_RESULT int jump(int offset); + Q_REQUIRED_RESULT int jumpTrue(int offset); + Q_REQUIRED_RESULT int jumpFalse(int offset); + Q_REQUIRED_RESULT int jumpNoException(int offset); + Q_REQUIRED_RESULT int jumpNotUndefined(int offset); // stuff for runtime calls void prepareCallWithArgCount(int argc); @@ -160,10 +160,10 @@ public: void gotoCatchException(); void getException(); void setException(); - void setUnwindHandler(int offset); + Q_REQUIRED_RESULT int setUnwindHandler(int offset); void clearUnwindHandler(); void unwindDispatch(); - void unwindToLabel(int level, int offset); + Q_REQUIRED_RESULT int unwindToLabel(int level, int offset); void pushCatchContext(int index, int name); void popContext(); void deadTemporalZoneCheck(int offsetForSavedIP, int variableName); diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp index ed4cdabd26..df3af1fce3 100644 --- a/src/qml/jit/qv4baselinejit.cpp +++ b/src/qml/jit/qv4baselinejit.cpp @@ -63,7 +63,9 @@ void BaselineJIT::generate() // qDebug()<<"jitting" << function->name()->toQString(); const char *code = function->codeData; uint len = function->compiledFunction->codeSize; - labels = collectLabelsInBytecode(code, len); + + for (unsigned i = 0, ei = function->compiledFunction->nLabelInfos; i != ei; ++i) + labels.insert(int(function->compiledFunction->labelInfoTable()[i])); as->generatePrologue(); decode(code, len); @@ -591,7 +593,7 @@ void BaselineJIT::generate_ConstructWithSpread(int func, int argc, int argv) void BaselineJIT::generate_SetUnwindHandler(int offset) { if (offset) - as->setUnwindHandler(absoluteOffsetForJump(offset)); + labels.insert(as->setUnwindHandler(absoluteOffsetForJump(offset))); else as->clearUnwindHandler(); } @@ -603,7 +605,7 @@ void BaselineJIT::generate_UnwindDispatch() void BaselineJIT::generate_UnwindToLabel(int level, int offset) { - as->unwindToLabel(level, absoluteOffsetForJump(offset)); + labels.insert(as->unwindToLabel(level, absoluteOffsetForJump(offset))); } void BaselineJIT::generate_DeadTemporalZoneCheck(int name) @@ -870,11 +872,11 @@ void BaselineJIT::generate_ToObject() } -void BaselineJIT::generate_Jump(int offset) { as->jump(absoluteOffsetForJump(offset)); } -void BaselineJIT::generate_JumpTrue(int /*traceSlot*/, int offset) { as->jumpTrue(absoluteOffsetForJump(offset)); } -void BaselineJIT::generate_JumpFalse(int /*traceSlot*/, int offset) { as->jumpFalse(absoluteOffsetForJump(offset)); } -void BaselineJIT::generate_JumpNoException(int offset) { as->jumpNoException(absoluteOffsetForJump(offset)); } -void BaselineJIT::generate_JumpNotUndefined(int offset) { as->jumpNotUndefined(absoluteOffsetForJump(offset)); } +void BaselineJIT::generate_Jump(int offset) { labels.insert(as->jump(absoluteOffsetForJump(offset))); } +void BaselineJIT::generate_JumpTrue(int /*traceSlot*/, int offset) { labels.insert(as->jumpTrue(absoluteOffsetForJump(offset))); } +void BaselineJIT::generate_JumpFalse(int /*traceSlot*/, int offset) { labels.insert(as->jumpFalse(absoluteOffsetForJump(offset))); } +void BaselineJIT::generate_JumpNoException(int offset) { labels.insert(as->jumpNoException(absoluteOffsetForJump(offset))); } +void BaselineJIT::generate_JumpNotUndefined(int offset) { labels.insert(as->jumpNotUndefined(absoluteOffsetForJump(offset))); } void BaselineJIT::generate_CmpEqNull() { as->cmpeqNull(); } void BaselineJIT::generate_CmpNeNull() { as->cmpneNull(); } @@ -1004,7 +1006,7 @@ void BaselineJIT::generate_GetTemplateObject(int index) void BaselineJIT::startInstruction(Instr::Type /*instr*/) { - if (hasLabel()) + if (labels.contains(currentInstructionOffset())) as->addLabel(currentInstructionOffset()); } diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h index 9e7dd8f2ca..385fbf72f3 100644 --- a/src/qml/jit/qv4baselinejit_p.h +++ b/src/qml/jit/qv4baselinejit_p.h @@ -221,16 +221,13 @@ public: void endInstruction(Moth::Instr::Type instr) override; protected: - bool hasLabel() const - { return std::find(labels.cbegin(), labels.cend(), currentInstructionOffset()) != labels.cend(); } - int absoluteOffsetForJump(int relativeOffset) const { return nextInstructionOffset() + relativeOffset; } private: QV4::Function *function; QScopedPointer as; - std::vector labels; + QSet labels; }; #endif // V4_ENABLE_JIT -- cgit v1.2.3