diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-06-01 12:21:08 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2018-06-21 12:27:21 +0000 |
commit | 267513e6d955cb93abb879c495dd079c254d3493 (patch) | |
tree | 8cd3bd26756142b80b9e12f77e8b3e7e868be35b /src/qml/jit | |
parent | 93a70a051b21ae253331f922027bd9bb7a3e457a (diff) |
Rework unwind handling
The old code was rather convoluted and expanded to quite
a bit of bytecode. It was also very hard to fix some
of the remaining issues with unwinding in there.
The new code handles unwinding a bit differently. Basically,
we now have three instructions to do what the spec requires.
SetUnwindHandler is the same as the old SetExceptionHandler
instruction. It basically tells the runtime where to jump to
to handle any abrupt completion (ie. throw/break/continue/return)
that requires unwinding.
UnwindToLabel is a new instruction that is used for unwinding
break/continue/return statements. It takes two arguments, one
telling the runtime how many levels to unwind and the second
a target label to jump to when unwinding is done.
UnwindDispatch is the third instruction and is invoked at
the end of each unwind block to dispatch the the parent
unwind handler if required and thus implement the support
for the levelled unwinding.
Change-Id: I079a39d0d897b3ecc2f0dc631ca29b25eae05250
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jit')
-rw-r--r-- | src/qml/jit/qv4assembler.cpp | 105 | ||||
-rw-r--r-- | src/qml/jit/qv4assembler_p.h | 5 | ||||
-rw-r--r-- | src/qml/jit/qv4baselinejit.cpp | 22 | ||||
-rw-r--r-- | src/qml/jit/qv4baselinejit_p.h | 7 |
4 files changed, 65 insertions, 74 deletions
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index a32039dc96..5702774cd7 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -712,6 +712,11 @@ struct PlatformAssembler64 : PlatformAssemblerCommon patches.push_back({ jump, offset }); } + Jump jumpEmpty() + { + return branch64(Equal, AccumulatorRegister, TrustedImm64(Primitive::emptyValue().asReturnedValue())); + } + void toBoolean(std::function<void(RegisterID)> continuation) { urshift64(AccumulatorRegister, TrustedImm32(Value::IsIntegerConvertible_Shift), ScratchRegister); @@ -815,26 +820,6 @@ struct PlatformAssembler64 : PlatformAssemblerCommon return branch32(Equal, TrustedImm32(3), ScratchRegister); } - void jumpStrictEqualStackSlotInt(int lhs, int rhs, int offset) - { - Address lhsAddr(JSStackFrameRegister, lhs * int(sizeof(Value))); - load64(lhsAddr, ScratchRegister); - Jump isUndef = branch64(Equal, ScratchRegister, TrustedImm64(0)); - Jump equal = branch32(Equal, TrustedImm32(rhs), ScratchRegister); - patches.push_back({ equal, offset }); - isUndef.link(this); - } - - void jumpStrictNotEqualStackSlotInt(int lhs, int rhs, int offset) - { - Address lhsAddr(JSStackFrameRegister, lhs * int(sizeof(Value))); - load64(lhsAddr, ScratchRegister); - Jump isUndef = branch64(Equal, ScratchRegister, TrustedImm64(0)); - patches.push_back({ isUndef, offset }); - Jump notEqual = branch32(NotEqual, TrustedImm32(rhs), ScratchRegister); - patches.push_back({ notEqual, offset }); - } - void setAccumulatorTag(QV4::Value::ValueTypeInternal tag, RegisterID sourceReg = NoRegister) { if (sourceReg == NoRegister) @@ -1163,6 +1148,11 @@ struct PlatformAssembler32 : PlatformAssemblerCommon patches.push_back({ jump, offset }); } + Jump jumpEmpty() + { + return branch32(Equal, AccumulatorRegisterTag, TrustedImm32(Primitive::emptyValue().asReturnedValue() >> 32)); + } + void toBoolean(std::function<void(RegisterID)> continuation) { urshift32(AccumulatorRegisterTag, TrustedImm32(Value::IsIntegerConvertible_Shift - 32), @@ -1202,34 +1192,6 @@ struct PlatformAssembler32 : PlatformAssemblerCommon done.link(this); } - void jumpStrictEqualStackSlotInt(int lhs, int rhs, int offset) - { - Address lhsAddr(JSStackFrameRegister, lhs * int(sizeof(Value))); - load32(lhsAddr, ScratchRegister); - Jump notEqInt = branch32(NotEqual, ScratchRegister, TrustedImm32(rhs)); - Jump notEqUndefVal = branch32(NotEqual, ScratchRegister, TrustedImm32(0)); - patches.push_back({ notEqUndefVal, offset }); - lhsAddr.offset += 4; - load32(lhsAddr, ScratchRegister); - Jump notEqUndefTag = branch32(NotEqual, ScratchRegister, TrustedImm32(0)); - patches.push_back({ notEqUndefTag, offset }); - notEqInt.link(this); - } - - void jumpStrictNotEqualStackSlotInt(int lhs, int rhs, int offset) - { - Address lhsAddr(JSStackFrameRegister, lhs * int(sizeof(Value))); - load32(lhsAddr, ScratchRegister); - Jump notEqual = branch32(NotEqual, TrustedImm32(rhs), ScratchRegister); - patches.push_back({ notEqual, offset }); - Jump notUndefValue = branch32(NotEqual, TrustedImm32(0), ScratchRegister); - lhsAddr.offset += 4; - load32(lhsAddr, ScratchRegister); - Jump equalUndef = branch32(Equal, TrustedImm32(0), ScratchRegister); - patches.push_back({ equalUndef, offset }); - notUndefValue.link(this); - } - void setAccumulatorTag(QV4::Value::ValueTypeInternal tag, RegisterID sourceReg = NoRegister) { if (sourceReg != NoRegister) @@ -2009,6 +1971,16 @@ void Assembler::jumpFalse(int offset) }); } +void Assembler::jumpNoException(int offset) +{ + auto jump = pasm()->branch32( + PlatformAssembler::Equal, + PlatformAssembler::Address(PlatformAssembler::EngineRegister, + offsetof(EngineBase, hasException)), + TrustedImm32(0)); + pasm()->patches.push_back({ jump, offset }); +} + void Assembler::jumpNotUndefined(int offset) { pasm()->jumpNotUndefined(offset); @@ -2019,16 +1991,6 @@ void JIT::Assembler::jumpEmpty(int offset) pasm()->jumpEmpty(offset); } -void Assembler::jumpStrictEqualStackSlotInt(int lhs, int rhs, int offset) -{ - pasm()->jumpStrictEqualStackSlotInt(lhs, rhs, offset); -} - -void Assembler::jumpStrictNotEqualStackSlotInt(int lhs, int rhs, int offset) -{ - pasm()->jumpStrictNotEqualStackSlotInt(lhs, rhs, offset); -} - void Assembler::prepareCallWithArgCount(int argc) { #ifndef QT_NO_DEBUG @@ -2220,12 +2182,14 @@ void Assembler::getException() void Assembler::setException() { + auto noException = pasm()->jumpEmpty(); Address addr(PlatformAssembler::EngineRegister, offsetof(EngineBase, exceptionValue)); pasm()->loadPtr(addr, PlatformAssembler::ScratchRegister); pasm()->storeAccumulator(Address(PlatformAssembler::ScratchRegister)); addr.offset = offsetof(EngineBase, hasException); Q_STATIC_ASSERT(sizeof(QV4::EngineBase::hasException) == 1); pasm()->store8(TrustedImm32(1), addr); + noException.link(pasm()); } void Assembler::setUnwindHandler(int offset) @@ -2240,6 +2204,31 @@ void Assembler::clearUnwindHandler() pasm()->storePtr(TrustedImmPtr(nullptr), pasm()->exceptionHandlerAddress()); } +void JIT::Assembler::unwindDispatch() +{ + checkException(); + pasm()->load32(Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLevel)), PlatformAssembler::ScratchRegister); + auto noUnwind = pasm()->branch32(PlatformAssembler::Equal, PlatformAssembler::ScratchRegister, TrustedImm32(0)); + pasm()->sub32(TrustedImm32(1), PlatformAssembler::ScratchRegister); + pasm()->store32(PlatformAssembler::ScratchRegister, Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLevel))); + auto jump = pasm()->branch32(PlatformAssembler::Equal, PlatformAssembler::ScratchRegister, TrustedImm32(0)); + gotoCatchException(); + jump.link(pasm()); + + pasm()->loadPtr(Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLabel)), PlatformAssembler::ScratchRegister); + pasm()->jump(PlatformAssembler::ScratchRegister); + + noUnwind.link(pasm()); +} + +void JIT::Assembler::unwindToLabel(int level, int offset) +{ + auto l = pasm()->storePtrWithPatch(TrustedImmPtr(nullptr), Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLabel))); + pasm()->ehTargets.push_back({ l, offset }); + pasm()->store32(TrustedImm32(level), Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLevel))); + gotoCatchException(); +} + void Assembler::pushCatchContext(int index, int name) { prepareCallWithArgCount(3); diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 73faf7b69f..d41b79f562 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -140,10 +140,9 @@ public: void jump(int offset); void jumpTrue(int offset); void jumpFalse(int offset); + void jumpNoException(int offset); void jumpNotUndefined(int offset); void jumpEmpty(int offset); - void jumpStrictEqualStackSlotInt(int lhs, int rhs, int offset); - void jumpStrictNotEqualStackSlotInt(int lhs, int rhs, int offset); // stuff for runtime calls void prepareCallWithArgCount(int argc); @@ -164,6 +163,8 @@ public: void setException(); void setUnwindHandler(int offset); void clearUnwindHandler(); + void unwindDispatch(); + void unwindToLabel(int level, int offset); void pushCatchContext(int index, int name); void popContext(); diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp index 031c6e620c..6c298d9331 100644 --- a/src/qml/jit/qv4baselinejit.cpp +++ b/src/qml/jit/qv4baselinejit.cpp @@ -561,6 +561,17 @@ void BaselineJIT::generate_SetUnwindHandler(int offset) as->clearUnwindHandler(); } +void BaselineJIT::generate_UnwindDispatch() +{ + as->unwindDispatch(); +} + +void BaselineJIT::generate_UnwindToLabel(int level, int offset) +{ + as->unwindToLabel(level, instructionOffset() + offset); +} + + void BaselineJIT::generate_ThrowException() { STORE_IP(); @@ -891,6 +902,7 @@ void BaselineJIT::generate_Construct(int func, int argc, int argv) void BaselineJIT::generate_Jump(int offset) { as->jump(instructionOffset() + offset); } void BaselineJIT::generate_JumpTrue(int offset) { as->jumpTrue(instructionOffset() + offset); } void BaselineJIT::generate_JumpFalse(int offset) { as->jumpFalse(instructionOffset() + offset); } +void BaselineJIT::generate_JumpNoException(int offset) { as->jumpNoException(instructionOffset() + offset); } void BaselineJIT::generate_JumpNotUndefined(int offset) { as->jumpNotUndefined(instructionOffset() + offset); } void BaselineJIT::generate_JumpEmpty(int offset) { as->jumpEmpty(instructionOffset() + offset); } @@ -929,16 +941,6 @@ void BaselineJIT::generate_CmpInstanceOf(int lhs) as->checkException(); } -void BaselineJIT::generate_JumpStrictEqualStackSlotInt(int lhs, int rhs, int offset) -{ - as->jumpStrictEqualStackSlotInt(lhs, rhs, instructionOffset() + offset); -} - -void BaselineJIT::generate_JumpStrictNotEqualStackSlotInt(int lhs, int rhs, int offset) -{ - as->jumpStrictNotEqualStackSlotInt(lhs, rhs, instructionOffset() + offset); -} - void BaselineJIT::generate_UNot() { as->unot(); } void BaselineJIT::generate_UPlus() { as->toNumber(); } void BaselineJIT::generate_UMinus() { as->uminus(); } diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h index 96fd8348b8..5441ea974b 100644 --- a/src/qml/jit/qv4baselinejit_p.h +++ b/src/qml/jit/qv4baselinejit_p.h @@ -129,6 +129,8 @@ public: void generate_CallScopeObjectProperty(int propIdx, int base, int argc, int argv) override; void generate_CallContextObjectProperty(int propIdx, int base, int argc, int argv) override; void generate_SetUnwindHandler(int offset) override; + void generate_UnwindDispatch() override; + void generate_UnwindToLabel(int level, int offset) override; void generate_ThrowException() override; void generate_GetException() override; void generate_SetException() override; @@ -161,6 +163,7 @@ public: void generate_Jump(int offset) override; void generate_JumpTrue(int offset) override; void generate_JumpFalse(int offset) override; + void generate_JumpNoException(int offset) override; void generate_JumpNotUndefined(int offset) override; void generate_JumpEmpty(int offset) override; void generate_CmpEqNull() override; @@ -177,10 +180,6 @@ public: void generate_CmpStrictNotEqual(int lhs) override; void generate_CmpIn(int lhs) override; void generate_CmpInstanceOf(int lhs) override; - void generate_JumpStrictEqualStackSlotInt(int lhs, int rhs, - int offset) override; - void generate_JumpStrictNotEqualStackSlotInt(int lhs, int rhs, - int offset) override; void generate_UNot() override; void generate_UPlus() override; void generate_UMinus() override; |