diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 5 | ||||
-rw-r--r-- | src/fastLong.js | 12 | ||||
-rw-r--r-- | src/intertyper.js | 43 | ||||
-rw-r--r-- | src/jsifier.js | 216 | ||||
-rw-r--r-- | src/library.js | 138 | ||||
-rw-r--r-- | src/library_fs.js | 14 | ||||
-rw-r--r-- | src/modules.js | 18 | ||||
-rw-r--r-- | src/parseTools.js | 124 | ||||
-rw-r--r-- | src/preamble.js | 20 | ||||
-rw-r--r-- | src/runtime.js | 19 | ||||
-rw-r--r-- | src/settings.js | 13 |
11 files changed, 395 insertions, 227 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index 3fb20253..17ad26ad 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -783,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; 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..09bdaa33 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -850,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 @@ -1013,7 +1014,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,14 +1069,36 @@ 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)))]); + //printErr(['\n', dump(ret), '\n', dump(triager(tokenizer(line)))]); var normal = triager(tokenizer(line)); delete normal.tokens; delete normal.indent; @@ -1087,11 +1111,14 @@ 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++; 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)) + makeBranch(item.labelFalse, item.currLabelId); if (labelTrue == ';' && labelFalse == ';') return ';'; - var head = 'if (' + condition + ') { '; - var head2 = 'if (!(' + condition + ')) { '; - var else_ = ' } else { '; - var tail = ' }'; + var head = 'if(' + condition + '){'; + var head2 = 'if(!(' + condition + ')){'; + var else_ = '}else{'; + var tail = '}'; if (labelTrue == ';') { return head2 + labelFalse + tail; } else if (labelFalse == ';') { @@ -1112,7 +1140,7 @@ function JSify(data, functionsOnly, givenFunctions) { item.groupedLabels = []; } if (!useIfs) { - ret += 'switch(' + signedIdent + ') {\n'; + ret += 'switch(' + signedIdent + '){'; } // process target labels, sorting them so output is consistently ordered keys(targetLabels).sort().forEach(function(targetLabel) { @@ -1125,17 +1153,17 @@ function JSify(data, functionsOnly, givenFunctions) { if (useIfs) { value = targetLabels[targetLabel].map(function(value) { return makeComparison(signedIdent, '==', makeSignOp(value, item.type, 're'), item.type) - }).join(' | '); - ret += 'if (' + value + ') {\n'; + }).join('|'); + ret += 'if(' + value + '){'; } else { value = targetLabels[targetLabel].map(function(value) { return 'case ' + makeSignOp(value, item.type, 're') + ':'; - }).join(' '); - ret += value + '{\n'; + }).join(''); + ret += value + '{'; } var phiSet = getPhiSetsForLabel(phiSets, targetLabel); - ret += INDENTATION + '' + phiSet + makeBranch(targetLabel, item.currLabelId || null) + '\n'; - ret += '}\n'; + ret += INDENTATION + '' + phiSet + makeBranch(targetLabel, item.currLabelId || null); + ret += '}'; if (RELOOP) { item.groupedLabels.push({ label: targetLabel, @@ -1146,15 +1174,15 @@ function JSify(data, functionsOnly, givenFunctions) { }); var phiSet = item.defaultLabelJS = getPhiSetsForLabel(phiSets, item.defaultLabel); if (useIfs) { - if (item.switchLabels.length > 0) ret += 'else {\n'; - ret += phiSet + makeBranch(item.defaultLabel, item.currLabelId) + '\n'; - if (item.switchLabels.length > 0) ret += '}\n'; + if (item.switchLabels.length > 0) ret += 'else{'; + ret += phiSet + makeBranch(item.defaultLabel, item.currLabelId) + ''; + if (item.switchLabels.length > 0) ret += '}'; } else { - ret += 'default: {\n'; - ret += phiSet + makeBranch(item.defaultLabel, item.currLabelId) + '\n'; - ret += '}\n'; + ret += 'default:{'; + ret += phiSet + makeBranch(item.defaultLabel, item.currLabelId) + ''; + ret += '}'; - ret += '} break; \n'; // finish switch and break, to move control flow properly (breaks from makeBranch just broke out of the switch) + ret += '}break;'; // finish switch and break, to move control flow properly (breaks from makeBranch just broke out of the switch) } if (item.value) { ret += ' ' + toNiceIdent(item.value); @@ -1162,10 +1190,11 @@ function JSify(data, functionsOnly, givenFunctions) { return ret; } function returnHandler(item) { - var ret = RuntimeGenerator.stackExit(item.funcData.initialStack, item.funcData.otherStackAllocations) + ';\n'; + var ret = RuntimeGenerator.stackExit(item.funcData.initialStack, item.funcData.otherStackAllocations); + if (ret.length > 0) ret += ';'; if (LABEL_DEBUG && functionNameFilterTest(item.funcData.ident)) { - ret += "Module.print(INDENT + 'Exiting: " + item.funcData.ident + "');\n" - + "INDENT = INDENT.substr(0, INDENT.length-2);\n"; + ret += "Module.print(INDENT + 'Exiting: " + item.funcData.ident + "');" + + "INDENT = INDENT.substr(0, INDENT.length-2);"; } ret += 'return'; var value = item.value ? finalizeLLVMParameter(item.value) : null; @@ -1191,7 +1220,7 @@ function JSify(data, functionsOnly, givenFunctions) { // in an assignment var disabled = DISABLE_EXCEPTION_CATCHING == 2 && !(item.funcData.ident in EXCEPTION_CATCHING_WHITELIST); var phiSets = calcPhiSets(item); - var call_ = makeFunctionCall(item.ident, item.params, item.funcData, item.type, ASM_JS && !disabled, !!item.assignTo || !item.standalone, true); + var call_ = makeFunctionCall(item, item.params, item.funcData, item.type, ASM_JS && !disabled, !!item.assignTo || !item.standalone, true); var ret; @@ -1217,11 +1246,16 @@ function JSify(data, functionsOnly, givenFunctions) { ret = makeVarArgsCleanup(ret); if (item.assignTo) { - ret = 'var ' + item.assignTo + ' = ' + ret; - if (USE_TYPED_ARRAYS == 2 && isIllegalType(item.type)) { + var illegal = USE_TYPED_ARRAYS == 2 && isIllegalType(item.type); + var assignTo = illegal ? item.assignTo + '$r' : item.assignTo; + ret = makeVarDef(assignTo) + '=' + ret; + if (ASM_JS) addVariable(assignTo, item.type); + if (illegal) { var bits = getBits(item.type); for (var i = 0; i < bits/32; i++) { - ret += 'var ' + item.assignTo + '$' + i + ' = ' + (i == 0 ? item.assignTo : 'tempRet' + (i-1)) + ';' + var v = item.assignTo + '$' + i; + ret += makeVarDef(v) + '=' + (i == 0 ? assignTo : 'tempRet' + (i-1)) + ';' + if (ASM_JS) addVariable(v, 'i32'); } } item.assignTo = null; @@ -1252,8 +1286,12 @@ function JSify(data, functionsOnly, givenFunctions) { } } function landingpadHandler(item) { + if (ASM_JS) { + addVariable(item.assignTo + '$0', 'i32'); + addVariable(item.assignTo + '$1', 'i32'); + } if (DISABLE_EXCEPTION_CATCHING && !(item.funcData.ident in EXCEPTION_CATCHING_WHITELIST) && USE_TYPED_ARRAYS == 2) { - ret = makeVarDef(item.assignTo) + '$0 = 0; ' + item.assignTo + '$1 = 0;'; + ret = makeVarDef(item.assignTo) + '$0 = 0; ' + makeVarDef(item.assignTo) + '$1 = 0;'; item.assignTo = null; if (VERBOSE) warnOnce('landingpad, but exceptions are disabled!'); return ret; @@ -1261,7 +1299,7 @@ function JSify(data, functionsOnly, givenFunctions) { var catchTypeArray = item.catchables.map(finalizeLLVMParameter).map(function(element) { return asmCoercion(element, 'i32') }).join(','); var ret = asmCoercion('___cxa_find_matching_catch(-1, -1' + (catchTypeArray.length > 0 ? ',' + catchTypeArray : '') +')', 'i32'); if (USE_TYPED_ARRAYS == 2) { - ret = makeVarDef(item.assignTo) + '$0 = ' + ret + '; ' + item.assignTo + '$1 = tempRet0;'; + ret = makeVarDef(item.assignTo) + '$0 = ' + ret + '; ' + makeVarDef(item.assignTo) + '$1 = tempRet0;'; item.assignTo = null; } return ret; @@ -1307,13 +1345,14 @@ function JSify(data, functionsOnly, givenFunctions) { item.ident = 'tempValue'; ret += item.ident + ' = [' + makeEmptyStruct(item.type) + '], '; } - return ret + item.ident + '.f' + item.indexes[0][0].text + ' = ' + finalizeLLVMParameter(item.value) + ', ' + item.ident + ')'; + return ret + item.ident + '.f' + item.indexes[0][0].text + '=' + finalizeLLVMParameter(item.value) + ', ' + item.ident + ')'; } function indirectbrHandler(item) { var phiSets = calcPhiSets(item); - var js = 'var ibr = ' + finalizeLLVMParameter(item.value) + ';\n'; + var js = makeVarDef('ibr') + '=' + finalizeLLVMParameter(item.value) + ';'; + if (ASM_JS) addVariable('ibr', 'i32'); for (var targetLabel in phiSets) { - js += 'if (' + makeComparison('ibr', '==', targetLabel, 'i32') + ') { ' + getPhiSetsForLabel(phiSets, targetLabel) + ' }\n'; + js += 'if(' + makeComparison('ibr', '==', targetLabel, 'i32') + '){' + getPhiSetsForLabel(phiSets, targetLabel) + '}'; } return js + makeBranch('ibr', item.currLabelId, true); } @@ -1349,7 +1388,9 @@ function JSify(data, functionsOnly, givenFunctions) { return ret; } - function makeFunctionCall(ident, params, funcData, type, forceByPointer, hasReturn, invoke) { + function makeFunctionCall(item, params, funcData, type, forceByPointer, hasReturn, invoke) { + var ident = item.ident; + // We cannot compile assembly. See comment in intertyper.js:'Call' assert(ident != 'asm', 'Inline assembly cannot be compiled to JavaScript!'); @@ -1368,7 +1409,7 @@ function JSify(data, functionsOnly, givenFunctions) { var callIdent = LibraryManager.getRootIdent(simpleIdent); if (callIdent) { simpleIdent = callIdent; // ident may not be in library, if all there is is ident__inline, but in this case it is - if (callIdent.indexOf('.') < 0) { + if (callIdent.indexOf('Math_') !== 0) { callIdent = '_' + callIdent; // Not Math.*, so add the normal prefix } } else { @@ -1499,6 +1540,9 @@ function JSify(data, functionsOnly, givenFunctions) { if (trueType !== returnType && !isIdenticallyImplemented(trueType, returnType)) { if (VERBOSE) warnOnce('Fixing function call based on return type from signature, on ' + [callIdent, returnType, trueType]); returnType = trueType; + if (trueType === 'void') { + item.assignTo = null; + } } } } @@ -1526,7 +1570,7 @@ function JSify(data, functionsOnly, givenFunctions) { if (!ASM_JS || functionTableCall) callIdent = Functions.getTable(sig) + '[' + callIdent + ']'; } - var ret = callIdent + '(' + args.join(', ') + ')'; + var ret = callIdent + '(' + args.join(',') + ')'; if (ASM_JS) { // TODO: do only when needed (library functions and Math.*?) XXX && simpleIdent in Functions.libraryFunctions) { ret = asmCoercion(ret, returnType); if (simpleIdent == 'abort' && funcData.returnType != 'void') { @@ -1537,7 +1581,7 @@ function JSify(data, functionsOnly, givenFunctions) { if (ASM_JS && funcData.setjmpTable) { // check if a longjmp was done. If a setjmp happened, check if ours. If ours, go to a special label to handle it. // otherwise, just return - the call to us must also have been an invoke, so the setjmp propagates that way - ret += '; if (((__THREW__|0) != 0) & ((threwValue|0) != 0)) { setjmpLabel = ' + asmCoercion('_testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable)', 'i32') + '; if ((setjmpLabel|0) > 0) { label = ' + SETJMP_LABEL + '; break } else return ' + (funcData.returnType != 'void' ? asmCoercion('0', funcData.returnType) : '') + ' } __THREW__ = threwValue = 0;\n'; + ret += '; if (((__THREW__|0) != 0) & ((threwValue|0) != 0)) { setjmpLabel = ' + asmCoercion('_testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable)', 'i32') + '; if ((setjmpLabel|0) > 0) { label = ' + SETJMP_LABEL + '; break } else return ' + (funcData.returnType != 'void' ? asmCoercion('0', funcData.returnType) : '') + ' } __THREW__ = threwValue = 0;'; } return ret; @@ -1558,7 +1602,7 @@ function JSify(data, functionsOnly, givenFunctions) { function getelementptrHandler(item) { return finalizeLLVMFunctionCall(item) } function callHandler(item) { if (item.standalone && LibraryManager.isStubFunction(item.ident)) return ';'; - var ret = makeFunctionCall(item.ident, item.params, item.funcData, item.type, false, !!item.assignTo || !item.standalone) + (item.standalone ? ';' : ''); + var ret = makeFunctionCall(item, item.params, item.funcData, item.type, false, !!item.assignTo || !item.standalone) + (item.standalone ? ';' : ''); return makeVarArgsCleanup(ret); } @@ -1805,14 +1849,14 @@ function JSify(data, functionsOnly, givenFunctions) { var shellParts = read(shellFile).split('{{BODY}}'); print(processMacros(preprocess(shellParts[1]))); // Print out some useful metadata - if (EMIT_GENERATED_FUNCTIONS || PGO) { + if (RUNNING_JS_OPTS || PGO) { var generatedFunctions = JSON.stringify(keys(Functions.implementedFunctions).filter(function(func) { return IGNORED_FUNCTIONS.indexOf(func.ident) < 0; })); if (PGO) { print('PGOMonitor.allGenerated = ' + generatedFunctions + ';\nremoveRunDependency("pgo");\n'); } - if (EMIT_GENERATED_FUNCTIONS) { + if (RUNNING_JS_OPTS) { print('// EMSCRIPTEN_GENERATED_FUNCTIONS: ' + generatedFunctions + '\n'); } } diff --git a/src/library.js b/src/library.js index 02981a80..5e71b087 100644 --- a/src/library.js +++ b/src/library.js @@ -459,14 +459,17 @@ LibraryManager.library = { // http://pubs.opengroup.org/onlinepubs/009695399/functions/creat.html return _open(path, {{{ cDefine('O_WRONLY') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_TRUNC') }}}, allocate([mode, 0, 0, 0], 'i32', ALLOC_STACK)); }, - mkstemp__deps: ['creat'], - mkstemp: function(template) { - if (!_mkstemp.counter) _mkstemp.counter = 0; - var c = (_mkstemp.counter++).toString(); + mktemp: function(template) { + if (!_mktemp.counter) _mktemp.counter = 0; + var c = (_mktemp.counter++).toString(); var rep = 'XXXXXX'; while (c.length < rep.length) c = '0' + c; writeArrayToMemory(intArrayFromString(c), template + Pointer_stringify(template).indexOf(rep)); - return _creat(template, 0600); + return template; + }, + mkstemp__deps: ['creat', 'mktemp'], + mkstemp: function(template) { + return _creat(_mktemp(template), 0600); }, fcntl__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'], fcntl: function(fildes, cmd, varargs, dup2) { @@ -3005,8 +3008,8 @@ LibraryManager.library = { return ret; }, - abs: 'Math.abs', - labs: 'Math.abs', + abs: 'Math_abs', + labs: 'Math_abs', #if USE_TYPED_ARRAYS == 2 llabs__deps: [function() { Types.preciseI64MathUsed = 1 }], llabs: function(lo, hi) { @@ -3799,8 +3802,8 @@ LibraryManager.library = { p1 = p1|0; p2 = p2|0; num = num|0; var i = 0, v1 = 0, v2 = 0; while ((i|0) < (num|0)) { - var v1 = {{{ makeGetValueAsm('p1', 'i', 'i8', true) }}}; - var v2 = {{{ makeGetValueAsm('p2', 'i', 'i8', true) }}}; + v1 = {{{ makeGetValueAsm('p1', 'i', 'i8', true) }}}; + v2 = {{{ makeGetValueAsm('p2', 'i', 'i8', true) }}}; if ((v1|0) != (v2|0)) return ((v1|0) > (v2|0) ? 1 : -1)|0; i = (i+1)|0; } @@ -4224,9 +4227,9 @@ LibraryManager.library = { var ret = 0; ret = {{{ makeGetValueAsm('ctlz_i8', 'x >>> 24', 'i8') }}}; if ((ret|0) < 8) return ret|0; - var ret = {{{ makeGetValueAsm('ctlz_i8', '(x >> 16)&0xff', 'i8') }}}; + ret = {{{ makeGetValueAsm('ctlz_i8', '(x >> 16)&0xff', 'i8') }}}; if ((ret|0) < 8) return (ret + 8)|0; - var ret = {{{ makeGetValueAsm('ctlz_i8', '(x >> 8)&0xff', 'i8') }}}; + ret = {{{ makeGetValueAsm('ctlz_i8', '(x >> 8)&0xff', 'i8') }}}; if ((ret|0) < 8) return (ret + 16)|0; return ({{{ makeGetValueAsm('ctlz_i8', 'x&0xff', 'i8') }}} + 24)|0; }, @@ -4260,9 +4263,9 @@ LibraryManager.library = { var ret = 0; ret = {{{ makeGetValueAsm('cttz_i8', 'x & 0xff', 'i8') }}}; if ((ret|0) < 8) return ret|0; - var ret = {{{ makeGetValueAsm('cttz_i8', '(x >> 8)&0xff', 'i8') }}}; + ret = {{{ makeGetValueAsm('cttz_i8', '(x >> 8)&0xff', 'i8') }}}; if ((ret|0) < 8) return (ret + 8)|0; - var ret = {{{ makeGetValueAsm('cttz_i8', '(x >> 16)&0xff', 'i8') }}}; + ret = {{{ makeGetValueAsm('cttz_i8', '(x >> 16)&0xff', 'i8') }}}; if ((ret|0) < 8) return (ret + 16)|0; return ({{{ makeGetValueAsm('cttz_i8', 'x >>> 24', 'i8') }}} + 24)|0; }, @@ -4699,30 +4702,30 @@ LibraryManager.library = { // math.h |