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<jmp_buf *>(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<jmp_buf *>(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:
vme(ctxt, code);
}
+void VME::restoreState(VM::Context *context, QVector<VM::Value> &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<VM::Value> &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;
+}
{
assert(!context->engine->unwindStack.isEmpty());
- ExecutionEngine::ExceptionHandler handler = context->engine->unwindStack.last();
+ ExecutionEngine::ExceptionHandler *handler = context->engine->unwindStack.last();
// clean up call contexts
- while (context != handler.context) {
+ while (context != handler->context) {
context->leaveCallContext();
context = context->parent;
}
- handler.context->result = value;
+ handler->context->result = value;
- longjmp(handler.stackFrame, 1);
+ longjmp(handler->stackFrame, 1);
}
void *__qmljs_create_exception_handler(Context *context)
{
- context->engine->unwindStack.append(ExecutionEngine::ExceptionHandler());
- ExecutionEngine::ExceptionHandler *handler = &context->engine->unwindStack.last();
+ ExecutionEngine::ExceptionHandler *handler = new ExecutionEngine::ExceptionHandler;
+ context->engine->unwindStack.append(handler);
handler->context = context;
return handler->stackFrame;
}
{
assert(!context->engine->unwindStack.isEmpty());
+ delete context->engine->unwindStack.last();
context->engine->unwindStack.pop_back();
}