Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -1323,8 +1323,11 @@ LibraryManager.library = {
// setjmp.h
// ==========================================================================

#if SUPPORT_LONGJMP == 'emscripten'
_emscripten_throw_longjmp__sig: 'v',
_emscripten_throw_longjmp: function() { throw 'longjmp'; },
_emscripten_throw_longjmp: function() { throw Infinity; },
Copy link
Collaborator Author

@juj juj Dec 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if the existence of this whole function should be gated behind

#if SUPPORT_LONGJMP == 'emscripten'

?

Though the function

void emscripten_longjmp(uintptr_t env, int val) {
  setThrew(env, val);
  _emscripten_throw_longjmp();
}

in emscripten_setjmp.c is not gated behind a #ifndef __USING_WASM_SJLJ__, which seems to be at odds against the choice with line 709 in preamble.js (#if SUPPORT_LONGJMP == 'emscripten')?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those both seem like reasonable suggestions. Neither should save any code size benefit I guess because neither should ever be referenced in that case.. but its still good for correctness to prevent accidental references.

#endif

#if !SUPPORT_LONGJMP
#if !INCLUDE_FULL_LIBRARY
// These are in order to print helpful error messages when either longjmp of
Expand All @@ -1340,6 +1343,7 @@ LibraryManager.library = {
// built with SUPPORT_LONGJMP=1, the object file contains references of not
// longjmp but _emscripten_throw_longjmp, which is called from
// emscripten_longjmp.
_emscripten_throw_longjmp: function() { error('longjmp support was disabled (SUPPORT_LONGJMP=0), but it is required by the code (either set SUPPORT_LONGJMP=1, or remove uses of it in the project)'); },
get _emscripten_throw_longjmp__deps() {
return this.longjmp__deps;
},
Expand Down
5 changes: 4 additions & 1 deletion src/library_dylink.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,10 @@ var LibraryDylink = {
return dynCall(sig, arguments[0], Array.prototype.slice.call(arguments, 1));
} catch(e) {
stackRestore(sp);
if (e !== e+0 && e !== 'longjmp') throw e;
// Exceptions thrown from C++ exception will be integer numbers.
// longjmp will throw the number Infinity. Re-throw other types of
// exceptions using a compact and fast check.
if (e !== e+0) throw e;
_setThrew(1, 0);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/preamble.js
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ function makeAbortWrapper(original) {
ABORT // rethrow exception if abort() was called in the original function call above
|| abortWrapperDepth > 1 // rethrow exceptions not caught at the top level if exception catching is enabled; rethrow from exceptions from within callMain
#if SUPPORT_LONGJMP == 'emscripten'
|| e === 'longjmp' // rethrow longjmp if enabled
|| e === Infinity // rethrow longjmp if enabled (In Emscripten EH format longjmp will throw Infinity)
#endif
) {
throw e;
Expand Down
6 changes: 5 additions & 1 deletion system/lib/compiler-rt/emscripten_setjmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ typedef struct TableEntry {

extern void setTempRet0(uint32_t value);
extern void setThrew(uintptr_t threw, int value);
extern void _emscripten_throw_longjmp(); // defined in src/library.js

TableEntry* saveSetjmp(uintptr_t* env, uint32_t label, TableEntry* table, uint32_t size) {
// Not particularly fast: slow table lookup of setjmpId to label. But setjmp
Expand Down Expand Up @@ -63,10 +62,15 @@ uint32_t testSetjmp(uintptr_t id, TableEntry* table, uint32_t size) {
return 0;
}

#ifndef __USING_WASM_SJLJ__

extern void _emscripten_throw_longjmp(); // defined in src/library.js

void emscripten_longjmp(uintptr_t env, int val) {
setThrew(env, val);
_emscripten_throw_longjmp();
}
#endif

#ifdef __USING_WASM_SJLJ__

Expand Down
15 changes: 7 additions & 8 deletions tools/js_manipulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,22 +120,21 @@ def make_invoke(sig):
# wasm won't implicitly convert undefined to 0 in this case.
exceptional_ret = '\n return BigInt(0);' if legal_sig[0] == 'j' else ''
body = '%s%s;' % (ret, make_dynCall(sig, args))
# C++ exceptions are numbers, and longjmp is a string 'longjmp'
if settings.SUPPORT_LONGJMP:
rethrow = "if (e !== e+0 && e !== 'longjmp') throw e;"
else:
rethrow = "if (e !== e+0) throw e;"

# Exceptions thrown from C++ exception will be integer numbers.
# longjmp will throw the number Infinity.
# Create a try-catch guard that rethrows the exception if anything else
# than a Number was thrown. To do that quickly and in a code size conserving
# manner, use the compact test "e !== e+0" to check if e was not a Number.
ret = '''\
function invoke_%s(%s) {
var sp = stackSave();
try {
%s
} catch(e) {
stackRestore(sp);
%s
if (e !== e+0) throw e;
_setThrew(1, 0);%s
}
}''' % (sig, ','.join(args), body, rethrow, exceptional_ret)
}''' % (sig, ','.join(args), body, exceptional_ret)

return ret