aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js34
-rw-r--r--src/compiler.js15
-rw-r--r--src/compiler_phase.html33
-rw-r--r--src/fastLong.js12
-rw-r--r--src/intertyper.js168
-rw-r--r--src/jsifier.js216
-rw-r--r--src/library.js845
-rw-r--r--src/library_fs.js83
-rw-r--r--src/library_gl.js168
-rw-r--r--src/library_idbfs.js216
-rw-r--r--src/library_memfs.js23
-rw-r--r--src/library_nodefs.js234
-rw-r--r--src/library_sdl.js465
-rw-r--r--src/library_sockfs.js12
-rw-r--r--src/modules.js28
-rw-r--r--src/parseTools.js314
-rw-r--r--src/preamble.js31
-rw-r--r--src/runtime.js19
-rw-r--r--src/settings.js444
-rw-r--r--src/struct_info.json1045
-rw-r--r--src/utility.js11
21 files changed, 3029 insertions, 1387 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index 750f2a4c..17ad26ad 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -30,6 +30,8 @@ function analyzer(data, sidePass) {
var item = { items: data };
var data = item;
+ var newTypes = {};
+
// Gather
// Single-liners
['globalVariable', 'functionStub', 'unparsedFunction', 'unparsedGlobals', 'unparsedTypes', 'alias'].forEach(function(intertype) {
@@ -42,6 +44,7 @@ function analyzer(data, sidePass) {
temp.splitOut.forEach(function(type) {
//dprint('types', 'adding defined type: ' + type.name_);
Types.types[type.name_] = type;
+ newTypes[type.name_] = 1;
if (QUANTUM_SIZE === 1) {
Types.fatTypes[type.name_] = copy(type);
}
@@ -780,13 +783,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;
@@ -897,7 +901,7 @@ function analyzer(data, sidePass) {
});
}
- function addTypeInternal(type, data) {
+ function addTypeInternal(type) {
if (type.length == 1) return;
if (Types.types[type]) return;
if (['internal', 'hidden', 'inbounds', 'void'].indexOf(type) != -1) return;
@@ -908,8 +912,9 @@ function analyzer(data, sidePass) {
// to look at the underlying type - it was not defined explicitly
// anywhere else.
var nonPointing = removeAllPointing(type);
+ if (Types.types[nonPointing]) return;
var check = /^\[(\d+)\ x\ (.*)\]$/.exec(nonPointing);
- if (check && !Types.types[nonPointing]) {
+ if (check) {
var num = parseInt(check[1]);
num = Math.max(num, 1); // [0 x something] is used not for allocations and such of course, but
// for indexing - for an |array of unknown length|, basically. So we
@@ -917,7 +922,7 @@ function analyzer(data, sidePass) {
// check that we never allocate with this (either as a child structure
// in the analyzer, or in calcSize in alloca).
var subType = check[2];
- addTypeInternal(subType, data); // needed for anonymous structure definitions (see below)
+ addTypeInternal(subType); // needed for anonymous structure definitions (see below)
// Huge structural types are represented very inefficiently, both here and in generated JS. Best to avoid them - for example static char x[10*1024*1024]; is bad, while static char *x = malloc(10*1024*1024) is fine.
if (num >= 10*1024*1024) warnOnce('warning: very large fixed-size structural type: ' + type + ' - can you reduce it? (compilation may be slow)');
@@ -926,6 +931,7 @@ function analyzer(data, sidePass) {
fields: range(num).map(function() { return subType }),
lineNum: '?'
};
+ newTypes[nonPointing] = 1;
// Also add a |[0 x type]| type
var zerod = '[0 x ' + subType + ']';
if (!Types.types[zerod]) {
@@ -934,6 +940,7 @@ function analyzer(data, sidePass) {
fields: [subType, subType], // Two, so we get the flatFactor right. We care about the flatFactor, not the size here
lineNum: '?'
};
+ newTypes[zerod] = 1;
}
return;
}
@@ -964,6 +971,7 @@ function analyzer(data, sidePass) {
packed: packed,
lineNum: '?'
};
+ newTypes[type] = 1;
return;
}
@@ -975,13 +983,14 @@ function analyzer(data, sidePass) {
flatSize: 1,
lineNum: '?'
};
+ newTypes[type] = 1;
}
- function addType(type, data) {
- addTypeInternal(type, data);
+ function addType(type) {
+ addTypeInternal(type);
if (QUANTUM_SIZE === 1) {
Types.flipTypes();
- addTypeInternal(type, data);
+ addTypeInternal(type);
Types.flipTypes();
}
}
@@ -992,7 +1001,7 @@ function analyzer(data, sidePass) {
// which handles type definitions, and later. Doing so before the first side pass will result in
// making bad guesses about types which are actually defined
for (var type in Types.needAnalysis) {
- if (type) addType(type, data);
+ if (type) addType(type);
}
Types.needAnalysis = {};
}
@@ -1021,17 +1030,18 @@ function analyzer(data, sidePass) {
var more = true;
while (more) {
more = false;
- for (var typeName in types) {
+ for (var typeName in newTypes) {
var type = types[typeName];
if (type.flatIndexes) continue;
var ready = true;
type.fields.forEach(function(field) {
if (isStructType(field)) {
if (!types[field]) {
- addType(field, item);
+ addType(field);
ready = false;
} else {
if (!types[field].flatIndexes) {
+ newTypes[field] = 1;
ready = false;
}
}
@@ -1058,6 +1068,8 @@ function analyzer(data, sidePass) {
Runtime.QUANTUM_SIZE = trueQuantumSize;
Types.flipTypes();
}
+
+ newTypes = null;
}
// Variable analyzer
diff --git a/src/compiler.js b/src/compiler.js
index 4f16986c..90060837 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -206,6 +206,11 @@ 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.
+var temp = JSON.parse(read(STRUCT_INFO));
+C_STRUCTS = temp.structs;
+C_DEFINES = temp.defines;
+
// Load compiler code
load('modules.js');
@@ -215,7 +220,12 @@ load('analyzer.js');
load('jsifier.js');
if (phase == 'funcs' && RELOOP) { // XXX handle !singlePhase
RelooperModule = { TOTAL_MEMORY: ceilPowerOfTwo(2*RELOOPER_BUFFER_SIZE) };
- load(RELOOPER);
+ try {
+ load(RELOOPER);
+ } catch(e) {
+ printErr('cannot load relooper at ' + RELOOPER + ' : ' + e + ', trying in current dir');
+ load('relooper.js');
+ }
assert(typeof Relooper != 'undefined');
}
globalEval(processMacros(preprocess(read('runtime.js'))));
@@ -269,6 +279,9 @@ function compile(raw) {
intertyped = null;
JSify(analyzed);
+ //dumpInterProf();
+ //printErr(phase + ' paths (fast, slow): ' + [fastPaths, slowPaths]);
+
phase = null;
if (DEBUG_MEMORY) {
diff --git a/src/compiler_phase.html b/src/compiler_phase.html
new file mode 100644
index 00000000..8ca631e8
--- /dev/null
+++ b/src/compiler_phase.html
@@ -0,0 +1,33 @@
+<html>
+<body>
+<h2>Run the emscripten compiler in a web page, just for laughs</h2>
+Open the web console to see stderr output
+<hr>
+<pre id="output"></pre>
+<script>
+ arguments = ['tmp/emscripten_temp/tmpbTF9CI.txt', 'tmp/emscripten_temp/tmpz8Yvie.pre.ll', 'pre']; // copy from emscripten.py output
+
+ var outputElement = document.getElementById('output');
+ print = function(x) {
+ outputElement.innerHTML += 'output hidden, profiling mode';
+ print = function(){};
+ //outputElement.innerHTML += x;
+ };
+
+ // For generated code
+ var Module = {
+ print: function(x) {
+ throw 'what?'
+ }
+ };
+
+ var startTime = Date.now();
+</script>
+<script src="compiler.js">
+</script>
+<script>
+ outputElement.innerHTML += '<br>total time: ' + (Date.now() - startTime);
+</script>
+</body>
+</html>
+
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 e43cc298..09bdaa33 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -3,6 +3,8 @@
// LLVM assembly => internal intermediate representation, which is ready
// to be processed by the later stages.
+var fastPaths = 0, slowPaths = 0;
+
// Line tokenizer
function tokenizer(item, inner) {
//assert(item.lineNum != 40000);
@@ -373,6 +375,14 @@ function intertyper(lines, sidePass, baseLineNums) {
// Line parsers to intermediate form
// globals: type or variable
+ function noteGlobalVariable(ret) {
+ if (!NAMED_GLOBALS) {
+ Variables.globals[ret.ident].type = ret.type;
+ Variables.globals[ret.ident].external = ret.external;
+ }
+ Types.needAnalysis[ret.type] = 0;
+ }
+
function globalHandler(item) {
function scanConst(value, type) {
// Gets an array of constant items, separated by ',' tokens
@@ -497,7 +507,6 @@ function intertyper(lines, sidePass, baseLineNums) {
external = true;
item.tokens.splice(2, 1);
}
- Types.needAnalysis[item.tokens[2].text] = 0;
var ret = {
intertype: 'globalVariable',
ident: toNiceIdent(ident),
@@ -507,11 +516,7 @@ function intertyper(lines, sidePass, baseLineNums) {
named: named,
lineNum: item.lineNum
};
- if (!NAMED_GLOBALS) {
- Variables.globals[ret.ident].type = ret.type;
- Variables.globals[ret.ident].external = external;
- }
- Types.needAnalysis[ret.type] = 0;
+ noteGlobalVariable(ret);
if (ident == '@llvm.global_ctors') {
ret.ctors = [];
if (item.tokens[3].item) {
@@ -845,6 +850,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
@@ -984,11 +990,150 @@ function intertyper(lines, sidePass, baseLineNums) {
return ret;
}
+ // Fast paths - quick parses of common patterns, avoid tokenizing entirely
+
+ function tryFastPaths(line) {
+ var m, ret;
+ if (phase === 'pre') {
+ // string constant
+ if (0) { // works, but not worth it m = /([@\.\w\d_]+) = (private )?(unnamed_addr )?(constant )?(\[\d+ x i8\]) c"([^"]+)".*/.exec(line.lineText)) {
+ if (m[1] === '@llvm.global_ctors') return ret;
+ ret = {
+ intertype: 'globalVariable',
+ ident: toNiceIdent(m[1]),
+ type: m[5],
+ external: false,
+ private_: m[2] !== null,
+ named: m[3] === null,
+ lineNum: line.lineNum,
+ value: {
+ intertype: 'string',
+ text: m[6]
+ }
+ };
+ noteGlobalVariable(ret);
+ }
+ } else if (phase === 'funcs') {
+ // 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];
+ switch (intertype) {
+ case 'getelementptr': {
+ if (args[0] === 'i' && args.indexOf('inbounds ') === 0) {
+ args = args.substr(9);
+ }
+ var params = args.split(', ').map(function(param) {
+ var parts = param.split(' ');
+ assert(parts.length === 2);
+ Types.needAnalysis[parts[0]] = 0;
+ return {
+ intertype: 'value',
+ type: parts[0],
+ ident: toNiceIdent(parts[1]),
+ byVal: 0
+ }
+ });
+ ret = {
+ intertype: 'getelementptr',
+ lineNum: line.lineNum,
+ assignTo: toNiceIdent(assignTo),
+ ident: params[0].ident,
+ type: '*',
+ params: params
+ };
+ break;
+ }
+ case 'load': {
+ if (m = /(^[%\w\d\._\-@\*]+) ([%\w\d\._\-@]+)(, align \d+)?$/.exec(args)) {
+ var ident = toNiceIdent(m[2]);
+ var type = m[1];
+ assert(type[type.length-1] === '*', type);
+ var valueType = type.substr(0, type.length-1);
+ ret = {
+ intertype: 'load',
+ lineNum: line.lineNum,
+ assignTo: toNiceIdent(assignTo),
+ ident: ident,
+ type: valueType,
+ valueType: valueType,
+ pointerType: type,
+ pointer: {
+ intertype: 'value',
+ ident: ident,
+ type: type,
+ },
+ align: parseAlign(m[3])
+ };
+ }
+ 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(' = icmp ') > 0) printErr('close: ' + JSON.stringify(line.lineText));
+ }
+ if (ret) {
+ if (COMPILER_ASSERTIONS) {
+ //printErr(['\n', dump(ret), '\n', dump(triager(tokenizer(line)))]);
+ var normal = triager(tokenizer(line));
+ delete normal.tokens;
+ delete normal.indent;
+ assert(sortedJsonCompare(normal, ret), 'fast path: ' + dump(normal) + '\n vs \n' + dump(ret));
+ }
+ }
+ return ret;
+ }
+
// Input
lineSplitter().forEach(function(line) {
+ 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 item = triager(t);
+ item = triager(t);
+
+ /*
+ var type = item ? item.intertype + (item.op ? ':' + item.op : ''): 'none';
+ if (!interProf[type]) interProf[type] = { ms: 0, n: 0 };
+ interProf[type].ms += Date.now() - time;
+ interProf[type].n++;
+ */
+
if (!item) return;
finalResults.push(item);
if (item.tokens) item.tokens = null; // We do not need tokens, past the intertyper. Clean them up as soon as possible here.
@@ -996,3 +1141,12 @@ function intertyper(lines, sidePass, baseLineNums) {
return finalResults;
}
+// intertyper profiler
+
+/*
+var interProf = {};
+function dumpInterProf() {
+ printErr('\nintertyper/' + phase + ' (ms | n): ' + JSON.stringify(keys(interProf).sort(function(x, y) { return interProf[y].ms - interProf[x].ms }).map(function(x) { return x + ' : ' + interProf[x].ms + ' | ' + interProf[x].n }), null, ' ') + '\n');
+}
+*/
+
diff --git a/src/jsifier.js b/src/jsifier.js
index 96cb8d9a..0e5f8ef3 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -347,7 +347,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',
@@ -418,7 +418,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') {
@@ -537,6 +537,7 @@ function JSify(data, functionsOnly, givenFunctions) {
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 +585,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 +594,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 +619,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 +636,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 +658,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 +669,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 +689,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 +700,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 +722,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 +751,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) {
+ ret += ' return +0;\n';
+ } else {
+ ret += ' return 0;\n';
+ }
+ }
} else {
- ret += (SHOW_LABELS ? indent + '/* ' + block.entries[0] + ' */' : '') + '\n' + getLabelLines(block.labels[0], indent);
+ ret += (SHOW_LABELS ? indent + '/* ' + block.entries[0] + ' */' : '') + '\n' + getLabelLines(block.labels[0]);
}
ret += '\n';
} else {
@@ -764,7 +775,7 @@ function JSify(data, functionsOnly, givenFunctions) {
// add blocks
for (var i = 0; i < block.labels.length; i++) {
var label = block.labels[i];
- var content = getLabelLines(label, '', true);
+ var content = getLabelLines(label, true);
//printErr(func.ident + ' : ' + label.ident + ' : ' + content + '\n');
var last = label.lines[label.lines.length-1];
if (!last.signedIdent) {
@@ -810,9 +821,17 @@ function JSify(data, functionsOnly, givenFunctions) {
// Finalize function
if (LABEL_DEBUG && functionNameFilterTest(func.ident)) func.JS += " INDENT = INDENT.substr(0, INDENT.length-2);\n";
// Ensure a return in a function with a type that returns, even if it lacks a return (e.g., if it aborts())
- if (RELOOP && func.lines.length > 0 && func.returnType != 'void') {
- var returns = func.labels.filter(function(label) { return label.lines[label.lines.length-1].intertype == 'return' }).length;
- if (returns == 0) func.JS += INDENTATION + 'return ' + asmCoercion('0', func.returnType);
+ if (RELOOP && ASM_JS && func.lines.length > 0 && func.returnType != 'void') {
+ var lastCurly = func.JS.lastIndexOf('}');
+ var lastReturn = func.JS.lastIndexOf('return ');
+ if ((lastCurly < 0 && lastReturn < 0) || // no control flow, no return
+ (lastCurly >= 0 && lastReturn < lastCurly)) { // control flow, no return past last join
+ if (func.returnType in Runtime.FLOAT_TYPES) {
+ func.JS += ' return +0;\n';
+ } else {
+ func.JS += ' return 0;\n';
+ }
+ }
}
func.JS += '}\n';
@@ -898,6 +917,11 @@ function JSify(data, functionsOnly, givenFunctions) {
// Function lines
function valueHandler(item) {
+ if (item.vars) {
+ item.vars.forEach(function(v) {
+ addVariable(v[0], v[1]);
+ });
+ }
return item.ident;
}
function noopHandler(item) {
@@ -959,7 +983,7 @@ function JSify(data, functionsOnly, givenFunctions) {
var parts = label.split('|');
var trueLabel = parts[1] || '';
var oldLabel = parts[2] || '';
- var labelSetting = oldLabel ? 'label = ' + getLabelId(oldLabel) + ';' +
+ var labelSetting = oldLabel ? 'label=' + getLabelId(oldLabel) + ';' +
(SHOW_LABELS ? ' /* to: ' + getOriginalLabelId(cleanLabel(oldLabel)) + ' */' : '') : ''; // TODO: optimize away the setting
if (label[1] == 'R') {
if (label[2] == 'N') { // BRNOL: break, no label setting
@@ -980,7 +1004,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}
} else {
if (!labelIsVariable) label = getLabelId(label);
- return pre + 'label = ' + label + ';' + (SHOW_LABELS ? ' /* to: ' + getOriginalLabelId(cleanLabel(label)) + ' */' : '') + ' break;';
+ return pre + 'label=' + label + ';' + (SHOW_LABELS ? ' /* to: ' + getOriginalLabelId(cleanLabel(label)) + ' */' : '') + 'break;';
}
}
@@ -1002,14 +1026,14 @@ function JSify(data, functionsOnly, givenFunctions) {
var labelSets = phiSets[label];
// FIXME: Many of the |var |s here are not needed, but without them we get slowdowns with closure compiler. TODO: remove this workaround.
if (labelSets.length == 1) {
- return (ASM_JS ? '' : 'var ') + labelSets[0].ident + ' = ' + labelSets[0].valueJS + ';';
+ return (ASM_JS ? '' : 'var ') + labelSets[0].ident + '=' + labelSets[0].valueJS + ';';
}
// TODO: eliminate unneeded sets (to undefined etc.)
var deps = {}; // for each ident we will set, which others it depends on
- var valueJSes = {};
+ var map = {};
labelSets.forEach(function(labelSet) {
deps[labelSet.ident] = {};
- valueJSes[labelSet.ident] = labelSet.valueJS;
+ map[labelSet.ident] = labelSet;
});
labelSets.forEach(function(labelSet) {
walkInterdata(labelSet.value, function mark(item) {
@@ -1028,14 +1052,18 @@ function JSify(data, functionsOnly, givenFunctions) {
}
for (var i = 0; i < idents.length; i++) {
if (keys(deps[idents[i]]).length == 0) {
- post = 'var ' + idents[i] + ' = ' + valueJSes[idents[i]] + ';' + post;
+ post = idents[i] + '=' + map[idents[i]].valueJS + ';' + post;
+ if (!ASM_JS) post = 'var ' + post;
+ else addVariable(idents[i], map[idents[i]].value.type);
remove(idents[i]);
continue mainLoop;
}
}
// If we got here, we have circular dependencies, and must break at least one.
- pre += 'var ' + idents[0] + '$phi = ' + valueJSes[idents[0]] + ';';
- post += 'var ' + idents[0] + ' = ' + idents[0] + '$phi;';
+ pre += makeVarDef(idents[0]) + '$phi=' + map[idents[0]].valueJS + ';';
+ post += makeVarDef(idents[0]) + '=' + idents[0] + '$phi;';
+ addVariable(idents[0] + '$phi', map[idents[0]].value.type);
+ addVariable(idents[0], map[idents[0]].value.type);
remove(idents[0]);
}
return pre + post;
@@ -1062,10 +1090,10 @@ function JSify(data, functionsOnly, givenFunctions) {
var labelTrue = (item.labelTrueJS = getPhiSetsForLabel(phiSets, item.labelTrue)) + makeBranch(item.labelTrue, item.currLabelId);
var labelFalse = (item.labelFalseJS = getPhiSetsForLabel(phiSets, item.labelFalse)) + makeBr