diff --git a/cmake/Platform/Emscripten.cmake b/cmake/Platform/Emscripten.cmake index ef813eb800a25..4f434d1402f9c 100644 --- a/cmake/Platform/Emscripten.cmake +++ b/cmake/Platform/Emscripten.cmake @@ -124,22 +124,22 @@ SET(APPLE) set(CMAKE_C_SIZEOF_DATA_PTR 4) set(CMAKE_CXX_SIZEOF_DATA_PTR 4) -set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELEASE") -set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_MINSIZEREL") -set(CMAKE_C_FLAGS_RELWITHDEBINFO "" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELWITHDEBINFO") -set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_RELEASE") -set(CMAKE_CXX_FLAGS_MINSIZEREL "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_MINSIZEREL") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_RELWITHDEBINFO") +set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O2" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELEASE") +set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG -O2" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_MINSIZEREL") +set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELWITHDEBINFO") +set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O2" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_RELEASE") +set(CMAKE_CXX_FLAGS_MINSIZEREL "-DNDEBUG -O2" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_MINSIZEREL") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_RELWITHDEBINFO") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-O2" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_RELEASE") set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-O2" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_MINSIZEREL") -set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO") +set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO") set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "-O2" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_RELEASE") set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "-O2" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL") -set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO") +set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO") set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "-O2" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_RELEASE") set(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "-O2" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL") -set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO") +set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO") function(em_validate_asmjs_after_build target) add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo Validating build output for asm.js... COMMAND "python" ARGS "${EMSCRIPTEN_ROOT_PATH}/tools/validate_asmjs.py" "$") @@ -205,3 +205,24 @@ endfunction() function(em_link_post_js target) em_add_tracked_link_flag(${target} "--post-js" ${ARGN}) endfunction() + +# Experimental support for targeting generation of Visual Studio project files (vs-tool) of Emscripten projects for Windows. +# To use this, pass the combination -G "Visual Studio 10" -DCMAKE_TOOLCHAIN_FILE=Emscripten.cmake +if ("${CMAKE_GENERATOR}" MATCHES "^Visual Studio.*") + # By default, CMake generates VS project files with a true directive. + # This causes VS to attempt to invoke rc.exe during the build, which will fail since app manifests are meaningless for Emscripten. + # To disable this, add the following linker flag. This flag will not go to emcc, since the Visual Studio CMake generator will swallow it. + set(EMSCRIPTEN_VS_LINKER_FLAGS "/MANIFEST:NO") + # CMake is hardcoded to write a ClCompile directive $(IntDir) in all VS project files it generates. + # This makes VS pass emcc a -o param that points to a directory instead of a file, which causes emcc autogenerate the output filename. + # CMake is hardcoded to assume all object files have the suffix .obj, so adjust the emcc-autogenerated default suffix name to match. + set(EMSCRIPTEN_VS_LINKER_FLAGS "${EMSCRIPTEN_VS_LINKER_FLAGS} --default-obj-ext .obj") + # Also hint CMake that it should not hardcode generation. Requires a custom CMake build for this to work (ignored on others) + # See http://www.cmake.org/Bug/view.php?id=14673 and https://github.com/juj/CMake + set(CMAKE_VS_NO_DEFAULT_OBJECTFILENAME 1) + + # Apply and cache Emscripten Visual Studio IDE-specific linker flags. + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EMSCRIPTEN_VS_LINKER_FLAGS}" CACHE STRING "") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${EMSCRIPTEN_VS_LINKER_FLAGS}" CACHE STRING "") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${EMSCRIPTEN_VS_LINKER_FLAGS}" CACHE STRING "") +endif() diff --git a/emcc b/emcc index 0f4f8800ef4e5..621cb340a7e87 100755 --- a/emcc +++ b/emcc @@ -348,7 +348,9 @@ Options that are modified or new in %s include: --embed-file and --preload-file wildcard is supported - --compression Compress both the compiled code and embedded/ + --compression **THIS OPTION IS DEPRECATED** + + Compress both the compiled code and embedded/ preloaded files. should be a triple, ,, @@ -517,6 +519,13 @@ Options that are modified or new in %s include: file, and if that is not set, the default location ~/.emscripten is assumed. + --default-obj-ext .ext Specifies the file suffix to generate if the location + of a directory name is passed to -o directive, e.g. + emcc -c a.c -o dir/ + will by default generate an output name 'dir/a.o', + but this cmdline param can be passed to generate a + file with a custom suffix 'dir/a.ext'. + The target file, if specified (-o ), defines what will be generated: @@ -804,6 +813,7 @@ try: use_preload_cache = False no_heap_copy = False proxy_to_worker = False + default_object_extension = '.o' if use_cxx: default_cxx_std = '-std=c++03' # Enforce a consistent C++ standard when compiling .cpp files, if user does not specify one on the cmdline. @@ -914,6 +924,7 @@ try: newargs[i] = '' newargs[i+1] = '' elif newargs[i].startswith('--compression'): + logging.warning('--compression is deprecated. Instead, it is recommended you use native gzip compression in your webserver') check_bad_eq(newargs[i]) parts = newargs[i+1].split(',') assert len(parts) == 3, '--compression requires specifying native_encoder,js_decoder,js_name - see emcc --help. got: %s' % newargs[i+1] @@ -999,6 +1010,12 @@ try: # This option is parsed in tools/shared.py, here only clean it up from being passed to clang. newargs[i] = '' newargs[i+1] = '' + elif newargs[i] == '--default-obj-ext': + newargs[i] = '' + default_object_extension = newargs[i+1] + if not default_object_extension.startswith('.'): + default_object_extension = '.' + default_object_extension + newargs[i+1] = '' newargs = [ arg for arg in newargs if arg is not '' ] @@ -1173,7 +1190,9 @@ try: logging.warning('disabling asm.js since embind is not ready for it yet') shared.Settings.ASM_JS = 0 - if os.environ.get('EMCC_FAST_COMPILER'): + fastcomp = os.environ.get('EMCC_FAST_COMPILER') == '1' + + if fastcomp: shared.Settings.ASM_JS = 1 if shared.Settings.DISABLE_EXCEPTION_CATCHING == 0: logging.warning('disabling exception catching since not supported in fastcomp yet') @@ -1192,9 +1211,12 @@ try: assert shared.Settings.PGO == 0, 'pgo not supported in fastcomp' assert shared.Settings.TARGET_LE32 == 1, 'fastcomp requires le32' assert not bind, 'embind not supported in fastcomp yet' + if jcache: + logging.warning('jcache is not supported in fastcomp (you should not need it anyhow), disabling') + jcache = False if shared.Settings.ASM_JS: - assert opt_level >= 1 or os.environ.get('EMCC_FAST_COMPILER'), 'asm.js requires -O1 or above' + assert opt_level >= 1 or fastcomp, 'asm.js requires -O1 or above' if bind: shared.Settings.RESERVED_FUNCTION_POINTERS = max(shared.Settings.RESERVED_FUNCTION_POINTERS, 10) @@ -1206,16 +1228,6 @@ try: shared.Settings.CORRECT_OVERFLOWS = 1 assert not shared.Settings.PGO, 'cannot run PGO in ASM_JS mode' - heap = 4096 - while heap < shared.Settings.TOTAL_MEMORY: - if heap < 16*1024*1024: - heap *= 2 - else: - heap += 16*1024*1024 - if heap != shared.Settings.TOTAL_MEMORY: - logging.warning('increasing TOTAL_MEMORY to %d to be more reasonable for asm.js' % heap) - shared.Settings.TOTAL_MEMORY = heap - if shared.Settings.CORRECT_SIGNS >= 2 or shared.Settings.CORRECT_OVERFLOWS >= 2 or shared.Settings.CORRECT_ROUNDINGS >= 2: debug_level = 4 # must keep debug info to do line-by-line operations @@ -1340,7 +1352,16 @@ try: else: if len(input_files) == 1: temp_output_base = in_temp(unsuffixed(uniquename(input_files[0]))) - shutil.move(temp_output_base + '.o', specified_target) + if specified_target.endswith('/') or specified_target.endswith('\\') or os.path.isdir(specified_target): # User passed '-o as the location of the output. Generating output file ' + obj_output_name) + try: + shutil.move(temp_output_base + '.o', obj_output_name) + except IOError, e: + logging.error('Could not write to output file ' + obj_output_name + '. Perhaps the output directory does not exist?') + exit(1) + else: # User passed '-o ' as the location to output to. + shutil.move(temp_output_base + '.o', specified_target) if os.path.exists(temp_output_base + '.d'): # There was a .d file generated, from -MD or -MMD and friends, save a copy of it to where the output resides, # adjusting the target name away from the temporary file name to the specified target. @@ -1722,22 +1743,25 @@ 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'] - # Simplify LLVM bitcode for fastcomp - if os.environ.get('EMCC_FAST_COMPILER') and not AUTODEBUG: - link_opts += ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt'] - if (not save_bc and not os.environ.get('EMCC_FAST_COMPILER')) or AUTODEBUG: + if (not save_bc and not fastcomp) or 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: + # Simplify LLVM bitcode for fastcomp + link_opts += ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt'] shared.Building.llvm_opt(final, link_opts) if DEBUG: save_intermediate('linktime', 'bc') - - if save_bc: - shutil.copyfile(final, save_bc) + if save_bc: + shutil.copyfile(final, save_bc) + if fastcomp: + shared.Building.llvm_opt(final, ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt'], final + '.adsimp.bc') + final += '.adsimp.bc' + if DEBUG: save_intermediate('adsimp', 'bc') # Prepare .ll for Emscripten if not LEAVE_INPUTS_RAW: @@ -1754,7 +1778,7 @@ try: if DEBUG: save_intermediate('autodebug', 'll') # Simplify bitcode after autodebug - if os.environ.get('EMCC_FAST_COMPILER') and (AUTODEBUG or LEAVE_INPUTS_RAW): + if fastcomp and (AUTODEBUG or LEAVE_INPUTS_RAW): shared.Building.llvm_opt(final, ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt'], final + '.adsimp.bc') final += '.adsimp.bc' if DEBUG: save_intermediate('adsimp', 'bc') diff --git a/emrun b/emrun index d5975b8ae59b0..e3596eed76e17 100755 --- a/emrun +++ b/emrun @@ -492,15 +492,18 @@ def win_print_gpu_info(): print "GPU"+str(i)+ ": " + gpus[i] + " with " + gpu_memory[i] + " MBs of VRAM" def linux_print_gpu_info(): - glxinfo = subprocess.check_output('glxinfo') - for line in glxinfo.split("\n"): - if "OpenGL vendor string:" in line: - gl_vendor = line[len("OpenGL vendor string:"):].strip() - if "OpenGL version string:" in line: - gl_version = line[len("OpenGL version string:"):].strip() - if "OpenGL renderer string:" in line: - gl_renderer = line[len("OpenGL renderer string:"):].strip() - logi('GPU: ' + gl_vendor + ' ' + gl_renderer + ', GL version ' + gl_version) + try: + glxinfo = subprocess.check_output('glxinfo') + for line in glxinfo.split("\n"): + if "OpenGL vendor string:" in line: + gl_vendor = line[len("OpenGL vendor string:"):].strip() + if "OpenGL version string:" in line: + gl_version = line[len("OpenGL version string:"):].strip() + if "OpenGL renderer string:" in line: + gl_renderer = line[len("OpenGL renderer string:"):].strip() + logi('GPU: ' + gl_vendor + ' ' + gl_renderer + ', GL version ' + gl_version) + except: + pass def osx_print_gpu_info(): try: @@ -722,11 +725,12 @@ def find_browser(name): ('firefox_beta', os.path.expanduser('~/firefox_beta/firefox')), ('firefox_aurora', os.path.expanduser('~/firefox_aurora/firefox')), ('firefox_nightly', os.path.expanduser('~/firefox_nightly/firefox')), - ('chrome', which('google-chrome-stable'))] + ('chrome', which('google-chrome-stable')), + ('chrome', which('google-chrome'))] for (alias, browser_exe) in browser_locations: if name == alias: - if os.path.isfile(browser_exe): + if browser_exe is not None and os.path.isfile(browser_exe): return [browser_exe] return None # Could not find the browser diff --git a/src/jsifier.js b/src/jsifier.js index 6b831b044ace1..58dc46532e1f8 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -6,7 +6,6 @@ // Handy sets var STRUCT_LIST = set('struct', 'list'); -var UNDERSCORE_OPENPARENS = set('_', '('); var RELOOP_IGNORED_LASTS = set('return', 'unreachable', 'resume'); var addedLibraryItems = {}; @@ -96,19 +95,6 @@ function JSify(data, functionsOnly, givenFunctions) { // Functions - Functions.currExternalFunctions = !mainPass ? givenFunctions.currExternalFunctions : {}; - - data.functionStubs.forEach(function(func) { - // Don't overwrite stubs that have more info. - if (!Functions.currExternalFunctions.hasOwnProperty(func.ident) || - !Functions.currExternalFunctions[func.ident].numParams === undefined) { - Functions.currExternalFunctions[func.ident] = { - hasVarArgs: func.hasVarArgs, - numParams: func.params && func.params.length - }; - } - }); - if (phase == 'funcs') { // || phase == 'pre') { // pre has function shells, just to defined implementedFunctions var MAX_BATCH_FUNC_LINES = 1000; while (data.unparsedFunctions.length > 0) { @@ -1824,7 +1810,7 @@ function JSify(data, functionsOnly, givenFunctions) { print('staticSealed = true; // seal the static portion of memory\n'); print('STACK_MAX = STACK_BASE + ' + TOTAL_STACK + ';\n'); print('DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);\n'); - print('assert(DYNAMIC_BASE < TOTAL_MEMORY); // Stack must fit in TOTAL_MEMORY; allocations from here on may enlarge TOTAL_MEMORY\n'); + print('assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");\n'); } if (asmLibraryFunctions.length > 0) { diff --git a/src/library.js b/src/library.js index fc731e01fb09a..354e55494eb19 100644 --- a/src/library.js +++ b/src/library.js @@ -8858,7 +8858,8 @@ LibraryManager.library = { } } str += ')'; - args = args.callee.caller.arguments; + var caller = args.callee.caller; + args = caller ? caller.arguments : []; if (first) str = ''; return [args, funcname, str]; diff --git a/src/library_gl.js b/src/library_gl.js index 29f78c8a74df7..6af4a86c68714 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -547,6 +547,9 @@ var LibraryGL = { Module.ctx.getExtension('WEBKIT_EXT_texture_filter_anisotropic'); GL.floatExt = Module.ctx.getExtension('OES_texture_float'); + + // Extension available from Firefox 26 and Google Chrome 30 + GL.instancedArraysExt = Module.ctx.getExtension('ANGLE_instanced_arrays'); // These are the 'safe' feature-enabling extensions that don't add any performance impact related to e.g. debugging, and // should be enabled by default so that client GLES2/GL code will not need to go through extra hoops to get its stuff working. @@ -1916,6 +1919,13 @@ var LibraryGL = { return id; }; + function ensurePrecision(source) { + if (!/precision +(low|medium|high)p +float *;/.test(source)) { + source = 'precision mediump float;\n' + source; + } + return source; + } + var glShaderSource = _glShaderSource; _glShaderSource = function _glShaderSource(shader, count, string, length) { var source = GL.getSource(shader, count, string, length); @@ -1989,6 +1999,7 @@ var LibraryGL = { source = 'varying float v_fogFragCoord; \n' + source.replace(/gl_FogFragCoord/g, 'v_fogFragCoord'); } + source = ensurePrecision(source); } else { // Fragment shader for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) { var old = source; @@ -2020,7 +2031,7 @@ var LibraryGL = { source = 'varying float v_fogFragCoord; \n' + source.replace(/gl_FogFragCoord/g, 'v_fogFragCoord'); } - source = 'precision mediump float;\n' + source; + source = ensurePrecision(source); } #if GL_DEBUG GL.shaderSources[shader] = source; @@ -4959,6 +4970,45 @@ var LibraryGL = { return Module.ctx.getError(); } }, + + // ANGLE_instanced_arrays WebGL extension related functions + + glVertexAttribDivisor__sig: 'vii', + glVertexAttribDivisor: function(index, divisor) { +#if GL_ASSERTIONS + assert(GL.instancedArraysExt, 'Must have ANGLE_instanced_arrays extension to use WebGL instancing'); +#endif + GL.instancedArraysExt.vertexAttribDivisorANGLE(index, divisor); + }, + + glDrawArraysInstanced__sig: 'viiii', + glDrawArraysInstanced: function(mode, first, count, primcount) { +#if GL_ASSERTIONS + assert(GL.instancedArraysExt, 'Must have ANGLE_instanced_arrays extension to use WebGL instancing'); +#endif + GL.instancedArraysExt.drawArraysInstancedANGLE(mode, first, count, primcount); + }, + + glDrawElementsInstanced__sig: 'viiiii', + glDrawElementsInstanced: function(mode, count, type, indices, primcount) { +#if GL_ASSERTIONS + assert(GL.instancedArraysExt, 'Must have ANGLE_instanced_arrays extension to use WebGL instancing'); +#endif + GL.instancedArraysExt.drawElementsInstancedANGLE(mode, count, type, indices, primcount); + }, + + // OpenGL Desktop/ES 2.0 instancing extensions compatibility + + glVertexAttribDivisorNV: 'glVertexAttribDivisor', + glDrawArraysInstancedNV: 'glDrawArraysInstanced', + glDrawElementsInstancedNV: 'glDrawElementsInstanced', + glVertexAttribDivisorEXT: 'glVertexAttribDivisor', + glDrawArraysInstancedEXT: 'glDrawArraysInstanced', + glDrawElementsInstancedEXT: 'glDrawElementsInstanced', + glVertexAttribDivisorARB: 'glVertexAttribDivisor', + glDrawArraysInstancedARB: 'glDrawArraysInstanced', + glDrawElementsInstancedARB: 'glDrawElementsInstanced', + // signatures of simple pass-through functions, see later glActiveTexture__sig: 'vi', diff --git a/src/library_sdl.js b/src/library_sdl.js index 2efc127123866..1c1e8107cb819 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1220,6 +1220,7 @@ var LibrarySDL = { if (surf) SDL.freeSurface(surf); }, + SDL_UpperBlit__deps: ['SDL_LockSurface'], SDL_UpperBlit: function(src, srcrect, dst, dstrect) { var srcData = SDL.surfaces[src]; var dstData = SDL.surfaces[dst]; diff --git a/src/parseTools.js b/src/parseTools.js index ff9812640c83c..874514b16fe40 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -16,6 +16,7 @@ function processMacros(text) { // Simple #if/else/endif preprocessing for a file. Checks if the // ident checked is true in our global. +// Also handles #include x.js (similar to C #include ) function preprocess(text) { var lines = text.split('\n'); var ret = ''; @@ -30,25 +31,29 @@ function preprocess(text) { ret += line + '\n'; } } else { - if (line[1] && line[1] == 'i') { // if - var parts = line.split(' '); - var ident = parts[1]; - var op = parts[2]; - var value = parts[3]; - if (op) { - if (op === '==') { - showStack.push(ident in this && this[ident] == value); - } else if (op === '!=') { - showStack.push(!(ident in this && this[ident] == value)); + if (line[1] == 'i') { + if (line[2] == 'f') { // if + var parts = line.split(' '); + var ident = parts[1]; + var op = parts[2]; + var value = parts[3]; + if (op) { + if (op === '==') { + showStack.push(ident in this && this[ident] == value); + } else if (op === '!=') { + showStack.push(!(ident in this && this[ident] == value)); + } else { + error('unsupported preprecessor op ' + op); + } } else { - error('unsupported preprecessor op ' + op); + showStack.push(ident in this && this[ident] > 0); } - } else { - showStack.push(ident in this && this[ident] > 0); + } else if (line[2] == 'n') { // include + ret += '\n' + read(line.substr(line.indexOf(' ')+1)) + '\n' } - } else if (line[2] && line[2] == 'l') { // else + } else if (line[2] == 'l') { // else showStack.push(!showStack.pop()); - } else if (line[2] && line[2] == 'n') { // endif + } else if (line[2] == 'n') { // endif showStack.pop(); } else { throw "Unclear preprocessor command: " + line; diff --git a/src/preamble.js b/src/preamble.js index 832ec2c30d092..f9fccdf6a01c2 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -866,6 +866,21 @@ var TOTAL_STACK = Module['TOTAL_STACK'] || {{{ TOTAL_STACK }}}; var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || {{{ TOTAL_MEMORY }}}; var FAST_MEMORY = Module['FAST_MEMORY'] || {{{ FAST_MEMORY }}}; +#if ASM_JS +var totalMemory = 4096; +while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) { + if (totalMemory < 16*1024*1024) { + totalMemory *= 2; + } else { + totalMemory += 16*1024*1024 + } +} +if (totalMemory !== TOTAL_MEMORY) { + Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable'); + TOTAL_MEMORY = totalMemory; +} +#endif + // Initialize the runtime's memory #if USE_TYPED_ARRAYS // check for full engine support (use string 'subarray' to avoid closure compiler confusion) diff --git a/src/relooper/Relooper.cpp b/src/relooper/Relooper.cpp index 70cf844bd9dc4..de69e0ef3520b 100644 --- a/src/relooper/Relooper.cpp +++ b/src/relooper/Relooper.cpp @@ -417,7 +417,7 @@ void Relooper::Calculate(Block *Entry) { for (BlockSet::iterator iter = Original->BranchesIn.begin(); iter != Original->BranchesIn.end(); iter++) { Block *Prior = *iter; Block *Split = new Block(Original->Code, Original->BranchVar); - Parent->Blocks.push_back(Split); + Parent->AddBlock(Split); PrintDebug(" to %d\n", Split->Id); Split->BranchesIn.insert(Prior); Branch *Details = Prior->BranchesOut[Original]; diff --git a/src/runtime.js b/src/runtime.js index 8ba5d08d5c924..cd3afb4ba77bc 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -250,7 +250,7 @@ var Runtime = { prev = curr; return curr; }); - if (type.name_[0] === '[') { + 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; diff --git a/tests/test_other.py b/tests/test_other.py index df9e2da548eca..4bdd889be4204 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -397,6 +397,8 @@ class Test { self.assertContained('hello, world!', run_js(os.path.join(self.get_dir(), 'a.out.js'))) def test_unaligned_memory(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') + open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r''' #include #include @@ -421,6 +423,8 @@ def test_unaligned_memory(self): self.assertContained('data: 67452301\ndata[0,1] 16bit: 2301\ndata[1,2] 16bit: 4523', run_js(os.path.join(self.get_dir(), 'a.out.js'))) def test_unaligned_memory_2(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') + open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r''' #include #include @@ -463,6 +467,7 @@ def test(args): assert 'function _malloc' in src def test_dangerous_func_cast(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') src = r''' #include typedef void (*voidfunc)(); @@ -522,6 +527,8 @@ def test_l_link(self): assert not os.path.exists('a.out') and not os.path.exists('a.exe'), 'Must not leave unneeded linker stubs' def test_static_link(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') + def test(name, header, main, side, expected, args=[], suffix='cpp', first=True): print name #t = main ; main = side ; side = t @@ -1791,6 +1798,7 @@ def test_scons(self): # also incidentally tests c++11 integration in llvm 3.1 assert 'If you see this - the world is all right!' in output def test_embind(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') for args, fail in [ ([], True), # without --bind, we fail (['--bind'], False), @@ -1856,6 +1864,8 @@ def test_emconfig(self): assert output == invalid def test_link_s(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo safe heap in fastcomp') + # -s OPT=VALUE can conflict with -s as a linker option. We warn and ignore open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r''' extern "C" { @@ -1950,19 +1960,19 @@ def test_crunch(self): # crunch should not be run if a .crn exists that is more recent than the .dds shutil.copyfile(path_from_root('tests', 'ship.dds'), 'ship.dds') time.sleep(0.1) - Popen([PYTHON, FILE_PACKAGER, 'test.data', '--pre-run', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate() + Popen([PYTHON, FILE_PACKAGER, 'test.data', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate() assert os.stat('test.data').st_size < 0.25*os.stat('ship.dds').st_size, 'Compressed should be much smaller than dds' crunch_time = os.stat('ship.crn').st_mtime dds_time = os.stat('ship.dds').st_mtime assert crunch_time > dds_time, 'Crunch is more recent' # run again, should not recrunch! time.sleep(0.1) - Popen([PYTHON, FILE_PACKAGER, 'test.data', '--pre-run', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate() + Popen([PYTHON, FILE_PACKAGER, 'test.data', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate() assert crunch_time == os.stat('ship.crn').st_mtime, 'Crunch is unchanged' # update dds, so should recrunch time.sleep(0.1) os.utime('ship.dds', None) - Popen([PYTHON, FILE_PACKAGER, 'test.data', '--pre-run', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate() + Popen([PYTHON, FILE_PACKAGER, 'test.data', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate() assert crunch_time < os.stat('ship.crn').st_mtime, 'Crunch was changed' def test_headless(self): @@ -2139,6 +2149,8 @@ def test_fs_stream_proto(self): self.assertContained('File size: 722', out) def test_simd(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') + self.clear() Popen([PYTHON, EMCC, path_from_root('tests', 'linpack.c'), '-O2', '-DSP', '--llvm-opts', '''['-O3', '-vectorize', '-vectorize-loops', '-bb-vectorize-vector-bits=128', '-force-vector-width=4']''']).communicate() self.assertContained('Unrolled Single Precision', run_js('a.out.js')) @@ -2187,3 +2199,12 @@ def test_float_h(self): out, err = process.communicate() assert process.returncode is 0, 'float.h should agree with our system: ' + out + '\n\n\n' + err + def test_default_obj_ext(self): + outdir = os.path.join(self.get_dir(), 'out_dir') + '/' + os.mkdir(outdir) + process = Popen([PYTHON, EMCC, '-c', path_from_root('tests', 'hello_world.c'), '-o', outdir], stdout=PIPE, stderr=PIPE) + process.communicate() + assert(os.path.isfile(outdir + 'hello_world.o')) + process = Popen([PYTHON, EMCC, '-c', path_from_root('tests', 'hello_world.c'), '-o', outdir, '--default-obj-ext', 'obj'], stdout=PIPE, stderr=PIPE) + process.communicate() + assert(os.path.isfile(outdir + 'hello_world.obj')) diff --git a/tests/test_sanity.py b/tests/test_sanity.py index dc3d53db3b610..e8b1f88562e32 100644 --- a/tests/test_sanity.py +++ b/tests/test_sanity.py @@ -195,6 +195,34 @@ def test_llvm(self): finally: del os.environ['EM_IGNORE_SANITY'] + def test_llvm_fastcomp(self): + if os.environ.get('EMCC_FAST_COMPILER') != '1': return self.skip('not using fastcomp') + + WARNING = 'fastcomp in use, but LLVM has not been built with the JavaScript backend as a target' + + restore() + + # Should see js backend during sanity check + assert check_fastcomp() + output = self.check_working(EMCC) + assert WARNING not in output, output + + # Fake incorrect llc output, no mention of js backend + restore() + f = open(CONFIG_FILE, 'a') + f.write('LLVM_ROOT = "' + path_from_root('tests', 'fake') + '"') + f.close() + + if not os.path.exists(path_from_root('tests', 'fake')): + os.makedirs(path_from_root('tests', 'fake')) + + f = open(path_from_root('tests', 'fake', 'llc'), 'w') + f.write('#!/bin/sh\n') + f.write('echo "llc fake output\nRegistered Targets:\nno j-s backend for you!"') + f.close() + os.chmod(path_from_root('tests', 'fake', 'llc'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) + output = self.check_working(EMCC, WARNING) + def test_node(self): NODE_WARNING = 'node version appears too old' NODE_WARNING_2 = 'cannot check node version' diff --git a/tools/shared.py b/tools/shared.py index eb1c63be6eea2..2b34090d64ab2 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -286,6 +286,21 @@ def check_llvm_version(): except Exception, e: logging.warning('Could not verify LLVM version: %s' % str(e)) +def check_fastcomp(): + try: + llc_version_info = Popen([LLVM_COMPILER, '--version'], stdout=PIPE).communicate()[0] + pre, targets = llc_version_info.split('Registered Targets:') + if 'js' not in targets or 'JavaScript (asm.js, emscripten) backend' not in targets: + logging.critical('fastcomp in use, but LLVM has not been built with the JavaScript backend as a target, llc reports:') + print >> sys.stderr, '===========================================================================' + print >> sys.stderr, llc_version_info, + print >> sys.stderr, '===========================================================================' + return False + return True + except Exception, e: + logging.warning('cound not check fastcomp: %s' % str(e)) + return True + EXPECTED_NODE_VERSION = (0,8,0) def check_node_version(): @@ -322,7 +337,7 @@ def find_temp_directory(): # we re-check sanity when the settings are changed) # We also re-check sanity and clear the cache when the version changes -EMSCRIPTEN_VERSION = '1.8.0' +EMSCRIPTEN_VERSION = '1.8.1' def generate_sanity(): return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT @@ -353,9 +368,11 @@ def check_sanity(force=False): Cache.erase() force = False # the check actually failed, so definitely write out the sanity file, to avoid others later seeing failures too - # some warning, not fatal checks - do them even if EM_IGNORE_SANITY is on + # some warning, mostly not fatal checks - do them even if EM_IGNORE_SANITY is on check_llvm_version() check_node_version() + if os.environ.get('EMCC_FAST_COMPILER') == '1': + fastcomp_ok = check_fastcomp() if os.environ.get('EM_IGNORE_SANITY'): logging.info('EM_IGNORE_SANITY set, ignoring sanity checks') @@ -377,6 +394,11 @@ 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') == '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) except: @@ -1438,7 +1460,7 @@ def is_bitcode(filename): @staticmethod def ensure_relooper(relooper): if os.path.exists(relooper): return - if os.environ.get('EMCC_FAST_COMPILER'): + if os.environ.get('EMCC_FAST_COMPILER') == '1': logging.debug('not building relooper to js, using it in c++ backend') return @@ -1513,6 +1535,8 @@ def fix(m): text = m.groups(0)[0] assert text.count('(') == 1 and text.count(')') == 1, 'must have simple expressions in emscripten_jcache_printf calls, no parens' assert text.count('"') == 2, 'must have simple expressions in emscripten_jcache_printf calls, no strings as varargs parameters' + if os.environ.get('EMCC_FAST_COMPILER') == '1': # fake it in fastcomp + return text.replace('emscripten_jcache_printf', 'printf') start = text.index('(') end = text.rindex(')') args = text[start+1:end].split(',')