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 <simon.hausmann@digia.com>
This commit is contained in:
Lars Knoll 2013-10-23 14:03:09 +02:00 committed by The Qt Project
parent 34bf0139c7
commit 4f8df70107
5 changed files with 102 additions and 13 deletions

View File

@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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