From 8f69d75c785ff86face31db880abdb8414d1cbfe Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 14 Nov 2012 10:15:19 +0100 Subject: Fix interpreter exception handling. The stack frame of the interpreting function is restored, but all the datastructures live on the heap. So, save them out on handler creation, and restore them afterwards. Change-Id: I84b84007cc9944b56926bf0387c2798f7841cd2a Reviewed-by: Lars Knoll --- moth/qv4vme_moth.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++---- moth/qv4vme_moth_p.h | 4 ++++ 2 files changed, 46 insertions(+), 4 deletions(-) (limited to 'moth') diff --git a/moth/qv4vme_moth.cpp b/moth/qv4vme_moth.cpp index 66df75f79e..e9c43d4701 100644 --- a/moth/qv4vme_moth.cpp +++ b/moth/qv4vme_moth.cpp @@ -197,13 +197,30 @@ void VME::operator()(QQmlJS::VM::Context *context, const uchar *code TEMP(instr.targetTempIndex) = __qmljs_builtin_typeof(args[0], context); break; case Instr::instr_callBuiltin::builtin_throw: - TEMP(instr.targetTempIndex) = __qmljs_builtin_typeof(args[0], context); + TRACE(builtin_throw, "Throwing now...%s", ""); + __qmljs_builtin_throw(args[0], context); break; - case Instr::instr_callBuiltin::builtin_create_exception_handler: + case Instr::instr_callBuiltin::builtin_create_exception_handler: { + TRACE(builtin_create_exception_handler, "%s", ""); buf = __qmljs_create_exception_handler(context); - TEMP(instr.targetTempIndex) = VM::Value::fromInt32(setjmp(* static_cast(buf))); - break; + // The targetTempIndex is the only value we need from the instr to + // continue execution when an exception is caught. + int targetTempIndex = instr.targetTempIndex; + int didThrow = setjmp(* static_cast(buf)); + // Two ways to come here: after a create, or after a throw. + if (didThrow) + // At this point, the interpreter state can be anything but + // valid, so first restore the state. This includes all relevant + // locals. + restoreState(context, stack, targetTempIndex, code); + else + // Save the state and any variables we need when catching an + // exception, so we can restore the state at that point. + saveState(context, stack, targetTempIndex, code); + TEMP(targetTempIndex) = VM::Value::fromInt32(didThrow); + } break; case Instr::instr_callBuiltin::builtin_delete_exception_handler: + TRACE(builtin_delete_exception_handler, "%s", ""); __qmljs_delete_exception_handler(context); break; case Instr::instr_callBuiltin::builtin_get_exception: @@ -328,3 +345,24 @@ void VME::exec(VM::Context *ctxt, const uchar *code) vme(ctxt, code); } +void VME::restoreState(VM::Context *context, QVector &stack, int &targetTempIndex, const uchar *&code) +{ + typedef VM::ExecutionEngine::ExceptionHandler EH; + EH::InterpreterState *state = context->engine->unwindStack.last()->interpreterState; + assert(state); + stack.resize(state->stack.size()); + ::memcpy(stack.data(), state->stack.data(), sizeof(VM::Value) * state->stack.size()); + targetTempIndex = state->targetTempIndex; + code = state->code; +} + +void VME::saveState(VM::Context *context, const QVector &stack, int targetTempIndex, const uchar *code) +{ + typedef VM::ExecutionEngine::ExceptionHandler EH; + EH::InterpreterState *state = new EH::InterpreterState; + context->engine->unwindStack.last()->interpreterState = state; + state->stack.resize(stack.size()); + ::memcpy(state->stack.data(), stack.data(), sizeof(VM::Value) * stack.size()); + state->targetTempIndex = targetTempIndex; + state->code = code; +} diff --git a/moth/qv4vme_moth_p.h b/moth/qv4vme_moth_p.h index db1507d84d..b1bc45bab5 100644 --- a/moth/qv4vme_moth_p.h +++ b/moth/qv4vme_moth_p.h @@ -21,6 +21,10 @@ public: #ifdef MOTH_THREADED_INTERPRETER static void **instructionJumpTable(); #endif + +private: + static void restoreState(VM::Context *context, QVector &stack, int &targetTempIndex, const uchar *&code); + static void saveState(VM::Context *context, const QVector &stack, int targetTempIndex, const uchar *code); }; } // namespace Moth -- cgit v1.2.3