Skip to content

Commit 9aca4d4

Browse files
committed
Move emscripten exception handling code to native
1 parent ff75baa commit 9aca4d4

14 files changed

+95
-132
lines changed

emcc.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2237,6 +2237,8 @@ def check_memory_setting(setting):
22372237
# so we include then unconditionally when exceptions are enabled.
22382238
'___cxa_is_pointer_type',
22392239
'___cxa_can_catch',
2240+
'___cxa_increment_exception_refcount',
2241+
'___cxa_decrement_exception_refcount',
22402242

22412243
# Emscripten exception handling can generate invoke calls, and they call
22422244
# setThrew(). We cannot handle this using deps_info as the invokes are not

src/library_exceptions.js

Lines changed: 11 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,6 @@ var LibraryExceptions = {
3737
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.exceptionDestructor, 'destructor', '*') }}};
3838
};
3939

40-
this.get_destructor = function() {
41-
return {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.exceptionDestructor, '*') }}};
42-
};
43-
44-
this.set_refcount = function(refcount) {
45-
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'refcount', 'i32') }}};
46-
};
47-
4840
this.set_caught = function (caught) {
4941
caught = caught ? 1 : 0;
5042
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.caught, 'caught', 'i8') }}};
@@ -67,33 +59,7 @@ var LibraryExceptions = {
6759
this.init = function(type, destructor) {
6860
this.set_type(type);
6961
this.set_destructor(destructor);
70-
this.set_refcount(0);
71-
this.set_caught(false);
72-
this.set_rethrown(false);
7362
}
74-
75-
this.add_ref = function() {
76-
#if USE_PTHREADS
77-
Atomics.add(HEAP32, (this.ptr + {{{ C_STRUCTS.__cxa_exception.referenceCount }}}) >> 2, 1);
78-
#else
79-
var value = {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'i32') }}};
80-
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'value + 1', 'i32') }}};
81-
#endif
82-
};
83-
84-
// Returns true if last reference released.
85-
this.release_ref = function() {
86-
#if USE_PTHREADS
87-
var prev = Atomics.sub(HEAP32, (this.ptr + {{{ C_STRUCTS.__cxa_exception.referenceCount }}}) >> 2, 1);
88-
#else
89-
var prev = {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'i32') }}};
90-
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'prev - 1', 'i32') }}};
91-
#endif
92-
#if ASSERTIONS
93-
assert(prev > 0);
94-
#endif
95-
return prev === 1;
96-
};
9763
},
9864

9965
$CatchInfo__deps: ['$ExceptionInfo', '__cxa_is_pointer_type'],
@@ -160,80 +126,13 @@ var LibraryExceptions = {
160126
}
161127
},
162128

163-
$exception_addRef: function (info) {
164-
#if EXCEPTION_DEBUG
165-
err('addref ' + info.excPtr);
166-
#endif
167-
info.add_ref();
168-
},
169-
170-
$exception_decRef__deps: ['__cxa_free_exception'
171-
#if EXCEPTION_DEBUG
172-
, '$exceptionLast', '$exceptionCaught'
173-
#endif
174-
],
175-
$exception_decRef: function(info) {
176-
#if EXCEPTION_DEBUG
177-
err('decref ' + info.excPtr);
178-
#endif
179-
// A rethrown exception can reach refcount 0; it must not be discarded
180-
// Its next handler will clear the rethrown flag and addRef it, prior to
181-
// final decRef and destruction here
182-
if (info.release_ref() && !info.get_rethrown()) {
183-
var destructor = info.get_destructor();
184-
if (destructor) {
185-
// In Wasm, destructors return 'this' as in ARM
186-
{{{ makeDynCall('ii', 'destructor') }}}(info.excPtr);
187-
}
188-
___cxa_free_exception(info.excPtr);
189-
#if EXCEPTION_DEBUG
190-
err('decref freeing exception ' + [info.excPtr, exceptionLast, 'stack', exceptionCaught]);
191-
#endif
192-
}
193-
},
194-
195-
// Exceptions
196-
__cxa_allocate_exception__sig: 'vi',
197-
__cxa_allocate_exception: function(size) {
198-
// Thrown object is prepended by exception metadata block
199-
return _malloc(size + {{{ C_STRUCTS.__cxa_exception.__size__ }}}) + {{{ C_STRUCTS.__cxa_exception.__size__ }}};
200-
},
201-
202-
__cxa_free_exception__deps: ['$ExceptionInfo'],
203-
__cxa_free_exception__sig: 'vi',
204-
__cxa_free_exception: function(ptr) {
205-
#if ABORTING_MALLOC || ASSERTIONS
206-
try {
207-
#endif
208-
return _free(new ExceptionInfo(ptr).ptr);
209-
#if ABORTING_MALLOC || ASSERTIONS
210-
} catch(e) {
211-
#if ASSERTIONS
212-
err('exception during cxa_free_exception: ' + e);
213-
#endif
214-
}
215-
#endif
216-
},
217-
218-
__cxa_increment_exception_refcount__deps: ['$exception_addRef', '$ExceptionInfo'],
219-
__cxa_increment_exception_refcount: function(ptr) {
220-
if (!ptr) return;
221-
exception_addRef(new ExceptionInfo(ptr));
222-
},
223-
224-
__cxa_decrement_exception_refcount__deps: ['$exception_decRef', '$ExceptionInfo'],
225-
__cxa_decrement_exception_refcount: function(ptr) {
226-
if (!ptr) return;
227-
exception_decRef(new ExceptionInfo(ptr));
228-
},
229-
230129
// Here, we throw an exception after recording a couple of values that we need to remember
231130
// We also remember that it was the last exception thrown as we need to know that later.
232131
__cxa_throw__sig: 'viii',
233132
__cxa_throw__deps: ['$ExceptionInfo', '$exceptionLast', '$uncaughtExceptionCount'],
234133
__cxa_throw: function(ptr, type, destructor) {
235134
#if EXCEPTION_DEBUG
236-
err('Compiled code throwing an exception, ' + [ptr,type,destructor]);
135+
err('Compiled code throwing an exception, ' + [ptr.toString(16),type,destructor]);
237136
#endif
238137
var info = new ExceptionInfo(ptr);
239138
// Initialize ExceptionInfo content after it was allocated in __cxa_allocate_exception.
@@ -276,8 +175,9 @@ var LibraryExceptions = {
276175
return type;
277176
},
278177

279-
__cxa_begin_catch__deps: ['$CatchInfo', '$exceptionCaught', '$exception_addRef',
280-
'$uncaughtExceptionCount'],
178+
__cxa_begin_catch__deps: ['$CatchInfo', '$exceptionCaught',
179+
'$uncaughtExceptionCount',
180+
'__cxa_increment_exception_refcount'],
281181
__cxa_begin_catch: function(ptr) {
282182
var catchInfo = new CatchInfo(ptr);
283183
var info = catchInfo.get_exception_info();
@@ -290,15 +190,15 @@ var LibraryExceptions = {
290190
#if EXCEPTION_DEBUG
291191
err('cxa_begin_catch ' + [ptr, 'stack', exceptionCaught]);
292192
#endif
293-
exception_addRef(info);
193+
___cxa_increment_exception_refcount(catchInfo.get_base_ptr());
294194
return catchInfo.get_exception_ptr();
295195
},
296196

297197
// We're done with a catch. Now, we can run the destructor if there is one
298198
// and free the exception. Note that if the dynCall on the destructor fails
299199
// due to calling apply on undefined, that means that the destructor is
300200
// an invalid index into the FUNCTION_TABLE, so something has gone wrong.
301-
__cxa_end_catch__deps: ['$exceptionCaught', '$exceptionLast', '$exception_decRef',
201+
__cxa_end_catch__deps: ['$exceptionCaught', '$exceptionLast', '__cxa_decrement_exception_refcount',
302202
'$CatchInfo'],
303203
__cxa_end_catch__sig: 'v',
304204
__cxa_end_catch: function() {
@@ -313,7 +213,7 @@ var LibraryExceptions = {
313213
#if EXCEPTION_DEBUG
314214
err('cxa_end_catch popped ' + [catchInfo, exceptionLast, 'stack', exceptionCaught]);
315215
#endif
316-
exception_decRef(catchInfo.get_exception_info());
216+
___cxa_decrement_exception_refcount(catchInfo.get_base_ptr());
317217
catchInfo.free();
318218
exceptionLast = 0; // XXX in decRef?
319219
},
@@ -339,13 +239,15 @@ var LibraryExceptions = {
339239
throw exception;
340240
},
341241

342-
__cxa_current_primary_exception__deps: ['$exceptionCaught', '$exception_addRef', '$CatchInfo'],
242+
__cxa_current_primary_exception__deps: ['$exceptionCaught',
243+
'__cxa_increment_exception_refcount',
244+
'$CatchInfo'],
343245
__cxa_current_primary_exception: function() {
344246
if (!exceptionCaught.length) {
345247
return 0;
346248
}
347249
var catchInfo = exceptionCaught[exceptionCaught.length - 1];
348-
exception_addRef(catchInfo.get_exception_info());
250+
___cxa_increment_exception_refcount(catchInfo.get_base_ptr());
349251
return catchInfo.get_base_ptr();
350252
},
351253

system/lib/libcxxabi/src/cxa_exception.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@
1919

2020
namespace __cxxabiv1 {
2121

22-
#ifdef __USING_EMSCRIPTEN_EXCEPTIONS__
22+
#if defined(__EMSCRIPTEN__) && !defined(__USING_WASM_EXCEPTIONS__)
2323

2424
struct _LIBCXXABI_HIDDEN __cxa_exception {
2525
size_t referenceCount;
2626
std::type_info *exceptionType;
27-
void (*exceptionDestructor)(void *);
27+
// In Wasm, destructors return 'this' as in ARM
28+
void *(*exceptionDestructor)(void *);
2829
uint8_t caught;
2930
uint8_t rethrown;
3031
};
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#include <cstring>
2+
#include <cstdio>
3+
4+
#include "cxxabi.h"
5+
6+
#include "cxa_exception.h"
7+
#include "include/atomic_support.h"
8+
9+
namespace __cxxabiv1 {
10+
11+
extern "C" {
12+
13+
// Utility routines
14+
static inline __cxa_exception* cxa_exception_from_thrown_object(void* thrown_object) {
15+
return static_cast<__cxa_exception*>(thrown_object) - 1;
16+
}
17+
18+
void *__cxa_allocate_exception(size_t thrown_size) _NOEXCEPT {
19+
size_t actual_size = sizeof(__cxa_exception) + thrown_size;
20+
char* buffer = (char*)::malloc(actual_size);
21+
::memset(buffer, 0, actual_size);
22+
//printf("__cxa_allocate_exception obj=%p header=%p\n", buffer + sizeof(__cxa_exception), buffer);
23+
return buffer + sizeof(__cxa_exception);
24+
}
25+
26+
void __cxa_free_exception(void *thrown_object) _NOEXCEPT {
27+
__cxa_exception* exception = cxa_exception_from_thrown_object(thrown_object);
28+
//printf("__cxa_free_exception obj=%p header=%p\n", thrown_object, exception);
29+
::free(exception);
30+
}
31+
32+
#ifdef __USING_EMSCRIPTEN_EXCEPTIONS__
33+
void __cxa_increment_exception_refcount(void *thrown_object) _NOEXCEPT {
34+
if (thrown_object != NULL) {
35+
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
36+
//printf("__cxa_increment_exception_refcount obj=%p header=%p\n", thrown_object, exception_header);
37+
std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1));
38+
}
39+
}
40+
41+
_LIBCXXABI_NO_CFI void __cxa_decrement_exception_refcount(void *thrown_object) _NOEXCEPT {
42+
if (thrown_object != NULL) {
43+
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
44+
//printf("__cxa_decrement_exception_refcount obj=%p header=%p rethrown=%d\n", thrown_object, exception_header, exception_header->rethrown);
45+
// A rethrown exception can reach refcount 0; it must not be discarded
46+
// Its next handler will clear the rethrown flag and addRef it, prior to
47+
// final decRef and destruction here
48+
if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0 && !exception_header->rethrown) {
49+
//printf("__cxa_decrement_exception_refcount destructor=%p\n", exception_header->exceptionDestructor);
50+
if (NULL != exception_header->exceptionDestructor)
51+
exception_header->exceptionDestructor(thrown_object);
52+
__cxa_free_exception(thrown_object);
53+
//err('decref freeing exception ' + [info.excPtr, exceptionLast, 'stack', exceptionCaught]);
54+
}
55+
}
56+
}
57+
#endif
58+
59+
}
60+
61+
} // abi

system/lib/libcxxabi/src/private_typeinfo.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
// is_equal() with use_strcmp=false so the string names are not compared.
4343

4444
#include <string.h>
45+
#include <stdio.h>
4546

4647
#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
4748
#include "abort_message.h"
@@ -1337,9 +1338,11 @@ __base_class_type_info::search_below_dst(__dynamic_cast_info* info,
13371338
extern "C" {
13381339

13391340
int __cxa_can_catch(__shim_type_info* catchType, __shim_type_info* excpType, void **thrown) {
1340-
//std::type_info *t1 = static_cast<std::type_info*>(catchType);
1341-
//std::type_info *t2 = static_cast<std::type_info*>(excpType);
1342-
//printf("can %s catch %s (%p)?\n", t1->name(), t2->name(), thrown);
1341+
#if 0
1342+
std::type_info *t1 = static_cast<std::type_info*>(catchType);
1343+
std::type_info *t2 = static_cast<std::type_info*>(excpType);
1344+
printf("can %s catch %s (%p)?\n", t1->name(), t2->name(), thrown);
1345+
#endif
13431346

13441347
void *temp = *thrown;
13451348
int ret = catchType->can_catch(excpType, temp);
@@ -1352,6 +1355,6 @@ int __cxa_is_pointer_type(__shim_type_info* type) {
13521355
}
13531356

13541357
}
1355-
#endif // __USING_EMSCRIPTEN_EXCEPTIONS__
1358+
#endif // !__USING_WASM_EXCEPTIONS__
13561359

13571360
} // __cxxabiv1

system/lib/standalone/standalone.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,3 @@ void
133133
__cxa_throw(void* ptr, void* type, void* destructor) {
134134
abort();
135135
}
136-
137-
void* __cxa_allocate_exception(size_t thrown_size) {
138-
abort();
139-
}

tests/other/metadce/hello_libcxx_O2_fexceptions.exports

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
__cxa_can_catch
2+
__cxa_decrement_exception_refcount
3+
__cxa_increment_exception_refcount
24
__cxa_is_pointer_type
35
__errno_location
46
__indirect_function_table

tests/other/metadce/hello_libcxx_O2_fexceptions.imports

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
env.__cxa_allocate_exception
21
env.__cxa_begin_catch
32
env.__cxa_end_catch
43
env.__cxa_find_matching_catch_2
54
env.__cxa_find_matching_catch_3
6-
env.__cxa_free_exception
75
env.__cxa_rethrow
86
env.__cxa_throw
97
env.__cxa_uncaught_exceptions

tests/other/metadce/hello_libcxx_O2_fexceptions.sent

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
__cxa_allocate_exception
21
__cxa_atexit
32
__cxa_begin_catch
43
__cxa_end_catch
54
__cxa_find_matching_catch_2
65
__cxa_find_matching_catch_3
7-
__cxa_free_exception
86
__cxa_rethrow
97
__cxa_throw
108
__cxa_uncaught_exceptions

tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.exports

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
__cxa_can_catch
2+
__cxa_decrement_exception_refcount
23
__cxa_demangle
4+
__cxa_increment_exception_refcount
35
__cxa_is_pointer_type
46
__errno_location
57
__indirect_function_table

0 commit comments

Comments
 (0)