summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/v4/llvm_runtime.cpp7
-rw-r--r--src/v4/moth/qv4vme_moth.cpp21
-rw-r--r--src/v4/moth/qv4vme_moth_p.h3
-rw-r--r--src/v4/qmljs_engine.h8
-rw-r--r--src/v4/qmljs_runtime.cpp59
-rw-r--r--src/v4/qmljs_runtime.h14
-rw-r--r--src/v4/qv4functionobject.cpp25
-rw-r--r--src/v4/qv4globalobject.cpp9
-rw-r--r--src/v4/qv4isel_masm.cpp7
-rw-r--r--tools/v4/main.cpp3
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;
}