aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js117
-rw-r--r--src/compiler.js14
-rw-r--r--src/fastLong.js12
-rw-r--r--src/intertyper.js92
-rw-r--r--src/jsifier.js228
-rw-r--r--src/library.js782
-rw-r--r--src/library_browser.js1
-rw-r--r--src/library_fs.js115
-rw-r--r--src/library_gl.js184
-rw-r--r--src/library_idbfs.js216
-rw-r--r--src/library_memfs.js24
-rw-r--r--src/library_nodefs.js234
-rw-r--r--src/library_sdl.js227
-rw-r--r--src/library_sockfs.js12
-rw-r--r--src/modules.js32
-rw-r--r--src/parseTools.js146
-rw-r--r--src/postamble.js3
-rw-r--r--src/preamble.js169
-rw-r--r--src/runtime.js19
-rw-r--r--src/settings.js441
-rw-r--r--src/struct_info.json1045
21 files changed, 2740 insertions, 1373 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index 3fb20253..95fbccc7 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -188,7 +188,7 @@ function analyzer(data, sidePass) {
if (USE_TYPED_ARRAYS == 2) {
function getLegalVars(base, bits, allowLegal) {
bits = bits || 32; // things like pointers are all i32, but show up as 0 bits from getBits
- if (allowLegal && bits <= 32) return [{ ident: base + ('i' + bits in Runtime.INT_TYPES ? '' : '$0'), bits: bits }];
+ if (allowLegal && bits <= 32) return [{ intertype: 'value', ident: base + ('i' + bits in Runtime.INT_TYPES ? '' : '$0'), bits: bits, type: 'i' + bits }];
if (isNumber(base)) return getLegalLiterals(base, bits);
if (base[0] == '{') {
warnOnce('seeing source of illegal data ' + base + ', likely an inline struct - assuming zeroinit');
@@ -198,7 +198,7 @@ function analyzer(data, sidePass) {
var i = 0;
if (base == 'zeroinitializer' || base == 'undef') base = 0;
while (bits > 0) {
- ret[i] = { ident: base ? base + '$' + i : '0', bits: Math.min(32, bits) };
+ ret[i] = { intertype: 'value', ident: base ? base + '$' + i : '0', bits: Math.min(32, bits), type: 'i' + Math.min(32, bits) };
bits -= 32;
i++;
}
@@ -209,7 +209,7 @@ function analyzer(data, sidePass) {
var ret = new Array(Math.ceil(bits/32));
var i = 0;
while (bits > 0) {
- ret[i] = { ident: (parsed[i]|0).toString(), bits: Math.min(32, bits) }; // resign all values
+ ret[i] = { intertype: 'value', ident: (parsed[i]|0).toString(), bits: Math.min(32, bits), type: 'i' + Math.min(32, bits) }; // resign all values
bits -= 32;
i++;
}
@@ -225,7 +225,8 @@ function analyzer(data, sidePass) {
return getLegalLiterals(value.ident, bits);
} else if (value.intertype == 'structvalue') {
return getLegalStructuralParts(value).map(function(part) {
- return { ident: part.ident, bits: part.type.substr(1) };
+ part.bits = part.type.substr(1); // can be some nested IR, like LLVM calls
+ return part;
});
} else {
return getLegalVars(value.ident, bits);
@@ -550,11 +551,7 @@ function analyzer(data, sidePass) {
return {
intertype: 'phiparam',
label: param.label,
- value: {
- intertype: 'value',
- ident: values[k++][j].ident,
- type: 'i' + element.bits,
- }
+ value: values[k++][j]
};
})
});
@@ -783,13 +780,14 @@ function analyzer(data, sidePass) {
assert(PRECISE_I64_MATH, 'Must have precise i64 math for non-constant 64-bit shifts');
Types.preciseI64MathUsed = 1;
value.intertype = 'value';
- value.ident = 'var ' + value.assignTo + '$0 = ' +
+ value.ident = makeVarDef(value.assignTo) + '$0=' +
asmCoercion('_bitshift64' + value.op[0].toUpperCase() + value.op.substr(1) + '(' +
asmCoercion(sourceElements[0].ident, 'i32') + ',' +
asmCoercion(sourceElements[1].ident, 'i32') + ',' +
asmCoercion(value.params[1].ident + '$0', 'i32') + ')', 'i32'
) + ';' +
- 'var ' + value.assignTo + '$1 = tempRet0;';
+ makeVarDef(value.assignTo) + '$1=tempRet0;';
+ value.vars = [[value.assignTo + '$0', 'i32'], [value.assignTo + '$1', 'i32']];
value.assignTo = null;
i++;
continue;
@@ -801,27 +799,65 @@ function analyzer(data, sidePass) {
var whole = shifts >= 0 ? Math.floor(shifts/32) : Math.ceil(shifts/32);
var fraction = Math.abs(shifts % 32);
if (signed) {
- var signedFill = '(' + makeSignOp(sourceElements[sourceElements.length-1].ident, 'i' + sourceElements[sourceElements.length-1].bits, 're', 1, 1) + ' < 0 ? -1 : 0)';
- var signedKeepAlive = { intertype: 'value', ident: sourceElements[sourceElements.length-1].ident, type: 'i32' };
- }
- for (var j = 0; j < targetElements.length; j++) {
- var result = {
- intertype: 'value',
- ident: (j + whole >= 0 && j + whole < sourceElements.length) ? sourceElements[j + whole].ident : (signed ? signedFill : '0'),
- params: [(signed && j + whole > sourceElements.length) ? signedKeepAlive : null],
+ var signedFill = {
+ intertype: 'mathop',
+ op: 'select',
+ variant: 's',
type: 'i32',
+ params: [{
+ intertype: 'mathop',
+ op: 'icmp',
+ variant: 'slt',
+ type: 'i32',
+ params: [
+ { intertype: 'value', ident: sourceElements[sourceElements.length-1].ident, type: 'i' + Math.min(sourceBits, 32) },
+ { intertype: 'value', ident: '0', type: 'i32' }
+ ]
+ },
+ { intertype: 'value', ident: '-1', type: 'i32' },
+ { intertype: 'value', ident: '0', type: 'i32' },
+ ]
};
- if (j == 0 && sourceBits < 32) {
- // zext sign correction
- result.ident = makeSignOp(result.ident, 'i' + sourceBits, isUnsignedOp(value.op) ? 'un' : 're', 1, 1);
- }
- if (fraction != 0) {
- var other = {
+ }
+ for (var j = 0; j < targetElements.length; j++) {
+ var inBounds = j + whole >= 0 && j + whole < sourceElements.length;
+ var result;
+ if (inBounds || !signed) {
+ result = {
intertype: 'value',
- ident: (j + sign + whole >= 0 && j + sign + whole < sourceElements.length) ? sourceElements[j + sign + whole].ident : (signed ? signedFill : '0'),
- params: [(signed && j + sign + whole > sourceElements.length) ? signedKeepAlive : null],
- type: 'i32',
+ ident: inBounds ? sourceElements[j + whole].ident : '0',
+ type: 'i' + Math.min(sourceBits, 32),
};
+ if (j == 0 && sourceBits < 32) {
+ // zext sign correction
+ var result2 = {
+ intertype: 'mathop',
+ op: isUnsignedOp(value.op) ? 'zext' : 'sext',
+ params: [result, {
+ intertype: 'type',
+ ident: 'i32',
+ type: 'i' + sourceBits
+ }],
+ type: 'i32'
+ };
+ result = result2;
+ }
+ } else {
+ // out of bounds and signed
+ result = copy(signedFill);
+ }
+ if (fraction != 0) {
+ var other;
+ var otherInBounds = j + sign + whole >= 0 && j + sign + whole < sourceElements.length;
+ if (otherInBounds || !signed) {
+ other = {
+ intertype: 'value',
+ ident: otherInBounds ? sourceElements[j + sign + whole].ident : '0',
+ type: 'i32',
+ };
+ } else {
+ other = copy(signedFill);
+ }
other = {
intertype: 'mathop',
op: shiftOp,
@@ -871,10 +907,17 @@ function analyzer(data, sidePass) {
}
if (targetBits <= 32) {
// We are generating a normal legal type here
- legalValue = {
- intertype: 'value',
- ident: targetElements[0].ident + (targetBits < 32 ? '&' + (Math.pow(2, targetBits)-1) : ''),
- type: 'rawJS'
+ legalValue = { intertype: 'value', ident: targetElements[0].ident, type: 'i32' };
+ if (targetBits < 32) {
+ legalValue = {
+ intertype: 'mathop',
+ op: 'and',
+ type: 'i32',
+ params: [
+ legalValue,
+ { intertype: 'value', ident: (Math.pow(2, targetBits)-1).toString(), type: 'i32' }
+ ]
+ }
};
legalValue.assignTo = item.assignTo;
toAdd.push(legalValue);
@@ -1116,7 +1159,7 @@ function analyzer(data, sidePass) {
rawLinesIndex: i
};
if (variable.origin === 'alloca') {
- variable.allocatedNum = item.allocatedNum;
+ variable.allocatedNum = item.ident;
}
if (variable.origin === 'call') {
variable.type = getReturnType(variable.type);
@@ -1607,9 +1650,9 @@ 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' || !isNumber(item.allocatedNum)) break;
+ if (!item.assignTo || item.intertype != 'alloca' || !isNumber(item.ident)) break;
item.allocatedSize = func.variables[item.assignTo].impl === VAR_EMULATED ?
- calcAllocatedSize(item.allocatedType)*item.allocatedNum: 0;
+ calcAllocatedSize(item.allocatedType)*item.ident: 0;
if (USE_TYPED_ARRAYS === 2) {
// We need to keep the stack aligned
item.allocatedSize = Runtime.forceAlign(item.allocatedSize, Runtime.STACK_ALIGN);
@@ -1618,7 +1661,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' || !isNumber(item.allocatedNum)) break;
+ if (!item.assignTo || item.intertype != 'alloca' || !isNumber(item.ident)) break;
item.allocatedIndex = index;
index += item.allocatedSize;
delete item.allocatedSize;
@@ -1646,7 +1689,7 @@ function analyzer(data, sidePass) {
for (var i = 0; i < lines.length; i++) {
var item = lines[i];
- if (!finishedInitial && (!item.assignTo || item.intertype != 'alloca' || !isNumber(item.allocatedNum))) {
+ if (!finishedInitial && (!item.assignTo || item.intertype != 'alloca' || !isNumber(item.ident))) {
finishedInitial = true;
}
if (item.intertype == 'alloca' && finishedInitial) {
diff --git a/src/compiler.js b/src/compiler.js
index e42f5e19..d490f454 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -185,7 +185,6 @@ if (SAFE_HEAP) USE_BSS = 0; // must initialize heap for safe heap
assert(!(USE_TYPED_ARRAYS === 2 && QUANTUM_SIZE !== 4), 'For USE_TYPED_ARRAYS == 2, must have normal QUANTUM_SIZE of 4');
if (ASM_JS) {
assert(!ALLOW_MEMORY_GROWTH, 'Cannot grow asm.js heap');
- assert((TOTAL_MEMORY&(TOTAL_MEMORY-1)) == 0, 'asm.js heap must be power of 2');
}
assert(!(!NAMED_GLOBALS && BUILD_AS_SHARED_LIB), 'shared libraries must have named globals');
@@ -206,6 +205,16 @@ if (phase == 'pre') {
if (VERBOSE) printErr('VERBOSE is on, this generates a lot of output and can slow down compilation');
+// Load struct and define information.
+try {
+ var temp = JSON.parse(read(STRUCT_INFO));
+} catch(e) {
+ printErr('cannot load struct info at ' + STRUCT_INFO + ' : ' + e + ', trying in current dir');
+ temp = JSON.parse(read('struct_info.compiled.json'));
+}
+C_STRUCTS = temp.structs;
+C_DEFINES = temp.defines;
+
// Load compiler code
load('modules.js');
@@ -307,3 +316,6 @@ if (ll_file) {
}
}
+//var M = keys(tokenCacheMisses).map(function(m) { return [m, misses[m]] }).sort(function(a, b) { return a[1] - b[1] });
+//printErr(dump(M.slice(M.length-10)));
+
diff --git a/src/fastLong.js b/src/fastLong.js
index 4f6efd9f..2b70b2fb 100644
--- a/src/fastLong.js
+++ b/src/fastLong.js
@@ -5,12 +5,12 @@ function ___muldsi3($a, $b) {
var $1 = 0, $2 = 0, $3 = 0, $6 = 0, $8 = 0, $11 = 0, $12 = 0;
$1 = $a & 65535;
$2 = $b & 65535;
- $3 = Math.imul($2, $1) | 0;
+ $3 = Math_imul($2, $1) | 0;
$6 = $a >>> 16;
- $8 = ($3 >>> 16) + (Math.imul($2, $6) | 0) | 0;
+ $8 = ($3 >>> 16) + (Math_imul($2, $6) | 0) | 0;
$11 = $b >>> 16;
- $12 = Math.imul($11, $1) | 0;
- return (tempRet0 = (($8 >>> 16) + (Math.imul($11, $6) | 0) | 0) + ((($8 & 65535) + $12 | 0) >>> 16) | 0, 0 | ($8 + $12 << 16 | $3 & 65535)) | 0;
+ $12 = Math_imul($11, $1) | 0;
+ return (tempRet0 = (($8 >>> 16) + (Math_imul($11, $6) | 0) | 0) + ((($8 & 65535) + $12 | 0) >>> 16) | 0, 0 | ($8 + $12 << 16 | $3 & 65535)) | 0;
}
function ___divdi3($a$0, $a$1, $b$0, $b$1) {
$a$0 = $a$0 | 0;
@@ -63,8 +63,8 @@ function ___muldi3($a$0, $a$1, $b$0, $b$1) {
$y_sroa_0_0_extract_trunc = $b$0;
$1$0 = ___muldsi3($x_sroa_0_0_extract_trunc, $y_sroa_0_0_extract_trunc) | 0;
$1$1 = tempRet0;
- $2 = Math.imul($a$1, $y_sroa_0_0_extract_trunc) | 0;
- return (tempRet0 = ((Math.imul($b$1, $x_sroa_0_0_extract_trunc) | 0) + $2 | 0) + $1$1 | $1$1 & 0, 0 | $1$0 & -1) | 0;
+ $2 = Math_imul($a$1, $y_sroa_0_0_extract_trunc) | 0;
+ return (tempRet0 = ((Math_imul($b$1, $x_sroa_0_0_extract_trunc) | 0) + $2 | 0) + $1$1 | $1$1 & 0, 0 | $1$0 & -1) | 0;
}
function ___udivdi3($a$0, $a$1, $b$0, $b$1) {
$a$0 = $a$0 | 0;
diff --git a/src/intertyper.js b/src/intertyper.js
index 07f2020c..781c8187 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -5,14 +5,16 @@
var fastPaths = 0, slowPaths = 0;
+var tokenCache = {};
+['=', 'i32', 'label', ';', '4', '0', '1', '2', '255', 'align', 'i8*', 'i8', 'i16', 'getelementptr', 'inbounds', 'unnamed_addr', 'x', 'load', 'preds', 'br', 'i32*', 'i1', 'store', '<label>', 'constant', 'c', 'private', 'null', 'internal', 'to', 'bitcast', 'define', 'nounwind', 'nocapture', '%this', 'call', '...'].forEach(function(text) { tokenCache[text] = { text: text } });
+
+//var tokenCacheMisses = {};
+
// Line tokenizer
-function tokenizer(item, inner) {
- //assert(item.lineNum != 40000);
- //if (item.lineNum) print(item.lineNum);
+function tokenize(text, lineNum) {
var tokens = [];
var quotes = 0;
var lastToken = null;
- var CHUNKSIZE = 64; // How much forward to peek forward. Too much means too many string segments copied
// Note: '{' is not an encloser, as its use in functions is split over many lines
var enclosers = {
'[': 0,
@@ -26,22 +28,33 @@ function tokenizer(item, inner) {
function makeToken(text) {
if (text.length == 0) return;
// merge certain tokens
- if (lastToken && ( (lastToken.text == '%' && text[0] == '"') || /^\**$/.test(text) ) ) {
+ if (lastToken && /^\**$/.test(text)) {
lastToken.text += text;
return;
}
+ var cached = tokenCache[text];
+ if (cached) {
+ //assert(cached.text === text);
+ tokens.push(cached);
+ lastToken = cached;
+ return;
+ }
+ //tokenCacheMisses[text] = (misses[text] || 0) + 1;
+
var token = {
text: text
};
if (text[0] in enclosers) {
- token.item = tokenizer({
- lineText: text.substr(1, text.length-2)
- }, true);
+ token.item = tokenize(text.substr(1, text.length-2));
token.type = text[0];
}
// merge certain tokens
if (lastToken && isType(lastToken.text) && isFunctionDef(token)) {
+ if (lastToken.text in tokenCache) {
+ // create a copy of the cached value
+ lastToken = tokens[tokens.length-1] = { text: lastToken.text };
+ }
lastToken.text += ' ' + text;
} else if (lastToken && text[0] == '}') { // }, }*, etc.
var openBrace = tokens.length-1;
@@ -63,7 +76,7 @@ function tokenizer(item, inner) {
}
}
// Split using meaningful characters
- var lineText = item.lineText + ' ';
+ var lineText = text + ' ';
var re = /[\[\]\(\)<>, "]/g;
var segments = lineText.split(re);
segments.pop();
@@ -141,15 +154,11 @@ function tokenizer(item, inner) {
var newItem = {
tokens: tokens,
indent: lineText.search(/[^ ]/),
- lineNum: item.lineNum
+ lineNum: lineNum || 0
};
return newItem;
}
-function tokenize(text) {
- return tokenizer({ lineText: text }, true);
-}
-
// Handy sets
var ENCLOSER_STARTERS = set('[', '(', '<');
@@ -251,7 +260,7 @@ function intertyper(lines, sidePass, baseLineNums) {
if (mainPass && /^}.*/.test(line)) {
inFunction = false;
if (mainPass) {
- var func = funcHeaderHandler(tokenizer({ lineText: currFunctionLines[0], lineNum: currFunctionLineNum }, true));
+ var func = funcHeaderHandler(tokenize(currFunctionLines[0], currFunctionLineNum));
if (SKIP_STACK_IN_SMALL && /emscripten_autodebug/.exec(func.ident)) {
warnOnce('Disabling SKIP_STACK_IN_SMALL because we are apparently processing autodebugger data');
@@ -766,15 +775,13 @@ function intertyper(lines, sidePass, baseLineNums) {
return item;
}
// 'alloca'
- var allocaPossibleVars = ['allocatedNum'];
function allocaHandler(item) {
item.intertype = 'alloca';
item.allocatedType = item.tokens[1].text;
if (item.tokens.length > 3 && Runtime.isNumberType(item.tokens[3].text)) {
- item.allocatedNum = toNiceIdent(item.tokens[4].text);
- item.possibleVars = allocaPossibleVars;
+ item.ident = toNiceIdent(item.tokens[4].text);
} else {
- item.allocatedNum = 1;
+ item.ident = 1;
}
item.type = addPointing(item.tokens[1].text); // type of pointer we will get
Types.needAnalysis[item.type] = 0;
@@ -850,6 +857,7 @@ function intertyper(lines, sidePass, baseLineNums) {
// TODO: also remove 2nd param?
} else if (item.op in LLVM.COMPS) {
item.type = 'i1';
+ if (item.params[1].intertype === 'type') item.params[1].intertype = 'value'; // parsed as type, but comparisons have just values there
}
if (USE_TYPED_ARRAYS == 2) {
// Some specific corrections, since 'i64' is special
@@ -1013,7 +1021,8 @@ function intertyper(lines, sidePass, baseLineNums) {
noteGlobalVariable(ret);
}
} else if (phase === 'funcs') {
- if (m = /^ (%[\w\d\._]+) = (getelementptr|load) ([%\w\d\._ ,\*\-@]+)$/.exec(line.lineText)) {
+ // TODO: (void)call, store
+ if (m = /^ (%[\w\d\._]+) = (getelementptr|load|icmp) ([%\w\d\._ ,\*\-@]+)$/.exec(line.lineText)) {
var assignTo = m[1];
var intertype = m[2];
var args = m[3];
@@ -1067,15 +1076,37 @@ function intertyper(lines, sidePass, baseLineNums) {
}
break;
}
+ case 'icmp': {
+ var parts = args.split(' ');
+ assert(parts.length === 4);
+ ret = {
+ intertype: 'mathop',
+ op: 'icmp',
+ variant: parts[0],
+ lineNum: line.lineNum,
+ assignTo: toNiceIdent(assignTo),
+ params: [{
+ intertype: 'value',
+ ident: toNiceIdent(parts[2].substr(0, parts[2].length-1)),
+ type: parts[1]
+ }, {
+ intertype: 'value',
+ ident: toNiceIdent(parts[3]),
+ type: parts[1]
+ }],
+ type: 'i1',
+ };
+ break;
+ }
default: throw 'unexpected fast path type ' + intertype;
}
- //else if (line.lineText.indexOf(' = load ') > 0) printErr('close: ' + JSON.stringify(line.lineText));
}
+ //else if (line.lineText.indexOf(' = icmp ') > 0) printErr('close: ' + JSON.stringify(line.lineText));
}
if (ret) {
if (COMPILER_ASSERTIONS) {
- //printErr(['\n', JSON.stringify(ret), '\n', JSON.stringify(triager(tokenizer(line)))]);
- var normal = triager(tokenizer(line));
+ //printErr(['\n', dump(ret), '\n', dump(triager(tokenizer(line)))]);
+ var normal = triager(tokenize(line));
delete normal.tokens;
delete normal.indent;
assert(sortedJsonCompare(normal, ret), 'fast path: ' + dump(normal) + '\n vs \n' + dump(ret));
@@ -1087,17 +1118,20 @@ function intertyper(lines, sidePass, baseLineNums) {
// Input
lineSplitter().forEach(function(line) {
- var item = tryFastPaths(line);
- if (item) {
- finalResults.push(item);
- fastPaths++;
- return;
+ var item;
+ if (COMPILER_FASTPATHS) {
+ item = tryFastPaths(line);
+ if (item) {
+ finalResults.push(item);
+ fastPaths++;
+ return;
+ }
}
slowPaths++;
//var time = Date.now();
- var t = tokenizer(line);
+ var t = tokenize(line.lineText, line.lineNum);
item = triager(t);
/*
diff --git a/src/jsifier.js b/src/jsifier.js
index 96cb8d9a..f638ea08 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -234,8 +234,8 @@ function JSify(data, functionsOnly, givenFunctions) {
function globalVariableHandler(item) {
function needsPostSet(value) {
if (typeof value !== 'string') return false;
- return value[0] in UNDERSCORE_OPENPARENS || value.substr(0, 14) === 'CHECK_OVERFLOW'
- || value.substr(0, 6) === 'GLOBAL';
+ // (' is ok, as it is something we can indexize later into a concrete int: ('{{ FI_ ...
+ return /^([(_][^']|CHECK_OVERFLOW|GLOBAL).*/.test(value);
}
item.intertype = 'GlobalVariableStub';
@@ -308,6 +308,8 @@ function JSify(data, functionsOnly, givenFunctions) {
JS: makeSetValue(makeGlobalUse(item.ident), i, value, structTypes[i], false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors
});
constant[i] = '0';
+ } else {
+ if (typeof value === 'string') constant[i] = deParenCarefully(value);
}
});
@@ -347,7 +349,7 @@ function JSify(data, functionsOnly, givenFunctions) {
js += 'if (globalScope) { assert(!globalScope["' + item.ident + '"]); globalScope["' + item.ident + '"] = ' + item.ident + ' }';
}
if (item.external && !NAMED_GLOBALS) {
- js = 'var ' + item.ident + ' = ' + js; // force an explicit naming, even if unnamed globals, for asm forwarding
+ js = 'var ' + item.ident + '=' + js; // force an explicit naming, even if unnamed globals, for asm forwarding
}
itemsDict.GlobalVariableStub.push({
intertype: 'GlobalVariable',
@@ -405,6 +407,9 @@ function JSify(data, functionsOnly, givenFunctions) {
var snippet = LibraryManager.library[ident];
var redirectedIdent = null;
var deps = LibraryManager.library[ident + '__deps'] || [];
+ deps.forEach(function(dep) {
+ if (typeof snippet === 'string' && !(dep in LibraryManager.library)) warn('missing library dependency ' + dep + ', make sure you are compiling with the right options (see #ifdefs in src/library*.js)');
+ });
var isFunction = false;
if (typeof snippet === 'string') {
@@ -418,7 +423,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}
// In asm, we need to know about library functions. If there is a target, though, then no
// need to consider this a library function - we will call directly to it anyhow
- if (ASM_JS && !redirectedIdent && (typeof target == 'function' || /Math\.\w+/.exec(snippet))) {
+ if (ASM_JS && !redirectedIdent && (typeof target == 'function' || /Math_\w+/.exec(snippet))) {
Functions.libraryFunctions[ident] = 1;
}
} else if (typeof snippet === 'object') {
@@ -536,7 +541,7 @@ function JSify(data, functionsOnly, givenFunctions) {
case 'unreachable': line.JS = unreachableHandler(line); break;
default: throw 'what is this line? ' + dump(line);
}
- assert(line.JS);
+ //if (ASM_JS) assert(line.JS.indexOf('var ') < 0, dump(line));
if (line.assignTo) makeAssign(line);
Framework.currItem = null;
});
@@ -584,7 +589,7 @@ function JSify(data, functionsOnly, givenFunctions) {
if (DLOPEN_SUPPORT) Functions.getIndex(func.ident);
- func.JS += 'function ' + func.ident + '(' + paramIdents.join(', ') + ') {\n';
+ func.JS += 'function ' + func.ident + '(' + paramIdents.join(',') + '){\n';
if (PGO) {
func.JS += INDENTATION + 'PGOMonitor.called["' + func.ident + '"] = 1;\n';
@@ -593,13 +598,23 @@ function JSify(data, functionsOnly, givenFunctions) {
if (ASM_JS) {
// spell out argument types
func.params.forEach(function(param) {
- func.JS += INDENTATION + param.ident + ' = ' + asmCoercion(param.ident, param.type) + ';\n';
+ func.JS += INDENTATION + param.ident + '=' + deParen(asmCoercion(param.ident, param.type)) + ';\n';
});
+ addVariable('label', 'i32', func);
+
+ if (func.setjmpTable) {
+ addVariable('setjmpLabel', 'i32', func);
+ addVariable('setjmpTable', 'i32', func);
+ }
+
// spell out local variables
- var vars = values(func.variables).filter(function(v) { return v.origin != 'funcparam' });
+ var vars = values(func.variables).filter(function(v) {
+ return v.origin !== 'funcparam' &&
+ (!isIllegalType(getImplementationType(v)) || v.ident.indexOf('$', 1) > 0); // not illegal, or a broken up illegal (we have illegal chunks explicitly anyhow)
+ });
if (vars.length > 0) {
- var chunkSize = 8;
+ var chunkSize = 20;
var chunks = [];
var i = 0;
while (i < vars.length) {
@@ -608,22 +623,15 @@ function JSify(data, functionsOnly, givenFunctions) {
}
for (i = 0; i < chunks.length; i++) {
func.JS += INDENTATION + 'var ' + chunks[i].map(function(v) {
- var type = getImplementationType(v);
- if (!isIllegalType(type) || v.ident.indexOf('$', 1) > 0) { // not illegal, or a broken up illegal
- return v.ident + ' = ' + asmInitializer(type); //, func.variables[v.ident].impl);
- } else {
- return range(Math.ceil(getBits(type)/32)).map(function(i) {
- return v.ident + '$' + i + '= 0';
- }).join(',');
- }
- }).join(', ') + ';\n';
+ return v.ident + '=' + asmInitializer(getImplementationType(v)); //, func.variables[v.ident].impl);
+ }).join(',') + ';\n';
}
}
}
- if (true) { // TODO: optimize away when not needed
- if (CLOSURE_ANNOTATIONS) func.JS += '/** @type {number} */';
- func.JS += INDENTATION + 'var label = 0;\n';
+ if (CLOSURE_ANNOTATIONS) func.JS += '/** @type {number} */';
+ if (!ASM_JS) {
+ func.JS += INDENTATION + 'var label=0;\n';
}
if (ASM_JS) {
@@ -632,12 +640,12 @@ function JSify(data, functionsOnly, givenFunctions) {
hasByVal = hasByVal || param.byVal;
});
if (hasByVal) {
- func.JS += INDENTATION + 'var tempParam = 0;\n';
+ func.JS += INDENTATION + 'var tempParam=0;\n';
}
}
if (func.hasVarArgsCall) {
- func.JS += INDENTATION + 'var tempVarArgs = 0;\n';
+ func.JS += INDENTATION + 'var tempVarArgs=0;\n';
}
// Prepare the stack, if we need one. If we have other stack allocations, force the stack to be set up.
@@ -654,7 +662,7 @@ function JSify(data, functionsOnly, givenFunctions) {
if (param.byVal) {
var type = removePointing(param.type);
var typeInfo = Types.types[type];
- func.JS += INDENTATION + (ASM_JS ? '' : 'var ') + 'tempParam = ' + param.ident + '; ' + param.ident + ' = ' + RuntimeGenerator.stackAlloc(typeInfo.flatSize) + ';' +
+ func.JS += INDENTATION + (ASM_JS ? '' : 'var ') + 'tempParam = ' + param.ident + '; ' + param.ident + '=' + RuntimeGenerator.stackAlloc(typeInfo.flatSize) + ';' +
makeCopyValues(param.ident, 'tempParam', typeInfo.flatSize, 'null', null, param.byVal) + ';\n';
}
});
@@ -665,14 +673,14 @@ function JSify(data, functionsOnly, givenFunctions) {
function walkBlock(block, indent) {
if (!block) return '';
dprint('relooping', 'walking block: ' + block.type + ',' + block.entries + ' : ' + block.labels.length);
- function getLabelLines(label, indent, relooping) {
+ function getLabelLines(label, relooping) {
if (!label) return '';
var ret = '';
if ((LABEL_DEBUG >= 2) && functionNameFilterTest(func.ident)) {
- ret += indent + "Module.print(INDENT + '" + func.ident + ":" + label.ident + "');\n";
+ ret += INDENTATION + "Module.print(INDENT + '" + func.ident + ":" + label.ident + "');\n";
}
if (EXECUTION_TIMEOUT > 0) {
- ret += indent + 'if (Date.now() - START_TIME >= ' + (EXECUTION_TIMEOUT*1000) + ') throw "Timed out!" + (new Error().stack);\n';
+ ret += INDENTATION + 'if (Date.now() - START_TIME >= ' + (EXECUTION_TIMEOUT*1000) + ') throw "Timed out!" + (new Error().stack);\n';
}
if (PRINT_SPLIT_FILE_MARKER && Debugging.on && Debugging.getAssociatedSourceFile(label.lines[label.lines.length-1].lineNum)) {
@@ -685,6 +693,7 @@ function JSify(data, functionsOnly, givenFunctions) {
var i = 0;
return ret + label.lines.map(function(line) {
var JS = line.JS;
+ if (!relooping) JS = INDENTATION + JS;
if (relooping && i == label.lines.length-1) {
if (line.intertype == 'branch' || line.intertype == 'switch') {
JS = ''; // just branching operations - done in the relooper, so nothing need be done here
@@ -695,12 +704,10 @@ function JSify(data, functionsOnly, givenFunctions) {
i++;
// invoke instructions span two lines, and the debug info is located
// on the second line, hence the +1
- return JS + (Debugging.on ? Debugging.getComment(line.lineNum + (line.intertype === 'invoke' ? 1 : 0)) : '');
- })
- .join('\n')
- .split('\n') // some lines include line breaks
- .map(function(line) { return indent + line })
- .join('\n');
+ if (Debugging.on) JS += Debugging.getComment(line.lineNum + (line.intertype === 'invoke' ? 1 : 0));
+ //assert(JS.indexOf('\n') < 0, JS);
+ return JS;
+ }).join('\n');
}
var ret = '';
if (!RELOOP || func.forceEmulated) { // TODO: also if just 1 label?
@@ -719,19 +726,19 @@ function JSify(data, functionsOnly, givenFunctions) {
ret += 'dummy: 0';
ret += '};\n';
} else {
- ret += 'var setjmpLabel = 0;\n';
- ret += 'var setjmpTable = ' + RuntimeGenerator.stackAlloc(4 * (MAX_SETJMPS + 1) * 2) + ';\n';
+ ret += makeVarDef('setjmpLabel') + '=0;\n';
+ ret += makeVarDef('setjmpTable') + '=' + RuntimeGenerator.stackAlloc(4 * (MAX_SETJMPS + 1) * 2) + ';\n';
ret += makeSetValue('setjmpTable', '0', '0', 'i32') + ';'; // initialize first entry to 0
}
}
- ret += indent + 'while(1) ';
+ ret += indent + 'while(1)';
if (func.setjmpTable && !ASM_JS) {
ret += 'try { ';
}
- ret += 'switch(' + asmCoercion('label', 'i32') + ') {\n';
+ ret += 'switch(' + asmCoercion('label', 'i32') + '){\n';
ret += block.labels.map(function(label) {
- return indent + INDENTATION + 'case ' + getLabelId(label.ident) + ': ' + (SHOW_LABELS ? '// ' + getOriginalLabelId(label.ident) : '') + '\n'
- + getLabelLines(label, indent + INDENTATION + INDENTATION);
+ return INDENTATION + 'case ' + getLabelId(label.ident) + ': ' + (SHOW_LABELS ? '// ' + getOriginalLabelId(label.ident) : '') + '\n'
+ + getLabelLines(label);
}).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
@@ -748,8 +755,16 @@ function JSify(data, functionsOnly, givenFunctions) {
if (func.setjmpTable && !ASM_JS) {
ret += ' } catch(e) { if (!e.longjmp || !(e.id in mySetjmpIds)) throw(e); setjmpTable[setjmpLabels[e.id]](e.value) }';
}
+ if (ASM_JS && func.returnType !== 'void') {
+ // Add a return
+ if (func.returnType in Runtime.FLOAT_TYPES) {