aboutsummaryrefslogtreecommitdiff
path: root/src/jsifier.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/jsifier.js')
-rw-r--r--src/jsifier.js60
1 files changed, 45 insertions, 15 deletions
diff --git a/src/jsifier.js b/src/jsifier.js
index 926be71a..a01b2655 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -701,18 +701,22 @@ function JSify(data, functionsOnly, givenFunctions) {
ret += indent + 'label = ' + getLabelId(block.entries[0]) + '; ' + (SHOW_LABELS ? '/* ' + getOriginalLabelId(block.entries[0]) + ' */' : '') + '\n';
} // otherwise, should have been set before!
if (func.setjmpTable) {
- assert(!ASM_JS, 'asm.js mode does not support setjmp yet');
- var setjmpTable = {};
- 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 },';
- });
- ret += 'dummy: 0';
- ret += '};\n';
+ if (!ASM_JS) {
+ var setjmpTable = {};
+ 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.oldLabel) + '": ' + 'function(value) { label = ' + getLabelId(triple.newLabel) + '; ' + triple.assignTo + ' = value },';
+ });
+ ret += 'dummy: 0';
+ ret += '};\n';
+ } else {
+ ret += 'var setjmpLabel = 0;\n';
+ ret += 'var setjmpTable = ' + RuntimeGenerator.stackAlloc(4 * (MAX_SETJMPS + 1) * 2) + ';\n';
+ }
}
ret += indent + 'while(1) ';
- if (func.setjmpTable) {
+ if (func.setjmpTable && !ASM_JS) {
ret += 'try { ';
}
ret += 'switch(' + asmCoercion('label', 'i32') + ') {\n';
@@ -720,9 +724,19 @@ function JSify(data, functionsOnly, givenFunctions) {
return indent + ' case ' + getLabelId(label.ident) + ': ' + (SHOW_LABELS ? '// ' + getOriginalLabelId(label.ident) : '') + '\n'
+ getLabelLines(label, indent + ' ');
}).join('\n') + '\n';
+ if (func.setjmpTable && ASM_JS) {
+ // emit a label in which we write to the proper local variable, before jumping to the actual label
+ ret += ' case -1111: ';
+ ret += func.setjmpTable.map(function(triple) { // original label, label we created for right after the setjmp, variable setjmp result goes into
+ return 'if ((setjmpLabel|0) == ' + getLabelId(triple.oldLabel) + ') { ' + triple.assignTo + ' = threwValue; label = ' + triple.newLabel + ' }\n';
+ }).join(' else ');
+ if (ASSERTIONS) ret += 'else abort(-3);\n';
+ ret += '__THREW__ = threwValue = 0;\n';
+ ret += 'break;\n';
+ }
if (ASSERTIONS) ret += indent + ' default: assert(0' + (ASM_JS ? '' : ', "bad label: " + label') + ');\n';
ret += indent + '}\n';
- if (func.setjmpTable) {
+ if (func.setjmpTable && !ASM_JS) {
ret += ' } catch(e) { if (!e.longjmp || !(e.id in mySetjmpIds)) throw(e); setjmpTable[setjmpLabels[e.id]](e.value) }';
}
} else {
@@ -1186,7 +1200,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}
item.reloopingJS = ret; // everything but the actual branching (which the relooper will do for us)
item.toLabelJS = getPhiSetsForLabel(phiSets, item.toLabel);
- item.unwindLabelJS = getPhiSetsForLabel(phiSets, item.unwindLabel);
+ item.unwindLabelJS = (ASM_JS ? '__THREW__ = 0;' : '') + getPhiSetsForLabel(phiSets, item.unwindLabel);
ret += 'if (!__THREW__) { ' + item.toLabelJS + makeBranch(item.toLabel, item.currLabelId)
+ ' } else { ' + item.unwindLabelJS + makeBranch(item.unwindLabel, item.currLabelId) + ' }';
return ret;
@@ -1210,6 +1224,12 @@ function JSify(data, functionsOnly, givenFunctions) {
}
});
makeFuncLineActor('landingpad', function(item) {
+ if (DISABLE_EXCEPTION_CATCHING && USE_TYPED_ARRAYS == 2) {
+ ret = makeVarDef(item.assignTo) + '$0 = 0; ' + item.assignTo + '$1 = 0;';
+ item.assignTo = null;
+ if (ASSERTIONS) warnOnce('landingpad, but exceptions are disabled!');
+ return ret;
+ }
var catchTypeArray = item.catchables.map(finalizeLLVMParameter).map(function(element) { return asmCoercion(element, 'i32') }).join(',');
var ret = asmCoercion('___cxa_find_matching_catch(-1, -1' + (catchTypeArray.length > 0 ? ',' + catchTypeArray : '') +')', 'i32');
if (USE_TYPED_ARRAYS == 2) {
@@ -1295,6 +1315,8 @@ function JSify(data, functionsOnly, givenFunctions) {
// We cannot compile assembly. See comment in intertyper.js:'Call'
assert(ident != 'asm', 'Inline assembly cannot be compiled to JavaScript!');
+ if (ASM_JS && funcData.setjmpTable) forceByPointer = true; // in asm.js mode, we must do an invoke for each call
+
ident = Variables.resolveAliasToIdent(ident);
var shortident = ident.slice(1);
var simpleIdent = shortident;
@@ -1449,6 +1471,13 @@ function JSify(data, functionsOnly, givenFunctions) {
ret += '; return 0'; // special case: abort() can happen without return, breaking the return type of asm functions. ensure a return
}
}
+
+ if (ASM_JS && funcData.setjmpTable) {
+ // check if a longjmp was done. If a setjmp happened, check if ours. If ours, go to -111 to handle it.
+ // otherwise, just return - the call to us must also have been an invoke, so the setjmp propagates that way
+ ret += '; if (((__THREW__|0) != 0) & ((threwValue|0) > 0)) { setjmpLabel = _testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable); if ((setjmpLabel|0) > 0) { label = -1111; break } else return ' + (funcData.returnType != 'void' ? asmCoercion('0', funcData.returnType) : '') + ' } __THREW__ = threwValue = 0;\n';
+ }
+
return ret;
}
makeFuncLineActor('getelementptr', function(item) { return finalizeLLVMFunctionCall(item) });
@@ -1458,11 +1487,12 @@ function JSify(data, functionsOnly, givenFunctions) {
});
makeFuncLineActor('unreachable', function(item) {
+ var ret = '';
+ if (ASM_JS && item.funcData.returnType != 'void') ret = 'return ' + asmCoercion('0', item.funcData.returnType) + ';';
if (ASSERTIONS) {
- return ASM_JS ? 'abort()' : 'throw "Reached an unreachable!"';
- } else {
- return ';';
+ ret = (ASM_JS ? 'abort()' : 'throw "Reached an unreachable!"') + ';' + ret;
}
+ return ret || ';';
});
// Final combiner