diff --git a/AUTHORS b/AUTHORS index 2a60562617d80..8a8f7c663731b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -249,3 +249,7 @@ a license to everyone to use it as detailed in LICENSE.) * Kerby Geffrard * cynecx * Chris Gibson +* Harald Reingruber +* Aiden Koss +* Dustin VanLerberghe +* Philip Bielby (copyright owned by Jagex Ltd.) diff --git a/ChangeLog.markdown b/ChangeLog.markdown index 4fbcf75d08a1e..25fc32bc2bc81 100644 --- a/ChangeLog.markdown +++ b/ChangeLog.markdown @@ -9,6 +9,7 @@ Not all changes are documented here. In particular, new features, user-oriented Current trunk code ------------------ + - Updated to libc++'s "v2" ABI, which provides better alignment for string data and other improvements. This is an ABI-incompatible change, so bitcode files from previous versions will not be compatible. - To see a list of commits in the active development branch 'incoming', which have not yet been packaged in a release, see - Emscripten: https://github.com/kripken/emscripten/compare/1.36.1...incoming - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.36.1...incoming diff --git a/embuilder.py b/embuilder.py index 6ac56fd998c11..e11b89b60b5af 100755 --- a/embuilder.py +++ b/embuilder.py @@ -144,6 +144,13 @@ def build_port(port_name, lib_name, params): build(''' int main() {} ''', ['optimizer.2.exe'], ['-O2']) + elif what == 'wasm_compiler_rt': + if shared.get_llvm_target() == shared.WASM_TARGET: + build(''' + int main() {} + ''', ['wasm_compiler_rt.a'], ['-s', 'BINARYEN=1']) + else: + shared.logging.warning('wasm_compiler_rt not built when using JSBackend') elif what == 'zlib': build_port('zlib', 'libz.a', ['-s', 'USE_ZLIB=1']) elif what == 'bullet': @@ -175,4 +182,3 @@ def build_port(port_name, lib_name, params): else: shared.logging.error('unfamiliar operation: ' + operation) sys.exit(1) - diff --git a/emcc.py b/emcc.py index 297b9db809b98..5cf9ee59d7995 100755 --- a/emcc.py +++ b/emcc.py @@ -518,11 +518,6 @@ def detect_fixed_language_mode(args): shrink_level = 2 settings_changes.append('INLINING_LIMIT=25') opt_level = validate_arg_level(requested_level, 3, 'Invalid optimization level: ' + newargs[i]) - # We leave the -O option in place so that the clang front-end runs in that - # optimization mode, but we disable the actual optimization passes, as we'll - # run them separately. - newargs.append('-mllvm') - newargs.append('-disable-llvm-optzns') elif newargs[i].startswith('--js-opts'): check_bad_eq(newargs[i]) js_opts = eval(newargs[i+1]) @@ -1178,6 +1173,17 @@ def check(input_file): if shared.Settings.GLOBAL_BASE < 0: shared.Settings.GLOBAL_BASE = 8 # default if nothing else sets it + if shared.Settings.WASM_BACKEND: + if shared.Settings.SIMD: + newargs.append('-msimd128') + else: + # We leave the -O option in place so that the clang front-end runs in that + # optimization mode, but we disable the actual optimization passes, as we'll + # run them separately. + if opt_level > 0: + newargs.append('-mllvm') + newargs.append('-disable-llvm-optzns') + shared.Settings.EMSCRIPTEN_VERSION = shared.EMSCRIPTEN_VERSION shared.Settings.OPT_LEVEL = opt_level shared.Settings.DEBUG_LEVEL = debug_level @@ -1280,7 +1286,7 @@ def compile_source_file(i, input_file): log_time('bitcodeize inputs') - if not LEAVE_INPUTS_RAW: + if not LEAVE_INPUTS_RAW and not shared.Settings.WASM_BACKEND: assert len(temp_files) == len(input_files) # Optimize source files diff --git a/emscripten-version.txt b/emscripten-version.txt index dd62092ad711e..71be8e725dcda 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1,2 +1,2 @@ -"1.36.4" +"1.36.5" diff --git a/emscripten.py b/emscripten.py index 0b927e02cc569..7575cdf7ab291 100755 --- a/emscripten.py +++ b/emscripten.py @@ -579,16 +579,16 @@ def make_emulated_param(i): simdintfloatfuncs += ['fromInt16x8Bits'] if metadata['simdUint32x4']: simdinttypes += ['Uint32x4'] - simdintfloatfuncs += ['fromUint32x4', 'fromUint32x4Bits'] + simdintfloatfuncs += ['fromUint32x4Bits'] if metadata['simdInt32x4']: simdinttypes += ['Int32x4'] - simdintfloatfuncs += ['fromInt32x4', 'fromInt32x4Bits'] + simdintfloatfuncs += ['fromInt32x4Bits'] if metadata['simdFloat32x4']: simdfloattypes += ['Float32x4'] - simdintfloatfuncs += ['fromFloat32x4', 'fromFloat32x4Bits'] + simdintfloatfuncs += ['fromFloat32x4Bits'] if metadata['simdFloat64x2']: simdfloattypes += ['Float64x2'] - simdintfloatfuncs += ['fromFloat64x2', 'fromFloat64x2Bits'] + simdintfloatfuncs += ['fromFloat64x2Bits'] if metadata['simdBool8x16']: simdbooltypes += ['Bool8x16'] if metadata['simdBool16x8']: @@ -834,6 +834,19 @@ def string_contains_any(s, str_list): simd_bool_symbols = filter(lambda x: not string_contains_any(x, nonexisting_simd_symbols), simd_bool_symbols) asm_global_funcs += ''.join(simd_bool_symbols) + # SIMD conversions (not bitcasts) between same lane sizes: + def add_simd_cast(dst, src): + return ' var SIMD_' + dst + '_from' + src + '=SIMD_' + dst + '.from' + src + ';\n' + def add_simd_casts(t1, t2): + return add_simd_cast(t1, t2) + add_simd_cast(t2, t1) + if metadata['simdInt8x16'] and metadata['simdUint8x16']: asm_global_funcs += add_simd_casts('Int8x16', 'Uint8x16') + if metadata['simdInt16x8'] and metadata['simdUint16x8']: asm_global_funcs += add_simd_casts('Int16x8', 'Uint16x8') + if metadata['simdInt32x4'] and metadata['simdUint32x4']: asm_global_funcs += add_simd_casts('Int32x4', 'Uint32x4') + if metadata['simdInt32x4'] and metadata['simdFloat32x4']: asm_global_funcs += add_simd_casts('Int32x4', 'Float32x4') + if metadata['simdUint32x4'] and metadata['simdFloat32x4']: asm_global_funcs += add_simd_casts('Uint32x4', 'Float32x4') + if metadata['simdInt32x4'] and metadata['simdFloat64x2']: asm_global_funcs += add_simd_cast('Int32x4', 'Float64x2') # Unofficial, needed for emscripten_int32x4_fromFloat64x2 + if metadata['simdUint32x4'] and metadata['simdFloat64x2']: asm_global_funcs += add_simd_cast('Uint32x4', 'Float64x2') # Unofficial, needed for emscripten_uint32x4_fromFloat64x2 + # Unofficial, Bool64x2 does not yet exist, but needed for Float64x2 comparisons. if metadata['simdFloat64x2']: asm_global_funcs += ' var SIMD_Int32x4_fromBool64x2Bits = global.SIMD.Int32x4.fromBool64x2Bits;\n' @@ -1294,8 +1307,12 @@ def emscript_wasm_backend(infile, settings, outfile, libraries=None, compiler_en temp_s = temp_files.get('.wb.s').name backend_compiler = os.path.join(shared.LLVM_ROOT, 'llc') - backend_args = [backend_compiler, infile, '-march=wasm32', '-filetype=asm', '-o', temp_s] + backend_args = [backend_compiler, infile, '-march=wasm32', '-filetype=asm', + '-asm-verbose=false', + '-o', temp_s] backend_args += ['-thread-model=single'] # no threads support in backend, tell llc to not emit atomics + # disable slow and relatively unimportant optimization passes + backend_args += ['-combiner-alias-analysis=false', '-combiner-global-alias-analysis=false'] if DEBUG: logging.debug('emscript: llvm wasm backend: ' + ' '.join(backend_args)) t = time.time() @@ -1312,6 +1329,9 @@ def emscript_wasm_backend(infile, settings, outfile, libraries=None, compiler_en s2wasm_args += ['--emscripten-glue'] s2wasm_args += ['--global-base=%d' % shared.Settings.GLOBAL_BASE] s2wasm_args += ['--initial-memory=%d' % shared.Settings.TOTAL_MEMORY] + def compiler_rt_fail(): raise Exception('Expected wasm_compiler_rt.a to already be built') + compiler_rt_lib = shared.Cache.get('wasm_compiler_rt.a', lambda: compiler_rt_fail(), 'a') + s2wasm_args += ['-l', compiler_rt_lib] if DEBUG: logging.debug('emscript: binaryen s2wasm: ' + ' '.join(s2wasm_args)) t = time.time() diff --git a/site/source/docs/api_reference/emscripten.h.rst b/site/source/docs/api_reference/emscripten.h.rst index c43e1edf1b11a..1be380628c3a8 100644 --- a/site/source/docs/api_reference/emscripten.h.rst +++ b/site/source/docs/api_reference/emscripten.h.rst @@ -317,7 +317,7 @@ Functions :rtype: double :return: The pixel ratio or 1.0 if not supported. -.. c:function::void emscripten_hide_mouse(void) +.. c:function:: void emscripten_hide_mouse(void) Hide the OS mouse cursor over the canvas. @@ -1170,21 +1170,21 @@ Typedefs Functions --------- -.. c::function:: void emscripten_sleep(unsigned int ms) +.. c:function:: void emscripten_sleep(unsigned int ms) Sleep for `ms` milliseconds. -.. c::function:: emscripten_coroutine emscripten_coroutine_create(em_arg_callback_func func, void *arg, int stack_size) +.. c:function:: emscripten_coroutine emscripten_coroutine_create(em_arg_callback_func func, void *arg, int stack_size) Create a coroutine which will be run as `func(arg)`. :param int stack_size: the stack size that should be allocated for the coroutine, use 0 for the default value. -.. c::function:: int emscripten_coroutine_next(emscripten_coroutine coroutine) +.. c:function:: int emscripten_coroutine_next(emscripten_coroutine coroutine) Run `coroutine` until it returns, or `emscripten_yield` is called. A non-zero value is returned if `emscripten_yield` is called, otherwise 0 is returned, and future calls of `emscripten_coroutine_next` on this coroutine is undefined behaviour. -.. c::function:: void emscripten_yield(void) +.. c:function:: void emscripten_yield(void) This function should only be called in a coroutine created by `emscripten_coroutine_create`, when it called, the coroutine is paused and the caller will continue. diff --git a/site/source/docs/api_reference/html5.h.rst b/site/source/docs/api_reference/html5.h.rst index d3a8e5a179956..5a4079149347f 100644 --- a/site/source/docs/api_reference/html5.h.rst +++ b/site/source/docs/api_reference/html5.h.rst @@ -130,8 +130,17 @@ General types .. c:macro:: EM_BOOL - This is the Emscripten type for a ``bool``. + This is the Emscripten type for a ``bool``. + Possible values: + .. c:macro:: EM_TRUE + + This is the Emscripten value for ``true``. + + .. c:macro:: EM_FALSE + + This is the Emscripten value for ``false``. + .. c:macro:: EM_UTF8 diff --git a/site/source/docs/api_reference/module.rst b/site/source/docs/api_reference/module.rst index ae1c2d68fb8bc..cf2aa28025736 100644 --- a/site/source/docs/api_reference/module.rst +++ b/site/source/docs/api_reference/module.rst @@ -102,7 +102,11 @@ Other methods This method should be called to destroy C++ objects created in JavaScript using :ref:`WebIDL bindings `. If this method is not called, an object may be garbage collected, but its destructor will not be called. :param obj: The JavaScript-wrapped C++ object to be destroyed. - + +.. js:function:: Module.onCustomMessage + + When compiled with ``PROXY_TO_WORKER = 1`` (see `settings.js `_), this callback (which should be implemented on both the client and worker's ``Module`` object) allows sending custom messages and data between the web worker and the main thread (using the ``postCustomMessage`` function defined in `proxyClient.js `_ and `proxyWorker.js `_). + Overriding execution environment ================================ diff --git a/site/source/docs/optimizing/Optimizing-Code.rst b/site/source/docs/optimizing/Optimizing-Code.rst index e565546e7ef05..d0e494684c82f 100644 --- a/site/source/docs/optimizing/Optimizing-Code.rst +++ b/site/source/docs/optimizing/Optimizing-Code.rst @@ -74,6 +74,8 @@ Trading off code size and performance ------------------------------------- You may wish to build the less performance-sensitive source files in your project using :ref:`-Os ` or :ref:`-Oz ` and the remainder using :ref:`-O2 ` (:ref:`-Os ` and :ref:`-Oz ` are similar to :ref:`-O2 `, but reduce code size at the expense of performance. :ref:`-Oz ` reduces code size more than :ref:`-Os `.) +Note that ``-Oz`` may take longer to build. For example, it enables ``EVAL_CTORS`` which tries to optimize out C++ global constructors, which takes time. + Miscellaneous code size tips ---------------------------- @@ -82,9 +84,11 @@ In addition to the above (defining a separate memory initialization file as :ref - Use :ref:`llvm-lto ` when compiling from bitcode to JavaScript: ``--llvm-lto 1``. This can break some code as the LTO code path is less tested. - Disable :ref:`optimizing-code-inlining`: ``-s INLINING_LIMIT=1``. Compiling with -Os or -Oz generally avoids inlining too. - Use :ref:`closure ` on the outside non-asm.js code: ``--closure 1``. This can break code that doesn't use `closure annotations properly `_. -- You can use the ``NO_FILESYSTEM`` and ``NO_BROWSER`` options to disable bundling of filesystem and browser support code, which by default are included. This can be useful if you are building a pure computational library, for example. See ``settings.js`` for more detals. +- You can use the ``NO_FILESYSTEM`` option to disable bundling of filesystem support code (the compiler should optimize it out if not used, but may not always succeed). This can be useful if you are building a pure computational library, for example. See ``settings.js`` for more detals. - You can use ``EXPORTED_RUNTIME_METHODS`` to define which runtime methods are exported. By default a bunch of useful methods are exported, which you may not need; setting this to a smaller list will cause fewer methods to be exported. In conjunction with the closure compiler, this can be very effective, since closure can eliminate non-exported code. See ``settings.js`` for more detals. See ``test_no_nuthin`` in ``tests/test_other.py`` for an example usage in the test suite. - +- You can use ``ELIMINATE_DUPLICATE_FUNCTIONS`` to remove duplicate functions, which C++ templates often create. See ``settings.js`` for more details. +- You can move some of your code into the `Emterpreter `_, which will then run much slower (as it is interpreted), but it will transfer all that code into a smaller amount of data. +- You can use separate modules through `dynamic linking `_. That can increase the total code size of everything, but reduces the maximum size of a single module, which can help in some cases (e.g. if a single big module hits a memory limit). Very large codebases ==================== diff --git a/site/source/docs/porting/pthreads.rst b/site/source/docs/porting/pthreads.rst index 04bbed3bebf84..d7675b3172b2c 100644 --- a/site/source/docs/porting/pthreads.rst +++ b/site/source/docs/porting/pthreads.rst @@ -15,7 +15,7 @@ By default, support for pthreads is not enabled, since the specification is stil - Pass the compiler flag -s USE_PTHREADS=1 when compiling any .c/.cpp files, AND when linking to generate the final output .js file. - Optionally, pass the linker flag -s PTHREAD_POOL_SIZE= to specify a predefined pool of web workers to populate at page preRun time before application main() is called. If -1 is passed to both PTHREAD_POOL_SIZE and PTHREAD_HINT_NUM_CORES, then a popup dialog will ask the user the size of the pool (useful for testing). -- Optionally, pass the linker flag -s PTHREAD_HINT_NUM_CORES= to choose what the function emscripten_num_logical_cores(); will return if navigator.hardwareConcurrency is not supported. If -1 is specified here, a popup dialog will be shown at startup to let the user specify the value that is returned here. This can be helpful in order to dynamically test how an application behaves with different values here. +- Optionally, pass the linker flag -s PTHREAD_HINT_NUM_CORES= to choose what the function emscripten_num_logical_cores(); will return if navigator.hardwareConcurrency is not supported. If -1 is specified here, a popup dialog will be shown at startup to let the user specify the value that is returned here. This can be helpful in order to dynamically test how an application behaves with different values here. There should be no other changes required. In C/C++ code, the preprocessor check #ifdef __EMSCRIPTEN_PTHREADS__ can be used to detect whether Emscripten is currently targeting pthreads. @@ -42,6 +42,8 @@ The Emscripten implementation for the pthreads API should follow the POSIX stand - One particular note to pay attention to when porting is that sometimes in existing codebases the callback function pointers to pthread_create() and pthread_cleanup_push() omit the void* argument, which strictly speaking is undefined behavior in C/C++, but works in several x86 calling conventions. Doing this in Emscripten will issue a compiler warning, and can abort at runtime when attempting to call a function pointer with incorrect signature, so in the presence of such errors, it is good to check the signatures of the thread callback functions. +- Note that the function emscripten_num_logical_cores() will always return the value of navigator.hardwareConcurrency, i.e. the number of logical cores on the system, even when shared memory is not supported. This means that it is possible for emscripten_num_logical_cores() to return a value greater than 1, while at the same time emscripten_has_threading_support() can return false. The return value of emscripten_has_threading_support() denotes whether the browser has shared memory support available. + Also note that when compiling code that uses pthreads, an additional JavaScript file `pthread-main.js` is generated alongside the output .js file. That file must be deployed with the rest of the generated code files. By default, `pthread-main.js` will be loaded relative to the main HTML page URL. If it is desirable to load the file from a different location e.g. in a CDN environment, then one can define the `Module.locateFile(filename)` function in the main HTML `Module` object to return the URL of the target location of the `pthread-main.js` entry point. If this function is not defined in `Module`, then the relative location specified by `Module.pthreadMainPrefixURL + '/pthread-main.js'` will be used instead. If this is prefix URL is not specified either, then the default location relative to the main HTML file is used. Running code and tests diff --git a/src/closure-externs.js b/src/closure-externs.js index fe6d84aac5ecd..492a634718e24 100644 --- a/src/closure-externs.js +++ b/src/closure-externs.js @@ -168,3 +168,28 @@ navigator.mozGamepads = function() {}; * @return {Array.} */ navigator.gamepads = function() {}; + +/** + * Backported from latest closure... + * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/currentScript + */ +Document.prototype.currentScript; + +//Atomics library (not yet in latest closure): +//See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics +var Atomics; +Atomics.prototype.NOTEQUAL = -1; +Atomics.prototype.OK = 0; +Atomics.prototype.TIMEDOUT = -2; +Atomics.prototype.add = function(typedArray, index, value) {}; +Atomics.prototype.and = function(typedArray, index, value) {}; +Atomics.prototype.compareExchange = function(typedArray, index, expectedValue, replacementValue) {}; +Atomics.prototype.exchange = function(typedArray, index, value) {}; +Atomics.prototype.load = function(typedArray, index) {}; +Atomics.prototype.or = function(typedArray, index, value) {}; +Atomics.prototype.store = function(typedArray, index, value) {}; +Atomics.prototype.sub = function(typedArray, index, value) {}; +Atomics.prototype.xor = function(typedArray, index, value) {}; +Atomics.prototype.wait = function(typedArray, index, valuei, timeout) {}; +Atomics.prototype.wake = function(typedArray, index, value) {}; +Atomics.prototype.isLockFree = function(size) {}; diff --git a/src/cpuprofiler.js b/src/cpuprofiler.js index 88c4b4cc182db..dec30c18c4d52 100644 --- a/src/cpuprofiler.js +++ b/src/cpuprofiler.js @@ -1,3 +1,22 @@ +// cpuprofiler.js is an interactive CPU execution profiler which measures the time spent in executing code that utilizes requestAnimationFrame(), setTimeout() and/or setInterval() handlers to run. +// Visit https://github.com/kripken/emscripten for the latest version. + +// performance.now() might get faked later (this is done in the openwebgames.com test harness), so save the real one for cpu profiler. +// However, in Safari, assigning to the performance object will mysteriously vanish in other imported .js + {{{ SCRIPT }}} + + + diff --git a/tests/fuzz/14.c.txt b/tests/fuzz/14.c.txt index 118ce7ddf498e..201bb41b2ca16 100644 --- a/tests/fuzz/14.c.txt +++ b/tests/fuzz/14.c.txt @@ -1 +1 @@ -523D07B9 +checksum = 523D07B9 diff --git a/tests/pthread/test_pthread_gcc_atomic_fetch_and_op.cpp b/tests/pthread/test_pthread_gcc_atomic_fetch_and_op.cpp index 84f71ce2a3bb1..5bfe6154ace76 100644 --- a/tests/pthread/test_pthread_gcc_atomic_fetch_and_op.cpp +++ b/tests/pthread/test_pthread_gcc_atomic_fetch_and_op.cpp @@ -155,6 +155,11 @@ int main() } } } + + // Test that regex replacing also works on these. + emscripten_atomic_fence(); + __sync_synchronize(); + // XXX NAND support does not exist in Atomics API. #if 0 { diff --git a/tests/sqlite/benchmark.c b/tests/sqlite/benchmark.c index 04dc150a2a9ef..63dacb0344b41 100644 --- a/tests/sqlite/benchmark.c +++ b/tests/sqlite/benchmark.c @@ -54,7 +54,7 @@ int main(int argc, char **argv){ sqlite3 *db; char *zErrMsg = 0; int rc, i; - clock_t t; + double t; int n, m; n = argc > 1 ? atoi(argv[1]) : 5000; @@ -79,12 +79,12 @@ int main(int argc, char **argv){ #define TIME(msg) \ { \ - int now = emscripten_get_now(); \ - printf(msg " : took %d ms\n", (int)(now - t)); \ + double now = emscripten_get_now(); \ + printf(msg " : took %f ms\n", now - t); \ t = now; \ } - t = clock(); + t = emscripten_get_now(); TIME("'startup' - IGNORE THIS VALUE, it is an artifact"); RUN("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100));"); diff --git a/tests/sqlite/test.c b/tests/sqlite/test.c index 7b8cf19749dbd..f06703647404b 100644 --- a/tests/sqlite/test.c +++ b/tests/sqlite/test.c @@ -1,4 +1,5 @@ #include +#include #include static int callback(void *NotUsed, int argc, char **argv, char **azColName){ diff --git a/tests/test_browser.py b/tests/test_browser.py index 6c94ba77902ca..173f56c8f468c 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -3053,6 +3053,9 @@ def test_canvas_style_proxy(self): def test_canvas_size_proxy(self): self.btest(path_from_root('tests', 'canvas_size_proxy.c'), expected='0', args=['--proxy-to-worker']) + def test_custom_messages_proxy(self): + self.btest(path_from_root('tests', 'custom_messages_proxy.c'), expected='1', args=['--proxy-to-worker', '--shell-file', path_from_root('tests', 'custom_messages_proxy_shell.html'), '--post-js', path_from_root('tests', 'custom_messages_proxy_postjs.js')]) + def test_separate_asm(self): for opts in [['-O0'], ['-O1'], ['-O2'], ['-O2', '--closure', '1']]: print opts diff --git a/tests/test_core.py b/tests/test_core.py index de0b89bdc7431..e93c16f9d194c 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -8064,7 +8064,10 @@ def setUp(self): asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "-s", "SAFE_HEAP=1"]) asm2i = make_run("asm2i", compiler=CLANG, emcc_args=["-O2", '-s', 'EMTERPRETIFY=1']) #asm2m = make_run("asm2m", compiler=CLANG, emcc_args=["-O2", "--memory-init-file", "0", "-s", "MEM_INIT_METHOD=2", "-s", "ASSERTIONS=1"]) -#binaryen = make_run("binaryen", compiler=CLANG, emcc_args=['-O2', '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-s-expr"']) +#binaryen0 = make_run("binaryen", compiler=CLANG, emcc_args=['-O0', '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-s-expr"']) +#binaryen1 = make_run("binaryen", compiler=CLANG, emcc_args=['-O1', '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-s-expr"']) +#binaryen2 = make_run("binaryen", compiler=CLANG, emcc_args=['-O2', '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-s-expr"']) +#binaryen3 = make_run("binaryen", compiler=CLANG, emcc_args=['-O3', '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-s-expr"']) #normalyen = make_run("normalyen", compiler=CLANG, emcc_args=['-O0', '-s', 'GLOBAL_BASE=1024']) # useful comparison to binaryen #spidaryen = make_run("binaryen", compiler=CLANG, emcc_args=['-O0', '-s', 'BINARYEN=1', '-s', 'BINARYEN_SCRIPTS="spidermonkify.py"']) diff --git a/tests/test_sanity.py b/tests/test_sanity.py index 87b7309d3f5d0..dacb968113b58 100644 --- a/tests/test_sanity.py +++ b/tests/test_sanity.py @@ -692,7 +692,10 @@ def test(): def test_embuilder(self): restore() - for command, expected, success, result_libs in [ + tests = [] + if get_llvm_target() == WASM_TARGET: + tests.append(([PYTHON, 'embuilder.py', 'build', 'wasm_compiler_rt'], ['building and verifying wasm_compiler_rt', 'success'], True, ['wasm_compiler_rt.a']),) + for command, expected, success, result_libs in tests + [ ([PYTHON, 'embuilder.py'], ['Emscripten System Builder Tool', 'build libc', 'native_optimizer'], True, []), ([PYTHON, 'embuilder.py', 'build', 'waka'], 'ERROR', False, []), ([PYTHON, 'embuilder.py', 'build', 'libc'], ['building and verifying libc', 'success'], True, ['libc.bc']), @@ -962,4 +965,3 @@ def test_binaryen(self): assert os.path.exists(tag_file) subprocess.check_call([PYTHON, 'emcc.py', 'tests/hello_world.c', '-s', 'BINARYEN=1']) self.assertContained('hello, world!', run_js('a.out.js')) - diff --git a/tools/shared.py b/tools/shared.py index 68e1921a00e84..070e61663fe0a 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -877,14 +877,18 @@ def get_llvm_target(): COMPILER_OPTS # Can be set in EM_CONFIG, optionally except: COMPILER_OPTS = [] + +# Set the LIBCPP ABI version to at least 2 so that we get nicely aligned string +# data and other nice fixes. COMPILER_OPTS = COMPILER_OPTS + [#'-fno-threadsafe-statics', # disabled due to issue 1289 '-target', get_llvm_target(), '-D__EMSCRIPTEN_major__=' + str(EMSCRIPTEN_VERSION_MAJOR), '-D__EMSCRIPTEN_minor__=' + str(EMSCRIPTEN_VERSION_MINOR), - '-D__EMSCRIPTEN_tiny__=' + str(EMSCRIPTEN_VERSION_TINY)] + '-D__EMSCRIPTEN_tiny__=' + str(EMSCRIPTEN_VERSION_TINY), + '-D_LIBCPP_ABI_VERSION=2'] if LLVM_TARGET == WASM_TARGET: - # wasm target does not automatically define emscripten stuff, so do it here + # wasm target does not automatically define emscripten stuff, so do it here. COMPILER_OPTS = COMPILER_OPTS + ['-DEMSCRIPTEN', '-D__EMSCRIPTEN__'] diff --git a/tools/system_libs.py b/tools/system_libs.py index 15ace0335f16f..a994a474eab16 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -236,6 +236,33 @@ def create_dlmalloc_split(libname): shared.Building.link([dlmalloc_o, split_malloc_o], lib) return lib + def create_wasm_compiler_rt(libname): + srcdir = shared.path_from_root('system', 'lib', 'compiler-rt', 'lib', 'builtins') + filenames = ['addtf3.c', 'ashlti3.c', 'ashrti3.c', 'comparetf2.c', 'divtf3.c', 'divti3.c', + 'extenddftf2.c', 'extendsftf2.c', + 'fixdfti.c', 'fixsfti.c', 'fixtfdi.c', 'fixtfsi.c', 'fixtfti.c', + 'fixunsdfti.c', 'fixunssfti.c', 'fixunstfdi.c', 'fixunstfsi.c', 'fixunstfti.c', + 'floatditf.c', 'floatsitf.c', 'floattidf.c', 'floattisf.c', + 'floatunditf.c', 'floatunsitf.c', 'floatuntidf.c', 'floatuntisf.c', 'lshrti3.c', + 'modti3.c', 'multf3.c', 'multi3.c', 'subtf3.c', 'udivti3.c', 'umodti3.c', 'ashrdi3.c', + 'ashldi3.c', 'fixdfdi.c', 'floatdidf.c', 'lshrdi3.c', 'moddi3.c', + 'trunctfdf2.c', 'trunctfsf2.c', 'umoddi3.c', 'fixunsdfdi.c', 'muldi3.c', + 'divdi3.c', 'divmoddi4.c', 'udivdi3.c', 'udivmoddi4.c'] + files = (os.path.join(srcdir, f) for f in filenames) + o_s = [] + commands = [] + for src in files: + o = in_temp(os.path.basename(src) + '.o') + # Use clang directly instead of emcc. Since emcc's intermediate format (produced by -S) is LLVM IR, there's no way to + # get emcc to output wasm .s files, which is what we archive in compiler_rt. + commands.append([shared.CLANG_CC, '--target=wasm32', '-S', shared.path_from_root('system', 'lib', src), '-O2', '-o', o]) + o_s.append(o) + run_commands(commands) + lib = in_temp(libname) + run_commands([[shared.LLVM_AR, 'cr', '-format=gnu', lib] + o_s]) + return lib + + # Setting this in the environment will avoid checking dependencies and make building big projects a little faster # 1 means include everything; otherwise it can be the name of a lib (libcxx, etc.) # You can provide 1 to include everything, or a comma-separated list with the ones you want @@ -385,6 +412,11 @@ def do_create(): force = force.union(deps) ret.sort(key=lambda x: x.endswith('.a')) # make sure to put .a files at the end. + # Handle backend compiler_rt separately because it is not a bitcode system lib like the others. + # Here, just ensure that it's in the cache. + if shared.Settings.BINARYEN and shared.Settings.WASM_BACKEND: + crt_file = shared.Cache.get('wasm_compiler_rt.a', lambda: create_wasm_compiler_rt('wasm_compiler_rt.a'), extension='a') + for actual in ret: if os.path.basename(actual) == 'libcxxabi.bc': # libcxxabi and libcxx *static* linking is tricky. e.g. cxa_demangle.cpp disables c++