diff options
author | Erik Verbruggen <erik.verbruggen@qt.io> | 2016-08-10 11:45:24 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2016-08-10 13:20:54 +0000 |
commit | 6fe7ccf59b917e9383c07c1e7a71631200590e3a (patch) | |
tree | 90ff95735566e64b098be0fd11633457ee09b1b7 /src/qml/jsruntime/qv4runtimeapi_p.h | |
parent | 9425f832cdc036818cb08d1bd1328345fcb6f2ff (diff) |
V4: Fix JavaScript finally-block execution
After moving all runtime functions into the Runtime class and doing
indirect function calls, the code generation would always emit code
to check for an exception after a call. This is problematic for methods
that do not throw, but might be called when an exception is thrown. I.e.
in a finally block. This is especially problematic for methods like
popScope, the very first runtime method that is called in a finally
block. The result was that after popScope, execution was passed over to
the exception handler block for that finally block (meaning: the body
of the finally block was never executed).
The fix is to declare an enumerator in an anonymous enum for each
runtime method that indicates if an exception check is needed. The
existing ExceptionCheck templates are used to set the value.
Change-Id: I5bd8bcf2a92acabf2a33b3764447de6cc364bba9
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4runtimeapi_p.h')
-rw-r--r-- | src/qml/jsruntime/qv4runtimeapi_p.h | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index cbc7a2ddc1..582cdcf4e9 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -58,8 +58,41 @@ namespace QV4 { struct NoThrowEngine; +namespace { +template <typename T> +struct ExceptionCheck { + enum { NeedsCheck = 1 }; +}; +// push_catch and pop context methods shouldn't check for exceptions +template <> +struct ExceptionCheck<void (*)(QV4::ExecutionEngine *)> { + enum { NeedsCheck = 0 }; +}; +template <typename A> +struct ExceptionCheck<void (*)(A, QV4::NoThrowEngine)> { + enum { NeedsCheck = 0 }; +}; +template <> +struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowEngine *)> { + enum { NeedsCheck = 0 }; +}; +template <typename A> +struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowEngine *, A)> { + enum { NeedsCheck = 0 }; +}; +template <typename A, typename B> +struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowEngine *, A, B)> { + enum { NeedsCheck = 0 }; +}; +template <typename A, typename B, typename C> +struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> { + enum { NeedsCheck = 0 }; +}; +} // anonymous namespace + #define RUNTIME_METHOD(returnvalue, name, args) \ typedef returnvalue (*Method_##name)args; \ + enum { Method_##name##_NeedsExceptionCheck = ExceptionCheck<Method_##name>::NeedsCheck }; \ static returnvalue method_##name args; \ const Method_##name name |