diff --git a/AUTHORS b/AUTHORS index 792fb5236edb0..2c292ddeb942d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -119,3 +119,4 @@ a license to everyone to use it as detailed in LICENSE.) * Emerson José Silveira da Costa * Jari Vetoniemi * Sindre Sorhus +* James S Urquhart diff --git a/emcc b/emcc index 7460da619e307..83ce452977660 100755 --- a/emcc +++ b/emcc @@ -61,6 +61,7 @@ BITCODE_ENDINGS = ('.bc', '.o', '.obj') DYNAMICLIB_ENDINGS = ('.dylib', '.so', '.dll') STATICLIB_ENDINGS = ('.a',) ASSEMBLY_ENDINGS = ('.ll',) +HEADER_ENDINGS = ('.h', '.hxx', '.hpp', '.hh', '.H', '.HXX', '.HPP', '.HH') LIB_PREFIXES = ('', 'lib') @@ -159,7 +160,8 @@ Options that are modified or new in %s include: output. -O3 As -O2, plus additional optimizations that can - take a significant amount of compilation time. + take a significant amount of compilation time and/or + are relatively new. For tips on optimizing your code, see https://github.com/kripken/emscripten/wiki/Optimizing-Code @@ -484,10 +486,13 @@ Options that are modified or new in %s include: libraries, and after any link-time optimizations (if any). - --memory-init-file If on, we generate a separate memory initialization - file. This is more efficient than storing the - memory initialization data embedded inside - JavaScript as text. (default is off) + --memory-init-file 0: Do not emit a separate memory initialization + file, keep the static initialization inside + the generated JavaScript as text (default) + 1: Emit a separate memory initialization file + in binary format. This is more efficient than + storing it as text inside JavaScript, but does + mean you have another file to publish. -Wno-warn-absolute-paths If not specified, the compiler will warn about any uses of absolute paths in -I and -L command line @@ -695,15 +700,12 @@ if len(sys.argv) == 1 or sys.argv[1] in ['x', 't']: sys.exit(0) use_cxx = True -header = False # pre-compiled headers. We fake that by just copying the file for i in range(1, len(sys.argv)): arg = sys.argv[i] if not arg.startswith('-'): if arg.endswith(('.c','.m')): use_cxx = False - if arg.endswith('.h') and sys.argv[i-1] != '-include': - header = True if '-M' in sys.argv or '-MM' in sys.argv: # Just output dependencies, do not compile. Warning: clang and gcc behave differently with -MF! (clang seems to not recognize it) @@ -737,15 +739,6 @@ if '.' in target: else: final_suffix = '' -if header: # header or such - if len(sys.argv) >= 3: # if there is a source and a target, then copy, otherwise do nothing - sys.argv = filter(lambda arg: not arg.startswith('-I'), sys.argv) - logging.debug('Just copy:' + sys.argv[-1] + target) - shutil.copy(sys.argv[-1], target) - else: - logging.debug('No-op.') - exit(0) - if TEMP_DIR: temp_dir = TEMP_DIR if os.path.exists(temp_dir): @@ -1062,6 +1055,7 @@ try: input_files = [] has_source_inputs = False + has_header_inputs = False lib_dirs = [shared.path_from_root('system', 'local', 'lib'), shared.path_from_root('system', 'lib')] libs = [] @@ -1073,7 +1067,7 @@ try: prev = newargs[i-1] if prev in ['-MT', '-MF', '-MQ', '-D', '-U', '-o', '-x', '-Xpreprocessor', '-include', '-imacros', '-idirafter', '-iprefix', '-iwithprefix', '-iwithprefixbefore', '-isysroot', '-imultilib', '-A', '-isystem', '-iquote', '-install_name', '-compatibility_version', '-current_version', '-I', '-L']: continue # ignore this gcc-style argument - if (os.path.islink(arg) and os.path.realpath(arg).endswith(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS)): + if (os.path.islink(arg) and os.path.realpath(arg).endswith(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS + HEADER_ENDINGS)): arg = os.path.realpath(arg) if not arg.startswith('-'): @@ -1082,11 +1076,14 @@ try: exit(1) arg_ending = filename_type_ending(arg) - if arg_ending.endswith(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS) or shared.Building.is_ar(arg): # we already removed -o , so all these should be inputs + if arg_ending.endswith(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS + HEADER_ENDINGS) or shared.Building.is_ar(arg): # we already removed -o , so all these should be inputs newargs[i] = '' if arg_ending.endswith(SOURCE_ENDINGS): input_files.append(arg) has_source_inputs = True + elif arg_ending.endswith(HEADER_ENDINGS): + input_files.append(arg) + has_header_inputs = True elif arg_ending.endswith(ASSEMBLY_ENDINGS) or shared.Building.is_bitcode(arg): # this should be bitcode, make sure it is valid input_files.append(arg) elif arg_ending.endswith(STATICLIB_ENDINGS + DYNAMICLIB_ENDINGS): @@ -1125,7 +1122,7 @@ try: # -c means do not link in gcc, and for us, the parallel is to not go all the way to JS, but stop at bitcode has_dash_c = '-c' in newargs if has_dash_c: - assert has_source_inputs, 'Must have source code inputs to use -c' + assert has_source_inputs or has_header_inputs, 'Must have source code or header inputs to use -c' target = target_basename + '.o' final_suffix = 'o' @@ -1159,7 +1156,7 @@ try: input_files = filter(lambda input_file: check(input_file), input_files) if len(input_files) == 0: - logging.error('no input files\nnote that input files without a known suffix are ignored, make sure your input files end with one of: ' + str(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + STATICLIB_ENDINGS + ASSEMBLY_ENDINGS)) + logging.error('no input files\nnote that input files without a known suffix are ignored, make sure your input files end with one of: ' + str(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + STATICLIB_ENDINGS + ASSEMBLY_ENDINGS + HEADER_ENDINGS)) exit(0) newargs = CC_ADDITIONAL_ARGS + newargs @@ -1226,7 +1223,8 @@ try: assert not shared.Settings.PGO, 'cannot run PGO in ASM_JS mode' if shared.Settings.SAFE_HEAP and not js_opts: - logging.warning('asm.js+SAFE_HEAP requires js opts to be run (-O1 or above by default)') + js_opts = True + logging.warning('enabling js opts to allow SAFE_HEAP to work properly') if shared.Settings.ALLOW_MEMORY_GROWTH: logging.error('Cannot enable ALLOW_MEMORY_GROWTH with asm.js, build with -s ASM_JS=0 if you need a growable heap'); @@ -1299,6 +1297,15 @@ try: log_time('parse arguments and setup') + # Precompiled headers support + if has_header_inputs: + for header in input_files: + assert header.endswith(HEADER_ENDINGS), 'if you have one header input, we assume you want to precompile headers, and cannot have source files or other inputs as well: ' + str(input_files) + ' : ' + header + args = newargs + shared.EMSDK_CXX_OPTS + input_files + logging.debug("running (for precompiled headers: " + call + ' ' + ' '.join(args)) + execute([call] + args) # let compiler frontend print directly, so colors are saved (PIPE kills that) + sys.exit(1) + # First, generate LLVM bitcode. For each input file, we get base.o with bitcode for input_file in input_files: file_ending = filename_type_ending(input_file) @@ -1992,12 +1999,12 @@ try: else: return 'eliminate' - js_optimizer_queue += [get_eliminate()] + if opt_level >= 2: + js_optimizer_queue += [get_eliminate()] - if shared.Settings.AGGRESSIVE_VARIABLE_ELIMINATION: - js_optimizer_queue += ['aggressiveVariableElimination'] + if shared.Settings.AGGRESSIVE_VARIABLE_ELIMINATION: + js_optimizer_queue += ['aggressiveVariableElimination'] - if opt_level >= 2: js_optimizer_queue += ['simplifyExpressions'] if closure and not shared.Settings.ASM_JS: @@ -2016,13 +2023,13 @@ try: js_optimizer_queue += ['outline'] js_optimizer_extra_info['sizeToOutline'] = shared.Settings.OUTLINING_LIMIT - if (not closure or shared.Settings.ASM_JS) and shared.Settings.RELOOP and debug_level < 3: + if opt_level >= 2 and (not closure or shared.Settings.ASM_JS) and shared.Settings.RELOOP and debug_level < 3: if shared.Settings.ASM_JS and opt_level >= 3 and shared.Settings.OUTLINING_LIMIT == 0: js_optimizer_queue += ['registerizeHarder'] else: js_optimizer_queue += ['registerize'] - if opt_level > 0: + if opt_level >= 2: if debug_level < 2 and shared.Settings.ASM_JS: js_optimizer_queue += ['minifyNames'] if debug_level == 0: js_optimizer_queue += ['minifyWhitespace'] diff --git a/emscripten.py b/emscripten.py index 725f573f9413b..ce929858fd87c 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1204,7 +1204,7 @@ def fix(m): if DEBUG: logging.debug(' emscript: final python processing took %s seconds' % (time.time() - t)) -if os.environ.get('EMCC_FAST_COMPILER'): +if os.environ.get('EMCC_FAST_COMPILER') == '1': emscript = emscript_fast def main(args, compiler_engine, cache, jcache, relooper, temp_files, DEBUG, DEBUG_CACHE): diff --git a/src/jsifier.js b/src/jsifier.js index 726a5edaad423..f48195843ea72 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1844,7 +1844,7 @@ function JSify(data, functionsOnly) { // rest of the output that we started to print out earlier (see comment on the // "Final shape that will be created"). if (PRECISE_I64_MATH && Types.preciseI64MathUsed) { - if (!INCLUDE_FULL_LIBRARY) { + if (!INCLUDE_FULL_LIBRARY && !SIDE_MODULE) { // first row are utilities called from generated code, second are needed from fastLong ['i64Add', 'i64Subtract', 'bitshift64Shl', 'bitshift64Lshr', 'bitshift64Ashr', 'llvm_ctlz_i32', 'llvm_cttz_i32'].forEach(function(func) { @@ -1866,6 +1866,7 @@ function JSify(data, functionsOnly) { } }); } + // these may be duplicated in side modules and the main module without issue print(read('fastLong.js')); print('// EMSCRIPTEN_END_FUNCS\n'); print(read('long.js')); diff --git a/src/library.js b/src/library.js index bc577e7813037..bca4794438312 100644 --- a/src/library.js +++ b/src/library.js @@ -162,7 +162,7 @@ LibraryManager.library = { if (times) { // NOTE: We don't keep track of access timestamps. var offset = {{{ C_STRUCTS.utimbuf.modtime }}}; - time = {{{ makeGetValue('times', 'offset', 'i32') }}} + time = {{{ makeGetValue('times', 'offset', 'i32') }}}; time *= 1000; } else { time = Date.now(); @@ -1182,7 +1182,7 @@ LibraryManager.library = { for (var i = 0; i < length; i++) { {{{ makeSetValue('buf', 'i', 'value.charCodeAt(i)', 'i8') }}}; } - if (len > length) {{{ makeSetValue('buf', 'i++', '0', 'i8') }}} + if (len > length) {{{ makeSetValue('buf', 'i++', '0', 'i8') }}}; return i; } }, @@ -4318,21 +4318,36 @@ LibraryManager.library = { _ZTVN10__cxxabiv120__si_class_type_infoE: [2], // yes inherited classes #endif + // We store an extra header in front of the exception data provided + // by the user. + // This header is: + // * type + // * destructor function pointer + // This is then followed by the actual exception data. + __cxa_exception_header_size: 8, + __cxa_last_thrown_exception: 0, + __cxa_caught_exceptions: [], + // Exceptions + __cxa_allocate_exception__deps: ['__cxa_exception_header_size'], __cxa_allocate_exception: function(size) { - return _malloc(size); + var ptr = _malloc(size + ___cxa_exception_header_size); + return ptr + ___cxa_exception_header_size; }, + __cxa_free_exception__deps: ['__cxa_exception_header_size'], __cxa_free_exception: function(ptr) { try { - return _free(ptr); + return _free(ptr - ___cxa_exception_header_size); } catch(e) { // XXX FIXME #if ASSERTIONS Module.printErr('exception during cxa_free_exception: ' + e); #endif } }, + // Here, we throw an exception after recording a couple of values that we need to remember + // We also remember that it was the last exception thrown as we need to know that later. __cxa_throw__sig: 'viii', - __cxa_throw__deps: ['llvm_eh_exception', '_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch'], + __cxa_throw__deps: ['_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch', '__cxa_exception_header_size', '__cxa_last_thrown_exception'], __cxa_throw: function(ptr, type, destructor) { if (!___cxa_throw.initialized) { try { @@ -4349,28 +4364,34 @@ LibraryManager.library = { #if EXCEPTION_DEBUG Module.printErr('Compiled code throwing an exception, ' + [ptr,type,destructor] + ', at ' + stackTrace()); #endif - {{{ makeSetValue('_llvm_eh_exception.buf', '0', 'ptr', 'void*') }}}; - {{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'type', 'void*') }}}; - {{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, 'destructor', 'void*') }}}; + var header = ptr - ___cxa_exception_header_size; + {{{ makeSetValue('header', 0, 'type', 'void*') }}}; + {{{ makeSetValue('header', 4, 'destructor', 'void*') }}}; + ___cxa_last_thrown_exception = ptr; if (!("uncaught_exception" in __ZSt18uncaught_exceptionv)) { __ZSt18uncaught_exceptionv.uncaught_exception = 1; } else { __ZSt18uncaught_exceptionv.uncaught_exception++; } - {{{ makeThrow('ptr') }}}; + {{{ makeThrow('ptr') }}} }, - __cxa_rethrow__deps: ['llvm_eh_exception', '__cxa_end_catch'], + // This exception will be caught twice, but while begin_catch runs twice, + // we early-exit from end_catch when the exception has been rethrown, so + // pop that here from the caught exceptions. + __cxa_rethrow__deps: ['__cxa_end_catch', '__cxa_caught_exceptions'], __cxa_rethrow: function() { ___cxa_end_catch.rethrown = true; - {{{ makeThrow(makeGetValue('_llvm_eh_exception.buf', '0', 'void*')) }}}; + var ptr = ___cxa_caught_exceptions.pop(); + {{{ makeThrow('ptr') }}} }, - llvm_eh_exception__postset: '_llvm_eh_exception.buf = allocate(12, "void*", ALLOC_STATIC);', + llvm_eh_exception__deps: ['__cxa_last_thrown_exception'], llvm_eh_exception: function() { - return {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}}; + return ___cxa_last_thrown_exception; }, llvm_eh_selector__jsargs: true, + llvm_eh_selector__deps: ['__cxa_last_thrown_exception'], llvm_eh_selector: function(unused_exception_value, personality/*, varargs*/) { - var type = {{{ makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') }}} + var type = ___cxa_last_thrown_exception; for (var i = 2; i < arguments.length; i++) { if (arguments[i] == type) return type; } @@ -4379,12 +4400,22 @@ LibraryManager.library = { llvm_eh_typeid_for: function(type) { return type; }, - __cxa_begin_catch__deps: ['_ZSt18uncaught_exceptionv'], + // Note that we push the last thrown exception here rather than the ptr. + // This is because if the exception is a pointer (as in test 3 of test_exceptions_typed), + // we don't actually get the value that we allocated, but something else. Easiest + // to remember that the last exception thrown is going to be the first to be caught, + // so just use that value instead as it is what we're really looking for. + __cxa_begin_catch__deps: ['_ZSt18uncaught_exceptionv', '__cxa_caught_exceptions'], __cxa_begin_catch: function(ptr) { __ZSt18uncaught_exceptionv.uncaught_exception--; + ___cxa_caught_exceptions.push(___cxa_last_thrown_exception); return ptr; }, - __cxa_end_catch__deps: ['llvm_eh_exception', '__cxa_free_exception'], + // We're done with a catch. Now, we can run the destructor if there is one + // and free the exception. Note that if the dynCall on the destructor fails + // due to calling apply on undefined, that means that the destructor is + // an invalid index into the FUNCTION_TABLE, so something has gone wrong. + __cxa_end_catch__deps: ['__cxa_free_exception', '__cxa_last_thrown_exception', '___cxa_exception_header_size', '__cxa_caught_exceptions'], __cxa_end_catch: function() { if (___cxa_end_catch.rethrown) { ___cxa_end_catch.rethrown = false; @@ -4396,22 +4427,20 @@ LibraryManager.library = { #else __THREW__ = 0; #endif - // Clear type. - {{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, '0', 'void*') }}}; // Call destructor if one is registered then clear it. - var ptr = {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}}; - var destructor = {{{ makeGetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, 'void*') }}}; - if (destructor) { - Runtime.dynCall('vi', destructor, [ptr]); - {{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, '0', 'i32') }}}; - } - // Free ptr if it isn't null. + var ptr = ___cxa_caught_exceptions.pop(); if (ptr) { + header = ptr - ___cxa_exception_header_size; + var destructor = {{{ makeGetValue('header', 4, 'void*') }}}; + if (destructor) { + Runtime.dynCall('vi', destructor, [ptr]); + {{{ makeSetValue('header', 4, '0', 'i32') }}}; + } ___cxa_free_exception(ptr); - {{{ makeSetValue('_llvm_eh_exception.buf', '0', '0', 'void*') }}}; + ___cxa_last_thrown_exception = 0; } }, - __cxa_get_exception_ptr__deps: ['llvm_eh_exception'], + __cxa_get_exception_ptr__deps: ['___cxa_last_thrown_exception'], __cxa_get_exception_ptr: function(ptr) { return ptr; }, @@ -4431,7 +4460,7 @@ LibraryManager.library = { terminate: '__cxa_call_unexpected', - __gxx_personality_v0__deps: ['llvm_eh_exception', '_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch'], + __gxx_personality_v0__deps: ['_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch'], __gxx_personality_v0: function() { }, @@ -4464,10 +4493,11 @@ LibraryManager.library = { // functionality boils down to picking a suitable 'catch' block. // We'll do that here, instead, to keep things simpler. - __cxa_find_matching_catch__deps: ['__cxa_does_inherit', '__cxa_is_number_type', '__resumeException'], + __cxa_find_matching_catch__deps: ['__cxa_does_inherit', '__cxa_is_number_type', '__resumeException', '__cxa_last_thrown_exception', '__cxa_exception_header_size'], __cxa_find_matching_catch: function(thrown, throwntype) { - if (thrown == -1) thrown = {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}}; - if (throwntype == -1) throwntype = {{{ makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') }}}; + if (thrown == -1) thrown = ___cxa_last_thrown_exception; + header = thrown - ___cxa_exception_header_size; + if (throwntype == -1) throwntype = {{{ makeGetValue('header', 0, 'void*') }}}; var typeArray = Array.prototype.slice.call(arguments, 2); // If throwntype is a pointer, this means a pointer has been @@ -4498,8 +4528,8 @@ LibraryManager.library = { #if EXCEPTION_DEBUG Module.print("Resuming exception"); #endif - if ({{{ makeGetValue('_llvm_eh_exception.buf', 0, 'void*') }}} == 0) {{{ makeSetValue('_llvm_eh_exception.buf', 0, 'ptr', 'void*') }}}; - {{{ makeThrow('ptr') }}}; + if (!___cxa_last_thrown_exception) { ___cxa_last_thrown_exception = ptr; } + {{{ makeThrow('ptr') }}} }, // Recursively walks up the base types of 'possibilityType' @@ -7600,7 +7630,7 @@ LibraryManager.library = { node = DNS.lookup_name(node); addr = __inet_pton4_raw(node); if (family === {{{ cDefine('AF_UNSPEC') }}}) { - family = {{{ cDefine('AF_INET') }}} + family = {{{ cDefine('AF_INET') }}}; } else if (family === {{{ cDefine('AF_INET6') }}}) { addr = [0, 0, _htonl(0xffff), addr]; } diff --git a/src/library_openal.js b/src/library_openal.js index eb152f629ddaa..67481824ca055 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -201,12 +201,15 @@ var LibraryOpenAL = { } if (ctx) { + var gain = ctx.createGain(); + gain.connect(ctx.destination); var context = { ctx: ctx, err: 0, src: [], buf: [], - interval: setInterval(function() { AL.updateSources(context); }, AL.QUEUE_INTERVAL) + interval: setInterval(function() { AL.updateSources(context); }, AL.QUEUE_INTERVAL), + gain: gain }; AL.contexts.push(context); return AL.contexts.length; @@ -254,7 +257,7 @@ var LibraryOpenAL = { } for (var i = 0; i < count; ++i) { var gain = AL.currentContext.ctx.createGain(); - gain.connect(AL.currentContext.ctx.destination); + gain.connect(AL.currentContext.gain); AL.currentContext.src.push({ state: 0x1011 /* AL_INITIAL */, queue: [], @@ -294,6 +297,34 @@ var LibraryOpenAL = { this._velocity = val; if (this.panner) this.panner.setVelocity(val[0], val[1], val[2]); }, + get direction() { + return this._direction || [0, 0, 0]; + }, + set direction(val) { + this._direction = val; + if (this.panner) this.panner.setOrientation(val[0], val[1], val[2]); + }, + get coneOuterGain() { + return this._coneOuterGain || 0.0; + }, + set coneOuterGain(val) { + this._coneOuterGain = val; + if (this.panner) this.panner.coneOuterGain = val; + }, + get coneInnerAngle() { + return this._coneInnerAngle || 360.0; + }, + set coneInnerAngle(val) { + this._coneInnerAngle = val; + if (this.panner) this.panner.coneInnerAngle = val; + }, + get coneOuterAngle() { + return this._coneOuterAngle || 360.0; + }, + set coneOuterAngle(val) { + this._coneOuterAngle = val; + if (this.panner) this.panner.coneOuterAngle = val; + }, gain: gain, panner: null, buffersPlayed: 0, @@ -320,6 +351,12 @@ var LibraryOpenAL = { return; } switch (param) { + case 0x1001 /* AL_CONE_INNER_ANGLE */: + src.coneInnerAngle = value; + break; + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + src.coneOuterAngle = value; + break; case 0x1007 /* AL_LOOPING */: src.loop = (value === 1 /* AL_TRUE */); break; @@ -406,12 +443,15 @@ var LibraryOpenAL = { case 0x1021 /* AL_ROLLOFF_FACTOR */: src.rolloffFactor = value; break; - // case 0x1022 /* AL_CONE_OUTER_GAIN */: - // break; - // case 0x1001 /* AL_CONE_INNER_ANGLE */: - // break; - // case 0x1002 /* AL_CONE_OUTER_ANGLE */: - // break; + case 0x1022 /* AL_CONE_OUTER_GAIN */: + src.coneOuterGain = value; + break; + case 0x1001 /* AL_CONE_INNER_ANGLE */: + src.coneInnerAngle = value; + break; + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + src.coneOuterAngle = value; + break; case 0x1020 /* AL_REFERENCE_DISTANCE */: src.refDistance = value; break; @@ -443,6 +483,9 @@ var LibraryOpenAL = { case 0x1004 /* AL_POSITION */: src.position = [v1, v2, v3]; break; + case 0x1005 /* AL_DIRECTION */: + src.direction = [v1, v2, v3]; + break; case 0x1006 /* AL_VELOCITY */: src.velocity = [v1, v2, v3]; break; @@ -594,6 +637,21 @@ var LibraryOpenAL = { } }, + alIsBuffer: function(bufferId) { + if (!AL.currentContext) { + return false; + } + if (bufferId > AL.currentContext.buf.length) { + return false; + } + + if (!AL.currentContext.buf[bufferId - 1]) { + return false; + } else { + return true; + } + }, + alBufferData: function(buffer, format, data, size, freq) { if (!AL.currentContext) { #if OPENAL_DEBUG @@ -743,6 +801,12 @@ var LibraryOpenAL = { case 0x202 /* AL_SOURCE_RELATIVE */: {{{ makeSetValue('value', '0', 'src.panner ? 1 : 0', 'i32') }}}; break; + case 0x1001 /* AL_CONE_INNER_ANGLE */: + {{{ makeSetValue('value', '0', 'src.coneInnerAngle', 'i32') }}}; + break; + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + {{{ makeSetValue('value', '0', 'src.coneOuterAngle', 'i32') }}}; + break; case 0x1009 /* AL_BUFFER */: if (!src.queue.length) { {{{ makeSetValue('value', '0', '0', 'i32') }}}; @@ -809,12 +873,15 @@ var LibraryOpenAL = { case 0x1021 /* AL_ROLLOFF_FACTOR */: {{{ makeSetValue('value', '0', 'src.rolloffFactor', 'float') }}} break; - // case 0x1022 /* AL_CONE_OUTER_GAIN */: - // break; - // case 0x1001 /* AL_CONE_INNER_ANGLE */: - // break; - // case 0x1002 /* AL_CONE_OUTER_ANGLE */: - // break; + case 0x1022 /* AL_CONE_OUTER_GAIN */: + {{{ makeSetValue('value', '0', 'src.coneOuterGain', 'float') }}} + break; + case 0x1001 /* AL_CONE_INNER_ANGLE */: + {{{ makeSetValue('value', '0', 'src.coneInnerAngle', 'float') }}} + break; + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + {{{ makeSetValue('value', '0', 'src.coneOuterAngle', 'float') }}} + break; case 0x1020 /* AL_REFERENCE_DISTANCE */: {{{ makeSetValue('value', '0', 'src.refDistance', 'float') }}} break; @@ -830,6 +897,49 @@ var LibraryOpenAL = { } }, + alGetSourcefv: function(source, param, values) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alGetSourcefv called without a valid context"); +#endif + return; + } + var src = AL.currentContext.src[source - 1]; + if (!src) { +#if OPENAL_DEBUG + console.error("alGetSourcefv called with an invalid source"); +#endif + AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */; + return; + } + switch (param) { + case 0x1004 /* AL_POSITION */: + var position = src.position; + {{{ makeSetValue('values', '0', 'position[0]', 'float') }}} + {{{ makeSetValue('values', '4', 'position[1]', 'float') }}} + {{{ makeSetValue('values', '8', 'position[2]', 'float') }}} + break; + case 0x1005 /* AL_DIRECTION */: + var direction = src.direction; + {{{ makeSetValue('values', '0', 'direction[0]', 'float') }}} + {{{ makeSetValue('values', '4', 'direction[1]', 'float') }}} + {{{ makeSetValue('values', '8', 'direction[2]', 'float') }}} + break; + case 0x1006 /* AL_VELOCITY */: + var velocity = src.velocity; + {{{ makeSetValue('values', '0', 'velocity[0]', 'float') }}} + {{{ makeSetValue('values', '4', 'velocity[1]', 'float') }}} + {{{ makeSetValue('values', '8', 'velocity[2]', 'float') }}} + break; + default: +#if OPENAL_DEBUG + console.error("alGetSourcefv with param " + param + " not implemented yet"); +#endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; + break; + } + }, + alDistanceModel: function(model) { if (model !== 0 /* AL_NONE */) { #if OPENAL_DEBUG @@ -838,6 +948,136 @@ var LibraryOpenAL = { } }, + alGetListenerf: function(pname, values) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alGetListenerf called without a valid context"); +#endif + return; + } + switch (pname) { + case 0x100A /* AL_GAIN */: + {{{ makeSetValue('value', '0', 'AL.currentContext.gain.gain', 'float') }}} + break; + default: +#if OPENAL_DEBUG + console.error("alGetListenerf with param " + pname + " not implemented yet"); +#endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; + break; + } + + }, + + alGetListenerfv: function(pname, values) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alGetListenerfv called without a valid context"); +#endif + return; + } + switch (pname) { + case 0x1004 /* AL_POSITION */: + var position = AL.currentContext.ctx.listener._position || [0,0,0]; + {{{ makeSetValue('values', '0', 'position[0]', 'float') }}} + {{{ makeSetValue('values', '4', 'position[1]', 'float') }}} + {{{ makeSetValue('values', '8', 'position[2]', 'float') }}} + break; + case 0x1006 /* AL_VELOCITY */: + var velocity = AL.currentContext.ctx.listener._velocity || [0,0,0]; + {{{ makeSetValue('values', '0', 'velocity[0]', 'float') }}} + {{{ makeSetValue('values', '4', 'velocity[1]', 'float') }}} + {{{ makeSetValue('values', '8', 'velocity[2]', 'float') }}} + break; + case 0x100F /* AL_ORIENTATION */: + var orientation = AL.currentContext.ctx.listener._orientation || [0,0,0,0,0,0]; + {{{ makeSetValue('values', '0', 'orientation[0]', 'float') }}} + {{{ makeSetValue('values', '4', 'orientation[1]', 'float') }}} + {{{ makeSetValue('values', '8', 'orientation[2]', 'float') }}} + {{{ makeSetValue('values', '12', 'orientation[3]', 'float') }}} + {{{ makeSetValue('values', '16', 'orientation[4]', 'float') }}} + {{{ makeSetValue('values', '20', 'orientation[5]', 'float') }}} + break; + default: +#if OPENAL_DEBUG + console.error("alGetListenerfv with param " + pname + " not implemented yet"); +#endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; + break; + } + }, + + alGetListeneri: function(pname, value) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alGetListeneri called without a valid context"); +#endif + return; + } + switch (pname) { + default: +#if OPENAL_DEBUG + console.error("alGetListeneri with param " + pname + " not implemented yet"); +#endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; + break; + } + }, + + alListenerf: function(param, value) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alListenerf called without a valid context"); +#endif + return; + } + switch (param) { + case 0x100A /* AL_GAIN */: + AL.currentContext.gain.value = value; + break; + default: +#if OPENAL_DEBUG + console.error("alListenerf with param " + param + " not implemented yet"); +#endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; + break; + } + }, + + alEnable: function(param) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alEnable called without a valid context"); +#endif + return; + } + switch (param) { + default: +#if OPENAL_DEBUG + console.error("alEnable with param " + param + " not implemented yet"); +#endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; + break; + } + }, + + alDisable: function(param) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alDisable called without a valid context"); +#endif + return; + } + switch (pname) { + default: +#if OPENAL_DEBUG + console.error("alDisable with param " + param + " not implemented yet"); +#endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; + break; + } + }, + alListenerfv: function(param, values) { if (!AL.currentContext) { #if OPENAL_DEBUG @@ -847,32 +1087,32 @@ var LibraryOpenAL = { } switch (param) { case 0x1004 /* AL_POSITION */: - AL.currentContext.ctx.listener.setPosition( - {{{ makeGetValue('values', '0', 'float') }}}, - {{{ makeGetValue('values', '4', 'float') }}}, - {{{ makeGetValue('values', '8', 'float') }}} - ); + var x = {{{ makeGetValue('values', '0', 'float') }}}; + var y = {{{ makeGetValue('values', '4', 'float') }}}; + var z = {{{ makeGetValue('values', '8', 'float') }}}; + AL.currentContext.ctx.listener._position = [x, y, z]; + AL.currentContext.ctx.listener.setPosition(x, y, z); break; case 0x1006 /* AL_VELOCITY */: - AL.currentContext.ctx.listener.setVelocity( - {{{ makeGetValue('values', '0', 'float') }}}, - {{{ makeGetValue('values', '4', 'float') }}}, - {{{ makeGetValue('values', '8', 'float') }}} - ); + var x = {{{ makeGetValue('values', '0', 'float') }}}; + var y = {{{ makeGetValue('values', '4', 'float') }}}; + var z = {{{ makeGetValue('values', '8', 'float') }}}; + AL.currentContext.ctx.listener._velocity = [x, y, z]; + AL.currentContext.ctx.listener.setVelocity(x, y, z); break; case 0x100F /* AL_ORIENTATION */: - AL.currentContext.ctx.listener.setOrientation( - {{{ makeGetValue('values', '0', 'float') }}}, - {{{ makeGetValue('values', '4', 'float') }}}, - {{{ makeGetValue('values', '8', 'float') }}}, - {{{ makeGetValue('values', '12', 'float') }}}, - {{{ makeGetValue('values', '16', 'float') }}}, - {{{ makeGetValue('values', '20', 'float') }}} - ); + var x = {{{ makeGetValue('values', '0', 'float') }}}; + var y = {{{ makeGetValue('values', '4', 'float') }}}; + var z = {{{ makeGetValue('values', '8', 'float') }}}; + var x2 = {{{ makeGetValue('values', '12', 'float') }}}; + var y2 = {{{ makeGetValue('values', '16', 'float') }}}; + var z2 = {{{ makeGetValue('values', '20', 'float') }}}; + AL.currentContext.ctx.listener._orientation = [x, y, z, x2, y2, z2]; + AL.currentContext.ctx.listener.setOrientation(x, y, z, x2, y2, z2); break; default: #if OPENAL_DEBUG - console.log("alListenerfv with param " + param + " not implemented yet"); + console.error("alListenerfv with param " + param + " not implemented yet"); #endif AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; break; diff --git a/src/parseTools.js b/src/parseTools.js index e09cd2e244201..bad080b756fb7 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1332,7 +1332,7 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"'; if (printType[0] === '#') printType = printType.substr(1); if (ASM_JS) { - if (!ignore) return asmCoercion('SAFE_HEAP_LOAD(' + asmCoercion(offset, 'i32') + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Runtime.FLOAT_TYPES)|0) + ', ' + (!!unsigned+0) + ')', type); + if (!ignore && phase !== 'funcs') return asmCoercion('SAFE_HEAP_LOAD(' + asmCoercion(offset, 'i32') + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Runtime.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); @@ -1444,7 +1444,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"'; if (printType[0] === '#') printType = printType.substr(1); if (ASM_JS) { - if (!ignore) return asmCoercion('SAFE_HEAP_STORE(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Runtime.FLOAT_TYPES)|0) + ')', type); + if (!ignore && phase !== 'funcs') return asmCoercion('SAFE_HEAP_STORE(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Runtime.FLOAT_TYPES)|0) + ')', type); // else fall through } else { return 'SAFE_HEAP_STORE(' + offset + ', ' + value + ', ' + (ASM_JS ? 0 : printType) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')'; diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h index b6e6307bf1886..2fc82f504cdad 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -50,10 +50,14 @@ extern "C" { * return $0 + $1; * }, calc(), otherCalc()); * - * Note the {,} + * Note the { and }. If you just want to receive an output value + * (int or double) but *not* to pass any values, you can use + * EM_ASM_INT_V and EM_ASM_DOUBLE_V respectively. */ #define EM_ASM_INT(code, ...) emscripten_asm_const_int(#code, __VA_ARGS__) #define EM_ASM_DOUBLE(code, ...) emscripten_asm_const_double(#code, __VA_ARGS__) +#define EM_ASM_INT_V(code) emscripten_asm_const_int(#code) +#define EM_ASM_DOUBLE_V(code) emscripten_asm_const_double(#code) /* * Forces LLVM to not dead-code-eliminate a function. Note that @@ -227,7 +231,14 @@ void emscripten_get_canvas_size(int *width, int *height, int *isFullscreen); * absolute time, and is only meaningful in comparison to * other calls to this function. The unit is ms. */ +#if EMSCRIPTEN double emscripten_get_now(); +#else +#include +double emscripten_get_now() { + return (1000*clock())/(double)CLOCKS_PER_SEC; +} +#endif /* * Simple random number generation in [0, 1), maps to Math.random(). diff --git a/tests/box2d/Benchmark.cpp b/tests/box2d/Benchmark.cpp index 0db1d4bef6aa3..4fd7965113e55 100644 --- a/tests/box2d/Benchmark.cpp +++ b/tests/box2d/Benchmark.cpp @@ -25,6 +25,10 @@ typedef struct { #include #include +#if EMSCRIPTEN +#include +#endif + #include "Box2D/Box2D.h" using namespace std; @@ -52,6 +56,14 @@ result_t measure(clock_t *times) { return r; } +b2World *world; +clock_t *times, minn = CLOCKS_PER_SEC * 1000 * 100, maxx = -1; +b2Body* topBody; +int32 frameCounter = 0; +int responsive_main_loop; + +void iter(); + int main(int argc, char **argv) { int arg = argc > 1 ? argv[1][0] - '0' : 3; switch(arg) { @@ -64,24 +76,28 @@ int main(int argc, char **argv) { default: printf("error: %d\\n", arg); return -1; } + // do not split out warmup, do not ignore initial stalls + FRAMES += WARMUP; + WARMUP = 0; + + times = new clock_t[FRAMES]; + // Define the gravity vector. b2Vec2 gravity(0.0f, -10.0f); // Construct a world object, which will hold and simulate the rigid bodies. - b2World world(gravity); - world.SetAllowSleeping(false); + world = new b2World(gravity); + world->SetAllowSleeping(false); { b2BodyDef bd; - b2Body* ground = world.CreateBody(&bd); + b2Body* ground = world->CreateBody(&bd); b2EdgeShape shape; shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); ground->CreateFixture(&shape, 0.0f); } - b2Body* topBody; - { float32 a = 0.5f; b2PolygonShape shape; @@ -99,7 +115,7 @@ int main(int argc, char **argv) { b2BodyDef bd; bd.type = b2_dynamicBody; bd.position = y; - b2Body* body = world.CreateBody(&bd); + b2Body* body = world->CreateBody(&bd); body->CreateFixture(&shape, 5.0f); topBody = body; @@ -112,25 +128,54 @@ int main(int argc, char **argv) { } for (int32 i = 0; i < WARMUP; ++i) { - world.Step(1.0f/60.0f, 3, 3); + world->Step(1.0f/60.0f, 3, 3); + } + +#if EMSCRIPTEN + responsive_main_loop = argc > 2 ? argv[2][0] - '0' : 0; + if (responsive_main_loop) { + printf("responsive main loop\n"); + emscripten_set_main_loop(iter, 60, 1); + } else { +#endif + do { + iter(); + } while (frameCounter <= FRAMES); +#if EMSCRIPTEN } +#endif - clock_t times[FRAMES]; - for (int32 i = 0; i < FRAMES; ++i) { - clock_t start = clock(); - world.Step(1.0f/60.0f, 3, 3); - clock_t end = clock(); - times[i] = end - start; + return 0; +} + +void iter() { + if (frameCounter < FRAMES) { + clock_t start = clock(); + world->Step(1.0f/60.0f, 3, 3); + clock_t end = clock(); + clock_t curr = end - start; + times[frameCounter] = curr; + if (curr < minn) minn = curr; + if (curr > maxx) maxx = curr; #if DEBUG printf("%f :: ", topBody->GetPosition().y); - printf("%f\n", (float32)(end - start) / CLOCKS_PER_SEC * 1000); + printf("%f\n", (float32)(end - start) / CLOCKS_PER_SEC * 1000); #endif - } + frameCounter++; + return; + } + + // that's it! + + frameCounter++; result_t result = measure(times); - printf("frame averages: %.3f +- %.3f\n", result.mean, result.stddev); + printf("frame averages: %.3f +- %.3f, range: %.3f to %.3f \n", result.mean, result.stddev, float(minn)/CLOCKS_PER_SEC * 1000, float(maxx)/CLOCKS_PER_SEC * 1000); - return 0; +#if EMSCRIPTEN + emscripten_run_script("if (Module.reportCompletion) Module.reportCompletion()"); + if (responsive_main_loop) emscripten_cancel_main_loop(); +#endif } diff --git a/tests/core/test_inlinejs3.in b/tests/core/test_inlinejs3.in index e21ed041b4dc6..9ddd590708b97 100644 --- a/tests/core/test_inlinejs3.in +++ b/tests/core/test_inlinejs3.in @@ -15,6 +15,9 @@ int main(int argc, char **argv) { }, i, double(i) / 12); } + EM_ASM_INT({ globalVar = $0 }, sum); // no outputs, just input + sum = 0; + sum = EM_ASM_INT_V({ return globalVar }); // no inputs, just output printf("sum: %d\n", sum); return 0; } diff --git a/tests/core/test_longjmp_throw.cpp b/tests/core/test_longjmp_throw.cpp new file mode 100644 index 0000000000000..a5b658e8f5daa --- /dev/null +++ b/tests/core/test_longjmp_throw.cpp @@ -0,0 +1,38 @@ +#include +#include + +static jmp_buf buf; +volatile int x = 0; + +void second(void) { + printf("second\n"); + if (x == 17) throw 5; + else longjmp(buf, -1); +} + +void first(void) { + printf("first\n"); + longjmp(buf, 1); +} + +int main() { + int jmpval = setjmp(buf); + if (!jmpval) { + x++; + first(); + printf("skipped\n"); + } else if (jmpval == 1) { + printf("result: %d %d\n", x, jmpval); + x++; + try { + second(); + } catch(int a) { + x--; + second(); + } + } else if (jmpval == -1) { + printf("result: %d %d\n", x, jmpval); + } + + return 0; +} diff --git a/tests/core/test_longjmp_throw.out b/tests/core/test_longjmp_throw.out new file mode 100644 index 0000000000000..e9cc75258d28d --- /dev/null +++ b/tests/core/test_longjmp_throw.out @@ -0,0 +1,4 @@ +first +result: 1 1 +second +result: 2 -1 diff --git a/tests/poppler/utils/pdftoppm.cc b/tests/poppler/utils/pdftoppm.cc index f600e5ba37bc9..4df0f5d8f56e2 100644 --- a/tests/poppler/utils/pdftoppm.cc +++ b/tests/poppler/utils/pdftoppm.cc @@ -183,6 +183,10 @@ static void savePageSlice(PDFDoc *doc, bitmap->writePNMFile(ppmFile); } } else { +#if EMSCRIPTEN // XXX EMSCRIPTEN: avoid writing to stdout, better for benchmarking + printf("avoiding writing to stdout\n"); +#else + #ifdef _WIN32 setmode(fileno(stdout), O_BINARY); #endif @@ -194,6 +198,7 @@ static void savePageSlice(PDFDoc *doc, } else { bitmap->writePNMFile(stdout); } +#endif } } diff --git a/tests/sqlite/benchmark.c b/tests/sqlite/benchmark.c index 802abab111f49..de8007420e7bc 100644 --- a/tests/sqlite/benchmark.c +++ b/tests/sqlite/benchmark.c @@ -2,8 +2,13 @@ #include #include +#include + +int print = 1; + static int callback(void *NotUsed, int argc, char **argv, char **azColName){ int i; + if (!print) return 0; for(i=0; i 1 ? atoi(argv[1]) : 5000; + m = argc > 2 ? atoi(argv[2]) : 1; rc = sqlite3_open(":memory:", &db); if( rc ){ @@ -69,20 +78,21 @@ int main(){ #define TIME(msg) \ { \ - printf(msg " : took %d ms\n", (1000*(clock()-t))/CLOCKS_PER_SEC); \ - t = clock(); \ + int now = emscripten_get_now(); \ + printf(msg " : took %d ms\n", (int)(now - t)); \ + t = now; \ } t = clock(); - TIME("'startup'"); + TIME("'startup' - IGNORE THIS VALUE, it is an artifact"); RUN("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100));"); TIME("create table"); RUN("BEGIN;"); - // 25000 INSERTs in a transaction - for (i = 0; i < 5000; i++) { + // n*5 INSERTs in a transaction + for (i = 0; i < n; i++) { RUN("INSERT INTO t1 VALUES(1,12345,'one 1 one 1 one 1');"); RUN("INSERT INTO t1 VALUES(2,23422,'two two two two');"); RUN("INSERT INTO t1 VALUES(3,31233,'three three 33333333333 three');"); @@ -95,10 +105,13 @@ int main(){ TIME("commit"); // Counts - RUN("SELECT count(*) FROM t1;"); - RUN("SELECT count(*) FROM t1 WHERE a == 4"); - RUN("SELECT count(*) FROM t1 WHERE b > 20000 AND b < 50000;"); - RUN("SELECT count(*) FROM t1 WHERE c like '%three%';"); + for (i = 0; i < m; i++) { + print = i == 0; + RUN("SELECT count(*) FROM t1;"); + RUN("SELECT count(*) FROM t1 WHERE a == 4"); + RUN("SELECT count(*) FROM t1 WHERE b > 20000 AND b < 50000;"); + RUN("SELECT count(*) FROM t1 WHERE c like '%three%';"); + } TIME("selects"); // Index @@ -106,8 +119,11 @@ int main(){ RUN("CREATE INDEX iibb ON t1(b);"); TIME("create indexes"); - RUN("SELECT count(*) FROM t1 WHERE a == 4"); - RUN("SELECT count(*) FROM t1 WHERE b > 20000 AND b < 50000;"); + for (i = 0; i < m; i++) { + print = i == 0; + RUN("SELECT count(*) FROM t1 WHERE a == 4"); + RUN("SELECT count(*) FROM t1 WHERE b > 20000 AND b < 50000;"); + } TIME("selects with indexes"); sqlite3_close(db); diff --git a/tests/test_core.py b/tests/test_core.py index 99c69459c9563..2a2981476730e 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1157,6 +1157,16 @@ def test_longjmp_exc(self): src, output = (test_path + s for s in ('.in', '.out')) self.do_run_from_file(src, output) + def test_longjmp_throw(self): + if self.run_name == 'asm3': return self.skip('issue 2069') # FIXME + + for disable_throw in [0, 1]: + print disable_throw + Settings.DISABLE_EXCEPTION_CATCHING = disable_throw + test_path = path_from_root('tests', 'core', 'test_longjmp_throw') + src, output = (test_path + s for s in ('.cpp', '.out')) + self.do_run_from_file(src, output) + def test_setjmp_many(self): if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp: make MAX_SETJMPS take effect') @@ -1266,12 +1276,16 @@ class MyException def test_exceptions_2(self): if self.emcc_args is None: return self.skip('need emcc to add in libcxx properly') - Settings.DISABLE_EXCEPTION_CATCHING = 0 + if self.run_name == 'asm2x86': return self.skip('TODO') - test_path = path_from_root('tests', 'core', 'test_exceptions_2') - src, output = (test_path + s for s in ('.in', '.out')) + Settings.DISABLE_EXCEPTION_CATCHING = 0 - self.do_run_from_file(src, output) + for safe in [0,1]: + print safe + Settings.SAFE_HEAP = safe + test_path = path_from_root('tests', 'core', 'test_exceptions_2') + src, output = (test_path + s for s in ('.in', '.out')) + self.do_run_from_file(src, output) def test_exceptions_white_list(self): if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') @@ -2809,6 +2823,46 @@ class Bar { self.do_run(src, 'Constructing main object.\nConstructing lib object.\n', post_build=self.dlfcn_post_build) + def test_dlfcn_i64(self): + if not self.can_dlfcn(): return + if not Settings.ASM_JS: return self.skip('TODO') + + self.prep_dlfcn_lib() + Settings.EXPORTED_FUNCTIONS = ['_foo'] + lib_src = ''' + int foo(int x) { + return (long long)x / (long long)1234; + } + ''' + dirname = self.get_dir() + filename = os.path.join(dirname, 'liblib.c') + self.build(lib_src, dirname, filename) + shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) + + self.prep_dlfcn_main() + Settings.EXPORTED_FUNCTIONS = ['_main'] + src = r''' + #include + #include + #include + + typedef int (*intfunc)(int); + + void *p; + + int main() { + p = malloc(1024); + void *lib_handle = dlopen("liblib.so", 0); + printf("load %p\n", lib_handle); + intfunc x = (intfunc)dlsym(lib_handle, "foo"); + printf("foo func %p\n", x); + if (p == 0) return 1; + printf("|%d|\n", x(81234567)); + return 0; + } + ''' + self.do_run(src, '|65830|', post_build=self.dlfcn_post_build) + def test_dlfcn_qsort(self): if not self.can_dlfcn(): return diff --git a/tests/test_other.py b/tests/test_other.py index 8895a911ff449..bc05826ea0be7 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -2324,3 +2324,30 @@ def test_module_print(self): output = run_js(os.path.join(self.get_dir(), 'a.out.js'), stderr=PIPE, full_output=True, engine=NODE_JS) assert r'<{(123456789)}>' in output, output + def test_precompiled_headers(self): + self.clear() + + open('header.h', 'w').write('#define X 5\n') + Popen([PYTHON, EMCC, '-xc++-header', 'header.h', '-c']).communicate() + assert os.path.exists('header.h.gch') + + open('src.cpp', 'w').write(r''' +#include +int main() { + printf("|%d|\n", X); + return 0; +} +''') + Popen([PYTHON, EMCC, 'src.cpp', '-include', 'header.h']).communicate() + + output = run_js(self.in_dir('a.out.js'), stderr=PIPE, full_output=True, engine=NODE_JS) + assert '|5|' in output, output + + # also verify that the gch is actually used + err = Popen([PYTHON, EMCC, 'src.cpp', '-include', 'header.h', '-Xclang', '-print-stats'], stderr=PIPE).communicate() + assert '*** PCH/Modules Loaded:\nModule: header.h.gch' in err[1], err[1] + # and sanity check it is not mentioned when not + try_delete('header.h.gch') + err = Popen([PYTHON, EMCC, 'src.cpp', '-include', 'header.h', '-Xclang', '-print-stats'], stderr=PIPE).communicate() + assert '*** PCH/Modules Loaded:\nModule: header.h.gch' not in err[1], err[1] + diff --git a/tools/find_bigis.py b/tools/find_bigis.py index d11c1a814385b..1261e7fff44ea 100644 --- a/tools/find_bigis.py +++ b/tools/find_bigis.py @@ -6,7 +6,7 @@ filename = sys.argv[1] data = open(filename).read() -iss = re.findall('[^%]i\d+ [^=]', data) +iss = re.findall(' i\d+ [^=]', data) set_iss = set(iss) bigs = [] for iss in set_iss: diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index e030b707c8201..9ba6643b7193e 100644 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -11,9 +11,9 @@ def path_from_root(*pathelems): JS_OPTIMIZER = path_from_root('tools', 'js-optimizer.js') -NUM_CHUNKS_PER_CORE = 1.5 -MIN_CHUNK_SIZE = int(os.environ.get('EMCC_JSOPT_MIN_CHUNK_SIZE') or 1024*1024) # configuring this is just for debugging purposes -MAX_CHUNK_SIZE = 20*1024*1024 +NUM_CHUNKS_PER_CORE = 3 +MIN_CHUNK_SIZE = int(os.environ.get('EMCC_JSOPT_MIN_CHUNK_SIZE') or 512*1024) # configuring this is just for debugging purposes +MAX_CHUNK_SIZE = 5*1024*1024 WINDOWS = sys.platform.startswith('win') diff --git a/tools/shared.py b/tools/shared.py index f88eace0f56dc..bd1d1bee34433 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -345,7 +345,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.9.5' +EMSCRIPTEN_VERSION = '1.10.0' def generate_sanity(): return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT + '|' + get_clang_version()