diff --git a/emcc.py b/emcc.py index 3ed96d293dd87..4a79f07f030d6 100755 --- a/emcc.py +++ b/emcc.py @@ -2237,6 +2237,8 @@ def check_memory_setting(setting): # so we include then unconditionally when exceptions are enabled. '___cxa_is_pointer_type', '___cxa_can_catch', + '___cxa_increment_exception_refcount', + '___cxa_decrement_exception_refcount', # Emscripten exception handling can generate invoke calls, and they call # setThrew(). We cannot handle this using deps_info as the invokes are not diff --git a/src/library_exceptions.js b/src/library_exceptions.js index 763e106de9f30..0442e0976ce08 100644 --- a/src/library_exceptions.js +++ b/src/library_exceptions.js @@ -37,14 +37,6 @@ var LibraryExceptions = { {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.exceptionDestructor, 'destructor', '*') }}}; }; - this.get_destructor = function() { - return {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.exceptionDestructor, '*') }}}; - }; - - this.set_refcount = function(refcount) { - {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'refcount', 'i32') }}}; - }; - this.set_caught = function (caught) { caught = caught ? 1 : 0; {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.caught, 'caught', 'i8') }}}; @@ -67,33 +59,7 @@ var LibraryExceptions = { this.init = function(type, destructor) { this.set_type(type); this.set_destructor(destructor); - this.set_refcount(0); - this.set_caught(false); - this.set_rethrown(false); } - - this.add_ref = function() { -#if USE_PTHREADS - Atomics.add(HEAP32, (this.ptr + {{{ C_STRUCTS.__cxa_exception.referenceCount }}}) >> 2, 1); -#else - var value = {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'i32') }}}; - {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'value + 1', 'i32') }}}; -#endif - }; - - // Returns true if last reference released. - this.release_ref = function() { -#if USE_PTHREADS - var prev = Atomics.sub(HEAP32, (this.ptr + {{{ C_STRUCTS.__cxa_exception.referenceCount }}}) >> 2, 1); -#else - var prev = {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'i32') }}}; - {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'prev - 1', 'i32') }}}; -#endif -#if ASSERTIONS - assert(prev > 0); -#endif - return prev === 1; - }; }, $CatchInfo__deps: ['$ExceptionInfo', '__cxa_is_pointer_type'], @@ -160,80 +126,13 @@ var LibraryExceptions = { } }, - $exception_addRef: function (info) { -#if EXCEPTION_DEBUG - err('addref ' + info.excPtr); -#endif - info.add_ref(); - }, - - $exception_decRef__deps: ['__cxa_free_exception' -#if EXCEPTION_DEBUG - , '$exceptionLast', '$exceptionCaught' -#endif - ], - $exception_decRef: function(info) { -#if EXCEPTION_DEBUG - err('decref ' + info.excPtr); -#endif - // A rethrown exception can reach refcount 0; it must not be discarded - // Its next handler will clear the rethrown flag and addRef it, prior to - // final decRef and destruction here - if (info.release_ref() && !info.get_rethrown()) { - var destructor = info.get_destructor(); - if (destructor) { - // In Wasm, destructors return 'this' as in ARM - {{{ makeDynCall('ii', 'destructor') }}}(info.excPtr); - } - ___cxa_free_exception(info.excPtr); -#if EXCEPTION_DEBUG - err('decref freeing exception ' + [info.excPtr, exceptionLast, 'stack', exceptionCaught]); -#endif - } - }, - - // Exceptions - __cxa_allocate_exception__sig: 'vi', - __cxa_allocate_exception: function(size) { - // Thrown object is prepended by exception metadata block - return _malloc(size + {{{ C_STRUCTS.__cxa_exception.__size__ }}}) + {{{ C_STRUCTS.__cxa_exception.__size__ }}}; - }, - - __cxa_free_exception__deps: ['$ExceptionInfo'], - __cxa_free_exception__sig: 'vi', - __cxa_free_exception: function(ptr) { -#if ABORTING_MALLOC || ASSERTIONS - try { -#endif - return _free(new ExceptionInfo(ptr).ptr); -#if ABORTING_MALLOC || ASSERTIONS - } catch(e) { -#if ASSERTIONS - err('exception during cxa_free_exception: ' + e); -#endif - } -#endif - }, - - __cxa_increment_exception_refcount__deps: ['$exception_addRef', '$ExceptionInfo'], - __cxa_increment_exception_refcount: function(ptr) { - if (!ptr) return; - exception_addRef(new ExceptionInfo(ptr)); - }, - - __cxa_decrement_exception_refcount__deps: ['$exception_decRef', '$ExceptionInfo'], - __cxa_decrement_exception_refcount: function(ptr) { - if (!ptr) return; - exception_decRef(new ExceptionInfo(ptr)); - }, - // Here, we throw an exception after recording a couple of values that we need to remember // We also remember that it was the last exception thrown as we need to know that later. __cxa_throw__sig: 'viii', __cxa_throw__deps: ['$ExceptionInfo', '$exceptionLast', '$uncaughtExceptionCount'], __cxa_throw: function(ptr, type, destructor) { #if EXCEPTION_DEBUG - err('Compiled code throwing an exception, ' + [ptr,type,destructor]); + err('Compiled code throwing an exception, ' + [ptr.toString(16),type,destructor]); #endif var info = new ExceptionInfo(ptr); // Initialize ExceptionInfo content after it was allocated in __cxa_allocate_exception. @@ -276,8 +175,9 @@ var LibraryExceptions = { return type; }, - __cxa_begin_catch__deps: ['$CatchInfo', '$exceptionCaught', '$exception_addRef', - '$uncaughtExceptionCount'], + __cxa_begin_catch__deps: ['$CatchInfo', '$exceptionCaught', + '$uncaughtExceptionCount', + '__cxa_increment_exception_refcount'], __cxa_begin_catch: function(ptr) { var catchInfo = new CatchInfo(ptr); var info = catchInfo.get_exception_info(); @@ -290,7 +190,7 @@ var LibraryExceptions = { #if EXCEPTION_DEBUG err('cxa_begin_catch ' + [ptr, 'stack', exceptionCaught]); #endif - exception_addRef(info); + ___cxa_increment_exception_refcount(catchInfo.get_base_ptr()); return catchInfo.get_exception_ptr(); }, @@ -298,7 +198,7 @@ var LibraryExceptions = { // and free the exception. Note that if the dynCall on the destructor fails // due to calling apply on undefined, that means that the destructor is // an invalid index into the FUNCTION_TABLE, so something has gone wrong. - __cxa_end_catch__deps: ['$exceptionCaught', '$exceptionLast', '$exception_decRef', + __cxa_end_catch__deps: ['$exceptionCaught', '$exceptionLast', '__cxa_decrement_exception_refcount', '$CatchInfo'], __cxa_end_catch__sig: 'v', __cxa_end_catch: function() { @@ -313,7 +213,7 @@ var LibraryExceptions = { #if EXCEPTION_DEBUG err('cxa_end_catch popped ' + [catchInfo, exceptionLast, 'stack', exceptionCaught]); #endif - exception_decRef(catchInfo.get_exception_info()); + ___cxa_decrement_exception_refcount(catchInfo.get_base_ptr()); catchInfo.free(); exceptionLast = 0; // XXX in decRef? }, @@ -339,13 +239,15 @@ var LibraryExceptions = { throw exception; }, - __cxa_current_primary_exception__deps: ['$exceptionCaught', '$exception_addRef', '$CatchInfo'], + __cxa_current_primary_exception__deps: ['$exceptionCaught', + '__cxa_increment_exception_refcount', + '$CatchInfo'], __cxa_current_primary_exception: function() { if (!exceptionCaught.length) { return 0; } var catchInfo = exceptionCaught[exceptionCaught.length - 1]; - exception_addRef(catchInfo.get_exception_info()); + ___cxa_increment_exception_refcount(catchInfo.get_base_ptr()); return catchInfo.get_base_ptr(); }, diff --git a/system/lib/libcxxabi/src/cxa_exception.h b/system/lib/libcxxabi/src/cxa_exception.h index b6b4dd107b475..be08b971d704d 100644 --- a/system/lib/libcxxabi/src/cxa_exception.h +++ b/system/lib/libcxxabi/src/cxa_exception.h @@ -19,12 +19,13 @@ namespace __cxxabiv1 { -#ifdef __USING_EMSCRIPTEN_EXCEPTIONS__ +#if defined(__EMSCRIPTEN__) && !defined(__USING_WASM_EXCEPTIONS__) struct _LIBCXXABI_HIDDEN __cxa_exception { size_t referenceCount; std::type_info *exceptionType; - void (*exceptionDestructor)(void *); + // In Wasm, destructors return 'this' as in ARM + void *(*exceptionDestructor)(void *); uint8_t caught; uint8_t rethrown; }; diff --git a/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp b/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp new file mode 100644 index 0000000000000..ac6e7cf1a38e7 --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp @@ -0,0 +1,61 @@ +#include +#include + +#include "cxxabi.h" + +#include "cxa_exception.h" +#include "include/atomic_support.h" + +namespace __cxxabiv1 { + +extern "C" { + +// Utility routines +static inline __cxa_exception* cxa_exception_from_thrown_object(void* thrown_object) { + return static_cast<__cxa_exception*>(thrown_object) - 1; +} + +void *__cxa_allocate_exception(size_t thrown_size) _NOEXCEPT { + size_t actual_size = sizeof(__cxa_exception) + thrown_size; + char* buffer = (char*)::malloc(actual_size); + ::memset(buffer, 0, actual_size); + //printf("__cxa_allocate_exception obj=%p header=%p\n", buffer + sizeof(__cxa_exception), buffer); + return buffer + sizeof(__cxa_exception); +} + +void __cxa_free_exception(void *thrown_object) _NOEXCEPT { + __cxa_exception* exception = cxa_exception_from_thrown_object(thrown_object); + //printf("__cxa_free_exception obj=%p header=%p\n", thrown_object, exception); + ::free(exception); +} + +#ifdef __USING_EMSCRIPTEN_EXCEPTIONS__ +void __cxa_increment_exception_refcount(void *thrown_object) _NOEXCEPT { + if (thrown_object != NULL) { + __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); + //printf("__cxa_increment_exception_refcount obj=%p header=%p\n", thrown_object, exception_header); + std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1)); + } +} + +_LIBCXXABI_NO_CFI void __cxa_decrement_exception_refcount(void *thrown_object) _NOEXCEPT { + if (thrown_object != NULL) { + __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); + //printf("__cxa_decrement_exception_refcount obj=%p header=%p rethrown=%d\n", thrown_object, exception_header, exception_header->rethrown); + // A rethrown exception can reach refcount 0; it must not be discarded + // Its next handler will clear the rethrown flag and addRef it, prior to + // final decRef and destruction here + if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0 && !exception_header->rethrown) { + //printf("__cxa_decrement_exception_refcount destructor=%p\n", exception_header->exceptionDestructor); + if (NULL != exception_header->exceptionDestructor) + exception_header->exceptionDestructor(thrown_object); + __cxa_free_exception(thrown_object); + //err('decref freeing exception ' + [info.excPtr, exceptionLast, 'stack', exceptionCaught]); + } + } +} +#endif + +} + +} // abi diff --git a/system/lib/libcxxabi/src/private_typeinfo.cpp b/system/lib/libcxxabi/src/private_typeinfo.cpp index 8072ebb7ef2d0..d65903a794281 100644 --- a/system/lib/libcxxabi/src/private_typeinfo.cpp +++ b/system/lib/libcxxabi/src/private_typeinfo.cpp @@ -42,6 +42,7 @@ // is_equal() with use_strcmp=false so the string names are not compared. #include +#include #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST #include "abort_message.h" @@ -1337,9 +1338,11 @@ __base_class_type_info::search_below_dst(__dynamic_cast_info* info, extern "C" { int __cxa_can_catch(__shim_type_info* catchType, __shim_type_info* excpType, void **thrown) { - //std::type_info *t1 = static_cast(catchType); - //std::type_info *t2 = static_cast(excpType); - //printf("can %s catch %s (%p)?\n", t1->name(), t2->name(), thrown); +#if 0 + std::type_info *t1 = static_cast(catchType); + std::type_info *t2 = static_cast(excpType); + printf("can %s catch %s (%p)?\n", t1->name(), t2->name(), thrown); +#endif void *temp = *thrown; int ret = catchType->can_catch(excpType, temp); @@ -1352,6 +1355,6 @@ int __cxa_is_pointer_type(__shim_type_info* type) { } } -#endif // __USING_EMSCRIPTEN_EXCEPTIONS__ +#endif // !__USING_WASM_EXCEPTIONS__ } // __cxxabiv1 diff --git a/system/lib/standalone/standalone.c b/system/lib/standalone/standalone.c index 119d9436fd906..fdec5b758b25c 100644 --- a/system/lib/standalone/standalone.c +++ b/system/lib/standalone/standalone.c @@ -133,7 +133,3 @@ void __cxa_throw(void* ptr, void* type, void* destructor) { abort(); } - -void* __cxa_allocate_exception(size_t thrown_size) { - abort(); -} diff --git a/tests/other/metadce/hello_libcxx_O2_fexceptions.exports b/tests/other/metadce/hello_libcxx_O2_fexceptions.exports index 33a97d023d92f..ea761c324badd 100644 --- a/tests/other/metadce/hello_libcxx_O2_fexceptions.exports +++ b/tests/other/metadce/hello_libcxx_O2_fexceptions.exports @@ -1,4 +1,6 @@ __cxa_can_catch +__cxa_decrement_exception_refcount +__cxa_increment_exception_refcount __cxa_is_pointer_type __errno_location __indirect_function_table diff --git a/tests/other/metadce/hello_libcxx_O2_fexceptions.imports b/tests/other/metadce/hello_libcxx_O2_fexceptions.imports index 4bcbb0d06aaf4..d7111628d98eb 100644 --- a/tests/other/metadce/hello_libcxx_O2_fexceptions.imports +++ b/tests/other/metadce/hello_libcxx_O2_fexceptions.imports @@ -1,9 +1,7 @@ -env.__cxa_allocate_exception env.__cxa_begin_catch env.__cxa_end_catch env.__cxa_find_matching_catch_2 env.__cxa_find_matching_catch_3 -env.__cxa_free_exception env.__cxa_rethrow env.__cxa_throw env.__cxa_uncaught_exceptions diff --git a/tests/other/metadce/hello_libcxx_O2_fexceptions.sent b/tests/other/metadce/hello_libcxx_O2_fexceptions.sent index 21c54d195a506..8877d50e9917e 100644 --- a/tests/other/metadce/hello_libcxx_O2_fexceptions.sent +++ b/tests/other/metadce/hello_libcxx_O2_fexceptions.sent @@ -1,10 +1,8 @@ -__cxa_allocate_exception __cxa_atexit __cxa_begin_catch __cxa_end_catch __cxa_find_matching_catch_2 __cxa_find_matching_catch_3 -__cxa_free_exception __cxa_rethrow __cxa_throw __cxa_uncaught_exceptions diff --git a/tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.exports b/tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.exports index d08a19d314593..084692fc90d9e 100644 --- a/tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.exports +++ b/tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.exports @@ -1,5 +1,7 @@ __cxa_can_catch +__cxa_decrement_exception_refcount __cxa_demangle +__cxa_increment_exception_refcount __cxa_is_pointer_type __errno_location __indirect_function_table diff --git a/tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.imports b/tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.imports index 4bcbb0d06aaf4..d7111628d98eb 100644 --- a/tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.imports +++ b/tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.imports @@ -1,9 +1,7 @@ -env.__cxa_allocate_exception env.__cxa_begin_catch env.__cxa_end_catch env.__cxa_find_matching_catch_2 env.__cxa_find_matching_catch_3 -env.__cxa_free_exception env.__cxa_rethrow env.__cxa_throw env.__cxa_uncaught_exceptions diff --git a/tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.sent b/tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.sent index 21c54d195a506..8877d50e9917e 100644 --- a/tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.sent +++ b/tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.sent @@ -1,10 +1,8 @@ -__cxa_allocate_exception __cxa_atexit __cxa_begin_catch __cxa_end_catch __cxa_find_matching_catch_2 __cxa_find_matching_catch_3 -__cxa_free_exception __cxa_rethrow __cxa_throw __cxa_uncaught_exceptions diff --git a/tools/deps_info.py b/tools/deps_info.py index 0db2d26bd38b7..b84fae2de0621 100644 --- a/tools/deps_info.py +++ b/tools/deps_info.py @@ -61,9 +61,9 @@ 'SDL_PushEvent': ['malloc', 'free'], 'SDL_free': ['free'], 'SDL_malloc': ['malloc', 'free'], - '__cxa_allocate_exception': ['malloc'], - '__cxa_end_catch': ['setThrew', 'free'], - '__cxa_free_exception': ['free'], + '__cxa_end_catch': ['setThrew', 'free', '__cxa_decrement_exception_refcount'], + '__cxa_current_primary_exception': ['__cxa_increment_exception_refcount'], + '__cxa_begin_catch': ['__cxa_increment_exception_refcount'], '_embind_register_class': ['free'], '_embind_register_enum_value': ['free'], '_embind_register_function': ['free'], @@ -201,7 +201,7 @@ def get_deps_info(): if not settings.EXCEPTION_HANDLING and settings.LINK_AS_CXX: - _deps_info['__cxa_begin_catch'] = ['__cxa_is_pointer_type'] + _deps_info['__cxa_begin_catch'] = ['__cxa_is_pointer_type', '__cxa_increment_exception_refcount'] _deps_info['__cxa_find_matching_catch'] = ['__cxa_can_catch'] _deps_info['__cxa_find_matching_catch_1'] = ['__cxa_can_catch'] _deps_info['__cxa_find_matching_catch_2'] = ['__cxa_can_catch'] diff --git a/tools/system_libs.py b/tools/system_libs.py index 9c7bd30fd3450..52141b7d0601e 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1008,13 +1008,15 @@ def get_files(self): 'private_typeinfo.cpp' ] if self.eh_mode == Exceptions.NONE: - filenames += ['cxa_noexception.cpp'] + filenames += ['cxa_noexception.cpp', 'cxa_exception_emscripten.cpp'] elif self.eh_mode == Exceptions.WASM: filenames += [ 'cxa_exception_storage.cpp', 'cxa_exception.cpp', 'cxa_personality.cpp' ] + elif self.eh_mode == Exceptions.EMSCRIPTEN: + filenames += ['cxa_exception_emscripten.cpp'] return files_in_path( path_components=['system', 'lib', 'libcxxabi', 'src'],