summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jsifier.js34
-rw-r--r--src/library.js87
-rw-r--r--src/library_sdl.js20
-rw-r--r--src/modules.js6
-rw-r--r--src/parseTools.js36
-rw-r--r--src/preamble.js30
-rw-r--r--src/settings.js9
-rw-r--r--system/include/SDL/SDL_stdinc.h2
-rw-r--r--system/include/libc/ctype.h4
-rw-r--r--system/include/libcxx/ostream2
-rw-r--r--system/include/net/arpa/inet.h2
-rw-r--r--system/include/net/netdb.h9
-rw-r--r--system/include/net/netinet/in.h2
-rw-r--r--system/include/sys/socket.h15
-rw-r--r--tests/ctype/output.txt104
-rw-r--r--tests/ctype/src.c187
-rw-r--r--tests/printf/output.txt2
-rw-r--r--tests/printf/test.c2
-rw-r--r--tests/runner.py745
-rwxr-xr-xtools/emmaken.py14
-rw-r--r--tools/file2json.py19
-rw-r--r--tools/make_file.py2
-rw-r--r--tools/shared.py139
23 files changed, 872 insertions, 600 deletions
diff --git a/src/jsifier.js b/src/jsifier.js
index 9c34ddf1..bd432001 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -42,6 +42,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
substrate = new Substrate('JSifyer');
var GLOBAL_VARIABLES = !mainPass ? givenGlobalVariables : data.globalVariables;
+ Variables.globals = GLOBAL_VARIABLES;
Functions.currFunctions = !mainPass ? givenFunctions.currFunctions : {};
Functions.currExternalFunctions = !mainPass ? givenFunctions.currExternalFunctions : {};
@@ -299,6 +300,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
substrate.addActor('FunctionStub', {
processItem: function(item) {
var ret = [item];
+ if (IGNORED_FUNCTIONS.indexOf(item.ident) >= 0) return null;
var shortident = item.ident.substr(1);
if (BUILD_AS_SHARED_LIB) {
// Shared libraries reuse the runtime of their parents.
@@ -409,6 +411,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
funcs: {},
seen: {},
processItem: function(item) {
+ if (IGNORED_FUNCTIONS.indexOf(item.ident) >= 0) return null;
if (this.seen[item.__uid__]) return null;
if (item.intertype == 'function') {
this.funcs[item.ident] = item;
@@ -831,28 +834,13 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
// We cannot compile assembly. See comment in intertyper.js:'Call'
assert(ident != 'asm', 'Inline assembly cannot be compiled to JavaScript!');
- // Special cases
- if (ident == '_llvm_va_start') {
- // varargs - we received a pointer to the varargs as a final 'extra' parameter
- var data = 'arguments[' + Framework.currItem.funcData.ident + '.length]';
- return makeSetValue(params[0].ident, 0, data, 'void*');
- } else if (ident == '_llvm_va_end') {
- return ';';
- } else if (ident == '_EMSCRIPTEN_COMMENT') {
- var param = finalizeParam(params[0]);
- if (param.indexOf('CHECK_OVERFLOW') >= 0) {
- param = param.split('(')[1].split(',')[0];
- }
- return '// ' + GLOBAL_VARIABLES[param].value.text.replace('\\00', '') + ' ';
- }
-
+ var shortident = LibraryManager.getRootIdent(ident.slice(1)) || ident.slice(1); // ident may not be in library, if all there is is ident__inline
var func = Functions.currFunctions[ident] || Functions.currExternalFunctions[ident];
-
var args = [];
var argsTypes = [];
var varargs = [];
var varargsTypes = [];
- var useJSArgs = (ident.slice(1) + '__jsargs') in LibraryManager.library;
+ var useJSArgs = (shortident + '__jsargs') in LibraryManager.library;
params.forEach(function(param, i) {
var val = finalizeParam(param);
@@ -878,11 +866,21 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
varargs = makePointer('[' + varargs + ']', 0, 'ALLOC_STACK', varargsTypes);
}
+ args = args.concat(varargs);
+ var argsText = args.join(', ');
+
+ // Inline if either we inline whenever we can (and we can), or if there is no noninlined version
+ var inline = LibraryManager.library[shortident + '__inline'];
+ var nonInlined = shortident in LibraryManager.library;
+ if (inline && (INLINE_LIBRARY_FUNCS || !nonInlined)) {
+ return inline.apply(null, args); // Warning: inlining does not prevent recalculation of the arguments. They should be simple identifiers
+ }
+
if (getVarData(funcData, ident)) {
ident = 'FUNCTION_TABLE[' + ident + ']';
}
- return ident + '(' + args.concat(varargs).join(', ') + ')';
+ return ident + '(' + args.join(', ') + ')';
}
makeFuncLineActor('getelementptr', function(item) { return finalizeLLVMFunctionCall(item) });
makeFuncLineActor('call', function(item) {
diff --git a/src/library.js b/src/library.js
index c753422d..faa86c68 100644
--- a/src/library.js
+++ b/src/library.js
@@ -24,7 +24,7 @@ LibraryManager.library = {
_impure_ptr: 0,
$FS__deps: ['$ERRNO_CODES', '__setErrNo', 'stdin', 'stdout', 'stderr', '_impure_ptr'],
- $FS__postset: 'FS.init();',
+ $FS__postset: 'FS.init(); __ATEXIT__.push({ func: function() { FS.quit() } });',
$FS: {
// The path to the current folder.
currentPath: '/',
@@ -246,8 +246,7 @@ LibraryManager.library = {
// Makes sure a file's contents are loaded. Returns whether the file has
// been loaded successfully. No-op for files that have been loaded already.
forceLoadFile: function(obj) {
- if (obj.isDevice || obj.isFolder || obj.link ||
- 'contents' in obj) return true;
+ if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
var success = true;
if (typeof XMLHttpRequest !== 'undefined') {
// Browser.
@@ -323,19 +322,6 @@ LibraryManager.library = {
return input.cache.shift();
};
if (!output) output = function(val) {
- if (!output.printer) {
- if (typeof print == 'function') {
- // Either console or custom print function defined.
- output.printer = print;
- } else if (console && typeof console.log == 'function') {
- // Browser-like environment with a console.
- output.printer = console.log;
- } else {
- // Fallback to a harmless no-op.
- output.printer = function() {};
- }
- }
- if (!output.buffer) output.buffer = [];
if (val === null || val === '\n'.charCodeAt(0)) {
output.printer(output.buffer.join(''));
output.buffer = [];
@@ -343,6 +329,8 @@ LibraryManager.library = {
output.buffer.push(String.fromCharCode(val));
}
};
+ if (!output.printer) output.printer = print;
+ if (!output.buffer) output.buffer = [];
if (!error) error = output;
// Create the temporary folder.
@@ -403,6 +391,12 @@ LibraryManager.library = {
// Once initialized, permissions start having effect.
FS.ignorePermissions = false;
+ },
+
+ quit: function() {
+ // Flush any partially-printed lines in stdout and stderr
+ if (FS.streams[2].object.output.buffer.length > 0) FS.streams[2].object.output('\n'.charCodeAt(0));
+ if (FS.streams[3].object.output.buffer.length > 0) FS.streams[3].object.output('\n'.charCodeAt(0));
}
},
@@ -3353,6 +3347,7 @@ LibraryManager.library = {
qsort__deps: ['memcpy'],
qsort: function(base, num, size, comparator) {
+ if (num == 0 || size == 0) return;
// forward calls to the JavaScript sort method
// first, sort the items logically
comparator = FUNCTION_TABLE[comparator];
@@ -3572,13 +3567,21 @@ LibraryManager.library = {
// string.h
// ==========================================================================
+ memcpy__inline: function (dest, src, num, idunno) {
+ var ret = '';
+#if ASSERTIONS
+ ret += "assert(" + num + " % 1 === 0, 'memcpy given ' + " + num + " + ' bytes to copy. Problem with QUANTUM_SIZE=1 corrections perhaps?');";
+#endif
+ ret += makeCopyValues(dest, src, num, 'null');
+ return ret;
+ },
memcpy: function (dest, src, num, idunno) {
#if ASSERTIONS
assert(num % 1 === 0, 'memcpy given ' + num + ' bytes to copy. Problem with QUANTUM_SIZE=1 corrections perhaps?');
#endif
- // || 0, since memcpy sometimes copies uninitialized areas XXX: Investigate why initializing alloc'ed memory does not fix that too
- {{{ makeCopyValues('dest', 'src', 'num', 'null', ' || 0') }}};
+ {{{ makeCopyValues('dest', 'src', 'num', 'null') }}};
},
+
llvm_memcpy_i32: 'memcpy',
llvm_memcpy_i64: 'memcpy',
llvm_memcpy_p0i8_p0i8_i32: 'memcpy',
@@ -3598,6 +3601,9 @@ LibraryManager.library = {
llvm_memmove_p0i8_p0i8_i32: 'memmove',
llvm_memmove_p0i8_p0i8_i64: 'memmove',
+ memset__inline: function(ptr, value, num) {
+ return makeSetValues(ptr, 0, value, 'null', num);
+ },
memset: function(ptr, value, num) {
{{{ makeSetValues('ptr', '0', 'value', 'null', 'num') }}}
},
@@ -3978,6 +3984,14 @@ LibraryManager.library = {
// LLVM specifics
// ==========================================================================
+ llvm_va_start__inline: function(ptr) {
+ // varargs - we received a pointer to the varargs as a final 'extra' parameter
+ var data = 'arguments[' + Framework.currItem.funcData.ident + '.length]';
+ return makeSetValue(ptr, 0, data, 'void*');
+ },
+
+ llvm_va_end: function() {},
+
llvm_va_copy: function(ppdest, ppsrc) {
{{{ makeCopyValues('ppdest', 'ppsrc', QUANTUM_SIZE, 'null') }}}
/* Alternate implementation that copies the actual DATA; it assumes the va_list is prefixed by its size
@@ -4003,6 +4017,15 @@ LibraryManager.library = {
}
return ret;
},
+
+ llvm_ctlz_i32: function(x) {
+ for (var i=0; i<32; i++) {
+ if ( (x & (1 << (31-i))) != 0 ) {
+ return i;
+ }
+ }
+ return 32;
+ },
__assert_fail: function(condition, file, line) {
ABORT = true;
@@ -4158,8 +4181,8 @@ LibraryManager.library = {
return ret;
},
- llvm_expect_i32: function(x, y) {
- return x == y; // TODO: inline this
+ llvm_expect_i32__inline: function(x, y) {
+ return '((' + x + ')==(' + y + '))';
},
llvm_lifetime_start: function() {},
@@ -4169,10 +4192,20 @@ LibraryManager.library = {
// iostream.h
// ==========================================================================
- // TODO: Document; compile from real implementation.
+ // libc++
+
+ $libcxx__postset: 'try { __ZNSt3__14coutE = 1 } catch(e){}; try { __ZNSt3__14cerrE = 2 } catch(e){};',
+ $libcxx: {},
+
+ _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEElsEPKv__deps: ['fputs', '$libcxx'],
+ _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEElsEPKv: function(stream, str) {
+ _fputs(str, _stdout); // XXX stderr etc.
+ },
+
+ // glibc
_ZNSt8ios_base4InitC1Ev: function() {
- // need valid 'file descriptors'
+ // need valid 'file descriptors' for glibc
//__ZSt4cout = 1;
//__ZSt4cerr = 2;
},
@@ -4245,6 +4278,11 @@ LibraryManager.library = {
scalbnf: 'ldexp',
scalbln: 'ldexp',
scalblnf: 'ldexp',
+ cbrt: function(x) {
+ return Math.pow(x, 1/3);
+ },
+ cbrtf: 'cbrt',
+ cbrtl: 'cbrt',
modf: function(x, intpart) {
{{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'double') }}}
@@ -5374,6 +5412,11 @@ LibraryManager.library = {
_Z21emscripten_run_scriptPKc: function(ptr) {
eval(Pointer_stringify(ptr));
+ },
+
+ EMSCRIPTEN_COMMENT__inline: function(param) {
+ param = stripCorrections(param);
+ return '// ' + Variables.globals[param].value.text.replace('\\00', '') + ' ';
}
};
diff --git a/src/library_sdl.js b/src/library_sdl.js
index af94301a..5ca049fe 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -255,6 +255,8 @@ mergeInto(LibraryManager.library, {
},
SDL_SetVideoMode: function(width, height, depth, flags) {
+ Module['canvas'].width = width;
+ Module['canvas'].height = height;
return SDL.screen = SDL.makeSurface(width, height, flags);
},
@@ -268,7 +270,7 @@ mergeInto(LibraryManager.library, {
}
surfData.ctx.putImageData(surfData.image, 0, 0);
}
- _SDL_CloseAudio(); // make sure we don't leave our audio timer running
+ if (SDL.audio) _SDL_CloseAudio(); // make sure we don't leave our audio timer running
__shutdownRuntime__();
throw 'SDL_Quit!';
},
@@ -304,11 +306,27 @@ mergeInto(LibraryManager.library, {
if (!surfData.colors) {
var data = surfData.image.data;
var buffer = surfData.buffer;
+#if USE_TYPED_ARRAYS == 2
+ assert(buffer % 4 == 0, 'Invalid buffer offset: ' + buffer);
+ var src = buffer >> 2;
+ var dst = 0;
+ while (dst < num) {
+ var val = HEAP32[src]; // This is optimized. Instead, we could do {{{ makeGetValue('buffer', 'dst', 'i32') }}};
+ data[dst] = val & 0xff;
+ data[dst+1] = (val >> 8) & 0xff;
+ data[dst+2] = (val >> 16) & 0xff;
+ data[dst+3] = 0xff;
+ src++;
+ dst += 4;
+ }
+#else
for (var i = 0; i < num; i++) {
// We may need to correct signs here. Potentially you can hardcode a write of 255 to alpha, say, and
// the compiler may decide to write -1 in the llvm bitcode...
data[i] = {{{ makeGetValue('buffer', 'i', 'i8') + (CORRECT_SIGNS ? '&0xff' : '') }}};
+ if (i % 4 == 3) data[i] = 0xff;
}
+#endif
} else {
var width = Module['canvas'].width;
var height = Module['canvas'].height;
diff --git a/src/modules.js b/src/modules.js
index 2341b575..3b370878 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -186,6 +186,10 @@ var Debugging = {
}
};
+var Variables = {
+ globals: null
+};
+
var Types = {
types: {},
fatTypes: {}, // With QUANTUM_SIZE=1, we store the full-size type data here
@@ -255,7 +259,7 @@ var LibraryManager = {
load: function() {
assert(!this.library);
- for (var suffix in set('', '_sdl', '_gl', '_browser')) {
+ for (var suffix in set('', '_sdl', '_browser')) {
eval(processMacros(preprocess(read('library' + suffix + '.js'), CONSTANTS)));
}
},
diff --git a/src/parseTools.js b/src/parseTools.js
index f9ef419a..2e7e1970 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -793,14 +793,23 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore) {
}
}
+var UNROLL_LOOP_LIMIT = 5;
+
function makeSetValues(ptr, pos, value, type, num) {
function safety(where) {
where = where || getFastValue(ptr, '+', pos) + '+$mspi$';
return ';' + (SAFE_HEAP ? 'SAFE_HEAP_ACCESS(' + where + ', ' + type + ', 1)' : '');
}
if (USE_TYPED_ARRAYS in set(0, 1)) {
+ if (isNumber(num)) {
+ if (num < UNROLL_LOOP_LIMIT) {
+ return range(num).map(function(i) {
+ return makeSetValue(ptr, getFastValue(pos, '+', i), value, type);
+ }).join('; ');
+ }
+ }
return 'for (var $mspi$ = 0; $mspi$ < ' + num + '; $mspi$++) {\n' +
- makeSetValue(ptr, getFastValue(pos, '+', '$mspi$'), value, type) + ';\n}';
+ makeSetValue(ptr, getFastValue(pos, '+', '$mspi$'), value, type) + '\n}';
} else { // USE_TYPED_ARRAYS == 2
/*
return 'for (var $mspi$ = 0; $mspi$ < ' + num + '; $mspi$++) {\n' +
@@ -837,6 +846,17 @@ function makeCopyValues(dest, src, num, type, modifier) {
return (SAFE_HEAP ? 'SAFE_HEAP_COPY_HISTORY(' + to + ', ' + from + ')' : '');
}
if (USE_TYPED_ARRAYS in set(0, 1)) {
+ if (isNumber(num)) {
+ if (num < UNROLL_LOOP_LIMIT) {
+ return range(num).map(function(i) {
+ return type !== 'null' ? makeSetValue(dest, i, makeGetValue(src, i, type) + (modifier || ''), type)
+ : // Null is special-cased: We copy over all heaps
+ makeGetSlabs(dest, 'null', true).map(function(slab) {
+ return slab + '[' + dest + '+' + i + ']=' + slab + '[' + src + '+' + i + ']';
+ }).join('; ') + '; ' + safety(dest + '+' + i, src + '+' + i)
+ }).join('; ');
+ }
+ }
return 'for (var $mcpi$ = 0; $mcpi$ < ' + num + '; $mcpi$++) {\n' +
(type !== 'null' ? makeSetValue(dest, '$mcpi$', makeGetValue(src, '$mcpi$', type) + (modifier || ''), type)
: // Null is special-cased: We copy over all heaps
@@ -1362,3 +1382,17 @@ function finalizeBlockAddress(param) {
return Functions.currFunctions[param.func].labelIds[param.label]; // XXX We rely on currFunctions here...?
}
+function stripCorrections(param) {
+ var m;
+ if (m = /^\((.*)\)$/.exec(param)) {
+ param = m[1];
+ }
+ if (m = /^\((\w+)\)&\d+$/.exec(param)) {
+ param = m[1];
+ }
+ if (m = /CHECK_OVERFLOW\(([^,)]*),.*/.exec(param)) {
+ param = m[1];
+ }
+ return param;
+}
+
diff --git a/src/preamble.js b/src/preamble.js
index c8f93b56..faf7aa72 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -23,6 +23,9 @@ var ACCEPTABLE_SAFE_HEAP_ERRORS = 0;
function SAFE_HEAP_ACCESS(dest, type, store, ignore) {
//if (dest === A_NUMBER) print ([dest, type, store] + ' ' + new Error().stack); // Something like this may be useful, in debugging
+#if USE_TYPED_ARRAYS == 2
+ return; // It is legitimate to violate the load-store assumption in this case
+#endif
if (type && type[type.length-1] == '*') type = 'i32'; // pointers are ints, for our purposes here
// Note that this will pass even with unions: You can store X, load X, then store Y and load Y.
// You cannot, however, do the nonportable act of store X and load Y!
@@ -30,7 +33,7 @@ function SAFE_HEAP_ACCESS(dest, type, store, ignore) {
HEAP_HISTORY[dest] = ignore ? null : type;
} else {
#if USE_TYPED_ARRAYS == 0
- if (!HEAP[dest] && HEAP[dest] !== 0 && HEAP[dest] !== false) { // false can be the result of a mathop comparator
+ if (!HEAP[dest] && HEAP[dest] !== 0 && HEAP[dest] !== false && !ignore) { // false can be the result of a mathop comparator
var error = true;
try {
if (HEAP[dest].toString() === 'NaN') error = false; // NaN is acceptable, as a double value
@@ -98,11 +101,11 @@ function SAFE_HEAP_STORE(dest, value, type, ignore) {
if (type[type.length-1] === '*') type = 'i32'; // hardcoded pointers as 32-bit
switch(type) {
case 'i1': case 'i8': HEAP8[dest] = value; break;
- case 'i16': assert(dest % 2 === 0, type + ' stores must be aligned'); HEAP16[dest>>1] = value; break;
- case 'i32': assert(dest % 4 === 0, type + ' stores must be aligned'); HEAP32[dest>>2] = value; break;
- case 'i64': assert(dest % 4 === 0, type + ' stores must be aligned'); warn64(); HEAP32[dest>>2] = value; break; // XXX store int64 as int32
- case 'float': assert(dest % 4 === 0, type + ' stores must be aligned'); HEAPF32[dest>>2] = value; break;
- case 'double': assert(dest % 4 === 0, type + ' stores must be aligned'); warn64(); HEAPF32[dest>>2] = value; break; // XXX store doubles as floats
+ case 'i16': assert(dest % 2 === 0, type + ' stores must be aligned: ' + dest); HEAP16[dest>>1] = value; break;
+ case 'i32': assert(dest % 4 === 0, type + ' stores must be aligned: ' + dest); HEAP32[dest>>2] = value; break;
+ case 'i64': assert(dest % 4 === 0, type + ' stores must be aligned: ' + dest); warn64(); HEAP32[dest>>2] = value; break; // XXX store int64 as int32
+ case 'float': assert(dest % 4 === 0, type + ' stores must be aligned: ' + dest); HEAPF32[dest>>2] = value; break;
+ case 'double': assert(dest % 4 === 0, type + ' stores must be aligned: ' + dest); warn64(); HEAPF32[dest>>2] = value; break; // XXX store doubles as floats
default: throw 'weird type for typed array II: ' + type + new Error().stack;
}
#else
@@ -139,18 +142,18 @@ function SAFE_HEAP_LOAD(dest, type, unsigned, ignore) {
break;
}
case 'i16': {
- assert(dest % 2 === 0, type + ' loads must be aligned');
+ assert(dest % 2 === 0, type + ' loads must be aligned: ' + dest);
ret = (unsigned ? HEAPU16 : HEAP16)[dest>>1];
break;
}
case 'i32': case 'i64': { // XXX store int64 as int32
- assert(dest % 4 === 0, type + ' loads must be aligned');
+ assert(dest % 4 === 0, type + ' loads must be aligned: ' + dest);
if (type === 'i64') warn64();
ret = (unsigned ? HEAPU32 : HEAP32)[dest>>2];
break;
}
case 'float': case 'double': { // XXX store doubles as floats
- assert(dest % 4 === 0, type + ' loads must be aligned');
+ assert(dest % 4 === 0, type + ' loads must be aligned: ' + dest);
if (type === 'double') warn64();
ret = HEAPF32[dest>>2];
break;
@@ -503,7 +506,8 @@ Module['Array_stringify'] = Array_stringify;
// Memory management
-var FUNCTION_TABLE;
+var FUNCTION_TABLE; // XXX: In theory the indexes here can be equal to pointers to stacked or malloced memory. Such comparisons should
+ // be false, but can turn out true. We should probably set the top bit to prevent such issues.
var PAGE_SIZE = 4096;
function alignMemoryPage(x) {
@@ -655,8 +659,10 @@ Module['String_copy'] = String_copy;
// Tools
-if (typeof print === 'undefined') {
- this['print'] = console.log; // we are on the web
+if (typeof console === 'object' && typeof console.log === 'function') {
+ this['print'] = function(x) { console.log(x) }; // web console
+} else if (typeof print === 'undefined') {
+ this['print'] = function(){}; // harmless no-op
}
// This processes a JS string into a C-line array of numbers, 0-terminated.
diff --git a/src/settings.js b/src/settings.js
index 0cbe989b..0e70316f 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -53,6 +53,8 @@ SKIP_STACK_IN_SMALL = 1; // When enabled, does not push/pop the stack at all in
// may allocate stack later, and in a loop, this can be
// very bad. In particular, when debugging, printf()ing
// a lot can exhaust the stack very fast, with this option.
+ // In particular, be careful with the autodebugger!
+INLINE_LIBRARY_FUNCS = 1; // Will inline library functions that have __inline defined
// Generated code debugging options
SAFE_HEAP = 0; // Check each write to the heap against a list of blocked addresses
@@ -114,6 +116,13 @@ PROFILE = 0; // Enables runtime profiling. See test_profiling for a usage exampl
EXPORTED_FUNCTIONS = ['_main']; // Functions that are explicitly exported, so they are guaranteed to
// be accessible outside of the generated code.
+IGNORED_FUNCTIONS = []; // Functions that we should not generate, neither a stub nor a complete function.
+ // This is useful if your project code includes a function, and you want to replace
+ // that in the compiled code with your own handwritten JS. (Of course even without
+ // this option, you could just override the generated function at runtime. However,
+ // JS engines might optimize better if the function is defined once in a single
+ // place in your code.)
+
EXPORTED_GLOBALS = []; // Global non-function variables that are explicitly
// exported, so they are guaranteed to be
// accessible outside of the generated code.
diff --git a/system/include/SDL/SDL_stdinc.h b/system/include/SDL/SDL_stdinc.h
index 89cbc3c5..c4ce7ccd 100644
--- a/system/include/SDL/SDL_stdinc.h
+++ b/system/include/SDL/SDL_stdinc.h
@@ -65,7 +65,7 @@
#endif
#if defined(HAVE_INTTYPES_H)
# include <inttypes.h>
-#elif defined(HAVE_STDINT_H)
+#elif defined(EMSCRIPTEN) || defined(HAVE_STDINT_H)
# include <stdint.h>
#endif
#ifdef HAVE_CTYPE_H
diff --git a/system/include/libc/ctype.h b/system/include/libc/ctype.h
index 6df2e7c4..43d21f3f 100644
--- a/system/include/libc/ctype.h
+++ b/system/include/libc/ctype.h
@@ -33,9 +33,9 @@ int _EXFUN(toascii, (int __c));
#ifndef _MB_CAPABLE
_CONST
#endif
-extern __IMPORT char *__ctype_ptr__;
+/* XXX Emscripten extern __IMPORT char *__ctype_ptr__; */
-#ifndef __cplusplus
+#if 0 /* ndef __cplusplus XXX Emscripten: Do not use the macros here. always use the simple functions */
/* XXX Emscripten - these confuse libc++. moved to inside ifndef __cplusplus, and added CTYPE_ */
#define CTYPE__U 01
diff --git a/system/include/libcxx/ostream b/system/include/libcxx/ostream
index f1a3de9c..c70f3c15 100644
--- a/system/include/libcxx/ostream
+++ b/system/include/libcxx/ostream
@@ -204,6 +204,7 @@ protected:
basic_ostream() {} // extension, intentially does not initialize
};
+/*
template <class _CharT, class _Traits>
class _LIBCPP_VISIBLE basic_ostream<_CharT, _Traits>::sentry
{
@@ -1287,6 +1288,7 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const bitset<_Size>& __x)
extern template class basic_ostream<char>;
extern template class basic_ostream<wchar_t>;
+*/
_LIBCPP_END_NAMESPACE_STD
diff --git a/system/include/net/arpa/inet.h b/system/include/net/arpa/inet.h
index 76ad8b5f..af7845fd 100644
--- a/system/include/net/arpa/inet.h
+++ b/system/include/net/arpa/inet.h
@@ -1,5 +1,7 @@
/* */
+#include <stdint.h>
+
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
diff --git a/system/include/net/netdb.h b/system/include/net/netdb.h
index 3b6f3389..ee33be5f 100644
--- a/system/include/net/netdb.h
+++ b/system/include/net/netdb.h
@@ -16,3 +16,12 @@ extern void freeaddrinfo(struct addrinfo *ai);
extern int getnameinfo (struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, unsigned int flags);
const char *gai_strerror(int ecode);
+struct hostent
+{
+ char *h_name;
+ char **h_aliases;
+ int h_addrtype;
+ int h_length;
+ char **h_addr_list;
+};
+
diff --git a/system/include/net/netinet/in.h b/system/include/net/netinet/in.h
index 0def3127..7ac40c03 100644
--- a/system/include/net/netinet/in.h
+++ b/system/include/net/netinet/in.h
@@ -1,6 +1,8 @@
#define INET_ADDRSTRLEN 16
+#define INADDR_ANY 0
+
struct in_addr {
unsigned long s_addr;
};
diff --git a/system/include/sys/socket.h b/system/include/sys/socket.h
index 95a0635a..68e06509 100644
--- a/system/include/sys/socket.h
+++ b/system/include/sys/socket.h
@@ -1,5 +1,9 @@
/* */
+#define SOMAXCONN 128
+#define PF_INET 2
+#define SO_BROADCAST 6
+
#define AF_UNSPEC 100
#define SOCK_STREAM 200
#define SOL_SOCKET 50
@@ -38,3 +42,14 @@ ssize_t send(int s, const void *buf, size_t len, int flags);
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);
+struct msghdr
+{
+ void *msg_name;
+ socklen_t msg_namelen;
+ struct iovec *msg_iov;
+ size_t msg_iovlen;
+ void * msg_control;
+ size_t msg_controllen;
+ int msg_flags;
+};
+
diff --git a/tests/ctype/output.txt b/tests/ctype/output.txt
index 43775583..5212c40a 100644
--- a/tests/ctype/output.txt
+++ b/tests/ctype/output.txt
@@ -125,3 +125,107 @@ isascii('A'): 1
isascii('5'): 1
isascii('.'): 1
isascii(183): 0
+
+islower(-45): 0
+islower( 10): 0
+islower('a'): 1
+islower('A'): 0
+islower('5'): 0
+islower('.'): 0
+islower(183): 0
+
+isupper(-45): 0
+isupper( 10): 0
+isupper('a'): 0
+isupper('A'): 1
+isupper('5'): 0
+isupper('.'): 0
+isupper(183): 0
+
+isupper(-45): 0
+isupper( 10): 0
+isupper('a'): 0
+isupper('A'): 1
+isupper('5'): 0
+isupper('.'): 0
+isupper(183): 0
+
+isalpha(-45): 0
+isalpha( 10): 0
+isalpha('a'): 1
+isalpha('A'): 1
+isalpha('5'): 0
+isalpha('.'): 0
+isalpha(183): 0
+
+isdigit(-45): 0
+isdigit( 10): 0
+isdigit('a'): 0
+isdigit('A'): 0
+isdigit('5'): 1
+isdigit('.'): 0
+isdigit(183): 0
+
+isxdigit(-45): 0
+isxdigit( 10): 0
+isxdigit('a'): 1
+isxdigit('A'): 1
+isxdigit('5'): 1
+isxdigit('.'): 0
+isxdigit(183): 0
+
+isalnum(-45): 0
+isalnum( 10): 0
+isalnum('a'): 1
+isalnum('A'): 1
+isalnum('5'): 1
+isalnum('.'): 0
+isalnum(183): 0
+
+ispunct(-45): 0
+ispunct( 10): 0
+ispunct('a'): 0
+ispunct('A'): 0
+ispunct('5'): 0
+ispunct('.'): 1
+ispunct(183): 0
+
+isspace(-45): 0
+isspace( 10): 1
+isspace('a'): 0
+isspace('A'): 0
+isspace('5'): 0
+isspace('.'): 0
+isspace(183): 0
+
+isblank(-45): 0
+isblank( 10): 0
+isblank('a'): 0
+isblank('A'): 0
+isblank('5'): 0
+isblank('.'): 0
+isblank(183): 0
+
+iscntrl(-45): 0
+iscntrl( 10): 1
+iscntrl('a'): 0
+iscntrl('A'): 0
+iscntrl('5'): 0
+iscntrl('.'): 0
+iscntrl(183): 0
+
+isprint(-45): 0
+isprint( 10): 0
+isprint('a'): 1
+isprint('A'): 1
+isprint('5'): 1
+isprint('.'): 1
+isprint(183): 0
+
+isgraph(-45): 0
+isgraph( 10): 0
+isgraph('a'): 1
+isgraph('A'): 1
+isgraph('5'): 1
+isgraph('.'): 1
+isgraph(183): 0
diff --git a/tests/ctype/src.c b/tests/ctype/src.c
index 34436c3b..3fe99b25 100644
--- a/tests/ctype/src.c
+++ b/tests/ctype/src.c
@@ -73,127 +73,124 @@ int main() {
printf("isascii('.'): %d\n", isascii('.') != 0);
printf("isascii(183): %d\n", isascii(183) != 0);
- /* These appear to require glibc headers and fail with newlib
-
// These are manually preprocessed to use __ctype_b_loc. The flags combination
// that the test runner uses seems to cause the macro to be ignored.
printf("\n");
- printf("islower(-45): %d\n", ((*__ctype_b_loc ())[(int) ((-45))] & (unsigned short int) _ISlower) != 0);
- printf("islower( 10): %d\n", ((*__ctype_b_loc ())[(int) ((10))] & (unsigned short int) _ISlower) != 0);
- printf("islower('a'): %d\n", ((*__ctype_b_loc ())[(int) (('a'))] & (unsigned short int) _ISlower) != 0);
- printf("islower('A'): %d\n", ((*__ctype_b_loc ())[(int) (('A'))] & (unsigned short int) _ISlower) != 0);
- printf("islower('5'): %d\n", ((*__ctype_b_loc ())[(int) (('5'))] & (unsigned short int) _ISlower) != 0);
- printf("islower('.'): %d\n", ((*__ctype_b_loc ())[(int) (('.'))] & (unsigned short int) _ISlower) != 0);
- printf("islower(183): %d\n", ((*__ctype_b_loc ())[(int) ((183))] & (unsigned short int) _ISlower) != 0);
+ printf("islower(-45): %d\n", islower(-45));
+ printf("islower( 10): %d\n", islower(10));
+ printf("islower('a'): %d\n", islower('a'));
+ printf("islower('A'): %d\n", islower('A'));
+ printf("islower('5'): %d\n", islower('5'));
+ printf("islower('.'): %d\n", islower('.'));
+ printf("islower(183): %d\n", islower(183));
printf("\n");
- printf("isupper(-45): %d\n", ((*__ctype_b_loc ())[(int) ((-45))] & (unsigned short int) _ISupper) != 0);
- printf("isupper( 10): %d\n", ((*__ctype_b_loc ())[(int) ((10))] & (unsigned short int) _ISupper) != 0);
- printf("isupper('a'): %d\n", ((*__ctype_b_loc ())[(int) (('a'))] & (unsigned short int) _ISupper) != 0);
- printf("isupper('A'): %d\n", ((*__ctype_b_loc ())[(int) (('A'))] & (unsigned short int) _ISupper) != 0);
- printf("isupper('5'): %d\n", ((*__ctype_b_loc ())[(int) (('5'))] & (unsigned short int) _ISupper) != 0);
- printf("isupper('.'): %d\n", ((*__ctype_b_loc ())[(int) (('.'))] & (unsigned short int) _ISupper) != 0);
- printf("isupper(183): %d\n", ((*__ctype_b_loc ())[(int) ((183))] & (unsigned short int) _ISupper) != 0);
+ printf("isupper(-45): %d\n", isupper(-45));
+ printf("isupper( 10): %d\n", isupper(10));
+ printf("isupper('a'): %d\n", isupper('a'));
+ printf("isupper('A'): %d\n", isupper('A'));
+ printf("isupper('5'): %d\n", isupper('5'));
+ printf("isupper('.'): %d\n", isupper('.'));
+ printf("isupper(183): %d\n", isupper(183));
printf("\n");
- printf("isupper(-45): %d\n", ((*__ctype_b_loc ())[(int) ((-45))] & (unsigned short int) _ISupper) != 0);
- printf("isupper( 10): %d\n", ((*__ctype_b_loc ())[(int) ((10))] & (unsigned short int) _ISupper) != 0);
- printf("isupper('a'): %d\n", ((*__ctype_b_loc ())[(int) (('a'))] & (unsigned short int) _ISupper) != 0);
- printf("isupper('A'): %d\n", ((*__ctype_b_loc ())[(int) (('A'))] & (unsigned short int) _ISupper) != 0);
- printf("isupper('5'): %d\n", ((*__ctype_b_loc ())[(int) (('5'))] & (unsigned short int) _ISupper) != 0);
- printf("isupper('.'): %d\n", ((*__ctype_b_loc ())[(int) (('.'))] & (unsigned short int) _ISupper) != 0);
- printf("isupper(183): %d\n", ((*__ctype_b_loc ())[(int) ((183))] & (unsigned short int) _ISupper) != 0);
+ printf("isupper(-45): %d\n", isupper(-45));
+ printf("isupper( 10): %d\n", isupper(10));
+ printf("isupper('a'): %d\n", isupper('a'));
+ printf("isupper('A'): %d\n", isupper('A'));
+ printf("isupper('5'): %d\n", isupper('5'));
+ printf("isupper('.'): %d\n", isupper('.'));
+ printf("isupper(183): %d\n", isupper(183));
printf("\n");
- printf("isalpha(-45): %d\n", ((*__ctype_b_loc ())[(int) ((-45))] & (unsigned short int) _ISalpha) != 0);
- printf("isalpha( 10): %d\n", ((*__ctype_b_loc ())[(int) ((10))] & (unsigned short int) _ISalpha) != 0);
- printf("isalpha('a'): %d\n", ((*__ctype_b_loc ())[(int) (('a'))] & (unsigned short int) _ISalpha) != 0);
- printf("isalpha('A'): %d\n", ((*__ctype_b_loc ())[(int) (('A'))] & (unsigned short int) _ISalpha) != 0);
- printf("isalpha('5'): %d\n", ((*__ctype_b_loc ())[(int) (('5'))] & (unsigned short int) _ISalpha) != 0);
- printf("isalpha('.'): %d\n", ((*__ctype_b_loc ())[(int) (('.'))] & (unsigned short int) _ISalpha) != 0);
- printf("isalpha(183): %d\n", ((*__ctype_b_loc ())[(int) ((183))] & (unsigned short int) _ISalpha) != 0);
+ printf("isalpha(-45): %d\n", isalpha(-45));
+ printf("isalpha( 10): %d\n", isalpha(10));
+ printf("isalpha('a'): %d\n", isalpha('a'));
+ printf("isalpha('A'): %d\n", isalpha('A'));
+ printf("isalpha('5'): %d\n", isalpha('5'));
+ printf("isalpha('.'): %d\n", isalpha('.'));
+ printf("isalpha(183): %d\n", isalpha(183));
printf("\n");
- printf("isdigit(-45): %d\n", ((*__ctype_b_loc ())[(int) ((-45))] & (unsigned short int) _ISdigit) != 0);
- printf("isdigit( 10): %d\n", ((*__ctype_b_loc ())[(int) ((10))] & (unsigned short int) _ISdigit) != 0);
- printf("isdigit('a'): %d\n", ((*__ctype_b_loc ())[(int) (('a'))] & (unsigned short int) _ISdigit) != 0);
- printf("isdigit('A'): %d\n", ((*__ctype_b_loc ())[(int) (('A'))] & (unsigned short int) _ISdigit) != 0);
- printf("isdigit('5'): %d\n", ((*__ctype_b_loc ())[(int) (('5'))] & (unsigned short int) _ISdigit) != 0);
- printf("isdigit('.'): %d\n", ((*__ctype_b_loc ())[(int) (('.'))] & (unsigned short int) _ISdigit) != 0);
- printf("isdigit(183): %d\n", ((*__ctype_b_loc ())[(int) ((183))] & (unsigned short int) _ISdigit) != 0);
+ printf("isdigit(-45): %d\n", isdigit(-45));
+ printf("isdigit( 10): %d\n", isdigit(10));
+ printf("isdigit('a'): %d\n", isdigit('a'));
+ printf("isdigit('A'): %d\n", isdigit('A'));
+ printf("isdigit('5'): %d\n", isdigit('5'));
+ printf("isdigit('.'): %d\n", isdigit('.'));
+ printf("isdigit(183): %d\n", isdigit(183));
printf("\n");
- printf("isxdigit(-45): %d\n", ((*__ctype_b_loc ())[(int) ((-45))] & (unsigned short int) _ISxdigit) != 0);
- printf("isxdigit( 10): %d\n", ((*__ctype_b_loc ())[(int) ((10))] & (unsigned short int) _ISxdigit) != 0);
- printf("isxdigit('a'): %d\n", ((*__ctype_b_loc ())[(int) (('a'))] & (unsigned short int) _ISxdigit) != 0);
- printf("isxdigit('A'): %d\n", ((*__ctype_b_loc ())[(int) (('A'))] & (unsigned short int) _ISxdigit) != 0);
- printf("isxdigit('5'): %d\n", ((*__ctype_b_loc ())[(int) (('5'))] & (unsigned short int) _ISxdigit) != 0);
- printf("isxdigit('.'): %d\n", ((*__ctype_b_loc ())[(int) (('.'))] & (unsigned short int) _ISxdigit) != 0);
- printf("isxdigit(183): %d\n", ((*__ctype_b_loc ())[(int) ((183))] & (unsigned short int) _ISxdigit) != 0);
+ printf("isxdigit(-45): %d\n", isxdigit(-45));
+ printf("isxdigit( 10): %d\n", isxdigit(10));
+ printf("isxdigit('a'): %d\n", isxdigit('a'));
+ printf("isxdigit('A'): %d\n", isxdigit('A'));
+ printf("isxdigit('5'): %d\n", isxdigit('5'));
+ printf("isxdigit('.'): %d\n", isxdigit('.'));
+ printf("isxdigit(183): %d\n", isxdigit(183));
printf("\n");
- printf("isalnum(-45): %d\n", ((*__ctype_b_loc ())[(int) ((-45))] & (unsigned short int) _ISalnum) != 0);
- printf("isalnum( 10): %d\n", ((*__ctype_b_loc ())[(int) ((10))] & (unsigned short int) _ISalnum) != 0);
- printf("isalnum('a'): %d\n", ((*__ctype_b_loc ())[(int) (('a'))] & (unsigned short int) _ISalnum) != 0);
- printf("isalnum('A'): %d\n", ((*__ctype_b_loc ())[(int) (('A'))] & (unsigned short int) _ISalnum) != 0);
- printf("isalnum('5'): %d\n", ((*__ctype_b_loc ())[(int) (('5'))] & (unsigned short int) _ISalnum) != 0);
- printf("isalnum('.'): %d\n", ((*__ctype_b_loc ())[(int) (('.'))] & (unsigned short int) _ISalnum) != 0);
- printf("isalnum(183): %d\n", ((*__ctype_b_loc ())[(int) ((183))] & (unsigned short int) _ISalnum) != 0);
+ printf("isalnum(-45): %d\n", isalnum(-45));
+ printf("isalnum( 10): %d\n", isalnum(10));
+ printf("isalnum('a'): %d\n", isalnum('a'));
+ printf("isalnum('A'): %d\n", isalnum('A'));
+ printf("isalnum('5'): %d\n", isalnum('5'));
+ printf("isalnum('.'): %d\n", isalnum('.'));
+ printf("isalnum(183): %d\n", isalnum(183));
printf("\n");
- printf("ispunct(-45): %d\n", ((*__ctype_b_loc ())[(int) ((-45))] & (unsigned short int) _ISpunct) != 0);
- printf("ispunct( 10): %d\n", ((*__ctype_b_loc ())[(int) ((10))] & (unsigned short int) _ISpunct) != 0);
- printf("ispunct('a'): %d\n", ((*__ctype_b_loc ())[(int) (('a'))] & (unsigned short int) _ISpunct) != 0);
- printf("ispunct('A'): %d\n", ((*__ctype_b_loc ())[(int) (('A'))] & (unsigned short int) _ISpunct) != 0);
- printf("ispunct('5'): %d\n", ((*__ctype_b_loc ())[(int) (('5'))] & (unsigned short int) _ISpunct) != 0);
- printf("ispunct('.'): %d\n", ((*__ctype_b_loc ())[(int) (('.'))] & (unsigned short int) _ISpunct) != 0);
- printf("ispunct(183): %d\n", ((*__ctype_b_loc ())[(int) ((183))] & (unsigned short int) _ISpunct) != 0);
+ printf("ispunct(-45): %d\n", ispunct(-45));
+ printf("ispunct( 10): %d\n", ispunct(10));
+ printf("ispunct('a'): %d\n", ispunct('a'));
+ printf("ispunct('A'): %d\n", ispunct('A'));
+ printf("ispunct('5'): %d\n", ispunct('5'));
+ printf("ispunct('.'): %d\n", ispunct('.'));
+ printf("ispunct(183): %d\n", ispunct(183));
printf("\n");
- printf("isspace(-45): %d\n", ((*__ctype_b_loc ())[(int) ((-45))] & (unsigned short int) _ISspace) != 0);
- printf("isspace( 10): %d\n", ((*__ctype_b_loc ())[(int) ((10))] & (unsigned short int) _ISspace) != 0);
- printf("isspace('a'): %d\n", ((*__ctype_b_loc ())[(int) (('a'))] & (unsigned short int) _ISspace) != 0);
- printf("isspace('A'): %d\n", ((*__ctype_b_loc ())[(int) (('A'))] & (unsigned short int) _ISspace) != 0);
- printf("isspace('5'): %d\n", ((*__ctype_b_loc ())[(int) (('5'))] & (unsigned short int) _ISspace) != 0);
- printf("isspace('.'): %d\n", ((*__ctype_b_loc ())[(int) (('.'))] & (unsigned short int) _ISspace) != 0);
- printf("isspace(183): %d\n", ((*__ctype_b_loc ())[(int) ((183))] & (unsigned short int) _ISspace) != 0);
+ printf("isspace(-45): %d\n", isspace(-45));
+ printf("isspace( 10): %d\n", isspace(10));
+ printf("isspace('a'): %d\n", isspace('a'));
+ printf("isspace('A'): %d\n", isspace('A'));
+ printf("isspace('5'): %d\n", isspace('5'));
+ printf("isspace('.'): %d\n", isspace('.'));
+ printf("isspace(183): %d\n", isspace(183));
printf("\n");
- printf("isblank(-45): %d\n", ((*__ctype_b_loc ())[(int) ((-45))] & (unsigned short int) _ISblank) != 0);
- printf("isblank( 10): %d\n", ((*__ctype_b_loc ())[(int) ((10))] & (unsigned short int) _ISblank) != 0);
- printf("isblank('a'): %d\n", ((*__ctype_b_loc ())[(int) (('a'))] & (unsigned short int) _ISblank) != 0);
- printf("isblank('A'): %d\n", ((*__ctype_b_loc ())[(int) (('A'))] & (unsigned short int) _ISblank) != 0);
- printf("isblank('5'): %d\n", ((*__ctype_b_loc ())[(int) (('5'))] & (unsigned short int) _ISblank) != 0);
- printf("isblank('.'): %d\n", ((*__ctype_b_loc ())[(int) (('.'))] & (unsigned short int) _ISblank) != 0);
- printf("isblank(183): %d\n", ((*__ctype_b_loc ())[(int) ((183))] & (unsigned short int) _ISblank) != 0);
+ printf("isblank(-45): %d\n", isblank(-45));
+ printf("isblank( 10): %d\n", isblank(10));
+ printf("isblank('a'): %d\n", isblank('a'));
+ printf("isblank('A'): %d\n", isblank('A'));
+ printf("isblank('5'): %d\n", isblank('5'));
+ printf("isblank('.'): %d\n", isblank('.'));
+ printf("isblank(183): %d\n", isblank(183));
printf("\n");
- printf("iscntrl(-45): %d\n", ((*__ctype_b_loc ())[(int) ((-45))] & (unsigned short int) _IScntrl) != 0);
- printf("iscntrl( 10): %d\n", ((*__ctype_b_loc ())[(int) ((10))] & (unsigned short int) _IScntrl) != 0);
- printf("iscntrl('a'): %d\n", ((*__ctype_b_loc ())[(int) (('a'))] & (unsigned short int) _IScntrl) != 0);
- printf("iscntrl('A'): %d\n", ((*__ctype_b_loc ())[(int) (('A'))] & (unsigned short int) _IScntrl) != 0);
- printf("iscntrl('5'): %d\n", ((*__ctype_b_loc ())[(int) (('5'))] & (unsigned short int) _IScntrl) != 0);
- printf("iscntrl('.'): %d\n", ((*__ctype_b_loc ())[(int) (('.'))] & (unsigned short int) _IScntrl) != 0);
- printf("iscntrl(183): %d\n", ((*__ctype_b_loc ())[(int) ((183))] & (unsigned short int) _IScntrl) != 0);
+ printf("iscntrl(-45): %d\n", iscntrl(-45));
+ printf("iscntrl( 10): %d\n", iscntrl(10));
+ printf("iscntrl('a'): %d\n", iscntrl('a'));
+ printf("iscntrl('A'): %d\n", iscntrl('A'));
+ printf("iscntrl('5'): %d\n", iscntrl('5'));
+ printf("iscntrl('.'): %d\n", iscntrl('.'));
+ printf("iscntrl(183): %d\n", iscntrl(183));
printf("\n");
- printf("isprint(-45): %d\n", ((*__ctype_b_loc ())[(int) ((-45))] & (unsigned short int) _ISprint) != 0);
- printf("isprint( 10): %d\n", ((*__ctype_b_loc ())[(int) ((10))] & (unsigned short int) _ISprint) != 0);
- printf("isprint('a'): %d\n", ((*__ctype_b_loc ())[(int) (('a'))] & (unsigned short int) _ISprint) != 0);
- printf("isprint('A'): %d\n", ((*__ctype_b_loc ())[(int) (('A'))] & (unsigned short int) _ISprint) != 0);
- printf("isprint('5'): %d\n", ((*__ctype_b_loc ())[(int) (('5'))] & (unsigned short int) _ISprint) != 0);
- printf("isprint('.'): %d\n", ((*__ctype_b_loc ())[(int) (('.'))] & (unsigned short int) _ISprint) != 0);
- printf("isprint(183): %d\n", ((*__ctype_b_loc ())[(int) ((183))] & (unsigned short int) _ISprint) != 0);
+ printf("isprint(-45): %d\n", isprint(-45));
+ printf("isprint( 10): %d\n", isprint(10));
+ printf("isprint('a'): %d\n", isprint('a'));
+ printf("isprint('A'): %d\n", isprint('A'));
+ printf("isprint('5'): %d\n", isprint('5'));
+ printf("isprint('.'): %d\n", isprint('.'));
+ printf("isprint(183): %d\n", isprint(183));
printf("\n");
- printf("isgraph(-45): %d\n", ((*__ctype_b_loc ())[(int) ((-45))] & (unsigned short int) _ISgraph) != 0);
- printf("isgraph( 10): %d\n", ((*__ctype_b_loc ())[(int) ((10))] & (unsigned short int) _ISgraph) != 0);
- printf("isgraph('a'): %d\n", ((*__ctype_b_loc ())[(int) (('a'))] & (unsigned short int) _ISgraph) != 0);
- printf("isgraph('A'): %d\n", ((*__ctype_b_loc ())[(int) (('A'))] & (unsigned short int) _ISgraph) != 0);
- printf("isgraph('5'): %d\n", ((*__ctype_b_loc ())[(int) (('5'))] & (unsigned short int) _ISgraph) != 0);
- printf("isgraph('.'): %d\n", ((*__ctype_b_loc ())[(int) (('.'))] & (unsigned short int) _ISgraph) != 0);
- printf("isgraph(183): %d\n", ((*__ctype_b_loc ())[(int) ((183))] & (unsigned short int) _ISgraph) != 0);
- */
-
+ printf("isgraph(-45): %d\n", isgraph(-45));
+ printf("isgraph( 10): %d\n", isgraph(10));
+ printf("isgraph('a'): %d\n", isgraph('a'));
+ printf("isgraph('A'): %d\n", isgraph('A'));
+ printf("isgraph('5'): %d\n", isgraph('5'));
+ printf("isgraph('.'): %d\n", isgraph('.'));
+ printf("isgraph(183): %d\n", isgraph(183));
+
return 0;
}
diff --git a/tests/printf/output.txt b/tests/printf/output.txt
index 01822327..19a6c1c2 100644
--- a/tests/printf/output.txt
+++ b/tests/printf/output.txt
@@ -8274,3 +8274,5 @@ ffffff8000000000
1
1
1
+
+no_new_line
diff --git a/tests/printf/test.c b/tests/printf/test.c
index efd9d087..d05ba096 100644
--- a/tests/printf/test.c
+++ b/tests/printf/test.c
@@ -8279,5 +8279,7 @@ int main() {
printf("%hhx\n", -0xFF);
printf("%hx\n", -0xFFFF);
printf("%x\n", -0xFFFFFFFF);
+ printf("\n");
+ printf("no_new_line");
return 0;
}
diff --git a/tests/runner.py b/tests/runner.py
index 979b5978..3fd63574 100644
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -5,14 +5,14 @@ See settings.py file for options&params. Edit as needed.
These tests can be run in parallel using nose, for example
- nosetests --processes=4 -v -s tests/runner.py
+ nosetests --processes=4 -v -s tests/runner.py
will use 4 processes. To install nose do something like
|pip install nose| or |sudo apt-get install python-nose|.
'''
from subprocess import Popen, PIPE, STDOUT
-import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, tempfile, re, json, difflib
+import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, tempfile, re, difflib
# Setup
@@ -28,40 +28,30 @@ try:
except:
raise Exception('Cannot find "COMPILER_OPTS" definition. Is ~/.emscripten set up properly? You may need to copy the template from settings.py into it.')
-# Paths
-
-EMSCRIPTEN = path_from_root('emscripten.py')
-DEMANGLER = path_from_root('third_party', 'demangler.py')
-NAMESPACER = path_from_root('tools', 'namespacer.py')
-EMMAKEN = path_from_root('tools', 'emmaken.py')
-AUTODEBUGGER = path_from_root('tools', 'autodebugger.py')
-DFE = path_from_root('tools', 'dead_function_eliminator.py')
-
-# Global cache for tests (we have multiple TestCase instances; this object lets them share data)
-
-GlobalCache = {}
-
-class Dummy: pass
-Settings = Dummy()
-Settings.saveJS = 0
-
# Core test runner class, shared between normal tests and benchmarks
class RunnerCore(unittest.TestCase):
+ save_dir = 0
+ save_JS = 0
+
def setUp(self):
- dirname = tempfile.mkdtemp(prefix="ems_" + self.__class__.__name__ + "_", dir=TEMP_DIR)
+ if not self.save_dir:
+ dirname = tempfile.mkdtemp(prefix="ems_" + self.__class__.__name__ + "_", dir=TEMP_DIR)
+ else:
+ dirname = os.path.join(TEMP_DIR, 'tmp')
if not os.path.exists(dirname):
os.makedirs(dirname)
self.working_dir = dirname
def tearDown(self):
- if Settings.saveJS:
+ if self.save_JS:
for name in os.listdir(self.get_dir()):
if name.endswith(('.o.js', '.cc.js')):
suff = '.'.join(name.split('.')[-2:])
shutil.copy(os.path.join(self.get_dir(), name),
os.path.join(TEMP_DIR, self.id().replace('__main__.', '').replace('.test_', '.')+'.'+suff))
- shutil.rmtree(self.get_dir())
+ if not self.save_dir:
+ shutil.rmtree(self.get_dir())
def skip(self, why):
print >> sys.stderr, '<skipping: %s> ' % why,
@@ -71,73 +61,33 @@ class RunnerCore(unittest.TestCase):
# Similar to LLVM::createStandardModulePasses()
def pick_llvm_opts(self, optimization_level, handpicked=None):
- global LLVM_OPT_OPTS, QUANTUM_SIZE, USE_TYPED_ARRAYS
+ global LLVM_OPT_OPTS
if handpicked is None:
handpicked = True # Not even TA2 can withstand instruction combining
- LLVM_OPT_OPTS = pick_llvm_opts(optimization_level, handpicked, quantum_size=QUANTUM_SIZE)
-
- # Emscripten optimizations that we run on the .ll file
- def do_ll_opts(self, filename):
- # Remove target info. This helps LLVM opts, if we run them later
- cleaned = filter(lambda line: not line.startswith('target datalayout = ') and not line.startswith('target triple = '),
- open(filename + '.o.ll', 'r').readlines())
- os.unlink(filename + '.o.ll')
- open(filename + '.o.ll.orig', 'w').write(''.join(cleaned))
-
- output = Popen(['python', DFE, filename + '.o.ll.orig', filename + '.o.ll'], stdout=PIPE, stderr=STDOUT).communicate()[0]
- assert os.path.exists(filename + '.o.ll'), 'Failed to run ll optimizations'
-
- # Optional LLVM optimizations
- def do_llvm_opts(self, filename):
- if LLVM_OPTS:
- shutil.move(filename + '.o', filename + '.o.pre')
- output = Popen([LLVM_OPT, filename + '.o.pre'] + LLVM_OPT_OPTS + ['-o=' + filename + '.o'], stdout=PIPE, stderr=STDOUT).communicate()[0]
- assert os.path.exists(filename + '.o'), 'Failed to run llvm optimizations: ' + output
-
- def do_llvm_dis(self, filename):
- # LLVM binary ==> LLVM assembly
- try:
- os.remove(filename + '.o.ll')
- except:
- pass
- output = Popen([LLVM_DIS, filename + '.o'] + LLVM_DIS_OPTS + ['-o=' + filename + '.o.ll'], stdout=PIPE, stderr=STDOUT).communicate()[0]
- assert os.path.exists(filename + '.o.ll'), 'Could not create .ll file: ' + output
-
- def do_llvm_as(self, source, target):
- # LLVM assembly ==> LLVM binary
- try:
- os.remove(target)
- except:
- pass
- output = Popen([LLVM_AS, source, '-o=' + target], stdout=PIPE, stderr=STDOUT).communicate()[0]
- assert os.path.exists(target), 'Could not create bc file: ' + output
-
- def do_link(self, files, target):
- output = Popen([LLVM_LINK] + files + ['-o', target], stdout=PIPE, stderr=STDOUT).communicate()[0]
- assert output is None or 'Could not open input file' not in output, 'Linking error: ' + output
+ LLVM_OPT_OPTS = pick_llvm_opts(optimization_level, handpicked, quantum_size=Settings.QUANTUM_SIZE)
def prep_ll_run(self, filename, ll_file, force_recompile=False, build_ll_hook=None):
if ll_file.endswith(('.bc', '.o')):
if ll_file != filename + '.o':
shutil.copy(ll_file, filename + '.o')
- self.do_llvm_dis(filename)
+ Building.llvm_dis(filename)
else:
shutil.copy(ll_file, filename + '.o.ll')
force_recompile = force_recompile or os.stat(filename + '.o.ll').st_size > 50000 # if the file is big, recompile just to get ll_opts
- if LLVM_OPTS or force_recompile or build_ll_hook:
- self.do_ll_opts(filename)
+ if Building.LLVM_OPTS or force_recompile or build_ll_hook:
+ Building.ll_opts(filename)
if build_ll_hook:
build_ll_hook(filename)
shutil.move(filename + '.o.ll', filename + '.o.ll.pre')
- self.do_llvm_as(filename + '.o.ll.pre', filename + '.o')
+ Building.llvm_as(filename + '.o.ll.pre', filename + '.o')
output = Popen([LLVM_AS, filename + '.o.ll.pre'] + ['-o=' + filename + '.o'], stdout=PIPE, stderr=STDOUT).communicate()[0]
assert 'error:' not in output, 'Error in llvm-as: ' + output
- self.do_llvm_opts(filename)
- self.do_llvm_dis(filename)
+ Building.llvm_opts(filename)
+ Building.llvm_dis(filename)
# Build JavaScript code from source code
def build(self, src, dirname, filename, output_processor=None, main_file=None, additional_files=[], libraries=[], includes=[], build_ll_hook=None, extra_emscripten_args=[]):
@@ -166,7 +116,7 @@ class RunnerCore(unittest.TestCase):
os.remove(f + '.o.ll')
except:
pass
- output = Popen([COMPILER, '-emit-llvm'] + COMPILER_OPTS + COMPILER_TEST_OPTS +
+ output = Popen([Building.COMPILER, '-emit-llvm'] + COMPILER_OPTS + Building.COMPILER_TEST_OPTS +
['-I', dirname, '-I', os.path.join(dirname, 'include')] +
map(lambda include: '-I' + include, includes) +
['-c', f, '-o', f + '.o'],
@@ -178,8 +128,8 @@ class RunnerCore(unittest.TestCase):
# Link all files
if len(additional_files) + len(libraries) > 0:
shutil.move(filename + '.o', filename + '.o.alone')
- self.do_link([filename + '.o.alone'] + map(lambda f: f + '.o', additional_files) + libraries,
- filename + '.o')
+ Building.link([filename + '.o.alone'] + map(lambda f: f + '.o', additional_files) + libraries,
+ filename + '.o')
if not os.path.exists(filename + '.o'):
print "Failed to link LLVM binaries:\n\n", output
raise Exception("Linkage error");
@@ -187,32 +137,7 @@ class RunnerCore(unittest.TestCase):
# Finalize
self.prep_ll_run(filename, filename + '.o', build_ll_hook=build_ll_hook)
- self.do_emscripten(filename, output_processor, extra_args=extra_emscripten_args)
-
- def do_emscripten(self, filename, output_processor=None, append_ext=True, extra_args=[]):
- # Add some headers by default. TODO: remove manually adding these in each test
- if '-H' not in extra_args:
- extra_args += ['-H', 'libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/langinfo.h,libc/time.h']
-
- # Run Emscripten
- exported_settings = {}
- for setting in ['QUANTUM_SIZE', 'RELOOP', 'OPTIMIZE', 'ASSERTIONS', 'USE_TYPED_ARRAYS', 'SAFE_HEAP', 'CHECK_OVERFLOWS', 'CORRECT_OVERFLOWS', 'CORRECT_SIGNS', 'CHECK_SIGNS', 'CORRECT_OVERFLOWS_LINES', 'CORRECT_SIGNS_LINES', 'CORRECT_ROUNDINGS', 'CORRECT_ROUNDINGS_LINES', 'INVOKE_RUN', 'SAFE_HEAP_LINES', 'INIT_STACK', 'AUTO_OPTIMIZE', 'EXPORTED_FUNCTIONS', 'EXPORTED_GLOBALS', 'BUILD_AS_SHARED_LIB', 'INCLUDE_FULL_LIBRARY', 'RUNTIME_TYPE_INFO', 'DISABLE_EXCEPTION_CATCHING', 'TOTAL_MEMORY', 'FAST_MEMORY', 'EXCEPTION_DEBUG', 'PROFILE']:
- try:
- value = eval(setting)
- if value is not None:
- exported_settings[setting] = value
- except:
- pass
- settings = ['-s %s=%s' % (k, json.dumps(v)) for k, v in exported_settings.items()]
- compiler_output = timeout_run(Popen(['python', EMSCRIPTEN, filename + ('.o.ll' if append_ext else ''), '-o', filename + '.o.js'] + settings + extra_args, stdout=PIPE, stderr=STDOUT), TIMEOUT, 'Compiling')
- #print compiler_output
-
- # Detect compilation crashes and errors
- if compiler_output is not None and 'Traceback' in compiler_output and 'in test_' in compiler_output: print compiler_output; assert 0
- assert os.path.exists(filename + '.o.js') and len(open(filename + '.o.js', 'r').read()) > 0, 'Emscripten failed to generate .js: ' + str(compiler_output)
-
- if output_processor is not None:
- output_processor(open(filename + '.o.js').read())
+ Building.emscripten(filename, output_processor, extra_args=extra_emscripten_args)
def run_generated_code(self, engine, filename, args=[], check_timeout=True):
stdout = os.path.join(self.get_dir(), 'stdout') # use files, as PIPE can get too full and hang us
@@ -256,6 +181,28 @@ class RunnerCore(unittest.TestCase):
limit_size(''.join([a.rstrip()+'\n' for a in difflib.unified_diff(value.split('\n'), string.split('\n'), fromfile='expected', tofile='actual')]))
))
+ library_cache = {}
+
+ def get_library(self, name, generated_libs, configure=['./configure'], configure_args=[], make=['make'], make_args=['-j', '2'], cache=True):
+ build_dir = self.get_build_dir()
+ output_dir = self.get_dir()
+
+ cache_name = name + '|' + Building.COMPILER
+ if self.library_cache is not None:
+ if cache and self.library_cache.get(cache_name):
+ print >> sys.stderr, '<load build from cache> ',
+ bc_file = os.path.join(output_dir, 'lib' + name + '.bc')
+ f = open(bc_file, 'wb')
+ f.write(self.library_cache[cache_name])
+ f.close()
+ return bc_file
+
+ print >> sys.stderr, '<building and saving into cache> ',
+
+ return Building.build_library(name, build_dir, output_dir, generated_libs, configure, configure_args, make, make_args, self.library_cache, cache_name,
+ copy_project=True)
+
+
###################################################################################################
if 'benchmark' not in str(sys.argv):
@@ -266,11 +213,9 @@ if 'benchmark' not in str(sys.argv):
class T(RunnerCore): # Short name, to make it more fun to use manually on the commandline
## Does a complete test - builds, runs, checks output, etc.
def do_run(self, src, expected_output=None, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None, extra_emscripten_args=[]):
- #print 'Running test:', inspect.stack()[1][3].replace('test_', ''), '[%s,%s,%s]' % (COMPILER.split(os.sep)[-1], 'llvm-optimizations' if LLVM_OPTS else '', 'reloop&optimize' if RELOOP else '')
if force_c or (main_file is not None and main_file[-2:]) == '.c':
basename = 'src.c'
- global COMPILER
- COMPILER = to_cc(COMPILER)
+ Building.COMPILER = to_cc(Building.COMPILER)
dirname = self.get_dir()
filename = os.path.join(dirname, basename)
@@ -289,7 +234,7 @@ if 'benchmark' not in str(sys.argv):
# Run in both JavaScript engines, if optimizing - significant differences there (typed arrays)
if js_engines is None:
js_engines = [SPIDERMONKEY_ENGINE, V8_ENGINE]
- if USE_TYPED_ARRAYS == 2:
+ if Settings.USE_TYPED_ARRAYS == 2:
js_engines = [SPIDERMONKEY_ENGINE] # when oh when will v8 support typed arrays in the console
for engine in js_engines:
js_output = self.run_generated_code(engine, filename + '.o.js', args)
@@ -306,7 +251,7 @@ if 'benchmark' not in str(sys.argv):
filename = os.path.join(self.get_dir(), 'src.cpp')
self.prep_ll_run(filename, ll_file, force_recompile, build_ll_hook)
- self.do_emscripten(filename, extra_args=extra_emscripten_args)
+ Building.emscripten(filename, extra_args=extra_emscripten_args)
self.do_run(None,
expected_output,
args,
@@ -380,7 +325,7 @@ if 'benchmark' not in str(sys.argv):
self.do_run(src, '*5,23,10,19,121,1,37,1,0*\n0:-1,1:134217727,2:4194303,3:131071,4:4095,5:127,6:3,7:0,8:0*\n*56,09*\nfixed:320434\n*21*')
def test_sintvars(self):
- global CORRECT_SIGNS; CORRECT_SIGNS = 1 # Relevant to this test
+ Settings.CORRECT_SIGNS = 1 # Relevant to this test
src = '''
#include <stdio.h>
struct S {
@@ -407,11 +352,11 @@ if 'benchmark' not in str(sys.argv):
}
'''
output = '*32780,32522,258*\n*258,2*\n*32780,32999,-219*\n*65317,510*'
- global CORRECT_OVERFLOWS; CORRECT_OVERFLOWS = 0 # We should not need overflow correction to get this right
+ Settings.CORRECT_OVERFLOWS = 0 # We should not need overflow correction to get this right
self.do_run(src, output, force_c=True)
def test_bigint(self):
- if USE_TYPED_ARRAYS != 0: return self.skip('Typed arrays truncate i64')
+ if Settings.USE_TYPED_ARRAYS != 0: return self.skip('Typed arrays truncate i64')
src = '''
#include <stdio.h>
int main()
@@ -435,8 +380,8 @@ if 'benchmark' not in str(sys.argv):
self.do_run(src, '*245127260211081,579378795077769,808077213656969,16428841631881,791648372025088*\n*13.00,6.00,3.00,*3*')
def test_unsigned(self):
- global CORRECT_SIGNS; CORRECT_SIGNS = 1 # We test for exactly this sort of thing here
- global CHECK_SIGNS; CHECK_SIGNS = 0
+ Settings.CORRECT_SIGNS = 1 # We test for exactly this sort of thing here
+ Settings.CHECK_SIGNS = 0
src = '''
#include <stdio.h>
const signed char cvals[2] = { -1, -2 }; // compiler can store this is a string, so -1 becomes \FF, and needs re-signing
@@ -477,12 +422,12 @@ if 'benchmark' not in str(sys.argv):
# Now let's see some code that should just work in USE_TYPED_ARRAYS == 2, but requires
# corrections otherwise
- if USE_TYPED_ARRAYS == 2:
- CORRECT_SIGNS = 0
- CHECK_SIGNS = 1
+ if Settings.USE_TYPED_ARRAYS == 2:
+ Settings.CORRECT_SIGNS = 0
+ Settings.CHECK_SIGNS = 1
else:
- CORRECT_SIGNS = 1
- CHECK_SIGNS = 0
+ Settings.CORRECT_SIGNS = 1
+ Settings.CHECK_SIGNS = 0
src = '''
#include <stdio.h>
@@ -530,7 +475,7 @@ if 'benchmark' not in str(sys.argv):
self.do_run(src, '*255*\n*65535*\n*-1*\n*-1*\n*-1*')
def test_bitfields(self):
- global SAFE_HEAP; SAFE_HEAP = 0 # bitfields do loads on invalid areas, by design
+ Settings.SAFE_HEAP = 0 # bitfields do loads on invalid areas, by design
src = '''
#include <stdio.h>
struct bitty {
@@ -641,7 +586,7 @@ if 'benchmark' not in str(sys.argv):
self.do_run(src, '*yes*')
# Test for issue 39
- if not LLVM_OPTS:
+ if not Building.LLVM_OPTS:
self.do_ll_run(path_from_root('tests', 'issue_39.ll'), '*yes*')
def test_if_else(self):
@@ -960,7 +905,7 @@ if 'benchmark' not in str(sys.argv):
return 1;
}
'''
- if QUANTUM_SIZE == 1:
+ if Settings.QUANTUM_SIZE == 1:
self.do_run(src, 'sizeofs:6,8\n*C___: 0,3,6,9<24*\n*Carr: 0,3,6,9<24*\n*C__w: 0,3,9,12<24*\n*Cp1_: 1,2,5,8<24*\n*Cp2_: 0,2,5,8<24*\n*Cint: 0,3,4,7<24*\n*C4__: 0,3,4,7<24*\n*C4_2: 0,3,5,8<20*\n*C__z: 0,3,5,8<28*')
else:
self.do_run(src, 'sizeofs:6,8\n*C___: 0,6,12,20<24*\n*Carr: 0,6,12,20<24*\n*C__w: 0,6,12,20<24*\n*Cp1_: 4,6,12,20<24*\n*Cp2_: 0,6,12,20<24*\n*Cint: 0,8,12,20<24*\n*C4__: 0,8,12,20<24*\n*C4_2: 0,6,10,16<20*\n*C__z: 0,8,16,24<28*')
@@ -1003,15 +948,14 @@ if 'benchmark' not in str(sys.argv):
'''
self.do_run(src, '*throw...caught!infunc...done!*')
- global DISABLE_EXCEPTION_CATCHING
- DISABLE_EXCEPTION_CATCHING = 1
+ Settings.DISABLE_EXCEPTION_CATCHING = 1
self.do_run(src, 'Compiled code throwing an exception')
def test_typed_exceptions(self):
return self.skip('TODO: fix this for llvm 3.0')
- global SAFE_HEAP; SAFE_HEAP = 0 # Throwing null will cause an ignorable null pointer access.
- global EXCEPTION_DEBUG; EXCEPTION_DEBUG = 0 # Messes up expected output.
+ Settings.SAFE_HEAP = 0 # Throwing null will cause an ignorable null pointer access.
+ Settings.EXCEPTION_DEBUG = 0 # Messes up expected output.
src = open(path_from_root('tests', 'exceptions', 'typed.cpp'), 'r').read()
expected = open(path_from_root('tests', 'exceptions', 'output.txt'), 'r').read()
self.do_run(src, expected)
@@ -1372,7 +1316,7 @@ if 'benchmark' not in str(sys.argv):
printf("*%d,%d,%d*\\n", sizeof(PyGC_Head), sizeof(gc_generation), int(GEN_HEAD(2)) - int(GEN_HEAD(1)));
}
'''
- if QUANTUM_SIZE == 1:
+ if Settings.QUANTUM_SIZE == 1:
# Compressed memory. Note that sizeof() does give the fat sizes, however!
self.do_run(src, '*0,0,0,1,2,3,4,5*\n*1,0,0*\n*0*\n0:1,1\n1:1,1\n2:1,1\n*12,20,5*')
else:
@@ -1402,7 +1346,7 @@ if 'benchmark' not in str(sys.argv):
def test_sizeof(self):
# Has invalid writes between printouts
- global SAFE_HEAP; SAFE_HEAP = 0
+ Settings.SAFE_HEAP = 0
src = '''
#include <stdio.h>
@@ -1436,8 +1380,7 @@ if 'benchmark' not in str(sys.argv):
self.do_run(src, '*2,2,5,8,8***8,8,5,8,8***7,2,6,990,7,2*', [], lambda x: x.replace('\n', '*'))
def test_emscripten_api(self):
- global OPTIMIZE, RELOOP, LLVM_OPTS
- if OPTIMIZE or RELOOP or LLVM_OPTS: return self.skip('FIXME')
+ #if Settings.OPTIMIZE or Settings.RELOOP or Building.LLVM_OPTS: return self.skip('FIXME')
src = '''
#include <stdio.h>
@@ -1481,7 +1424,7 @@ if 'benchmark' not in str(sys.argv):
return 0;
}
'''
- if QUANTUM_SIZE == 1:
+ if Settings.QUANTUM_SIZE == 1:
self.do_run(src, '''*4*\n0:22016,0,8,12\n1:22018,1,12,8\n''')
else:
self.do_run(src, '''*16*\n0:22016,0,32,48\n1:22018,1,48,32\n''')
@@ -1580,13 +1523,13 @@ if 'benchmark' not in str(sys.argv):
return 0;
}
'''
- if QUANTUM_SIZE == 1:
+ if Settings.QUANTUM_SIZE == 1:
self.do_run(src, '*4,2,3*\n*6,2,3*')
else:
self.do_run(src, '*4,3,4*\n*6,4,6*')
def test_varargs(self):
- if QUANTUM_SIZE == 1: return self.skip('FIXME: Add support for this')
+ if Settings.QUANTUM_SIZE == 1: return self.skip('FIXME: Add support for this')
src = '''
#include <stdio.h>
@@ -1653,9 +1596,9 @@ if 'benchmark' not in str(sys.argv):
self.do_run(src, '*cheez: 0+24*\n*cheez: 0+24*\n*albeit*\n*albeit*\nQ85*\nmaxxi:21*\nmaxxD:22.10*\n')
def test_stdlibs(self):
- if USE_TYPED_ARRAYS == 2:
+ if Settings.USE_TYPED_ARRAYS == 2:
# Typed arrays = 2 + safe heap prints a warning that messes up our output.
- global SAFE_HEAP; SAFE_HEAP = 0
+ Settings.SAFE_HEAP = 0
src = '''
#include <stdio.h>
#include <stdlib.h>
@@ -1708,7 +1651,7 @@ if 'benchmark' not in str(sys.argv):
self.do_run(src, '*1,2,3,5,5,6*\n*stdin==0:0*\n*%*\n*5*\n*66.0*\n*10*\n*0*\n*-10*\n*18*\n*10*\n*0*\n*4294967286*\n*cleaned*')
def test_time(self):
- if USE_TYPED_ARRAYS == 2: return self.skip('Typed arrays = 2 truncate i64s')
+ if Settings.USE_TYPED_ARRAYS == 2: return self.skip('Typed arrays = 2 truncate i64s')
src = open(path_from_root('tests', 'time', 'src.c'), 'r').read()
expected = open(path_from_root('tests', 'time', 'output.txt'), 'r').read()
self.do_run(src, expected,
@@ -1717,10 +1660,9 @@ if 'benchmark' not in str(sys.argv):
def test_statics(self):
# static initializers save i16 but load i8 for some reason
- global SAFE_HEAP, SAFE_HEAP_LINES
- if SAFE_HEAP:
- SAFE_HEAP = 3
- SAFE_HEAP_LINES = ['src.cpp:19', 'src.cpp:26']
+ if Settings.SAFE_HEAP:
+ Settings.SAFE_HEAP = 3
+ Settings.SAFE_HEAP_LINES = ['src.cpp:19', 'src.cpp:26']
src = '''
#include <stdio.h>
@@ -1906,7 +1848,7 @@ if 'benchmark' not in str(sys.argv):
return 0;
}
'''
- if QUANTUM_SIZE == 1:
+ if Settings.QUANTUM_SIZE == 1:
# Compressed memory. Note that sizeof() does give the fat sizes, however!
self.do_run(src, '*16,0,1,2,2,3|20,0,1,1,2,3,3,4|24,0,5,0,1,1,2,3,3,4*\n*0,0,0,1,2,62,63,64,72*\n*2*')
else:
@@ -1914,7 +1856,6 @@ if 'benchmark' not in str(sys.argv):
self.do_run(src, '*16,0,4,8,8,12|20,0,4,4,8,12,12,16|24,0,20,0,4,4,8,12,12,16*\n*0,0,0,1,2,64,68,69,72*\n*2*')
def test_dlfcn_basic(self):
- global BUILD_AS_SHARED_LIB
lib_src = '''
#include <cstdio>
@@ -1929,7 +1870,7 @@ if 'benchmark' not in str(sys.argv):
'''
dirname = self.get_dir()
filename = os.path.join(dirname, 'liblib.cpp')
- BUILD_AS_SHARED_LIB = 1
+ Settings.BUILD_AS_SHARED_LIB = 1
self.build(lib_src, dirname, filename)
shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so'))
@@ -1951,7 +1892,7 @@ if 'benchmark' not in str(sys.argv):
return 0;
}
'''
- BUILD_AS_SHARED_LIB = 0
+ Settings.BUILD_AS_SHARED_LIB = 0
def add_pre_run_and_checks(filename):
src = open(filename, 'r').read().replace(
'// {{PRE_RUN_ADDITIONS}}',
@@ -1962,7 +1903,6 @@ if 'benchmark' not in str(sys.argv):
post_build=add_pre_run_and_checks)
def test_dlfcn_qsort(self):
- global BUILD_AS_SHARED_LIB, EXPORTED_FUNCTIONS
lib_src = '''
int lib_cmp(const void* left, const void* right) {
const int* a = (const int*) left;
@@ -1980,8 +1920,8 @@ if 'benchmark' not in str(sys.argv):
'''
dirname = self.get_dir()
filename = os.path.join(dirname, 'liblib.cpp')
- BUILD_AS_SHARED_LIB = 1
- EXPORTED_FUNCTIONS = ['_get_cmp']
+ Settings.BUILD_AS_SHARED_LIB = 1
+ Settings.EXPORTED_FUNCTIONS = ['_get_cmp']
self.build(lib_src, dirname, filename)
shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so'))
@@ -2035,8 +1975,8 @@ if 'benchmark' not in str(sys.argv):
return 0;
}
'''
- BUILD_AS_SHARED_LIB = 0
- EXPORTED_FUNCTIONS = ['_main']
+ Settings.BUILD_AS_SHARED_LIB = 0
+ Settings.EXPORTED_FUNCTIONS = ['_main']
def add_pre_run_and_checks(filename):
src = open(filename, 'r').read().replace(
'// {{PRE_RUN_ADDITIONS}}',
@@ -2048,10 +1988,8 @@ if 'benchmark' not in str(sys.argv):
post_build=add_pre_run_and_checks)
def test_dlfcn_data_and_fptr(self):
- global LLVM_OPTS
- if LLVM_OPTS: return self.skip('LLVM opts will optimize out parent_func')
+ if Building.LLVM_OPTS: return self.skip('LLVM opts will optimize out parent_func')
- global BUILD_AS_SHARED_LIB, EXPORTED_FUNCTIONS, EXPORTED_GLOBALS
lib_src = '''
#include <stdio.h>
@@ -2076,9 +2014,9 @@ if 'benchmark' not in str(sys.argv):
'''
dirname = self.get_dir()
filename = os.path.join(dirname, 'liblib.cpp')
- BUILD_AS_SHARED_LIB = 1
- EXPORTED_FUNCTIONS = ['_func']
- EXPORTED_GLOBALS = ['_global']
+ Settings.BUILD_AS_SHARED_LIB = 1
+ Settings.EXPORTED_FUNCTIONS = ['_func']
+ Settings.EXPORTED_GLOBALS = ['_global']
self.build(lib_src, dirname, filename)
shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so'))
@@ -2134,9 +2072,9 @@ if 'benchmark' not in str(sys.argv):
return 0;
}
'''
- BUILD_AS_SHARED_LIB = 0
- EXPORTED_FUNCTIONS = ['_main']
- EXPORTED_GLOBALS = []
+ Settings.BUILD_AS_SHARED_LIB = 0
+ Settings.EXPORTED_FUNCTIONS = ['_main']
+ Settings.EXPORTED_GLOBALS = []
def add_pre_run_and_checks(filename):
src = open(filename, 'r').read().replace(
'// {{PRE_RUN_ADDITIONS}}',
@@ -2148,7 +2086,6 @@ if 'benchmark' not in str(sys.argv):
post_build=add_pre_run_and_checks)
def test_dlfcn_alias(self):
- global BUILD_AS_SHARED_LIB, EXPORTED_FUNCTIONS, INCLUDE_FULL_LIBRARY
lib_src = r'''
#include <stdio.h>
extern int parent_global;
@@ -2158,8 +2095,8 @@ if 'benchmark' not in str(sys.argv):
'''
dirname = self.get_dir()
filename = os.path.join(dirname, 'liblib.cpp')
- BUILD_AS_SHARED_LIB = 1
- EXPORTED_FUNCTIONS = ['_func']
+ Settings.BUILD_AS_SHARED_LIB = 1
+ Settings.EXPORTED_FUNCTIONS = ['_func']
self.build(lib_src, dirname, filename)
shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so'))
@@ -2181,9 +2118,9 @@ if 'benchmark' not in str(sys.argv):
return 0;
}
'''
- BUILD_AS_SHARED_LIB = 0
- INCLUDE_FULL_LIBRARY = 1
- EXPORTED_FUNCTIONS = ['_main']
+ Settings.BUILD_AS_SHARED_LIB = 0
+ Settings.INCLUDE_FULL_LIBRARY = 1
+ Settings.EXPORTED_FUNCTIONS = ['_main']
def add_pre_run_and_checks(filename):
src = open(filename, 'r').read().replace(
'// {{PRE_RUN_ADDITIONS}}',
@@ -2194,11 +2131,10 @@ if 'benchmark' not in str(sys.argv):
output_nicerizer=lambda x: x.replace('\n', '*'),
post_build=add_pre_run_and_checks,
extra_emscripten_args=['-H', 'libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/time.h,libc/langinfo.h'])
- INCLUDE_FULL_LIBRARY = 0
+ Settings.INCLUDE_FULL_LIBRARY = 0
def test_dlfcn_varargs(self):
- if QUANTUM_SIZE == 1: return self.skip('FIXME: Add support for this')
- global BUILD_AS_SHARED_LIB, EXPORTED_FUNCTIONS
+ if Settings.QUANTUM_SIZE == 1: return self.skip('FIXME: Add support for this')
lib_src = r'''
void print_ints(int n, ...);
extern "C" void func() {
@@ -2207,8 +2143,8 @@ if 'benchmark' not in str(sys.argv):
'''
dirname = self.get_dir()
filename = os.path.join(dirname, 'liblib.cpp')
- BUILD_AS_SHARED_LIB = 1
- EXPORTED_FUNCTIONS = ['_func']
+ Settings.BUILD_AS_SHARED_LIB = 1
+ Settings.EXPORTED_FUNCTIONS = ['_func']
self.build(lib_src, dirname, filename)
shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so'))
@@ -2239,8 +2175,8 @@ if 'benchmark' not in str(sys.argv):
return 0;
}
'''
- BUILD_AS_SHARED_LIB = 0
- EXPORTED_FUNCTIONS = ['_main']
+ Settings.BUILD_AS_SHARED_LIB = 0
+ Settings.EXPORTED_FUNCTIONS = ['_main']
def add_pre_run_and_checks(filename):
src = open(filename, 'r').read().replace(
'// {{PRE_RUN_ADDITIONS}}',
@@ -2294,7 +2230,7 @@ if 'benchmark' not in str(sys.argv):
self.do_run(src, re.sub(r'(^|\n)\s+', r'\1', expected))
def test_strtod(self):
- if USE_TYPED_ARRAYS == 2: return self.skip('Typed arrays = 2 truncate doubles')
+ if Settings.USE_TYPED_ARRAYS == 2: return self.skip('Typed arrays = 2 truncate doubles')
src = r'''
#include <stdio.h>
#include <stdlib.h>
@@ -2349,13 +2285,13 @@ if 'benchmark' not in str(sys.argv):
self.do_run(src, re.sub(r'\n\s+', '\n', expected))
def test_parseInt(self):
- if USE_TYPED_ARRAYS != 0: return self.skip('Typed arrays truncate i64')
+ if Settings.USE_TYPED_ARRAYS != 0: return self.skip('Typed arrays truncate i64')
src = open(path_from_root('tests', 'parseInt', 'src.c'), 'r').read()
expected = open(path_from_root('tests', 'parseInt', 'output.txt'), 'r').read()
self.do_run(src, expected)
def test_printf(self):
- if USE_TYPED_ARRAYS != 0: return self.skip('Typed arrays truncate i64')
+ if Settings.USE_TYPED_ARRAYS != 0: return self.skip('Typed arrays truncate i64')
src = open(path_from_root('tests', 'printf', 'test.c'), 'r').read()
expected = open(path_from_root('tests', 'printf', 'output.txt'), 'r').read()
self.do_run(src, expected)
@@ -2410,7 +2346,7 @@ if 'benchmark' not in str(sys.argv):
self.do_run(src, expected, extra_emscripten_args=['-H', 'libc/langinfo.h'])
def test_files(self):
- global CORRECT_SIGNS; CORRECT_SIGNS = 1 # Just so our output is what we expect. Can flip them both.
+ Settings.CORRECT_SIGNS = 1 # Just so our output is what we expect. Can flip them both.
def post(filename):
src = open(filename, 'r').read().replace(
'// {{PRE_RUN_ADDITIONS}}',
@@ -2762,7 +2698,7 @@ if 'benchmark' not in str(sys.argv):
self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected), post_build=add_pre_run_and_checks)
def test_fs_base(self):
- global INCLUDE_FULL_LIBRARY; INCLUDE_FULL_LIBRARY = 1
+ Settings.INCLUDE_FULL_LIBRARY = 1
try:
def addJS(filename):
src = open(filename, 'r').read().replace(
@@ -2773,7 +2709,7 @@ if 'benchmark' not in str(sys.argv):
expected = open(path_from_root('tests', 'filesystem', 'output.txt'), 'r').read()
self.do_run(src, expected, post_build=addJS, extra_emscripten_args=['-H', 'libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/langinfo.h,libc/time.h'])
finally:
- INCLUDE_FULL_LIBRARY = 0
+ Settings.INCLUDE_FULL_LIBRARY = 0
def test_unistd_access(self):
def add_pre_run(filename):
@@ -2968,12 +2904,25 @@ if 'benchmark' not in str(sys.argv):
def test_ctype(self):
# The bit fiddling done by the macros using __ctype_b_loc requires this.
- global CORRECT_SIGNS; CORRECT_SIGNS = 1
+ Settings.CORRECT_SIGNS = 1
src = open(path_from_root('tests', 'ctype', 'src.c'), 'r').read()
expected = open(path_from_root('tests', 'ctype', 'output.txt'), 'r').read()
self.do_run(src, expected)
CORRECT_SIGNS = 0
+ def test_iostream(self):
+ src = '''
+ #include <iostream>
+
+ int main()
+ {
+ std::cout << "hello world";
+ return 0;
+ }
+ '''
+
+ self.do_run(src, 'hello world')
+
### 'Big' tests
def test_fannkuch(self):
@@ -2983,8 +2932,7 @@ if 'benchmark' not in str(sys.argv):
self.do_run(src, 'Pfannkuchen(%d) = %d.' % (i,j), [str(i)], no_build=i>1)
def test_raytrace(self):
- global USE_TYPED_ARRAYS
- if USE_TYPED_ARRAYS == 2: return self.skip('Relies on double values')
+ if Settings.USE_TYPED_ARRAYS == 2: return self.skip('Relies on double values')
src = open(path_from_root('tests', 'raytrace.cpp'), 'r').read()
output = open(path_from_root('tests', 'raytrace.ppm'), 'r').read()
@@ -2998,9 +2946,9 @@ if 'benchmark' not in str(sys.argv):
self.do_run(src, j, [str(i)], lambda x: x.replace('\n', '*'), no_build=i>1)
def test_dlmalloc(self):
- global CORRECT_SIGNS; CORRECT_SIGNS = 2
- global CORRECT_SIGNS_LINES; CORRECT_SIGNS_LINES = ['src.cpp:' + str(i+4) for i in [4816, 4191, 4246, 4199, 4205, 4235, 4227]]
- global TOTAL_MEMORY; TOTAL_MEMORY = 100*1024*1024 # needed with typed arrays
+ Settings.CORRECT_SIGNS = 2
+ Settings.CORRECT_SIGNS_LINES = ['src.cpp:' + str(i+4) for i in [4816, 4191, 4246, 4199, 4205, 4235, 4227]]
+ Settings.TOTAL_MEMORY = 100*1024*1024 # needed with typed arrays
src = open(path_from_root('src', 'dlmalloc.c'), 'r').read() + '\n\n\n' + open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read()
self.do_run(src, '*1,0*', ['200', '1'])
@@ -3011,21 +2959,6 @@ if 'benchmark' not in str(sys.argv):
self.do_run(src, '*1,0*', ['200', '1'], extra_emscripten_args=['-m'])
self.do_run(src, '*400,0*', ['400', '400'], extra_emscripten_args=['-m'], no_build=True)
- def zzztest_gl(self):
- # Switch to gcc from g++ - we don't compile properly otherwise (why?)
- global COMPILER
- COMPILER = COMPILER.replace('++', '')
-
- def post(filename):
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- '''Module["__CANVAS__"] = {
- getContext: function() {},
- };'''
- )
- open(filename, 'w').write(src)
- self.do_run(path_from_root('tests', 'gl'), '*?*', main_file='sdl_ogl.c', post_build=post)
-
def test_libcxx(self):
self.do_run(path_from_root('tests', 'libcxx'),
'june -> 30\nPrevious (in alphabetical order) is july\nNext (in alphabetical order) is march',
@@ -3046,13 +2979,13 @@ if 'benchmark' not in str(sys.argv):
''', 'hello world', includes=[path_from_root('tests', 'libcxx', 'include')]);
def test_cubescript(self):
- global COMPILER_TEST_OPTS; COMPILER_TEST_OPTS = [] # remove -g, so we have one test without it by default
+ Building.COMPILER_TEST_OPTS = [] # remove -g, so we have one test without it by default
- global SAFE_HEAP; SAFE_HEAP = 0 # Has some actual loads of unwritten-to places, in the C++ code...
+ Settings.SAFE_HEAP = 0 # Has some actual loads of unwritten-to places, in the C++ code...
# Overflows happen in hash loop
- global CORRECT_OVERFLOWS; CORRECT_OVERFLOWS = 1
- global CHECK_OVERFLOWS; CHECK_OVERFLOWS = 0
+ Settings.CORRECT_OVERFLOWS = 1
+ Settings.CHECK_OVERFLOWS = 0
self.do_run(path_from_root('tests', 'cubescript'), '*\nTemp is 33\n9\n5\nhello, everyone\n*', main_file='command.cpp')
#build_ll_hook=self.do_autodebug)
@@ -3071,15 +3004,14 @@ if 'benchmark' not in str(sys.argv):
# print opt, "FAIL"
def test_lua(self):
- global QUANTUM_SIZE
- if QUANTUM_SIZE == 1: return self.skip('TODO: make this work')
+ if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: make this work')
# Overflows in luaS_newlstr hash loop
- global SAFE_HEAP; SAFE_HEAP = 0 # Has various warnings, with copied HEAP_HISTORY values (fixed if we copy 'null' as the type)
- global CORRECT_OVERFLOWS; CORRECT_OVERFLOWS = 1
- global CHECK_OVERFLOWS; CHECK_OVERFLOWS = 0
- global CORRECT_SIGNS; CORRECT_SIGNS = 1 # Not sure why, but needed
- global INIT_STACK; INIT_STACK = 1 # TODO: Investigate why this is necessary
+ Settings.SAFE_HEAP = 0 # Has various warnings, with copied HEAP_HISTORY values (fixed if we copy 'null' as the type)
+ Settings.CORRECT_OVERFLOWS = 1
+ Settings.CHECK_OVERFLOWS = 0
+ Settings.CORRECT_SIGNS = 1 # Not sure why, but needed
+ Settings.INIT_STACK = 1 # TODO: Investigate why this is necessary
self.do_ll_run(path_from_root('tests', 'lua', 'lua.ll'),
'hello lua world!\n17\n1\n2\n3\n4\n7',
@@ -3087,68 +3019,20 @@ if 'benchmark' not in str(sys.argv):
output_nicerizer=lambda string: string.replace('\n\n', '\n').replace('\n\n', '\n'),
extra_emscripten_args=['-H', 'libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/langinfo.h,libc/time.h'])
- def get_building_dir(self):
+ def get_build_dir(self):
return os.path.join(self.get_dir(), 'building')
- # Build a library into a .bc file. We build the .bc file once and cache it for all our tests. (We cache in
- # memory since the test directory is destroyed and recreated for each test. Note that we cache separately
- # for different compilers)
- def get_library(self, name, generated_libs, configure=['./configure'], configure_args=[], make=['make'], make_args=['-j', '2'], cache=True, build_subdir=None):
- if type(generated_libs) is not list: generated_libs = [generated_libs]
- if build_subdir and configure.startswith('./'):
- configure = '.' + configure
-
- if GlobalCache is not None:
- cache_name = name + '|' + COMPILER
- if cache and GlobalCache.get(cache_name):
- print >> sys.stderr, '<load build from cache> ',
- bc_file = os.path.join(self.get_dir(), 'lib' + name + '.bc')
- f = open(bc_file, 'wb')
- f.write(GlobalCache[cache_name])
- f.close()
- return bc_file
-
- temp_dir = self.get_building_dir()
- project_dir = os.path.join(temp_dir, name)
- shutil.copytree(path_from_root('tests', name), project_dir) # Useful in debugging sometimes to comment this out
- os.chdir(project_dir)
- if build_subdir:
- try:
- os.mkdir('cbuild')
- except:
- pass
- os.chdir(os.path.join(project_dir, 'cbuild'))
- env = os.environ.copy()
- env['RANLIB'] = env['AR'] = env['CXX'] = env['CC'] = env['LIBTOOL'] = EMMAKEN
- env['EMMAKEN_COMPILER'] = COMPILER
- env['EMSCRIPTEN_TOOLS'] = path_from_root('tools')
- env['CFLAGS'] = env['EMMAKEN_CFLAGS'] = ' '.join(COMPILER_OPTS + COMPILER_TEST_OPTS) # Normal CFLAGS is ignored by some configure's.
- if configure: # Useful in debugging sometimes to comment this out (and the lines below up to and including the |make| call)
- env['EMMAKEN_JUST_CONFIGURE'] = '1'
- Popen(configure + configure_args, stdout=open(os.path.join(self.get_dir(), 'configure'), 'w'),
- stderr=open(os.path.join(self.get_dir(), 'configure_err'), 'w'), env=env).communicate()[0]
- del env['EMMAKEN_JUST_CONFIGURE']
- Popen(make + make_args, stdout=open(os.path.join(self.get_dir(), 'make'), 'w'),
- stderr=open(os.path.join(self.get_dir(), 'make_err'), 'w'), env=env).communicate()[0]
- bc_file = os.path.join(project_dir, 'bc.bc')
- self.do_link(map(lambda lib: os.path.join(project_dir, 'cbuild', lib) if build_subdir else os.path.join(project_dir, lib), generated_libs), bc_file)
- if cache and GlobalCache is not None:
- print >> sys.stderr, '<save build into cache> ',
- GlobalCache[cache_name] = open(bc_file, 'rb').read()
- return bc_file
-
def get_freetype(self):
- global INIT_STACK; INIT_STACK = 1 # TODO: Investigate why this is necessary
+ Settings.INIT_STACK = 1 # TODO: Investigate why this is necessary
return self.get_library('freetype', os.path.join('objs', '.libs', 'libfreetype.a.bc'))
def test_freetype(self):
- if QUANTUM_SIZE == 1: return self.skip('TODO: Figure out and try to fix')
+ if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: Figure out and try to fix')
- if LLVM_OPTS: global RELOOP; RELOOP = 0 # Too slow; we do care about typed arrays and OPTIMIZE though
+ if Building.LLVM_OPTS: Settings.RELOOP = 0 # Too slow; we do care about typed arrays and OPTIMIZE though
- global CORRECT_SIGNS
- if CORRECT_SIGNS == 0: CORRECT_SIGNS = 1 # Not sure why, but needed
+ if Settings.CORRECT_SIGNS == 0: Settings.CORRECT_SIGNS = 1 # Not sure why, but needed
def post(filename):
# Embed the font into the document
@@ -3171,22 +3055,21 @@ if 'benchmark' not in str(sys.argv):
def test_sqlite(self):
# gcc -O3 -I/home/alon/Dev/emscripten/tests/sqlite -ldl src.c
- global QUANTUM_SIZE, OPTIMIZE, RELOOP, USE_TYPED_ARRAYS
- if QUANTUM_SIZE == 1: return self.skip('TODO FIXME')
- RELOOP = 0 # too slow
+ if Settings.QUANTUM_SIZE == 1: return self.skip('TODO FIXME')
+ Settings.RELOOP = 0 # too slow
auto_optimize_data = read_auto_optimize_data(path_from_root('tests', 'sqlite', 'sqlite-autooptimize.fails.txt'))
- global CORRECT_SIGNS; CORRECT_SIGNS = 2
- global CORRECT_SIGNS_LINES; CORRECT_SIGNS_LINES = auto_optimize_data['signs_lines']
- global CORRECT_OVERFLOWS; CORRECT_OVERFLOWS = 0
- global CORRECT_ROUNDINGS; CORRECT_ROUNDINGS = 0
- global SAFE_HEAP; SAFE_HEAP = 0 # uses time.h to set random bytes, other stuff
- global DISABLE_EXCEPTION_CATCHING; DISABLE_EXCEPTION_CATCHING = 1
- global FAST_MEMORY; FAST_MEMORY = 4*1024*1024
- global EXPORTED_FUNCTIONS; EXPORTED_FUNCTIONS = ['_main', '_sqlite3_open', '_sqlite3_close', '_sqlite3_exec', '_sqlite3_free', '_callback'];
+ Settings.CORRECT_SIGNS = 2
+ Settings.CORRECT_SIGNS_LINES = auto_optimize_data['signs_lines']
+ Settings.CORRECT_OVERFLOWS = 0
+ Settings.CORRECT_ROUNDINGS = 0
+ Settings.SAFE_HEAP = 0 # uses time.h to set random bytes, other stuff
+ Settings.DISABLE_EXCEPTION_CATCHING = 1
+ Settings.FAST_MEMORY = 4*1024*1024
+ Settings.EXPORTED_FUNCTIONS = ['_main', '_sqlite3_open', '_sqlite3_close', '_sqlite3_exec', '_sqlite3_free', '_callback'];
- global INVOKE_RUN; INVOKE_RUN = 0 # We append code that does run() ourselves
+ Settings.INVOKE_RUN = 0 # We append code that does run() ourselves
def post(filename):
src = open(filename, 'a')
@@ -3216,7 +3099,7 @@ if 'benchmark' not in str(sys.argv):
post_build=post)#,build_ll_hook=self.do_autodebug)
def test_zlib(self):
- global CORRECT_SIGNS; CORRECT_SIGNS = 1
+ Settings.CORRECT_SIGNS = 1
self.do_run(open(path_from_root('tests', 'zlib', 'example.c'), 'r').read(),
open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(),
@@ -3224,33 +3107,16 @@ if 'benchmark' not in str(sys.argv):
includes=[path_from_root('tests', 'zlib')],
force_c=True)
- def zzztest_glibc(self):
- global CORRECT_SIGNS; CORRECT_SIGNS = 1
- global CORRECT_OVERFLOWS; CORRECT_OVERFLOWS = 1
- global CORRECT_ROUNDINGS; CORRECT_ROUNDINGS = 1
-
- self.do_run(r'''
- #include <stdio.h>
- int main() { printf("hai\n"); return 1; }
- ''',
- libraries=[self.get_library('glibc', [os.path.join('src', '.libs', 'libBulletCollision.a.bc'),
- os.path.join('src', '.libs', 'libBulletDynamics.a.bc'),
- os.path.join('src', '.libs', 'libLinearMath.a.bc')],
- configure_args=['--disable-sanity-checks'])],
- includes=[path_from_root('tests', 'glibc', 'include')])
-
def test_the_bullet(self): # Called thus so it runs late in the alphabetical cycle... it is long
- global SAFE_HEAP, SAFE_HEAP_LINES, USE_TYPED_ARRAYS, LLVM_OPTS
-
- if LLVM_OPTS: SAFE_HEAP = 0 # Optimizations make it so we do not have debug info on the line we need to ignore
+ if Building.LLVM_OPTS: Settings.SAFE_HEAP = 0 # Optimizations make it so we do not have debug info on the line we need to ignore
- if USE_TYPED_ARRAYS == 2: return self.skip('We have slightly different rounding here for some reason. TODO: activate this')
+ if Settings.USE_TYPED_ARRAYS == 2: return self.skip('We have slightly different rounding here for some reason. TODO: activate this')
- if SAFE_HEAP:
+ if Settings.SAFE_HEAP:
# Ignore bitfield warnings
- SAFE_HEAP = 3
- SAFE_HEAP_LINES = ['btVoronoiSimplexSolver.h:40', 'btVoronoiSimplexSolver.h:41',
- 'btVoronoiSimplexSolver.h:42', 'btVoronoiSimplexSolver.h:43']
+ Settings.SAFE_HEAP = 3
+ Settings.SAFE_HEAP_LINES = ['btVoronoiSimplexSolver.h:40', 'btVoronoiSimplexSolver.h:41',
+ 'btVoronoiSimplexSolver.h:42', 'btVoronoiSimplexSolver.h:43']
self.do_run(open(path_from_root('tests', 'bullet', 'Demos', 'HelloWorld', 'HelloWorld.cpp'), 'r').read(),
open(path_from_root('tests', 'bullet', 'output.txt'), 'r').read(),
@@ -3262,25 +3128,18 @@ if 'benchmark' not in str(sys.argv):
js_engines=[SPIDERMONKEY_ENGINE]) # V8 issue 1407
def test_poppler(self):
- global RELOOP, LLVM_OPTS, USE_TYPED_ARRAYS, QUANTUM_SIZE
-
# llvm-link failure when using clang, LLVM bug 9498, still relevant?
- if RELOOP or LLVM_OPTS: return self.skip('TODO')
- if USE_TYPED_ARRAYS == 2 or QUANTUM_SIZE == 1: return self.skip('TODO: Figure out and try to fix')
-
- USE_TYPED_ARRAYS = 0 # XXX bug - we fail with this FIXME
+ if Settings.RELOOP or Building.LLVM_OPTS: return self.skip('TODO')
+ if Settings.USE_TYPED_ARRAYS == 2 or Settings.QUANTUM_SIZE == 1: return self.skip('TODO: Figure out and try to fix')
- global SAFE_HEAP; SAFE_HEAP = 0 # Has variable object
+ Settings.USE_TYPED_ARRAYS = 0 # XXX bug - we fail with this FIXME
- #global CORRECT_OVERFLOWS; CORRECT_OVERFLOWS = 1
- global CHECK_OVERFLOWS; CHECK_OVERFLOWS = 0
+ Settings.SAFE_HEAP = 0 # Has variable object
- #global CHECK_OVERFLOWS; CHECK_OVERFLOWS = 1
- #global CHECK_SIGNS; CHECK_SIGNS = 1
+ Settings.CHECK_OVERFLOWS = 0
- global CORRECT_SIGNS; CORRECT_SIGNS = 1
- global CORRECT_SIGNS_LINES
- CORRECT_SIGNS_LINES = ['parseargs.cc:171', 'BuiltinFont.cc:64', 'NameToCharCode.cc:115', 'GooHash.cc:368',
+ Settings.CORRECT_SIGNS = 1
+ Settings.CORRECT_SIGNS_LINES = ['parseargs.cc:171', 'BuiltinFont.cc:64', 'NameToCharCode.cc:115', 'GooHash.cc:368',
'Stream.h:469', 'PDFDoc.cc:1064', 'Lexer.cc:201', 'Splash.cc:1130', 'XRef.cc:997',
'vector:714', 'Lexer.cc:259', 'Splash.cc:438', 'Splash.cc:532', 'GfxFont.cc:1152',
'Gfx.cc:3838', 'Splash.cc:3162', 'Splash.cc:3163', 'Splash.cc:3164', 'Splash.cc:3153',
@@ -3294,13 +3153,13 @@ if 'benchmark' not in str(sys.argv):
'psobjs.c:195', 'pshglob.c:165', 'ttload.c:694', 'ttmtx.c:195', 'sfobjs.c:957',
'sfobjs.c:958', 'ftstream.c:369', 'ftstream.c:372', 'ttobjs.c:1007'] # And many more...
- global COMPILER_TEST_OPTS; COMPILER_TEST_OPTS += [
+ Building.COMPILER_TEST_OPTS += [
'-I' + path_from_root('tests', 'libcxx', 'include'), # Avoid libstdc++ linking issue, see libcxx test
'-I' + path_from_root('tests', 'freetype', 'include'),
'-I' + path_from_root('tests', 'poppler', 'include'),
]
- global INVOKE_RUN; INVOKE_RUN = 0 # We append code that does run() ourselves
+ Settings.INVOKE_RUN = 0 # We append code that does run() ourselves
# See post(), below
input_file = open(os.path.join(self.get_dir(), 'paper.pdf.js'), 'w')
@@ -3336,7 +3195,7 @@ if 'benchmark' not in str(sys.argv):
# Combine libraries
combined = os.path.join(self.get_building_dir(), 'combined.bc')
- self.do_link([freetype, poppler], combined)
+ Building.link([freetype, poppler], combined)
self.do_ll_run(combined,
lambda: map(ord, open(path_from_root('tests', 'poppler', 'ref.ppm'), 'r').read()).__str__().replace(' ', ''),
@@ -3345,14 +3204,11 @@ if 'benchmark' not in str(sys.argv):
#, build_ll_hook=self.do_autodebug)
def test_openjpeg(self):
- global USE_TYPED_ARRAYS
- global CORRECT_SIGNS
- if USE_TYPED_ARRAYS == 2:
- CORRECT_SIGNS = 1
+ if Settings.USE_TYPED_ARRAYS == 2:
+ Settings.CORRECT_SIGNS = 1
else:
- CORRECT_SIGNS = 2
- global CORRECT_SIGNS_LINES
- CORRECT_SIGNS_LINES = ["mqc.c:566", "mqc.c:317"]
+ Settings.CORRECT_SIGNS = 2
+ Settings.CORRECT_SIGNS_LINES = ["mqc.c:566", "mqc.c:317"]
original_j2k = path_from_root('tests', 'openjpeg', 'syntensity_lobby_s.j2k')
@@ -3428,16 +3284,15 @@ if 'benchmark' not in str(sys.argv):
output_nicerizer=image_compare)# build_ll_hook=self.do_autodebug)
def test_python(self):
- global QUANTUM_SIZE, USE_TYPED_ARRAYS
- if QUANTUM_SIZE == 1 or USE_TYPED_ARRAYS == 2: return self.skip('TODO: make this work')
+ if Settings.QUANTUM_SIZE == 1 or Settings.USE_TYPED_ARRAYS == 2: return self.skip('TODO: make this work')
# Overflows in string_hash
- global CORRECT_OVERFLOWS; CORRECT_OVERFLOWS = 1
- global CHECK_OVERFLOWS; CHECK_OVERFLOWS = 0
- global RELOOP; RELOOP = 0 # Too slow; we do care about typed arrays and OPTIMIZE though
- global SAFE_HEAP; SAFE_HEAP = 0 # Has bitfields which are false positives. Also the PyFloat_Init tries to detect endianness.
- global CORRECT_SIGNS; CORRECT_SIGNS = 1 # Not sure why, but needed
- global EXPORTED_FUNCTIONS; EXPORTED_FUNCTIONS = ['_main', '_PyRun_SimpleStringFlags'] # for the demo
+ Settings.CORRECT_OVERFLOWS = 1
+ Settings.CHECK_OVERFLOWS = 0
+ Settings.RELOOP = 0 # Too slow; we do care about typed arrays and OPTIMIZE though
+ Settings.SAFE_HEAP = 0 # Has bitfields which are false positives. Also the PyFloat_Init tries to detect endianness.
+ Settings.CORRECT_SIGNS = 1 # Not sure why, but needed
+ Settings.EXPORTED_FUNCTIONS = ['_main', '_PyRun_SimpleStringFlags'] # for the demo
self.do_ll_run(path_from_root('tests', 'python', 'python.ll'),
'hello python world!\n[0, 2, 4, 6]\n5\n22\n5.470000',
@@ -3448,15 +3303,14 @@ if 'benchmark' not in str(sys.argv):
# They are only valid enough for us to read for test purposes, not for llvm-as
# to process.
def test_cases(self):
- global QUANTUM_SIZE
- global CHECK_OVERFLOWS; CHECK_OVERFLOWS = 0
- if LLVM_OPTS: return self.skip("Our code is not exactly 'normal' llvm assembly")
+ Settings.CHECK_OVERFLOWS = 0
+ if Building.LLVM_OPTS: return self.skip("Our code is not exactly 'normal' llvm assembly")
for name in glob.glob(path_from_root('tests', 'cases', '*.ll')):
shortname = name.replace('.ll', '')
print "Testing case '%s'..." % shortname
output_file = path_from_root('tests', 'cases', shortname + '.txt')
- if QUANTUM_SIZE == 1:
+ if Settings.QUANTUM_SIZE == 1:
q1_output_file = path_from_root('tests', 'cases', shortname + '_q1.txt')
if os.path.exists(q1_output_file):
output_file = q1_output_file
@@ -3474,7 +3328,7 @@ if 'benchmark' not in str(sys.argv):
self.prep_ll_run(filename, filename+'.o.ll.ll', force_recompile=True) # rebuild .bc
def test_autodebug(self):
- if LLVM_OPTS: return self.skip('LLVM opts mess us up')
+ if Building.LLVM_OPTS: return self.skip('LLVM opts mess us up')
# Run a test that should work, generating some code
self.test_structs()
@@ -3527,8 +3381,8 @@ if 'benchmark' not in str(sys.argv):
self.do_run(src, '*hello slim world*', build_ll_hook=hook)
def test_profiling(self):
- global PROFILE; PROFILE = 1
- global INVOKE_RUN; INVOKE_RUN = 0
+ Settings.PROFILE = 1
+ Settings.INVOKE_RUN = 0
src = '''
#include <stdio.h>
@@ -3624,7 +3478,7 @@ if 'benchmark' not in str(sys.argv):
# Way 2: use CppHeaderParser
- global RUNTIME_TYPE_INFO; RUNTIME_TYPE_INFO = 1
+ Settings.RUNTIME_TYPE_INFO = 1
header = '''
#include <stdio.h>
@@ -3810,9 +3664,8 @@ Child2:9
''', post_build=post2)
def test_typeinfo(self):
- global RUNTIME_TYPE_INFO; RUNTIME_TYPE_INFO = 1
- global QUANTUM_SIZE
- if QUANTUM_SIZE != 4: return self.skip('We assume normal sizes in the output here')
+ Settings.RUNTIME_TYPE_INFO = 1
+ if Settings.QUANTUM_SIZE != 4: return self.skip('We assume normal sizes in the output here')
src = '''
#include<stdio.h>
@@ -3854,7 +3707,7 @@ Child2:9
post_build=post)
# Make sure that without the setting, we don't spam the .js with the type info
- RUNTIME_TYPE_INFO = 0
+ Settings.RUNTIME_TYPE_INFO = 0
self.do_run(src, 'No type info.', post_build=post)
### Tests for tools
@@ -3864,11 +3717,28 @@ Child2:9
#include<stdio.h>
int main() {
printf("*closured*\\n");
+
+ FILE *file = fopen("somefile.binary", "rb");
+ char buffer[1024];
+ size_t read = fread(buffer, 1, 4, file);
+ printf("data: %d", buffer[0]);
+ for (int i = 1; i < 4; i++)
+ printf(",%d", buffer[i]);
+ printf("\\n");
+
return 0;
}
'''
- def add_cc(filename):
+ def post(filename):
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ '''
+ FS.createDataFile('/', 'somefile.binary', [100, 1, 50, 25, 10, 77, 123], true, false);
+ '''
+ )
+ open(filename, 'w').write(src)
+
Popen(['java', '-jar', CLOSURE_COMPILER,
'--compilation_level', 'ADVANCED_OPTIMIZATIONS',
'--formatting', 'PRETTY_PRINT',
@@ -3879,13 +3749,14 @@ Child2:9
assert re.search('function \w\(', src) # see before
assert 'function _main()' not in src # closure should have wiped it out
open(filename, 'w').write(src)
- self.do_run(src, '*closured*', post_build=add_cc)
+
+ self.do_run(src, '*closured*\ndata: 100,1,50,25\n', post_build=post)
def test_safe_heap(self):
- global SAFE_HEAP, SAFE_HEAP_LINES
+ if Settings.USE_TYPED_ARRAYS == 2: return self.skip('It is ok to violate the load-store assumption with TA2')
+ if not Settings.SAFE_HEAP: return self.skip('We need SAFE_HEAP to test SAFE_HEAP')
+ if Building.LLVM_OPTS: return self.skip('LLVM can optimize away the intermediate |x|')
- if not SAFE_HEAP: return self.skip('We need SAFE_HEAP to test SAFE_HEAP')
- if LLVM_OPTS: return self.skip('LLVM can optimize away the intermediate |x|')
src = '''
#include<stdio.h>
int main() {
@@ -3906,14 +3777,14 @@ Child2:9
# And we should not fail if we disable checking on that line
- SAFE_HEAP = 3
- SAFE_HEAP_LINES = ["src.cpp:7"]
+ Settings.SAFE_HEAP = 3
+ Settings.SAFE_HEAP_LINES = ["src.cpp:7"]
self.do_run(src, '*ok*')
# But if we disable the wrong lines, we still fail
- SAFE_HEAP_LINES = ["src.cpp:99"]
+ Settings.SAFE_HEAP_LINES = ["src.cpp:99"]
try:
self.do_run(src, '*nothingatall*')
@@ -3923,14 +3794,14 @@ Child2:9
# And reverse the checks with = 2
- SAFE_HEAP = 2
- SAFE_HEAP_LINES = ["src.cpp:99"]
+ Settings.SAFE_HEAP = 2
+ Settings.SAFE_HEAP_LINES = ["src.cpp:99"]
self.do_run(src, '*ok*')
def test_check_overflow(self):
- global CHECK_OVERFLOWS; CHECK_OVERFLOWS = 1
- global CORRECT_OVERFLOWS; CORRECT_OVERFLOWS = 0
+ Settings.CHECK_OVERFLOWS = 1
+ Settings.CORRECT_OVERFLOWS = 0
src = '''
#include<stdio.h>
@@ -3994,15 +3865,14 @@ Child2:9
new_filename = os.path.join(dirname, 'new.bc')
shutil.copy(filename + '.o', new_filename)
- self.do_emscripten(new_filename, append_ext=False)
+ Building.emscripten(new_filename, append_ext=False)
shutil.copy(filename + '.o.js', os.path.join(self.get_dir(), 'new.cpp.o.js'))
self.do_run(None, 'test\n', basename='new.cpp', no_build=True)
def test_linespecific(self):
- global CHECK_SIGNS; CHECK_SIGNS = 0
- global CHECK_OVERFLOWS; CHECK_OVERFLOWS = 0
- global CORRECT_SIGNS, CORRECT_OVERFLOWS, CORRECT_ROUNDINGS, CORRECT_SIGNS_LINES, CORRECT_OVERFLOWS_LINES, CORRECT_ROUNDINGS_LINES
+ Settings.CHECK_SIGNS = 0
+ Settings.CHECK_OVERFLOWS = 0
# Signs
@@ -4018,28 +3888,28 @@ Child2:9
}
'''
- CORRECT_SIGNS = 0
+ Settings.CORRECT_SIGNS = 0
self.do_run(src, '*1*') # This is a fail - we expect 0
- CORRECT_SIGNS = 1
+ Settings.CORRECT_SIGNS = 1
self.do_run(src, '*0*') # Now it will work properly
# And now let's fix just that one line
- CORRECT_SIGNS = 2
- CORRECT_SIGNS_LINES = ["src.cpp:9"]
+ Settings.CORRECT_SIGNS = 2
+ Settings.CORRECT_SIGNS_LINES = ["src.cpp:9"]
self.do_run(src, '*0*')
# Fixing the wrong line should not work
- CORRECT_SIGNS = 2
- CORRECT_SIGNS_LINES = ["src.cpp:3"]
+ Settings.CORRECT_SIGNS = 2
+ Settings.CORRECT_SIGNS_LINES = ["src.cpp:3"]
self.do_run(src, '*1*')
# And reverse the checks with = 2
- CORRECT_SIGNS = 3
- CORRECT_SIGNS_LINES = ["src.cpp:3"]
+ Settings.CORRECT_SIGNS = 3
+ Settings.CORRECT_SIGNS_LINES = ["src.cpp:3"]
self.do_run(src, '*0*')
- CORRECT_SIGNS = 3
- CORRECT_SIGNS_LINES = ["src.cpp:9"]
+ Settings.CORRECT_SIGNS = 3
+ Settings.CORRECT_SIGNS_LINES = ["src.cpp:9"]
self.do_run(src, '*1*')
# Overflows
@@ -4057,7 +3927,7 @@ Child2:9
'''
correct = '*186854335,63*'
- CORRECT_OVERFLOWS = 0
+ Settings.CORRECT_OVERFLOWS = 0
try:
self.do_run(src, correct)
raise Exception('UNEXPECTED-PASS')
@@ -4065,17 +3935,17 @@ Child2:9
assert 'UNEXPECTED' not in str(e), str(e)
assert 'Expected to find' in str(e), str(e)
- CORRECT_OVERFLOWS = 1
+ Settings.CORRECT_OVERFLOWS = 1
self.do_run(src, correct) # Now it will work properly
# And now let's fix just that one line
- CORRECT_OVERFLOWS = 2
- CORRECT_OVERFLOWS_LINES = ["src.cpp:6"]
+ Settings.CORRECT_OVERFLOWS = 2
+ Settings.CORRECT_OVERFLOWS_LINES = ["src.cpp:6"]
self.do_run(src, correct)
# Fixing the wrong line should not work
- CORRECT_OVERFLOWS = 2
- CORRECT_OVERFLOWS_LINES = ["src.cpp:3"]
+ Settings.CORRECT_OVERFLOWS = 2
+ Settings.CORRECT_OVERFLOWS_LINES = ["src.cpp:3"]
try:
self.do_run(src, correct)
raise Exception('UNEXPECTED-PASS')
@@ -4084,11 +3954,11 @@ Child2:9
assert 'Expected to find' in str(e), str(e)
# And reverse the checks with = 2
- CORRECT_OVERFLOWS = 3
- CORRECT_OVERFLOWS_LINES = ["src.cpp:3"]
+ Settings.CORRECT_OVERFLOWS = 3
+ Settings.CORRECT_OVERFLOWS_LINES = ["src.cpp:3"]
self.do_run(src, correct)
- CORRECT_OVERFLOWS = 3
- CORRECT_OVERFLOWS_LINES = ["src.cpp:6"]
+ Settings.CORRECT_OVERFLOWS = 3
+ Settings.CORRECT_OVERFLOWS_LINES = ["src.cpp:6"]
try:
self.do_run(src, correct)
raise Exception('UNEXPECTED-PASS')
@@ -4120,29 +3990,27 @@ Child2:9
}
'''
- CORRECT_ROUNDINGS = 0
+ Settings.CORRECT_ROUNDINGS = 0
self.do_run(src.replace('TYPE', 'long long'), '*-3**2**-6**5*') # JS floor operations, always to the negative. This is an undetected error here!
self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # We get these right, since they are 32-bit and we can shortcut using the |0 trick
- CORRECT_ROUNDINGS = 1
+ Settings.CORRECT_ROUNDINGS = 1
self.do_run(src.replace('TYPE', 'long long'), '*-2**2**-5**5*') # Correct
self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # Correct
- CORRECT_ROUNDINGS = 2
- CORRECT_ROUNDINGS_LINES = ["src.cpp:13"] # Fix just the last mistake
+ Settings.CORRECT_ROUNDINGS = 2
+ Settings.CORRECT_ROUNDINGS_LINES = ["src.cpp:13"] # Fix just the last mistake
self.do_run(src.replace('TYPE', 'long long'), '*-3**2**-5**5*')
self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # Here we are lucky and also get the first one right
# And reverse the check with = 2
- CORRECT_ROUNDINGS = 3
- CORRECT_ROUNDINGS_LINES = ["src.cpp:999"]
+ Settings.CORRECT_ROUNDINGS = 3
+ Settings.CORRECT_ROUNDINGS_LINES = ["src.cpp:999"]
self.do_run(src.replace('TYPE', 'long long'), '*-2**2**-5**5*')
self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*')
def test_autooptimize(self):
- global CHECK_OVERFLOWS, CORRECT_OVERFLOWS, CHECK_SIGNS, CORRECT_SIGNS, AUTO_OPTIMIZE
-
- AUTO_OPTIMIZE = CHECK_OVERFLOWS = CORRECT_OVERFLOWS = CHECK_SIGNS = CORRECT_SIGNS = 1
+ Settings.AUTO_OPTIMIZE = Settings.CHECK_OVERFLOWS = Settings.CORRECT_OVERFLOWS = Settings.CHECK_SIGNS = Settings.CORRECT_SIGNS = 1
src = '''
#include<stdio.h>
@@ -4182,39 +4050,37 @@ class %s(T):
def setUp(self):
super(%s, self).setUp()
- global COMPILER, QUANTUM_SIZE, RELOOP, OPTIMIZE, ASSERTIONS, USE_TYPED_ARRAYS, LLVM_OPTS, SAFE_HEAP, CHECK_OVERFLOWS, CORRECT_OVERFLOWS, CORRECT_OVERFLOWS_LINES, CORRECT_SIGNS, CORRECT_SIGNS_LINES, CHECK_SIGNS, COMPILER_TEST_OPTS, CORRECT_ROUNDINGS, CORRECT_ROUNDINGS_LINES, INVOKE_RUN, SAFE_HEAP_LINES, INIT_STACK, AUTO_OPTIMIZE, RUNTIME_TYPE_INFO, DISABLE_EXCEPTION_CATCHING, PROFILE, TOTAL_MEMORY, FAST_MEMORY
-
- COMPILER = %r
+ Building.COMPILER = %r
llvm_opts = %d
embetter = %d
quantum_size = %d
- USE_TYPED_ARRAYS = %d
- INVOKE_RUN = 1
- RELOOP = OPTIMIZE = embetter
- QUANTUM_SIZE = quantum_size
- ASSERTIONS = 1-embetter
- SAFE_HEAP = 1-(embetter and llvm_opts)
- LLVM_OPTS = llvm_opts
- AUTO_OPTIMIZE = 0
- CHECK_OVERFLOWS = 1-(embetter or llvm_opts)
- CORRECT_OVERFLOWS = 1-(embetter and llvm_opts)
- CORRECT_SIGNS = 0
- CORRECT_ROUNDINGS = 0
- CORRECT_OVERFLOWS_LINES = CORRECT_SIGNS_LINES = CORRECT_ROUNDINGS_LINES = SAFE_HEAP_LINES = []
- CHECK_SIGNS = 0 #1-(embetter or llvm_opts)
- INIT_STACK = 0
- RUNTIME_TYPE_INFO = 0
- DISABLE_EXCEPTION_CATCHING = 0
- PROFILE = 0
- TOTAL_MEMORY = FAST_MEMORY = None
-
- if QUANTUM_SIZE == 1 or USE_TYPED_ARRAYS == 2:
- RELOOP = 0 # XXX Would be better to use this, but it isn't really what we test in these cases, and is very slow
-
- if LLVM_OPTS:
+ Settings.USE_TYPED_ARRAYS = %d
+ Settings.INVOKE_RUN = 1
+ Settings.RELOOP = Settings.OPTIMIZE = embetter
+ Settings.QUANTUM_SIZE = quantum_size
+ Settings.ASSERTIONS = 1-embetter
+ Settings.SAFE_HEAP = 1-(embetter and llvm_opts)
+ Building.LLVM_OPTS = llvm_opts
+ Settings.AUTO_OPTIMIZE = 0
+ Settings.CHECK_OVERFLOWS = 1-(embetter or llvm_opts)
+ Settings.CORRECT_OVERFLOWS = 1-(embetter and llvm_opts)
+ Settings.CORRECT_SIGNS = 0
+ Settings.CORRECT_ROUNDINGS = 0
+ Settings.CORRECT_OVERFLOWS_LINES = CORRECT_SIGNS_LINES = CORRECT_ROUNDINGS_LINES = SAFE_HEAP_LINES = []
+ Settings.CHECK_SIGNS = 0 #1-(embetter or llvm_opts)
+ Settings.INIT_STACK = 0
+ Settings.RUNTIME_TYPE_INFO = 0
+ Settings.DISABLE_EXCEPTION_CATCHING = 0
+ Settings.PROFILE = 0
+ Settings.TOTAL_MEMORY = Settings.FAST_MEMORY = None
+
+ if Settings.QUANTUM_SIZE == 1 or Settings.USE_TYPED_ARRAYS == 2:
+ Settings.RELOOP = 0 # XXX Would be better to use this, but it isn't really what we test in these cases, and is very slow
+
+ if Building.LLVM_OPTS:
self.pick_llvm_opts(3)
- COMPILER_TEST_OPTS = ['-g']
+ Building.COMPILER_TEST_OPTS = ['-g']
os.chdir(self.get_dir()) # Ensure the directory exists and go there
@@ -4239,11 +4105,9 @@ TT = %s
class OtherTests(RunnerCore):
def test_eliminator(self):
- coffee = path_from_root('tools', 'eliminator', 'node_modules', 'coffee-script', 'bin', 'coffee')
- eliminator = path_from_root('tools', 'eliminator', 'eliminator.coffee')
input = open(path_from_root('tools', 'eliminator', 'eliminator-test.js')).read()
expected = open(path_from_root('tools', 'eliminator', 'eliminator-test-output.js')).read()
- output = Popen([coffee, eliminator], stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate(input)[0]
+ output = Popen([COFFEESCRIPT, VARIABLE_ELIMINATOR], stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate(input)[0]
self.assertEquals(output, expected)
else:
@@ -4262,24 +4126,24 @@ else:
except:
pass
- COMPILER = CLANG
+ Building.COMPILER = CLANG
JS_ENGINE = SPIDERMONKEY_ENGINE
#JS_ENGINE = V8_ENGINE
- global COMPILER_TEST_OPTS; COMPILER_TEST_OPTS = []
-
- QUANTUM_SIZE = 1
- RELOOP = OPTIMIZE = 1
- USE_TYPED_ARRAYS = 1
- ASSERTIONS = SAFE_HEAP = CHECK_OVERFLOWS = CORRECT_OVERFLOWS = CHECK_SIGNS = INIT_STACK = AUTO_OPTIMIZE = RUNTIME_TYPE_INFO = 0
- INVOKE_RUN = 1
- CORRECT_SIGNS = 0
- CORRECT_ROUNDINGS = 0
- CORRECT_OVERFLOWS_LINES = CORRECT_SIGNS_LINES = CORRECT_ROUNDINGS_LINES = SAFE_HEAP_LINES = []
- DISABLE_EXCEPTION_CATCHING = 1
- if USE_TYPED_ARRAYS:
- TOTAL_MEMORY = 100*1024*1024 # XXX Needed for dlmalloc. TODO: Test other values
- FAST_MEMORY = 10*1024*1024
+ Building.COMPILER_TEST_OPTS = []
+
+ Settings.QUANTUM_SIZE = 1
+ Settings.RELOOP = Settings.OPTIMIZE = 1
+ Settings.USE_TYPED_ARRAYS = 1
+ Settings.ASSERTIONS = Settings.SAFE_HEAP = Settings.CHECK_OVERFLOWS = Settings.CORRECT_OVERFLOWS = Settings.CHECK_SIGNS = Settings.INIT_STACK = Settings.AUTO_OPTIMIZE = Settings.RUNTIME_TYPE_INFO = 0
+ Settings.INVOKE_RUN = 1
+ Settings.CORRECT_SIGNS = 0
+ Settings.CORRECT_ROUNDINGS = 0
+ Settings.CORRECT_OVERFLOWS_LINES = Settings.CORRECT_SIGNS_LINES = Settings.CORRECT_ROUNDINGS_LINES = Settings.SAFE_HEAP_LINES = []
+ Settings.DISABLE_EXCEPTION_CATCHING = 1
+ if Settings.USE_TYPED_ARRAYS:
+ Settings.TOTAL_MEMORY = 100*1024*1024 # XXX Needed for dlmalloc. TODO: Test other values
+ Settings.FAST_MEMORY = 10*1024*1024
TEST_REPS = 4
TOTAL_TESTS = 6
@@ -4313,10 +4177,8 @@ else:
print ' Native (gcc): mean: %.3f (+-%.3f) seconds (max: %.3f, min: %.3f, noise/signal: %.3f) JS is %.2f X slower' % (mean_native, std_native, max(native_times), min(native_times), std_native/mean_native, final)
def do_benchmark(self, src, args=[], expected_output='FAIL', main_file=None, llvm_opts=False, handpicked=False):
- global USE_TYPED_ARRAYS, LLVM_OPTS
-
- LLVM_OPTS = llvm_opts
- if LLVM_OPTS:
+ Building.LLVM_OPTS = llvm_opts
+ if Building.LLVM_OPTS:
self.pick_llvm_opts(3, handpicked)
dirname = self.get_dir()
@@ -4451,24 +4313,23 @@ else:
def test_raytrace(self):
global POST_OPTIMIZATIONS; POST_OPTIMIZATIONS = ['closure']
- global QUANTUM_SIZE, USE_TYPED_ARRAYS
- old_quantum = QUANTUM_SIZE
- old_use_typed_arrays = USE_TYPED_ARRAYS
- QUANTUM_SIZE = 1
- USE_TYPED_ARRAYS = 0 # Rounding errors with TA2 are too big in this very rounding-sensitive code. However, TA2 is much faster (2X)
+ old_quantum = Settings.QUANTUM_SIZE
+ old_use_typed_arrays = Settings.USE_TYPED_ARRAYS
+ Settings.QUANTUM_SIZE = 1
+ Settings.USE_TYPED_ARRAYS = 0 # Rounding errors with TA2 are too big in this very rounding-sensitive code. However, TA2 is much faster (2X)
src = open(path_from_root('tests', 'raytrace.cpp'), 'r').read().replace('double', 'float') # benchmark with floats
self.do_benchmark(src, ['7', '256'], '256 256', llvm_opts=True, handpicked=False)
- QUANTUM_SIZE = old_quantum
- USE_TYPED_ARRAYS = old_use_typed_arrays
+ Settings.QUANTUM_SIZE = old_quantum
+ Settings.USE_TYPED_ARRAYS = old_use_typed_arrays
def test_dlmalloc(self):
global POST_OPTIMIZATIONS; POST_OPTIMIZATIONS = ['eliminator']
- global COMPILER_TEST_OPTS; COMPILER_TEST_OPTS = ['-g']
- global CORRECT_SIGNS; CORRECT_SIGNS = 2
- global CORRECT_SIGNS_LINES; CORRECT_SIGNS_LINES = ['src.cpp:' + str(i+4) for i in [4816, 4191, 4246, 4199, 4205, 4235, 4227]]
+ Building.COMPILER_TEST_OPTS = ['-g']
+ Settings.CORRECT_SIGNS = 2
+ Settings.CORRECT_SIGNS_LINES = ['src.cpp:' + str(i+4) for i in [4816, 4191, 4246, 4199, 4205, 4235, 4227]]
src = open(path_from_root('src', 'dlmalloc.c'), 'r').read() + '\n\n\n' + open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read()
self.do_benchmark(src, ['400', '400'], '*400,0*', llvm_opts=True, handpicked=True)
diff --git a/tools/emmaken.py b/tools/emmaken.py
index 4984435a..f97eaa4f 100755
--- a/tools/emmaken.py
+++ b/tools/emmaken.py
@@ -51,6 +51,14 @@ to run g++ on it despite the .c extension, see
https://github.com/kripken/emscripten/issues/6
(If a similar situation occurs with ./configure, you can do the same there too.)
+
+emmaken can be influenced by a few environment variables:
+
+ EMMAKEN_NO_SDK - Will tell emmaken *not* to use the emscripten headers. Instead
+ your system headers will be used.
+
+ EMMAKEN_COMPILER - The compiler to be used, if you don't want the default clang.
+
'''
import sys
@@ -76,7 +84,11 @@ try:
#f.write('Args: ' + ' '.join(sys.argv) + '\nCMake? ' + str(CMAKE_CONFIG) + '\n')
#f.close()
- CXX = CLANG
+ if os.environ.get('EMMAKEN_COMPILER'):
+ CXX = os.environ['EMMAKEN_COMPILER']
+ else:
+ CXX = CLANG
+
CC = to_cc(CXX)
# If we got here from a redirection through emmakenxx.py, then force a C++ compiler here
diff --git a/tools/file2json.py b/tools/file2json.py
index a1c37244..f26f2864 100644
--- a/tools/file2json.py
+++ b/tools/file2json.py
@@ -28,3 +28,22 @@ if len(sys.argv) < 3:
else:
print 'var ' + sys.argv[2] + '=' + json + ';'
+'''
+or (but this fails, we get a string at runtime?)
+
+data = open(sys.argv[1], 'r').read()
+counter = 0
+print '[',
+for i in range(len(data)):
+ last = i == len(data)-1
+ print ord(data[i]),
+ counter += 1
+ if counter % 20 == 0:
+ print
+ if counter % 1005 == 0 and not last:
+ print '] + [',
+ elif not last: print ',',
+
+print ']'
+'''
+
diff --git a/tools/make_file.py b/tools/make_file.py
index 6885610d..720eb0e4 100644
--- a/tools/make_file.py
+++ b/tools/make_file.py
@@ -11,7 +11,7 @@ m = re.search('\[[\d, -]*\]', data)
data = eval(m.group(0))
data = [x&0xff for x in data]
string = ''.join([chr(item) for item in data])
-out = open(sys.argv[1]+'.raw', 'wb')
+out = open(sys.argv[1]+'.' + (sys.argv[2] if len(sys.argv) >= 3 else 'raw'), 'wb')
print data[0:80]
print string[0:80]
out.write(string)
diff --git a/tools/shared.py b/tools/shared.py
index 8f630ad6..6367b41a 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -1,4 +1,4 @@
-import shutil, time, os
+import shutil, time, os, json
from subprocess import Popen, PIPE, STDOUT
__rootpath__ = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
@@ -10,7 +10,7 @@ if not os.path.exists(CONFIG_FILE):
shutil.copy(path_from_root('settings.py'), CONFIG_FILE)
exec(open(CONFIG_FILE, 'r').read())
-# Tools
+# Tools/paths
CLANG=os.path.expanduser(os.path.join(LLVM_ROOT, 'clang++'))
LLVM_LINK=os.path.join(LLVM_ROOT, 'llvm-link')
@@ -21,9 +21,17 @@ LLVM_DIS=os.path.expanduser(os.path.join(LLVM_ROOT, 'llvm-dis'))
LLVM_DIS_OPTS = ['-show-annotations'] # For LLVM 2.8+. For 2.7, you may need to do just []
LLVM_INTERPRETER=os.path.expanduser(os.path.join(LLVM_ROOT, 'lli'))
LLVM_COMPILER=os.path.expanduser(os.path.join(LLVM_ROOT, 'llc'))
-
+COFFEESCRIPT = path_from_root('tools', 'eliminator', 'node_modules', 'coffee-script', 'bin', 'coffee')
+
+EMSCRIPTEN = path_from_root('emscripten.py')
+DEMANGLER = path_from_root('third_party', 'demangler.py')
+NAMESPACER = path_from_root('tools', 'namespacer.py')
+EMMAKEN = path_from_root('tools', 'emmaken.py')
+AUTODEBUGGER = path_from_root('tools', 'autodebugger.py')
+DFE = path_from_root('tools', 'dead_function_eliminator.py')
BINDINGS_GENERATOR = path_from_root('tools', 'bindings_generator.py')
EXEC_LLVM = path_from_root('tools', 'exec_llvm.py')
+VARIABLE_ELIMINATOR = path_from_root('tools', 'eliminator', 'eliminator.coffee')
# Additional compiler options
@@ -41,6 +49,8 @@ if USE_EMSDK:
'-I' + path_from_root('system', 'include', 'gfx'),
'-I' + path_from_root('system', 'include', 'net'),
'-I' + path_from_root('system', 'include', 'SDL'),
+] + [
+ '-U__APPLE__'
]
# Engine tweaks
@@ -196,3 +206,126 @@ def read_auto_optimize_data(filename):
'overflows_lines': overflows_lines
}
+# Settings
+
+class Dummy: pass
+
+Settings = Dummy() # A global singleton. Not pretty, but nicer than passing |, settings| everywhere
+
+# Building
+
+class Building:
+ COMPILER = CLANG
+ LLVM_OPTS = False
+ COMPILER_TEST_OPTS = []
+
+ @staticmethod
+ def build_library(name, build_dir, output_dir, generated_libs, configure=['./configure'], configure_args=[], make=['make'], make_args=['-j', '2'], cache=None, cache_name=None, copy_project=False):
+ ''' Build a library into a .bc file. We build the .bc file once and cache it for all our tests. (We cache in
+ memory since the test directory is destroyed and recreated for each test. Note that we cache separately
+ for different compilers) '''
+
+ if type(generated_libs) is not list: generated_libs = [generated_libs]
+
+ temp_dir = build_dir
+ if copy_project:
+ project_dir = os.path.join(temp_dir, name)
+ shutil.copytree(path_from_root('tests', name), project_dir) # Useful in debugging sometimes to comment this out
+ else:
+ project_dir = build_dir
+ try:
+ old_dir = os.getcwd()
+ except:
+ old_dir = None
+ os.chdir(project_dir)
+ env = os.environ.copy()
+ env['RANLIB'] = env['AR'] = env['CXX'] = env['CC'] = env['LIBTOOL'] = EMMAKEN
+ env['EMMAKEN_COMPILER'] = Building.COMPILER
+ env['EMSCRIPTEN_TOOLS'] = path_from_root('tools')
+ env['CFLAGS'] = env['EMMAKEN_CFLAGS'] = ' '.join(COMPILER_OPTS + Building.COMPILER_TEST_OPTS) # Normal CFLAGS is ignored by some configure's.
+ if configure: # Useful in debugging sometimes to comment this out (and the lines below up to and including the |make| call)
+ env['EMMAKEN_JUST_CONFIGURE'] = '1'
+ Popen(configure + configure_args, stdout=open(os.path.join(output_dir, 'configure'), 'w'),
+ stderr=open(os.path.join(output_dir, 'configure_err'), 'w'), env=env).communicate()[0]
+ del env['EMMAKEN_JUST_CONFIGURE']
+ Popen(make + make_args, stdout=open(os.path.join(output_dir, 'make'), 'w'),
+ stderr=open(os.path.join(output_dir, 'make_err'), 'w'), env=env).communicate()[0]
+ bc_file = os.path.join(project_dir, 'bc.bc')
+ Building.link(map(lambda lib: os.path.join(project_dir, lib), generated_libs), bc_file)
+ if cache is not None:
+ cache[cache_name] = open(bc_file, 'rb').read()
+ if old_dir:
+ os.chdir(old_dir)
+ return bc_file
+
+ @staticmethod
+ def link(files, target):
+ output = Popen([LLVM_LINK] + files + ['-o', target], stdout=PIPE, stderr=STDOUT).communicate()[0]
+ assert not os.path.exists(target) or output is None or 'Could not open input file' not in output, 'Linking error: ' + output
+
+ # Emscripten optimizations that we run on the .ll file
+ @staticmethod
+ def ll_opts(filename):
+ # Remove target info. This helps LLVM opts, if we run them later
+ cleaned = filter(lambda line: not line.startswith('target datalayout = ') and not line.startswith('target triple = '),
+ open(filename + '.o.ll', 'r').readlines())
+ os.unlink(filename + '.o.ll')
+ open(filename + '.o.ll.orig', 'w').write(''.join(cleaned))
+
+ output = Popen(['python', DFE, filename + '.o.ll.orig', filename + '.o.ll'], stdout=PIPE, stderr=STDOUT).communicate()[0]
+ assert os.path.exists(filename + '.o.ll'), 'Failed to run ll optimizations'
+
+ # Optional LLVM optimizations
+ @staticmethod
+ def llvm_opts(filename):
+ if Building.LLVM_OPTS:
+ shutil.move(filename + '.o', filename + '.o.pre')
+ output = Popen([LLVM_OPT, filename + '.o.pre'] + LLVM_OPT_OPTS + ['-o=' + filename + '.o'], stdout=PIPE, stderr=STDOUT).communicate()[0]
+ assert os.path.exists(filename + '.o'), 'Failed to run llvm optimizations: ' + output
+
+ @staticmethod
+ def llvm_dis(filename):
+ # LLVM binary ==> LLVM assembly
+ try:
+ os.remove(filename + '.o.ll')
+ except:
+ pass
+ output = Popen([LLVM_DIS, filename + '.o'] + LLVM_DIS_OPTS + ['-o=' + filename + '.o.ll'], stdout=PIPE, stderr=STDOUT).communicate()[0]
+ assert os.path.exists(filename + '.o.ll'), 'Could not create .ll file: ' + output
+
+ @staticmethod
+ def llvm_as(source, target):
+ # LLVM assembly ==> LLVM binary
+ try:
+ os.remove(target)
+ except:
+ pass
+ output = Popen([LLVM_AS, source, '-o=' + target], stdout=PIPE, stderr=STDOUT).communicate()[0]
+ assert os.path.exists(target), 'Could not create bc file: ' + output
+
+ @staticmethod
+ def emscripten(filename, output_processor=None, append_ext=True, extra_args=[]):
+ # Add some headers by default. TODO: remove manually adding these in each test
+ if '-H' not in extra_args:
+ extra_args += ['-H', 'libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/langinfo.h,libc/time.h']
+
+ # Run Emscripten
+ exported_settings = {}
+ for setting in ['QUANTUM_SIZE', 'RELOOP', 'OPTIMIZE', 'ASSERTIONS', 'USE_TYPED_ARRAYS', 'SAFE_HEAP', 'CHECK_OVERFLOWS', 'CORRECT_OVERFLOWS', 'CORRECT_SIGNS', 'CHECK_SIGNS', 'CORRECT_OVERFLOWS_LINES', 'CORRECT_SIGNS_LINES', 'CORRECT_ROUNDINGS', 'CORRECT_ROUNDINGS_LINES', 'INVOKE_RUN', 'SAFE_HEAP_LINES', 'INIT_STACK', 'AUTO_OPTIMIZE', 'EXPORTED_FUNCTIONS', 'EXPORTED_GLOBALS', 'BUILD_AS_SHARED_LIB', 'INCLUDE_FULL_LIBRARY', 'RUNTIME_TYPE_INFO', 'DISABLE_EXCEPTION_CATCHING', 'TOTAL_MEMORY', 'FAST_MEMORY', 'EXCEPTION_DEBUG', 'PROFILE']:
+ try:
+ value = eval('Settings.' + setting)
+ if value is not None:
+ exported_settings[setting] = value
+ except:
+ pass
+ settings = ['-s %s=%s' % (k, json.dumps(v)) for k, v in exported_settings.items()]
+ compiler_output = timeout_run(Popen(['python', EMSCRIPTEN, filename + ('.o.ll' if append_ext else ''), '-o', filename + '.o.js'] + settings + extra_args, stdout=PIPE, stderr=STDOUT), TIMEOUT, 'Compiling')
+ #print compiler_output
+
+ # Detect compilation crashes and errors
+ if compiler_output is not None and 'Traceback' in compiler_output and 'in test_' in compiler_output: print compiler_output; assert 0
+ assert os.path.exists(filename + '.o.js') and len(open(filename + '.o.js', 'r').read()) > 0, 'Emscripten failed to generate .js: ' + str(compiler_output)
+
+ if output_processor is not None:
+ output_processor(open(filename + '.o.js').read())
+