aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js276
-rw-r--r--src/compiler.js26
-rw-r--r--src/intertyper.js40
-rw-r--r--src/jsifier.js75
-rw-r--r--src/library.js273
-rw-r--r--src/modules.js2
-rw-r--r--src/parseTools.js346
-rw-r--r--src/postamble.js4
-rw-r--r--src/preamble.js106
-rw-r--r--src/settings.js10
-rw-r--r--src/shell.html6
-rw-r--r--src/shell.js23
12 files changed, 800 insertions, 387 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index 1c643303..8ded86f1 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -11,11 +11,8 @@ var VAR_EMULATED = 'emulated';
var ENTRY_IDENT = toNiceIdent('%0');
var ENTRY_IDENTS = set(toNiceIdent('%0'), toNiceIdent('%1'));
-function cleanFunc(func) {
- func.lines = func.lines.filter(function(line) { return line.intertype !== null });
- func.labels.forEach(function(label) {
- label.lines = label.lines.filter(function(line) { return line.intertype !== null });
- });
+function recomputeLines(func) {
+ func.lines = func.labels.map(function(label) { return label.lines }).reduce(concatenator, []);
}
// Handy sets
@@ -71,6 +68,7 @@ function analyzer(data, sidePass) {
subItem.endLineNum = null;
subItem.lines = []; // We will fill in the function lines after the legalizer, since it can modify them
subItem.labels = [];
+ subItem.forceEmulated = false;
// no explicit 'entry' label in clang on LLVM 2.8 - most of the time, but not all the time! - so we add one if necessary
if (item.items[i+1].intertype !== 'label') {
@@ -122,10 +120,6 @@ function analyzer(data, sidePass) {
processItem: function(data) {
// Legalization
if (USE_TYPED_ARRAYS == 2) {
- function isIllegalType(type) {
- var bits = getBits(type);
- return bits > 0 && (bits >= 64 || !isPowerOfTwo(bits));
- }
function getLegalVars(base, bits) {
assert(!isNumber(base));
var ret = new Array(Math.ceil(bits/32));
@@ -142,7 +136,7 @@ function analyzer(data, sidePass) {
var ret = new Array(Math.ceil(bits/32));
var i = 0;
while (bits > 0) {
- ret[i] = { ident: parsed[i].toString(), bits: Math.min(32, bits) };
+ ret[i] = { ident: (parsed[i]|0).toString(), bits: Math.min(32, bits) }; // resign all values
bits -= 32;
i++;
}
@@ -184,6 +178,13 @@ function analyzer(data, sidePass) {
i++;
}
}
+ function fixUnfolded(item) {
+ // Unfolded items may need some correction to work properly in the global scope
+ if (item.intertype in MATHOPS) {
+ item.op = item.intertype;
+ item.intertype = 'mathop';
+ }
+ }
data.functions.forEach(function(func) {
// Legalize function params
legalizeFunctionParameters(func.params);
@@ -220,10 +221,29 @@ function analyzer(data, sidePass) {
// accessible through ident$x, and not constants we need to parse then and there)
if (subItem != item && (!(subItem.intertype in UNUNFOLDABLE) ||
(subItem.intertype == 'value' && isNumber(subItem.ident) && isIllegalType(subItem.type)))) {
- var tempIdent = '$$emscripten$temp$' + (tempId++);
- subItem.assignTo = tempIdent;
- unfolded.unshift(subItem);
- return { intertype: 'value', ident: tempIdent, type: subItem.type };
+ if (item.intertype == 'phi') {
+ assert(subItem.intertype == 'value', 'We can only unfold illegal constants in phis');
+ // we must handle this in the phi itself, if we unfold normally it will not be pushed back with the phi
+ } else {
+ var tempIdent = '$$emscripten$temp$' + (tempId++);
+ subItem.assignTo = tempIdent;
+ unfolded.unshift(subItem);
+ fixUnfolded(subItem);
+ return { intertype: 'value', ident: tempIdent, type: subItem.type };
+ }
+ } else if (subItem.intertype == 'switch' && isIllegalType(subItem.type)) {
+ subItem.switchLabels.forEach(function(switchLabel) {
+ if (switchLabel.value[0] != '$') {
+ var tempIdent = '$$emscripten$temp$' + (tempId++);
+ unfolded.unshift({
+ assignTo: tempIdent,
+ intertype: 'value',
+ ident: switchLabel.value,
+ type: subItem.type
+ });
+ switchLabel.value = tempIdent;
+ }
+ });
}
});
if (unfolded.length > 0) {
@@ -270,7 +290,7 @@ function analyzer(data, sidePass) {
continue;
}
// call, return: Return value is in an unlegalized array literal. Not fully optimal.
- case 'call': case 'invoke': {
+ case 'call': {
bits = getBits(value.type);
var elements = getLegalVars(item.assignTo, bits);
var toAdd = [value];
@@ -298,6 +318,12 @@ function analyzer(data, sidePass) {
i++;
continue;
}
+ case 'invoke': {
+ legalizeFunctionParameters(value.params);
+ // We can't add lines after this, since invoke already modifies control flow. So we handle the return in invoke
+ i++;
+ continue;
+ }
case 'value': {
bits = getBits(value.type);
var elements = getLegalVars(item.assignTo, bits);
@@ -355,6 +381,12 @@ function analyzer(data, sidePass) {
var toAdd = [];
var elements = getLegalVars(item.assignTo, bits);
var j = 0;
+ var literalValues = {}; // special handling of literals - we cannot unfold them normally
+ value.params.map(function(param) {
+ if (isNumber(param.value.ident)) {
+ literalValues[param.value.ident] = getLegalLiterals(param.value.ident, bits);
+ }
+ });
elements.forEach(function(element) {
toAdd.push({
intertype: 'phi',
@@ -366,7 +398,7 @@ function analyzer(data, sidePass) {
label: param.label,
value: {
intertype: 'value',
- ident: param.value.ident + '$' + j,
+ ident: (param.value.ident in literalValues) ? literalValues[param.value.ident][j].ident : (param.value.ident + '$' + j),
type: 'i' + element.bits,
}
};
@@ -377,6 +409,10 @@ function analyzer(data, sidePass) {
i += removeAndAdd(label.lines, i, toAdd);
continue;
}
+ case 'switch': {
+ i++;
+ continue; // special case, handled in makeComparison
+ }
case 'bitcast': {
var inType = item.type2;
var outType = item.type;
@@ -387,16 +423,18 @@ function analyzer(data, sidePass) {
}
// fall through
}
- case 'inttoptr': case 'ptrtoint': {
+ case 'inttoptr': case 'ptrtoint': case 'zext': case 'sext': case 'trunc': case 'ashr': case 'lshr': case 'shl': case 'or': case 'and': case 'xor': {
value = {
op: item.intertype,
- param1: item.params[0]
+ variant: item.variant,
+ type: item.type,
+ params: item.params
};
// fall through
}
case 'mathop': {
var toAdd = [];
- var sourceBits = getBits(value.param1.type);
+ var sourceBits = getBits(value.params[0].type);
// All mathops can be parametrized by how many shifts we do, and how big the source is
var shifts = 0;
var targetBits = sourceBits;
@@ -408,11 +446,11 @@ function analyzer(data, sidePass) {
// fall through
}
case 'lshr': {
- shifts = parseInt(value.param2.ident);
+ shifts = parseInt(value.params[1].ident);
break;
}
case 'shl': {
- shifts = -parseInt(value.param2.ident);
+ shifts = -parseInt(value.params[1].ident);
break;
}
case 'sext': {
@@ -420,7 +458,7 @@ function analyzer(data, sidePass) {
// fall through
}
case 'trunc': case 'zext': case 'ptrtoint': {
- targetBits = getBits(value.param2.ident);
+ targetBits = getBits(value.params[1] ? value.params[1].ident : value.type);
break;
}
case 'inttoptr': {
@@ -431,31 +469,35 @@ function analyzer(data, sidePass) {
break;
}
case 'select': {
- sourceBits = targetBits = getBits(value.param2.type);
- var otherElementsA = getLegalVars(value.param2.ident, sourceBits);
- var otherElementsB = getLegalVars(value.param3.ident, sourceBits);
+ sourceBits = targetBits = getBits(value.params[1].type);
+ var otherElementsA = getLegalVars(value.params[1].ident, sourceBits);
+ var otherElementsB = getLegalVars(value.params[2].ident, sourceBits);
processor = function(result, j) {
return {
intertype: 'mathop',
op: 'select',
type: 'i' + otherElementsA[j].bits,
- param1: value.param1,
- param2: { intertype: 'value', ident: otherElementsA[j].ident, type: 'i' + otherElementsA[j].bits },
- param3: { intertype: 'value', ident: otherElementsB[j].ident, type: 'i' + otherElementsB[j].bits }
+ params: [
+ value.params[0],
+ { intertype: 'value', ident: otherElementsA[j].ident, type: 'i' + otherElementsA[j].bits },
+ { intertype: 'value', ident: otherElementsB[j].ident, type: 'i' + otherElementsB[j].bits }
+ ]
};
};
break;
}
case 'or': case 'and': case 'xor': {
- var otherElements = getLegalVars(value.param2.ident, sourceBits);
+ var otherElements = getLegalVars(value.params[1].ident, sourceBits);
processor = function(result, j) {
return {
intertype: 'mathop',
op: value.op,
type: 'i' + otherElements[j].bits,
- param1: result,
- param2: { intertype: 'value', ident: otherElements[j].ident, type: 'i' + otherElements[j].bits }
- };
+ params: [
+ result,
+ { intertype: 'value', ident: otherElements[j].ident, type: 'i' + otherElements[j].bits }
+ ]
+ };
};
break;
}
@@ -471,16 +513,16 @@ function analyzer(data, sidePass) {
var sourceElements;
if (sourceBits <= 32) {
// The input is a legal type
- sourceElements = [{ ident: value.param1.ident, bits: sourceBits }];
+ sourceElements = [{ ident: value.params[0].ident, bits: sourceBits }];
} else {
- sourceElements = getLegalVars(value.param1.ident, sourceBits);
+ sourceElements = getLegalVars(value.params[0].ident, sourceBits);
}
if (!isNumber(shifts)) {
// We can't statically legalize this, do the operation at runtime TODO: optimize
assert(sourceBits == 64, 'TODO: handle nonconstant shifts on != 64 bits');
value.intertype = 'value';
value.ident = 'Runtime.bitshift64(' + sourceElements[0].ident + ', ' +
- sourceElements[1].ident + ',"' + value.op + '",' + value.param2.ident + '$0);' +
+ sourceElements[1].ident + ',"' + value.op + '",' + value.params[1].ident + '$0);' +
'var ' + value.assignTo + '$0 = ' + value.assignTo + '[0], ' + value.assignTo + '$1 = ' + value.assignTo + '[1];';
i++;
continue;
@@ -499,37 +541,43 @@ function analyzer(data, sidePass) {
var result = {
intertype: 'value',
ident: (j + whole >= 0 && j + whole < sourceElements.length) ? sourceElements[j + whole].ident : (signed ? signedFill : '0'),
- param1: (signed && j + whole > sourceElements.length) ? signedKeepAlive : null,
+ params: [(signed && j + whole > sourceElements.length) ? signedKeepAlive : null],
type: 'i32',
};
if (fraction != 0) {
var other = {
intertype: 'value',
ident: (j + sign + whole >= 0 && j + sign + whole < sourceElements.length) ? sourceElements[j + sign + whole].ident : (signed ? signedFill : '0'),
- param1: (signed && j + sign + whole > sourceElements.length) ? signedKeepAlive : null,
+ params: [(signed && j + sign + whole > sourceElements.length) ? signedKeepAlive : null],
type: 'i32',
};
other = {
intertype: 'mathop',
op: shiftOp,
type: 'i32',
- param1: other,
- param2: { intertype: 'value', ident: (32 - fraction).toString(), type: 'i32' }
+ params: [
+ other,
+ { intertype: 'value', ident: (32 - fraction).toString(), type: 'i32' }
+ ]
};
result = {
intertype: 'mathop',
// shifting in 1s from the top is a special case
op: (signed && shifts >= 0 && j + sign + whole >= sourceElements.length) ? 'ashr' : shiftOpReverse,
type: 'i32',
- param1: result,
- param2: { intertype: 'value', ident: fraction.toString(), type: 'i32' }
+ params: [
+ result,
+ { intertype: 'value', ident: fraction.toString(), type: 'i32' }
+ ]
};
result = {
intertype: 'mathop',
op: 'or',
type: 'i32',
- param1: result,
- param2: other
+ params: [
+ result,
+ other
+ ]
}
}
if (targetElements[j].bits < 32 && shifts < 0) {
@@ -538,8 +586,10 @@ function analyzer(data, sidePass) {
intertype: 'mathop',
op: 'and',
type: 'i32',
- param1: result,
- param2: { intertype: 'value', ident: (Math.pow(2, targetElements[j].bits)-1).toString(), type: 'i32' }
+ params: [
+ result,
+ { intertype: 'value', ident: (Math.pow(2, targetElements[j].bits)-1).toString(), type: 'i32' }
+ ]
}
}
if (processor) {
@@ -550,8 +600,11 @@ function analyzer(data, sidePass) {
}
if (targetBits <= 32) {
// We are generating a normal legal type here
- legalValue = { intertype: 'value', ident: targetElements[0].ident, type: 'rawJS' };
- // truncation to smaller than 32 bits has already been done, if necessary
+ legalValue = {
+ intertype: 'value',
+ ident: targetElements[0].ident + (targetBits < 32 ? '&' + (Math.pow(2, targetBits)-1) : ''),
+ type: 'rawJS'
+ };
legalValue.assignTo = item.assignTo;
toAdd.push(legalValue);
}
@@ -857,7 +910,7 @@ function analyzer(data, sidePass) {
variable.impl = VAR_EMULATED;
} else if (variable.origin == 'funcparam') {
variable.impl = VAR_EMULATED;
- } else if (variable.type == 'i64*' && I64_MODE == 1) {
+ } else if (variable.type == 'i64*' && USE_TYPED_ARRAYS == 2) {
variable.impl = VAR_EMULATED;
} else if (MICRO_OPTS && variable.pointingLevels === 0) {
// A simple int value, can be implemented as a native variable
@@ -1098,23 +1151,65 @@ function analyzer(data, sidePass) {
}
});
+ function operateOnLabels(line, func) {
+ function process(item, id) {
+ ['label', 'labelTrue', 'labelFalse', 'toLabel', 'unwindLabel', 'defaultLabel'].forEach(function(id) {
+ if (item[id]) {
+ func(item, id);
+ }
+ });
+ }
+ if (line.intertype in BRANCH_INVOKE) {
+ process(line);
+ } else if (line.intertype == 'switch') {
+ process(line);
+ line.switchLabels.forEach(process);
+ }
+ }
+
// Label analyzer
substrate.addActor('LabelAnalyzer', {
processItem: function(item) {
item.functions.forEach(function(func) {
func.labelsDict = {};
func.labelIds = {};
- func.labelIdCounter = 0;
+ func.labelIdsInverse = {};
+ func.labelIds[toNiceIdent('%0')] = 0;
+ func.labelIdsInverse[0] = toNiceIdent('%0');
+ func.labelIdCounter = 1;
func.labels.forEach(function(label) {
- func.labelsDict[label.ident] = label;
func.labelIds[label.ident] = func.labelIdCounter++;
+ func.labelIdsInverse[func.labelIdCounter-1] = label.ident;
+ });
+
+ // Minify label ids to numeric ids.
+ func.labels.forEach(function(label) {
+ label.ident = func.labelIds[label.ident];
+ label.lines.forEach(function(line) {
+ operateOnLabels(line, function(item, id) {
+ item[id] = func.labelIds[item[id]].toString(); // strings, because we will append as we process
+ });
+ });
+ });
+
+ func.labels.forEach(function(label) {
+ func.labelsDict[label.ident] = label;
+ });
+
+ // Correct phis
+ func.labels.forEach(function(label) {
+ label.lines.forEach(function(phi) {
+ if (phi.intertype == 'phi') {
+ for (var i = 0; i < phi.params.length; i++) {
+ phi.params[i].label = func.labelIds[phi.params[i].label];
+ }
+ }
+ });
});
- func.labelIds[toNiceIdent('%0')] = -1; // entry is always -1
- func.hasIndirectBr = false;
func.lines.forEach(function(line) {
if (line.intertype == 'indirectbr') {
- func.hasIndirectBr = true;
+ func.forceEmulated = true;
}
});
@@ -1129,6 +1224,52 @@ function analyzer(data, sidePass) {
return null;
}
+ // Basic longjmp support, see library.js setjmp/longjmp
+ var setjmp = toNiceIdent('@setjmp');
+ func.setjmpTable = null;
+ for (var i = 0; i < func.labels.length; i++) {
+ var label = func.labels[i];
+ for (var j = 0; j < label.lines.length; j++) {
+ var line = label.lines[j];
+ if (line.intertype == 'call' && line.ident == setjmp) {
+ // Add a new label
+ var oldIdent = label.ident;
+ var newIdent = func.labelIdCounter++;
+ if (!func.setjmpTable) func.setjmpTable = [];
+ func.setjmpTable.push([oldIdent, newIdent, line.assignTo]);
+ func.labels.splice(i+1, 0, {
+ intertype: 'label',
+ ident: newIdent,
+ lineNum: label.lineNum + 0.5,
+ lines: label.lines.slice(j+1)
+ });
+ label.lines = label.lines.slice(0, j+1);
+ label.lines.push({
+ intertype: 'branch',
+ label: toNiceIdent(newIdent),
+ lineNum: line.lineNum + 0.01, // XXX legalizing might confuse this
+ });
+ // Correct phis
+ func.labels.forEach(function(label) {
+ label.lines.forEach(function(phi) {
+ if (phi.intertype == 'phi') {
+ for (var i = 0; i < phi.params.length; i++) {
+ var sourceLabelId = getActualLabelId(phi.params[i].label);
+ if (sourceLabelId == oldIdent) {
+ phi.params[i].label = newIdent;
+ }
+ }
+ }
+ });
+ });
+ }
+ }
+ }
+ if (func.setjmpTable) {
+ func.forceEmulated = true;
+ recomputeLines(func);
+ }
+
if (!MICRO_OPTS) {
// 'Emulate' phis, by doing an if where the phi appears in the .ll. For this
// we need __lastLabel__.
@@ -1223,8 +1364,7 @@ function analyzer(data, sidePass) {
var lines = func.labels[0].lines;
for (var i = 0; i < lines.length; i++) {
var item = lines[i];
- if (!item.assignTo || item.intertype != 'alloca') break;
- assert(isNumber(item.allocatedNum));
+ if (!item.assignTo || item.intertype != 'alloca' || !isNumber(item.allocatedNum)) break;
item.allocatedSize = func.variables[item.assignTo].impl === VAR_EMULATED ?
calcAllocatedSize(item.allocatedType)*item.allocatedNum: 0;
if (USE_TYPED_ARRAYS === 2) {
@@ -1235,7 +1375,7 @@ function analyzer(data, sidePass) {
var index = 0;
for (var i = 0; i < lines.length; i++) {
var item = lines[i];
- if (!item.assignTo || item.intertype != 'alloca') break;
+ if (!item.assignTo || item.intertype != 'alloca' || !isNumber(item.allocatedNum)) break;
item.allocatedIndex = index;
index += item.allocatedSize;
delete item.allocatedSize;
@@ -1260,7 +1400,7 @@ function analyzer(data, sidePass) {
var finishedInitial = false;
for (var i = 0; i < lines.length; i++) {
var item = lines[i];
- if (!item.assignTo || item.intertype != 'alloca') {
+ if (!item.assignTo || item.intertype != 'alloca' || !isNumber(item.allocatedNum)) {
finishedInitial = true;
continue;
}
@@ -1288,22 +1428,6 @@ function analyzer(data, sidePass) {
}
});
- function operateOnLabels(line, func) {
- function process(item, id) {
- ['label', 'labelTrue', 'labelFalse', 'toLabel', 'unwindLabel', 'defaultLabel'].forEach(function(id) {
- if (item[id]) {
- func(item, id);
- }
- });
- }
- if (line.intertype in BRANCH_INVOKE) {
- process(line);
- } else if (line.intertype == 'switch') {
- process(line);
- line.switchLabels.forEach(process);
- }
- }
-
//! @param toLabelId If false, just a dry run - useful to search for labels
function replaceLabels(line, labelIds, toLabelId) {
var ret = [];
@@ -1394,7 +1518,7 @@ function analyzer(data, sidePass) {
label.allOutLabels = [];
});
- // First, find allInLabels
+ // First, find allInLabels. TODO: use typed arrays here to optimize this for memory and speed
var more = true, nextModified, modified = set(getLabelIds(labels));
while (more) {
more = false;
@@ -1445,7 +1569,7 @@ function analyzer(data, sidePass) {
var idCounter = 0;
function makeBlockId(entries) {
idCounter++;
- return entries.join('$') + '$' + idCounter;
+ return '$_$' + idCounter;
}
// There are X main kinds of blocks:
@@ -1745,7 +1869,7 @@ function analyzer(data, sidePass) {
// TODO: each of these can be run in parallel
item.functions.forEach(function(func) {
dprint('relooping', "// relooping function: " + func.ident);
- func.block = makeBlock(func.labels, [toNiceIdent(func.labels[0].ident)], func.labelsDict, func.hasIndirectBr);
+ func.block = makeBlock(func.labels, [toNiceIdent(func.labels[0].ident)], func.labelsDict, func.forceEmulated);
});
return finish();
diff --git a/src/compiler.js b/src/compiler.js
index d37bc68b..2e95552d 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -19,6 +19,7 @@ var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIR
if (ENVIRONMENT_IS_NODE) {
// Expose functionality in the same simple way that the shells work
+ // Note that we pollute the global namespace here, otherwise we break in node
print = function(x) {
process['stdout'].write(x + '\n');
};
@@ -37,26 +38,30 @@ if (ENVIRONMENT_IS_NODE) {
return ret;
};
+ load = function(f) {
+ globalEval(read(f));
+ };
+
arguments_ = process['argv'].slice(2);
} else if (ENVIRONMENT_IS_SHELL) {
// Polyfill over SpiderMonkey/V8 differences
if (!this['read']) {
- read = function(f) { snarf(f) };
+ this['read'] = function(f) { snarf(f) };
}
- if (!this['arguments']) {
+ if (typeof scriptArgs != 'undefined') {
arguments_ = scriptArgs;
- } else {
+ } else if (typeof arguments != 'undefined') {
arguments_ = arguments;
}
} else if (ENVIRONMENT_IS_WEB) {
- print = printErr = function(x) {
+ this['print'] = printErr = function(x) {
console.log(x);
};
- read = function(url) {
+ this['read'] = function(url) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
xhr.send(null);
@@ -69,7 +74,7 @@ if (ENVIRONMENT_IS_NODE) {
} else if (ENVIRONMENT_IS_WORKER) {
// We can do very little here...
- load = importScripts;
+ this['load'] = importScripts;
} else {
throw 'Unknown runtime environment. Where are we?';
@@ -80,17 +85,17 @@ function globalEval(x) {
}
if (typeof load == 'undefined' && typeof read != 'undefined') {
- load = function(f) {
+ this['load'] = function(f) {
globalEval(read(f));
};
}
if (typeof printErr === 'undefined') {
- printErr = function(){};
+ this['printErr'] = function(){};
}
if (typeof print === 'undefined') {
- print = printErr;
+ this['print'] = printErr;
}
// *** Environment setup code ***
@@ -138,7 +143,6 @@ EXPORTED_GLOBALS = set(EXPORTED_GLOBALS);
// Settings sanity checks
assert(!(USE_TYPED_ARRAYS === 2 && QUANTUM_SIZE !== 4), 'For USE_TYPED_ARRAYS == 2, must have normal QUANTUM_SIZE of 4');
-assert(!(USE_TYPED_ARRAYS !== 2 && I64_MODE === 1), 'i64 mode 1 is only supported with typed arrays mode 2');
// Output some info and warnings based on settings
@@ -149,7 +153,7 @@ if (!MICRO_OPTS || !RELOOP || ASSERTIONS || CHECK_SIGNS || CHECK_OVERFLOWS || IN
print('// Note: For maximum-speed code, see "Optimizing Code" on the Emscripten wiki, https://github.com/kripken/emscripten/wiki/Optimizing-Code');
}
-if (DOUBLE_MODE || I64_MODE || CORRECT_SIGNS || CORRECT_OVERFLOWS || CORRECT_ROUNDINGS) {
+if (DOUBLE_MODE || CORRECT_SIGNS || CORRECT_OVERFLOWS || CORRECT_ROUNDINGS) {
print('// Note: Some Emscripten settings may limit the speed of the generated code.');
}
diff --git a/src/intertyper.js b/src/intertyper.js
index 91ad15eb..c5a9583b 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -334,6 +334,8 @@ function intertyper(data, sidePass, baseLineNums) {
return 'Phi';
if (tokensLength >= 3 && token0Text == 'landingpad')
return 'Landingpad';
+ if (token0Text == 'fence')
+ return '/dev/null';
} else if (item.indent === 0) {
if ((tokensLength >= 1 && token0Text.substr(-1) == ':') ||
(tokensLength >= 3 && token1Text == '<label>'))
@@ -728,11 +730,22 @@ function intertyper(data, sidePass, baseLineNums) {
this.forwardItem(item, 'Reintegrator');
}
});
- // 'landingpad' - just a stub implementation
+ // 'landingpad'
substrate.addActor('Landingpad', {
processItem: function(item) {
item.intertype = 'landingpad';
item.type = item.tokens[1].text;
+ item.catchables = [];
+ var catchIdx = findTokenText(item, "catch");
+ if (catchIdx != -1) {
+ do {
+ var nextCatchIdx = findTokenTextAfter(item, "catch", catchIdx+1);
+ if (nextCatchIdx == -1)
+ nextCatchIdx = item.tokens.length;
+ item.catchables.push(parseLLVMSegment(item.tokens.slice(catchIdx+2, nextCatchIdx)));
+ catchIdx = nextCatchIdx;
+ } while (catchIdx != item.tokens.length);
+ }
Types.needAnalysis[item.type] = 0;
this.forwardItem(item, 'Reintegrator');
}
@@ -789,38 +802,39 @@ function intertyper(data, sidePass, baseLineNums) {
}
if (item.tokens[1].text == 'exact') item.tokens.splice(1, 1); // TODO: Implement trap values
var segments = splitTokenList(item.tokens.slice(1));
+ item.params = [];
for (var i = 1; i <= 4; i++) {
if (segments[i-1]) {
if (i > 1 && segments[i-1].length == 1 && segments[0].length > 1 && !isType(segments[i-1][0].text)) {
segments[i-1].unshift(segments[0][0]); // Add the type from the first segment, they are all alike
}
- item['param'+i] = parseLLVMSegment(segments[i-1]);
+ item.params[i-1] = parseLLVMSegment(segments[i-1]);
}
}
if (item.op === 'select') {
- assert(item.param2.type === item.param3.type);
- item.type = item.param2.type;
+ assert(item.params[1].type === item.params[2].type);
+ item.type = item.params[1].type;
} else if (item.op === 'inttoptr' || item.op === 'ptrtoint') {
- item.type = item.param2.type;
+ item.type = item.params[1].type;
} else {
- item.type = item.param1.type;
+ item.type = item.params[0].type;
}
if (item.op != 'ptrtoint') {
- for (var i = 1; i <= 4; i++) {
- if (item['param'+i]) item['param'+i].type = item.type; // All params have the same type, normally
+ for (var i = 0; i < 4; i++) {
+ if (item.params[i]) item.params[i].type = item.type; // All params have the same type, normally
}
}
if (item.op in LLVM.EXTENDS) {
- item.type = item.param2.ident;
- item.param1.type = item.param2.type;
+ item.type = item.params[1].ident;
+ item.params[0].type = item.params[1].type;
// TODO: also remove 2nd param?
}
- if (I64_MODE == 1) {
+ if (USE_TYPED_ARRAYS == 2) {
// Some specific corrections, since 'i64' is special
if (item.op in LLVM.SHIFTS) {
- item.param2.type = 'i32';
+ item.params[1].type = 'i32';
} else if (item.op == 'select') {
- item.param1.type = 'i1';
+ item.params[0].type = 'i1';
}
}
Types.needAnalysis[item.type] = 0;
diff --git a/src/jsifier.js b/src/jsifier.js
index b830fc7c..5ad1573b 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -66,7 +66,7 @@ function JSify(data, functionsOnly, givenFunctions) {
assert(!BUILD_AS_SHARED_LIB, 'Cannot have both INCLUDE_FULL_LIBRARY and BUILD_AS_SHARED_LIB set.')
libFuncsToInclude = [];
for (var key in LibraryManager.library) {
- if (!key.match(/__(deps|postset)$/)) {
+ if (!key.match(/__(deps|postset|inline)$/)) {
libFuncsToInclude.push(key);
}
}
@@ -167,7 +167,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}
// Add current value(s)
var currValue = flatten(values[i]);
- if (I64_MODE == 1 && typeData.fields[i] == 'i64') {
+ if (USE_TYPED_ARRAYS == 2 && typeData.fields[i] == 'i64') {
// 'flatten' out the 64-bit value into two 32-bit halves
ret[index++] = currValue>>>0;
ret[index++] = 0;
@@ -229,7 +229,7 @@ function JSify(data, functionsOnly, givenFunctions) {
return makeEmptyStruct(type);
} else if (value.intertype === 'string') {
return JSON.stringify(parseLLVMString(value.text)) +
- ' /* ' + value.text.substr(0, 20).replace(/\*/g, '_') + ' */'; // make string safe for inclusion in comment
+ ' /* ' + value.text.substr(0, 20).replace(/[*<>]/g, '_') + ' */'; // make string safe for inclusion in comment
} else {
return alignStruct(handleSegments(value.contents), type);
}
@@ -574,14 +574,30 @@ function JSify(data, functionsOnly, givenFunctions) {
if (block.type == 'emulated') {
if (block.labels.length > 1) {
if (block.entries.length == 1) {
- ret += indent + '__label__ = ' + getLabelId(block.entries[0]) + '; ' + (SHOW_LABELS ? '/* ' + block.entries[0] + ' */' : '') + '\n';
+ ret += indent + '__label__ = ' + getLabelId(block.entries[0]) + '; ' + (SHOW_LABELS ? '/* ' + getOriginalLabelId(block.entries[0]) + ' */' : '') + '\n';
} // otherwise, should have been set before!
- ret += indent + 'while(1) switch(__label__) {\n';
+ if (func.setjmpTable) {
+ var setjmpTable = {};
+ 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';
+ }
+ ret += indent + 'while(1) ';
+ if (func.setjmpTable) {
+ ret += 'try { ';
+ }
+ ret += 'switch(__label__) {\n';
ret += block.labels.map(function(label) {
- return indent + ' case ' + getLabelId(label.ident) + ': // ' + label.ident + '\n'
+ return indent + ' case ' + getLabelId(label.ident) + ': ' + (SHOW_LABELS ? '// ' + getOriginalLabelId(label.ident) : '') + '\n'
+ getLabelLines(label, indent + ' ');
}).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) }';
+ }
} else {
ret += (SHOW_LABELS ? indent + '/* ' + block.entr