aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-10-01 15:10:33 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-03 09:24:32 +0200
commit8abf7f5876a48c0879bce628597533c7b6eca9a0 (patch)
treef01dd867b10affb44cefbe050a1f4fcb1a9dfcd1 /src/qml/jsruntime
parenta8796a84fe45aa78123c661aab912f900f2ca0bc (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.pri11
-rw-r--r--src/qml/jsruntime/qv4context.cpp4
-rw-r--r--src/qml/jsruntime/qv4exception.cpp5
-rw-r--r--src/qml/jsruntime/qv4exception_gcc.cpp100
-rw-r--r--src/qml/jsruntime/qv4exception_p.h1
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();