diff options
51 files changed, 632 insertions, 143 deletions
@@ -94,4 +94,5 @@ a license to everyone to use it as detailed in LICENSE.) * Pin Zhang <zhangpin04@gmail.com> * Nick Bray <ncbray@chromium.org> (copyright owned by Google, Inc.) * Aidan Hobson Sayers <aidanhs@cantab.net> +* Charlie Birks <admin@daftgames.net> @@ -1577,6 +1577,35 @@ try: js_transform_tempfiles = [final] + if memory_init_file: + if shared.Settings.USE_TYPED_ARRAYS != 2: + if type(memory_init_file) == int: logging.warning('memory init file requires typed arrays mode 2') + else: + memfile = target + '.mem' + shared.try_delete(memfile) + def repl(m): + # handle chunking of the memory initializer + s = re.sub('[\[\]\n\(\)\. ]', '', m.groups(0)[0]) + s = s.replace('concat', ',') + if s[-1] == ',': s = s[:-1] + open(memfile, 'wb').write(''.join(map(lambda x: chr(int(x or '0')), s.split(',')))) + if DEBUG: + # Copy into temp dir as well, so can be run there too + temp_memfile = os.path.join(shared.EMSCRIPTEN_TEMP_DIR, os.path.basename(memfile)) + if os.path.abspath(memfile) != os.path.abspath(memfile): + shutil.copyfile(memfile, temp_memfile) + return 'loadMemoryInitializer("%s");' % os.path.basename(memfile) + src = re.sub(shared.JS.memory_initializer_pattern, repl, open(final).read(), count=1) + open(final + '.mem.js', 'w').write(src) + final += '.mem.js' + js_transform_tempfiles[-1] = final # simple text substitution preserves comment line number mappings + if DEBUG: + if os.path.exists(memfile): + save_intermediate('meminit') + logging.debug('wrote memory initialization to %s' % memfile) + else: + logging.debug('did not see memory initialization') + # It is useful to run several js optimizer passes together, to save on unneeded unparsing/reparsing js_optimizer_queue = [] js_optimizer_extra_info = {} @@ -1654,35 +1683,6 @@ try: src = re.sub(r'\n+[ \n]*\n+', '\n', src) open(final, 'w').write(src) - if memory_init_file: - if shared.Settings.USE_TYPED_ARRAYS != 2: - if type(memory_init_file) == int: logging.warning('memory init file requires typed arrays mode 2') - else: - memfile = target + '.mem' - shared.try_delete(memfile) - def repl(m): - # handle chunking of the memory initializer - s = re.sub('[\[\]\n\(\)\. ]', '', m.groups(0)[0]) - s = s.replace('concat', ',') - if s[-1] == ',': s = s[:-1] - open(memfile, 'wb').write(''.join(map(lambda x: chr(int(x or '0')), s.split(',')))) - if DEBUG: - # Copy into temp dir as well, so can be run there too - temp_memfile = os.path.join(shared.EMSCRIPTEN_TEMP_DIR, os.path.basename(memfile)) - if os.path.abspath(memfile) != os.path.abspath(memfile): - shutil.copyfile(memfile, temp_memfile) - return 'loadMemoryInitializer("%s");' % os.path.basename(memfile) - src = re.sub(shared.JS.memory_initializer_pattern, repl, src, count=1) - open(final + '.mem.js', 'w').write(src) - final += '.mem.js' - js_transform_tempfiles[-1] = final # simple text substitution preserves comment line number mappings - if DEBUG: - if os.path.exists(memfile): - save_intermediate('meminit') - logging.debug('wrote memory initialization to %s' % memfile) - else: - logging.debug('did not see memory initialization') - def generate_source_map(map_file_base_name, offset=0): jsrun.run_js(shared.path_from_root('tools', 'source-maps', 'sourcemapper.js'), shared.NODE_JS, js_transform_tempfiles + diff --git a/src/analyzer.js b/src/analyzer.js index 2a7d64f5..b20dedff 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -281,6 +281,14 @@ function analyzer(data, sidePass) { Array.prototype.splice.apply(params, [i, 1].concat(toAdd)); i += toAdd.length; continue; + } else if (param.intertype == 'structvalue') { + // 'flatten' out the struct into scalars + var toAdd = param.params; + toAdd.forEach(function(param) { + param.byval = 0; + }); + Array.prototype.splice.apply(params, [i, 1].concat(toAdd)); + continue; // do not increment i; proceed to process the new params } i++; } diff --git a/src/jsifier.js b/src/jsifier.js index 179a910a..7273f54c 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -23,7 +23,7 @@ function JSify(data, functionsOnly, givenFunctions) { var mainPass = !functionsOnly; if (mainPass) { - var shellFile = SHELL_FILE ? SHELL_FILE : (BUILD_AS_SHARED_LIB ? 'shell_sharedlib.js' : 'shell.js'); + var shellFile = SHELL_FILE ? SHELL_FILE : (BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'shell_sharedlib.js' : 'shell.js'); if (phase == 'pre') { // We will start to print out the data, but must do so carefully - we are @@ -47,10 +47,11 @@ function JSify(data, functionsOnly, givenFunctions) { var shellParts = read(shellFile).split('{{BODY}}'); print(processMacros(preprocess(shellParts[0]))); - var preFile = BUILD_AS_SHARED_LIB ? 'preamble_sharedlib.js' : 'preamble.js'; + var preFile = BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'preamble_sharedlib.js' : 'preamble.js'; var pre = processMacros(preprocess(read(preFile).replace('{{RUNTIME}}', getRuntime()))); print(pre); + // Populate implementedFunctions. Note that this is before types, and will be updated later. data.unparsedFunctions.forEach(function(func) { Functions.implementedFunctions[func.ident] = Functions.getSignature(func.returnType, func.params.map(function(param) { return param.type })); }); @@ -80,7 +81,7 @@ function JSify(data, functionsOnly, givenFunctions) { if (phase == 'pre') { var libFuncsToInclude; if (INCLUDE_FULL_LIBRARY) { - assert(!BUILD_AS_SHARED_LIB, 'Cannot have both INCLUDE_FULL_LIBRARY and BUILD_AS_SHARED_LIB set.') + assert(!(BUILD_AS_SHARED_LIB || SIDE_MODULE), 'Cannot have both INCLUDE_FULL_LIBRARY and BUILD_AS_SHARED_LIB/SIDE_MODULE set.') libFuncsToInclude = []; for (var key in LibraryManager.library) { if (!key.match(/__(deps|postset|inline|asm|sig)$/)) { @@ -454,7 +455,7 @@ function JSify(data, functionsOnly, givenFunctions) { var postsetId = ident + '__postset'; var postset = LibraryManager.library[postsetId]; - if (postset && !addedLibraryItems[postsetId]) { + if (postset && !addedLibraryItems[postsetId] && !SIDE_MODULE) { addedLibraryItems[postsetId] = true; ret.push({ intertype: 'GlobalVariablePostSet', @@ -497,6 +498,7 @@ function JSify(data, functionsOnly, givenFunctions) { Functions.libraryFunctions[ident.substr(1)] = 2; } } + if (SIDE_MODULE) return ';'; // we import into the side module js library stuff from the outside parent if ((!ASM_JS || phase == 'pre') && (EXPORT_ALL || (ident in EXPORTED_FUNCTIONS))) { contentText += '\nModule["' + ident + '"] = ' + ident + ';'; @@ -1835,7 +1837,7 @@ function JSify(data, functionsOnly, givenFunctions) { print('Runtime.typeInfo = ' + JSON.stringify(Types.types)); print('Runtime.structMetadata = ' + JSON.stringify(Types.structMetadata)); } - var postFile = BUILD_AS_SHARED_LIB ? 'postamble_sharedlib.js' : 'postamble.js'; + var postFile = BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'postamble_sharedlib.js' : 'postamble.js'; var postParts = processMacros(preprocess(read(postFile))).split('{{GLOBAL_VARS}}'); print(postParts[0]); @@ -1871,6 +1873,12 @@ function JSify(data, functionsOnly, givenFunctions) { // Data if (mainPass) { + if (phase == 'pre') { + // types have been parsed, so we can figure out function signatures (which can use types) + data.unparsedFunctions.forEach(function(func) { + Functions.implementedFunctions[func.ident] = Functions.getSignature(func.returnType, func.params.map(function(param) { return param.type })); + }); + } substrate.addItems(data.functionStubs, 'FunctionStub'); assert(data.functions.length == 0); } else { diff --git a/src/library.js b/src/library.js index 9e78db13..3ba2f56b 100644 --- a/src/library.js +++ b/src/library.js @@ -6808,24 +6808,38 @@ LibraryManager.library = { _pthread_once.seen[ptr] = 1; }, + $PTHREAD_SPECIFIC: {}, + $PTHREAD_SPECIFIC_NEXT_KEY: 1, + pthread_key_create__deps: ['$PTHREAD_SPECIFIC', '$PTHREAD_SPECIFIC_NEXT_KEY', '$ERRNO_CODES'], pthread_key_create: function(key, destructor) { - if (!_pthread_key_create.keys) _pthread_key_create.keys = {}; + if (key == 0) { + return ERRNO_CODES.EINVAL; + } + {{{ makeSetValue('key', '0', 'PTHREAD_SPECIFIC_NEXT_KEY', 'i32*') }}} // values start at 0 - _pthread_key_create.keys[key] = 0; + PTHREAD_SPECIFIC[PTHREAD_SPECIFIC_NEXT_KEY] = 0; + PTHREAD_SPECIFIC_NEXT_KEY++; + return 0; }, + pthread_getspecific__deps: ['$PTHREAD_SPECIFIC'], pthread_getspecific: function(key) { - return _pthread_key_create.keys[key] || 0; + return PTHREAD_SPECIFIC[key] || 0; }, + pthread_setspecific__deps: ['$PTHREAD_SPECIFIC', '$ERRNO_CODES'], pthread_setspecific: function(key, value) { - _pthread_key_create.keys[key] = value; + if (value == 0) { + return ERRNO_CODES.EINVAL; + } + PTHREAD_SPECIFIC[key] = value; + return 0; }, - pthread_key_delete: ['$ERRNO_CODES'], + pthread_key_delete__deps: ['$PTHREAD_SPECIFIC', '$ERRNO_CODES'], pthread_key_delete: function(key) { - if (_pthread_key_create.keys[key]) { - delete _pthread_key_create.keys[key]; + if (key in PTHREAD_SPECIFIC) { + delete PTHREAD_SPECIFIC[key]; return 0; } return ERRNO_CODES.EINVAL; diff --git a/src/library_browser.js b/src/library_browser.js index 558c9a59..591a3c11 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -821,6 +821,13 @@ mergeInto(LibraryManager.library, { emscripten_set_canvas_size: function(width, height) { Browser.setCanvasSize(width, height); }, + + emscripten_get_canvas_size: function(width, height, isFullscreen) { + var canvas = Module['canvas']; + {{{ makeSetValue('width', '0', 'canvas.width', 'i32') }}}; + {{{ makeSetValue('height', '0', 'canvas.height', 'i32') }}}; + {{{ makeSetValue('isFullscreen', '0', 'Browser.isFullScreen ? 1 : 0', 'i32') }}}; + }, emscripten_get_now: function() { if (ENVIRONMENT_IS_NODE) { diff --git a/src/library_fs.js b/src/library_fs.js index e1397356..9c8223ab 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -802,6 +802,90 @@ mergeInto(LibraryManager.library, { } }, + indexedDB: function() { + return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; + }, + + DB_NAME: function() { + return 'EM_FS_' + window.location.pathname; + }, + DB_VERSION: 20, + DB_STORE_NAME: 'FILE_DATA', + + // asynchronously saves a list of files to an IndexedDB. The DB will be created if not already existing. + saveFilesToDB: function(paths, onload, onerror) { + onload = onload || function(){}; + onerror = onerror || function(){}; + var indexedDB = FS.indexedDB(); + try { + var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); + } catch (e) { + return onerror(e); + } + openRequest.onupgradeneeded = function() { + console.log('creating db'); + var db = openRequest.result; + db.createObjectStore(FS.DB_STORE_NAME); + }; + openRequest.onsuccess = function() { + var db = openRequest.result; + var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite'); + var files = transaction.objectStore(FS.DB_STORE_NAME); + var ok = 0, fail = 0, total = paths.length; + function finish() { + if (fail == 0) onload(); else onerror(); + } + paths.forEach(function(path) { + var putRequest = files.put(FS.analyzePath(path).object.contents, path); + putRequest.onsuccess = function() { ok++; if (ok + fail == total) finish() }; + putRequest.onerror = function() { fail++; if (ok + fail == total) finish() }; + }); + transaction.onerror = onerror; + }; + openRequest.onerror = onerror; + }, + + // asychronously loads a file from IndexedDB. + loadFilesFromDB: function(paths, onload, onerror) { + onload = onload || function(){}; + onerror = onerror || function(){}; + var indexedDB = FS.indexedDB(); + try { + var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); + } catch (e) { + return onerror(e); + } + openRequest.onupgradeneeded = onerror; // no database to load from + openRequest.onsuccess = function() { + var db = openRequest.result; + try { + var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly'); + } catch(e) { + onerror(e); + return; + } + var files = transaction.objectStore(FS.DB_STORE_NAME); + var ok = 0, fail = 0, total = paths.length; + function finish() { + if (fail == 0) onload(); else onerror(); + } + paths.forEach(function(path) { + var getRequest = files.get(path); + getRequest.onsuccess = function() { + if (FS.analyzePath(path).exists) { + FS.unlink(path); + } + FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true); + ok++; + if (ok + fail == total) finish(); + }; + getRequest.onerror = function() { fail++; if (ok + fail == total) finish() }; + }); + transaction.onerror = onerror; + }; + openRequest.onerror = onerror; + }, + // // general // diff --git a/src/library_memfs.js b/src/library_memfs.js index 63326c42..354f5e95 100644 --- a/src/library_memfs.js +++ b/src/library_memfs.js @@ -2,17 +2,13 @@ mergeInto(LibraryManager.library, { $MEMFS__deps: ['$FS'], $MEMFS: { // content modes - CONTENT_OWNING: 1, // contains a subarray into the heap, and we own it - need to free() when no longer needed + CONTENT_OWNING: 1, // contains a subarray into the heap, and we own it, without copying (note: someone else needs to free() it, if that is necessary) CONTENT_FLEXIBLE: 2, // has been modified or never set to anything, and is a flexible js array that can grow/shrink CONTENT_FIXED: 3, // contains some fixed-size content written into it, in a typed array ensureFlexible: function(node) { if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) { var contents = node.contents; node.contents = Array.prototype.slice.call(contents); - if (node.contentMode === MEMFS.CONTENT_OWNING) { - assert(contents.byteOffset); - Module['_free'](contents.byteOffset); - } node.contentMode = MEMFS.CONTENT_FLEXIBLE; } }, diff --git a/src/library_openal.js b/src/library_openal.js index 7f5d5df6..dea986f3 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -244,7 +244,6 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alDeleteSources called without a valid context"); #endif - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } for (var i = 0; i < count; ++i) { @@ -258,7 +257,6 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alGenSources called without a valid context"); #endif - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } for (var i = 0; i < count; ++i) { @@ -318,7 +316,6 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alSourcei called without a valid context"); #endif - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } var src = AL.currentContext.src[source - 1]; @@ -387,7 +384,6 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alSourcef called without a valid context"); #endif - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } var src = AL.currentContext.src[source - 1]; @@ -440,7 +436,6 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alSource3f called without a valid context"); #endif - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } var src = AL.currentContext.src[source - 1]; @@ -481,7 +476,6 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alSourceQueueBuffers called without a valid context"); #endif - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } var src = AL.currentContext.src[source - 1]; @@ -518,7 +512,6 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alSourceUnqueueBuffers called without a valid context"); #endif - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } var src = AL.currentContext.src[source - 1]; @@ -557,7 +550,6 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alDeleteBuffers called without a valid context"); #endif - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } if (count > AL.currentContext.buf.length) { @@ -601,7 +593,6 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alGenBuffers called without a valid context"); #endif - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } for (var i = 0; i < count; ++i) { @@ -615,7 +606,6 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alBufferData called without a valid context"); #endif - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } if (buffer > AL.currentContext.buf.length) { @@ -680,7 +670,6 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alSourcePlay called without a valid context"); #endif - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } var src = AL.currentContext.src[source - 1]; @@ -700,7 +689,6 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alSourceStop called without a valid context"); #endif - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } var src = AL.currentContext.src[source - 1]; @@ -720,7 +708,6 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alSourcePause called without a valid context"); #endif - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } var src = AL.currentContext.src[source - 1]; @@ -740,7 +727,6 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alGetSourcei called without a valid context"); #endif - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } var src = AL.currentContext.src[source - 1]; @@ -804,7 +790,6 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alGetSourcef called without a valid context"); #endif - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } var src = AL.currentContext.src[source - 1]; @@ -865,7 +850,6 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alListenerfv called without a valid context"); #endif - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } switch (param) { diff --git a/src/library_sdl.js b/src/library_sdl.js index 7b1837e8..d6cb6d18 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -567,7 +567,12 @@ var LibrarySDL = { switch (event.type) { case 'keydown': case 'keyup': { var down = event.type === 'keydown'; - var code = SDL.keyCodes[event.keyCode] || event.keyCode; + var code = event.keyCode; + if (code >= 65 && code <= 90) { + code += 32; // make lowercase for SDL + } else { + code = SDL.keyCodes[event.keyCode] || event.keyCode; + } {{{ makeSetValue('SDL.keyboardState', 'code', 'down', 'i8') }}}; // TODO: lmeta, rmeta, numlock, capslock, KMOD_MODE, KMOD_RESERVED diff --git a/src/parseTools.js b/src/parseTools.js index 046dac1b..66354dca 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -430,6 +430,8 @@ function parseParamTokens(params) { ret.push(parseLLVMFunctionCall(segment)); } else if (segment[1].text === 'blockaddress') { ret.push(parseBlockAddress(segment)); + } else if (segment[1].type && segment[1].type == '{') { + ret.push(parseLLVMSegment(segment)); } else { if (segment[2] && segment[2].text == 'to') { // part of bitcast params segment = segment.slice(0, 2); diff --git a/src/settings.js b/src/settings.js index cb64bfd9..03b4ed64 100644 --- a/src/settings.js +++ b/src/settings.js @@ -6,6 +6,11 @@ // emcc -s OPTION1=VALUE1 -s OPTION2=VALUE2 [..other stuff..] // // See https://github.com/kripken/emscripten/wiki/Code-Generation-Modes/ +// +// Note that the values here are the defaults in -O0, that is, unoptimized +// mode. See apply_opt_level in tools/shared.py for how -O1,2,3 affect these +// flags. +// // Tuning var QUANTUM_SIZE = 4; // This is the size of an individual field in a structure. 1 would @@ -131,6 +136,16 @@ var OUTLINING_LIMIT = 0; // A function size above which we try to automatically // large functions (JS engines often compile them very slowly, // compile them with lower optimizations, or do not optimize them // at all). If 0, we do not perform outlining at all. + // To see which funcs are large, you can inspect the source + // in a debug build (-g2 or -g for example), and can run + // tools/find_bigfuncs.py on that to get a sorted list by size. + // Another possibility is to look in the web console in firefox, + // which will note slowly-compiling functions. + // You will probably want to experiment with various values to + // see the impact on compilation time, code size and runtime + // throughput. It is hard to say what values to start testing + // with, but something around 20,000 to 100,000 might make sense. + // (The unit size is number of AST nodes.) // Generated code debugging options var SAFE_HEAP = 0; // Check each write to the heap, for example, this will give a clear @@ -380,9 +395,7 @@ var HEADLESS = 0; // If 1, will include shim code that tries to 'fake' a browser var BENCHMARK = 0; // If 1, will just time how long main() takes to execute, and not // print out anything at all whatsoever. This is useful for benchmarking. -var ASM_JS = 0; // If 1, generate code in asm.js format. XXX This is highly experimental, - // and will not work on most codebases yet. It is NOT recommended that you - // try this yet. +var ASM_JS = 0; // If 1, generate code in asm.js format. var PGO = 0; // Enables profile-guided optimization in the form of runtime checks for // which functions are actually called. Emits a list during shutdown that you diff --git a/src/shell.html b/src/shell.html index 22bc9de9..ff5f6e35 100644 --- a/src/shell.html +++ b/src/shell.html @@ -87,6 +87,6 @@ }; Module.setStatus('Downloading...'); </script> - <script type='text/javascript'>{{{ SCRIPT_CODE }}}</script> + <script async type='text/javascript'>{{{ SCRIPT_CODE }}}</script> </body> </html> diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h index 1ed4c721..1b9a8f25 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -170,6 +170,12 @@ void emscripten_hide_mouse(); void emscripten_set_canvas_size(int width, int height); /* + * Get the current pixel width and height of the <canvas> element + * as well as whether the canvas is fullscreen or not. + */ +void emscripten_get_canvas_size(int *width, int *height, int *isFullscreen); + +/* * Returns the highest-precision representation of the * current time that the browser provides. This uses either * Date.now or performance.now. The result is *not* an diff --git a/tests/aniso.c b/tests/aniso.c index f210e5a5..e8d7bd3f 100644 --- a/tests/aniso.c +++ b/tests/aniso.c @@ -27,6 +27,7 @@ REDISTRIBUTION OF THIS SOFTWARE. #include "SDL/SDL_opengl.h" #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <assert.h> diff --git a/tests/cases/callwithstructural64_ta2.ll b/tests/cases/callwithstructural64_ta2.ll new file mode 100644 index 00000000..d16b0e87 --- /dev/null +++ b/tests/cases/callwithstructural64_ta2.ll @@ -0,0 +1,29 @@ +; ModuleID = 'foo.bc' +target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:32" +target triple = "le32-unknown-nacl" + +%ac = type { i8*, i64 } + +@0 = constant [9 x i8] c"func %s\0A\00" +@1 = constant [4 x i8] c"foo\00" + +declare void @llvm.trap() noreturn nounwind + +define void @direct(%ac) { +entry: + %str = alloca %ac + store %ac %0, %ac* %str + %1 = getelementptr inbounds %ac* %str, i32 0, i32 0 + %2 = load i8** %1 + call void (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @0, i32 0, i32 0), i8* %2) + ret void +} + +declare void @printf(i8*, ...) + +define i32 @main() { +entry: + call void @direct(%ac { i8* getelementptr inbounds ([4 x i8]* @1, i32 0, i32 0), i64 3 }) + ret i32 0 +} + diff --git a/tests/cases/callwithstructural64_ta2.txt b/tests/cases/callwithstructural64_ta2.txt new file mode 100644 index 00000000..51a6ac7c --- /dev/null +++ b/tests/cases/callwithstructural64_ta2.txt @@ -0,0 +1 @@ +func foo diff --git a/tests/cases/callwithstructural_ta2.ll b/tests/cases/callwithstructural_ta2.ll new file mode 100644 index 00000000..bc6f852a --- /dev/null +++ b/tests/cases/callwithstructural_ta2.ll @@ -0,0 +1,29 @@ +; ModuleID = 'foo.bc' +target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:32" +target triple = "le32-unknown-nacl" + +%ac = type { i8*, i32 } + +@0 = constant [9 x i8] c"func %s\0A\00" +@1 = constant [4 x i8] c"foo\00" + +declare void @llvm.trap() noreturn nounwind + +define void @direct(%ac) { +entry: + %str = alloca %ac + store %ac %0, %ac* %str + %1 = getelementptr inbounds %ac* %str, i32 0, i32 0 + %2 = load i8** %1 + call void (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @0, i32 0, i32 0), i8* %2) + ret void +} + +declare void @printf(i8*, ...) + +define i32 @main() { +entry: + call void @direct(%ac { i8* getelementptr inbounds ([4 x i8]* @1, i32 0, i32 0), i32 3 }) + ret i32 0 +} + diff --git a/tests/cases/callwithstructural_ta2.txt b/tests/cases/callwithstructural_ta2.txt new file mode 100644 index 00000000..51a6ac7c --- /dev/null +++ b/tests/cases/callwithstructural_ta2.txt @@ -0,0 +1 @@ +func foo diff --git a/tests/cases/structinparam.ll b/tests/cases/structinparam.ll new file mode 100644 index 00000000..d81f5e67 --- /dev/null +++ b/tests/cases/structinparam.ll @@ -0,0 +1,36 @@ +; ModuleID = 'min.bc' +target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:32" +target triple = "le32-unknown-nacl" + +%ac = type { i8*, i32 } + +@0 = constant [9 x i8] c"func %s\0A\00" +@1 = constant [4 x i8] c"foo\00" +@2 = constant [9 x i8] c"main %s\0A\00" + +declare void @llvm.trap() noreturn nounwind + +define void @direct(%ac) { +entry: + %str = alloca %ac + store %ac %0, %ac* %str + %1 = getelementptr inbounds %ac* %str, i32 0, i32 0 + %2 = load i8** %1 + call void (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @0, i32 0, i32 0), i8* %2) + ret void +} + +declare void @printf(i8*, ...) + +define i32 @main() { +entry: + %str = alloca %ac + store %ac { i8* getelementptr inbounds ([4 x i8]* @1, i32 0, i32 0), i32 3 }, %ac* %str + %0 = getelementptr inbounds %ac* %str, i32 0, i32 0 + %1 = load i8** %0 + call void (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @2, i32 0, i32 0), i8* %1) + %2 = load %ac* %str + call void @direct(%ac %2) + ret i32 0 +} + diff --git a/tests/cases/structinparam.txt b/tests/cases/structinparam.txt new file mode 100644 index 00000000..785191e7 --- /dev/null +++ b/tests/cases/structinparam.txt @@ -0,0 +1,2 @@ +main foo +func foo diff --git a/tests/cubegeom_color.c b/tests/cubegeom_color.c index 7d384324..ff30e1a9 100644 --- a/tests/cubegeom_color.c +++ b/tests/cubegeom_color.c @@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE. #endif #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <assert.h> diff --git a/tests/cubegeom_pre.c b/tests/cubegeom_pre.c index fb1a5e02..40b03cf7 100644 --- a/tests/cubegeom_pre.c +++ b/tests/cubegeom_pre.c @@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE. #endif #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <assert.h> diff --git a/tests/cubegeom_pre2.c b/tests/cubegeom_pre2.c index 51961bf7..df04ae31 100644 --- a/tests/cubegeom_pre2.c +++ b/tests/cubegeom_pre2.c @@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE. #endif #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <assert.h> diff --git a/tests/cubegeom_pre2_vao.c b/tests/cubegeom_pre2_vao.c index cba262ff..733c8fc6 100644 --- a/tests/cubegeom_pre2_vao.c +++ b/tests/cubegeom_pre2_vao.c @@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE. #endif #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <assert.h> diff --git a/tests/cubegeom_pre2_vao2.c b/tests/cubegeom_pre2_vao2.c index 3784006c..69096833 100644 --- a/tests/cubegeom_pre2_vao2.c +++ b/tests/cubegeom_pre2_vao2.c @@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE. #endif #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <assert.h> diff --git a/tests/cubegeom_pre3.c b/tests/cubegeom_pre3.c index 4ba2a779..ceaa757e 100644 --- a/tests/cubegeom_pre3.c +++ b/tests/cubegeom_pre3.c @@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE. #endif #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <assert.h> diff --git a/tests/cubegeom_pre_vao.c b/tests/cubegeom_pre_vao.c index cae68cfc..8c598143 100644 --- a/tests/cubegeom_pre_vao.c +++ b/tests/cubegeom_pre_vao.c @@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE. #endif #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <assert.h> diff --git a/tests/cubegeom_texturematrix.c b/tests/cubegeom_texturematrix.c index 99a4469e..abb667eb 100644 --- a/tests/cubegeom_texturematrix.c +++ b/tests/cubegeom_texturematrix.c @@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE. #endif #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <assert.h> diff --git a/tests/file_db.cpp b/tests/file_db.cpp new file mode 100644 index 00000000..ebb3bb30 --- /dev/null +++ b/tests/file_db.cpp @@ -0,0 +1,47 @@ +#include <stdio.h> +#include <emscripten.h> + +void later(void *) {} + +int main() { +#if FIRST + FILE *f = fopen("waka.txt", "w"); + fputc('a', f); + fputc('z', f); + fclose(f); + + EM_ASM( + FS.saveFilesToDB(['waka.txt', 'moar.txt'], function() { + Module.print('save ok'); + var xhr = new XMLHttpRequest(); + xhr.open('GET', 'http://localhost:8888/report_result?1'); + xhr.send(); + setTimeout(function() { window.close() }, 1000); + }, function(e) { + abort('saving should succeed ' + e); + }); + ); +#else + EM_ASM( + FS.loadFilesFromDB(['waka.txt', 'moar.txt'], function() { + function stringy(arr) { + return Array.prototype.map.call(arr, function(x) { return String.fromCharCode(x) }).join(''); + } + assert(stringy(FS.analyzePath('waka.txt').object.contents) == 'az'); + var secret = stringy(FS.analyzePath('moar.txt').object.contents); + Module.print('load: ' + secret); + var xhr = new XMLHttpRequest(); + xhr.open('GET', 'http://localhost:8888/report_result?' + secret); + xhr.send(); + setTimeout(function() { window.close() }, 1000); + }, function() { + abort('loading should succeed'); + }); + ); +#endif + + emscripten_async_call(later, NULL, 100); // keep runtime alive + + return 0; +} + diff --git a/tests/float_tex.cpp b/tests/float_tex.cpp index 61531124..c40ff786 100644 --- a/tests/float_tex.cpp +++ b/tests/float_tex.cpp @@ -113,7 +113,7 @@ static void gl_init(void) { /* Store the vertices in a vertex buffer object (VBO) */ glGenBuffers(1, &indicesVBO); glBindBuffer(GL_ARRAY_BUFFER, indicesVBO); - glBufferData(GL_ARRAY_BUFFER, elements.size() * sizeof(uint), &elements[0], GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, elements.size() * sizeof(float), &elements[0], GL_STATIC_DRAW); /* Get the locations of the uniforms so we can access them */ nodeSamplerLocation = glGetUniformLocation(program, "nodeInfo"); glBindAttribLocation(program, 0, "indices"); diff --git a/tests/gl_matrix_identity.c b/tests/gl_matrix_identity.c index 98b1c21f..9f990a77 100644 --- a/tests/gl_matrix_identity.c +++ b/tests/gl_matrix_identity.c @@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE. #endif #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <assert.h> diff --git a/tests/glshaderinfo.cpp b/tests/glshaderinfo.cpp index 8ec393a8..56da2414 100644 --- a/tests/glshaderinfo.cpp +++ b/tests/glshaderinfo.cpp @@ -1,8 +1,6 @@ #define GL_GLEXT_PROTOTYPES #define EGL_EGLEXT_PROTOTYPES -#define _GNU_SOURCE - #include <math.h> #include <stdlib.h> #include <stdio.h> diff --git a/tests/http.h b/tests/http.h index 7eff7013..d20f012b 100644 --- a/tests/http.h +++ b/tests/http.h @@ -8,6 +8,7 @@ #ifndef __HTTP_H__ #define __HTTP_H__ +#include <stdarg.h> #include <string> diff --git a/tests/pthread/specific.c b/tests/pthread/specific.c new file mode 100644 index 00000000..914884e7 --- /dev/null +++ b/tests/pthread/specific.c @@ -0,0 +1,60 @@ +#include <stdio.h> +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +static void destr_function(void *arg) +{ + // Not implemented yet in Emscripten +} + +int main(void) +{ + pthread_key_t key = 0; + int rv; + int data = 123; + int *data2; + + assert(pthread_key_delete(key) != 0); + assert(pthread_getspecific(key) == NULL); + + rv = pthread_key_create(&key, &destr_function); + printf("pthread_key_create = %d\n", rv); + assert(rv == 0); + + assert(pthread_getspecific(key) == NULL); + + rv = pthread_setspecific(key, (void*) &data); + printf("pthread_setspecific = %d\n", rv); + assert(rv == 0); + + data2 = pthread_getspecific(key); + assert(data2 != NULL); + printf("pthread_getspecific = %d\n", *data2); + assert(*data2 == 123); + + rv = pthread_key_create(&key, &destr_function); + data2 = pthread_getspecific(key); + printf("pthread_getspecific after key recreate = %p\n", data2); + assert(data2 == NULL); + + rv = pthread_key_delete(key); + printf("pthread_key_delete = %d\n", rv); + assert(rv == 0); + + rv = pthread_key_delete(key); + printf("pthread_key_delete repeated = %d\n", rv); + assert(rv == EINVAL); + + rv = pthread_setspecific(key, NULL); + printf("pthread_setspecific for value NULL = %d\n", rv); + assert(rv == EINVAL); + + rv = pthread_key_create(&key, &destr_function); + assert(rv == 0); + rv = pthread_key_delete(key); + printf("pthread_key_delete just after created = %d\n", rv); + assert(rv == 0); + + return 0; +} diff --git a/tests/pthread/specific.c.txt b/tests/pthread/specific.c.txt new file mode 100644 index 00000000..ad122b3d --- /dev/null +++ b/tests/pthread/specific.c.txt @@ -0,0 +1,8 @@ +pthread_key_create = 0 +pthread_setspecific = 0 +pthread_getspecific = 123 +pthread_getspecific after key recreate = (nil) +pthread_key_delete = 0 +pthread_key_delete repeated = 22 +pthread_setspecific for value NULL = 22 +pthread_key_delete just after created = 0 diff --git a/tests/s3tc.c b/tests/s3tc.c index 16ee783f..5f7bee83 100644 --- a/tests/s3tc.c +++ b/tests/s3tc.c @@ -27,6 +27,7 @@ REDISTRIBUTION OF THIS SOFTWARE. #include "SDL/SDL_opengl.h" #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <assert.h> diff --git a/tests/s3tc_crunch.c b/tests/s3tc_crunch.c index 90ed02d9..c2606c8f 100644 --- a/tests/s3tc_crunch.c +++ b/tests/s3tc_crunch.c @@ -27,6 +27,7 @@ REDISTRIBUTION OF THIS SOFTWARE. #include "SDL/SDL_opengl.h" #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <assert.h> diff --git a/tests/sdl_canvas.c b/tests/sdl_canvas.c index 10044ff4..6bd659b8 100644 --- a/tests/sdl_canvas.c +++ b/tests/sdl_canvas.c @@ -1,4 +1,5 @@ #include <stdio.h> +#include <stdlib.h> #include <SDL/SDL.h> #include <SDL/SDL_ttf.h> #include <emscripten.h> @@ -43,6 +44,16 @@ int main(int argc, char **argv) { SDL_Flip(screen); SDL_LockSurface(screen); + + int width, height, isFullscreen; + emscripten_get_canvas_size(&width, &height, &isFullscreen); + + if (width != 600 && height != 450) + { + printf("error: wrong width/height\n"); + abort(); + } + int sum = 0; for (int i = 0; i < screen->h; i++) { sum += *((char*)screen->pixels + i*screen->w*4 + i*4 + 0); diff --git a/tests/sdl_headless.c b/tests/sdl_headless.c new file mode 100644 index 00000000..349c5e26 --- /dev/null +++ b/tests/sdl_headless.c @@ -0,0 +1,65 @@ +#include <stdio.h> +#include <stdlib.h> +#include <SDL/SDL.h> +#include <SDL/SDL_ttf.h> +#include <emscripten.h> + + +int main(int argc, char **argv) { +#if EMSCRIPTEN + // include GL stuff, to check that we can compile hybrid 2d/GL apps + extern void glBegin(int mode); + extern void glBindBuffer(int target, int buffer); + if (argc == 9876) { + glBegin(0); + glBindBuffer(0, 0); + } +#endif + + SDL_Init(SDL_INIT_VIDEO); + SDL_Surface *screen = SDL_SetVideoMode(600, 450, 32, SDL_HWSURFACE); + + printf("Init: %d\n", TTF_Init()); + + TTF_Font *font = TTF_OpenFont("sans-serif", 40); + printf("Font: %p\n", font); + + SDL_Color color = { 0xff, 0x99, 0x00, 0xff }; + + SDL_Surface *text = TTF_RenderText_Solid(font, "hello orange world", color); + + SDL_Color color2 = { 0xbb, 0, 0xff, 0xff }; + SDL_Surface *text2 = TTF_RenderText_Solid(font, "a second line, purple", color2); + + // render + SDL_Rect dest = { 0, 50, 0, 0 }; + SDL_BlitSurface (text, NULL, screen, NULL); + dest.y = 100; + SDL_BlitSurface (text2, NULL, screen, &dest); + + // fill stuff + SDL_Rect rect = { 200, 200, 175, 125 }; + SDL_FillRect(screen, &rect, SDL_MapRGBA(screen->format, 0x22, 0x22, 0xff, 0xff)); + + SDL_Flip(screen); + + SDL_LockSurface(screen); + + int sum = 0; + for (int i = 0; i < screen->h; i++) { + sum += *((char*)screen->pixels + i*screen->w*4 + i*4 + 0); + } + printf("Sum: %d\n", sum); + + printf("you should see two lines of text in different colors and a blue rectangle\n"); + + SDL_Quit(); + + printf("done.\n"); + + int result = sum > 3000 && sum < 5000; // varies a little on different browsers, font differences? + REPORT_RESULT(); + + return 0; +} + diff --git a/tests/sdl_image_prepare_data.c b/tests/sdl_image_prepare_data.c index d45a2e60..043ace47 100644 --- a/tests/sdl_image_prepare_data.c +++ b/tests/sdl_image_prepare_data.c @@ -58,7 +58,7 @@ int main() { printf("prepare..\n"); #define SIZE 203164 - FILE *f = open("screenshot.not", "rb"); + FILE *f = fopen("screenshot.not", "rb"); char *buffer = malloc(SIZE); fread(buffer, SIZE, 1, f); fclose(f); diff --git a/tests/sdl_pumpevents.c b/tests/sdl_pumpevents.c index 64becaad..e765d285 100644 --- a/tests/sdl_pumpevents.c +++ b/tests/sdl_pumpevents.c @@ -40,6 +40,20 @@ int loop2() return r; } +int alphakey() +{ + unsigned i; + int r = 0; + + SDL_PumpEvents(); + + const Uint8 *keys = SDL_GetKeyState(NULL); + if (keys[SDLK_a]) + r = 4; + + return r; +} + int main(int argc, char *argv[]) { SDL_Init(SDL_INIT_EVERYTHING); @@ -49,6 +63,8 @@ int main(int argc, char *argv[]) result += loop1(); emscripten_run_script("keydown(39);"); // right result += loop2(); + emscripten_run_script("keydown(65);"); // A + result += alphakey(); REPORT_RESULT(); return 0; } diff --git a/tests/test_browser.py b/tests/test_browser.py index 7c387071..32b29966 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -38,8 +38,6 @@ class browser(BrowserCore): message='You should see "hello, world!" and a colored cube.') def test_html_source_map(self): - if 'test_html_source_map' not in str(sys.argv): return self.skip('''This test -requires manual intervention; will not be run unless explicitly requested''') cpp_file = os.path.join(self.get_dir(), 'src.cpp') html_file = os.path.join(self.get_dir(), 'src.html') # browsers will try to 'guess' the corresponding original line if a @@ -64,14 +62,20 @@ requires manual intervention; will not be run unless explicitly requested''') ''') # use relative paths when calling emcc, because file:// URIs can only load # sourceContent when the maps are relative paths + try_delete(html_file) + try_delete(html_file + '.map') Popen([PYTHON, EMCC, 'src.cpp', '-o', 'src.html', '-g4'], cwd=self.get_dir()).communicate() + assert os.path.exists(html_file) + assert os.path.exists(html_file + '.map') + import webbrowser, time webbrowser.open_new('file://' + html_file) + time.sleep(1) print ''' -Set the debugger to pause on exceptions -You should see an exception thrown at src.cpp:7. -Press any key to continue.''' - raw_input() +If manually bisecting: + Check that you see src.cpp among the page sources. + Even better, add a breakpoint, e.g. on the printf, then reload, then step through and see the print (best to run with EM_SAVE_DIR=1 for the reload). +''' def build_native_lzma(self): lzma_native = path_from_root('third_party', 'lzma.js', 'lzma-native') @@ -790,6 +794,17 @@ Press any key to continue.''' def test_glut_touchevents(self): self.btest('glut_touchevents.c', '1') + def test_file_db(self): + secret = str(time.time()) + open('moar.txt', 'w').write(secret) + self.btest('file_db.cpp', '1', args=['--preload-file', 'moar.txt', '-DFIRST']) + shutil.copyfile('test.html', 'first.html') + self.btest('file_db.cpp', secret) + shutil.copyfile('test.html', 'second.html') + open('moar.txt', 'w').write('aliantha') + self.btest('file_db.cpp', secret, args=['--preload-file', 'moar.txt']) # even with a file there, we load over it + shutil.move('test.html', 'third.html') + def test_sdl_pumpevents(self): # key events should be detected using SDL_PumpEvents open(os.path.join(self.get_dir(), 'pre.js'), 'w').write(''' @@ -801,7 +816,7 @@ Press any key to continue.''' document.dispatchEvent(event); } ''') - self.btest('sdl_pumpevents.c', expected='3', args=['--pre-js', 'pre.js']) + self.btest('sdl_pumpevents.c', expected='7', args=['--pre-js', 'pre.js']) def test_sdl_audio(self): shutil.copyfile(path_from_root('tests', 'sounds', 'alarmvictory_1.ogg'), os.path.join(self.get_dir(), 'sound.ogg')) diff --git a/tests/test_core.py b/tests/test_core.py index 142d6df4..7c5b651f 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -4664,6 +4664,12 @@ The current type of b is: 9 ''' self.do_run(src, 'BA') + def test_pthread_specific(self): + if self.emcc_args is None: return self.skip('requires emcc') + src = open(path_from_root('tests', 'pthread', 'specific.c'), 'r').read() + expected = open(path_from_root('tests', 'pthread', 'specific.c.txt'), 'r').read() + self.do_run(src, expected, force_c=True) + def test_time(self): # XXX Not sure what the right output is here. Looks like the test started failing with daylight savings changes. Modified it to pass again. src = open(path_from_root('tests', 'time', 'src.c'), 'r').read() @@ -5567,7 +5573,6 @@ The current type of b is: 9 if Settings.ASM_JS: return self.skip('TODO: dlopen in asm') Settings.NAMED_GLOBALS = 1 - Settings.LINKABLE = 1 lib_src = ''' #include <cstdio> @@ -6762,6 +6767,7 @@ date: 18.07.2013w; day 18, month 7, year 2013, extra: 201, 3 def test_files(self): if self.emcc_args is not None and '-O2' in self.emcc_args: self.emcc_args += ['--closure', '1'] # Use closure here, to test we don't break FS stuff + self.emcc_args = filter(lambda x: x != '-g', self.emcc_args) # ensure we test --closure 1 --memory-init-file 1 (-g would disable closure) Settings.CORRECT_SIGNS = 1 # Just so our output is what we expect. Can flip them both. post = ''' @@ -6788,8 +6794,13 @@ def process(filename): other.close() src = open(path_from_root('tests', 'files.cpp'), 'r').read() + + mem_file = 'src.cpp.o.js.mem' + try_delete(mem_file) self.do_run(src, ('size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\nok.\ntexte\n', 'size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\ntexte\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\nok.\n'), post_build=post, extra_emscripten_args=['-H', 'libc/fcntl.h']) + if self.emcc_args and '--memory-init-file' in self.emcc_args: + assert os.path.exists(mem_file) def test_files_m(self): # Test for Module.stdin etc. diff --git a/tests/test_other.py b/tests/test_other.py index d6e67e59..a6813b07 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -330,27 +330,6 @@ f.close() os.chdir(path_from_root('tests')) # Move away from the directory we are about to remove. shutil.rmtree(tempdirname) - def test_nostdincxx(self): - try: - old = os.environ.get('EMCC_LLVM_TARGET') or '' - for compiler in [EMCC, EMXX]: - for target in ['i386-pc-linux-gnu', 'le32-unknown-nacl']: - print compiler, target - os.environ['EMCC_LLVM_TARGET'] = target - out, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-v'], stdout=PIPE, stderr=PIPE).communicate() - out2, err2 = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-v', '-nostdinc++'], stdout=PIPE, stderr=PIPE).communicate() - assert out == out2 - def focus(e): - assert 'search starts here:' in e, e - assert e.count('End of search list.') == 1, e - return e[e.index('search starts here:'):e.index('End of search list.')+20] - err = focus(err) - err2 = focus(err2) - assert err == err2, err + '\n\n\n\n' + err2 - finally: - if old: - os.environ['EMCC_LLVM_TARGET'] = old - def test_failure_error_code(self): for compiler in [EMCC, EMXX]: # Test that if one file is missing from the build, then emcc shouldn't succeed, and shouldn't try to produce an output file. @@ -1902,7 +1881,7 @@ seeked= file. if SPIDERMONKEY_ENGINE not in JS_ENGINES: return self.skip('cannot run without spidermonkey due to node limitations (Uint8ClampedArray etc.)') shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'example.png')) - Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_canvas.c'), '-s', 'HEADLESS=1']).communicate() + Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_headless.c'), '-s', 'HEADLESS=1']).communicate() output = run_js('a.out.js', engine=SPIDERMONKEY_ENGINE, stderr=PIPE) assert '''Init: 0 Font: 0x1 diff --git a/tests/test_sanity.py b/tests/test_sanity.py index 931645e2..4188afff 100644 --- a/tests/test_sanity.py +++ b/tests/test_sanity.py @@ -519,4 +519,29 @@ fi finally: del os.environ['EMCC_DEBUG'] - del os.environ['EMCC_JSOPT_MIN_CHUNK_SIZE']
\ No newline at end of file + del os.environ['EMCC_JSOPT_MIN_CHUNK_SIZE'] + + def test_nostdincxx(self): + restore() + Cache.erase() + + try: + old = os.environ.get('EMCC_LLVM_TARGET') or '' + for compiler in [EMCC, EMXX]: + for target in ['i386-pc-linux-gnu', 'le32-unknown-nacl']: + print compiler, target + os.environ['EMCC_LLVM_TARGET'] = target + out, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-v'], stdout=PIPE, stderr=PIPE).communicate() + out2, err2 = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-v', '-nostdinc++'], stdout=PIPE, stderr=PIPE).communicate() + assert out == out2 + def focus(e): + assert 'search starts here:' in e, e + assert e.count('End of search list.') == 1, e + return e[e.index('search starts here:'):e.index('End of search list.')+20] + err = focus(err) + err2 = focus(err2) + assert err == err2, err + '\n\n\n\n' + err2 + finally: + if old: + os.environ['EMCC_LLVM_TARGET'] = old + diff --git a/tests/tex_nonbyte.c b/tests/tex_nonbyte.c index 8f2ec162..960d0efb 100644 --- a/tests/tex_nonbyte.c +++ b/tests/tex_nonbyte.c @@ -37,6 +37,7 @@ REDISTRIBUTION OF THIS SOFTWARE. #endif #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <assert.h> diff --git a/tools/file_packager.py b/tools/file_packager.py index bb62e905..8a1f1ba5 100644 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -344,14 +344,7 @@ if has_preloaded: }, send: function() {}, onload: function() { - var data = this.byteArray.subarray(this.start, this.end); - var size = this.end - this.start; - var ptr = Module['_malloc'](size); // XXX leaked if a preload plugin replaces with new data - Module['HEAPU8'].set(data, ptr); - var arrayBuffer = Module['HEAPU8'].subarray(ptr, ptr + size); - assert(arrayBuffer, 'Loading file ' + name + ' failed'); - var byteArray = !arrayBuffer.subarray ? new Uint8Array(arrayBuffer) : arrayBuffer; - + var byteArray = this.byteArray.subarray(this.start, this.end); if (this.crunched) { var ddsHeader = byteArray.subarray(0, 128); var that = this; @@ -375,7 +368,7 @@ if has_preloaded: } else { Runtime.warn('Preloading file ' + that.name + ' failed'); } - }); + }, false, true); // canOwn this data in the filesystem, it is a slide into the heap that will never change this.requests[this.name] = null; }, }; @@ -419,7 +412,12 @@ for file_ in data_files: if has_preloaded: # Get the big archive and split it up - use_data = ' DataRequest.prototype.byteArray = byteArray;\n' + use_data = ''' + // copy the entire loaded file into a spot in the heap. Files will refer to slices in that. They cannot be freed though. + var ptr = Module['_malloc'](byteArray.length); + Module['HEAPU8'].set(byteArray, ptr); + DataRequest.prototype.byteArray = Module['HEAPU8'].subarray(ptr, ptr+byteArray.length); +''' for file_ in data_files: if file_['mode'] == 'preload': use_data += ' DataRequest.prototype.requests["%s"].onload();\n' % (file_['dstpath']) diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index 9a5104bf..b42164f9 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -135,6 +135,7 @@ var ASSIGN_OR_ALTER = set('assign', 'unary-postfix', 'unary-prefix'); var CONTROL_FLOW = set('do', 'while', 'for', 'if', 'switch'); var NAME_OR_NUM = set('name', 'num'); var ASSOCIATIVE_BINARIES = set('+', '*', '|', '&', '^'); +var ALTER_FLOW = set('break', 'continue', 'return'); var BREAK_CAPTURERS = set('do', 'while', 'for', 'switch'); var CONTINUE_CAPTURERS = LOOP; @@ -3070,10 +3071,10 @@ function outline(ast) { currSize += size; if (!isIf) { var last = part.body; - last = last[stats.length-1]; + last = last[last.length-1]; if (last && last[0] === 'block') last = last[1][last[1].length-1]; if (last && last[0] === 'stat') last = last[1]; - force = !last || last[0] !== 'break'; + force = !last || !(last[0] in ALTER_FLOW); } }); assert(currSize); @@ -3487,7 +3488,7 @@ function outline(ast) { } } outliningParents[newIdent] = func[1]; - printErr('performed outline ' + [func[1], newIdent, 'code sizes (pre/post):', originalCodeSize, measureSize(code), 'overhead (w/r):', setSize(setSub(codeInfo.writes, owned)), setSize(setSub(codeInfo.reads, owned)), ' owned: ', setSize(owned), ' left: ', setSize(asmData.vars), setSize(asmData.params), ' loopsDepth: ', loops]); + printErr('performed outline ' + [func[1], newIdent, 'pre size', originalCodeSize, 'resulting size', measureSize(code), 'overhead (w/r):', setSize(setSub(codeInfo.writes, owned)), setSize(setSub(codeInfo.reads, owned)), ' owned: ', setSize(owned), ' left: ', setSize(asmData.vars), setSize(asmData.params), ' loopsDepth: ', loops]); calculateThreshold(func, asmData); return [newFunc]; } @@ -3633,6 +3634,8 @@ function outline(ast) { var maxTotalFunctions = Infinity; // debugging tool + printErr('\n'); + var more = true; while (more) { more = false; @@ -3691,7 +3694,8 @@ function outline(ast) { } } } - printErr('... resulting size of ' + func[1] + ' is ' + measureSize(func)); + ret.push(func); + printErr('... resulting sizes of ' + func[1] + ' is ' + ret.map(measureSize) + '\n'); } denormalizeAsm(func, asmData); }); diff --git a/tools/test-js-optimizer-asm-outline1-output.js b/tools/test-js-optimizer-asm-outline1-output.js index 895004d8..612da16a 100644 --- a/tools/test-js-optimizer-asm-outline1-output.js +++ b/tools/test-js-optimizer-asm-outline1-output.js @@ -348,6 +348,15 @@ function switchh() { HEAP32[sp + 44 >> 2] = 0; switchh$2(sp); helper$0 = HEAP32[sp + 8 >> 2] | 0; + tempValue = HEAP32[sp + 40 >> 2] | 0; + tempInt = HEAP32[sp + 44 >> 2] | 0; + tempDouble = +HEAPF32[sp + 44 >> 2]; + HEAP32[sp + 40 >> 2] = 0; + HEAP32[sp + 44 >> 2] = 0; + if ((tempValue | 0) == 5) { + STACKTOP = sp; + return; + } HEAP32[sp + 8 >> 2] = helper$0; HEAP32[sp + 16 >> 2] = helper$1; HEAP32[sp + 32 >> 2] = 0; @@ -749,36 +758,39 @@ function switchh$2(sp) { var helper$0 = 0, helper$1 = 0; helper$0 = HEAP32[sp + 8 >> 2] | 0; helper$1 = HEAP32[sp + 16 >> 2] | 0; - if (helper$0) { - helper$0 = 0; - switch (helper$1 | 0) { - case 1: - { - f(1); - g(); - break; - } - default: - { - helper$0 = 1; + OL : do { + if (helper$0) { + helper$0 = 0; + switch (helper$1 | 0) { + case 1: + { + f(1); + g(); + HEAP32[sp + 40 >> 2] = 5; + break OL; + } + default: + { + helper$0 = 1; + } } } - } - if (helper$0) { - helper$0 = 0; - switch (helper$1 | 0) { - case 2: - { - f(2); - g(); - break; - } - default: - { - helper$0 = 1; + if (helper$0) { + helper$0 = 0; + switch (helper$1 | 0) { + case 2: + { + f(2); + g(); + break; + } + default: + { + helper$0 = 1; + } } } - } + } while (0); HEAP32[sp + 8 >> 2] = helper$0; } diff --git a/tools/test-js-optimizer-asm-outline1.js b/tools/test-js-optimizer-asm-outline1.js index 3c454182..4282ec8e 100644 --- a/tools/test-js-optimizer-asm-outline1.js +++ b/tools/test-js-optimizer-asm-outline1.js @@ -269,7 +269,7 @@ function switchh() { case 1: { f(1); g(); - break; + return; } case 2: { f(2); |