diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 10 | ||||
-rw-r--r-- | src/compiler.js | 4 | ||||
-rw-r--r-- | src/fastLong.js | 17 | ||||
-rw-r--r-- | src/jsifier.js | 37 | ||||
-rw-r--r-- | src/library.js | 66 | ||||
-rw-r--r-- | src/modules.js | 2 | ||||
-rw-r--r-- | src/parseTools.js | 13 | ||||
-rw-r--r-- | src/settings.js | 13 |
8 files changed, 61 insertions, 101 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index 3278139b..7fbdf24d 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -660,10 +660,12 @@ 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 = _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') + ');' + + value.ident = 'var ' + 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;'; value.assignTo = null; i++; diff --git a/src/compiler.js b/src/compiler.js index 9c19aeb0..313fd5f7 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -168,6 +168,10 @@ if (SAFE_HEAP >= 2) { EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS); EXPORTED_GLOBALS = set(EXPORTED_GLOBALS); EXCEPTION_CATCHING_WHITELIST = set(EXCEPTION_CATCHING_WHITELIST); + +DEAD_FUNCTIONS.forEach(function(dead) { + DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push(dead.substr(1)); +}); DEAD_FUNCTIONS = numberedSet(DEAD_FUNCTIONS); RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG; diff --git a/src/fastLong.js b/src/fastLong.js index 95f398db..d1ce5d39 100644 --- a/src/fastLong.js +++ b/src/fastLong.js @@ -22,13 +22,13 @@ function ___divdi3($a$0, $a$1, $b$0, $b$1) { $1$1 = (($a$1 | 0) < 0 ? -1 : 0) >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1; $2$0 = $b$1 >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1; $2$1 = (($b$1 | 0) < 0 ? -1 : 0) >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1; - $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1); + $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1) | 0; $4$1 = tempRet0; - $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1); + $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1) | 0; $7$0 = $2$0 ^ $1$0; $7$1 = $2$1 ^ $1$1; $8$0 = ___udivmoddi4($4$0, $4$1, $6$0, tempRet0, 0) | 0; - $10$0 = _i64Subtract($8$0 ^ $7$0, tempRet0 ^ $7$1, $7$0, $7$1); + $10$0 = _i64Subtract($8$0 ^ $7$0, tempRet0 ^ $7$1, $7$0, $7$1) | 0; return (tempRet0 = tempRet0, $10$0) | 0; } function ___remdi3($a$0, $a$1, $b$0, $b$1) { @@ -44,11 +44,11 @@ function ___remdi3($a$0, $a$1, $b$0, $b$1) { $1$1 = (($a$1 | 0) < 0 ? -1 : 0) >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1; $2$0 = $b$1 >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1; $2$1 = (($b$1 | 0) < 0 ? -1 : 0) >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1; - $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1); + $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1) | 0; $4$1 = tempRet0; - $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1); + $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1) | 0; ___udivmoddi4($4$0, $4$1, $6$0, tempRet0, $rem); - $10$0 = _i64Subtract(HEAP32[$rem >> 2] ^ $1$0, HEAP32[$rem + 4 >> 2] ^ $1$1, $1$0, $1$1); + $10$0 = _i64Subtract(HEAP32[$rem >> 2] ^ $1$0, HEAP32[$rem + 4 >> 2] ^ $1$1, $1$0, $1$1) | 0; $10$1 = tempRet0; STACKTOP = __stackBase__; return (tempRet0 = $10$1, $10$0) | 0; @@ -245,7 +245,7 @@ function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) { } else { $d_sroa_0_0_insert_insert99$0 = 0 | $b$0 & -1; $d_sroa_0_0_insert_insert99$1 = $d_sroa_1_4_extract_shift$0 | $b$1 & 0; - $137$0 = _i64Add($d_sroa_0_0_insert_insert99$0, $d_sroa_0_0_insert_insert99$1, -1, -1); + $137$0 = _i64Add($d_sroa_0_0_insert_insert99$0, $d_sroa_0_0_insert_insert99$1, -1, -1) | 0; $137$1 = tempRet0; $q_sroa_1_1198 = $q_sroa_1_1_ph; $q_sroa_0_1199 = $q_sroa_0_1_ph; @@ -262,7 +262,7 @@ function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) { $150$1 = tempRet0; $151$0 = $150$1 >> 31 | (($150$1 | 0) < 0 ? -1 : 0) << 1; $152 = $151$0 & 1; - $154$0 = _i64Subtract($r_sroa_0_0_insert_insert42$0, $r_sroa_0_0_insert_insert42$1, $151$0 & $d_sroa_0_0_insert_insert99$0, ((($150$1 | 0) < 0 ? -1 : 0) >> 31 | (($150$1 | 0) < 0 ? -1 : 0) << 1) & $d_sroa_0_0_insert_insert99$1); + $154$0 = _i64Subtract($r_sroa_0_0_insert_insert42$0, $r_sroa_0_0_insert_insert42$1, $151$0 & $d_sroa_0_0_insert_insert99$0, ((($150$1 | 0) < 0 ? -1 : 0) >> 31 | (($150$1 | 0) < 0 ? -1 : 0) << 1) & $d_sroa_0_0_insert_insert99$1) | 0; $r_sroa_0_0_extract_trunc = $154$0; $r_sroa_1_4_extract_trunc = tempRet0; $155 = $sr_1202 - 1 | 0; @@ -296,3 +296,4 @@ function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) { return (tempRet0 = $_0$1, $_0$0) | 0; } // ======================================================================= + diff --git a/src/jsifier.js b/src/jsifier.js index a01b2655..aab21eea 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -484,17 +484,12 @@ function JSify(data, functionsOnly, givenFunctions) { if (BUILD_AS_SHARED_LIB) { // Shared libraries reuse the runtime of their parents. item.JS = ''; - } else if (LibraryManager.library.hasOwnProperty(shortident)) { - item.JS = addFromLibrary(shortident); - } else if (!LibraryManager.library.hasOwnProperty(shortident + '__inline')) { - if (!(item.ident in DEAD_FUNCTIONS) && !UNRESOLVED_AS_DEAD) { - item.JS = 'var ' + item.ident + '; // stub for ' + item.ident; - if (ASM_JS) { - error('Unresolved symbol: ' + item.ident + ', this must be corrected for asm.js validation to succeed. Consider adding it to DEAD_FUNCTIONS.'); - } else if (WARN_ON_UNDEFINED_SYMBOLS) { - warn('Unresolved symbol: ' + item.ident); - } + } else { + if (!LibraryManager.library.hasOwnProperty(shortident) && !LibraryManager.library.hasOwnProperty(shortident + '__inline')) { + if (ASSERTIONS) printErr('warning: missing function: ' + shortident); + LibraryManager.library[shortident] = new Function("Module['printErr']('missing function: " + shortident + "'); abort(-1);"); } + item.JS = addFromLibrary(shortident); } return ret; } @@ -713,6 +708,7 @@ function JSify(data, functionsOnly, givenFunctions) { } else { ret += 'var setjmpLabel = 0;\n'; ret += 'var setjmpTable = ' + RuntimeGenerator.stackAlloc(4 * (MAX_SETJMPS + 1) * 2) + ';\n'; + ret += makeSetValue('setjmpTable', '0', '0', 'i32') + ';'; // initialize first entry to 0 } } ret += indent + 'while(1) '; @@ -1370,7 +1366,7 @@ function JSify(data, functionsOnly, givenFunctions) { args = args.map(function(arg, i) { return indexizeFunctions(arg, argsTypes[i]) }); if (ASM_JS) { - if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced) { + if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced || funcData.setjmpTable) { args = args.map(function(arg, i) { return asmCoercion(arg, argsTypes[i]) }); } else { args = args.map(function(arg, i) { return asmEnsureFloat(arg, argsTypes[i]) }); @@ -1438,30 +1434,25 @@ function JSify(data, functionsOnly, givenFunctions) { returnType = getReturnType(type); } - if (callIdent in DEAD_FUNCTIONS) { - var ret = 'abort(' + DEAD_FUNCTIONS[callIdent] + ')'; - if (ASM_JS) ret = asmCoercion(ret, returnType); - return ret; - } - if (byPointer) { var sig = Functions.getSignature(returnType, argsTypes, hasVarArgs); if (ASM_JS) { assert(returnType.search(/\("'\[,/) == -1); // XXX need isFunctionType(type, out) - if (!byPointerForced) { + if (!byPointerForced && !funcData.setjmpTable) { + // normal asm function pointer call callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py } else { - // This is a forced call, through an invoke_*. + // This is a call through an invoke_*, either a forced one, or a setjmp-required one // note: no need to update argsTypes at this point - Functions.unimplementedFunctions[callIdent] = sig; - args.unshift(byPointerForced ? Functions.getIndex(callIdent) : callIdent); + if (byPointerForced) Functions.unimplementedFunctions[callIdent] = sig; + args.unshift(byPointerForced ? Functions.getIndex(callIdent) : asmCoercion(callIdent, 'i32')); callIdent = 'invoke_' + sig; } } else if (SAFE_DYNCALLS) { assert(!ASM_JS, 'cannot emit safe dyncalls in asm'); callIdent = '(tempInt=' + callIdent + ',tempInt < 0 || tempInt >= FUNCTION_TABLE.length-1 || !FUNCTION_TABLE[tempInt] ? abort("dyncall error: ' + sig + ' " + FUNCTION_TABLE_NAMES[tempInt]) : tempInt)'; } - if (!byPointerForced) callIdent = Functions.getTable(sig) + '[' + callIdent + ']'; + if (!ASM_JS || (!byPointerForced && !funcData.setjmpTable)) callIdent = Functions.getTable(sig) + '[' + callIdent + ']'; } var ret = callIdent + '(' + args.join(', ') + ')'; @@ -1475,7 +1466,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 -111 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 = _testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable); if ((setjmpLabel|0) > 0) { label = -1111; 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 = -1111; break } else return ' + (funcData.returnType != 'void' ? asmCoercion('0', funcData.returnType) : '') + ' } __THREW__ = threwValue = 0;\n'; } return ret; diff --git a/src/library.js b/src/library.js index cd416599..5bbf4204 100644 --- a/src/library.js +++ b/src/library.js @@ -4168,32 +4168,6 @@ LibraryManager.library = { } }, - mbtowc: function(pwc, pmb, maxx) { - // XXX doesn't really handle multibyte at all - if (!pmb) return 0; - maxx = Math.min({{{ cDefine('_NL_CTYPE_MB_CUR_MAX') }}}, maxx); - var i; - for (i = 0; i < maxx; i++) { - var curr = {{{ makeGetValue('pmb', 0, 'i8') }}}; - if (pwc) { - {{{ makeSetValue('pwc', '0', 'curr', 'i8') }}}; - {{{ makeSetValue('pwc', '1', '0', 'i8') }}}; - pwc += 2; - } - pmb++; - if (!curr) break; - } - return i; - }, - - wcrtomb: function(s, wc, ps) { - // XXX doesn't really handle multibyte at all - if (s) { - {{{ makeSetValue('s', '0', 'wc', 'i8') }}}; - } - return 1; - }, - arc4random: 'rand', // ========================================================================== @@ -4243,8 +4217,6 @@ LibraryManager.library = { return ret|0; }, - wmemcpy: function() { throw 'wmemcpy not implemented' }, - llvm_memcpy_i32: 'memcpy', llvm_memcpy_i64: 'memcpy', llvm_memcpy_p0i8_p0i8_i32: 'memcpy', @@ -4274,8 +4246,6 @@ LibraryManager.library = { llvm_memmove_p0i8_p0i8_i32: 'memmove', llvm_memmove_p0i8_p0i8_i64: 'memmove', - wmemmove: function() { throw 'wmemmove not implemented' }, - memset__inline: function(ptr, value, num, align) { return makeSetValues(ptr, 0, value, 'null', num, align); }, @@ -4316,32 +4286,18 @@ LibraryManager.library = { llvm_memset_p0i8_i32: 'memset', llvm_memset_p0i8_i64: 'memset', - wmemset: function() { throw 'wmemset not implemented' }, - strlen__sig: 'ii', strlen__asm: true, strlen: function(ptr) { ptr = ptr|0; var curr = 0; curr = ptr; - while ({{{ makeGetValueAsm('curr', '0', 'i8') }}}|0 != 0) { + while ({{{ makeGetValueAsm('curr', '0', 'i8') }}}) { curr = (curr + 1)|0; } return (curr - ptr)|0; }, - // TODO: Implement when we have real unicode support. - mblen: function() { - return 1; - }, - - wcslen: function() { throw 'wcslen not implemented' }, - mbrlen: function() { throw 'mbrlen not implemented' }, - mbsrtowcs: function() { throw 'mbsrtowcs not implemented' }, - wcsnrtombs: function() { throw 'wcsnrtombs not implemented' }, - mbsnrtowcs: function() { throw 'mbsnrtowcs not implemented' }, - mbrtowc: function() { throw 'mbrtowc not implemented' }, - strspn: function(pstr, pset) { var str = pstr, set, strcurr, setcurr; while (1) { @@ -4382,7 +4338,7 @@ LibraryManager.library = { do { {{{ makeCopyValues('(pdest+i)|0', '(psrc+i)|0', 1, 'i8', null, 1) }}}; i = (i+1)|0; - } while (({{{ makeGetValue('psrc', 'i-1', 'i8') }}})|0 != 0); + } while ({{{ makeGetValueAsm('psrc', 'i-1', 'i8') }}}); return pdest|0; }, @@ -4437,11 +4393,11 @@ LibraryManager.library = { strcat: function(pdest, psrc) { pdest = pdest|0; psrc = psrc|0; var i = 0; - pdest = (pdest + _strlen(pdest))|0; + pdest = (pdest + (_strlen(pdest)|0))|0; do { {{{ makeCopyValues('pdest+i', 'psrc+i', 1, 'i8', null, 1) }}}; i = (i+1)|0; - } while ({{{ makeGetValueAsm('psrc', 'i-1', 'i8') }}} != 0); + } while ({{{ makeGetValueAsm('psrc', 'i-1', 'i8') }}}); return pdest|0; }, @@ -4501,8 +4457,8 @@ LibraryManager.library = { px = px|0; py = py|0; n = n|0; var i = 0, x = 0, y = 0; while ((i>>>0) < (n>>>0)) { - x = _tolower({{{ makeGetValueAsm('px', 'i', 'i8', 0, 1) }}}); - y = _tolower({{{ makeGetValueAsm('py', 'i', 'i8', 0, 1) }}}); + x = _tolower({{{ makeGetValueAsm('px', 'i', 'i8', 0, 1) }}})|0; + y = _tolower({{{ makeGetValueAsm('py', 'i', 'i8', 0, 1) }}})|0; if (((x|0) == (y|0)) & ((x|0) == 0)) return 0; if ((x|0) == 0) return -1; if ((y|0) == 0) return 1; @@ -5355,6 +5311,8 @@ LibraryManager.library = { llvm_objectsize_i32: function() { return -1 }, // TODO: support this + llvm_dbg_declare__inline: function() { throw 'llvm_debug_declare' }, // avoid warning + // ========================================================================== // llvm-mono integration // ========================================================================== @@ -6220,6 +6178,7 @@ LibraryManager.library = { saveSetjmp__asm: true, saveSetjmp__sig: 'iii', + saveSetjmp__deps: ['putchar'], saveSetjmp: function(env, label, table) { // Not particularly fast: slow table lookup of setjmpId to label. But setjmp // prevents relooping anyhow, so slowness is to be expected. And typical case @@ -6233,7 +6192,7 @@ LibraryManager.library = { #endif setjmpId = (setjmpId+1)|0; {{{ makeSetValueAsm('env', '0', 'setjmpId', 'i32') }}}; - while ((i|0) < {{{ MAX_SETJMPS }}}) { + while ((i|0) < {{{ 2*MAX_SETJMPS }}}) { if ({{{ makeGetValueAsm('table', 'i*4', 'i32') }}} == 0) { {{{ makeSetValueAsm('table', 'i*4', 'setjmpId', 'i32') }}}; {{{ makeSetValueAsm('table', 'i*4+4', 'label', 'i32') }}}; @@ -6243,7 +6202,8 @@ LibraryManager.library = { } i = (i+2)|0; } - abort(987); // if you hit this, adjust MAX_SETJMPS + {{{ makePrintChars('too many setjmps in a function call, build with a higher value for MAX_SETJMPS') }}}; + abort(0); return 0; }, @@ -6270,7 +6230,7 @@ LibraryManager.library = { setjmp__inline: function(env) { // Save the label #if ASM_JS - return '_saveSetjmp(' + env + ', label, setjmpTable)'; + return '_saveSetjmp(' + env + ', label, setjmpTable)|0'; #else return '(tempInt = setjmpId++, mySetjmpIds[tempInt] = 1, setjmpLabels[tempInt] = label,' + makeSetValue(env, '0', 'tempInt', 'i32', undefined, undefined, undefined, undefined, ',') + ', 0)'; #endif diff --git a/src/modules.js b/src/modules.js index 7a769846..ce162ac1 100644 --- a/src/modules.js +++ b/src/modules.js @@ -291,7 +291,7 @@ var Functions = { var sig = ASM_JS ? Functions.implementedFunctions[ident] || Functions.unimplementedFunctions[ident] || LibraryManager.library[ident.substr(1) + '__sig'] : 'x'; assert(sig, ident); if (!tables[sig]) tables[sig] = emptyTable(sig); // TODO: make them compact - tables[sig][this.indexedFunctions[ident]] = ident in DEAD_FUNCTIONS ? '0' : ident; + tables[sig][this.indexedFunctions[ident]] = ident; } var generated = false; var wrapped = {}; diff --git a/src/parseTools.js b/src/parseTools.js index 2eb456f1..f4ce12d5 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -2000,7 +2000,7 @@ function processMathop(item) { } function preciseCall(name) { Types.preciseI64MathUsed = true; - return finish([name + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + ')', 'tempRet0']); + return finish([asmCoercion(name + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + ')', 'i32'), 'tempRet0']); } function i64PreciseLib(type) { return preciseCall('_i64' + type[0].toUpperCase() + type.substr(1)); @@ -2363,3 +2363,14 @@ function getTypeFromHeap(suffix) { } } +// Generates code that prints without printf(), but just putchar (so can be directly inline in asm.js) +function makePrintChars(s, sep) { + sep = sep || ';'; + var ret = ''; + for (var i = 0; i < s.length; i++) { + ret += '_putchar(' + s.charCodeAt(i) + ')' + sep; + } + ret += '_putchar(10)'; + return ret; +} + diff --git a/src/settings.js b/src/settings.js index 7cd0c02e..c878be92 100644 --- a/src/settings.js +++ b/src/settings.js @@ -55,7 +55,7 @@ var ALLOW_MEMORY_GROWTH = 0; // If false, we abort with an error if we try to al // that case we must be careful about optimizations, in particular the // eliminator). Note that memory growth is only supported with typed // arrays. -var MAX_SETJMPS = 10; // size of setjmp table allocated in each function invocation (that has setjmp) +var MAX_SETJMPS = 20; // size of setjmp table allocated in each function invocation (that has setjmp) // Code embetterments var MICRO_OPTS = 1; // Various micro-optimizations, like nativizing variables @@ -342,19 +342,10 @@ var PGO = 0; // Enables profile-guided optimization in the form of runtime check // calling PGOMonitor.dump()); var DEAD_FUNCTIONS = []; // Functions on this list are not converted to JS, and calls to // them are turned into abort()s. This is potentially useful for - // (1) reducing code size, if you know some function will never - // be called (see PGO), and also (2) ASM.js requires all declared - // functions to have a corresponding implementation (even if the - // function is never called) and will emit an error during linking if no - // implementation can be found; with this option, asm.js validation will - // succeed for that function and calls to it. + // reducing code size. // If a dead function is actually called, you will get a runtime // error. // TODO: options to lazily load such functions -var UNRESOLVED_AS_DEAD = 0; // Handle all unresolved functions as if they were in the - // list of dead functions. This is a quick way to turn - // all unresolved references into runtime aborts (and not - // get compile-time warnings or errors on them). var EXPLICIT_ZEXT = 0; // If 1, generate an explicit conversion of zext i1 to i32, using ?: |