Skip to content

Commit 6b80c5d

Browse files
authored
Define emscripten exception struct in native code. NFC (#14431)
This is really step 1 of moving more of this code to be native.
1 parent f875fc6 commit 6b80c5d

File tree

8 files changed

+59
-47
lines changed

8 files changed

+59
-47
lines changed

src/library_exceptions.js

Lines changed: 17 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,6 @@ var LibraryExceptions = {
99
$exceptionLast: '0',
1010
$exceptionCaught: ' []',
1111

12-
// Static fields for ExceptionInfo class.
13-
$ExceptionInfoAttrs: {
14-
// ExceptionInfo native structure layout.
15-
DESTRUCTOR_OFFSET: 0,
16-
REFCOUNT_OFFSET: Runtime.POINTER_SIZE,
17-
TYPE_OFFSET: Runtime.POINTER_SIZE + 4,
18-
CAUGHT_OFFSET: Runtime.POINTER_SIZE + 8,
19-
RETHROWN_OFFSET: Runtime.POINTER_SIZE + 9,
20-
21-
// Total structure size with padding, should be multiple of allocation alignment.
22-
SIZE: alignMemory(Runtime.POINTER_SIZE + 10)
23-
},
24-
25-
$ExceptionInfo__deps: ['$ExceptionInfoAttrs'],
2612
// This class is the exception metadata which is prepended to each thrown object (in WASM memory).
2713
// It is allocated in one block among with a thrown object in __cxa_allocate_exception and freed
2814
// in ___cxa_free_exception. It roughly corresponds to __cxa_exception structure in libcxxabi. The
@@ -37,44 +23,44 @@ var LibraryExceptions = {
3723
// excPtr - Thrown object pointer to wrap. Metadata pointer is calculated from it.
3824
$ExceptionInfo: function(excPtr) {
3925
this.excPtr = excPtr;
40-
this.ptr = excPtr - ExceptionInfoAttrs.SIZE;
26+
this.ptr = excPtr - {{{ C_STRUCTS.__cxa_exception.__size__ }}};
4127

4228
this.set_type = function(type) {
43-
{{{ makeSetValue('this.ptr', 'ExceptionInfoAttrs.TYPE_OFFSET', 'type', '*') }}};
29+
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.exceptionType, 'type', '*') }}};
4430
};
4531

4632
this.get_type = function() {
47-
return {{{ makeGetValue('this.ptr', 'ExceptionInfoAttrs.TYPE_OFFSET', '*') }}};
33+
return {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.exceptionType, '*') }}};
4834
};
4935

5036
this.set_destructor = function(destructor) {
51-
{{{ makeSetValue('this.ptr', 'ExceptionInfoAttrs.DESTRUCTOR_OFFSET', 'destructor', '*') }}};
37+
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.exceptionDestructor, 'destructor', '*') }}};
5238
};
5339

5440
this.get_destructor = function() {
55-
return {{{ makeGetValue('this.ptr', 'ExceptionInfoAttrs.DESTRUCTOR_OFFSET', '*') }}};
41+
return {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.exceptionDestructor, '*') }}};
5642
};
5743

5844
this.set_refcount = function(refcount) {
59-
{{{ makeSetValue('this.ptr', 'ExceptionInfoAttrs.REFCOUNT_OFFSET', 'refcount', 'i32') }}};
45+
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'refcount', 'i32') }}};
6046
};
6147

6248
this.set_caught = function (caught) {
6349
caught = caught ? 1 : 0;
64-
{{{ makeSetValue('this.ptr', 'ExceptionInfoAttrs.CAUGHT_OFFSET', 'caught', 'i8') }}};
50+
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.caught, 'caught', 'i8') }}};
6551
};
6652

6753
this.get_caught = function () {
68-
return {{{ makeGetValue('this.ptr', 'ExceptionInfoAttrs.CAUGHT_OFFSET', 'i8') }}} != 0;
54+
return {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.caught, 'i8') }}} != 0;
6955
};
7056

7157
this.set_rethrown = function (rethrown) {
7258
rethrown = rethrown ? 1 : 0;
73-
{{{ makeSetValue('this.ptr', 'ExceptionInfoAttrs.RETHROWN_OFFSET', 'rethrown', 'i8') }}};
59+
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.rethrown, 'rethrown', 'i8') }}};
7460
};
7561

7662
this.get_rethrown = function () {
77-
return {{{ makeGetValue('this.ptr', 'ExceptionInfoAttrs.RETHROWN_OFFSET', 'i8') }}} != 0;
63+
return {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.rethrown, 'i8') }}} != 0;
7864
};
7965

8066
// Initialize native structure fields. Should be called once after allocated.
@@ -88,20 +74,20 @@ var LibraryExceptions = {
8874

8975
this.add_ref = function() {
9076
#if USE_PTHREADS
91-
Atomics.add(HEAP32, (this.ptr + ExceptionInfoAttrs.REFCOUNT_OFFSET) >> 2, 1);
77+
Atomics.add(HEAP32, (this.ptr + {{{ C_STRUCTS.__cxa_exception.referenceCount }}}) >> 2, 1);
9278
#else
93-
var value = {{{ makeGetValue('this.ptr', 'ExceptionInfoAttrs.REFCOUNT_OFFSET', 'i32') }}};
94-
{{{ makeSetValue('this.ptr', 'ExceptionInfoAttrs.REFCOUNT_OFFSET', 'value + 1', 'i32') }}};
79+
var value = {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'i32') }}};
80+
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'value + 1', 'i32') }}};
9581
#endif
9682
};
9783

9884
// Returns true if last reference released.
9985
this.release_ref = function() {
10086
#if USE_PTHREADS
101-
var prev = Atomics.sub(HEAP32, (this.ptr + ExceptionInfoAttrs.REFCOUNT_OFFSET) >> 2, 1);
87+
var prev = Atomics.sub(HEAP32, (this.ptr + {{{ C_STRUCTS.__cxa_exception.referenceCount }}}) >> 2, 1);
10288
#else
103-
var prev = {{{ makeGetValue('this.ptr', 'ExceptionInfoAttrs.REFCOUNT_OFFSET', 'i32') }}};
104-
{{{ makeSetValue('this.ptr', 'ExceptionInfoAttrs.REFCOUNT_OFFSET', 'prev - 1', 'i32') }}};
89+
var prev = {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'i32') }}};
90+
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'prev - 1', 'i32') }}};
10591
#endif
10692
#if ASSERTIONS
10793
assert(prev > 0);
@@ -205,11 +191,10 @@ var LibraryExceptions = {
205191
},
206192

207193
// Exceptions
208-
__cxa_allocate_exception__deps: ['$ExceptionInfoAttrs'],
209194
__cxa_allocate_exception__sig: 'vi',
210195
__cxa_allocate_exception: function(size) {
211196
// Thrown object is prepended by exception metadata block
212-
return _malloc(size + ExceptionInfoAttrs.SIZE) + ExceptionInfoAttrs.SIZE;
197+
return _malloc(size + {{{ C_STRUCTS.__cxa_exception.__size__ }}}) + {{{ C_STRUCTS.__cxa_exception.__size__ }}};
213198
},
214199

215200
__cxa_free_exception__deps: ['$ExceptionInfo'],

src/struct_info_internal.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,17 @@
4040
"global_locale"
4141
]
4242
}
43+
},
44+
{
45+
"file": "cxa_exception.h",
46+
"structs": {
47+
"__cxxabiv1::__cxa_exception": [
48+
"exceptionDestructor",
49+
"referenceCount",
50+
"exceptionType",
51+
"caught",
52+
"rethrown"
53+
]
54+
}
4355
}
4456
]

system/lib/libc/musl/arch/emscripten/atomic_arch.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ static inline void a_or_l(volatile void *p, long v)
3636
#define a_cas_p a_cas_p
3737
static inline void *a_cas_p(volatile void *p, void *t, void *s)
3838
{
39-
void* expected = t;
40-
__c11_atomic_compare_exchange_strong((_Atomic uintptr_t*)p, &expected, s, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
41-
return expected;
39+
uintptr_t expected = (uintptr_t)t;
40+
__c11_atomic_compare_exchange_strong((_Atomic uintptr_t*)p, &expected, (uintptr_t)s, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
41+
return (void*)expected;
4242
}
4343

4444
#define a_cas_l a_cas_l

system/lib/libcxxabi/src/cxa_default_handlers.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,11 @@
1313
#include "abort_message.h"
1414
#include "cxxabi.h"
1515
#include "cxa_handlers.h"
16+
#include "cxa_exception.h"
1617
#include "private_typeinfo.h"
1718
#include "include/atomic_support.h"
1819

1920
#if !defined(LIBCXXABI_SILENT_TERMINATE)
20-
// XXX EMSCRIPTEN: this header is not compatible with emscripten exceptions
21-
// and is only needed when !LIBCXXABI_SILENT_TERMINATE
22-
#include "cxa_exception.h"
2321

2422
_LIBCPP_SAFE_STATIC
2523
static const char* cause = "uncaught";

system/lib/libcxxabi/src/cxa_exception.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,19 @@
1717
#include "cxxabi.h"
1818
#include "unwind.h"
1919

20+
namespace __cxxabiv1 {
21+
2022
#ifdef __USING_EMSCRIPTEN_EXCEPTIONS__
21-
// Under emscripten-style exception handling the __cxa_exception type is
22-
// defined in JavaScript in src/library_exceptions.js.
23-
// Any usage of this header would lead to incompatabilities.
24-
#error "Not compatible with emscripten-style exception handling"
25-
#endif
2623

27-
namespace __cxxabiv1 {
24+
struct _LIBCXXABI_HIDDEN __cxa_exception {
25+
size_t referenceCount;
26+
std::type_info *exceptionType;
27+
void (*exceptionDestructor)(void *);
28+
uint8_t caught;
29+
uint8_t rethrown;
30+
};
31+
32+
#else
2833

2934
static const uint64_t kOurExceptionClass = 0x434C4E47432B2B00; // CLNGC++\0
3035
static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1
@@ -171,6 +176,8 @@ extern "C" _LIBCXXABI_FUNC_VIS __cxa_eh_globals * __cxa_get_globals_fast ();
171176
extern "C" _LIBCXXABI_FUNC_VIS void * __cxa_allocate_dependent_exception ();
172177
extern "C" _LIBCXXABI_FUNC_VIS void __cxa_free_dependent_exception (void * dependent_exception);
173178

179+
#endif // !__USING_EMSCRIPTEN_EXCEPTIONS__
180+
174181
} // namespace __cxxabiv1
175182

176183
#endif // _CXA_EXCEPTION_H

system/lib/libcxxabi/src/cxa_handlers.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@
1515
#include "abort_message.h"
1616
#include "cxxabi.h"
1717
#include "cxa_handlers.h"
18-
#ifndef __USING_EMSCRIPTEN_EXCEPTIONS__
1918
#include "cxa_exception.h"
20-
#endif
2119
#include "private_typeinfo.h"
2220
#include "include/atomic_support.h"
2321

tests/reference_struct_info.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,14 @@
12221222
"module": 4,
12231223
"nextInChain": 0
12241224
},
1225+
"__cxa_exception": {
1226+
"__size__": 16,
1227+
"caught": 12,
1228+
"exceptionDestructor": 8,
1229+
"exceptionType": 4,
1230+
"referenceCount": 0,
1231+
"rethrown": 13
1232+
},
12251233
"__wasi_fdstat_t": {
12261234
"__size__": 24,
12271235
"fs_filetype": 0,

tools/gen_struct_info.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ def parse_c_output(lines):
141141

142142
for line in lines:
143143
arg = line[1:].strip()
144+
if '::' in arg:
145+
arg = arg.split('::', 1)[1]
144146
if line[0] == 'K':
145147
# This is a key
146148
key = arg
@@ -252,7 +254,7 @@ def inspect_headers(headers, cflags):
252254
show('Compiling generated code...')
253255

254256
# -Oz optimizes enough to avoid warnings on code size/num locals
255-
cmd = [shared.EMCC] + cflags + ['-o', js_file[1], src_file[1],
257+
cmd = [shared.EMXX] + cflags + ['-o', js_file[1], src_file[1],
256258
'-O0',
257259
'-Werror',
258260
'-Wno-format',
@@ -408,6 +410,8 @@ def main(args):
408410

409411
internal_cflags = [
410412
'-I' + shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'internal'),
413+
'-I' + shared.path_from_root('system', 'lib', 'libcxxabi', 'src'),
414+
'-D__USING_EMSCRIPTEN_EXCEPTIONS__',
411415
]
412416

413417
# Look for structs in all passed headers.

0 commit comments

Comments
 (0)