diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 74 | ||||
-rw-r--r-- | src/compiler.js | 19 | ||||
-rw-r--r-- | src/intertyper.js | 2 | ||||
-rw-r--r-- | src/jsifier.js | 21 | ||||
-rw-r--r-- | src/library.js | 6 | ||||
-rw-r--r-- | src/parseTools.js | 46 | ||||
-rw-r--r-- | src/postamble.js | 4 | ||||
-rw-r--r-- | src/preamble.js | 2 | ||||
-rw-r--r-- | src/shell.html | 5 | ||||
-rw-r--r-- | src/shell.js | 19 |
10 files changed, 123 insertions, 75 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index 9aa84650..8ded86f1 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -319,7 +319,8 @@ function analyzer(data, sidePass) { continue; } case 'invoke': { - // We can't add lines after this, since invoke already modifies control flow. So we handle this in 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; } @@ -1150,18 +1151,61 @@ 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.lines.forEach(function(line) { if (line.intertype == 'indirectbr') { @@ -1190,7 +1234,7 @@ function analyzer(data, sidePass) { if (line.intertype == 'call' && line.ident == setjmp) { // Add a new label var oldIdent = label.ident; - var newIdent = oldIdent + '$$' + i; + var newIdent = func.labelIdCounter++; if (!func.setjmpTable) func.setjmpTable = []; func.setjmpTable.push([oldIdent, newIdent, line.assignTo]); func.labels.splice(i+1, 0, { @@ -1384,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 = []; @@ -1490,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; @@ -1541,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: diff --git a/src/compiler.js b/src/compiler.js index 1876ee1c..134ac5bd 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,12 +38,16 @@ 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']) { @@ -52,11 +57,11 @@ if (ENVIRONMENT_IS_NODE) { } } 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 *** diff --git a/src/intertyper.js b/src/intertyper.js index bd7b70f9..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>')) diff --git a/src/jsifier.js b/src/jsifier.js index b93cdf9a..b54aace3 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -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,7 +574,7 @@ 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! if (func.setjmpTable) { var setjmpTable = {}; @@ -591,7 +591,7 @@ function JSify(data, functionsOnly, givenFunctions) { } 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 + '}'; @@ -770,11 +770,14 @@ function JSify(data, functionsOnly, givenFunctions) { makeFuncLineActor('deleted', function(item) { return ';' }); - function getLabelId(label) { + function getOriginalLabelId(label) { var funcData = Framework.currItem.funcData; - var labelIds = funcData.labelIds; - if (labelIds[label] !== undefined) return labelIds[label]; - return labelIds[label] = funcData.labelIdCounter++; + var labelIdsInverse = funcData.labelIdsInverse; + return labelIdsInverse[label]; + } + + function getLabelId(label) { + return label; } function makeBranch(label, lastLabel, labelIsVariable) { @@ -788,7 +791,7 @@ function JSify(data, functionsOnly, givenFunctions) { var trueLabel = parts[1] || ''; var oldLabel = parts[2] || ''; var labelSetting = oldLabel ? '__label__ = ' + getLabelId(oldLabel) + ';' + - (SHOW_LABELS ? ' /* to: ' + cleanLabel(oldLabel) + ' */' : '') : ''; // TODO: optimize away the setting + (SHOW_LABELS ? ' /* to: ' + getOriginalLabelId(cleanLabel(oldLabel)) + ' */' : '') : ''; // TODO: optimize away the setting if (label[1] == 'R') { if (label[2] == 'N') { // BRNOL: break, no label setting labelSetting = ''; @@ -808,7 +811,7 @@ function JSify(data, functionsOnly, givenFunctions) { } } else { if (!labelIsVariable) label = getLabelId(label); - return pre + '__label__ = ' + label + ';' + (SHOW_LABELS ? ' /* to: ' + cleanLabel(label) + ' */' : '') + ' break;'; + return pre + '__label__ = ' + label + ';' + (SHOW_LABELS ? ' /* to: ' + getOriginalLabelId(cleanLabel(label)) + ' */' : '') + ' break;'; } } diff --git a/src/library.js b/src/library.js index 817f87e2..74a8a0ac 100644 --- a/src/library.js +++ b/src/library.js @@ -5183,7 +5183,7 @@ LibraryManager.library = { var dst = Number(start.getTimezoneOffset() != date.getTimezoneOffset()); {{{ makeSetValue('tmPtr', 'offsets.tm_isdst', 'dst', 'i32') }}} - var timezone = date.toString().match(/\(([A-Z]+)\)/)[1]; + var timezone = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | date.toString().match(/\(([A-Z]+)\)/)[1]; if (!(timezone in ___tm_timezones)) { ___tm_timezones[timezone] = allocate(intArrayFromString(timezone), 'i8', ALLOC_NORMAL); } @@ -5245,8 +5245,8 @@ LibraryManager.library = { var summer = new Date(2000, 6, 1); {{{ makeSetValue('__daylight', '0', 'Number(winter.getTimezoneOffset() != summer.getTimezoneOffset())', 'i32') }}} - var winterName = winter.toString().match(/\(([A-Z]+)\)/)[1]; - var summerName = summer.toString().match(/\(([A-Z]+)\)/)[1]; + var winterName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | winter.toString().match(/\(([A-Z]+)\)/)[1]; + var summerName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | summer.toString().match(/\(([A-Z]+)\)/)[1]; var winterNamePtr = allocate(intArrayFromString(winterName), 'i8', ALLOC_NORMAL); var summerNamePtr = allocate(intArrayFromString(summerName), 'i8', ALLOC_NORMAL); __tzname = _malloc(2 * {{{ Runtime.QUANTUM_SIZE }}}); // glibc does not need the double __ diff --git a/src/parseTools.js b/src/parseTools.js index 41caeaad..520d278e 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -324,7 +324,7 @@ function parseParamTokens(params) { ret.push({ intertype: 'value', type: segment[0].text, - ident: toNiceIdent(parseNumerical(segment[1].text)) + ident: toNiceIdent(parseNumerical(segment[1].text, segment[0].text)) }); Types.needAnalysis[removeAllPointing(ret[ret.length-1].type)] = 0; } @@ -559,12 +559,12 @@ function splitI64(value) { return makeInlineCalculation(makeI64('VALUE>>>0', 'Math.min(Math.floor(VALUE/4294967296), 4294967295)'), value, 'tempBigIntP'); } } -function mergeI64(value) { +function mergeI64(value, unsigned) { assert(USE_TYPED_ARRAYS == 2); if (legalizedI64s) { - return RuntimeGenerator.makeBigInt(value + '$0', value + '$1'); + return RuntimeGenerator.makeBigInt(value + '$0', value + '$1', unsigned); } else { - return makeInlineCalculation(RuntimeGenerator.makeBigInt('VALUE[0]', 'VALUE[1]'), value, 'tempI64'); + return makeInlineCalculation(RuntimeGenerator.makeBigInt('VALUE[0]', 'VALUE[1]', unsigned), value, 'tempI64'); } } @@ -701,8 +701,8 @@ function parseNumerical(value, type) { // Hexadecimal double value, as the llvm docs say, // "The one non-intuitive notation for constants is the hexadecimal form of floating point constants." value = IEEEUnHex(value); - } else if (type == 'i64' && USE_TYPED_ARRAYS == 2) { - value = parseI64Constant(value); + } else if (USE_TYPED_ARRAYS == 2 && isIllegalType(type)) { + return value; // do not parseFloat etc., that can lead to loss of precision } else if (value == 'null') { // NULL *is* 0, in C/C++. No JS null! (null == 0 is false, etc.) value = '0'; @@ -1114,7 +1114,7 @@ function makeCopyValues(dest, src, num, type, modifier, align, sep) { var oldDest = dest, oldSrc = src; dest = '$$dest'; src = '$$src'; - return 'for ($$src = ' + oldSrc + ', $$dest = ' + oldDest + ', $$stop = $$src + ' + num + '; $$src < $$stop; $$src++, $$dest++) {\n' + + return 'for (var $$src = ' + oldSrc + ', $$dest = ' + oldDest + ', $$stop = $$src + ' + num + '; $$src < $$stop; $$src++, $$dest++) {\n' + unroll(type, 1) + ' }'; } else { // USE_TYPED_ARRAYS == 2 // If we don't know how to handle this at compile-time, or handling it is best done in a large amount of code, call memset @@ -1453,7 +1453,7 @@ function finalizeLLVMParameter(param, noIndexizeFunctions) { if (param.type == 'i64' && USE_TYPED_ARRAYS == 2) { ret = parseI64Constant(ret); } - ret = parseNumerical(ret); + ret = parseNumerical(ret, param.type); } else if (param.intertype == 'structvalue') { ret = makeLLVMStruct(param.params.map(function(value) { return finalizeLLVMParameter(value, noIndexizeFunctions) })); } else if (param.intertype === 'blockaddress') { @@ -1672,22 +1672,22 @@ function processMathop(item) { case 'fptoui': case 'fptosi': return finish(splitI64(idents[0])); case 'icmp': { switch (variant) { - case 'uge': return high1 + ' >= ' + high2 + ' && (' + high1 + ' > ' + high2 + ' || ' + - low1 + ' >= ' + low2 + ')'; + case 'uge': return '(' + high1 + '>>>0) >= (' + high2 + '>>>0) && ((' + high1 + '>>>0) > (' + high2 + '>>>0) || ' + + '(' + low1 + '>>>0) >= (' + low2 + '>>>0))'; case 'sge': return '(' + high1 + '|0) >= (' + high2 + '|0) && ((' + high1 + '|0) > (' + high2 + '|0) || ' + - '(' + low1 + '|0) >= (' + low2 + '|0))'; - case 'ule': return high1 + ' <= ' + high2 + ' && (' + high1 + ' < ' + high2 + ' || ' + - low1 + ' <= ' + low2 + ')'; + '(' + low1 + '>>>0) >= (' + low2 + '>>>0))'; + case 'ule': return '(' + high1 + '>>>0) <= (' + high2 + '>>>0) && ((' + high1 + '>>>0) < (' + high2 + '>>>0) || ' + + '(' + low1 + '>>>0) <= (' + low2 + '>>>0))'; case 'sle': return '(' + high1 + '|0) <= (' + high2 + '|0) && ((' + high1 + '|0) < (' + high2 + '|0) || ' + - '(' + low1 + '|0) <= (' + low2 + '|0))'; - case 'ugt': return high1 + ' > ' + high2 + ' || (' + high1 + ' == ' + high2 + ' && ' + - low1 + ' > ' + low2 + ')'; + '(' + low1 + '>>>0) <= (' + low2 + '>>>0))'; + case 'ugt': return '(' + high1 + '>>>0) > (' + high2 + '>>>0) || ((' + high1 + '>>>0) == (' + high2 + '>>>0) && ' + + '(' + low1 + '>>>0) > (' + low2 + '>>>0))'; case 'sgt': return '(' + high1 + '|0) > (' + high2 + '|0) || ((' + high1 + '|0) == (' + high2 + '|0) && ' + - '(' + low1 + '|0) > (' + low2 + '|0))'; - case 'ult': return high1 + ' < ' + high2 + ' || (' + high1 + ' == ' + high2 + ' && ' + - low1 + ' < ' + low2 + ')'; + '(' + low1 + '>>>0) > (' + low2 + '>>>0))'; + case 'ult': return '(' + high1 + '>>>0) < (' + high2 + '>>>0) || ((' + high1 + '>>>0) == (' + high2 + '>>>0) && ' + + '(' + low1 + '>>>0) < (' + low2 + '>>>0))'; case 'slt': return '(' + high1 + '|0) < (' + high2 + '|0) || ((' + high1 + '|0) == (' + high2 + '|0) && ' + - '(' + low1 + '|0) < (' + low2 + '|0))'; + '(' + low1 + '>>>0) < (' + low2 + '>>>0))'; case 'ne': return low1 + ' != ' + low2 + ' || ' + high1 + ' != ' + high2 + ''; case 'eq': return low1 + ' == ' + low2 + ' && ' + high1 + ' == ' + high2 + ''; default: throw 'Unknown icmp variant: ' + variant; @@ -1704,9 +1704,9 @@ function processMathop(item) { // Dangerous, rounded operations. TODO: Fully emulate case 'add': warnI64_1(); return finish(splitI64(mergeI64(idents[0]) + '+' + mergeI64(idents[1]))); case 'sub': warnI64_1(); return finish(splitI64(mergeI64(idents[0]) + '-' + mergeI64(idents[1]))); - case 'sdiv': case 'udiv': warnI64_1(); return finish(splitI64(makeRounding(mergeI64(idents[0]) + '/' + mergeI64(idents[1]), bits, op[0] === 's'))); - case 'mul': warnI64_1(); return finish(splitI64(mergeI64(idents[0]) + '*' + mergeI64(idents[1]))); - case 'urem': case 'srem': warnI64_1(); return finish(splitI64(mergeI64(idents[0]) + '%' + mergeI64(idents[1]))); + case 'sdiv': case 'udiv': warnI64_1(); return finish(splitI64(makeRounding(mergeI64(idents[0], op[0] === 'u') + '/' + mergeI64(idents[1], op[0] === 'u'), bits, op[0] === 's'))); + case 'mul': warnI64_1(); return finish(splitI64(mergeI64(idents[0], op[0] === 'u') + '*' + mergeI64(idents[1], op[0] === 'u'))); + case 'urem': case 'srem': warnI64_1(); return finish(splitI64(mergeI64(idents[0], op[0] === 'u') + '%' + mergeI64(idents[1], op[0] === 'u'))); case 'bitcast': { // Pointers are not 64-bit, so there is really only one possible type of bitcast here, int to float or vice versa assert(USE_TYPED_ARRAYS == 2, 'Can only bitcast ints <-> floats with typed arrays mode 2'); diff --git a/src/postamble.js b/src/postamble.js index 390f9f27..56f0aee1 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -37,7 +37,9 @@ function run(args) { var ret = null; if (Module['_main']) { ret = Module.callMain(args); - exitRuntime(); + if (!Module['noExitRuntime']) { + exitRuntime(); + } } return ret; } diff --git a/src/preamble.js b/src/preamble.js index 45d2f4b2..98d12a43 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -583,7 +583,7 @@ var FUNCTION_TABLE; // XXX: In theory the indexes here can be equal to pointers var PAGE_SIZE = 4096; function alignMemoryPage(x) { - return Math.ceil(x/PAGE_SIZE)*PAGE_SIZE; + return ((x+4095)>>12)<<12; } var HEAP; diff --git a/src/shell.html b/src/shell.html index 69217b18..a41086b9 100644 --- a/src/shell.html +++ b/src/shell.html @@ -19,7 +19,10 @@ print: (function() { var element = document.getElementById('output'); return function(text) { - element.innerHTML += text.replace('\n', '<br>', 'g') + '<br>'; + text = text.replace(/</g, "<"); + text = text.replace(/>/g, ">"); + text = text.replace('\n', '<br>', 'g'); + element.innerHTML += text + '<br>'; }; })(), canvas: document.getElementById('canvas') diff --git a/src/shell.js b/src/shell.js index d67cc45a..bc527192 100644 --- a/src/shell.js +++ b/src/shell.js @@ -11,6 +11,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'); }; @@ -29,12 +30,16 @@ 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']) { @@ -44,11 +49,11 @@ if (ENVIRONMENT_IS_NODE) { } } 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); @@ -61,7 +66,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?'; @@ -72,17 +77,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 *** |