diff --git a/emcc.py b/emcc.py index a1ad29b7228cd..32bdda680fe01 100755 --- a/emcc.py +++ b/emcc.py @@ -2785,6 +2785,13 @@ def check_memory_setting(setting): '__cxa_is_pointer_type', '__cxa_can_catch', + # __cxa_begin_catch depends on this but we can't use deps info in this + # case because that only works for user-level code, and __cxa_begin_catch + # can be used by the standard library. + '__cxa_increment_exception_refcount', + # Same for __cxa_end_catch + '__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 # emitted because of library function usage, but by codegen itself. diff --git a/src/library_exceptions.js b/src/library_exceptions.js index bb3281330a3ea..d64e217cf1aa5 100644 --- a/src/library_exceptions.js +++ b/src/library_exceptions.js @@ -23,11 +23,9 @@ var LibraryExceptions = { // // excPtr - Thrown object pointer to wrap. Metadata pointer is calculated from it. $ExceptionInfo__docs: '/** @constructor */', - $ExceptionInfo__deps: ['__cxa_is_pointer_type', #if EXCEPTION_DEBUG - '$ptrToString', + $ExceptionInfo__deps: ['$ptrToString'], #endif - ], $ExceptionInfo: function(excPtr) { this.excPtr = excPtr; this.ptr = excPtr - {{{ C_STRUCTS.__cxa_exception.__size__ }}}; @@ -48,10 +46,6 @@ var LibraryExceptions = { 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') }}}; @@ -78,34 +72,8 @@ var LibraryExceptions = { this.set_adjusted_ptr(0); 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 SHARED_MEMORY - 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 SHARED_MEMORY - 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; - }; - this.set_adjusted_ptr = function(adjustedPtr) { {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.adjustedPtr, 'adjustedPtr', '*') }}}; }; @@ -131,52 +99,6 @@ var LibraryExceptions = { }; }, - $exception_addRef: function (info) { -#if EXCEPTION_DEBUG - dbg('exception_addRef ' + ptrToString(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 - dbg('exception_decRef ' + ptrToString(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('pp', 'destructor') }}}(info.excPtr); - } - ___cxa_free_exception(info.excPtr); -#if EXCEPTION_DEBUG - dbg('decref freeing exception ' + [ptrToString(info.excPtr), exceptionLast, 'stack', exceptionCaught]); -#endif - } - }, - - __cxa_increment_exception_refcount__deps: ['$exception_addRef', '$ExceptionInfo'], - __cxa_increment_exception_refcount__sig: 'vp', - __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__sig: 'vp', - __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: 'vppp', @@ -224,7 +146,8 @@ var LibraryExceptions = { return type; }, - __cxa_begin_catch__deps: ['$exceptionCaught', '$exception_addRef', '$uncaughtExceptionCount'], + __cxa_begin_catch__deps: ['$exceptionCaught', '__cxa_increment_exception_refcount', + '$uncaughtExceptionCount'], __cxa_begin_catch__sig: 'pp', __cxa_begin_catch: function(ptr) { var info = new ExceptionInfo(ptr); @@ -237,7 +160,7 @@ var LibraryExceptions = { #if EXCEPTION_DEBUG dbg('__cxa_begin_catch ' + [ptrToString(ptr), 'stack', exceptionCaught]); #endif - exception_addRef(info); + ___cxa_increment_exception_refcount(info.excPtr); return info.get_exception_ptr(); }, @@ -245,7 +168,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', 'setThrew'], __cxa_end_catch__sig: 'v', __cxa_end_catch: function() { // Clear state flag. @@ -259,17 +182,18 @@ var LibraryExceptions = { #if EXCEPTION_DEBUG dbg('__cxa_end_catch popped ' + [info, exceptionLast, 'stack', exceptionCaught]); #endif - exception_decRef(info); + ___cxa_decrement_exception_refcount(info.excPtr); exceptionLast = 0; // XXX in decRef? }, __cxa_get_exception_ptr__deps: ['$ExceptionInfo'], __cxa_get_exception_ptr__sig: 'pp', __cxa_get_exception_ptr: function(ptr) { + var rtn = new ExceptionInfo(ptr).get_exception_ptr(); #if EXCEPTION_DEBUG - dbg('__cxa_get_exception_ptr ' + ptrToString(ptr)); + err('__cxa_get_exception_ptr ' + ptrToString(ptr) + ' -> ' + ptrToString(rtn)); #endif - return new ExceptionInfo(ptr).get_exception_ptr(); + return rtn; }, __cxa_uncaught_exceptions__deps: ['$uncaughtExceptionCount'], @@ -285,13 +209,13 @@ var LibraryExceptions = { throw exception; }, - __cxa_current_primary_exception__deps: ['$exceptionCaught', '$exception_addRef'], + __cxa_current_primary_exception__deps: ['$exceptionCaught', '__cxa_increment_exception_refcount'], __cxa_current_primary_exception: function() { if (!exceptionCaught.length) { return 0; } var info = exceptionCaught[exceptionCaught.length - 1]; - exception_addRef(info); + ___cxa_increment_exception_refcount(info.excPtr); return info.excPtr; }, diff --git a/src/library_exceptions_stub.js b/src/library_exceptions_stub.js index e0a10712498db..16c7e532644c4 100644 --- a/src/library_exceptions_stub.js +++ b/src/library_exceptions_stub.js @@ -7,10 +7,6 @@ var LibraryExceptions = {}; [ - '__cxa_allocate_exception', - '__cxa_free_exception', - '__cxa_increment_exception_refcount', - '__cxa_decrement_exception_refcount', '__cxa_throw', '__cxa_rethrow', 'llvm_eh_typeid_for', diff --git a/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp b/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp index 0e408898c32fc..af7ec0c0452f0 100644 --- a/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp +++ b/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp @@ -1,21 +1,30 @@ -//===------------------- cxa_exception_emscripten.cpp ---------------------===// +//===-------------------- cxa_exception_emscripten.cpp --------------------===// // -// This code contains Emscripten specific code for exception handling. -// Emscripten has two modes of exception handling: Emscripten EH, which uses JS -// glue code, and Wasm EH, which uses the new Wasm exception handling proposal -// and meant to be faster. Code for different modes is demarcated with -// '__USING_EMSCRIPTEN_EXCEPTIONS__' and '__USING_WASM_EXCEPTIONS__'. +// Most code in the file is directly copied from cxa_exception.cpp. +// TODO(sbc): consider merging them +// +// Notable changes: + // __cxa_allocate_exception doesn't add get_cxa_exception_offset +// __cxa_decrement_exception_refcount dosn't call the destructor if rethrown +// Both of these changes are mirrored from the historical JS implemenation of +// thse functions. // //===----------------------------------------------------------------------===// +#include "cxxabi.h" #include "cxa_exception.h" -#include "private_typeinfo.h" -#include -#include -#include -#include +#include "include/atomic_support.h" +#include "fallback_malloc.h" +#include "stdio.h" +#include "assert.h" + +// Define to enable extra debugging on stderr. +#if EXCEPTIONS_DEBUG +#define DEBUG printf +#else +#define DEBUG(...) +#endif -#if !defined(__USING_WASM_EXCEPTIONS__) // Until recently, Rust's `rust_eh_personality` for emscripten referred to this // symbol. If Emscripten doesn't provide it, there will be errors when linking // rust. The rust personality function is never called so we can just abort. @@ -30,121 +39,116 @@ __gxx_personality_v0(int version, _Unwind_Context* context) { abort(); } -#endif // !defined(__USING_WASM_EXCEPTIONS__) -using namespace __cxxabiv1; +namespace __cxxabiv1 { -// Some utility routines are copied from cxa_exception.cpp -static inline __cxa_exception* -cxa_exception_from_thrown_object(void* thrown_object) { - return static_cast<__cxa_exception*>(thrown_object) - 1; +// Utility routines +static +inline +__cxa_exception* +cxa_exception_from_thrown_object(void* thrown_object) +{ + DEBUG("cxa_exception_from_thrown_object %p -> %p\n", + thrown_object, static_cast<__cxa_exception*>(thrown_object) - 1); + return static_cast<__cxa_exception*>(thrown_object) - 1; } // Note: This is never called when exception_header is masquerading as a // __cxa_dependent_exception. -static inline void* -thrown_object_from_cxa_exception(__cxa_exception* exception_header) { - return static_cast(exception_header + 1); +static +inline +void* +thrown_object_from_cxa_exception(__cxa_exception* exception_header) +{ + DEBUG("thrown_object_from_cxa_exception %p -> %p\n", + exception_header, static_cast(exception_header + 1)); + return static_cast(exception_header + 1); } -#if defined(__USING_EMSCRIPTEN_EXCEPTIONS__) || \ - defined(__USING_WASM_EXCEPTIONS__) - -// Get the exception object from the unwind pointer. -// Relies on the structure layout, where the unwind pointer is right in -// front of the user's exception object -static inline __cxa_exception* cxa_exception_from_unwind_exception( - _Unwind_Exception* unwind_exception) { - return cxa_exception_from_thrown_object(unwind_exception + 1); +// Round s up to next multiple of a. +static inline +size_t aligned_allocation_size(size_t s, size_t a) { + return (s + a - 1) & ~(a - 1); } -static inline void* thrown_object_from_unwind_exception( - _Unwind_Exception* unwind_exception) { - __cxa_exception* exception_header = - cxa_exception_from_unwind_exception(unwind_exception); - return thrown_object_from_cxa_exception(exception_header); +static inline +size_t cxa_exception_size_from_exception_thrown_size(size_t size) { + return aligned_allocation_size(size + sizeof (__cxa_exception), + alignof(__cxa_exception)); } extern "C" { -void* __thrown_object_from_unwind_exception( - _Unwind_Exception* unwind_exception) { - return thrown_object_from_unwind_exception(unwind_exception); +// Allocate a __cxa_exception object, and zero-fill it. +// Reserve "thrown_size" bytes on the end for the user's exception +// object. Zero-fill the object. If memory can't be allocated, call +// std::terminate. Return a pointer to the memory to be used for the +// user's exception object. +void *__cxa_allocate_exception(size_t thrown_size) _NOEXCEPT { + size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size); + + char *raw_buffer = + (char *)__aligned_malloc_with_fallback(actual_size); + if (NULL == raw_buffer) + std::terminate(); + __cxa_exception *exception_header = + static_cast<__cxa_exception *>((void *)(raw_buffer)); + ::memset(exception_header, 0, actual_size); + return thrown_object_from_cxa_exception(exception_header); } -// Given a thrown_object, puts the information about its type and message into -// 'type' and 'message' output parameters. 'type' will contain the string -// representation of the type of the exception, e.g., 'int'. 'message' will -// contain the result of 'std::exception::what()' method if the type of the -// exception is a subclass of std::exception; otherwise it will be NULL. The -// caller is responsible for freeing 'type' buffer and also 'message' buffer, if -// it is not NULL. -void __get_exception_message(void* thrown_object, char** type, char** message) { - __cxa_exception* exception_header = - cxa_exception_from_thrown_object(thrown_object); - const __shim_type_info* thrown_type = - static_cast(exception_header->exceptionType); - const char* type_name = thrown_type->name(); - - int status = 0; - char* demangled_buf = __cxa_demangle(type_name, 0, 0, &status); - if (status == 0 && demangled_buf) { - *type = demangled_buf; - } else { - if (demangled_buf) { - free(demangled_buf); - } - *type = (char*)malloc(strlen(type_name) + 1); - strcpy(*type, type_name); - } - - *message = NULL; - const __shim_type_info* catch_type = - static_cast(&typeid(std::exception)); - int can_catch = catch_type->can_catch(thrown_type, thrown_object); - if (can_catch) { - const char* what = - static_cast(thrown_object)->what(); - *message = (char*)malloc(strlen(what) + 1); - strcpy(*message, what); - } -} -// Returns a message saying that execution was terminated due to an exception. -// This message is freshly malloc'd and should be freed. -char* __get_exception_terminate_message(void* thrown_object) { - char* type; - char* message; - __get_exception_message(thrown_object, &type, &message); - char* result; - if (message != NULL) { - asprintf( - &result, "terminating with uncaught exception %s: %s", type, message); - free(message); - } else { - asprintf(&result, "terminating with uncaught exception of type %s", type); - } - free(type); - return result; -} +// Free a __cxa_exception object allocated with __cxa_allocate_exception. +void __cxa_free_exception(void *thrown_object) _NOEXCEPT { + // Compute the size of the padding before the header. + char *raw_buffer = + ((char *)cxa_exception_from_thrown_object(thrown_object)); + __aligned_free_with_fallback((void *)raw_buffer); } -#endif // __USING_EMSCRIPTEN_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__ - -#ifndef __USING_WASM_EXCEPTIONS__ - -namespace __cxxabiv1 { - -void* __cxa_allocate_exception(size_t size) _NOEXCEPT { - // Thrown object is prepended by exception metadata block - __cxa_exception* ex = (__cxa_exception*)malloc(size + sizeof(__cxa_exception)); - return thrown_object_from_cxa_exception(ex); +/* + If thrown_object is not null, atomically increment the referenceCount field + of the __cxa_exception header associated with the thrown object referred to + by thrown_object. + + Requires: If thrown_object is not NULL, it is a native exception. +*/ +void +__cxa_increment_exception_refcount(void *thrown_object) _NOEXCEPT { + if (thrown_object != NULL ) + { + __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); + DEBUG("INC: %p refcnt=%zu\n", thrown_object, exception_header->referenceCount); + std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1)); + } } -void __cxa_free_exception(void *thrown_object) _NOEXCEPT { - free(cxa_exception_from_thrown_object(thrown_object)); +/* + If thrown_object is not null, atomically decrement the referenceCount field + of the __cxa_exception header associated with the thrown object referred to + by thrown_object. If the referenceCount drops to zero, destroy and + deallocate the exception. + + Requires: If thrown_object is not NULL, it is a native exception. +*/ +_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); + DEBUG("DEC: %p refcnt=%zu rethrown=%d\n", thrown_object, + exception_header->referenceCount, exception_header->rethrown); + assert(exception_header->referenceCount > 0); + if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0 && !exception_header->rethrown) + { + DEBUG("DEL: %p\n", thrown_object); + if (NULL != exception_header->exceptionDestructor) + exception_header->exceptionDestructor(thrown_object); + __cxa_free_exception(thrown_object); + } + } } -} +} // extern "C" -#endif // !__USING_WASM_EXCEPTIONS__ +} // abi diff --git a/system/lib/libcxxabi/src/cxa_exception_js_utils.cpp b/system/lib/libcxxabi/src/cxa_exception_js_utils.cpp new file mode 100644 index 0000000000000..e2c61aa0967e5 --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_exception_js_utils.cpp @@ -0,0 +1,105 @@ +#include "cxxabi.h" + +#include "cxa_exception.h" +#include "private_typeinfo.h" +#include +// #include +// #include +#include + +namespace __cxxabiv1 { + +// Utility routines +static +inline +__cxa_exception* +cxa_exception_from_thrown_object(void* thrown_object) +{ + return static_cast<__cxa_exception*>(thrown_object) - 1; +} + +// Note: This is never called when exception_header is masquerading as a +// __cxa_dependent_exception. +static +inline +void* +thrown_object_from_cxa_exception(__cxa_exception* exception_header) +{ + return static_cast(exception_header + 1); +} + +// Get the exception object from the unwind pointer. +// Relies on the structure layout, where the unwind pointer is right in +// front of the user's exception object +static inline __cxa_exception* cxa_exception_from_unwind_exception( + _Unwind_Exception* unwind_exception) { + return cxa_exception_from_thrown_object(unwind_exception + 1); +} + +extern "C" { + +void* __thrown_object_from_unwind_exception( + _Unwind_Exception* unwind_exception) { + __cxa_exception* exception_header = + cxa_exception_from_unwind_exception(unwind_exception); + return thrown_object_from_cxa_exception(exception_header); +} + +// Given a thrown_object, puts the information about its type and message into +// 'type' and 'message' output parameters. 'type' will contain the string +// representation of the type of the exception, e.g., 'int'. 'message' will +// contain the result of 'std::exception::what()' method if the type of the +// exception is a subclass of std::exception; otherwise it will be NULL. The +// caller is responsible for freeing 'type' buffer and also 'message' buffer, if +// it is not NULL. +void __get_exception_message(void* thrown_object, char** type, char** message) { + __cxa_exception* exception_header = + cxa_exception_from_thrown_object(thrown_object); + const __shim_type_info* thrown_type = + static_cast(exception_header->exceptionType); + const char* type_name = thrown_type->name(); + + int status = 0; + char* demangled_buf = __cxa_demangle(type_name, 0, 0, &status); + if (status == 0 && demangled_buf) { + *type = demangled_buf; + } else { + if (demangled_buf) { + free(demangled_buf); + } + *type = (char*)malloc(strlen(type_name) + 1); + strcpy(*type, type_name); + } + + *message = NULL; + const __shim_type_info* catch_type = + static_cast(&typeid(std::exception)); + int can_catch = catch_type->can_catch(thrown_type, thrown_object); + if (can_catch) { + const char* what = + static_cast(thrown_object)->what(); + *message = (char*)malloc(strlen(what) + 1); + strcpy(*message, what); + } +} + +// Returns a message saying that execution was terminated due to an exception. +// This message is freshly malloc'd and should be freed. +char* __get_exception_terminate_message(void* thrown_object) { + char* type; + char* message; + __get_exception_message(thrown_object, &type, &message); + char* result; + if (message != NULL) { + asprintf( + &result, "terminating with uncaught exception %s: %s", type, message); + free(message); + } else { + asprintf(&result, "terminating with uncaught exception of type %s", type); + } + free(type); + return result; +} +} // extern "C" + +} // namespace __cxxabiv1 diff --git a/system/lib/libcxxabi/src/cxa_noexception.cpp b/system/lib/libcxxabi/src/cxa_noexception.cpp index 4a803f72e193e..1097f75866983 100644 --- a/system/lib/libcxxabi/src/cxa_noexception.cpp +++ b/system/lib/libcxxabi/src/cxa_noexception.cpp @@ -49,6 +49,17 @@ __cxa_uncaught_exception() throw() { return false; } unsigned int __cxa_uncaught_exceptions() throw() { return 0; } +#if __EMSCRIPTEN__ +// Under emscripten this code is also linked when building when +// DISABLE_EXCEPTION_CATCHING is set but DISABLE_EXCEPTION_THROWING is not. +// TODO(sbc): Perhaps just call std::terminate here. It could +// just be some test code that needs updating. +void *__cxa_allocate_exception(size_t thrown_size) _NOEXCEPT { + char* allocation = (char*)malloc(thrown_size + sizeof(__cxa_exception)); + return allocation + sizeof(__cxa_exception); +} +#endif + } // extern "C" // provide dummy implementations for the 'no exceptions' case. diff --git a/system/lib/standalone/standalone.c b/system/lib/standalone/standalone.c index 7f2185e8da8da..43a446e14fd78 100644 --- a/system/lib/standalone/standalone.c +++ b/system/lib/standalone/standalone.c @@ -171,11 +171,6 @@ void __cxa_throw(void* ptr, void* type, void* destructor) { abort(); } -__attribute__((__weak__)) -void* __cxa_allocate_exception(size_t thrown_size) { - abort(); -} - // WasmFS integration. We stub out file preloading and such, that are not // expected to work anyhow. diff --git a/test/core/test_exceptions_primary.cpp b/test/core/test_exceptions_primary.cpp index 511b7eafa357d..70c35edbd6826 100644 --- a/test/core/test_exceptions_primary.cpp +++ b/test/core/test_exceptions_primary.cpp @@ -9,6 +9,7 @@ #include // std::logic_error int main () { + std::cout << "in main\n"; std::exception_ptr p; try { throw std::logic_error("some logic_error exception"); // throws @@ -20,7 +21,7 @@ int main () { std::cout << "(after exception)\n"; try { - std::rethrow_exception (p); + std::rethrow_exception(p); } catch (const std::exception& e) { std::cout << "exception caught: " << e.what() << '\n'; } diff --git a/test/no_this_in_dyncall.out b/test/no_this_in_dyncall.out index f70d7bba4ae1f..d81cc0710eb6c 100644 --- a/test/no_this_in_dyncall.out +++ b/test/no_this_in_dyncall.out @@ -1 +1 @@ -42 \ No newline at end of file +42 diff --git a/test/other/metadce/test_metadce_cxx_ctors1.exports b/test/other/metadce/test_metadce_cxx_ctors1.exports index 7590b6e0dd3f1..f4dc65925fb0b 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.exports +++ b/test/other/metadce/test_metadce_cxx_ctors1.exports @@ -1,3 +1,4 @@ +__cxa_increment_exception_refcount __cxa_is_pointer_type __errno_location __indirect_function_table diff --git a/test/other/metadce/test_metadce_cxx_ctors2.exports b/test/other/metadce/test_metadce_cxx_ctors2.exports index 0605207136d30..183246153c0dd 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.exports +++ b/test/other/metadce/test_metadce_cxx_ctors2.exports @@ -1,3 +1,4 @@ +__cxa_increment_exception_refcount __cxa_is_pointer_type __errno_location __indirect_function_table diff --git a/test/other/metadce/test_metadce_cxx_except.exports b/test/other/metadce/test_metadce_cxx_except.exports index 3f04dd4390620..0697b34554a59 100644 --- a/test/other/metadce/test_metadce_cxx_except.exports +++ b/test/other/metadce/test_metadce_cxx_except.exports @@ -1,5 +1,7 @@ __cxa_can_catch +__cxa_decrement_exception_refcount __cxa_free_exception +__cxa_increment_exception_refcount __cxa_is_pointer_type __errno_location __indirect_function_table diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index 76cb23dce88c3..556009c26d005 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -30731 +30647 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index 1dabda97be1a0..e002babd75bc5 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -165312 +166229 diff --git a/test/other/metadce/test_metadce_cxx_mangle.exports b/test/other/metadce/test_metadce_cxx_mangle.exports index d517a701b28ff..2a14e2cb1fbda 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.exports +++ b/test/other/metadce/test_metadce_cxx_mangle.exports @@ -1,6 +1,8 @@ __cxa_can_catch +__cxa_decrement_exception_refcount __cxa_demangle __cxa_free_exception +__cxa_increment_exception_refcount __cxa_is_pointer_type __errno_location __indirect_function_table diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index f27a5fc2f515d..0f8b4a91ce346 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -30736 +30651 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index 66fd4fb1993fd..50931b6ce6811 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -220408 +221325 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.exports b/test/other/metadce/test_metadce_cxx_noexcept.exports index 7590b6e0dd3f1..f4dc65925fb0b 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.exports +++ b/test/other/metadce/test_metadce_cxx_noexcept.exports @@ -1,3 +1,4 @@ +__cxa_increment_exception_refcount __cxa_is_pointer_type __errno_location __indirect_function_table diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index 5a83e94204ad0..a17c777bce2e8 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -26205 +26122 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index f4b7350835a3f..79e609efbb1cd 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126251 +126371 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index 4146d1bfbc386..6121d7203d2bf 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20294 +20694 diff --git a/test/test_core.py b/test/test_core.py index 594299cc458a0..dec35b9f46535 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -1262,7 +1262,6 @@ def test_exceptions_off(self): @no_asan('TODO: ASan support in minimal runtime') @no_wasm64('MEMORY64 does not yet support exceptions') def test_exceptions_minimal_runtime(self): - self.set_setting('EXCEPTION_DEBUG') self.set_setting('EXIT_RUNTIME') self.maybe_closure() self.set_setting('MINIMAL_RUNTIME') @@ -1273,6 +1272,7 @@ def test_exceptions_minimal_runtime(self): self.set_setting('DISABLE_EXCEPTION_CATCHING', 0) self.do_run_from_file(test_file('core/test_exceptions.cpp'), test_file('core/test_exceptions_caught.out')) + self.set_setting('EXCEPTION_DEBUG') self.set_setting('DISABLE_EXCEPTION_CATCHING') self.do_run_from_file(test_file('core/test_exceptions.cpp'), test_file('core/test_exceptions_uncaught.out'), assert_returncode=NON_ZERO) diff --git a/test/test_other.py b/test/test_other.py index 7d70fb9c13768..e40d929cdb118 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13011,7 +13011,7 @@ def test_rust_gxx_personality_v0(self): return 0; } } - ''', assert_returncode=NON_ZERO) + ''', assert_returncode=NON_ZERO, emcc_args=['-fexceptions']) def test_bigint64array_polyfill(self): bigint64array = read_file(path_from_root('src/polyfill/bigint64array.js')) diff --git a/tools/deps_info.py b/tools/deps_info.py index 4d5f9a557019b..1bc56aa76a819 100644 --- a/tools/deps_info.py +++ b/tools/deps_info.py @@ -185,18 +185,16 @@ def append_deps_info(js_symbol_deps): def get_deps_info(): if not settings.WASM_EXCEPTIONS and settings.LINK_AS_CXX: - _deps_info['__cxa_begin_catch'] = ['__cxa_is_pointer_type', '__cxa_free_exception'] - _deps_info['__cxa_throw'] = ['__cxa_is_pointer_type'] - _deps_info['__cxa_find_matching_catch'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_1'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_2'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_3'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_4'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_5'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_6'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_7'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_8'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_9'] = ['__cxa_can_catch', 'setTempRet0'] + _deps_info['__cxa_end_catch'] = ['setThrew', '__cxa_decrement_exception_refcount'] + base_js_exception_deps = [ + '__cxa_is_pointer_type', + '__cxa_increment_exception_refcount', + ] + _deps_info['__cxa_throw'] = base_js_exception_deps + _deps_info['__cxa_begin_catch'] = base_js_exception_deps + _deps_info['__cxa_find_matching_catch'] = base_js_exception_deps + ['__cxa_can_catch', 'setTempRet0'] + for i in range(1, 10): + _deps_info['__cxa_find_matching_catch_%d' % i] = _deps_info['__cxa_find_matching_catch'] if settings.PTHREADS and settings.OFFSCREENCANVAS_SUPPORT: _deps_info['pthread_create'] = ['malloc'] if settings.FILESYSTEM and settings.SYSCALLS_REQUIRE_FILESYSTEM: diff --git a/tools/system_libs.py b/tools/system_libs.py index b0cca903a4963..8098052fbbba8 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1476,16 +1476,20 @@ def get_files(self): 'stdlib_stdexcept.cpp', 'stdlib_typeinfo.cpp', 'private_typeinfo.cpp', - 'cxa_exception_emscripten.cpp', + 'cxa_exception_js_utils.cpp', ] if self.eh_mode == Exceptions.NONE: filenames += ['cxa_noexception.cpp'] + elif self.eh_mode == Exceptions.EMSCRIPTEN: + filenames += ['cxa_exception_emscripten.cpp'] elif self.eh_mode == Exceptions.WASM: filenames += [ 'cxa_exception_storage.cpp', 'cxa_exception.cpp', 'cxa_personality.cpp' ] + else: + assert False return files_in_path( path='system/lib/libcxxabi/src',