diff options
author | Alon Zakai <alonzakai@gmail.com> | 2012-11-22 20:12:04 +0100 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2012-11-22 20:12:04 +0100 |
commit | e7491225c9ab4104342bb3d1079dbbc4f1b326d6 (patch) | |
tree | cdc396e8ae743a4007a6b3784c2ce6c450c80252 | |
parent | 23a27e95809a8437ed553c20eb4b1d6237ddd849 (diff) |
fix setjmp/longjmp to notice if we actually setjmped in the invocation of the function on the stack, so recursive functions can use setjmp/longjmp
-rw-r--r-- | src/jsifier.js | 3 | ||||
-rw-r--r-- | src/library.js | 2 | ||||
-rwxr-xr-x | tests/runner.py | 46 |
3 files changed, 49 insertions, 2 deletions
diff --git a/src/jsifier.js b/src/jsifier.js index 2791c65b..595e057c 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -619,6 +619,7 @@ function JSify(data, functionsOnly, givenFunctions) { } // otherwise, should have been set before! if (func.setjmpTable) { var setjmpTable = {}; + ret += indent + 'var setjmped = false;'; // set to true if we setjmp in this invocation ret += indent + 'var setjmpTable = {'; func.setjmpTable.forEach(function(triple) { // original label, label we created for right after the setjmp, variable setjmp result goes into ret += '"' + getLabelId(triple[0]) + '": ' + 'function(value) { label = ' + getLabelId(triple[1]) + '; ' + triple[2] + ' = value },'; @@ -637,7 +638,7 @@ function JSify(data, functionsOnly, givenFunctions) { }).join('\n'); ret += '\n' + indent + ' default: assert(0, "bad label: " + label);\n' + indent + '}'; if (func.setjmpTable) { - ret += ' } catch(e) { if (!e.longjmp) throw(e); setjmpTable[e.label](e.value) }'; + ret += ' } catch(e) { if (!setjmped) throw(e); if (!e.longjmp) throw(e); setjmpTable[e.label](e.value) }'; } } else { ret += (SHOW_LABELS ? indent + '/* ' + block.entries[0] + ' */' : '') + '\n' + getLabelLines(block.labels[0], indent); diff --git a/src/library.js b/src/library.js index 4b6cb460..12ac0ed0 100644 --- a/src/library.js +++ b/src/library.js @@ -5938,7 +5938,7 @@ LibraryManager.library = { setjmp__inline: function(env) { // Save the label - return '(' + makeSetValue(env, '0', 'label', 'i32') + ', 0)'; + return '(setjmped = true, ' + makeSetValue(env, '0', 'label', 'i32') + ', 0)'; }, longjmp: function(env, value) { diff --git a/tests/runner.py b/tests/runner.py index aa976652..a4bc4944 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -1987,6 +1987,52 @@ c5,de,15,8a else: self.do_run(src, 'second\nmain: 0\n') + def test_longjmp2(self): + src = r''' + #include <setjmp.h> + #include <stdio.h> + + typedef struct { + jmp_buf* jmp; + } jmp_state; + + void stack_manipulate_func(jmp_state* s, int level) { + jmp_buf buf; + + printf("Entering stack_manipulate_func, level: %d\n", level); + + if (level == 0) { + s->jmp = &buf; + if (setjmp(*(s->jmp)) == 0) { + printf("Setjmp normal execution path, level: %d\n", level); + stack_manipulate_func(s, level + 1); + } else { + printf("Setjmp error execution path, level: %d\n", level); + } + } else { + printf("Perform longjmp at level %d\n", level); + longjmp(*(s->jmp), 1); + } + + printf("Exiting stack_manipulate_func, level: %d\n", level); + } + + int main(int argc, char *argv[]) { + jmp_state s; + s.jmp = NULL; + stack_manipulate_func(&s, 0); + + return 0; + } + ''' + self.do_run(src, '''Entering stack_manipulate_func, level: 0 +Setjmp normal execution path, level: 0 +Entering stack_manipulate_func, level: 1 +Perform longjmp at level 1 +Setjmp error execution path, level: 0 +Exiting stack_manipulate_func, level: 0 +''') + def test_exceptions(self): if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1") |