summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-03-01 17:04:21 +0100
committerLars Knoll <lars.knoll@digia.com>2013-03-03 20:35:56 +0100
commitee967a10f258ea2acae2c2ea64f2923e91c8a2c5 (patch)
treef3aa2121d1243af8e6774a48f19084151331f4c5 /tools
parente5f6264ad2cac6dfa3ef8d92e2c85b07319dcc78 (diff)
Implement JavaScript exceptions using C++ exceptions
Instead of registering catch handlers with setjmp and throwing JS exceptions with longjmp, they are now thrown and caught as C++ exceptions. This allows for tight interoperability between C++ and JS in the future and allows for clear semantics with regards to cleaning up memory in the engine when throwing exceptions. (destructors are guaranteed to be called, unlike with setjmp/longjmp). The recent unwind table additions allow for the exceptions to be thrown through JIT generated code. Catching the exception is done by re-using the existing IR semantics where the beginning of a try block is marked by registering an exception handler. Execution after the registration continues conditionally, based on the return value of builtin_create_exception_handler. A return value of is 0 the try block(s) are executed. If an exception is thrown during that time, execution resumes at the point where builtin_create_exception_handler returns, but with a return value of 1. If an exception is thrown within the catch handler, the execution resumes again at the same point, but the inCatch IR variable will guide execution straight to the finally block(s), which calls delete_exception_handler. In the JIT as well as the interpreter this is implemented by entering a C++ code section that contains a C++ try {} catch {} block, in which the calling function is called again and continues right at the next instruction (or the interpreter loop is recursively entered). An exception will throw us out of that scope and back into the try {} catch {} wrapper, which can call again into the calling function. The IR guarantees that delete_exception_handler is always called, regardless of how the try or catch blocks are terminated. That is where in the JIT and interpreter we return from the nested function call and return back into the original stack frame, effectively unregistering the catch handler. Further cleanups with regards to the naming and the exception handler stack will come in subsequent patches, this is merely the minimal patch set to change to the new mechanism. This patch set breaks ARM until ARM exception handler tables are implemented. The interpreter changes are based on a patchset from Erik from https://codereview.qt-project.org/#change,45750 Change-Id: I543f2bd37b2186f7e48ffcab177d57b5ce932a0c Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/v4/main.cpp40
1 files changed, 20 insertions, 20 deletions
diff --git a/tools/v4/main.cpp b/tools/v4/main.cpp
index f6997eb7..d73fa480 100644
--- a/tools/v4/main.cpp
+++ b/tools/v4/main.cpp
@@ -369,30 +369,30 @@ int main(int argc, char *argv[])
const QString code = QString::fromUtf8(file.readAll());
file.close();
- void * buf = __qmljs_create_exception_handler(ctx);
- if (setjmp(*(jmp_buf *)buf)) {
+ __qmljs_create_exception_handler(ctx);
+ try {
+ QQmlJS::VM::Function *f = QQmlJS::VM::EvalFunction::parseSource(ctx, fn, code, QQmlJS::Codegen::GlobalCode,
+ /*strictMode =*/ false, /*inheritContext =*/ false);
+ if (!f)
+ continue;
+ vm.globalCode = f;
+
+ ctx->strictMode = f->isStrict;
+ ctx->lookups = f->lookups;
+ if (debugger)
+ debugger->aboutToCall(0, ctx);
+ QQmlJS::VM::Value result = f->code(ctx, f->codeData);
+ if (debugger)
+ debugger->justLeft(ctx);
+ if (!result.isUndefined()) {
+ if (! qgetenv("SHOW_EXIT_VALUE").isEmpty())
+ std::cout << "exit value: " << qPrintable(result.toString(ctx)->toQString()) << std::endl;
+ }
+ } catch (const QQmlJS::VM::Exception&) {
showException(ctx);
return EXIT_FAILURE;
}
- QQmlJS::VM::Function *f = QQmlJS::VM::EvalFunction::parseSource(ctx, fn, code, QQmlJS::Codegen::GlobalCode,
- /*strictMode =*/ false, /*inheritContext =*/ false);
- if (!f)
- continue;
- vm.globalCode = f;
-
- ctx->strictMode = f->isStrict;
- ctx->lookups = f->lookups;
- if (debugger)
- debugger->aboutToCall(0, ctx);
- QQmlJS::VM::Value result = f->code(ctx, f->codeData);
- if (debugger)
- debugger->justLeft(ctx);
- if (!result.isUndefined()) {
- if (! qgetenv("SHOW_EXIT_VALUE").isEmpty())
- std::cout << "exit value: " << qPrintable(result.toString(ctx)->toQString()) << std::endl;
- }
-
} else {
std::cerr << "Error: cannot open file " << fn.toUtf8().constData() << std::endl;
return EXIT_FAILURE;