aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <[email protected]>2013-10-23 14:03:09 +0200
committerThe Qt Project <[email protected]>2013-10-29 10:38:50 +0100
commit4f8df70107d17922303bb21db5a2cf92aa1aff99 (patch)
treee59fc784bf25c29f667d8f83fdddc156dffe1339 /src
parent34bf0139c75de861c948391737af3c8c2a42703c (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.h18
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp8
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp37
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp50
-rw-r--r--src/qml/jsruntime/qv4vme_moth_p.h2
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