diff --git a/AUTHORS b/AUTHORS index eb89e4840cea4..53c68d4dc9290 100644 --- a/AUTHORS +++ b/AUTHORS @@ -185,3 +185,5 @@ a license to everyone to use it as detailed in LICENSE.) * Tiago Quelhas * Reinier de Blois * Yuichi Nishiwaki +* Jérôme Bernard (copyright owned by Ercom) + diff --git a/emcc b/emcc index f14030b034d9b..7bd8315565c25 100755 --- a/emcc +++ b/emcc @@ -55,9 +55,9 @@ from tools.response_file import read_response_file # endings = dot + a suffix, safe to test by filename.endswith(endings) C_ENDINGS = ('.c', '.C') -CXX_ENDINGS = ('.cpp', '.cxx', '.cc', '.c++', '.CPP', '.CXX', '.CC', '.C++') -OBJC_ENDINGS = ('.m',) -OBJCXX_ENDINGS = ('.mm',) +CXX_ENDINGS = ('.cpp', '.cxx', '.cc', '.c++', '.CPP', '.CXX', '.CC', '.C++', '.i', '.ii') +OBJC_ENDINGS = ('.m', '.mi') +OBJCXX_ENDINGS = ('.mm', '.mii') SOURCE_ENDINGS = C_ENDINGS + CXX_ENDINGS + OBJC_ENDINGS + OBJCXX_ENDINGS BITCODE_ENDINGS = ('.bc', '.o', '.obj') DYNAMICLIB_ENDINGS = ('.dylib', '.so') # Windows .dll suffix is not included in this list, since those are never linked to directly on the command line. @@ -874,10 +874,12 @@ try: # Apply optimization level settings shared.Settings.apply_opt_level(opt_level, noisy=True) - fastcomp = os.environ.get('EMCC_FAST_COMPILER') != '0' - if fastcomp: - # Set ASM_JS default here so that we can override it from the command line. - shared.Settings.ASM_JS = 1 if opt_level > 0 else 2 + if os.environ.get('EMCC_FAST_COMPILER') == '0': + logging.critical('Non-fastcomp compiler is no longer available, please use fastcomp or an older version of emscripten') + sys.exit(1) + + # Set ASM_JS default here so that we can override it from the command line. + shared.Settings.ASM_JS = 1 if opt_level > 0 else 2 pre_fastcomp_opts = [] @@ -895,63 +897,54 @@ try: if key == 'EXPORTED_FUNCTIONS': shared.Settings.ORIGINAL_EXPORTED_FUNCTIONS = shared.Settings.EXPORTED_FUNCTIONS[:] # used for warnings in emscripten.py - if fastcomp: - try: - assert shared.Settings.ASM_JS > 0, 'ASM_JS must be enabled in fastcomp' - assert shared.Settings.UNALIGNED_MEMORY == 0, 'forced unaligned memory not supported in fastcomp' - assert shared.Settings.FORCE_ALIGNED_MEMORY == 0, 'forced aligned memory is not supported in fastcomp' - assert shared.Settings.CHECK_HEAP_ALIGN == 0, 'check heap align not supported in fastcomp - use SAFE_HEAP instead' - assert shared.Settings.SAFE_DYNCALLS == 0, 'safe dyncalls not supported in fastcomp' - assert shared.Settings.ASM_HEAP_LOG == 0, 'asm heap log not supported in fastcomp' - assert shared.Settings.LABEL_DEBUG == 0, 'label debug not supported in fastcomp' - assert shared.Settings.EXECUTION_TIMEOUT == -1, 'execution timeout not supported in fastcomp' - assert shared.Settings.NAMED_GLOBALS == 0, 'named globals not supported in fastcomp' - assert shared.Settings.PGO == 0, 'pgo not supported in fastcomp' - assert shared.Settings.TARGET_ASMJS_UNKNOWN_EMSCRIPTEN == 1, 'fastcomp requires asmjs-unknown-emscripten' - assert shared.Settings.USE_TYPED_ARRAYS == 2, 'altering USE_TYPED_ARRAYS is not supported' - assert shared.Settings.QUANTUM_SIZE == 4, 'altering the QUANTUM_SIZE is not supported' - assert not split_js_file, '--split-js is deprecated and not supported in fastcomp' - assert shared.Settings.INIT_HEAP == 0, 'HEAP_INIT is not supported in fastcomp (and should never be needed except for debugging)' - assert not shared.Settings.RUNTIME_TYPE_INFO, 'RUNTIME_TYPE_INFO is not supported in fastcomp' - assert not shared.Settings.CORRUPTION_CHECK, 'CORRUPTION_CHECK is not supported in asm.js mode, which is what fastcomp can emit (you can use non-asm.js mode in non-fastcomp)' - assert not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE, 'Linking modules is not supported in fastcomp' - assert not shared.Settings.DLOPEN_SUPPORT, 'dlopen() is not supported yet in fastcomp' - except Exception, e: - logging.error('Compiler settings are incompatible with fastcomp. You can fall back to the older compiler core, although that is not recommended, see http://kripken.github.io/emscripten-site/docs/building_from_source/LLVM-Backend.html') - raise e - - fastcomp_opts = [] - if shared.Settings.NO_EXIT_RUNTIME: - pre_fastcomp_opts += ['-emscripten-no-exit-runtime'] - if not llvm_lto: fastcomp_opts += ['-globalopt', '-globaldce'] - fastcomp_opts += ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt'] - if shared.Settings.DISABLE_EXCEPTION_CATCHING != 1: - fastcomp_opts += ['-enable-emscripten-cxx-exceptions'] - if shared.Settings.DISABLE_EXCEPTION_CATCHING == 2: - fastcomp_opts += ['-emscripten-cxx-exceptions-whitelist=' + ','.join(shared.Settings.EXCEPTION_CATCHING_WHITELIST or ['fake'])] - if shared.Settings.ASYNCIFY: - fastcomp_opts += ['-emscripten-asyncify'] - fastcomp_opts += ['-emscripten-asyncify-functions=' + ','.join(shared.Settings.ASYNCIFY_FUNCTIONS)] - fastcomp_opts += ['-emscripten-asyncify-whitelist=' + ','.join(shared.Settings.ASYNCIFY_WHITELIST)] - - else: # non-fastcomp - logging.critical('Non-fastcomp compiler is no longer available, please use fastcomp or an older version of emscripten') - sys.exit(1) - - if shared.Settings.ASM_JS: - assert opt_level >= 1 or fastcomp, 'asm.js requires -O1 or above' - - if shared.Settings.CORRECT_SIGNS != 1: - logging.warning('setting CORRECT_SIGNS to 1 for asm.js code generation') - shared.Settings.CORRECT_SIGNS = 1 - if shared.Settings.CORRECT_OVERFLOWS != 1: - logging.warning('setting CORRECT_OVERFLOWS to 1 for asm.js code generation') - shared.Settings.CORRECT_OVERFLOWS = 1 - assert not shared.Settings.PGO, 'cannot run PGO in ASM_JS mode' - - if shared.Settings.SAFE_HEAP and not js_opts: - js_opts = True - logging.warning('enabling js opts for SAFE_HEAP') + try: + assert shared.Settings.ASM_JS > 0, 'ASM_JS must be enabled in fastcomp' + assert shared.Settings.UNALIGNED_MEMORY == 0, 'forced unaligned memory not supported in fastcomp' + assert shared.Settings.FORCE_ALIGNED_MEMORY == 0, 'forced aligned memory is not supported in fastcomp' + assert shared.Settings.CHECK_HEAP_ALIGN == 0, 'check heap align not supported in fastcomp - use SAFE_HEAP instead' + assert shared.Settings.SAFE_DYNCALLS == 0, 'safe dyncalls not supported in fastcomp' + assert shared.Settings.ASM_HEAP_LOG == 0, 'asm heap log not supported in fastcomp' + assert shared.Settings.LABEL_DEBUG == 0, 'label debug not supported in fastcomp' + assert shared.Settings.EXECUTION_TIMEOUT == -1, 'execution timeout not supported in fastcomp' + assert shared.Settings.NAMED_GLOBALS == 0, 'named globals not supported in fastcomp' + assert shared.Settings.PGO == 0, 'pgo not supported in fastcomp' + assert shared.Settings.TARGET_ASMJS_UNKNOWN_EMSCRIPTEN == 1, 'fastcomp requires asmjs-unknown-emscripten' + assert shared.Settings.USE_TYPED_ARRAYS == 2, 'altering USE_TYPED_ARRAYS is not supported' + assert shared.Settings.QUANTUM_SIZE == 4, 'altering the QUANTUM_SIZE is not supported' + assert not split_js_file, '--split-js is deprecated and not supported in fastcomp' + assert shared.Settings.INIT_HEAP == 0, 'HEAP_INIT is not supported in fastcomp (and should never be needed except for debugging)' + assert not shared.Settings.RUNTIME_TYPE_INFO, 'RUNTIME_TYPE_INFO is not supported in fastcomp' + assert not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE, 'Linking modules is not supported in fastcomp' + assert not shared.Settings.DLOPEN_SUPPORT, 'dlopen() is not supported yet in fastcomp' + except Exception, e: + logging.error('Compiler settings are incompatible with fastcomp. You can fall back to the older compiler core, although that is not recommended, see http://kripken.github.io/emscripten-site/docs/building_from_source/LLVM-Backend.html') + raise e + + fastcomp_opts = [] + if shared.Settings.NO_EXIT_RUNTIME: + pre_fastcomp_opts += ['-emscripten-no-exit-runtime'] + if not llvm_lto: fastcomp_opts += ['-globalopt', '-globaldce'] + fastcomp_opts += ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt'] + if shared.Settings.DISABLE_EXCEPTION_CATCHING != 1: + fastcomp_opts += ['-enable-emscripten-cxx-exceptions'] + if shared.Settings.DISABLE_EXCEPTION_CATCHING == 2: + fastcomp_opts += ['-emscripten-cxx-exceptions-whitelist=' + ','.join(shared.Settings.EXCEPTION_CATCHING_WHITELIST or ['fake'])] + if shared.Settings.ASYNCIFY: + fastcomp_opts += ['-emscripten-asyncify'] + fastcomp_opts += ['-emscripten-asyncify-functions=' + ','.join(shared.Settings.ASYNCIFY_FUNCTIONS)] + fastcomp_opts += ['-emscripten-asyncify-whitelist=' + ','.join(shared.Settings.ASYNCIFY_WHITELIST)] + + if shared.Settings.CORRECT_SIGNS != 1: + logging.warning('setting CORRECT_SIGNS to 1 for asm.js code generation') + shared.Settings.CORRECT_SIGNS = 1 + if shared.Settings.CORRECT_OVERFLOWS != 1: + logging.warning('setting CORRECT_OVERFLOWS to 1 for asm.js code generation') + shared.Settings.CORRECT_OVERFLOWS = 1 + assert not shared.Settings.PGO, 'cannot run PGO in ASM_JS mode' + + if shared.Settings.SAFE_HEAP and not js_opts: + js_opts = True + logging.warning('enabling js opts for SAFE_HEAP') if shared.Settings.CORRECT_SIGNS >= 2 or shared.Settings.CORRECT_OVERFLOWS >= 2 or shared.Settings.CORRECT_ROUNDINGS >= 2 or shared.Settings.SAFE_HEAP >= 2: debug_level = 4 # must keep debug info to do line-by-line operations @@ -985,9 +978,6 @@ try: shared.Settings.LINKABLE = 1 # TODO: add FORCE_DCE option for the brave people that do want to dce here and in side modules debug_level = max(debug_level, 2) - if not fastcomp and shared.Settings.ASSERTIONS and shared.Settings.ALIASING_FUNCTION_POINTERS: - logging.warning('ALIASING_FUNCTION_POINTERS is on, function pointer comparisons may be invalid across types') - if shared.Settings.EMULATE_FUNCTION_POINTER_CASTS: shared.Settings.ALIASING_FUNCTION_POINTERS = 0 @@ -1037,8 +1027,6 @@ try: if js_opts: shared.Settings.RUNNING_JS_OPTS = 1 - shared.Settings.RUNNING_FASTCOMP = fastcomp - shared.Settings.EMSCRIPTEN_VERSION = shared.EMSCRIPTEN_VERSION shared.Settings.OPT_LEVEL = opt_level shared.Settings.DEBUG_LEVEL = debug_level @@ -1249,30 +1237,26 @@ try: # At minimum remove dead functions etc., this potentially saves a lot in the size of the generated code (and the time to compile it) link_opts += shared.Building.get_safe_internalize() + ['-globaldce'] - if (not save_bc and not fastcomp) or AUTODEBUG: + if AUTODEBUG: # let llvm opt directly emit ll, to skip writing and reading all the bitcode link_opts += ['-S'] shared.Building.llvm_opt(final, link_opts, final + '.link.ll') final = final + '.link.ll' if DEBUG: save_intermediate('linktime', 'll') else: - if fastcomp and not save_bc: + if not save_bc: # Simplify LLVM bitcode for fastcomp link_opts = pre_fastcomp_opts + link_opts + fastcomp_opts shared.Building.llvm_opt(final, link_opts) if DEBUG: save_intermediate('linktime', 'bc') if save_bc: shutil.copyfile(final, save_bc) - if fastcomp: - shared.Building.llvm_opt(final, fastcomp_opts, final + '.adsimp.bc') - final += '.adsimp.bc' - if DEBUG: save_intermediate('adsimp', 'bc') + shared.Building.llvm_opt(final, fastcomp_opts, final + '.adsimp.bc') + final += '.adsimp.bc' + if DEBUG: save_intermediate('adsimp', 'bc') # Prepare .ll for Emscripten - if not LEAVE_INPUTS_RAW: - if save_bc and not fastcomp: - final = shared.Building.llvm_dis(final, final + '.ll') - else: + if LEAVE_INPUTS_RAW: assert len(input_files) == 1 if DEBUG and save_bc: save_intermediate('ll', 'll') @@ -1283,7 +1267,7 @@ try: if DEBUG: save_intermediate('autodebug', 'll') # Simplify bitcode after autodebug - if fastcomp and (AUTODEBUG or LEAVE_INPUTS_RAW): + if AUTODEBUG or LEAVE_INPUTS_RAW: shared.Building.llvm_opt(final, fastcomp_opts, final + '.adsimp.bc') final += '.adsimp.bc' if DEBUG: save_intermediate('adsimp', 'bc') diff --git a/emscripten-version.txt b/emscripten-version.txt index 405669db29794..a59db5df63f1e 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1,2 +1,2 @@ -1.31.1 +1.31.2 diff --git a/site/build/text/docs/tools_reference/emcc.txt b/site/build/text/docs/tools_reference/emcc.txt index 58de454b6af05..ebec0498f7a99 100644 --- a/site/build/text/docs/tools_reference/emcc.txt +++ b/site/build/text/docs/tools_reference/emcc.txt @@ -544,8 +544,6 @@ Environment variables * "EMCC_DEBUG" - * "EMCC_FAST_COMPILER" - Search for 'os.environ' in emcc to see how these are used. The most interesting is possibly "EMCC_DEBUG", which forces the compiler to dump its build and temporary files to a temporary directory where they diff --git a/site/source/docs/building_from_source/LLVM-Backend.rst b/site/source/docs/building_from_source/LLVM-Backend.rst index cc2dea78d4bbb..a7b28863d9143 100644 --- a/site/source/docs/building_from_source/LLVM-Backend.rst +++ b/site/source/docs/building_from_source/LLVM-Backend.rst @@ -82,39 +82,7 @@ Some features that were present in the original compiler that are not present in How to disable Fastcomp ----------------------- -.. warning:: You should **NOT** disable Fastcomp. If you "really must", then: - - - The build will be slower, consume more memory, and result in sub-optimal code. - - There are more likely to be bugs, because the old compiler is less tested. - -The original compiler is still present, and you may want to use it if you need a feature that is not yet present in *Fastcomp*. There should be very few such features, as almost everything that is not deprecated or planned to be rewritten has already been ported. - -However, if you do need to, you can use the old compiler by turning off *Fastcomp*; you do this by setting ``EMCC_FAST_COMPILER=0`` when you build: -:: - - EMCC_FAST_COMPILER=0 emcc [..] - - -When you disable *Fastcomp* you can use **either** a build from the *Fastcomp* repositories, **or** a stock LLVM build. The latter is less tested, but should work in principle: Disabling *Fastcomp* does not use anything new in the *Fastcomp* repo (neither the new backend, nor the new target triple). - -You can check whether *Fastcomp* is enabled by looking at the debug output. For example, run ``EMCC_DEBUG=1 emcc tests/hello_world.c`` — if *Fastcomp* is on, then among the output will be: - -:: - - DEBUG root: emscript: llvm backend: ... - DEBUG root: emscript: llvm backend took - -This debug output shows both the command used to run the backend, and how much time it took. If *Fastcomp* is off on the other hand, the old compiler is used, and you will instead see: - -:: - - DEBUG root: emscript: ll=>js - DEBUG root: emscript: scan took ... - ... - DEBUG root: emcc step "emscript (llvm=>js)" took ... - -This shows that the old compiler (``ll=>js``) is called, as well as how much time each step takes, and the total time. Again, this is the output for the **old** compiler, so hopefully you will never see it! - +Fastcomp is now the only supported compiler and the old compiler has been removed from emscripten. .. _fastcomp-faq: diff --git a/site/source/docs/tools_reference/emcc.rst b/site/source/docs/tools_reference/emcc.rst index 8894040111ffc..8ad0289d69a36 100644 --- a/site/source/docs/tools_reference/emcc.rst +++ b/site/source/docs/tools_reference/emcc.rst @@ -464,7 +464,6 @@ Environment variables - ``EMMAKEN_COMPILER`` - ``EMMAKEN_CFLAGS`` - ``EMCC_DEBUG`` - - ``EMCC_FAST_COMPILER`` Search for 'os.environ' in `emcc `_ to see how these are used. The most interesting is possibly ``EMCC_DEBUG``, which forces the compiler to dump its build and temporary files to a temporary directory where they can be reviewed. diff --git a/src/corruptionCheck.js b/src/corruptionCheck.js deleted file mode 100644 index 8b37120afd20a..0000000000000 --- a/src/corruptionCheck.js +++ /dev/null @@ -1,98 +0,0 @@ - -// See settings.js, CORRUPTION_CHECK - -var CorruptionChecker = { - BUFFER_FACTOR: Math.round({{{ CORRUPTION_CHECK }}}), - - ptrs: {}, - checks: 0, - checkFrequency: 1, - - init: function() { - this.realMalloc = _malloc; - _malloc = Module['_malloc'] = this.malloc; - - this.realFree = _free; - _free = Module['_free'] = this.free; - - if (typeof _realloc != 'undefined') { - this.realRealloc = _realloc; - _realloc = Module['_realloc'] = this.realloc; - } - - __ATEXIT__.push({ func: function() { - Module.printErr('No corruption detected, ran ' + CorruptionChecker.checks + ' checks.'); - } }); - }, - malloc: function(size) { - if (size <= 0) size = 1; // malloc(0) sometimes happens - just allocate a larger area, no harm - CorruptionChecker.checkAll(); - size = (size+7)&(~7); - var allocation = CorruptionChecker.realMalloc(size*(1+2*CorruptionChecker.BUFFER_FACTOR)); - var ptr = allocation + size*CorruptionChecker.BUFFER_FACTOR; - assert(!CorruptionChecker.ptrs[ptr]); - CorruptionChecker.ptrs[ptr] = size; - CorruptionChecker.fillBuffer(allocation, size*CorruptionChecker.BUFFER_FACTOR); - CorruptionChecker.fillBuffer(allocation + size*(1+CorruptionChecker.BUFFER_FACTOR), size*CorruptionChecker.BUFFER_FACTOR); - //Module.printErr('malloc ' + size + ' ==> ' + [ptr, allocation]); - return ptr; - }, - free: function(ptr) { - if (!ptr) return; // ok to free(NULL), does nothing - CorruptionChecker.checkAll(); - var size = CorruptionChecker.ptrs[ptr]; - //Module.printErr('free ' + ptr + ' of size ' + size); - assert(size, ptr); - var allocation = ptr - size*CorruptionChecker.BUFFER_FACTOR; - //Module.printErr('free ' + ptr + ' of size ' + size + ' and allocation ' + allocation); - delete CorruptionChecker.ptrs[ptr]; - CorruptionChecker.realFree(allocation); - }, - realloc: function(ptr, newSize) { - //Module.printErr('realloc ' + ptr + ' to size ' + newSize); - if (newSize <= 0) newSize = 1; // like in malloc - if (!ptr) return CorruptionChecker.malloc(newSize); // realloc(NULL, size) forwards to malloc according to the spec - var size = CorruptionChecker.ptrs[ptr]; - assert(size); - var allocation = ptr - size*CorruptionChecker.BUFFER_FACTOR; - var newPtr = CorruptionChecker.malloc(newSize); - //Module.printErr('realloc ' + ptr + ' to size ' + newSize + ' is now ' + newPtr); - var newAllocation = newPtr + newSize*CorruptionChecker.BUFFER_FACTOR; - HEAPU8.set(HEAPU8.subarray(ptr, ptr + Math.min(size, newSize)), newPtr); - CorruptionChecker.free(ptr); - return newPtr; - }, - canary: function(x) { - return (x&127) + 10; - }, - fillBuffer: function(buffer, size) { - for (var x = buffer; x < buffer + size; x++) { - {{{ makeSetValue('x', 0, 'CorruptionChecker.canary(x)', 'i8', null, null, null, 1) }}}; - } - }, - checkBuffer: function(buffer, size) { - for (var x = buffer; x < buffer + size; x++) { - if (({{{ makeGetValue('x', 0, 'i8', null, null, null, null, 1) }}}&255) != CorruptionChecker.canary(x)) { - assert(0, 'Heap corruption detected!' + [x, buffer, size, {{{ makeGetValue('x', 0, 'i8') }}}&255, CorruptionChecker.canary(x)]); - } - } - }, - checkPtr: function(ptr) { - var size = CorruptionChecker.ptrs[ptr]; - assert(size); - var allocation = ptr - size*CorruptionChecker.BUFFER_FACTOR; - CorruptionChecker.checkBuffer(allocation, size*CorruptionChecker.BUFFER_FACTOR); - CorruptionChecker.checkBuffer(allocation + size*(1+CorruptionChecker.BUFFER_FACTOR), size*CorruptionChecker.BUFFER_FACTOR); - }, - checkAll: function(force) { - CorruptionChecker.checks++; - if (!force && CorruptionChecker.checks % CorruptionChecker.checkFrequency != 0) return; - //Module.printErr('checking for corruption ' + (CorruptionChecker.checks/CorruptionChecker.checkFrequency)); - for (var ptr in CorruptionChecker.ptrs) { - CorruptionChecker.checkPtr(ptr, false); - } - }, -}; - -CorruptionChecker.init(); - diff --git a/src/embind/embind.js b/src/embind/embind.js index e3f8a6904ca19..9d86bef77128a 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -651,18 +651,20 @@ var LibraryEmbind = { 'free', 'malloc', '$readLatin1String', '$registerType', '$simpleReadValueFromPointer'], _embind_register_std_wstring: function(rawType, charSize, name) { + // nb. do not cache HEAPU16 and HEAPU32, they may be destroyed by enlargeMemory(). name = readLatin1String(name); - var HEAP, shift; + var getHeap, shift; if (charSize === 2) { - HEAP = HEAPU16; + getHeap = function() { return HEAPU16; }; shift = 1; } else if (charSize === 4) { - HEAP = HEAPU32; + getHeap = function() { return HEAPU32; }; shift = 2; } registerType(rawType, { name: name, 'fromWireType': function(value) { + var HEAP = getHeap(); var length = HEAPU32[value >> 2]; var a = new Array(length); var start = (value + 4) >> shift; @@ -674,6 +676,7 @@ var LibraryEmbind = { }, 'toWireType': function(destructors, value) { // assumes 4-byte alignment + var HEAP = getHeap(); var length = value.length; var ptr = _malloc(4 + length * charSize); HEAPU32[ptr >> 2] = length; diff --git a/src/jsifier.js b/src/jsifier.js index 41b665626801f..e9d7093661ed0 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -157,7 +157,7 @@ function JSify(data, functionsOnly) { } // In asm, we need to know about library functions. If there is a target, though, then no // need to consider this a library function - we will call directly to it anyhow - if (ASM_JS && !redirectedIdent && (typeof target == 'function' || /Math_\w+/.exec(snippet))) { + if (!redirectedIdent && (typeof target == 'function' || /Math_\w+/.exec(snippet))) { Functions.libraryFunctions[finalName] = 1; } } else if (typeof snippet === 'object') { @@ -165,7 +165,7 @@ function JSify(data, functionsOnly) { } else if (typeof snippet === 'function') { isFunction = true; snippet = processLibraryFunction(snippet, ident, finalName); - if (ASM_JS) Functions.libraryFunctions[finalName] = 1; + Functions.libraryFunctions[finalName] = 1; } var postsetId = ident + '__postset'; @@ -181,31 +181,27 @@ function JSify(data, functionsOnly) { if (redirectedIdent) { deps = deps.concat(LibraryManager.library[redirectedIdent + '__deps'] || []); } - if (ASM_JS) { - // In asm, dependencies implemented in C might be needed by JS library functions. - // We don't know yet if they are implemented in C or not. To be safe, export such - // special cases. - [LIBRARY_DEPS_TO_AUTOEXPORT].forEach(function(special) { - deps.forEach(function(dep) { - if (dep == special && !EXPORTED_FUNCTIONS[dep]) { - EXPORTED_FUNCTIONS[dep] = 1; - } - }); + // In asm, dependencies implemented in C might be needed by JS library functions. + // We don't know yet if they are implemented in C or not. To be safe, export such + // special cases. + [LIBRARY_DEPS_TO_AUTOEXPORT].forEach(function(special) { + deps.forEach(function(dep) { + if (dep == special && !EXPORTED_FUNCTIONS[dep]) { + EXPORTED_FUNCTIONS[dep] = 1; + } }); - } + }); if (VERBOSE) printErr('adding ' + finalName + ' and deps ' + deps + ' : ' + (snippet + '').substr(0, 40)); var depsText = (deps ? '\n' + deps.map(addFromLibrary).filter(function(x) { return x != '' }).join('\n') : ''); var contentText = isFunction ? snippet : ('var ' + finalName + '=' + snippet + ';'); - if (ASM_JS) { - var sig = LibraryManager.library[ident + '__sig']; - if (isFunction && sig && LibraryManager.library[ident + '__asm']) { - // asm library function, add it as generated code alongside the generated code - Functions.implementedFunctions[finalName] = sig; - asmLibraryFunctions.push(contentText); - contentText = ' '; - EXPORTED_FUNCTIONS[finalName] = 1; - Functions.libraryFunctions[finalName] = 2; - } + var sig = LibraryManager.library[ident + '__sig']; + if (isFunction && sig && LibraryManager.library[ident + '__asm']) { + // asm library function, add it as generated code alongside the generated code + Functions.implementedFunctions[finalName] = sig; + asmLibraryFunctions.push(contentText); + contentText = ' '; + EXPORTED_FUNCTIONS[finalName] = 1; + Functions.libraryFunctions[finalName] = 2; } if (SIDE_MODULE) return ';'; // we import into the side module js library stuff from the outside parent if ((phase == 'glue') && @@ -421,10 +417,6 @@ function JSify(data, functionsOnly) { print('var i64Math = null;'); } - if (CORRUPTION_CHECK) { - assert(!ASM_JS, 'corruption checker is not compatible with asm.js'); - print(processMacros(read('corruptionCheck.js'))); - } if (HEADLESS) { print('if (!ENVIRONMENT_IS_WEB) {'); print(read('headlessCanvas.js')); diff --git a/src/library.js b/src/library.js index 0350700e8cc11..fd9c3b6b2ec5f 100644 --- a/src/library.js +++ b/src/library.js @@ -2991,11 +2991,6 @@ LibraryManager.library = { memcpy__inline: function(dest, src, num, align) { var ret = ''; -#if ASSERTIONS -#if ASM_JS == 0 - ret += "assert(" + num + " % 1 === 0);"; //, 'memcpy given ' + " + num + " + ' bytes to copy. Problem with quantum=1 corrections perhaps?');"; -#endif -#endif ret += makeCopyValues(dest, src, num, 'null', null, align); return ret; }, @@ -3548,11 +3543,7 @@ LibraryManager.library = { return; } // Clear state flag. -#if ASM_JS asm['setThrew'](0); -#else - __THREW__ = 0; -#endif // Call destructor if one is registered then clear it. var ptr = EXCEPTIONS.caught.pop(); #if EXCEPTION_DEBUG @@ -4102,10 +4093,8 @@ LibraryManager.library = { // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlopen.html filename = filename === 0 ? '__self__' : (ENV['LD_LIBRARY_PATH'] || '/') + Pointer_stringify(filename); -#if ASM_JS #if DLOPEN_SUPPORT == 0 abort('need to build with DLOPEN_SUPPORT=1 to get dlopen support in asm.js'); -#endif #endif if (DLFCN.loadedLibNames[filename]) { @@ -4131,11 +4120,7 @@ LibraryManager.library = { try { var lib_module = eval(lib_data)( -#if ASM_JS DLFCN.functionTable.length, -#else - {{{ Functions.getTable('x') }}}.length, -#endif Module ); } catch (e) { @@ -4217,12 +4202,8 @@ LibraryManager.library = { } else { var result = lib.module[symbol]; if (typeof result == 'function') { -#if ASM_JS result = lib.module.SYMBOL_TABLE[symbol]; assert(result); -#else - result = Runtime.addFunction(result); -#endif lib.cached_functions = result; } return result; @@ -5294,28 +5275,16 @@ LibraryManager.library = { return 0; }, -#if ASM_JS setjmp__deps: ['saveSetjmp', 'testSetjmp'], -#endif setjmp__inline: function(env) { // Save the label -#if ASM_JS return '_saveSetjmp(' + env + ', label, setjmpTable)|0'; -#else - return '(tempInt = setjmpId++, mySetjmpIds[tempInt] = 1, setjmpLabels[tempInt] = label,' + makeSetValue(env, '0', 'tempInt', 'i32', undefined, undefined, undefined, undefined, ',') + ', 0)'; -#endif }, -#if ASM_JS longjmp__deps: ['saveSetjmp', 'testSetjmp'], -#endif longjmp: function(env, value) { -#if ASM_JS asm['setThrew'](env, value || 1); throw 'longjmp'; -#else - throw { longjmp: true, id: {{{ makeGetValue('env', '0', 'i32') }}}, value: value || 1 }; -#endif }, emscripten_longjmp__deps: ['longjmp'], emscripten_longjmp: function(env, value) { @@ -8037,32 +8006,6 @@ LibraryManager.library = { return cache[fullname] = allocate(intArrayFromString(ret + ''), 'i8', ALLOC_NORMAL); }, -#if RUNNING_FASTCOMP == 0 -#if ASM_JS -#if ALLOW_MEMORY_GROWTH - emscripten_replace_memory__asm: true, // this is used inside the asm module - emscripten_replace_memory__sig: 'viiiiiiii', // bogus - emscripten_replace_memory: function(newBuffer) { - if ((byteLength(newBuffer) & 0xffff) || byteLength(newBuffer) < 0xffff) return false; - HEAP8 = new Int8View(newBuffer); - HEAP16 = new Int16View(newBuffer); - HEAP32 = new Int32View(newBuffer); - HEAPU8 = new Uint8View(newBuffer); - HEAPU16 = new Uint16View(newBuffer); - HEAPU32 = new Uint32View(newBuffer); - HEAPF32 = new Float32View(newBuffer); - HEAPF64 = new Float64View(newBuffer); - buffer = newBuffer; - return true; - }, - // this function is inside the asm block, but prevents validation as asm.js - // the codebase still benefits from being in the general asm.js shape, - // but should not declare itself as validating (which is prevented in ASM_JS == 2). - {{{ (assert(ASM_JS === 2), DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push('emscripten_replace_memory'), '') }}} -#endif -#endif -#endif - emscripten_debugger: function() { debugger; }, diff --git a/src/modules.js b/src/modules.js index 57f91f2241893..9abe198f07594 100644 --- a/src/modules.js +++ b/src/modules.js @@ -238,7 +238,7 @@ var Types = { preciseI64MathUsed: (PRECISE_I64_MATH == 2) }; -var firstTableIndex = FUNCTION_POINTER_ALIGNMENT * ((ASM_JS ? RESERVED_FUNCTION_POINTERS : 0) + 1); +var firstTableIndex = FUNCTION_POINTER_ALIGNMENT * RESERVED_FUNCTION_POINTERS + 1; var Functions = { // All functions that will be implemented in this file. Maps id to signature @@ -316,19 +316,17 @@ var Functions = { }, getTable: function(sig) { - return ASM_JS ? 'FUNCTION_TABLE_' + sig : 'FUNCTION_TABLE'; + return 'FUNCTION_TABLE_' + sig }, // Generate code for function indexing generateIndexing: function() { var tables = { pre: '' }; - if (ASM_JS) { - keys(Functions.neededTables).forEach(function(sig) { // add some default signatures that are used in the library - tables[sig] = zeros(firstTableIndex); - }); - } + keys(Functions.neededTables).forEach(function(sig) { // add some default signatures that are used in the library + tables[sig] = zeros(firstTableIndex); + }); for (var ident in this.indexedFunctions) { - var sig = ASM_JS ? Functions.implementedFunctions[ident] || Functions.unimplementedFunctions[ident] || LibraryManager.library[ident.substr(1) + '__sig'] : 'x'; + var sig = Functions.implementedFunctions[ident] || Functions.unimplementedFunctions[ident] || LibraryManager.library[ident.substr(1) + '__sig']; assert(sig, ident); if (!tables[sig]) tables[sig] = zeros(firstTableIndex); var index = this.indexedFunctions[ident]; @@ -358,43 +356,41 @@ var Functions = { table[i] = (libName.indexOf('Math_') < 0 ? '_' : '') + libName; } } - if (ASM_JS) { - var curr = table[i]; - if (curr && curr != '0' && !Functions.implementedFunctions[curr]) { - var short = toNiceIdent(curr); // fix Math.* to Math_* - curr = t + '_' + short; // libfuncs can alias with different sigs, wrap each separately - // This is a library function, we can't just put it in the function table, need a wrapper - if (!wrapped[curr]) { - var args = '', arg_coercions = '', call = short + '(', retPre = '', retPost = ''; - if (t[0] != 'v') { - var temp = asmFFICoercion('X', Functions.getSignatureType(t[0])).split('X'); - retPre = 'return ' + temp[0]; - retPost = temp[1]; - } - for (var j = 1; j < t.length; j++) { - args += (j > 1 ? ',' : '') + 'a' + j; - var type = Functions.getSignatureType(t[j]); - arg_coercions += 'a' + j + '=' + asmCoercion('a' + j, type) + ';'; - call += (j > 1 ? ',' : '') + asmCoercion('a' + j, type === 'float' ? 'double' : type); // ffi arguments must be doubles if they are floats - } - call += ')'; - if (short == '_setjmp') printErr('WARNING: setjmp used via a function pointer. If this is for libc setjmp (not something of your own with the same name), it will break things'); - tables.pre += 'function ' + curr + '__wrapper(' + args + ') { ' + arg_coercions + ' ; ' + retPre + call + retPost + ' }\n'; - wrapped[curr] = 1; + var curr = table[i]; + if (curr && curr != '0' && !Functions.implementedFunctions[curr]) { + var short = toNiceIdent(curr); // fix Math.* to Math_* + curr = t + '_' + short; // libfuncs can alias with different sigs, wrap each separately + // This is a library function, we can't just put it in the function table, need a wrapper + if (!wrapped[curr]) { + var args = '', arg_coercions = '', call = short + '(', retPre = '', retPost = ''; + if (t[0] != 'v') { + var temp = asmFFICoercion('X', Functions.getSignatureType(t[0])).split('X'); + retPre = 'return ' + temp[0]; + retPost = temp[1]; } - table[i] = curr + '__wrapper'; + for (var j = 1; j < t.length; j++) { + args += (j > 1 ? ',' : '') + 'a' + j; + var type = Functions.getSignatureType(t[j]); + arg_coercions += 'a' + j + '=' + asmCoercion('a' + j, type) + ';'; + call += (j > 1 ? ',' : '') + asmCoercion('a' + j, type === 'float' ? 'double' : type); // ffi arguments must be doubles if they are floats + } + call += ')'; + if (short == '_setjmp') printErr('WARNING: setjmp used via a function pointer. If this is for libc setjmp (not something of your own with the same name), it will break things'); + tables.pre += 'function ' + curr + '__wrapper(' + args + ') { ' + arg_coercions + ' ; ' + retPre + call + retPost + ' }\n'; + wrapped[curr] = 1; } + table[i] = curr + '__wrapper'; } } maxTable = Math.max(maxTable, table.length); } - if (ASM_JS) maxTable = ceilPowerOfTwo(maxTable); + maxTable = ceilPowerOfTwo(maxTable); for (var t in tables) { if (t == 'pre') continue; var table = tables[t]; // asm function table mask must be power of two, and non-asm must be aligned // if nonaliasing, then standardize function table size, to avoid aliasing pointers through the &M mask (in a small table using a big index) - var fullSize = ASM_JS ? (ALIASING_FUNCTION_POINTERS ? ceilPowerOfTwo(table.length) : maxTable) : ((table.length+FUNCTION_POINTER_ALIGNMENT-1)&-FUNCTION_POINTER_ALIGNMENT); + var fullSize = ALIASING_FUNCTION_POINTERS ? ceilPowerOfTwo(table.length) : maxTable; for (var i = table.length; i < fullSize; i++) { table[i] = 0; } @@ -410,9 +406,6 @@ var Functions = { } } } - if (!generated && !ASM_JS) { - tables['x'] = 'var FUNCTION_TABLE = [0, 0];\n'; // default empty table - } Functions.tables = tables; } }; @@ -575,7 +568,7 @@ var PassManager = { Functions: { blockAddresses: Functions.blockAddresses, indexedFunctions: Functions.indexedFunctions, - implementedFunctions: ASM_JS ? Functions.implementedFunctions : [], + implementedFunctions: Functions.implementedFunctions, unimplementedFunctions: Functions.unimplementedFunctions, neededTables: Functions.neededTables } diff --git a/src/parseTools.js b/src/parseTools.js index 3c61b5c9f6b2e..358fa5056a4d1 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -548,7 +548,7 @@ function splitI64(value, floatConversion) { // For negatives, we need to ensure a -1 if the value is overall negative, even if not significant negative component var lowInput = legalizedI64s ? value : 'VALUE'; - if (floatConversion && ASM_JS) lowInput = asmFloatToInt(lowInput); + if (floatConversion) lowInput = asmFloatToInt(lowInput); var low = lowInput + '>>>0'; var high = makeInlineCalculation( asmCoercion('Math_abs(VALUE)', 'double') + ' >= ' + asmEnsureFloat('1', 'double') + ' ? ' + @@ -903,11 +903,6 @@ function getHeapOffset(offset, type, forceAsm) { } } -function makeVarDef(js) { - if (!ASM_JS) js = 'var ' + js; - return js; -} - function ensureDot(value) { value = value.toString(); // if already dotted, or Infinity or NaN, nothing to do here @@ -920,7 +915,6 @@ function ensureDot(value) { } function asmEnsureFloat(value, type) { // ensures that a float type has either 5.5 (clearly a float) or +5 (float due to asm coercion) - if (!ASM_JS) return value; if (!isNumber(value)) return value; if (PRECISE_F32 && type === 'float') { // normally ok to just emit Math_fround(0), but if the constant is large we may need a .0 (if it can't fit in an int) @@ -945,7 +939,6 @@ function asmInitializer(type) { } function asmCoercion(value, type, signedness) { - if (!ASM_JS) return value; if (type == 'void') { return value; } else if (type in Compiletime.FLOAT_TYPES) { @@ -1053,15 +1046,12 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa var printType = type; if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"'; if (printType[0] === '#') printType = printType.substr(1); - if (ASM_JS) { - if (!ignore && phase !== 'funcs') return asmCoercion('SAFE_HEAP_LOAD(' + asmCoercion(offset, 'i32') + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Compiletime.FLOAT_TYPES)|0) + ', ' + (!!unsigned+0) + ')', type); - // else fall through - } else { - return asmCoercion('SAFE_HEAP_LOAD(' + offset + ', ' + (ASM_JS ? 0 : printType) + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')', type); + if (!ignore && phase !== 'funcs') { + return asmCoercion('SAFE_HEAP_LOAD(' + asmCoercion(offset, 'i32') + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Compiletime.FLOAT_TYPES)|0) + ', ' + (!!unsigned+0) + ')', type); } } var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type, forceAsm) + ']'; - if (ASM_JS && (phase == 'funcs' || forceAsm)) { + if (phase == 'funcs' || forceAsm) { ret = asmCoercion(ret, type); } if (ASM_HEAP_LOG) { @@ -1165,11 +1155,8 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, var printType = type; if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"'; if (printType[0] === '#') printType = printType.substr(1); - if (ASM_JS) { - if (!ignore && phase !== 'funcs') return asmCoercion('SAFE_HEAP_STORE(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Compiletime.FLOAT_TYPES)|0) + ')', type); - // else fall through - } else { - return 'SAFE_HEAP_STORE(' + offset + ', ' + value + ', ' + (ASM_JS ? 0 : printType) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')'; + if (!ignore && phase !== 'funcs') { + return asmCoercion('SAFE_HEAP_STORE(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Compiletime.FLOAT_TYPES)|0) + ')', type); } } return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type, forceAsm) + ']=' + value }).join(sep); @@ -1231,10 +1218,8 @@ function makeCopyValues(dest, src, num, type, modifier, align, sep) { return '(_memcpy(' + dest + ', ' + src + ', ' + num + ')|0)'; } num = parseInt(num); - if (ASM_JS) { - dest = stripCorrections(dest); // remove corrections, since we will be correcting after we add anyhow, - src = stripCorrections(src); // and in the heap assignment expression - } + dest = stripCorrections(dest); // remove corrections, since we will be correcting after we add anyhow, + src = stripCorrections(src); // and in the heap assignment expression var ret = []; [4, 2, 1].forEach(function(possibleAlign) { if (num == 0) return; @@ -1494,8 +1479,7 @@ function makeStructuralReturn(values, inAsm) { var i = -1; return 'return ' + asmCoercion(values.slice(1).map(function(value) { i++; - return ASM_JS ? (inAsm ? 'tempRet' + i + ' = ' + value : 'asm["setTempRet' + i + '"](' + value + ')') - : 'tempRet' + i + ' = ' + value; + return inAsm ? 'tempRet' + i + ' = ' + value : 'asm["setTempRet' + i + '"](' + value + ')'; }).concat([values[0]]).join(','), 'i32'); } diff --git a/src/preamble.js b/src/preamble.js index f40f88c227db2..030f99cc5f5f8 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -26,112 +26,6 @@ Module.print = Module.printErr = function(){}; #endif #if SAFE_HEAP -#if ASM_JS == 0 -//======================================== -// Debugging tools - Heap -//======================================== -var HEAP_WATCHED = []; -var HEAP_HISTORY = []; -function SAFE_HEAP_CLEAR(dest) { -#if SAFE_HEAP_LOG - Module.print('SAFE_HEAP clear: ' + dest); -#endif - HEAP_HISTORY[dest] = undefined; -} -var SAFE_HEAP_ERRORS = 0; -var ACCEPTABLE_SAFE_HEAP_ERRORS = 0; - -function SAFE_HEAP_ACCESS(dest, type, store, ignore, storeValue) { - //if (dest === A_NUMBER) Module.print ([dest, type, store, ignore, storeValue] + ' ' + stackTrace()); // Something like this may be useful, in debugging - - if (dest <= 0) abort('segmentation fault ' + (store ? ('storing value ' + storeValue) : 'loading') + ' type ' + type + ' at address ' + dest); - - // When using typed arrays, reads over the top of TOTAL_MEMORY will fail silently, so we must - // correct that by growing TOTAL_MEMORY as needed. Without typed arrays, memory is a normal - // JS array so it will work (potentially slowly, depending on the engine). - if (!ignore && dest >= Math.max(DYNAMICTOP, STATICTOP)) abort('segmentation fault ' + (store ? ('storing value ' + storeValue) : 'loading') + ' type ' + type + ' at address ' + dest + '. Heap ends at address ' + Math.max(DYNAMICTOP, STATICTOP)); - assert(ignore || DYNAMICTOP <= TOTAL_MEMORY); - return; // It is legitimate to violate the load-store assumption in this case -} - -function SAFE_HEAP_STORE(dest, value, type, ignore) { -#if SAFE_HEAP_LOG - Module.print('SAFE_HEAP store: ' + [dest, type, value, ignore]); -#endif - - if (!ignore && !value && (value === null || value === undefined)) { - throw('Warning: Writing an invalid value of ' + JSON.stringify(value) + ' at ' + dest + ' :: ' + stackTrace() + '\n'); - } - //if (!ignore && (value === Infinity || value === -Infinity || isNaN(value))) throw [value, typeof value, stackTrace()]; - - SAFE_HEAP_ACCESS(dest, type, true, ignore, value); - if (dest in HEAP_WATCHED) { - Module.print((new Error()).stack); - throw "Bad store!" + dest; - } - - // Check alignment - switch(type) { - case 'i16': assert(dest % 2 == 0); break; - case 'i32': assert(dest % 4 == 0); break; - case 'i64': assert(dest % 8 == 0); break; - case 'float': assert(dest % 4 == 0); break; -#if DOUBLE_MODE == 1 - case 'double': assert(dest % 4 == 0); break; -#else - case 'double': assert(dest % 4 == 0); break; -#endif - } - - setValue(dest, value, type, 1); -} - -function SAFE_HEAP_LOAD(dest, type, unsigned, ignore) { - SAFE_HEAP_ACCESS(dest, type, false, ignore); - -#if SAFE_HEAP_LOG - Module.print('SAFE_HEAP load: ' + [dest, type, getValue(dest, type, 1), ignore]); -#endif - - // Check alignment - switch(type) { - case 'i16': assert(dest % 2 == 0); break; - case 'i32': assert(dest % 4 == 0); break; - case 'i64': assert(dest % 8 == 0); break; - case 'float': assert(dest % 4 == 0); break; -#if DOUBLE_MODE == 1 - case 'double': assert(dest % 4 == 0); break; -#else - case 'double': assert(dest % 4 == 0); break; -#endif - } - - var ret = getValue(dest, type, 1); - if (unsigned) ret = unSign(ret, parseInt(type.substr(1)), 1); - return ret; -} - -function SAFE_HEAP_COPY_HISTORY(dest, src) { -#if SAFE_HEAP_LOG - Module.print('SAFE_HEAP copy: ' + [dest, src]); -#endif - HEAP_HISTORY[dest] = HEAP_HISTORY[src]; - SAFE_HEAP_ACCESS(dest, HEAP_HISTORY[dest] || null, true, false); -} - -function SAFE_HEAP_FILL_HISTORY(from, to, type) { -#if SAFE_HEAP_LOG - Module.print('SAFE_HEAP fill: ' + [from, to, type]); -#endif - for (var i = from; i < to; i++) { - HEAP_HISTORY[i] = type; - } -} - -//========================================== -#else -// ASM_JS safe heap - function getSafeHeapType(bytes, isFloat) { switch (bytes) { case 1: return 'i8'; @@ -178,8 +72,6 @@ function SAFE_FT_MASK(value, mask) { } return ret; } - -#endif #endif #if CHECK_HEAP_ALIGN @@ -249,10 +141,6 @@ var START_TIME = Date.now(); //======================================== var __THREW__ = 0; // Used in checking for thrown exceptions. -#if ASM_JS == 0 -var setjmpId = 1; // Used in setjmp/longjmp -var setjmpLabels = {}; -#endif var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort() var EXITSTATUS = 0; diff --git a/src/runtime.js b/src/runtime.js index a5efd53f2867b..c2e7b62c62534 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -32,7 +32,7 @@ var RuntimeGenerator = { stackEnter: function(initial, force) { if (initial === 0 && SKIP_STACK_IN_SMALL && !force) return ''; - var ret = 'var sp=' + (ASM_JS ? '0;sp=' : '') + 'STACKTOP'; + var ret = 'var sp=0;sp=STACKTOP'; if (initial > 0) ret += ';STACKTOP=(STACKTOP+' + initial + ')|0'; assert(initial % Runtime.STACK_ALIGN == 0); if (ASSERTIONS && Runtime.STACK_ALIGN == 4) { @@ -46,11 +46,7 @@ var RuntimeGenerator = { stackExit: function(initial, force) { if (initial === 0 && SKIP_STACK_IN_SMALL && !force) return ''; - var ret = ''; - if (SAFE_HEAP && !ASM_JS) { - ret += 'var i = sp; while ((i|0) < (STACKTOP|0)) { SAFE_HEAP_CLEAR(i|0); i = (i+1)|0 }'; - } - return ret += 'STACKTOP=sp'; + return 'STACKTOP=sp'; }, // An allocation that cannot normally be free'd (except through sbrk, which once @@ -133,25 +129,6 @@ var Runtime = { STACKTOP = stackTop; }, -#if RUNNING_FASTCOMP == 0 - // Imprecise bitops utilities - or64: function(x, y) { - var l = (x | 0) | (y | 0); - var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296; - return l + h; - }, - and64: function(x, y) { - var l = (x | 0) & (y | 0); - var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296; - return l + h; - }, - xor64: function(x, y) { - var l = (x | 0) ^ (y | 0); - var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296; - return l + h; - }, -#endif - //! Returns the size of a type, as C/C++ would have it (in 32-bit), in bytes. //! @param type The type, by name. getNativeTypeSize: function(type) { @@ -187,10 +164,6 @@ var Runtime = { return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE); }, -#if RUNNING_FASTCOMP == 0 - dedup: dedup, -#endif - STACK_ALIGN: {{{ STACK_ALIGN }}}, // This must be called before reading a double or i64 vararg. It will bump the pointer properly. @@ -221,177 +194,31 @@ var Runtime = { return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE); }, -#if RUNNING_FASTCOMP == 0 - // Calculate aligned size, just like C structs should be. TODO: Consider - // requesting that compilation be done with #pragma pack(push) /n #pragma pack(1), - // which would remove much of the complexity here. - calculateStructAlignment: function calculateStructAlignment(type) { - type.flatSize = 0; - type.alignSize = 0; - var diffs = []; - var prev = -1; - var index = 0; - type.flatIndexes = type.fields.map(function(field) { - index++; - var size, alignSize; - if (Compiletime.isNumberType(field) || Compiletime.isPointerType(field)) { - size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s. - alignSize = Runtime.getAlignSize(field, size); - } else if (Compiletime.isStructType(field)) { - if (field[1] === '0') { - // this is [0 x something]. When inside another structure like here, it must be at the end, - // and it adds no size - // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!'); - size = 0; - if (Types.types[field]) { - alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize); - } else { - alignSize = type.alignSize || QUANTUM_SIZE; - } - } else { - size = Types.types[field].flatSize; - alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize); - } - } else if (field[0] == 'b') { - // bN, large number field, like a [N x i8] - size = field.substr(1)|0; - alignSize = 1; - } else if (field[0] === '<') { - // vector type - size = alignSize = Types.types[field].flatSize; // fully aligned - } else if (field[0] === 'i') { - // illegal integer field, that could not be legalized because it is an internal structure field - // it is ok to have such fields, if we just use them as markers of field size and nothing more complex - size = alignSize = parseInt(field.substr(1))/8; - assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field); - } else { - assert(false, 'invalid type for calculateStructAlignment'); - } - if (type.packed) alignSize = 1; - type.alignSize = Math.max(type.alignSize, alignSize); - var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory - type.flatSize = curr + size; - if (prev >= 0) { - diffs.push(curr-prev); - } - prev = curr; - return curr; - }); - if (type.name_ && type.name_[0] === '[') { - // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid - // allocating a potentially huge array for [999999 x i8] etc. - type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2; - } - type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize); - if (diffs.length == 0) { - type.flatFactor = type.flatSize; - } else if (Runtime.dedup(diffs).length == 1) { - type.flatFactor = diffs[0]; - } - type.needsFlattening = (type.flatFactor != 1); - return type.flatIndexes; - }, - - // Given details about a structure, returns its alignment. For example, - // generateStructInfo( - // [ - // ['i32', 'field1'], - // ['i8', 'field2'] - // ] - // ) will return - // { field1: 0, field2: 4 } (depending on QUANTUM_SIZE) - // - // Instead of [type, name], you can also provide just [name]. In that case - // it will use type information present in LLVM bitcode. (It is safer to - // specify the type though, as it will then check the type.) You must then - // also specify the second parameter to generateStructInfo, which is the - // LLVM structure name. - // - // Note that LLVM optimizations can remove some of the debug info generated - // by -g. - // - // Note that you will need the full %struct.* name here at compile time, - // but not at runtime. The reason is that during compilation we cannot - // simplify the type names yet. At runtime, you can provide either the short - // or the full name. - // - // When providing a typeName, you can generate information for nested - // structs, for example, struct = ['field1', { field2: ['sub1', 'sub2', 'sub3'] }, 'field3'] - // which represents a structure whose 2nd field is another structure. - generateStructInfo: function(struct, typeName, offset) { - var type, alignment; - if (typeName) { - offset = offset || 0; - type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName]; - if (!type) return null; - if (type.fields.length != struct.length) { - printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo'); - return null; - } - alignment = type.flatIndexes; - } else { - var type = { fields: struct.map(function(item) { return item[0] }) }; - alignment = Runtime.calculateStructAlignment(type); - } - var ret = { - __size__: type.flatSize - }; - if (typeName) { - struct.forEach(function(item, i) { - if (typeof item === 'string') { - ret[item] = alignment[i] + offset; - } else { - // embedded struct - var key; - for (var k in item) key = k; - ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]); - } - }); - } else { - struct.forEach(function(item, i) { - ret[item[1]] = alignment[i]; - }); - } - return ret; - }, -#endif - dynCall: function(sig, ptr, args) { if (args && args.length) { #if ASSERTIONS assert(args.length == sig.length-1); #endif -#if ASM_JS if (!args.splice) args = Array.prototype.slice.call(args); args.splice(0, 0, ptr); #if ASSERTIONS assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\''); #endif return Module['dynCall_' + sig].apply(null, args); -#else - return FUNCTION_TABLE[ptr].apply(null, args); -#endif } else { #if ASSERTIONS assert(sig.length == 1); #endif -#if ASM_JS #if ASSERTIONS assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\''); #endif return Module['dynCall_' + sig].call(null, ptr); -#else - return FUNCTION_TABLE[ptr](); -#endif } }, -#if ASM_JS functionPointers: new Array(RESERVED_FUNCTION_POINTERS), -#endif addFunction: function(func) { -#if ASM_JS for (var i = 0; i < Runtime.functionPointers.length; i++) { if (!Runtime.functionPointers[i]) { Runtime.functionPointers[i] = func; @@ -399,23 +226,10 @@ var Runtime = { } } throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.'; -#else - var table = FUNCTION_TABLE; - var ret = table.length; - assert(ret % {{{ FUNCTION_POINTER_ALIGNMENT }}} === 0); - table.push(func); - for (var i = 0; i < {{{ FUNCTION_POINTER_ALIGNMENT }}}-1; i++) table.push(0); - return ret; -#endif }, removeFunction: function(index) { -#if ASM_JS Runtime.functionPointers[(index-{{{ FUNCTION_POINTER_ALIGNMENT }}})/{{{ FUNCTION_POINTER_ALIGNMENT }}}] = null; -#else - var table = FUNCTION_TABLE; - table[index] = null; -#endif }, asmConsts: [], diff --git a/src/settings.js b/src/settings.js index 8246c7dd36f9a..5b06c58483cec 100644 --- a/src/settings.js +++ b/src/settings.js @@ -211,16 +211,6 @@ var FUNCTION_POINTER_ALIGNMENT = 2; // Byte alignment of function pointers - we var ASM_HEAP_LOG = 0; // Simple heap logging, like SAFE_HEAP_LOG but cheaper, and in asm.js -var CORRUPTION_CHECK = 0; // When enabled, will emit a buffer area at the beginning and - // end of each allocation on the heap, filled with canary - // values that can be checked later. Corruption is checked for - // at the end of each at each free() (see jsifier to add more, and you - // can add more manual checks by calling CorruptionChecker.checkAll). - // 0 means not enabled, higher values mean the size of the - // buffer areas as a multiple of the allocated area (so - // 1 means 100%, or buffer areas equal to allocated area, - // both before and after). This must be an integer. - var LABEL_DEBUG = 0; // 1: Print out functions as we enter them // 2: Also print out each label as we enter it var LABEL_FUNCTION_FILTERS = []; // Filters for function label debug. @@ -582,7 +572,6 @@ var EMTERPRETIFY_ADVISE = 0; // Performs a static analysis to suggest which func // when you use the list, it might not work. var RUNNING_JS_OPTS = 0; // whether js opts will be run, after the main compiler -var RUNNING_FASTCOMP = 1; // whether we are running the fastcomp backend var BOOTSTRAPPING_STRUCT_INFO = 0; // whether we are in the generate struct_info bootstrap phase var COMPILER_ASSERTIONS = 0; // costly (slow) compile-time assertions diff --git a/tests/core/test_corruption_2.in b/tests/core/test_corruption_2.in deleted file mode 100644 index 4db3b7c420a2c..0000000000000 --- a/tests/core/test_corruption_2.in +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include -#include - -void bye() { printf("all ok\n"); } - -int main() { - atexit(bye); - - std::string testPath = "/Script/WA-KA.txt"; - std::fstream str(testPath.c_str(), std::ios::in | std::ios::binary); - - if (str.is_open()) { - std::cout << "open!" << std::endl; - } else { - std::cout << "missing!" << std::endl; - } - - return 1; -} diff --git a/tests/core/test_corruption_2.out b/tests/core/test_corruption_2.out deleted file mode 100644 index 26795dbaab7c5..0000000000000 --- a/tests/core/test_corruption_2.out +++ /dev/null @@ -1,2 +0,0 @@ -missing! -all ok diff --git a/tests/core/test_corruption_3.in b/tests/core/test_corruption_3.in deleted file mode 100644 index 08e7d345d97d3..0000000000000 --- a/tests/core/test_corruption_3.in +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include -#include - -void bye() { printf("all ok\n"); } - -int main(int argc, char **argv) { - atexit(bye); - - char *buffer = (char *)malloc(100); - for (int i = 0; i < 100; i++) buffer[i] = (i * i) % 256; - buffer = (char *)realloc(buffer, argc + 50); - for (int i = 0; i < argc + 50; i++) { - // printf("%d : %d : %d : %d\n", i, (int)(buffer + i), buffer[i], - // (char)((i*i)%256)); - assert(buffer[i] == (char)((i * i) % 256)); - } - return 1; -} diff --git a/tests/core/test_corruption_3.out b/tests/core/test_corruption_3.out deleted file mode 100644 index d48ce72996491..0000000000000 --- a/tests/core/test_corruption_3.out +++ /dev/null @@ -1 +0,0 @@ -all ok diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 8cbbafb716077..0500803697fb5 100644 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -442,6 +442,14 @@ module({ String.fromCharCode(65535); assert.equal(expected, cm.take_and_return_std_wstring(expected)); }); + + if (cm.isMemoryGrowthEnabled) { + test("can access a literal wstring after a memory growth", function() { + cm.force_memory_growth(); + assert.equal("get_literal_wstring", cm.get_literal_wstring()); + }); + } + }); BaseFixture.extend("embind", function() { diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 8bda11000fb4e..48582b781e387 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -121,6 +121,15 @@ std::wstring get_non_ascii_wstring() { return ws; } +std::wstring get_literal_wstring() { + return L"get_literal_wstring"; +} + +void force_memory_growth() { + auto heapu8 = val::global("Module")["HEAPU8"]; + delete [] new char[heapu8["byteLength"].as() + 1]; +} + std::string emval_test_take_and_return_const_char_star(const char* str) { return str; } @@ -1657,6 +1666,9 @@ EMSCRIPTEN_BINDINGS(tests) { function("get_non_ascii_string", &get_non_ascii_string); function("get_non_ascii_wstring", &get_non_ascii_wstring); + function("get_literal_wstring", &get_literal_wstring); + function("force_memory_growth", &force_memory_growth); + //function("emval_test_take_and_return_const_char_star", &emval_test_take_and_return_const_char_star); function("emval_test_take_and_return_std_string", &emval_test_take_and_return_std_string); function("emval_test_take_and_return_std_string_const_ref", &emval_test_take_and_return_std_string_const_ref); diff --git a/tests/embind/isMemoryGrowthEnabled=true.cpp b/tests/embind/isMemoryGrowthEnabled=true.cpp new file mode 100644 index 0000000000000..91dee4255800b --- /dev/null +++ b/tests/embind/isMemoryGrowthEnabled=true.cpp @@ -0,0 +1,7 @@ +#include + +using namespace emscripten; + +EMSCRIPTEN_BINDINGS(settings) { + constant("isMemoryGrowthEnabled", true); +} diff --git a/tests/test_core.py b/tests/test_core.py index 63e0bafcf1c20..76d0e31d0eb41 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5712,57 +5712,6 @@ def test_autodebug(self): ''' self.do_run(src, '''AD:-1,1''', build_ll_hook=self.do_autodebug) - def test_corruption(self): - if Settings.ASM_JS: return self.skip('cannot use corruption checks in asm') - - Settings.CORRUPTION_CHECK = 1 - - src = r''' - #include - #include - #include - int main(int argc, char **argv) { - int size = 1024*argc; - char *buffer = (char*)malloc(size); - #if CORRUPT - memset(buffer, argc, size+15); - #else - memset(buffer, argc, size); - #endif - for (int x = 0; x < size; x += argc*3) buffer[x] = x/3; - int ret = 0; - for (int x = 0; x < size; x++) ret += buffer[x]; - free(buffer); - printf("All ok, %d\n", ret); - } - ''' - - for corrupt in [1]: - self.do_run(src.replace('CORRUPT', str(corrupt)), 'Heap corruption detected!' if corrupt else 'All ok, 4209') - - def test_corruption_2(self): - if Settings.ASM_JS: return self.skip('cannot use corruption checks in asm') - - Settings.SAFE_HEAP = 1 - Settings.CORRUPTION_CHECK = 1 - - # test for free(0), malloc(0), etc. - test_path = path_from_root('tests', 'core', 'test_corruption_2') - src, output = (test_path + s for s in ('.in', '.out')) - - self.do_run_from_file(src, output) - - def test_corruption_3(self): - if Settings.ASM_JS: return self.skip('cannot use corruption checks in asm') - - Settings.CORRUPTION_CHECK = 1 - - # realloc - test_path = path_from_root('tests', 'core', 'test_corruption_3') - src, output = (test_path + s for s in ('.in', '.out')) - - self.do_run_from_file(src, output) - ### Integration tests def test_ccall(self): diff --git a/tests/test_other.py b/tests/test_other.py index b8672b235c75d..65775c7516085 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -482,7 +482,8 @@ def test_cxx11(self): assert process.returncode is 0, 'User should be able to specify custom -std= on the command line!' def test_odd_suffixes(self): - for suffix in ['CPP', 'c++', 'C++', 'cxx', 'CXX', 'cc', 'CC']: + for suffix in ['CPP', 'c++', 'C++', 'cxx', 'CXX', 'cc', 'CC', 'i', 'ii']: + self.clear() print suffix shutil.copyfile(path_from_root('tests', 'hello_world.cpp'), 'test.' + suffix) Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'test.' + suffix)]).communicate() @@ -2146,6 +2147,7 @@ def test_embind(self): (['--bind', '-O1'], False), (['--bind', '-O2'], False), (['--bind', '-O2', '--closure', '1'], False), + (['--bind', '-O2', '-s', 'ALLOW_MEMORY_GROWTH=1', path_from_root('tests', 'embind', 'isMemoryGrowthEnabled=true.cpp')], False), ]: print args, fail self.clear() diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index e32c8f8229f6a..3858bc034fde5 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -2564,8 +2564,7 @@ void registerizeHarder(Ref ast) { int id; std::unordered_set inblocks, outblocks; StringSet live; - bool checkedLive; - Junction(int id_) : id(id_), checkedLive(false) {} + Junction(int id_) : id(id_) {} }; struct Node { }; @@ -3235,19 +3234,23 @@ void registerizeHarder(Ref ast) { block->lastKillLoc = lastKillLoc; }; - // Ordered map to work in reverse order + // Ordered map to work in approximate reverse order of junction appearance std::set jWorkSet; - jWorkSet.insert(EXIT_JUNCTION); std::set bWorkSet; // Be sure to visit every junction at least once. // This avoids missing some vars because we disconnected them // when processing the labelled jumps. - for (int i = junctions.size() - 1; i >= EXIT_JUNCTION; i--) { + for (int i = EXIT_JUNCTION; i < junctions.size(); i++) { jWorkSet.insert(i); + for (auto b : junctions[i].inblocks) { + bWorkSet.insert(b); + } } + // Exit junction never has any live variable changes to propagate + jWorkSet.erase(EXIT_JUNCTION); - while (jWorkSet.size() > 0) { + do { // Iterate on just the junctions until we get stable live sets. // The first run of this loop will grow the live sets to their maximal size. // Subsequent runs will shrink them based on eliminated in-block uses. @@ -3258,8 +3261,7 @@ void registerizeHarder(Ref ast) { jWorkSet.erase(last); StringSet oldLive = junc.live; // copy it here, to check for changes later analyzeJunction(junc); - if (!junc.checkedLive || oldLive != junc.live) { - junc.checkedLive = true; + if (oldLive != junc.live) { // Live set changed, updated predecessor blocks and junctions. for (auto b : junc.inblocks) { bWorkSet.insert(b); @@ -3280,7 +3282,7 @@ void registerizeHarder(Ref ast) { jWorkSet.insert(block->entry); } } - } + } while (jWorkSet.size() > 0); // Insist that all function parameters are alive at function entry. // This ensures they will be assigned independent registers, even @@ -3304,40 +3306,61 @@ void registerizeHarder(Ref ast) { }; std::unordered_map junctionVariables; - auto initializeJunctionVariable = [&](IString name) { - junctionVariables[name].conf.reserve(asmData.locals.size()); + auto getJunctionVariable = [&](IString name) -> JuncVar& { + auto it_created = junctionVariables.insert(std::make_pair(name, JuncVar())); + JuncVar &jvar = it_created.first->second; + if (it_created.second) jvar.conf.reserve(asmData.locals.size()); + return jvar; }; for (size_t i = 0; i < junctions.size(); i++) { Junction& junc = junctions[i]; + + // Pre-compute the possible conflicts and links for each block rather + // than checking potentially impossible options for each var + std::unordered_map> possibleBlockConflicts; + std::unordered_map> possibleBlockLinks; + for (auto b : junc.outblocks) { + Block* block = blocks[b]; + Junction& jSucc = junctions[block->exit]; + for (auto name : jSucc.live) { + possibleBlockConflicts[name].push_back(block); + } + for (auto name_linkname : block->link) { + if (name_linkname.first != name_linkname.second) { + possibleBlockLinks[name_linkname.first].push_back(block); + } + } + } + for (auto name : junc.live) { + possibleBlockConflicts.erase(name); + } + for (auto name : junc.live) { - if (junctionVariables.count(name) == 0) initializeJunctionVariable(name); + JuncVar& jvar = getJunctionVariable(name); // It conflicts with all other names live at this junction. - junctionVariables[name].conf.insert(junc.live.begin(), junc.live.end()); // XXX this operation is very expensive - junctionVariables[name].conf.erase(name); // except for itself, of course - for (auto b : junc.outblocks) { - // It conflicts with any output vars of successor blocks, - // if they're assigned before it goes dead in that block. - Block* block = blocks[b]; - Junction& jSucc = junctions[block->exit]; - for (auto otherName : jSucc.live) { - if (junc.live.has(otherName)) continue; + jvar.conf.insert(junc.live.begin(), junc.live.end()); // XXX this operation is very expensive + jvar.conf.erase(name); // except for itself, of course + + // It conflicts with any output vars of successor blocks, + // if they're assigned before it goes dead in that block. + for (auto kv: possibleBlockConflicts) { + IString otherName = kv.first; + for (auto block : kv.second) { if (block->lastKillLoc[otherName] < block->firstDeadLoc[name]) { - if (junctionVariables.count(otherName) == 0) initializeJunctionVariable(otherName); - junctionVariables[name].conf.insert(otherName); - junctionVariables[otherName].conf.insert(name); - } - } - // It links with any linkages in the outgoing blocks. - if (block->link.has(name)) { - IString linkName = block->link[name]; - if (linkName != name) { - if (junctionVariables.count(linkName) == 0) initializeJunctionVariable(linkName); - junctionVariables[name].link.insert(linkName); - junctionVariables[linkName].link.insert(name); + jvar.conf.insert(otherName); + getJunctionVariable(otherName).conf.insert(name); + break; } } } + + // It links with any linkages in the outgoing blocks. + for (auto block: possibleBlockLinks[name]) { + IString linkName = block->link[name]; + jvar.link.insert(linkName); + getJunctionVariable(linkName).link.insert(name); + } } } diff --git a/tools/optimizer/simple_ast.cpp b/tools/optimizer/simple_ast.cpp index 9455efb330741..f744604f1aaba 100644 --- a/tools/optimizer/simple_ast.cpp +++ b/tools/optimizer/simple_ast.cpp @@ -62,7 +62,7 @@ void dump(const char *str, Ref node, bool pretty) { struct TraverseInfo { TraverseInfo() {} - TraverseInfo(Ref node, int index) : node(node), index(index) {} + TraverseInfo(Ref node) : node(node), index(0) {} Ref node; int index; }; @@ -123,7 +123,7 @@ void traversePre(Ref node, std::function visit) { if (!visitable(node)) return; visit(node); StackedStack stack; - stack.push_back(TraverseInfo(node, 0)); + stack.push_back(TraverseInfo(node)); while (stack.size() > 0) { TraverseInfo& top = stack.back(); if (top.index < (int)top.node->size()) { @@ -131,7 +131,7 @@ void traversePre(Ref node, std::function visit) { top.index++; if (visitable(sub)) { visit(sub); - stack.push_back(TraverseInfo(sub, 0)); + stack.push_back(TraverseInfo(sub)); } } else { stack.pop_back(); @@ -144,7 +144,7 @@ void traversePrePost(Ref node, std::function visitPre, std::function if (!visitable(node)) return; visitPre(node); StackedStack stack; - stack.push_back(TraverseInfo(node, 0)); + stack.push_back(TraverseInfo(node)); while (stack.size() > 0) { TraverseInfo& top = stack.back(); if (top.index < (int)top.node->size()) { @@ -152,7 +152,7 @@ void traversePrePost(Ref node, std::function visitPre, std::function top.index++; if (visitable(sub)) { visitPre(sub); - stack.push_back(TraverseInfo(sub, 0)); + stack.push_back(TraverseInfo(sub)); } } else { visitPost(top.node); @@ -166,7 +166,7 @@ void traversePrePostConditional(Ref node, std::function visitPre, st if (!visitable(node)) return; if (!visitPre(node)) return; StackedStack stack; - stack.push_back(TraverseInfo(node, 0)); + stack.push_back(TraverseInfo(node)); while (stack.size() > 0) { TraverseInfo& top = stack.back(); if (top.index < (int)top.node->size()) { @@ -174,7 +174,7 @@ void traversePrePostConditional(Ref node, std::function visitPre, st top.index++; if (visitable(sub)) { if (visitPre(sub)) { - stack.push_back(TraverseInfo(sub, 0)); + stack.push_back(TraverseInfo(sub)); } } } else { diff --git a/tools/shared.py b/tools/shared.py index 86342e6dc6406..40ddb15efbc3e 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -493,10 +493,9 @@ def check_sanity(force=False): logging.critical('Cannot find %s, check the paths in %s' % (cmd, EM_CONFIG)) sys.exit(1) - if os.environ.get('EMCC_FAST_COMPILER') != '0': - if not fastcomp_ok: - logging.critical('failing sanity checks due to previous fastcomp failure') - sys.exit(1) + if not fastcomp_ok: + logging.critical('failing sanity checks due to previous fastcomp failure') + sys.exit(1) try: subprocess.call([JAVA, '-version'], stdout=PIPE, stderr=PIPE) @@ -939,8 +938,6 @@ def copy(self, values): @classmethod def apply_opt_level(self, opt_level, noisy=False): - if opt_level == 0 and os.environ.get('EMCC_FAST_COMPILER') == '0': - self.attrs['ASM_JS'] = 0 # non-fastcomp has asm off in -O1 if opt_level >= 1: self.attrs['ASM_JS'] = 1 self.attrs['ASSERTIONS'] = 0