aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog137
-rw-r--r--src/analyzer.js10
-rw-r--r--src/compiler.js2
-rw-r--r--src/fastLong.js17
-rw-r--r--src/jsifier.js22
-rw-r--r--src/library.js14
-rw-r--r--src/parseTools.js13
-rw-r--r--src/settings.js6
-rwxr-xr-xtests/runner.py143
-rw-r--r--tests/time/src.c3
-rw-r--r--tools/find_bigfuncs.py23
-rw-r--r--tools/shared.py4
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')