aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2012-12-07 20:39:09 -0800
committerAlon Zakai <alonzakai@gmail.com>2012-12-07 20:39:09 -0800
commit51480ab006fe32fae1d717d70aea1147190845e5 (patch)
tree4d7e341e9b7ebc0308fd525bdc6e0a122e08dcdb
parentd2f19271a1aaa96a938a3cef6d65f15e934555a0 (diff)
rewrite setjmp code to identify, uniquely, each setjmp and match it to a longjmp. add testcase for #747, works in unoptimized builds
-rw-r--r--src/jsifier.js4
-rw-r--r--src/library.js4
-rw-r--r--src/preamble.js2
-rwxr-xr-xtests/runner.py51
4 files changed, 57 insertions, 4 deletions
diff --git a/src/jsifier.js b/src/jsifier.js
index d4d60cee..8b3c9683 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -620,7 +620,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 mySetjmpIds = {};\n';
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 },';
@@ -639,7 +639,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 (!setjmped) throw(e); setjmped = false; if (!e.longjmp) throw(e); setjmpTable[e.label](e.value) }';
+ ret += ' } catch(e) { if (!e.longjmp || !(e.id in mySetjmpIds)) throw(e); setjmpTable[setjmpLabels[e.id]](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 5a8a9ae7..1bdd840d 100644
--- a/src/library.js
+++ b/src/library.js
@@ -5940,11 +5940,11 @@ LibraryManager.library = {
setjmp__inline: function(env) {
// Save the label
- return '(setjmped = true, ' + makeSetValue(env, '0', 'label', 'i32') + ', 0)';
+ return '(tempInt = setjmpId++, mySetjmpIds[tempInt] = 1, setjmpLabels[tempInt] = label,' + makeSetValue(env, '0', 'tempInt', 'i32') + ', 0)';
},
longjmp: function(env, value) {
- throw { longjmp: true, label: {{{ makeGetValue('env', '0', 'i32') }}}, value: value || 1 };
+ throw { longjmp: true, id: {{{ makeGetValue('env', '0', 'i32') }}}, value: value || 1 };
},
// ==========================================================================
diff --git a/src/preamble.js b/src/preamble.js
index 9342bf2b..0917f977 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -276,6 +276,8 @@ Module['printProfiling'] = printProfiling;
//========================================
var __THREW__ = false; // Used in checking for thrown exceptions.
+var setjmpId = 1; // Used in setjmp/longjmp
+var setjmpLabels = {};
var ABORT = false;
diff --git a/tests/runner.py b/tests/runner.py
index 5cdc9497..6832d41e 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -2130,6 +2130,57 @@ setjmp exception execution path, level: 0
Exiting setjmp function, level: 0
''')
+ def test_longjmp4(self):
+ src = r'''
+ #include <setjmp.h>
+ #include <stdio.h>
+
+ typedef struct {
+ jmp_buf* jmp;
+ } jmp_state;
+
+ void second_func(jmp_state* s);
+
+ void first_func(jmp_state* s) {
+ jmp_buf* prev_jmp = s->jmp;
+ jmp_buf c_jmp;
+ int once = 0;
+
+ if (setjmp(c_jmp) == 0) {
+ printf("Normal execution path of first function!\n");
+
+ s->jmp = &c_jmp;
+ second_func(s);
+ } else {
+ printf("Exception execution path of first function! %d\n", once);
+
+ if (!once) {
+ printf("Calling longjmp the second time!\n");
+ once = 1;
+ longjmp(*(s->jmp), 1);
+ }
+ }
+ }
+
+ void second_func(jmp_state* s) {
+ longjmp(*(s->jmp), 1);
+ }
+
+ int main(int argc, char *argv[]) {
+ jmp_state s;
+ s.jmp = NULL;
+
+ first_func(&s);
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '''Normal execution path of first function!
+Exception execution path of first function! 0
+Calling longjmp the second time!
+Exception execution path of first function! 1
+''')
+
def test_exceptions(self):
if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1")