diff options
-rw-r--r-- | src/v4/llvm_runtime.cpp | 7 | ||||
-rw-r--r-- | src/v4/moth/qv4vme_moth.cpp | 21 | ||||
-rw-r--r-- | src/v4/moth/qv4vme_moth_p.h | 3 | ||||
-rw-r--r-- | src/v4/qmljs_engine.h | 8 | ||||
-rw-r--r-- | src/v4/qmljs_runtime.cpp | 59 | ||||
-rw-r--r-- | src/v4/qmljs_runtime.h | 14 | ||||
-rw-r--r-- | src/v4/qv4functionobject.cpp | 25 | ||||
-rw-r--r-- | src/v4/qv4globalobject.cpp | 9 | ||||
-rw-r--r-- | src/v4/qv4isel_masm.cpp | 7 | ||||
-rw-r--r-- | tools/v4/main.cpp | 3 |
10 files changed, 89 insertions, 67 deletions
diff --git a/src/v4/llvm_runtime.cpp b/src/v4/llvm_runtime.cpp index 0322eccc..c3aede78 100644 --- a/src/v4/llvm_runtime.cpp +++ b/src/v4/llvm_runtime.cpp @@ -476,13 +476,14 @@ void __qmljs_llvm_throw(ExecutionContext *context, Value *value) void __qmljs_llvm_create_exception_handler(ExecutionContext *context, Value *result) { - void *buf = __qmljs_create_exception_handler(context); - *result = Value::fromInt32(setjmp(* static_cast<jmp_buf *>(buf))); + // ### FIXME. + __qmljs_create_exception_handler(context); + *result = Value::undefinedValue(); } void __qmljs_llvm_delete_exception_handler(ExecutionContext *context) { - __qmljs_delete_exception_handler(context); + // ### FIXME. } void __qmljs_llvm_get_exception(ExecutionContext *context, Value *result) diff --git a/src/v4/moth/qv4vme_moth.cpp b/src/v4/moth/qv4vme_moth.cpp index caa58101..1238b369 100644 --- a/src/v4/moth/qv4vme_moth.cpp +++ b/src/v4/moth/qv4vme_moth.cpp @@ -270,13 +270,15 @@ VM::Value VME::run(QQmlJS::VM::ExecutionContext *context, const uchar *&code, const uchar *tryCode = code; run(context, tryCode, stack, stackSize); code = tryCode; - } catch (const VM::Exception &) { + } catch (VM::Exception &ex) { + ex.accept(context); try { *result = VM::Value::fromInt32(1); const uchar *catchCode = code; run(context, catchCode, stack, stackSize); code = catchCode; - } catch (const VM::Exception &) { + } catch (VM::Exception &ex) { + ex.accept(context); *result = VM::Value::fromInt32(1); const uchar *catchCode = code; run(context, catchCode, stack, stackSize); @@ -286,7 +288,6 @@ VM::Value VME::run(QQmlJS::VM::ExecutionContext *context, const uchar *&code, MOTH_END_INSTR(CallBuiltinCreateExceptionHandler) MOTH_BEGIN_INSTR(CallBuiltinDeleteExceptionHandler) - __qmljs_delete_exception_handler(context); return VM::Value(); MOTH_END_INSTR(CallBuiltinDeleteExceptionHandler) @@ -488,17 +489,3 @@ VM::Value VME::exec(VM::ExecutionContext *ctxt, const uchar *code) VME vme; return vme.run(ctxt, code); } - -void VME::restoreState(VM::ExecutionContext *context, VM::Value *&target, const uchar *&code) -{ - VM::ExecutionEngine::ExceptionHandler &handler = context->engine->unwindStack.last(); - target = handler.target; - code = handler.code; -} - -void VME::saveState(VM::ExecutionContext *context, VM::Value *target, const uchar *code) -{ - VM::ExecutionEngine::ExceptionHandler &handler = context->engine->unwindStack.last(); - handler.target = target; - handler.code = code; -} diff --git a/src/v4/moth/qv4vme_moth_p.h b/src/v4/moth/qv4vme_moth_p.h index 0b7fc9b7..7c09fc06 100644 --- a/src/v4/moth/qv4vme_moth_p.h +++ b/src/v4/moth/qv4vme_moth_p.h @@ -27,9 +27,6 @@ private: , void ***storeJumpTable = 0 #endif ); - - static void restoreState(VM::ExecutionContext *context, VM::Value *&target, const uchar *&code); - static void saveState(VM::ExecutionContext *context, VM::Value *target, const uchar *code); }; } // namespace Moth diff --git a/src/v4/qmljs_engine.h b/src/v4/qmljs_engine.h index cc978c63..2289e734 100644 --- a/src/v4/qmljs_engine.h +++ b/src/v4/qmljs_engine.h @@ -179,14 +179,6 @@ struct Q_V4_EXPORT ExecutionEngine String *id_set; String *id_eval; - struct ExceptionHandler { - ExecutionContext *context; - const uchar *code; // Interpreter state - Value *target; // Interpreter state - jmp_buf stackFrame; - }; - - QVector<ExceptionHandler> unwindStack; Value exception; QVector<Function *> functions; diff --git a/src/v4/qmljs_runtime.cpp b/src/v4/qmljs_runtime.cpp index 4047a5c8..1f737534 100644 --- a/src/v4/qmljs_runtime.cpp +++ b/src/v4/qmljs_runtime.cpp @@ -112,6 +112,38 @@ QString numberToString(double num, int radix = 10) return str; } +Exception::Exception(ExecutionContext *throwingContext) +{ + this->throwingContext = throwingContext; + accepted = false; +} + +Exception::~Exception() +{ + assert(accepted); +} + +void Exception::accept(ExecutionContext *catchingContext) +{ + assert(!accepted); + accepted = true; + partiallyUnwindContext(catchingContext); +} + +void Exception::partiallyUnwindContext(ExecutionContext *catchingContext) +{ + if (!throwingContext) + return; + ExecutionContext *context = throwingContext; + while (context != catchingContext) { + ExecutionContext *parent = context->parent; + if (!context->withObject) + context->leaveCallContext(); + context = parent; + } + throwingContext = context; +} + extern "C" { void __qmljs_init_closure(ExecutionContext *ctx, Value *result, VM::Function *clos) @@ -955,40 +987,17 @@ void __qmljs_construct_property(ExecutionContext *context, Value *result, const void __qmljs_throw(ExecutionContext *context, const Value &value) { - assert(!context->engine->unwindStack.isEmpty()); - if (context->engine->debugger) context->engine->debugger->aboutToThrow(value); - ExecutionEngine::ExceptionHandler &handler = context->engine->unwindStack.last(); - - // clean up call contexts - while (context != handler.context) { - ExecutionContext *parent = context->parent; - if (!context->withObject) - context->leaveCallContext(); - context = parent; - } - context->engine->exception = value; - throw Exception(); + throw Exception(context); } -Q_V4_EXPORT void * __qmljs_create_exception_handler(ExecutionContext *context) +Q_V4_EXPORT void __qmljs_create_exception_handler(ExecutionContext *context) { context->engine->exception = Value::undefinedValue(); - context->engine->unwindStack.append(ExecutionEngine::ExceptionHandler()); - ExecutionEngine::ExceptionHandler &handler = context->engine->unwindStack.last(); - handler.context = context; - return handler.stackFrame; -} - -void __qmljs_delete_exception_handler(ExecutionContext *context) -{ - assert(!context->engine->unwindStack.isEmpty()); - - context->engine->unwindStack.pop_back(); } void __qmljs_get_exception(ExecutionContext *context, Value *result) diff --git a/src/v4/qmljs_runtime.h b/src/v4/qmljs_runtime.h index 4da9015a..f504e6dd 100644 --- a/src/v4/qmljs_runtime.h +++ b/src/v4/qmljs_runtime.h @@ -89,7 +89,16 @@ struct ArrayObject; struct ErrorObject; struct ExecutionEngine; -struct Exception { +struct Q_V4_EXPORT Exception { + explicit Exception(ExecutionContext *throwingContext); + ~Exception(); + + void accept(ExecutionContext *catchingContext); + + void partiallyUnwindContext(ExecutionContext *catchingContext); +private: + ExecutionContext *throwingContext; + bool accepted; }; extern "C" { @@ -196,8 +205,7 @@ void __qmljs_delete_name(ExecutionContext *ctx, Value *result, String *name); void Q_NORETURN __qmljs_throw(ExecutionContext*, const Value &value); // actually returns a jmp_buf * -Q_V4_EXPORT void *__qmljs_create_exception_handler(ExecutionContext *context); -void __qmljs_delete_exception_handler(ExecutionContext *context); +Q_V4_EXPORT void __qmljs_create_exception_handler(ExecutionContext *context); void __qmljs_get_exception(ExecutionContext *context, Value *result); // binary operators diff --git a/src/v4/qv4functionobject.cpp b/src/v4/qv4functionobject.cpp index 437ea704..79905146 100644 --- a/src/v4/qv4functionobject.cpp +++ b/src/v4/qv4functionobject.cpp @@ -373,7 +373,13 @@ Value ScriptFunction::construct(Managed *that, ExecutionContext *context, Value ctx->argumentCount = argc; ctx->initCallContext(context); - Value result = f->function->code(ctx, f->function->codeData); + Value result = Value::undefinedValue(); + try { + result = f->function->code(ctx, f->function->codeData); + } catch (Exception &ex) { + ex.partiallyUnwindContext(ctx->parent); + throw; + } ctx->leaveCallContext(); if (result.isObject()) @@ -402,7 +408,13 @@ Value ScriptFunction::call(Managed *that, ExecutionContext *context, const Value ctx->argumentCount = argc; ctx->initCallContext(context); - Value result = f->function->code(ctx, f->function->codeData); + Value result = Value::undefinedValue(); + try { + result = f->function->code(ctx, f->function->codeData); + } catch (Exception &ex) { + ex.partiallyUnwindContext(ctx->parent); + throw; + } ctx->leaveCallContext(); return result; } @@ -446,7 +458,14 @@ Value BuiltinFunctionOld::call(Managed *that, ExecutionContext *context, const V ctx->argumentCount = argc; ctx->initCallContext(context); - Value result = f->code(ctx); + Value result = Value::undefinedValue(); + try { + result = f->code(ctx); + } catch (Exception &ex) { + ex.partiallyUnwindContext(ctx->parent); + throw; + } + ctx->leaveCallContext(); return result; } diff --git a/src/v4/qv4globalobject.cpp b/src/v4/qv4globalobject.cpp index 2c921b2e..2454126c 100644 --- a/src/v4/qv4globalobject.cpp +++ b/src/v4/qv4globalobject.cpp @@ -393,7 +393,14 @@ Value EvalFunction::evalCall(ExecutionContext *context, Value /*thisObject*/, Va bool cstrict = ctx->strictMode; ctx->strictMode = strict; - Value result = f->code(ctx, f->codeData); + Value result = Value::undefinedValue(); + try { + result = f->code(ctx, f->codeData); + } catch (Exception &ex) { + if (strict) + ex.partiallyUnwindContext(ctx->parent); + throw; + } ctx->strictMode = cstrict; diff --git a/src/v4/qv4isel_masm.cpp b/src/v4/qv4isel_masm.cpp index 16592760..26307e8a 100644 --- a/src/v4/qv4isel_masm.cpp +++ b/src/v4/qv4isel_masm.cpp @@ -646,10 +646,12 @@ static void *tryWrapper(ExecutionContext *context, void *localsPtr, void *(*exce void *addressToContinueAt = 0; try { addressToContinueAt = exceptionEntryPointInCallingFunction(context, localsPtr, 0); - } catch (const Exception&) { + } catch (Exception& ex) { + ex.accept(context); try { addressToContinueAt = exceptionEntryPointInCallingFunction(context, localsPtr, 1); - } catch (const Exception&) { + } catch (Exception& ex) { + ex.accept(context); addressToContinueAt = exceptionEntryPointInCallingFunction(context, localsPtr, 1); } } @@ -694,7 +696,6 @@ void InstructionSelection::callBuiltinDeleteExceptionHandler() { // This assumes that we're in code that was called by tryWrapper, so we return to try wrapper // with the address that we'd like to continue at, which is right after the ret below. - generateFunctionCall(Assembler::Void, __qmljs_delete_exception_handler, Assembler::ContextRegister); Assembler::DataLabelPtr continuation = _as->moveWithPatch(Assembler::TrustedImmPtr(0), Assembler::ReturnValueRegister); _as->leaveStandardStackFrame(/*locals*/0); _as->ret(); diff --git a/tools/v4/main.cpp b/tools/v4/main.cpp index d73fa480..89a25973 100644 --- a/tools/v4/main.cpp +++ b/tools/v4/main.cpp @@ -388,7 +388,8 @@ int main(int argc, char *argv[]) if (! qgetenv("SHOW_EXIT_VALUE").isEmpty()) std::cout << "exit value: " << qPrintable(result.toString(ctx)->toQString()) << std::endl; } - } catch (const QQmlJS::VM::Exception&) { + } catch (QQmlJS::VM::Exception& ex) { + ex.accept(ctx); showException(ctx); return EXIT_FAILURE; } |