diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2013-10-01 15:10:33 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-10-03 09:24:32 +0200 |
commit | 8abf7f5876a48c0879bce628597533c7b6eca9a0 (patch) | |
tree | f01dd867b10affb44cefbe050a1f4fcb1a9dfcd1 /src/qml/jsruntime | |
parent | a8796a84fe45aa78123c661aab912f900f2ca0bc (diff) |
Change v4 exceptions to use the common C++ ABIs foreign exceptions
On platforms where we use the common C++ ABI, throw the exception not using a
dummy C++ exception structure and the throw keyboard, but instead use the
lower-level _Unwind_RaiseException to throw a foreign exception. It is caught
with the existing "catch (...)" and re-throw is implemented similarly, by
grabbing the current exception from the globals (a standardized data structure)
and re-throwing it.
On platforms such as ARM that lack hooks for supplying our unwind tables to the
system run-time, this patch will make it possible to link the unwinder
statically into libQtQml (libgcc or libunwind) and thus force it to use our
unwind tables, because throwing or re-throwing will always go through our
statically linked code through direct calls to _Unwind_RaiseException (instead
of libstdc++).
Change-Id: Ic2ac056fc7ed9e93fb51e30ab45f35b260487c5f
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r-- | src/qml/jsruntime/jsruntime.pri | 11 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4context.cpp | 4 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4exception.cpp | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4exception_gcc.cpp | 100 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4exception_p.h | 1 |
5 files changed, 56 insertions, 65 deletions
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index 1739765009..88cd3a99b0 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -112,12 +112,11 @@ linux*|mac { LIBS += -ldl } -# Only on Android/ARM at the moment, because only there we have issues -# replacing __gnu_Unwind_Find_exidx with our own implementation, -# and thus require static libgcc linkage. -android:equals(QT_ARCH, "arm"):*g++* { - static_libgcc = $$system($$QMAKE_CXX -print-file-name=libgcc.a) - LIBS += $$static_libgcc +!win32:!ios { + *g++*:equals(QT_ARCH, "arm") { + static_libgcc = $$system($$QMAKE_CXX -print-file-name=libgcc.a) + LIBS += $$static_libgcc + } SOURCES += $$PWD/qv4exception_gcc.cpp DEFINES += V4_CXX_ABI_EXCEPTION } diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 78bf662c26..4bba0bfbd1 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -648,7 +648,7 @@ void ExecutionContext::throwUnimplemented(const QString &message) ReturnedValue ExecutionContext::catchException(StackTrace *trace) { if (!engine->hasException) - throw; + Exception::rethrow(); while (engine->current != this) engine->popContext(); if (trace) @@ -666,7 +666,7 @@ void ExecutionContext::rethrowException() while (engine->current != this) engine->popContext(); } - throw; + Exception::rethrow(); } void ExecutionContext::throwReferenceError(const ValueRef value) diff --git a/src/qml/jsruntime/qv4exception.cpp b/src/qml/jsruntime/qv4exception.cpp index f55dc949a9..8cee1535d4 100644 --- a/src/qml/jsruntime/qv4exception.cpp +++ b/src/qml/jsruntime/qv4exception.cpp @@ -98,6 +98,11 @@ void Exception::throwException(ExecutionContext *context, const ValueRef value) } #if !defined(V4_CXX_ABI_EXCEPTION) +void Exception::rethrow() +{ + throw; +} + struct DummyException {}; diff --git a/src/qml/jsruntime/qv4exception_gcc.cpp b/src/qml/jsruntime/qv4exception_gcc.cpp index 0d230ea3fb..d3c406f5a3 100644 --- a/src/qml/jsruntime/qv4exception_gcc.cpp +++ b/src/qml/jsruntime/qv4exception_gcc.cpp @@ -41,24 +41,14 @@ #include "qv4exception_p.h" -#include <private/qv4scopedvalue_p.h> +// On arm we link libgcc statically and want to avoid exporting the _Unwind* symbols +#if defined(Q_PROCESSOR_ARM) +#define HIDE_EXPORTS +#endif + #include <unwind.h> -#include <cxxabi.h> -#include <bits/atomic_word.h> -#include <typeinfo> #include <exception> -/* - * This is a little bit hacky as it relies on the fact that exceptions are - * reference counted in libstdc++ and that affects the layout of the standardized - * cxa_exception, making it bigger. LLVM's libcxxabi stores the reference count - * differently, so this here is entirely GNU libstdc++ specific. - * - * Eliminating this dependency is doable but requires replacing the use of C++ exceptions - * with foreign exceptions (a different exception class) and then using __cxa_get_globals - * to get hold of the exception inside the catch (...). AFAICS that would be portable. - */ - namespace { // 2.1.1 from http://mentorembedded.github.io/cxx-abi/abi-eh.html @@ -82,67 +72,63 @@ struct cxa_exception { _Unwind_Exception unwindHeader; }; -// This is what libstdc++ actually allocates -struct gcc_refcounted_compatible_exception { - _Atomic_word refCount; - cxa_exception x; +struct cxa_eh_globals +{ + cxa_exception *caughtExceptions; + unsigned int uncaughtExceptions; +#ifdef __ARM_EABI_UNWINDER__ + cxa_exception* propagatingExceptions; +#endif }; } +extern "C" cxa_eh_globals *__cxa_get_globals(); + static void exception_cleanup(_Unwind_Reason_Code, _Unwind_Exception *ex) { - gcc_refcounted_compatible_exception *exception = reinterpret_cast<gcc_refcounted_compatible_exception *>(ex + 1) - 1; - if (!--exception->refCount) { - if (exception->x.exceptionDestructor) - exception->x.exceptionDestructor(ex + 1); - abi::__cxa_free_exception(ex + 1); - } + free(ex); } -struct DummyException -{ - virtual ~DummyException() {} -}; +QT_BEGIN_NAMESPACE -static void exception_destructor(void *ex) +using namespace QV4; + +void Exception::rethrow() { - reinterpret_cast<DummyException *>(ex)->~DummyException(); -} + cxa_eh_globals *globals = __cxa_get_globals(); + cxa_exception *exception = globals->caughtExceptions; -QT_BEGIN_NAMESPACE + // Make sure we only re-throw our foreign exceptions. For general re-throw + // we'd need different code. +#ifndef __ARM_EABI_UNWINDER__ + Q_ASSERT(exception->unwindHeader.exception_class == 0x514d4c4a53563400); // QMLJSV40 +#endif -using namespace QV4; + globals->caughtExceptions = 0; + _Unwind_RaiseException(&exception->unwindHeader); +} void Exception::throwInternal() { - void *rawException = abi::__cxa_allocate_exception(sizeof(QV4::Exception)); - gcc_refcounted_compatible_exception *refCountedException = reinterpret_cast<gcc_refcounted_compatible_exception *>(rawException) - 1; - cxa_exception *exception = &refCountedException->x; - - (void)new (rawException) DummyException(); - - refCountedException->refCount = 1; - exception->typeInfo = const_cast<std::type_info*>(&typeid(DummyException)); - exception->exceptionDestructor = &exception_destructor; - exception->unexpectedHandler = std::unexpected; - exception->terminateHandler = std::terminate; - exception->unwindHeader.exception_cleanup = &exception_cleanup; + _Unwind_Exception *exception = (_Unwind_Exception*)malloc(sizeof(_Unwind_Exception)); + memset(exception, 0, sizeof(*exception)); + exception->exception_cleanup = &exception_cleanup; + #ifdef __ARM_EABI_UNWINDER__ - exception->unwindHeader.exception_class[0] = 'G'; - exception->unwindHeader.exception_class[1] = 'N'; - exception->unwindHeader.exception_class[2] = 'U'; - exception->unwindHeader.exception_class[3] = 'C'; - exception->unwindHeader.exception_class[4] = 'C'; - exception->unwindHeader.exception_class[5] = '+'; - exception->unwindHeader.exception_class[6] = '+'; - exception->unwindHeader.exception_class[7] = 0; + exception->exception_class[0] = 'Q'; + exception->exception_class[1] = 'M'; + exception->exception_class[2] = 'L'; + exception->exception_class[3] = 'J'; + exception->exception_class[4] = 'S'; + exception->exception_class[5] = 'V'; + exception->exception_class[6] = '4'; + exception->exception_class[7] = 0; #else - exception->unwindHeader.exception_class = 0x474e5543432b2b00; // GNUCC++0 + exception->exception_class = 0x514d4c4a53563400; // QMLJSV40 #endif - _Unwind_RaiseException(&exception->unwindHeader); - abi::__cxa_begin_catch(rawException); + _Unwind_RaiseException(exception); std::terminate(); } diff --git a/src/qml/jsruntime/qv4exception_p.h b/src/qml/jsruntime/qv4exception_p.h index 1f02d11f65..88896303a8 100644 --- a/src/qml/jsruntime/qv4exception_p.h +++ b/src/qml/jsruntime/qv4exception_p.h @@ -51,6 +51,7 @@ namespace QV4 { struct Q_QML_EXPORT Exception { static void Q_NORETURN throwException(ExecutionContext *throwingContext, const ValueRef exceptionValue); + static void Q_NORETURN rethrow(); private: static void Q_NORETURN throwInternal(); |