diff options
45 files changed, 478 insertions, 172 deletions
@@ -1,2 +1,2 @@ @echo off -python %~dp0\em++ %*
\ No newline at end of file +python "%~dp0\em++" %*
\ No newline at end of file diff --git a/em-config.bat b/em-config.bat index 63b15ea4..52d1af0e 100644 --- a/em-config.bat +++ b/em-config.bat @@ -1,2 +1,2 @@ @echo off -python %~dp0\em-config %*
\ No newline at end of file +python "%~dp0\em-config" %*
\ No newline at end of file @@ -1,2 +1,2 @@ @echo off -python %~dp0\emar %*
\ No newline at end of file +python "%~dp0\emar" %*
\ No newline at end of file @@ -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 + @@ -1,2 +1,2 @@ @echo off -python %~dp0\emcc %*
\ No newline at end of file +python "%~dp0\emcc" %*
\ No newline at end of file diff --git a/emconfigure.bat b/emconfigure.bat index f900f407..651ccf05 100644 --- a/emconfigure.bat +++ b/emconfigure.bat @@ -1,2 +1,2 @@ @echo off -python %~dp0\emconfigure %*
\ No newline at end of file +python "%~dp0\emconfigure" %*
\ No newline at end of file diff --git a/emlibtool.bat b/emlibtool.bat index 76ce48c3..4ea705be 100644 --- a/emlibtool.bat +++ b/emlibtool.bat @@ -1,2 +1,2 @@ @echo off -python %~dp0\emlibtool %*
\ No newline at end of file +python "%~dp0\emlibtool" %*
\ No newline at end of file @@ -1,2 +1,2 @@ @echo off -python %~dp0\emmake %*
\ No newline at end of file +python "%~dp0\emmake" %*
\ No newline at end of file diff --git a/emranlib.bat b/emranlib.bat index 69bf8aa4..a8af4ef7 100644 --- a/emranlib.bat +++ b/emranlib.bat @@ -1,2 +1,2 @@ @echo off -python %~dp0\emranlib %*
\ No newline at end of file +python "%~dp0\emranlib" %*
\ No newline at end of file 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 9d1f0cfd..e1397356 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -509,7 +509,7 @@ mergeInto(LibraryManager.library, { var mode = FS.getMode(canRead, canWrite); return FS.create(path, mode); }, - createDataFile: function(parent, name, data, canRead, canWrite) { + createDataFile: function(parent, name, data, canRead, canWrite, canOwn) { var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name); var mode = FS.getMode(canRead, canWrite); var node = FS.create(path, mode); @@ -522,7 +522,7 @@ mergeInto(LibraryManager.library, { // make sure we can write to the file FS.chmod(path, mode | {{{ cDefine('S_IWUGO') }}}); var stream = FS.open(path, 'w'); - FS.write(stream, data, 0, data.length, 0); + FS.write(stream, data, 0, data.length, 0, canOwn); FS.close(stream); FS.chmod(path, mode); } @@ -766,7 +766,7 @@ mergeInto(LibraryManager.library, { // You can also call this with a typed array instead of a url. It will then // do preloading for the Image/Audio part, as if the typed array were the // result of an XHR that you did manually. - createPreloadedFile: function(parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile) { + createPreloadedFile: function(parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) { Browser.init(); // TODO we should allow people to just pass in a complete filename instead // of parent and name being that we just join them anyways @@ -774,7 +774,7 @@ mergeInto(LibraryManager.library, { function processData(byteArray) { function finish(byteArray) { if (!dontCreateFile) { - FS.createDataFile(parent, name, byteArray, canRead, canWrite); + FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn); } if (onload) onload(); removeRunDependency('cp ' + fullname); @@ -1323,7 +1323,7 @@ mergeInto(LibraryManager.library, { if (!seeking) stream.position += bytesRead; return bytesRead; }, - write: function(stream, buffer, offset, length, position) { + write: function(stream, buffer, offset, length, position, canOwn) { if (length < 0 || position < 0) { throw new FS.ErrnoError(ERRNO_CODES.EINVAL); } @@ -1347,7 +1347,7 @@ mergeInto(LibraryManager.library, { // seek to the end before writing in append mode FS.llseek(stream, 0, {{{ cDefine('SEEK_END') }}}); } - var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position); + var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn); if (!seeking) stream.position += bytesWritten; return bytesWritten; }, diff --git a/src/library_memfs.js b/src/library_memfs.js index 0fa6cdfb..63326c42 100644 --- a/src/library_memfs.js +++ b/src/library_memfs.js @@ -1,6 +1,22 @@ 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_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; + } + }, + mount: function(mount) { return MEMFS.create_node(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0); }, @@ -40,6 +56,7 @@ mergeInto(LibraryManager.library, { mmap: MEMFS.stream_ops.mmap }; node.contents = []; + node.contentMode = MEMFS.CONTENT_FLEXIBLE; } else if (FS.isLink(node.mode)) { node.node_ops = { getattr: MEMFS.node_ops.getattr, @@ -98,6 +115,7 @@ mergeInto(LibraryManager.library, { node.timestamp = attr.timestamp; } if (attr.size !== undefined) { + MEMFS.ensureFlexible(node); var contents = node.contents; if (attr.size < contents.length) contents.length = attr.size; else while (attr.size > contents.length) contents.push(0); @@ -165,7 +183,7 @@ mergeInto(LibraryManager.library, { var contents = stream.node.contents; var size = Math.min(contents.length - position, length); #if USE_TYPED_ARRAYS == 2 - if (contents.subarray) { // typed array + if (size > 8 && contents.subarray) { // non-trivial, and typed array buffer.set(contents.subarray(position, position + size), offset); } else #endif @@ -176,13 +194,30 @@ mergeInto(LibraryManager.library, { } return size; }, - write: function(stream, buffer, offset, length, position) { - var contents = stream.node.contents; + write: function(stream, buffer, offset, length, position, canOwn) { + var node = stream.node; + node.timestamp = Date.now(); + var contents = node.contents; +#if USE_TYPED_ARRAYS == 2 + if (length && contents.length === 0 && position === 0 && buffer.subarray) { + // just replace it with the new data + assert(buffer.length); + if (canOwn && buffer.buffer === HEAP8.buffer && offset === 0) { + node.contents = buffer; // this is a subarray of the heap, and we can own it + node.contentMode = MEMFS.CONTENT_OWNING; + } else { + node.contents = new Uint8Array(buffer.subarray(offset, offset+length)); + node.contentMode = MEMFS.CONTENT_FIXED; + } + return length; + } +#endif + MEMFS.ensureFlexible(node); + var contents = node.contents; while (contents.length < position) contents.push(0); for (var i = 0; i < length; i++) { contents[position + i] = buffer[offset + i]; } - stream.node.timestamp = Date.now(); return length; }, llseek: function(stream, offset, whence) { @@ -202,6 +237,7 @@ mergeInto(LibraryManager.library, { return position; }, allocate: function(stream, offset, length) { + MEMFS.ensureFlexible(stream.node); var contents = stream.node.contents; var limit = offset + length; while (limit > contents.length) contents.push(0); @@ -214,10 +250,10 @@ mergeInto(LibraryManager.library, { var allocated; var contents = stream.node.contents; // Only make a new copy when MAP_PRIVATE is specified. - if (!(flags & {{{ cDefine('MAP_PRIVATE') }}})) { + if ( !(flags & {{{ cDefine('MAP_PRIVATE') }}}) && + (contents.buffer === buffer || contents.buffer === buffer.buffer) ) { // We can't emulate MAP_SHARED when the file is not backed by the buffer // we're mapping to (e.g. the HEAP buffer). - assert(contents.buffer === buffer || contents.buffer === buffer.buffer); allocated = false; ptr = contents.byteOffset; } else { @@ -240,4 +276,5 @@ mergeInto(LibraryManager.library, { }, } } -});
\ No newline at end of file +}); + 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 f0df8dca..1b9a8f25 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -19,6 +19,16 @@ extern "C" { #endif /* + * Convenient syntax for inline assembly/js. Allows stuff like + * + * EM_ASM(window.alert('hai')); + * + * Note: double-quotes (") are not supported, but you can use + * single-quotes (') in js anyhow. + */ +#define EM_ASM(...) asm(#__VA_ARGS__) + +/* * Forces LLVM to not dead-code-eliminate a function. Note that * you still need to use EXPORTED_FUNCTIONS so it stays alive * in JS, e.g. @@ -160,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/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/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> |