diff options
-rw-r--r-- | ChangeLog | 137 | ||||
-rw-r--r-- | src/analyzer.js | 10 | ||||
-rw-r--r-- | src/compiler.js | 2 | ||||
-rw-r--r-- | src/fastLong.js | 17 | ||||
-rw-r--r-- | src/jsifier.js | 22 | ||||
-rw-r--r-- | src/library.js | 14 | ||||
-rw-r--r-- | src/parseTools.js | 13 | ||||
-rw-r--r-- | src/settings.js | 6 | ||||
-rwxr-xr-x | tests/runner.py | 143 | ||||
-rw-r--r-- | tests/time/src.c | 3 | ||||
-rw-r--r-- | tools/find_bigfuncs.py | 23 | ||||
-rw-r--r-- | tools/shared.py | 4 |
12 files changed, 220 insertions, 174 deletions
diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index b60921cd..00000000 --- a/ChangeLog +++ /dev/null @@ -1,137 +0,0 @@ -2011-??-??: Version 2.0 - - * Bundled headers - * TODO: try to not need all the -h in tests/runner.py, and for user scripts too - -2011-07-31: Version 1.5 - - * eSpeak text-to-speech demo - * Filesystem emulation API - * Parse metadata type info for easier interaction with llvm structures - * Bindings generator improvements - * Many library improvements and fixes - * Various bug fixes - -2011-07-10: Version 1.4 - - * Compiling and loading of dynamic libraries - * Automatic bindings generation using CppHeaderParser - * Much improved emscripten.py - * Many library improvements and fixes - * Various bug fixes - -2011-06-22: Version 1.3 - - * Optional typed arrays with single shared buffer (TA2) - * Optional support for nonportable optimizations with TA2 - * Relooper optimizations - * Reading from stdin on the web opens window.prompt - * Various bug fixes - -2011-05-29: Version 1.2 - - * Doom demo - * Major SDL improvements: color palettes, input events, audio - * Various improvements for CHECK_* and CORRECT_*, and new AUTO_OPTIMIZE - * Experimental work towards supporting OpenGL in WebGL - * Various bug fixes - -2011-05-01: Version 1.1 - - * Much improved Bullet demo (llvm opts, quantum = 1, CubicVR.js) - * QUANTUM == 1 a.k.a memory compression option - * Dead function elimination tool - * Various performance improvements in generated code - * Various bug fixes - -2011-04-09: Version 1.0 - - * Poppler test and web demo - * Optimize compiler memory usage very significantly - * Support for LLVM 2.9 - * Better interaction with closure compiler - * Finish docs/paper.pdf - * Many bug fixes - -2011-03-05: Version 0.9 - - * OpenJPEG test and web demo - * Line number debugging info and autodebugger tool - * CORRECT_ROUNDINGS option - * Line-specific CORRECT_* options - * 20% faster compilation - * Generate strict mode JavaScript - * Many bug fixes, additional tests and library implementations - -2011-02-06: Version 0.8 - - * Freetype web demo (2011-02-08, right after 0.8) - * Freetype and zlib tests (including the entire build procedure) - * File emulation - * CHECK_OVERFLOWS & CORRECT_OVERFLOWS options to handle numerical size issues - * CHECK_SIGNS option to find whether GUARD_SIGNS is necessary - * Improvements to usage of llvm optimizations, and testing - * Many bug fixes, additional tests and library implementations - -2010-12-18: Version 0.7 - - * Python web demo - * Support for essentially all LLVM optimizations - * Proper support for C bitfields - * Many bug fixes, additional tests and library implementations - -2010-11-25: Version 0.6 - - * Web demos: Lua and Bullet/WebGL - * SAFE_HEAP checks for invalid reads/writes, nonportable .ll - * Basic C++ exceptions support (|catch(...)|) - * Optimize compilation of very large projects (memory and speed) - * Support for frontend-optimized .ll input, plus tests - * Integration (combining scripts with compiled C++) tools and tests - * Many bug fixes, additional tests and library implementations - -2010-11-02: Version 0.5 - - * Much faster compilation, in particular of large projects - * Bullet physics library test - * GCC name demangling test - * Module-ization of generated code (optional) - * Name demangler and namespace generator tools - * Many code cleanups, bug fixes, additional tests and library implementations - -2010-10-17: Version 0.4 - - * Much faster optimized code, now 10X the speed of our unoptimized code - * Support for the recently-released LLVM 2.8 - * Support for typed arrays - * Integration with the Closure Compiler - * Benchmarking framework in test runner - * Many code cleanups, bug fixes, and additional tests - -2010-10-05: Version 0.3 - - * Much faster compilation (but still slow with relooper) - * Clang support - * Optional memory alignment that precisely matches C/C++ - * Proper memory management, including stack and (optional) dlmalloc - * Rewritten relooper; no emulated blocks in any test - * Initial support for SDL - * Raytracing test + web demo - * Many code cleanups, bug fixes, additional tests and library implementations - -2010-09-11: Version 0.2 - - * sauer (cubescript) test passes (without RELOOPing), + web demo - * ES_SIZEOF - safe&portable sizeof replacement - * emscripten.py tool for easy compiling - * Better debugging support, using SAFE_HEAP and LABEL_DEBUG, using internal preprocessor - * Compiler can now run all tests in both SpiderMonkey and V8 - * Various compiler optimizations (still barely scratched the surface though) - * Many code cleanups, bug fixes, additional tests and library implementations - -2010-08-28: Version 0.1 - - * All tests pass, including fannkuch and fasta, but constglobalstructs - * Relooping of Fannkuch is complete, fasta has one left - * Emscriptened Fannkuch is 19X slower than gcc -O0, 37X than gcc -O2 - 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..d74ff7cb 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -168,6 +168,8 @@ if (SAFE_HEAP >= 2) { EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS); EXPORTED_GLOBALS = set(EXPORTED_GLOBALS); EXCEPTION_CATCHING_WHITELIST = set(EXCEPTION_CATCHING_WHITELIST); + +if (DEAD_FUNCTIONS.length && ASSERTIONS) DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push('putchar'); // for debug output 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..30a06d76 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -487,7 +487,7 @@ function JSify(data, functionsOnly, givenFunctions) { } 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) { + if (!(item.ident in DEAD_FUNCTIONS)) { 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.'); @@ -713,6 +713,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 +1371,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]) }); @@ -1441,6 +1442,10 @@ function JSify(data, functionsOnly, givenFunctions) { if (callIdent in DEAD_FUNCTIONS) { var ret = 'abort(' + DEAD_FUNCTIONS[callIdent] + ')'; if (ASM_JS) ret = asmCoercion(ret, returnType); + if (ASSERTIONS) { + assert(DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.indexOf('putchar') >= 0, 'need putchar for DEAD_FUNCTIONS + ASSERTIONS output'); + ret = '(' + makePrintChars('dead:' + callIdent, ',') + ',' + ret + ')'; + } return ret; } @@ -1448,20 +1453,21 @@ function JSify(data, functionsOnly, givenFunctions) { 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 +1481,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 dfaff1fb..29c3386f 100644 --- a/src/library.js +++ b/src/library.js @@ -4393,7 +4393,7 @@ 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; @@ -4457,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; @@ -6176,6 +6176,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 @@ -6189,7 +6190,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') }}}; @@ -6199,7 +6200,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; }, @@ -6226,7 +6228,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/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..8c7d1f83 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 @@ -351,10 +351,6 @@ var DEAD_FUNCTIONS = []; // Functions on this list are not converted to JS, and // 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 ?: diff --git a/tests/runner.py b/tests/runner.py index 00426b0c..7ae2dc41 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -138,7 +138,7 @@ class RunnerCore(unittest.TestCase): # Hardcode in the arguments, so js is portable without manual commandlinearguments if not args: return js = open(filename).read() - open(filename, 'w').write(js.replace('var ret = run();', 'var ret = run(%s);' % str(args))) + open(filename, 'w').write(js.replace('run();', 'run(%s);' % str(args))) def prep_ll_run(self, filename, ll_file, force_recompile=False, build_ll_hook=None): if ll_file.endswith(('.bc', '.o')): @@ -2505,6 +2505,145 @@ Calling longjmp the second time! Exception execution path of first function! 1 ''') + def test_longjmp_funcptr(self): + src = r''' + #include <stdio.h> + #include <setjmp.h> + + static jmp_buf buf; + + void (*fp)() = NULL; + + void second(void) { + printf("second\n"); // prints + longjmp(buf,1); // jumps back to where setjmp was called - making setjmp now return 1 + } + + void first(void) { + fp(); + printf("first\n"); // does not print + } + + int main(int argc, char **argv) { + fp = argc == 200 ? NULL : second; + + volatile int x = 0; + if ( ! setjmp(buf) ) { + x++; + first(); // when executed, setjmp returns 0 + } else { // when longjmp jumps back, setjmp returns 1 + printf("main: %d\n", x); // prints + } + + return 0; + } + ''' + self.do_run(src, 'second\nmain: 1\n') + + def test_longjmp_repeat(self): + Settings.MAX_SETJMPS = 1 + + src = r''' + #include <stdio.h> + #include <setjmp.h> + + static jmp_buf buf; + + int main() { + volatile int x = 0; + printf("setjmp:%d\n", setjmp(buf)); + x++; + printf("x:%d\n", x); + if (x < 4) longjmp(buf, x*2); + return 0; + } + ''' + self.do_run(src, '''setjmp:0 +x:1 +setjmp:2 +x:2 +setjmp:4 +x:3 +setjmp:6 +x:4 +''') + + def test_longjmp_stacked(self): + src = r''' + #include <stdio.h> + #include <setjmp.h> + #include <stdlib.h> + #include <string.h> + + int bottom, top; + + int run(int y) { + // confuse stack + char *s = (char*)alloca(100); + memset(s, 1, 100); + s[y] = y; + s[y/2] = y*2; + volatile int x = s[y]; + top = (int)alloca(4); + if (x <= 2) return x; + jmp_buf buf; + printf("setjmp of %d\n", x); + if (setjmp(buf) == 0) { + printf("going\n"); + x += run(x/2); + longjmp(buf, 1); + } + printf("back\n"); + return x/2; + } + + int main(int argc, char **argv) { + int sum = 0; + for (int i = 0; i < argc*2; i++) { + bottom = (int)alloca(4); + sum += run(10); + // scorch the earth + if (bottom < top) { + memset((void*)bottom, 1, top - bottom); + } else { + memset((void*)top, 1, bottom - top); + } + } + printf("%d\n", sum); + return sum; + } + ''' + self.do_run(src, '''setjmp of 10 +going +setjmp of 5 +going +back +back +setjmp of 10 +going +setjmp of 5 +going +back +back +12 +''') + + def test_setjmp_many(self): + src = r''' + #include <stdio.h> + #include <setjmp.h> + + int main(int argc) { + jmp_buf buf; + for (int i = 0; i < NUM; i++) printf("%d\n", setjmp(buf)); + if (argc-- == 1131) longjmp(buf, 11); + return 0; + } + ''' + for num in [Settings.MAX_SETJMPS, Settings.MAX_SETJMPS+1]: + print num + self.do_run(src.replace('NUM', str(num)), '0\n' * num if num <= Settings.MAX_SETJMPS or not Settings.ASM_JS else 'build with a higher value for MAX_SETJMPS') + def test_exceptions(self): if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1") if self.emcc_args is None: return self.skip('need emcc to add in libcxx properly') @@ -8035,7 +8174,7 @@ def process(filename): Settings.DEAD_FUNCTIONS = [] # Run the same code with argc that uses the dead function, see abort - test(('abort', 'is not a function'), args=['a', 'b'], no_build=True) + test(('dead:_unused' if Settings.ASSERTIONS else 'abort', 'is not a function'), args=['a', 'b'], no_build=True) # Normal stuff run_all('normal', r''' diff --git a/tests/time/src.c b/tests/time/src.c index aaf2878f..d33885fe 100644 --- a/tests/time/src.c +++ b/tests/time/src.c @@ -96,7 +96,8 @@ int main() { clock_t start = clock(); printf("clock(start): %d\n", start >= 0); while (clock() - start < 2 * CLOCKS_PER_SEC); // Poor man's sleep(). - printf("clock(end): %d\n", time(NULL) - start_t == 2); + clock_t diff = time(NULL) - start_t; + printf("clock(end): %d\n", diff >= 2 && diff < 30); // Verify that ctime_r(x, buf) is equivalent to asctime_r(localtime(x), buf). time_t t7 = time(0); diff --git a/tools/find_bigfuncs.py b/tools/find_bigfuncs.py new file mode 100644 index 00000000..ebff8b6e --- /dev/null +++ b/tools/find_bigfuncs.py @@ -0,0 +1,23 @@ +''' +Simple tool to find big functions in an .ll file. Anything over i64 is of interest. +''' + +import os, sys, re + +filename = sys.argv[1] +i = 0 +maxx = -1 +maxxest = '?' +start = -1 +curr = '?' +for line in open(filename): + i += 1 + if line.startswith('function '): + start = i + curr = line + elif line.startswith('}'): + size = i - start + if size > maxx: + maxx = size + maxxest = curr +print maxx, 'lines in', maxxest diff --git a/tools/shared.py b/tools/shared.py index 9010b6e2..33b0273e 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -111,7 +111,7 @@ else: config_file = config_file.replace('{{{ EMSCRIPTEN_ROOT }}}', __rootpath__) llvm_root = '/usr/bin' try: - llvm_root = os.path.dirname(Popen(['which', 'clang'], stdout=PIPE).communicate()[0].replace('\n', '')) + llvm_root = os.path.dirname(Popen(['which', 'llvm-dis'], stdout=PIPE).communicate()[0].replace('\n', '')) except: pass config_file = config_file.replace('{{{ LLVM_ROOT }}}', llvm_root) @@ -401,7 +401,7 @@ except: # Force a simple, standard target as much as possible: target 32-bit linux, and disable various flags that hint at other platforms COMPILER_OPTS = COMPILER_OPTS + ['-m32', '-U__i386__', '-U__i386', '-Ui386', '-U__SSE__', '-U__SSE_MATH__', '-U__SSE2__', '-U__SSE2_MATH__', '-U__MMX__', - '-DEMSCRIPTEN', '-U__STRICT_ANSI__', + '-DEMSCRIPTEN', '-D__EMSCRIPTEN__', '-U__STRICT_ANSI__', '-target', 'i386-pc-linux-gnu', '-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno'] USE_EMSDK = not os.environ.get('EMMAKEN_NO_SDK') |