aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jsifier.js11
-rwxr-xr-xtests/runner.py35
2 files changed, 41 insertions, 5 deletions
diff --git a/src/jsifier.js b/src/jsifier.js
index a01b2655..3d2d022b 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -1448,20 +1448,21 @@ function JSify(data, functionsOnly, givenFunctions) {
var sig = Functions.getSignature(returnType, argsTypes, hasVarArgs);
if (ASM_JS) {
assert(returnType.search(/\("'\[,/) == -1); // XXX need isFunctionType(type, out)
- if (!byPointerForced) {
+ if (!byPointerForced && !funcData.setjmpTable) {
+ // normal asm function pointer call
callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py
} else {
- // This is a forced call, through an invoke_*.
+ // This is a call through an invoke_*, either a forced one, or a setjmp-required one
// note: no need to update argsTypes at this point
- Functions.unimplementedFunctions[callIdent] = sig;
- args.unshift(byPointerForced ? Functions.getIndex(callIdent) : callIdent);
+ if (byPointerForced) Functions.unimplementedFunctions[callIdent] = sig;
+ args.unshift(byPointerForced ? Functions.getIndex(callIdent) : asmCoercion(callIdent, 'i32'));
callIdent = 'invoke_' + sig;
}
} else if (SAFE_DYNCALLS) {
assert(!ASM_JS, 'cannot emit safe dyncalls in asm');
callIdent = '(tempInt=' + callIdent + ',tempInt < 0 || tempInt >= FUNCTION_TABLE.length-1 || !FUNCTION_TABLE[tempInt] ? abort("dyncall error: ' + sig + ' " + FUNCTION_TABLE_NAMES[tempInt]) : tempInt)';
}
- if (!byPointerForced) callIdent = Functions.getTable(sig) + '[' + callIdent + ']';
+ if (!ASM_JS || (!byPointerForced && !funcData.setjmpTable)) callIdent = Functions.getTable(sig) + '[' + callIdent + ']';
}
var ret = callIdent + '(' + args.join(', ') + ')';
diff --git a/tests/runner.py b/tests/runner.py
index 2e01226f..33a2ef67 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -2489,6 +2489,41 @@ Calling longjmp the second time!
Exception execution path of first function! 1
''')
+ def test_longjmp_funcptr(self):
+ src = r'''
+ #include <stdio.h>
+ #include <setjmp.h>
+
+ static jmp_buf buf;
+
+ void (*fp)() = NULL;
+
+ void second(void) {
+ printf("second\n"); // prints
+ longjmp(buf,1); // jumps back to where setjmp was called - making setjmp now return 1
+ }
+
+ void first(void) {
+ fp();
+ printf("first\n"); // does not print
+ }
+
+ int main(int argc, char **argv) {
+ fp = argc == 200 ? NULL : second;
+
+ volatile int x = 0;
+ if ( ! setjmp(buf) ) {
+ x++;
+ first(); // when executed, setjmp returns 0
+ } else { // when longjmp jumps back, setjmp returns 1
+ printf("main: %d\n", x); // prints
+ }
+
+ return 0;
+ }
+ '''
+ self.do_run(src, 'second\nmain: 1\n')
+
def test_setjmp_many(self):
src = r'''
#include <stdio.h>