diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 167 | ||||
-rw-r--r-- | src/compiler.js | 23 | ||||
-rw-r--r-- | src/intertyper.js | 19 | ||||
-rw-r--r-- | src/jsifier.js | 208 | ||||
-rw-r--r-- | src/library.js | 595 | ||||
-rw-r--r-- | src/library_browser.js | 78 | ||||
-rw-r--r-- | src/library_gc.js | 4 | ||||
-rw-r--r-- | src/library_gl.js | 123 | ||||
-rw-r--r-- | src/library_glut.js | 28 | ||||
-rw-r--r-- | src/library_sdl.js | 20 | ||||
-rw-r--r-- | src/long.js | 33 | ||||
-rw-r--r-- | src/modules.js | 88 | ||||
-rw-r--r-- | src/parseTools.js | 291 | ||||
-rw-r--r-- | src/postamble.js | 8 | ||||
-rw-r--r-- | src/preamble.js | 73 | ||||
-rw-r--r-- | src/relooper/Relooper.cpp | 16 | ||||
-rw-r--r-- | src/relooper/Relooper.h | 4 | ||||
-rw-r--r-- | src/relooper/emscripten/Makefile | 18 | ||||
-rw-r--r-- | src/relooper/emscripten/glue.js | 3 | ||||
-rw-r--r-- | src/relooper/test.txt | 4 | ||||
-rw-r--r-- | src/runtime.js | 86 | ||||
-rw-r--r-- | src/settings.js | 25 | ||||
-rw-r--r-- | src/utility.js | 6 |
23 files changed, 1263 insertions, 657 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index 014579f4..0ad3e017 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -19,7 +19,7 @@ function recomputeLines(func) { var BRANCH_INVOKE = set('branch', 'invoke'); var SIDE_EFFECT_CAUSERS = set('call', 'invoke', 'atomic'); -var UNUNFOLDABLE = set('value', 'type', 'phiparam'); +var UNUNFOLDABLE = set('value', 'structvalue', 'type', 'phiparam'); // Analyzer @@ -120,12 +120,14 @@ function analyzer(data, sidePass) { processItem: function(data) { // Legalization if (USE_TYPED_ARRAYS == 2) { - function getLegalVars(base, bits) { - assert(!isNumber(base)); + function getLegalVars(base, bits, allowLegal) { + if (allowLegal && bits <= 32) return [{ ident: base, bits: bits }]; + if (isNumber(base)) return getLegalLiterals(base, bits); var ret = new Array(Math.ceil(bits/32)); var i = 0; + if (base == 'zeroinitializer' || base == 'undef') base = 0; while (bits > 0) { - ret[i] = { ident: base + '$' + i, bits: Math.min(32, bits) }; + ret[i] = { ident: base ? base + '$' + i : '0', bits: Math.min(32, bits) }; bits -= 32; i++; } @@ -142,6 +144,23 @@ function analyzer(data, sidePass) { } return ret; } + function getLegalStructuralParts(value) { + return value.params.slice(0); + } + function getLegalParams(params, bits) { + return params.map(function(param) { + var value = param.value || param; + if (isNumber(value.ident)) { + 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) }; + }); + } else { + return getLegalVars(value.ident, bits); + } + }); + } // Uses the right factor to multiply line numbers by so that they fit in between // the line[i] and the line after it function interpLines(lines, i, toAdd) { @@ -191,6 +210,7 @@ function analyzer(data, sidePass) { // Legalize lines in labels var tempId = 0; func.labels.forEach(function(label) { + if (dcheck('legalizer')) dprint('zz legalizing: \n' + dump(label.lines)); var i = 0, bits; while (i < label.lines.length) { var item = label.lines[i]; @@ -207,8 +227,12 @@ function analyzer(data, sidePass) { if (isIllegalType(item.valueType) || isIllegalType(item.type)) { isIllegal = true; } + if ((item.intertype == 'load' || item.intertype == 'store') && isStructType(item.valueType)) { + isIllegal = true; // storing an entire structure is illegal + } }); if (!isIllegal) { + //if (dcheck('legalizer')) dprint('no need to legalize \n' + dump(item)); i++; continue; } @@ -222,10 +246,10 @@ function analyzer(data, sidePass) { if (subItem != item && (!(subItem.intertype in UNUNFOLDABLE) || (subItem.intertype == 'value' && isNumber(subItem.ident) && isIllegalType(subItem.type)))) { if (item.intertype == 'phi') { - assert(subItem.intertype == 'value', 'We can only unfold illegal constants in phis'); + assert(subItem.intertype == 'value' || subItem.intertype == 'structvalue', 'We can only unfold illegal constants in phis'); // we must handle this in the phi itself, if we unfold normally it will not be pushed back with the phi } else { - var tempIdent = '$$emscripten$temp$' + (tempId++); + var tempIdent = '$$etemp$' + (tempId++); subItem.assignTo = tempIdent; unfolded.unshift(subItem); fixUnfolded(subItem); @@ -234,7 +258,7 @@ function analyzer(data, sidePass) { } else if (subItem.intertype == 'switch' && isIllegalType(subItem.type)) { subItem.switchLabels.forEach(function(switchLabel) { if (switchLabel.value[0] != '$') { - var tempIdent = '$$emscripten$temp$' + (tempId++); + var tempIdent = '$$etemp$' + (tempId++); unfolded.unshift({ assignTo: tempIdent, intertype: 'value', @@ -258,8 +282,7 @@ function analyzer(data, sidePass) { case 'store': { var toAdd = []; bits = getBits(item.valueType); - var elements; - elements = getLegalVars(item.value.ident, bits); + var elements = getLegalParams([item.value], bits)[0]; var j = 0; elements.forEach(function(element) { var tempVar = '$st$' + i + '$' + j; @@ -290,32 +313,43 @@ function analyzer(data, sidePass) { i += removeAndAdd(label.lines, i, toAdd); continue; } - // call, return: Return value is in an unlegalized array literal. Not fully optimal. + // call, return: Return the first 32 bits, the rest are in temp case 'call': { bits = getBits(value.type); var elements = getLegalVars(item.assignTo, bits); var toAdd = [value]; // legalize parameters legalizeFunctionParameters(value.params); - if (value.assignTo) { + if (value.assignTo && isIllegalType(item.type)) { // legalize return value - var j = 0; - toAdd = toAdd.concat(elements.map(function(element) { - return { + value.assignTo = elements[0].ident; + for (var j = 1; j < elements.length; j++) { + var element = elements[j]; + toAdd.push({ intertype: 'value', assignTo: element.ident, - type: 'i' + bits, - ident: value.assignTo + '[' + (j++) + ']' - }; - })); + type: element.bits, + ident: 'tempRet' + (j - 1) + }); + assert(j<10); // TODO: dynamically create more than 10 tempRet-s + } } i += removeAndAdd(label.lines, i, toAdd); continue; } + case 'landingpad': { + // not much to legalize + i++; + continue; + } case 'return': { bits = getBits(item.type); var elements = getLegalVars(item.value.ident, bits); - item.value.ident = '[' + elements.map(function(element) { return element.ident }).join(',') + ']'; + item.value.ident = '('; + for (var j = 1; j < elements.length; j++) { + item.value.ident += 'tempRet' + (j-1) + '=' + elements[j].ident + ','; + } + item.value.ident += elements[0].ident + ')'; i++; continue; } @@ -341,6 +375,21 @@ function analyzer(data, sidePass) { i += removeAndAdd(label.lines, i, toAdd); continue; } + case 'structvalue': { + bits = getBits(value.type); + var elements = getLegalVars(item.assignTo, bits); + var toAdd = []; + for (var j = 0; j < item.params.length; j++) { + toAdd[j] = { + intertype: 'value', + assignTo: elements[j].ident, + type: 'i32', + ident: item.params[j].ident + }; + } + i += removeAndAdd(label.lines, i, toAdd); + continue; + } case 'load': { bits = getBits(value.valueType); var elements = getLegalVars(item.assignTo, bits); @@ -382,13 +431,9 @@ function analyzer(data, sidePass) { var toAdd = []; var elements = getLegalVars(item.assignTo, bits); var j = 0; - var literalValues = {}; // special handling of literals - we cannot unfold them normally - value.params.map(function(param) { - if (isNumber(param.value.ident)) { - literalValues[param.value.ident] = getLegalLiterals(param.value.ident, bits); - } - }); + var values = getLegalParams(value.params, bits); elements.forEach(function(element) { + var k = 0; toAdd.push({ intertype: 'phi', assignTo: element.ident, @@ -399,7 +444,7 @@ function analyzer(data, sidePass) { label: param.label, value: { intertype: 'value', - ident: (param.value.ident in literalValues) ? literalValues[param.value.ident][j].ident : (param.value.ident + '$' + j), + ident: values[k++][j].ident, type: 'i' + element.bits, } }; @@ -414,6 +459,62 @@ function analyzer(data, sidePass) { i++; continue; // special case, handled in makeComparison } + case 'extractvalue': { // XXX we assume 32-bit alignment in extractvalue/insertvalue, + // but in theory they can run on packed structs too (see use getStructuralTypePartBits) + // potentially legalize the actual extracted value too if it is >32 bits, not just the extraction in general + var index = item.indexes[0][0].text; + var parts = getStructureTypeParts(item.type); + var indexedType = parts[index]; + var targetBits = getBits(indexedType); + var sourceBits = getBits(item.type); + var elements = getLegalVars(item.assignTo, targetBits, true); // possibly illegal + var sourceElements = getLegalVars(item.ident, sourceBits); // definitely illegal + var toAdd = []; + var sourceIndex = 0; + for (var partIndex = 0; partIndex < parts.length; partIndex++) { + if (partIndex == index) { + for (var j = 0; j < elements.length; j++) { + toAdd.push({ + intertype: 'value', + assignTo: elements[j].ident, + type: 'i' + elements[j].bits, + ident: sourceElements[sourceIndex+j].ident + }); + } + break; + } + sourceIndex += getStructuralTypePartBits(parts[partIndex])/32; + } + i += removeAndAdd(label.lines, i, toAdd); + continue; + } + case 'insertvalue': { + var index = item.indexes[0][0].text; // the modified index + var parts = getStructureTypeParts(item.type); + var indexedType = parts[index]; + var indexBits = getBits(indexedType); + var bits = getBits(item.type); // source and target + bits = getBits(value.type); + var toAdd = []; + var elements = getLegalVars(item.assignTo, bits); + var sourceElements = getLegalVars(item.ident, bits); + var indexElements = getLegalVars(item.value.ident, indexBits, true); // possibly legal + var sourceIndex = 0; + for (var partIndex = 0; partIndex < parts.length; partIndex++) { + var currNum = getStructuralTypePartBits(parts[partIndex])/32; + for (var j = 0; j < currNum; j++) { + toAdd.push({ + intertype: 'value', + assignTo: elements[sourceIndex+j].ident, + type: 'i' + elements[sourceIndex+j].bits, + ident: partIndex == index ? indexElements[j].ident : sourceElements[sourceIndex+j].ident + }); + } + sourceIndex += currNum; + } + i += removeAndAdd(label.lines, i, toAdd); + continue; + } case 'bitcast': { var inType = item.type2; var outType = item.type; @@ -477,17 +578,16 @@ function analyzer(data, sidePass) { } case 'select': { sourceBits = targetBits = getBits(value.params[1].type); - var otherElementsA = getLegalVars(value.params[1].ident, sourceBits); - var otherElementsB = getLegalVars(value.params[2].ident, sourceBits); + var params = getLegalParams(value.params.slice(1), sourceBits); processor = function(result, j) { return { intertype: 'mathop', op: 'select', - type: 'i' + otherElementsA[j].bits, + type: 'i' + params[0][j].bits, params: [ value.params[0], - { intertype: 'value', ident: otherElementsA[j].ident, type: 'i' + otherElementsA[j].bits }, - { intertype: 'value', ident: otherElementsB[j].ident, type: 'i' + otherElementsB[j].bits } + { intertype: 'value', ident: params[0][j].ident, type: 'i' + params[0][j].bits }, + { intertype: 'value', ident: params[1][j].ident, type: 'i' + params[1][j].bits } ] }; }; @@ -554,9 +654,10 @@ function analyzer(data, sidePass) { // We can't statically legalize this, do the operation at runtime TODO: optimize assert(sourceBits == 64, 'TODO: handle nonconstant shifts on != 64 bits'); value.intertype = 'value'; - value.ident = 'Runtime.bitshift64(' + sourceElements[0].ident + ', ' + + value.ident = 'Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + sourceElements[0].ident + ', ' + sourceElements[1].ident + ',"' + value.op + '",' + value.params[1].ident + '$0);' + - 'var ' + value.assignTo + '$0 = ' + value.assignTo + '[0], ' + value.assignTo + '$1 = ' + value.assignTo + '[1];'; + 'var ' + value.assignTo + '$0 = ' + makeGetTempDouble(0) + ', ' + value.assignTo + '$1 = ' + makeGetTempDouble(1) + ';'; + value.assignTo = null; i++; continue; } diff --git a/src/compiler.js b/src/compiler.js index 35f746a5..118ca83a 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -174,18 +174,25 @@ RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG; // Settings sanity checks 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 // Output some info and warnings based on settings -if (!MICRO_OPTS || !RELOOP || ASSERTIONS || CHECK_SIGNS || CHECK_OVERFLOWS || INIT_STACK || INIT_HEAP || - !SKIP_STACK_IN_SMALL || SAFE_HEAP || PGO || PROFILE || !DISABLE_EXCEPTION_CATCHING) { - print('// Note: Some Emscripten settings will significantly limit the speed of the generated code.'); -} else { - print('// Note: For maximum-speed code, see "Optimizing Code" on the Emscripten wiki, https://github.com/kripken/emscripten/wiki/Optimizing-Code'); -} +if (phase == 'pre') { + if (!MICRO_OPTS || !RELOOP || ASSERTIONS || CHECK_SIGNS || CHECK_OVERFLOWS || INIT_STACK || INIT_HEAP || + !SKIP_STACK_IN_SMALL || SAFE_HEAP || PGO || PROFILE || !DISABLE_EXCEPTION_CATCHING) { + print('// Note: Some Emscripten settings will significantly limit the speed of the generated code.'); + } else { + print('// Note: For maximum-speed code, see "Optimizing Code" on the Emscripten wiki, https://github.com/kripken/emscripten/wiki/Optimizing-Code'); + } -if (DOUBLE_MODE || CORRECT_SIGNS || CORRECT_OVERFLOWS || CORRECT_ROUNDINGS) { - print('// Note: Some Emscripten settings may limit the speed of the generated code.'); + if (DOUBLE_MODE || CORRECT_SIGNS || CORRECT_OVERFLOWS || CORRECT_ROUNDINGS) { + print('// Note: Some Emscripten settings may limit the speed of the generated code.'); + } } // Load compiler code diff --git a/src/intertyper.js b/src/intertyper.js index 5af291c7..5bca9236 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -69,11 +69,13 @@ function intertyper(data, sidePass, baseLineNums) { if (mainPass && (line[0] == '%' || line[0] == '@')) { // If this isn't a type, it's a global variable, make a note of the information now, we will need it later - var testType = /[@%\w\d\.\" $-]+ = type .*/.exec(line); + var parts = line.split(' = '); + assert(parts.length >= 2); + var left = parts[0], right = parts.slice(1).join(' = '); + var testType = /^type .*/.exec(right); if (!testType) { - var global = /([@%\w\d\.\" $-]+) = .*/.exec(line); - var globalIdent = toNiceIdent(global[1]); - var testAlias = /[@%\w\d\.\" $-]+ = (hidden )?alias .*/.exec(line); + var globalIdent = toNiceIdent(left); + var testAlias = /^(hidden )?alias .*/.exec(right); Variables.globals[globalIdent] = { name: globalIdent, alias: !!testAlias, @@ -125,6 +127,7 @@ function intertyper(data, sidePass, baseLineNums) { // We need this early, to know basic function info - ident, params, varargs ident: toNiceIdent(func.ident), params: func.params, + returnType: func.returnType, hasVarArgs: func.hasVarArgs, lineNum: currFunctionLineNum, lines: currFunctionLines @@ -520,7 +523,12 @@ function intertyper(data, sidePass, baseLineNums) { if (item.tokens[3].item) { var subTokens = item.tokens[3].item.tokens; splitTokenList(subTokens).forEach(function(segment) { - ret.ctors.push(segment[1].tokens.slice(-1)[0].text); + var ctor = toNiceIdent(segment[1].tokens.slice(-1)[0].text); + ret.ctors.push(ctor); + if (ASM_JS) { // must export the global constructors from asm.js module, so mark as implemented and exported + Functions.implementedFunctions[ctor] = 'v'; + EXPORTED_FUNCTIONS[ctor] = 1; + } }); } } else if (!external) { @@ -741,6 +749,7 @@ function intertyper(data, sidePass, baseLineNums) { } var last = getTokenIndexByText(item.tokens, ';'); item.params = splitTokenList(item.tokens.slice(1, last)).map(parseLLVMSegment); + item.type = item.params[1].type; this.forwardItem(item, 'Reintegrator'); } }); diff --git a/src/jsifier.js b/src/jsifier.js index 70329b3f..e41bcf67 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -9,6 +9,8 @@ var STRUCT_LIST = set('struct', 'list'); var UNDERSCORE_OPENPARENS = set('_', '('); var RELOOP_IGNORED_LASTS = set('return', 'unreachable', 'resume'); +var addedLibraryItems = {}; + // JSifier function JSify(data, functionsOnly, givenFunctions) { var mainPass = !functionsOnly; @@ -42,7 +44,9 @@ function JSify(data, functionsOnly, givenFunctions) { var pre = processMacros(preprocess(read(preFile).replace('{{RUNTIME}}', getRuntime()))); print(pre); - Functions.implementedFunctions = set(data.unparsedFunctions.map(function(func) { return func.ident })); + data.unparsedFunctions.forEach(function(func) { + Functions.implementedFunctions[func.ident] = Functions.getSignature(func.returnType, func.params.map(function(param) { return param.type })); + }); } } @@ -258,7 +262,7 @@ function JSify(data, functionsOnly, givenFunctions) { var ret = [item]; if (item.ident == '_llvm_global_ctors') { item.JS = '\n__ATINIT__ = __ATINIT__.concat([\n' + - item.ctors.map(function(ctor) { return ' { func: ' + toNiceIdent(ctor) + ' }' }).join(',\n') + + item.ctors.map(function(ctor) { return ' { func: function() { ' + ctor + '() } }' }).join(',\n') + '\n]);\n'; return ret; } else { @@ -273,12 +277,13 @@ function JSify(data, functionsOnly, givenFunctions) { item.JS = makeGlobalDef(item.ident); } - if (item.external) { + if (item.external && !ASM_JS) { // ASM_JS considers externs to be globals // Import external global variables from the library if available. var shortident = item.ident.slice(1); if (LibraryManager.library[shortident] && LibraryManager.library[shortident].length && !BUILD_AS_SHARED_LIB) { + if (addedLibraryItems[shortident]) return ret; var val = LibraryManager.library[shortident]; var padding; if (Runtime.isNumberType(item.type) || isPointerType(item.type)) { @@ -302,7 +307,17 @@ function JSify(data, functionsOnly, givenFunctions) { index = makeGlobalUse(item.ident); // index !== null indicates we are indexing this allocator = 'ALLOC_NONE'; } - constant = parseConst(item.value, item.type, item.ident); + if (item.external) { + assert(ASM_JS); + if (Runtime.isNumberType(item.type) || isPointerType(item.type)) { + constant = zeros(Runtime.getNativeFieldSize(item.type)); + } else { + constant = makeEmptyStruct(item.type); + } + constant = JSON.stringify(constant); + } else { + constant = parseConst(item.value, item.type, item.ident); + } if (typeof constant === 'string' && constant[0] != '[') { constant = [constant]; // A single item. We may need a postset for it. } @@ -333,13 +348,17 @@ function JSify(data, functionsOnly, givenFunctions) { } js += '\n' + makePointer('[0]', null, allocator, ['void*'], index) + ';'; } - if (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS)) { + if (!ASM_JS && (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS))) { js += '\nModule["' + item.ident + '"] = ' + item.ident + ';'; } if (BUILD_AS_SHARED_LIB == 2 && !item.private_) { // TODO: make the assert conditional on ASSERTIONS js += 'if (globalScope) { assert(!globalScope["' + item.ident + '"]); globalScope["' + item.ident + '"] = ' + item.ident + ' }'; } + if (item.external && !NAMED_GLOBALS) { + assert(ASM_JS); + js = 'var ' + item.ident + ' = ' + js; // force an explicit naming, even if unnamed globals, for asm forwarding + } return ret.concat({ intertype: 'GlobalVariable', JS: js, @@ -377,8 +396,6 @@ function JSify(data, functionsOnly, givenFunctions) { } }); - var addedLibraryItems = {}; - // functionStub substrate.addActor('FunctionStub', { processItem: function(item) { @@ -399,13 +416,19 @@ function JSify(data, functionsOnly, givenFunctions) { var isFunction = false; if (typeof snippet === 'string') { - if (LibraryManager.library[snippet]) { + var target = LibraryManager.library[snippet]; + if (target) { // Redirection for aliases. We include the parent, and at runtime make ourselves equal to it. // This avoid having duplicate functions with identical content. redirectedIdent = snippet; deps.push(snippet); snippet = '_' + snippet; } + // 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\..+/.exec(snippet))) { + Functions.libraryFunctions[ident] = 1; + } } else if (typeof snippet === 'object') { snippet = stringifyWithFunctions(snippet); } else if (typeof snippet === 'function') { @@ -420,6 +443,7 @@ function JSify(data, functionsOnly, givenFunctions) { snippet = snippet.replace('{', '{ var ret = (function() { if (Runtime.debug) Module.print("[library call:' + ident + ': " + Array.prototype.slice.call(arguments).map(Runtime.prettyPrint) + "]"); '); snippet = snippet.substr(0, snippet.length-1) + '}).apply(this, arguments); if (Runtime.debug && typeof ret !== "undefined") Module.print(" [ return:" + Runtime.prettyPrint(ret)); return ret; }'; } + if (ASM_JS) Functions.libraryFunctions[ident] = 1; } var postsetId = ident + '__postset'; @@ -435,6 +459,18 @@ function JSify(data, functionsOnly, givenFunctions) { if (redirectedIdent) { deps = deps.concat(LibraryManager.library[redirectedIdent + '__deps'] || []); } + if (ASM_JS) { + // In asm, dependencies implemented in C might be needed by JS library functions. + // We don't know yet if they are implemented in C or not. To be safe, export such + // special cases. + [LIBRARY_DEPS_TO_AUTOEXPORT].forEach(function(special) { + deps.forEach(function(dep) { + if (dep == special && !EXPORTED_FUNCTIONS[dep]) { + EXPORTED_FUNCTIONS[dep] = 1; + } + }); + }); + } // $ident's are special, we do not prefix them with a '_'. if (ident[0] === '$') { ident = ident.substr(1); @@ -442,7 +478,8 @@ function JSify(data, functionsOnly, givenFunctions) { ident = '_' + ident; } var text = (deps ? '\n' + deps.map(addFromLibrary).filter(function(x) { return x != '' }).join('\n') : ''); - text += isFunction ? snippet : 'var ' + ident + '=' + snippet + ';'; + // redirected idents just need a var, but no value assigned to them - it would be unused + text += isFunction ? snippet : ('var ' + ident + (redirectedIdent ? '' : '=' + snippet) + ';'); if (EXPORT_ALL || (ident in EXPORTED_FUNCTIONS)) { text += '\nModule["' + ident + '"] = ' + ident + ';'; } @@ -532,8 +569,8 @@ function JSify(data, functionsOnly, givenFunctions) { func.JS = '\n'; var paramIdents = func.params.map(function(param) { - return (param.intertype == 'varargs') ? null : toNiceIdent(param.ident); - }).filter(function(param) { return param != null; }) + return toNiceIdent(param.ident); + }); if (CLOSURE_ANNOTATIONS) { func.JS += '/**\n'; @@ -551,6 +588,34 @@ function JSify(data, functionsOnly, givenFunctions) { func.JS += 'function ' + func.ident + '(' + paramIdents.join(', ') + ') {\n'; + if (ASM_JS) { + // spell out argument types + func.params.forEach(function(param) { + func.JS += ' ' + param.ident + ' = ' + asmCoercion(param.ident, param.type) + ';\n'; + }); + + // spell out local variables + var vars = values(func.variables).filter(function(v) { return v.origin != 'funcparam' }); + if (vars.length > 0) { + var chunkSize = 8; + var chunks = []; + var i = 0; + while (i < vars.length) { + chunks.push(vars.slice(i, i+chunkSize)); + i += chunkSize; + } + for (i = 0; i < chunks.length; i++) { + func.JS += ' var ' + chunks[i].map(function(v) { + if (v.type != 'i64') { + return v.ident + ' = ' + asmInitializer(v.type); //, func.variables[v.ident].impl); + } else { + return v.ident + '$0 = 0, ' + v.ident + '$1 = 1'; + } + }).join(', ') + ';\n'; + } + } + } + if (PROFILE) { func.JS += ' if (PROFILING) { ' + 'var __parentProfilingNode__ = PROFILING_NODE; PROFILING_NODE = PROFILING_NODE.children["' + func.ident + '"]; ' @@ -560,6 +625,21 @@ function JSify(data, functionsOnly, givenFunctions) { + '}\n'; } + if (true) { // TODO: optimize away when not needed + if (CLOSURE_ANNOTATIONS) func.JS += '/** @type {number} */'; + func.JS += ' var label = 0;\n'; + } + + if (ASM_JS) { + var hasByVal = false; + func.params.forEach(function(param) { + hasByVal = hasByVal || param.byVal; + }); + if (hasByVal) { + func.JS += ' var tempParam = 0;\n'; + } + } + // Prepare the stack, if we need one. If we have other stack allocations, force the stack to be set up. func.JS += ' ' + RuntimeGenerator.stackEnter(func.initialStack, func.otherStackAllocations) + ';\n'; @@ -574,18 +654,13 @@ function JSify(data, functionsOnly, givenFunctions) { if (param.byVal) { var type = removePointing(param.type); var typeInfo = Types.types[type]; - func.JS += ' var tempParam = ' + param.ident + '; ' + param.ident + ' = ' + RuntimeGenerator.stackAlloc(typeInfo.flatSize) + ';' + + func.JS += ' ' + (ASM_JS ? '' : 'var ') + 'tempParam = ' + param.ident + '; ' + param.ident + ' = ' + RuntimeGenerator.stackAlloc(typeInfo.flatSize) + ';' + makeCopyValues(param.ident, 'tempParam', typeInfo.flatSize, 'null', null, param.byVal) + ';\n'; } }); if (LABEL_DEBUG && functionNameFilterTest(func.ident)) func.JS += " Module.print(INDENT + ' Entering: " + func.ident + ": ' + Array.prototype.slice.call(arguments)); INDENT += ' ';\n"; - if (true) { // TODO: optimize away when not needed - if (CLOSURE_ANNOTATIONS) func.JS += '/** @type {number} */'; - func.JS += ' var label;\n'; - } - // Walk function blocks and generate JS function walkBlock(block, indent) { if (!block) return ''; @@ -664,6 +739,8 @@ function JSify(data, functionsOnly, givenFunctions) { //Relooper.setDebug(1); Relooper.init(); + if (ASM_JS) Relooper.setAsmJSMode(1); + var blockMap = {}; // add blocks for (var i = 0; i < block.labels.length; i++) { @@ -716,12 +793,12 @@ function JSify(data, functionsOnly, givenFunctions) { if (PRINT_SPLIT_FILE_MARKER) { func.JS += '\n//FUNCTION_END_MARKER_OF_SOURCE_FILE_' + associatedSourceFile + '\n'; } - - if (EXPORT_ALL || (func.ident in EXPORTED_FUNCTIONS)) { + + if (!ASM_JS && (EXPORT_ALL || (func.ident in EXPORTED_FUNCTIONS))) { func.JS += 'Module["' + func.ident + '"] = ' + func.ident + ';'; } - if (INLINING_LIMIT && func.lines.length >= INLINING_LIMIT) { + if (!ASM_JS && INLINING_LIMIT && func.lines.length >= INLINING_LIMIT) { func.JS += func.ident + '["X"]=1;'; } @@ -767,8 +844,9 @@ function JSify(data, functionsOnly, givenFunctions) { var valueJS = item.JS; item.JS = ''; if (CLOSURE_ANNOTATIONS) item.JS += '/** @type {number} */ '; - item.JS += (item.overrideSSA ? '' : 'var ') + toNiceIdent(item.assignTo); - + if (!ASM_JS || item.intertype != 'alloca' || item.funcData.variables[item.assignTo].impl == VAR_EMULATED) { // asm only needs non-allocas + item.JS += ((ASM_JS || item.overrideSSA) ? '' : 'var ') + toNiceIdent(item.assignTo); + } var value = parseNumerical(valueJS); var impl = getVarImpl(item.funcData, item.assignTo); switch (impl) { @@ -798,7 +876,7 @@ function JSify(data, functionsOnly, givenFunctions) { return substrate.addActor('Intertype:' + intertype, { |