diff options
author | Lars Knoll <[email protected]> | 2013-10-23 14:03:09 +0200 |
---|---|---|
committer | The Qt Project <[email protected]> | 2013-10-29 10:38:50 +0100 |
commit | 4f8df70107d17922303bb21db5a2cf92aa1aff99 (patch) | |
tree | e59fc784bf25c29f667d8f83fdddc156dffe1339 /src | |
parent | 34bf0139c75de861c948391737af3c8c2a42703c (diff) |
Implement new exception handling for moth
Add the required instructions and check for
exceptions in the engine before storing any
results.
Change-Id: Ibfaf904d659859e8012920270825211ba202c63d
Reviewed-by: Simon Hausmann <[email protected]>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 18 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm.cpp | 8 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth.cpp | 37 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 50 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth_p.h | 2 |
5 files changed, 102 insertions, 13 deletions
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index b9163b38d3..f9a46a06d7 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -68,7 +68,10 @@ QT_BEGIN_NAMESPACE F(CallProperty, callProperty) \ F(CallElement, callElement) \ F(CallActivationProperty, callActivationProperty) \ + F(SetExceptionHandler, setExceptionHandler) \ F(CallBuiltinThrow, callBuiltinThrow) \ + F(CallBuiltinUnwindException, callBuiltinUnwindException) \ + F(CallBuiltinPushCatchScope, callBuiltinPushCatchScope) \ F(CallBuiltinPushScope, callBuiltinPushScope) \ F(CallBuiltinPopScope, callBuiltinPopScope) \ F(CallBuiltinForeachIteratorObject, callBuiltinForeachIteratorObject) \ @@ -302,10 +305,22 @@ union Instr quint32 callData; Param result; }; + struct instr_setExceptionHandler { + MOTH_INSTR_HEADER + qptrdiff offset; + }; struct instr_callBuiltinThrow { MOTH_INSTR_HEADER Param arg; }; + struct instr_callBuiltinUnwindException { + MOTH_INSTR_HEADER + Param result; + }; + struct instr_callBuiltinPushCatchScope { + MOTH_INSTR_HEADER + int name; + }; struct instr_callBuiltinPushScope { MOTH_INSTR_HEADER Param arg; @@ -491,6 +506,9 @@ union Instr instr_callElement callElement; instr_callActivationProperty callActivationProperty; instr_callBuiltinThrow callBuiltinThrow; + instr_setExceptionHandler setExceptionHandler; + instr_callBuiltinUnwindException callBuiltinUnwindException; + instr_callBuiltinPushCatchScope callBuiltinPushCatchScope; instr_callBuiltinPushScope callBuiltinPushScope; instr_callBuiltinPopScope callBuiltinPopScope; instr_callBuiltinForeachIteratorObject callBuiltinForeachIteratorObject; diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp index 2d13b4d8c8..09fcbfd946 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -723,6 +723,9 @@ void InstructionSelection::run(int functionIndex) } } + if (!_as->exceptionReturnLabel.isSet()) + visitRet(0); + JSC::MacroAssemblerCodeRef codeRef =_as->link(&compilationUnit->codeSizes[functionIndex]); compilationUnit->codeRefs[functionIndex] = codeRef; @@ -1909,7 +1912,10 @@ void InstructionSelection::visitCJump(V4IR::CJump *s) void InstructionSelection::visitRet(V4IR::Ret *s) { - if (V4IR::Temp *t = s->expr->asTemp()) { + if (!s) { + // this only happens if the method doesn't have a return statement and can + // only exit through an exception + } else if (V4IR::Temp *t = s->expr->asTemp()) { #if CPU(X86) || CPU(ARM) # if CPU(X86) diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index 06fb9caac8..835f0a8a23 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -263,6 +263,8 @@ void InstructionSelection::run(int functionIndex) int locals = frameSize(); assert(locals >= 0); + V4IR::BasicBlock *exceptionHandler = 0; + Instruction::Push push; push.value = quint32(locals); addInstruction(push); @@ -275,6 +277,18 @@ void InstructionSelection::run(int functionIndex) _nextBlock = (i < ei - 1) ? _function->basicBlocks[i + 1] : 0; _addrs.insert(_block, _codeNext - _codeStart); + if (_block->catchBlock != exceptionHandler) { + Instruction::SetExceptionHandler set; + set.offset = 0; + if (_block->catchBlock) { + ptrdiff_t loc = addInstruction(set) + (((const char *)&set.offset) - ((const char *)&set)); + _patches[_block->catchBlock].append(loc); + } else { + addInstruction(set); + } + exceptionHandler = _block->catchBlock; + } + foreach (V4IR::Stmt *s, _block->statements) { _currentStatement = s; @@ -774,18 +788,33 @@ void InstructionSelection::callBuiltinThrow(V4IR::Expr *arg) void InstructionSelection::callBuiltinReThrow() { - // ### + if (_block->catchBlock) { + // jump to exception handler + Instruction::Jump jump; + jump.offset = 0; + ptrdiff_t loc = addInstruction(jump) + (((const char *)&jump.offset) - ((const char *)&jump)); + + _patches[_block->catchBlock].append(loc); + } else { + Instruction::Ret ret; + ret.result = Param::createValue(QV4::Primitive::undefinedValue()); + addInstruction(ret); + } } -void InstructionSelection::callBuiltinUnwindException(V4IR::Temp *) +void InstructionSelection::callBuiltinUnwindException(V4IR::Temp *result) { - // ### + Instruction::CallBuiltinUnwindException call; + call.result = getResultParam(result); + addInstruction(call); } void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionName) { - // #### + Instruction::CallBuiltinPushCatchScope call; + call.name = registerString(exceptionName); + addInstruction(call); } void InstructionSelection::callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result) diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 04a07093c1..730b9d29a7 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -216,15 +216,25 @@ static inline QV4::Value *getValueRef(QV4::ExecutionContext *context, # define VALUE(param) (*getValueRef(context, stack, param, stackSize)) # define VALUEPTR(param) getValueRef(context, stack, param, stackSize) #endif -#define STOREVALUE(param, value) VALUE(param) = QV4::Value::fromReturnedValue((value)) +#define STOREVALUE(param, value) { \ + QV4::ReturnedValue tmp = (value); \ + if (context->engine->hasException) \ + goto catchException; \ + VALUE(param) = tmp; \ + } +#define CHECK_EXCEPTION \ + if (context->engine->hasException) \ + goto catchException -QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code, +QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code, QV4::SafeValue *stack, unsigned stackSize #ifdef MOTH_THREADED_INTERPRETER , void ***storeJumpTable #endif ) { + const uchar *exceptionHandler = 0; + #ifdef DO_TRACE_INSTR qDebug("Starting VME with context=%p and code=%p", context, code); #endif // DO_TRACE_INSTR @@ -244,12 +254,12 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code, QV4::SafeString * const runtimeStrings = context->compilationUnit->runtimeStrings; context->interpreterInstructionPointer = &code; -#ifdef MOTH_THREADED_INTERPRETER - const Instr *genericInstr = reinterpret_cast<const Instr *>(code); - goto *genericInstr->common.code; -#else + for (;;) { const Instr *genericInstr = reinterpret_cast<const Instr *>(code); +#ifdef MOTH_THREADED_INTERPRETER + goto *genericInstr->common.code; +#else switch (genericInstr->common.instructionType) { #endif @@ -288,6 +298,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code, MOTH_BEGIN_INSTR(StoreName) TRACE(inline, "property name = %s", runtimeStrings[instr.name]->toQString().toUtf8().constData()); __qmljs_set_activation_property(context, runtimeStrings[instr.name], VALUEPTR(instr.source)); + CHECK_EXCEPTION; MOTH_END_INSTR(StoreName) MOTH_BEGIN_INSTR(LoadElement) @@ -296,6 +307,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code, MOTH_BEGIN_INSTR(StoreElement) __qmljs_set_element(context, VALUEPTR(instr.base), VALUEPTR(instr.index), VALUEPTR(instr.source)); + CHECK_EXCEPTION; MOTH_END_INSTR(StoreElement) MOTH_BEGIN_INSTR(LoadProperty) @@ -304,6 +316,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code, MOTH_BEGIN_INSTR(StoreProperty) __qmljs_set_property(context, VALUEPTR(instr.base), runtimeStrings[instr.name], VALUEPTR(instr.source)); + CHECK_EXCEPTION; MOTH_END_INSTR(StoreProperty) MOTH_BEGIN_INSTR(Push) @@ -361,10 +374,23 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code, STOREVALUE(instr.result, __qmljs_call_activation_property(context, runtimeStrings[instr.name], callData)); MOTH_END_INSTR(CallActivationProperty) + MOTH_BEGIN_INSTR(SetExceptionHandler) + exceptionHandler = instr.offset ? ((uchar *)&instr.offset) + instr.offset : 0; + MOTH_END_INSTR(SetExceptionHandler) + MOTH_BEGIN_INSTR(CallBuiltinThrow) __qmljs_throw(context, VALUEPTR(instr.arg)); + CHECK_EXCEPTION; MOTH_END_INSTR(CallBuiltinThrow) + MOTH_BEGIN_INSTR(CallBuiltinUnwindException) + STOREVALUE(instr.result, __qmljs_builtin_unwind_exception(context)); + MOTH_END_INSTR(CallBuiltinUnwindException) + + MOTH_BEGIN_INSTR(CallBuiltinPushCatchScope) + context = __qmljs_builtin_push_catch_scope(context, runtimeStrings[instr.name]); + MOTH_END_INSTR(CallBuiltinPushCatchScope) + MOTH_BEGIN_INSTR(CallBuiltinPushScope) context = __qmljs_builtin_push_with_scope(VALUEPTR(instr.arg), context); MOTH_END_INSTR(CallBuiltinPushScope) @@ -524,9 +550,19 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code, qFatal("QQmlJS::Moth::VME: Internal error - unknown instruction %d", genericInstr->common.instructionType); break; } - } #endif + Q_ASSERT(false); + catchException: + Q_ASSERT(context->engine->hasException); + if (!exceptionHandler) { + context->engine->stackPop(stackSize); + return QV4::Encode::undefined(); + } + code = exceptionHandler; + } + + } #ifdef MOTH_THREADED_INTERPRETER diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h index 68d8086f52..974dfdd615 100644 --- a/src/qml/jsruntime/qv4vme_moth_p.h +++ b/src/qml/jsruntime/qv4vme_moth_p.h @@ -60,7 +60,7 @@ public: #endif private: - QV4::ReturnedValue run(QV4::ExecutionContext *, const uchar *&code, + QV4::ReturnedValue run(QV4::ExecutionContext *, const uchar *code, QV4::SafeValue *stack = 0, unsigned stackSize = 0 #ifdef MOTH_THREADED_INTERPRETER , void ***storeJumpTable = 0 |