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:
parent
34bf0139c7
commit
4f8df70107
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue