Skip to content

Commit a113c6b

Browse files
sbc100RReverser
authored andcommitted
Move parts of emscripten exception handling to native code. NFC
Specifically, this change moves the allocation and reference counting functions. This saves on code size but more importantly reduces the number and of complexity of imports/exports, which in turn helps with the wasm64 work I've been doing.
1 parent 055c6e8 commit a113c6b

23 files changed

+282
-233
lines changed

emcc.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2791,6 +2791,13 @@ def check_memory_setting(setting):
27912791
'__cxa_is_pointer_type',
27922792
'__cxa_can_catch',
27932793

2794+
# __cxa_begin_catch depends on this but we can't use deps info in this
2795+
# case because that only works for user-level code, and __cxa_begin_catch
2796+
# can be used by the standard library.
2797+
'__cxa_increment_exception_refcount',
2798+
# Same for __cxa_end_catch
2799+
'__cxa_decrement_exception_refcount',
2800+
27942801
# Emscripten exception handling can generate invoke calls, and they call
27952802
# setThrew(). We cannot handle this using deps_info as the invokes are not
27962803
# emitted because of library function usage, but by codegen itself.

src/jsifier.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -292,13 +292,13 @@ function ${name}(${args}) {
292292
warn('To build in STANDALONE_WASM mode without a main(), use emcc --no-entry');
293293
}
294294
}
295+
// We have already warned/errored about this function, so for the purposes of Closure use, mute all type checks
296+
// regarding this function, marking ot a variadic function that can take in anything and return anything.
297+
// (not useful to warn/error multiple times)
298+
LibraryManager.library[symbol + '__docs'] = '/** @type {function(...*):?} */';
295299
if (!RELOCATABLE) {
296300
// emit a stub that will fail at runtime
297301
LibraryManager.library[symbol] = new Function(`err('missing function: ${symbol}'); abort(-1);`);
298-
// We have already warned/errored about this function, so for the purposes of Closure use, mute all type checks
299-
// regarding this function, marking ot a variadic function that can take in anything and return anything.
300-
// (not useful to warn/error multiple times)
301-
LibraryManager.library[symbol + '__docs'] = '/** @type {function(...*):?} */';
302302
} else {
303303
// Create a stub for this symbol which can later be replaced by the
304304
// dynamic linker. If this stub is called before the symbol is

src/library_exceptions.js

Lines changed: 11 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,9 @@ var LibraryExceptions = {
2323
//
2424
// excPtr - Thrown object pointer to wrap. Metadata pointer is calculated from it.
2525
$ExceptionInfo__docs: '/** @constructor */',
26-
$ExceptionInfo__deps: ['__cxa_is_pointer_type',
2726
#if EXCEPTION_DEBUG
28-
'$ptrToString',
27+
$ExceptionInfo__deps: ['$ptrToString'],
2928
#endif
30-
],
3129
$ExceptionInfo: function(excPtr) {
3230
this.excPtr = excPtr;
3331
this.ptr = excPtr - {{{ C_STRUCTS.__cxa_exception.__size__ }}};
@@ -48,10 +46,6 @@ var LibraryExceptions = {
4846
return {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.exceptionDestructor, '*') }}};
4947
};
5048

51-
this.set_refcount = function(refcount) {
52-
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'refcount', 'i32') }}};
53-
};
54-
5549
this.set_caught = function (caught) {
5650
caught = caught ? 1 : 0;
5751
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.caught, 'caught', 'i8') }}};
@@ -78,34 +72,8 @@ var LibraryExceptions = {
7872
this.set_adjusted_ptr(0);
7973
this.set_type(type);
8074
this.set_destructor(destructor);
81-
this.set_refcount(0);
82-
this.set_caught(false);
83-
this.set_rethrown(false);
8475
}
8576

86-
this.add_ref = function() {
87-
#if SHARED_MEMORY
88-
Atomics.add(HEAP32, (this.ptr + {{{ C_STRUCTS.__cxa_exception.referenceCount }}}) >> 2, 1);
89-
#else
90-
var value = {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'i32') }}};
91-
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'value + 1', 'i32') }}};
92-
#endif
93-
};
94-
95-
// Returns true if last reference released.
96-
this.release_ref = function() {
97-
#if SHARED_MEMORY
98-
var prev = Atomics.sub(HEAP32, (this.ptr + {{{ C_STRUCTS.__cxa_exception.referenceCount }}}) >> 2, 1);
99-
#else
100-
var prev = {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'i32') }}};
101-
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'prev - 1', 'i32') }}};
102-
#endif
103-
#if ASSERTIONS
104-
assert(prev > 0);
105-
#endif
106-
return prev === 1;
107-
};
108-
10977
this.set_adjusted_ptr = function(adjustedPtr) {
11078
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.adjustedPtr, 'adjustedPtr', '*') }}};
11179
};
@@ -131,52 +99,6 @@ var LibraryExceptions = {
13199
};
132100
},
133101

134-
$exception_addRef: function (info) {
135-
#if EXCEPTION_DEBUG
136-
dbg('exception_addRef ' + ptrToString(info.excPtr));
137-
#endif
138-
info.add_ref();
139-
},
140-
141-
$exception_decRef__deps: ['__cxa_free_exception'
142-
#if EXCEPTION_DEBUG
143-
, '$exceptionLast', '$exceptionCaught'
144-
#endif
145-
],
146-
$exception_decRef: function(info) {
147-
#if EXCEPTION_DEBUG
148-
dbg('exception_decRef ' + ptrToString(info.excPtr));
149-
#endif
150-
// A rethrown exception can reach refcount 0; it must not be discarded
151-
// Its next handler will clear the rethrown flag and addRef it, prior to
152-
// final decRef and destruction here
153-
if (info.release_ref() && !info.get_rethrown()) {
154-
var destructor = info.get_destructor();
155-
if (destructor) {
156-
// In Wasm, destructors return 'this' as in ARM
157-
{{{ makeDynCall('pp', 'destructor') }}}(info.excPtr);
158-
}
159-
___cxa_free_exception(info.excPtr);
160-
#if EXCEPTION_DEBUG
161-
dbg('decref freeing exception ' + [ptrToString(info.excPtr), exceptionLast, 'stack', exceptionCaught]);
162-
#endif
163-
}
164-
},
165-
166-
__cxa_increment_exception_refcount__deps: ['$exception_addRef', '$ExceptionInfo'],
167-
__cxa_increment_exception_refcount__sig: 'vp',
168-
__cxa_increment_exception_refcount: function(ptr) {
169-
if (!ptr) return;
170-
exception_addRef(new ExceptionInfo(ptr));
171-
},
172-
173-
__cxa_decrement_exception_refcount__deps: ['$exception_decRef', '$ExceptionInfo'],
174-
__cxa_decrement_exception_refcount__sig: 'vp',
175-
__cxa_decrement_exception_refcount: function(ptr) {
176-
if (!ptr) return;
177-
exception_decRef(new ExceptionInfo(ptr));
178-
},
179-
180102
// Here, we throw an exception after recording a couple of values that we need to remember
181103
// We also remember that it was the last exception thrown as we need to know that later.
182104
__cxa_throw__sig: 'vppp',
@@ -224,7 +146,8 @@ var LibraryExceptions = {
224146
return type;
225147
},
226148

227-
__cxa_begin_catch__deps: ['$exceptionCaught', '$exception_addRef', '$uncaughtExceptionCount'],
149+
__cxa_begin_catch__deps: ['$exceptionCaught', '__cxa_increment_exception_refcount',
150+
'$uncaughtExceptionCount'],
228151
__cxa_begin_catch__sig: 'pp',
229152
__cxa_begin_catch: function(ptr) {
230153
var info = new ExceptionInfo(ptr);
@@ -237,15 +160,15 @@ var LibraryExceptions = {
237160
#if EXCEPTION_DEBUG
238161
dbg('__cxa_begin_catch ' + [ptrToString(ptr), 'stack', exceptionCaught]);
239162
#endif
240-
exception_addRef(info);
163+
___cxa_increment_exception_refcount(info.excPtr);
241164
return info.get_exception_ptr();
242165
},
243166

244167
// We're done with a catch. Now, we can run the destructor if there is one
245168
// and free the exception. Note that if the dynCall on the destructor fails
246169
// due to calling apply on undefined, that means that the destructor is
247170
// an invalid index into the FUNCTION_TABLE, so something has gone wrong.
248-
__cxa_end_catch__deps: ['$exceptionCaught', '$exceptionLast', '$exception_decRef'],
171+
__cxa_end_catch__deps: ['$exceptionCaught', '$exceptionLast', '__cxa_decrement_exception_refcount', 'setThrew'],
249172
__cxa_end_catch__sig: 'v',
250173
__cxa_end_catch: function() {
251174
// Clear state flag.
@@ -259,17 +182,18 @@ var LibraryExceptions = {
259182
#if EXCEPTION_DEBUG
260183
dbg('__cxa_end_catch popped ' + [info, exceptionLast, 'stack', exceptionCaught]);
261184
#endif
262-
exception_decRef(info);
185+
___cxa_decrement_exception_refcount(info.excPtr);
263186
exceptionLast = 0; // XXX in decRef?
264187
},
265188

266189
__cxa_get_exception_ptr__deps: ['$ExceptionInfo'],
267190
__cxa_get_exception_ptr__sig: 'pp',
268191
__cxa_get_exception_ptr: function(ptr) {
192+
var rtn = new ExceptionInfo(ptr).get_exception_ptr();
269193
#if EXCEPTION_DEBUG
270-
dbg('__cxa_get_exception_ptr ' + ptrToString(ptr));
194+
err('__cxa_get_exception_ptr ' + ptrToString(ptr) + ' -> ' + ptrToString(rtn));
271195
#endif
272-
return new ExceptionInfo(ptr).get_exception_ptr();
196+
return rtn;
273197
},
274198

275199
__cxa_uncaught_exceptions__deps: ['$uncaughtExceptionCount'],
@@ -285,13 +209,13 @@ var LibraryExceptions = {
285209
throw exception;
286210
},
287211

288-
__cxa_current_primary_exception__deps: ['$exceptionCaught', '$exception_addRef'],
212+
__cxa_current_primary_exception__deps: ['$exceptionCaught', '__cxa_increment_exception_refcount'],
289213
__cxa_current_primary_exception: function() {
290214
if (!exceptionCaught.length) {
291215
return 0;
292216
}
293217
var info = exceptionCaught[exceptionCaught.length - 1];
294-
exception_addRef(info);
218+
___cxa_increment_exception_refcount(info.excPtr);
295219
return info.excPtr;
296220
},
297221

src/library_exceptions_stub.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@
77
var LibraryExceptions = {};
88

99
[
10-
'__cxa_allocate_exception',
11-
'__cxa_free_exception',
12-
'__cxa_increment_exception_refcount',
13-
'__cxa_decrement_exception_refcount',
1410
'__cxa_throw',
1511
'__cxa_rethrow',
1612
'llvm_eh_typeid_for',

0 commit comments

Comments
 (0)