diff options
90 files changed, 5472 insertions, 1916 deletions
@@ -117,3 +117,5 @@ a license to everyone to use it as detailed in LICENSE.) * Andre Weissflog <floooh@gmail.com> * Alexandre Perrot <alexandre.perrot@gmail.com> * Emerson José Silveira da Costa <emerson.costa@gmail.com> +* Jari Vetoniemi <mailroxas@gmail.com> +* Sindre Sorhus <sindresorhus@gmail.com> @@ -12,12 +12,12 @@ Current trunk code - To see a list of commits in the active development branch 'incoming', which have not yet been packaged in a release, see https://github.com/kripken/emscripten/compare/1.8.2...incoming -v1.8.2: 1/4/2013 +v1.8.2: 1/4/2014 ------------------ - Fixed glGetFramebufferAttachmentParameteriv and an issue with glGetXXX when the returned value was null. - Full list of changes: https://github.com/kripken/emscripten/compare/1.8.1...1.8.2 -v1.8.1: 1/3/2013 +v1.8.1: 1/3/2014 ------------------ - Added support for WebGL hardware instancing extension. - Improved fastcomp native LLVM backend support. @@ -146,7 +146,7 @@ Options that are modified or new in %s include: This is the recommended setting when you want a reasonably optimized build that is generated as - quickly as possible (it is much faster than -O2). + quickly as possible (it builds much faster than -O2). (Note: for details on the affects of different opt levels, see apply_opt_level() in @@ -158,20 +158,11 @@ Options that are modified or new in %s include: time in return for the smallest and fastest output. - -O3 As -O2, plus dangerous optimizations that may - break the generated code! This adds + -O3 As -O2, plus additional optimizations that can + take a significant amount of compilation time. - -s FORCE_ALIGNED_MEMORY=1 - -s DOUBLE_MODE=0 - -s PRECISE_I64_MATH=0 - --closure 1 - --llvm-lto 3 - - This is not recommended at all. A better idea - is to try each of these separately on top of - -O2 to see what works. See the wiki and - src/settings.js (for the -s options) for more - information. + For tips on optimizing your code, see + https://github.com/kripken/emscripten/wiki/Optimizing-Code -s OPTION=VALUE JavaScript code generation option passed into the emscripten compiler. For the @@ -267,8 +258,7 @@ Options that are modified or new in %s include: code size and may in some cases increase runtime speed (although the opposite can also occur). Note that it takes time to run, and - may require some changes to the code. This - is run by default in -O3. + may require some changes to the code. In asm.js mode, closure will only be used on the 'shell' code around the compiled code (the @@ -781,6 +771,14 @@ def filename_type_ending(filename): suffix = filename_type_suffix(filename) return '' if not suffix else ('.' + suffix) +# Log out times for emcc stages +log_time_last = time.time() +def log_time(name): + global log_time_last + now = time.time() + logging.debug('emcc step "%s" took %.2f seconds' % (name, now - log_time_last)) + log_time_last = now + try: call = CXX if use_cxx else CC @@ -1029,9 +1027,7 @@ try: if js_opts is None: js_opts = opt_level >= 2 if llvm_opts is None: llvm_opts = LLVM_OPT_LEVEL[opt_level] - if llvm_lto is None and opt_level >= 3: llvm_lto = 3 if opt_level == 0: debug_level = 4 - if closure is None and opt_level == 3: closure = True if llvm_lto is None and bind: logging.debug('running lto for embind') # XXX this is a workaround for a pointer issue @@ -1196,7 +1192,6 @@ try: shared.Settings.ASM_JS = 1 assert shared.Settings.ALLOW_MEMORY_GROWTH == 0, 'memory growth not supported in fastcomp yet' assert shared.Settings.UNALIGNED_MEMORY == 0, 'forced unaligned memory not supported in fastcomp' - assert shared.Settings.SAFE_HEAP == 0, 'safe heap not supported in fastcomp yet' assert shared.Settings.CHECK_HEAP_ALIGN == 0, 'check heap align not supported in fastcomp yet' assert shared.Settings.SAFE_DYNCALLS == 0, 'safe dyncalls not supported in fastcomp' assert shared.Settings.RESERVED_FUNCTION_POINTERS == 0, 'reserved function pointers not supported in fastcomp' @@ -1230,6 +1225,13 @@ try: 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: + logging.warning('asm.js+SAFE_HEAP requires js opts to be run (-O1 or above by default)') + + 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'); + sys.exit(1); + 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 @@ -1295,6 +1297,8 @@ try: temp_files = [] + log_time('parse arguments and setup') + # 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) @@ -1334,6 +1338,8 @@ try: logging.error(input_file + ': Unknown file suffix when compiling to LLVM bitcode!') sys.exit(1) + log_time('bitcodeize inputs') + if not LEAVE_INPUTS_RAW: assert len(temp_files) == len(input_files) @@ -1380,6 +1386,8 @@ try: shared.Building.link(temp_files, specified_target) exit(0) + log_time('bitcodeize inputs') + ## Continue on to create JavaScript logging.debug('will generate JavaScript') @@ -1440,15 +1448,6 @@ try: libc_files = [ 'dlmalloc.c', os.path.join('libcxx', 'new.cpp'), - os.path.join('libc', 'stdlib', 'getopt_long.c'), - os.path.join('libc', 'gen', 'err.c'), - os.path.join('libc', 'gen', 'errx.c'), - os.path.join('libc', 'gen', 'warn.c'), - os.path.join('libc', 'gen', 'warnx.c'), - os.path.join('libc', 'gen', 'verr.c'), - os.path.join('libc', 'gen', 'verrx.c'), - os.path.join('libc', 'gen', 'vwarn.c'), - os.path.join('libc', 'gen', 'vwarnx.c'), ] musl_files = [ ['internal', [ @@ -1462,6 +1461,7 @@ try: ['stdio', [ '__overflow.c', '__toread.c', + '__towrite.c', '__uflow.c', ]], ['stdlib', [ @@ -1511,6 +1511,9 @@ try: ['internal', [ 'intscan.c', ]], + ['legacy', [ + 'err.c', + ]], ['locale', [ 'iconv.c', 'iswalnum_l.c', @@ -1541,7 +1544,9 @@ try: 'wctype_l.c', ]], ['math', [ + '__cos.c', '__cosdf.c', + '__sin.c', '__sindf.c', 'ilogb.c', 'ilogbf.c', @@ -1563,6 +1568,10 @@ try: 'tgammaf.c', 'tgammal.c' ]], + ['misc', [ + 'getopt.c', + 'getopt_long.c', + ]], ['multibyte', [ 'btowc.c', 'mblen.c', @@ -1581,6 +1590,7 @@ try: 'wctomb.c', ]], ['regex', [ + 'fnmatch.c', 'regcomp.c', 'regerror.c', 'regexec.c', @@ -1594,6 +1604,7 @@ try: 'vwprintf.c', 'wprintf.c', 'fputwc.c', + 'fputws.c', ]], ['stdlib', [ 'ecvt.c', @@ -1750,15 +1761,14 @@ try: libfile = shared.Cache.get(name, create) extra_files_to_link.append(libfile) + log_time('calculate system libraries') + # First, combine the bitcode files if there are several. We must also link if we have a singleton .a if len(input_files) + len(extra_files_to_link) > 1 or \ (not LEAVE_INPUTS_RAW and not (suffix(temp_files[0]) in BITCODE_ENDINGS or suffix(temp_files[0]) in DYNAMICLIB_ENDINGS) and shared.Building.is_ar(temp_files[0])): linker_inputs = temp_files + extra_files_to_link logging.debug('linking: ' + str(linker_inputs)) - t0 = time.time() shared.Building.link(linker_inputs, in_temp(target_basename + '.bc'), force_archive_contents = len(filter(lambda temp: not temp.endswith(STATICLIB_ENDINGS), temp_files)) == 0) - t1 = time.time() - logging.debug(' linking took %.2f seconds' % (t1 - t0)) final = in_temp(target_basename + '.bc') else: if not LEAVE_INPUTS_RAW: @@ -1768,19 +1778,16 @@ try: final = in_temp(input_files[0]) shutil.copyfile(input_files[0], final) + log_time('link') + if DEBUG: logging.debug('saving intermediate processing steps to %s' % shared.EMSCRIPTEN_TEMP_DIR) intermediate_counter = 0 - intermediate_time = None def save_intermediate(name=None, suffix='js'): - global intermediate_counter, intermediate_time + global intermediate_counter shutil.copyfile(final, os.path.join(shared.EMSCRIPTEN_TEMP_DIR, 'emcc-%d%s.%s' % (intermediate_counter, '' if name is None else '-' + name, suffix))) intermediate_counter += 1 - now = time.time() - if intermediate_time: - logging.debug(' step took %.2f seconds' % (now - intermediate_time)) - intermediate_time = now if not LEAVE_INPUTS_RAW: save_intermediate('basebc', 'bc') @@ -1841,6 +1848,8 @@ try: final += '.adsimp.bc' if DEBUG: save_intermediate('adsimp', 'bc') + log_time('post-link') + # Emscripten logging.debug('LLVM => JS') extra_args = [] if not js_libraries else ['--libraries', ','.join(map(os.path.abspath, js_libraries))] @@ -1848,6 +1857,8 @@ try: final = shared.Building.emscripten(final, append_ext=False, extra_args=extra_args) if DEBUG: save_intermediate('original') + log_time('emscript (llvm=>js)') + # Embed and preload files if len(preload_files) + len(embed_files) > 0: logging.debug('setting up files') @@ -1908,9 +1919,7 @@ try: shared.try_delete(memfile) def repl(m): # handle chunking of the memory initializer - s = re.sub('[\[\]\n\(\)\. ]', '', m.groups(0)[0]) - s = s.replace('concat', ',') - if s[-1] == ',': s = s[:-1] + s = m.groups(0)[0] open(memfile, 'wb').write(''.join(map(lambda x: chr(int(x or '0')), s.split(',')))) if DEBUG: # Copy into temp dir as well, so can be run there too @@ -1921,6 +1930,7 @@ try: src = re.sub(shared.JS.memory_initializer_pattern, repl, open(final).read(), count=1) open(final + '.mem.js', 'w').write(src) final += '.mem.js' + src = None js_transform_tempfiles[-1] = final # simple text substitution preserves comment line number mappings if DEBUG: if os.path.exists(memfile): @@ -1928,6 +1938,17 @@ try: logging.debug('wrote memory initialization to %s' % memfile) else: logging.debug('did not see memory initialization') + elif shared.Settings.USE_TYPED_ARRAYS == 2 and not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE: + # not writing a binary init, but we can at least optimize them by splitting them up + src = open(final).read() + src = shared.JS.optimize_initializer(src) + if src is not None: + logging.debug('optimizing memory initialization') + open(final + '.mem.js', 'w').write(src) + final += '.mem.js' + src = None + + log_time('source transforms') # It is useful to run several js optimizer passes together, to save on unneeded unparsing/reparsing js_optimizer_queue = [] @@ -1989,15 +2010,20 @@ try: if DEBUG: save_intermediate('closure') if js_opts: + if shared.Settings.ASM_JS and shared.Settings.SAFE_HEAP: js_optimizer_queue += ['safeHeap'] + if shared.Settings.OUTLINING_LIMIT > 0 and shared.Settings.ASM_JS: 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: - js_optimizer_queue += ['registerize'] + 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 debug_level < 2 and shared.Settings.ASM_JS: js_optimizer_queue = map(lambda p: p if p != 'registerize' else 'registerizeAndMinify', js_optimizer_queue) + if debug_level < 2 and shared.Settings.ASM_JS: js_optimizer_queue += ['minifyNames'] if debug_level == 0: js_optimizer_queue += ['minifyWhitespace'] if closure and shared.Settings.ASM_JS: @@ -2007,10 +2033,12 @@ try: flush_js_optimizer_queue() + log_time('js opts') + # Remove some trivial whitespace # TODO: do not run when compress has already been done on all parts of the code - src = open(final).read() - src = re.sub(r'\n+[ \n]*\n+', '\n', src) - open(final, 'w').write(src) + #src = open(final).read() + #src = re.sub(r'\n+[ \n]*\n+', '\n', src) + #open(final, 'w').write(src) def generate_source_map(map_file_base_name, offset=0): jsrun.run_js(shared.path_from_root('tools', 'source-maps', 'sourcemapper.js'), @@ -2113,6 +2141,8 @@ try: # copy final JS to output shutil.move(final, target) + log_time('final emitting') + if DEBUG: logging.debug('total time: %.2f seconds' % (time.time() - start_time)) finally: diff --git a/emscripten.py b/emscripten.py index befad8d5..725f573f 100755 --- a/emscripten.py +++ b/emscripten.py @@ -455,7 +455,7 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat'] + [m.replace('.', '_') for m in math_envs] if settings['RESERVED_FUNCTION_POINTERS'] > 0: basic_funcs.append('jsCall') - if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE', 'SAFE_HEAP_CLEAR'] + if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE'] if settings['CHECK_HEAP_ALIGN']: basic_funcs += ['CHECK_ALIGN_2', 'CHECK_ALIGN_4', 'CHECK_ALIGN_8'] if settings['ASSERTIONS']: basic_funcs += ['nullFunc'] @@ -725,7 +725,7 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None, outfile: The file where the output is written. """ - assert(settings['ASM_JS']) # TODO: apply ASM_JS even in -O0 for fastcomp + assert(settings['ASM_JS']) # Overview: # * Run LLVM backend to emit JS. JS includes function bodies, memory initializer, @@ -956,7 +956,7 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None, basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat'] + [m.replace('.', '_') for m in math_envs] if settings['RESERVED_FUNCTION_POINTERS'] > 0: basic_funcs.append('jsCall') - if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE', 'SAFE_HEAP_CLEAR'] + if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE'] if settings['CHECK_HEAP_ALIGN']: basic_funcs += ['CHECK_ALIGN_2', 'CHECK_ALIGN_4', 'CHECK_ALIGN_8'] if settings['ASSERTIONS']: basic_funcs += ['nullFunc'] diff --git a/src/compiler.js b/src/compiler.js index e4ce1c88..17a8e83c 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -183,9 +183,6 @@ if (SAFE_HEAP) USE_BSS = 0; // must initialize heap for safe heap // Settings sanity checks assert(!(USE_TYPED_ARRAYS === 2 && QUANTUM_SIZE !== 4), 'For USE_TYPED_ARRAYS == 2, must have normal QUANTUM_SIZE of 4'); -if (ASM_JS) { - assert(!ALLOW_MEMORY_GROWTH, 'Cannot grow asm.js heap'); -} assert(!(!NAMED_GLOBALS && BUILD_AS_SHARED_LIB), 'shared libraries must have named globals'); // Output some info and warnings based on settings diff --git a/src/headless.js b/src/headless.js index e5458641..5880c087 100644 --- a/src/headless.js +++ b/src/headless.js @@ -82,6 +82,16 @@ var window = { } listeners.push(func); }, + removeEventListener: function(id, func) { + var listeners = this.eventListeners[id]; + if (!listeners) return; + for (var i = 0; i < listeners.length; i++) { + if (listeners[i] === func) { + listeners.splice(i, 1); + return; + } + } + }, callEventListeners: function(id) { var listeners = this.eventListeners[id]; if (listeners) { @@ -101,6 +111,7 @@ var document = { headless: true, eventListeners: {}, addEventListener: window.addEventListener, + removeEventListener: window.removeEventListener, callEventListeners: window.callEventListeners, getElementById: function(id) { switch(id) { @@ -144,6 +155,7 @@ var document = { }, eventListeners: {}, addEventListener: document.addEventListener, + removeEventListener: document.removeEventListener, callEventListeners: document.callEventListeners, }; }; diff --git a/src/headlessCanvas.js b/src/headlessCanvas.js index 4951aed8..6b0f9d47 100644 --- a/src/headlessCanvas.js +++ b/src/headlessCanvas.js @@ -600,6 +600,7 @@ function headlessCanvas() { style: {}, eventListeners: {}, addEventListener: function(){}, + removeEventListener: function(){}, requestFullScreen: function() { document.fullscreenElement = document.getElementById('canvas'); window.setTimeout(function() { diff --git a/src/library.js b/src/library.js index 69569601..bc577e78 100644 --- a/src/library.js +++ b/src/library.js @@ -100,7 +100,7 @@ LibraryManager.library = { return FS.handleFSError(e); } if (stream.position < 0 || stream.position >= entries.length) { - {{{ makeSetValue('result', '0', '0', 'i8*') }}} + {{{ makeSetValue('result', '0', '0', 'i8*') }}}; return 0; } var id; @@ -118,15 +118,15 @@ LibraryManager.library = { FS.isLink(child.mode) ? 10 : // DT_LNK, symbolic link. 8; // DT_REG, regular file. } - {{{ makeSetValue('entry', C_STRUCTS.dirent.d_ino, 'id', 'i32') }}} - {{{ makeSetValue('entry', C_STRUCTS.dirent.d_off, 'offset', 'i32') }}} - {{{ makeSetValue('entry', C_STRUCTS.dirent.d_reclen, 'name.length + 1', 'i32') }}} + {{{ makeSetValue('entry', C_STRUCTS.dirent.d_ino, 'id', 'i32') }}}; + {{{ makeSetValue('entry', C_STRUCTS.dirent.d_off, 'offset', 'i32') }}}; + {{{ makeSetValue('entry', C_STRUCTS.dirent.d_reclen, 'name.length + 1', 'i32') }}}; for (var i = 0; i < name.length; i++) { - {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', 'name.charCodeAt(i)', 'i8') }}} + {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', 'name.charCodeAt(i)', 'i8') }}}; } - {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', '0', 'i8') }}} - {{{ makeSetValue('entry', C_STRUCTS.dirent.d_type, 'type', 'i8') }}} - {{{ makeSetValue('result', '0', 'entry', 'i8*') }}} + {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', '0', 'i8') }}}; + {{{ makeSetValue('entry', C_STRUCTS.dirent.d_type, 'type', 'i8') }}}; + {{{ makeSetValue('result', '0', 'entry', 'i8*') }}}; stream.position++; return 0; }, @@ -149,8 +149,6 @@ LibraryManager.library = { } return {{{ makeGetValue(0, '_readdir.result', 'i8*') }}}; }, - __01readdir64_: 'readdir', - // TODO: Check if we need to link any other aliases. // ========================================================================== // utime.h @@ -207,13 +205,13 @@ LibraryManager.library = { var length = i; if (allSlashes) { // All slashes result in a single slash. - {{{ makeSetValue('path', '1', '0', 'i8') }}} + {{{ makeSetValue('path', '1', '0', 'i8') }}}; return [path, -1]; } else { // Strip trailing slashes. while (slashPositions.length && slashPositions[slashPositions.length - 1] == length - 1) { - {{{ makeSetValue('path', 'slashPositions.pop(i)', '0', 'i8') }}} + {{{ makeSetValue('path', 'slashPositions.pop(i)', '0', 'i8') }}}; length--; } return [path, slashPositions.pop()]; @@ -227,16 +225,15 @@ LibraryManager.library = { var result = ___libgenSplitName(path); return result[0] + result[1] + 1; }, - __xpg_basename: 'basename', dirname__deps: ['__libgenSplitName'], dirname: function(path) { // char *dirname(char *path); // http://pubs.opengroup.org/onlinepubs/007908799/xsh/dirname.html var result = ___libgenSplitName(path); if (result[1] == 0) { - {{{ makeSetValue('result[0]', 1, '0', 'i8') }}} + {{{ makeSetValue('result[0]', 1, '0', 'i8') }}}; } else if (result[1] !== -1) { - {{{ makeSetValue('result[0]', 'result[1]', '0', 'i8') }}} + {{{ makeSetValue('result[0]', 'result[1]', '0', 'i8') }}}; } return result[0]; }, @@ -257,22 +254,22 @@ LibraryManager.library = { {{{ makeSetValue('buf', C_STRUCTS.stat.st_dev, 'stat.dev', 'i32') }}}; {{{ makeSetValue('buf', C_STRUCTS.stat.__st_dev_padding, '0', 'i32') }}}; {{{ makeSetValue('buf', C_STRUCTS.stat.__st_ino_truncated, 'stat.ino', 'i32') }}}; - {{{ makeSetValue('buf', C_STRUCTS.stat.st_mode, 'stat.mode', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_nlink, 'stat.nlink', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_uid, 'stat.uid', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_gid, 'stat.gid', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_rdev, 'stat.rdev', 'i32') }}} + {{{ makeSetValue('buf', C_STRUCTS.stat.st_mode, 'stat.mode', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_nlink, 'stat.nlink', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_uid, 'stat.uid', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_gid, 'stat.gid', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_rdev, 'stat.rdev', 'i32') }}}; {{{ makeSetValue('buf', C_STRUCTS.stat.__st_rdev_padding, '0', 'i32') }}}; - {{{ makeSetValue('buf', C_STRUCTS.stat.st_size, 'stat.size', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_blksize, '4096', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_blocks, 'stat.blocks', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_sec, 'Math.floor(stat.atime.getTime() / 1000)', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_nsec, '0', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_sec, 'Math.floor(stat.mtime.getTime() / 1000)', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_nsec, '0', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_sec, 'Math.floor(stat.ctime.getTime() / 1000)', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_nsec, '0', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_ino, 'stat.ino', 'i32') }}} + {{{ makeSetValue('buf', C_STRUCTS.stat.st_size, 'stat.size', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_blksize, '4096', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_blocks, 'stat.blocks', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_sec, 'Math.floor(stat.atime.getTime() / 1000)', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_nsec, '0', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_sec, 'Math.floor(stat.mtime.getTime() / 1000)', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_nsec, '0', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_sec, 'Math.floor(stat.ctime.getTime() / 1000)', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_nsec, '0', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_ino, 'stat.ino', 'i32') }}}; return 0; } catch (e) { FS.handleFSError(e); @@ -395,14 +392,6 @@ LibraryManager.library = { _umask.cmask = newMask; return oldMask; }, - stat64: 'stat', - fstat64: 'fstat', - lstat64: 'lstat', - __01fstat64_: 'fstat', - __01stat64_: 'stat', - __01lstat64_: 'lstat', - - // TODO: Check if other aliases are needed. // ========================================================================== // sys/statvfs.h @@ -414,17 +403,17 @@ LibraryManager.library = { // int statvfs(const char *restrict path, struct statvfs *restrict buf); // NOTE: None of the constants here are true. We're just returning safe and // sane values. - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bsize, '4096', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_frsize, '4096', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_blocks, '1000000', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bfree, '500000', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bavail, '500000', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_files, 'FS.nextInode', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_ffree, '1000000', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_favail, '1000000', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_fsid, '42', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_flag, '2', 'i32') }}} // ST_NOSUID - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_namemax, '255', 'i32') }}} + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bsize, '4096', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_frsize, '4096', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_blocks, '1000000', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bfree, '500000', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bavail, '500000', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_files, 'FS.nextInode', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_ffree, '1000000', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_favail, '1000000', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_fsid, '42', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_flag, '2', 'i32') }}}; // ST_NOSUID + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_namemax, '255', 'i32') }}}; return 0; }, fstatvfs__deps: ['statvfs'], @@ -433,8 +422,6 @@ LibraryManager.library = { // http://pubs.opengroup.org/onlinepubs/009604499/functions/statvfs.html return _statvfs(0, buf); }, - __01statvfs64_: 'statvfs', - __01fstatvfs64_: 'fstatvfs', // ========================================================================== // fcntl.h @@ -515,7 +502,7 @@ LibraryManager.library = { var arg = {{{ makeGetValue('varargs', 0, 'i32') }}}; var offset = {{{ C_STRUCTS.flock.l_type }}}; // We're always unlocked. - {{{ makeSetValue('arg', 'offset', cDefine('F_UNLCK'), 'i16') }}} + {{{ makeSetValue('arg', 'offset', cDefine('F_UNLCK'), 'i16') }}}; return 0; case {{{ cDefine('F_SETLK') }}}: case {{{ cDefine('F_SETLKW') }}}: @@ -571,6 +558,25 @@ LibraryManager.library = { }, // ========================================================================== + // nl_types.h + // ========================================================================== + + catopen: function(name, oflag) { + // nl_catd catopen (const char *name, int oflag) + return -1; + }, + + catgets: function(catd, set_id, msg_id, s) { + // char *catgets (nl_catd catd, int set_id, int msg_id, const char *s) + return s; + }, + + catclose: function(catd) { + // int catclose (nl_catd catd) + return 0; + }, + + // ========================================================================== // poll.h // ========================================================================== @@ -594,7 +600,7 @@ LibraryManager.library = { } mask &= events | {{{ cDefine('POLLERR') }}} | {{{ cDefine('POLLHUP') }}}; if (mask) nonzero++; - {{{ makeSetValue('pollfd', C_STRUCTS.pollfd.revents, 'mask', 'i16') }}} + {{{ makeSetValue('pollfd', C_STRUCTS.pollfd.revents, 'mask', 'i16') }}}; } return nonzero; }, @@ -1174,7 +1180,7 @@ LibraryManager.library = { } else { var length = Math.min(len, value.length); for (var i = 0; i < length; i++) { - {{{ makeSetValue('buf', 'i', 'value.charCodeAt(i)', 'i8') }}} + {{{ makeSetValue('buf', 'i', 'value.charCodeAt(i)', 'i8') }}}; } if (len > length) {{{ makeSetValue('buf', 'i++', '0', 'i8') }}} return i; @@ -1223,9 +1229,9 @@ LibraryManager.library = { // int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); // http://linux.die.net/man/2/getresuid // We have just one process/group/user, all with ID 0. - {{{ makeSetValue('ruid', '0', '0', 'i32') }}} - {{{ makeSetValue('euid', '0', '0', 'i32') }}} - {{{ makeSetValue('suid', '0', '0', 'i32') }}} + {{{ makeSetValue('ruid', '0', '0', 'i32') }}}; + {{{ makeSetValue('euid', '0', '0', 'i32') }}}; + {{{ makeSetValue('suid', '0', '0', 'i32') }}}; return 0; }, getresgid: 'getresuid', @@ -1237,7 +1243,7 @@ LibraryManager.library = { ___setErrNo(ERRNO_CODES.EINVAL); return -1; } else { - {{{ makeSetValue('grouplist', '0', '0', 'i32') }}} + {{{ makeSetValue('grouplist', '0', '0', 'i32') }}}; return 1; } }, @@ -1270,10 +1276,10 @@ LibraryManager.library = { } var length = Math.min(namelen, host.length); for (var i = 0; i < length; i++) { - {{{ makeSetValue('name', 'i', 'host.charCodeAt(i)', 'i8') }}} + {{{ makeSetValue('name', 'i', 'host.charCodeAt(i)', 'i8') }}}; } if (namelen > length) { - {{{ makeSetValue('name', 'i', '0', 'i8') }}} + {{{ makeSetValue('name', 'i', '0', 'i8') }}}; return 0; } else { ___setErrNo(ERRNO_CODES.ENAMETOOLONG); @@ -1390,8 +1396,8 @@ LibraryManager.library = { for (var i = 0; i < nbytes; i += 2) { var first = {{{ makeGetValue('src', 'i', 'i8') }}}; var second = {{{ makeGetValue('src', 'i + 1', 'i8') }}}; - {{{ makeSetValue('dest', 'i', 'second', 'i8') }}} - {{{ makeSetValue('dest', 'i + 1', 'first', 'i8') }}} + {{{ makeSetValue('dest', 'i', 'second', 'i8') }}}; + {{{ makeSetValue('dest', 'i + 1', 'first', 'i8') }}}; } }, tcgetpgrp: function(fildes) { @@ -1565,14 +1571,6 @@ LibraryManager.library = { if (bytes != 0) self.alloc(bytes); return ret; // Previous break location. }, - open64: 'open', - lseek64: 'lseek', - ftruncate64: 'ftruncate', - __01open64_: 'open', - __01lseek64_: 'lseek', - __01truncate64_: 'truncate', - __01ftruncate64_: 'ftruncate', - // TODO: Check if any other aliases are needed. // ========================================================================== // stdio.h @@ -1804,7 +1802,7 @@ LibraryManager.library = { break; case 'X': case 'x': - {{{ makeSetValue('argPtr', 0, 'parseInt(text, 16)', 'i32') }}} + {{{ makeSetValue('argPtr', 0, 'parseInt(text, 16)', 'i32') }}}; break; case 'F': case 'f': @@ -1815,15 +1813,15 @@ LibraryManager.library = { case 'E': // fallthrough intended if (long_) { - {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'double') }}} + {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'double') }}}; } else { - {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'float') }}} + {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'float') }}}; } break; case 's': var array = intArrayFromString(text); for (var j = 0; j < array.length; j++) { - {{{ makeSetValue('argPtr', 'j', 'array[j]', 'i8') }}} + {{{ makeSetValue('argPtr', 'j', 'array[j]', 'i8') }}}; } break; } @@ -2259,7 +2257,7 @@ LibraryManager.library = { case 'n': { // Write the length written so far to the next parameter. var ptr = getNextArg('i32*'); - {{{ makeSetValue('ptr', '0', 'ret.length', 'i32') }}} + {{{ makeSetValue('ptr', '0', 'ret.length', 'i32') }}}; break; } case '%': { @@ -2386,9 +2384,9 @@ LibraryManager.library = { ___setErrNo(ERRNO_CODES.ESPIPE); return -1; } - {{{ makeSetValue('pos', '0', 'stream.position', 'i32') }}} + {{{ makeSetValue('pos', '0', 'stream.position', 'i32') }}}; var state = (stream.eof ? 1 : 0) + (stream.error ? 2 : 0); - {{{ makeSetValue('pos', Runtime.getNativeTypeSize('i32'), 'state', 'i32') }}} + {{{ makeSetValue('pos', Runtime.getNativeTypeSize('i32'), 'state', 'i32') }}}; return 0; }, fgets__deps: ['fgetc'], @@ -2405,9 +2403,9 @@ LibraryManager.library = { if (streamObj.error || (streamObj.eof && i == 0)) return 0; else if (streamObj.eof) break; } - {{{ makeSetValue('s', 'i', 'byte_', 'i8') }}} + {{{ makeSetValue('s', 'i', 'byte_', 'i8') }}}; } - {{{ makeSetValue('s', 'i', '0', 'i8') }}} + {{{ makeSetValue('s', 'i', '0', 'i8') }}}; return s; }, gets__deps: ['fgets'], @@ -2471,7 +2469,7 @@ LibraryManager.library = { // int fputc(int c, FILE *stream); // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html var chr = unSign(c & 0xFF); - {{{ makeSetValue('_fputc.ret', '0', 'chr', 'i8') }}} + {{{ makeSetValue('_fputc.ret', '0', 'chr', 'i8') }}}; var ret = _write(stream, _fputc.ret, 1); if (ret == -1) { var streamObj = FS.getStream(stream); @@ -2525,7 +2523,7 @@ LibraryManager.library = { return 0; } while (streamObj.ungotten.length && bytesToRead > 0) { - {{{ makeSetValue('ptr++', '0', 'streamObj.ungotten.pop()', 'i8') }}} + {{{ makeSetValue('ptr++', '0', 'streamObj.ungotten.pop()', 'i8') }}}; bytesToRead--; bytesRead++; } @@ -2568,7 +2566,6 @@ LibraryManager.library = { return 0; }, fseeko: 'fseek', - fseeko64: 'fseek', fsetpos__deps: ['$FS', 'lseek', '__setErrNo', '$ERRNO_CODES'], fsetpos: function(stream, pos) { // int fsetpos(FILE *stream, const fpos_t *pos); @@ -2605,7 +2602,6 @@ LibraryManager.library = { } }, ftello: 'ftell', - ftello64: 'ftell', fwrite__deps: ['$FS', 'write'], fwrite: function(ptr, size, nitems, stream) { // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream); @@ -2897,22 +2893,6 @@ LibraryManager.library = { }, #endif - fopen64: 'fopen', - __01fopen64_: 'fopen', - __01freopen64_: 'freopen', - __01fseeko64_: 'fseek', - __01ftello64_: 'ftell', - __01tmpfile64_: 'tmpfile', - __isoc99_fscanf: 'fscanf', - // TODO: Check if any other aliases are needed. - _IO_getc: 'getc', - _IO_putc: 'putc', - _ZNSo3putEc: 'putchar', - _ZNSo5flushEv__deps: ['fflush', 'stdout'], - _ZNSo5flushEv: function() { - _fflush({{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}}); - }, - // ========================================================================== // sys/mman.h // ========================================================================== @@ -2950,7 +2930,6 @@ LibraryManager.library = { _mmap.mappings[ptr] = { malloc: ptr, num: num, allocated: allocated }; return ptr; }, - __01mmap64_: 'mmap', munmap: function(start, num) { if (!_mmap.mappings) _mmap.mappings = {}; @@ -3147,7 +3126,7 @@ LibraryManager.library = { // Set end pointer. if (endptr) { - {{{ makeSetValue('endptr', 0, 'str', '*') }}} + {{{ makeSetValue('endptr', 0, 'str', '*') }}}; } // Unsign if needed. @@ -3233,7 +3212,7 @@ LibraryManager.library = { // Set end pointer. if (endptr) { - {{{ makeSetValue('endptr', 0, 'str', '*') }}} + {{{ makeSetValue('endptr', 0, 'str', '*') }}}; } try { @@ -3327,7 +3306,7 @@ LibraryManager.library = { poolPtr = allocate(TOTAL_ENV_SIZE, 'i8', ALLOC_STATIC); envPtr = allocate(MAX_ENV_VALUES * {{{ Runtime.QUANTUM_SIZE }}}, 'i8*', ALLOC_STATIC); - {{{ makeSetValue('envPtr', '0', 'poolPtr', 'i8*') }}} + {{{ makeSetValue('envPtr', '0', 'poolPtr', 'i8*') }}}; {{{ makeSetValue(makeGlobalUse('_environ'), 0, 'envPtr', 'i8*') }}}; } else { envPtr = {{{ makeGetValue(makeGlobalUse('_environ'), '0', 'i8**') }}}; @@ -3451,7 +3430,7 @@ LibraryManager.library = { var limit = Math.min(nelem, 3); var doubleSize = {{{ Runtime.getNativeTypeSize('double') }}}; for (var i = 0; i < limit; i++) { - {{{ makeSetValue('loadavg', 'i * doubleSize', '0.1', 'double') }}} + {{{ makeSetValue('loadavg', 'i * doubleSize', '0.1', 'double') }}}; } return limit; }, @@ -3480,9 +3459,9 @@ LibraryManager.library = { } else { var size = Math.min(4095, absolute.path.length); // PATH_MAX - 1. for (var i = 0; i < size; i++) { - {{{ makeSetValue('resolved_name', 'i', 'absolute.path.charCodeAt(i)', 'i8') }}} + {{{ makeSetValue('resolved_name', 'i', 'absolute.path.charCodeAt(i)', 'i8') }}}; } - {{{ makeSetValue('resolved_name', 'size', '0', 'i8') }}} + {{{ makeSetValue('resolved_name', 'size', '0', 'i8') }}}; return resolved_name; } }, @@ -3690,7 +3669,7 @@ LibraryManager.library = { var padding = 0, curr = 0, i = 0; while ((i|0) < (num|0)) { curr = padding ? 0 : {{{ makeGetValueAsm('psrc', 'i', 'i8') }}}; - {{{ makeSetValue('pdest', 'i', 'curr', 'i8') }}} + {{{ makeSetValue('pdest', 'i', 'curr', 'i8') }}}; padding = padding ? 1 : ({{{ makeGetValueAsm('psrc', 'i', 'i8') }}} == 0); i = (i+1)|0; } @@ -3743,7 +3722,7 @@ LibraryManager.library = { if ({{{ makeGetValue('pdest', 'len+i', 'i8') }}} == 0) break; i ++; if (i == num) { - {{{ makeSetValue('pdest', 'len+i', 0, 'i8') }}} + {{{ makeSetValue('pdest', 'len+i', 0, 'i8') }}}; break; } } @@ -3830,6 +3809,7 @@ LibraryManager.library = { }, strnlen: function(ptr, num) { + num = num >>> 0; for (var i = 0; i < num; i++) { if ({{{ makeGetValue('ptr', 0, 'i8') }}} == 0) return i; ptr++; @@ -4110,7 +4090,7 @@ LibraryManager.library = { var i16size = {{{ Runtime.getNativeTypeSize('i16') }}}; var arr = _malloc(values.length * i16size); for (var i = 0; i < values.length; i++) { - {{{ makeSetValue('arr', 'i * i16size', 'values[i]', 'i16') }}} + {{{ makeSetValue('arr', 'i * i16size', 'values[i]', 'i16') }}}; } me.ret = allocate([arr + 128 * i16size], 'i16*', ALLOC_NORMAL); } @@ -4138,7 +4118,7 @@ LibraryManager.library = { var i32size = {{{ Runtime.getNativeTypeSize('i32') }}}; var arr = _malloc(values.length * i32size); for (var i = 0; i < values.length; i++) { - {{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}} + {{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}}; } me.ret = allocate([arr + 128 * i32size], 'i32*', ALLOC_NORMAL); } @@ -4165,7 +4145,7 @@ LibraryManager.library = { var i32size = {{{ Runtime.getNativeTypeSize('i32') }}}; var arr = _malloc(values.length * i32size); for (var i = 0; i < values.length; i++) { - {{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}} + {{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}}; } me.ret = allocate([arr + 128 * i32size], 'i32*', ALLOC_NORMAL); } @@ -4311,6 +4291,8 @@ LibraryManager.library = { abort('trap!'); }, + llvm_prefetch: function(){}, + __assert_fail: function(condition, filename, line, func) { ABORT = true; throw 'Assertion failed: ' + Pointer_stringify(condition) + ', at: ' + [filename ? Pointer_stringify(filename) : 'unknown filename', line, func ? Pointer_stringify(func) : 'unknown function'] + ' at ' + stackTrace(); @@ -4367,9 +4349,9 @@ 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*') }}} + {{{ 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*') }}}; if (!("uncaught_exception" in __ZSt18uncaught_exceptionv)) { __ZSt18uncaught_exceptionv.uncaught_exception = 1; } else { @@ -4415,18 +4397,18 @@ LibraryManager.library = { __THREW__ = 0; #endif // Clear type. - {{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, '0', 'void*') }}} + {{{ 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') }}} + {{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, '0', 'i32') }}}; } // Free ptr if it isn't null. if (ptr) { ___cxa_free_exception(ptr); - {{{ makeSetValue('_llvm_eh_exception.buf', '0', '0', 'void*') }}} + {{{ makeSetValue('_llvm_eh_exception.buf', '0', '0', 'void*') }}}; } }, __cxa_get_exception_ptr__deps: ['llvm_eh_exception'], @@ -4447,14 +4429,6 @@ LibraryManager.library = { throw exception; }, - _Unwind_Resume_or_Rethrow: function(ptr) { - {{{ makeThrow('ptr') }}}; - }, - _Unwind_RaiseException: function(ptr) { - {{{ makeThrow('ptr') }}}; - }, - _Unwind_DeleteException: function(ptr) {}, - terminate: '__cxa_call_unexpected', __gxx_personality_v0__deps: ['llvm_eh_exception', '_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch'], @@ -4567,7 +4541,20 @@ LibraryManager.library = { } }, - _ZNSt9exceptionD2Ev: function(){}, // XXX a dependency of dlmalloc, but not actually needed if libcxx is not anyhow included + // Destructors for std::exception since we don't have them implemented in libcxx as we aren't using libcxxabi. + // These are also needed for the dlmalloc tests. + _ZNSt9exceptionD1Ev: function() {}, + _ZNSt9exceptionD2Ev: function() {}, + + _ZNKSt9exception4whatEv__deps: ['_malloc'], + _ZNKSt9exception4whatEv: function() { + if (!__ZNKSt9exception4whatEv.buffer) { + var name = "std::exception"; + __ZNKSt9exception4whatEv.buffer = _malloc(name.length + 1); + writeStringToMemory(name, __ZNKSt9exception4whatEv.buffer); + } + return __ZNKSt9exception4whatEv.buffer; + }, _ZNSt9type_infoD2Ev: function(){}, @@ -4837,11 +4824,11 @@ LibraryManager.library = { cbrtl: 'cbrt', modf: function(x, intpart) { - {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'double') }}} + {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'double') }}}; return x - {{{ makeGetValue('intpart', 0, 'double') }}}; }, modff: function(x, intpart) { - {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'float') }}} + {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'float') }}}; return x - {{{ makeGetValue('intpart', 0, 'float') }}}; }, frexp: function(x, exp_addr) { @@ -4857,7 +4844,7 @@ LibraryManager.library = { if (exp_ === raw_exp) exp_ += 1; sig = sign*x/Math.pow(2, exp_); } - {{{ makeSetValue('exp_addr', 0, 'exp_', 'i32') }}} + {{{ makeSetValue('exp_addr', 0, 'exp_', 'i32') }}}; return sig; }, frexpf: 'frexp', @@ -5365,7 +5352,7 @@ LibraryManager.library = { time: function(ptr) { var ret = Math.floor(Date.now()/1000); if (ptr) { - {{{ makeSetValue('ptr', 0, 'ret', 'i32') }}} + {{{ makeSetValue('ptr', 0, 'ret', 'i32') }}}; } return ret; }, @@ -5392,9 +5379,9 @@ LibraryManager.library = { {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_min, 'i32') }}}, {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'i32') }}}, 0).getTime() / 1000; - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'new Date(timestamp).getDay()', 'i32') }}} + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'new Date(timestamp).getDay()', 'i32') }}}; var yday = Math.round((timestamp - (new Date(year, 0, 1)).getTime()) / (1000 * 60 * 60 * 24)); - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}} + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}; return timestamp; }, timelocal: 'mktime', @@ -5407,15 +5394,15 @@ LibraryManager.library = { gmtime_r__deps: ['__tm_timezone'], gmtime_r: function(time, tmPtr) { var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000); - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getUTCSeconds()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getUTCMinutes()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getUTCHours()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getUTCDate()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getUTCMonth()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getUTCFullYear()-1900', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getUTCDay()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, '0', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}} + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getUTCSeconds()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getUTCMinutes()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getUTCHours()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getUTCDate()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getUTCMonth()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getUTCFullYear()-1900', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getUTCDay()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, '0', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}}; var start = new Date(date); // define date using UTC, start from Jan 01 00:00:00 UTC start.setUTCDate(1); start.setUTCMonth(0); @@ -5424,8 +5411,8 @@ LibraryManager.library = { start.setUTCSeconds(0); start.setUTCMilliseconds(0); var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}} + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}}; return tmPtr; }, @@ -5448,23 +5435,23 @@ LibraryManager.library = { localtime_r: function(time, tmPtr) { _tzset(); var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000); - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getSeconds()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getMinutes()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getHours()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getDate()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getMonth()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getFullYear()-1900', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getDay()', 'i32') }}} + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getSeconds()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getMinutes()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getHours()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getDate()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getMonth()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getFullYear()-1900', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getDay()', 'i32') }}}; var start = new Date(date.getFullYear(), 0, 1); var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, 'start.getTimezoneOffset() * 60', 'i32') }}} + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, 'start.getTimezoneOffset() * 60', 'i32') }}}; var dst = Number(start.getTimezoneOffset() != date.getTimezoneOffset()); - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, 'dst', 'i32') }}} + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, 'dst', 'i32') }}}; - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}} + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}}; return tmPtr; }, @@ -5482,9 +5469,9 @@ LibraryManager.library = { var timePart = formatted.match(/\d{2}:\d{2}:\d{2}/)[0]; formatted = datePart + timePart + ' ' + date.getFullYear() + '\n'; formatted.split('').forEach(function(chr, index) { - {{{ makeSetValue('buf', 'index', 'chr.charCodeAt(0)', 'i8') }}} + {{{ makeSetValue('buf', 'index', 'chr.charCodeAt(0)', 'i8') }}}; }); - {{{ makeSetValue('buf', '25', '0', 'i8') }}} + {{{ makeSetValue('buf', '25', '0', 'i8') }}}; return buf; }, @@ -5514,18 +5501,18 @@ LibraryManager.library = { if (_tzset.called) return; _tzset.called = true; - {{{ makeSetValue(makeGlobalUse('_timezone'), '0', '-(new Date()).getTimezoneOffset() * 60', 'i32') }}} + {{{ makeSetValue(makeGlobalUse('_timezone'), '0', '-(new Date()).getTimezoneOffset() * 60', 'i32') }}}; var winter = new Date(2000, 0, 1); var summer = new Date(2000, 6, 1); - {{{ makeSetValue(makeGlobalUse('_daylight'), '0', 'Number(winter.getTimezoneOffset() != summer.getTimezoneOffset())', 'i32') }}} + {{{ makeSetValue(makeGlobalUse('_daylight'), '0', 'Number(winter.getTimezoneOffset() != summer.getTimezoneOffset())', 'i32') }}}; var winterName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | winter.toString().match(/\(([A-Z]+)\)/)[1]; var summerName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | summer.toString().match(/\(([A-Z]+)\)/)[1]; var winterNamePtr = allocate(intArrayFromString(winterName), 'i8', ALLOC_NORMAL); var summerNamePtr = allocate(intArrayFromString(summerName), 'i8', ALLOC_NORMAL); - {{{ makeSetValue(makeGlobalUse('_tzname'), '0', 'winterNamePtr', 'i32') }}} - {{{ makeSetValue(makeGlobalUse('_tzname'), Runtime.QUANTUM_SIZE, 'summerNamePtr', 'i32') }}} + {{{ makeSetValue(makeGlobalUse('_tzname'), '0', 'winterNamePtr', 'i32') }}}; + {{{ makeSetValue(makeGlobalUse('_tzname'), Runtime.QUANTUM_SIZE, 'summerNamePtr', 'i32') }}}; }, stime__deps: ['$ERRNO_CODES', '__setErrNo'], @@ -6095,15 +6082,15 @@ LibraryManager.library = { */ var fullDate = new Date(date.year, date.month, date.day, date.hour, date.min, date.sec, 0); - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_sec, 'fullDate.getSeconds()', 'i32') }}} - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_min, 'fullDate.getMinutes()', 'i32') }}} - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_hour, 'fullDate.getHours()', 'i32') }}} - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mday, 'fullDate.getDate()', 'i32') }}} - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mon, 'fullDate.getMonth()', 'i32') }}} - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_year, 'fullDate.getFullYear()-1900', 'i32') }}} - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_wday, 'fullDate.getDay()', 'i32') }}} - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_yday, '__arraySum(__isLeapYear(fullDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1', 'i32') }}} - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}} + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_sec, 'fullDate.getSeconds()', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_min, 'fullDate.getMinutes()', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_hour, 'fullDate.getHours()', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mday, 'fullDate.getDate()', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mon, 'fullDate.getMonth()', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_year, 'fullDate.getFullYear()-1900', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_wday, 'fullDate.getDay()', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_yday, '__arraySum(__isLeapYear(fullDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}}; // we need to convert the matched sequence into an integer array to take care of UTF-8 characters > 0x7F // TODO: not sure that intArrayFromString handles all unicode characters correctly @@ -6134,8 +6121,8 @@ LibraryManager.library = { var seconds = {{{ makeGetValue('rqtp', C_STRUCTS.timespec.tv_sec, 'i32') }}}; var nanoseconds = {{{ makeGetValue('rqtp', C_STRUCTS.timespec.tv_nsec, 'i32') }}}; if (rmtp !== 0) { - {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_sec, '0', 'i32') }}} - {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_nsec, '0', 'i32') }}} + {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_sec, '0', 'i32') }}}; + {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_nsec, '0', 'i32') }}}; } return _usleep((seconds * 1e6) + (nanoseconds / 1000)); }, @@ -6166,7 +6153,7 @@ LibraryManager.library = { } else { nsec = _emscripten_get_now_res(); } - {{{ makeSetValue('res', C_STRUCTS.timespec.tv_sec, '1', 'i32') }}} + {{{ makeSetValue('res', C_STRUCTS.timespec.tv_sec, '1', 'i32') }}}; {{{ makeSetValue('res', C_STRUCTS.timespec.tv_nsec, 'nsec', 'i32') }}} // resolution is milliseconds return 0; }, @@ -6250,9 +6237,6 @@ LibraryManager.library = { label = label|0; table = table|0; var i = 0; -#if ASSERTIONS - if ((label|0) == 0) abort(121); -#endif setjmpId = (setjmpId+1)|0; {{{ makeSetValueAsm('env', '0', 'setjmpId', 'i32') }}}; while ((i|0) < {{{ 2*MAX_SETJMPS }}}) { @@ -6310,6 +6294,10 @@ LibraryManager.library = { throw { longjmp: true, id: {{{ makeGetValue('env', '0', 'i32') }}}, value: value || 1 }; #endif }, + emscripten_longjmp__deps: ['longjmp'], + emscripten_longjmp: function(env, value) { + _longjmp(env, value); + }, // ========================================================================== // signal.h @@ -6847,7 +6835,7 @@ LibraryManager.library = { __setErrNo__postset: '___errno_state = Runtime.staticAlloc(4); {{{ makeSetValue("___errno_state", 0, 0, "i32") }}};', __setErrNo: function(value) { // For convenient setting and returning of errno. - {{{ makeSetValue('___errno_state', '0', 'value', 'i32') }}} + {{{ makeSetValue('___errno_state', '0', 'value', 'i32') }}}; return value; }, __errno_location__deps: ['__setErrNo'], @@ -6871,15 +6859,14 @@ LibraryManager.library = { // int setrlimit(int resource, const struct rlimit *rlp) return 0; }, - __01getrlimit64_: 'getrlimit', // TODO: Implement for real. We just do time used, and no useful data getrusage: function(resource, rlp) { // int getrusage(int resource, struct rusage *rlp); - {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_sec, '1', 'i32') }}} - {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_usec, '2', 'i32') }}} - {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_sec, '3', 'i32') }}} - {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_usec, '4', 'i32') }}} + {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_sec, '1', 'i32') }}}; + {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_usec, '2', 'i32') }}}; + {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_sec, '3', 'i32') }}}; + {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_usec, '4', 'i32') }}}; return 0; }, @@ -6943,8 +6930,8 @@ LibraryManager.library = { void **restrict stackaddr, size_t *restrict stacksize); */ /*FIXME: assumes that there is only one thread, and that attr is the current thread*/ - {{{ makeSetValue('stackaddr', '0', 'STACK_BASE', 'i8*') }}} - {{{ makeSetValue('stacksize', '0', 'TOTAL_STACK', 'i32') }}} + {{{ makeSetValue('stackaddr', '0', 'STACK_BASE', 'i8*') }}}; + {{{ makeSetValue('stacksize', '0', 'TOTAL_STACK', 'i32') }}}; return 0; }, @@ -6962,7 +6949,7 @@ LibraryManager.library = { if (key == 0) { return ERRNO_CODES.EINVAL; } - {{{ makeSetValue('key', '0', 'PTHREAD_SPECIFIC_NEXT_KEY', 'i32*') }}} + {{{ makeSetValue('key', '0', 'PTHREAD_SPECIFIC_NEXT_KEY', 'i32*') }}}; // values start at 0 PTHREAD_SPECIFIC[PTHREAD_SPECIFIC_NEXT_KEY] = 0; PTHREAD_SPECIFIC_NEXT_KEY++; @@ -7020,7 +7007,7 @@ LibraryManager.library = { posix_memalign__deps: ['memalign'], posix_memalign: function(memptr, alignment, size) { var ptr = _memalign(alignment, size); - {{{ makeSetValue('memptr', '0', 'ptr', 'i8*') }}} + {{{ makeSetValue('memptr', '0', 'ptr', 'i8*') }}}; return 0; }, @@ -7062,7 +7049,7 @@ LibraryManager.library = { if (addr === null) { return 0; } - {{{ makeSetValue('inp', '0', 'addr', 'i32') }}} + {{{ makeSetValue('inp', '0', 'addr', 'i32') }}}; return 1; }, @@ -7221,7 +7208,7 @@ LibraryManager.library = { if (ret === null) { return 0; } - {{{ makeSetValue('dst', '0', 'ret', 'i32') }}} + {{{ makeSetValue('dst', '0', 'ret', 'i32') }}}; return 1; }, _inet_pton6_raw__deps: ['htons'], @@ -7344,6 +7331,12 @@ LibraryManager.library = { // netdb.h // ========================================================================== + __h_errno_state: 'allocate(1, "i32", ALLOC_STATIC)', + __h_errno_location__deps: ['__h_errno_state'], + __h_errno_location: function() { + return ___h_errno_state; + }, + // We can't actually resolve hostnames in the browser, so instead // we're generating fake IP addresses with lookup_name that we can // resolve later on with lookup_addr. @@ -7399,6 +7392,7 @@ LibraryManager.library = { gethostbyaddr: function (addr, addrlen, type) { if (type !== {{{ cDefine('AF_INET') }}}) { ___setErrNo(ERRNO_CODES.EAFNOSUPPORT); + // TODO: set h_errno return null; } addr = {{{ makeGetValue('addr', '0', 'i32') }}}; // addr is in_addr @@ -7419,18 +7413,18 @@ LibraryManager.library = { var ret = _malloc({{{ C_STRUCTS.hostent.__size__ }}}); // XXX possibly leaked, as are others here var nameBuf = _malloc(name.length+1); writeStringToMemory(name, nameBuf); - {{{ makeSetValue('ret', C_STRUCTS.hostent.h_name, 'nameBuf', 'i8*') }}} + {{{ makeSetValue('ret', C_STRUCTS.hostent.h_name, 'nameBuf', 'i8*') }}}; var aliasesBuf = _malloc(4); - {{{ makeSetValue('aliasesBuf', '0', '0', 'i8*') }}} - {{{ makeSetValue('ret', C_STRUCTS.hostent.h_aliases, 'aliasesBuf', 'i8**') }}} + {{{ makeSetValue('aliasesBuf', '0', '0', 'i8*') }}}; + {{{ makeSetValue('ret', C_STRUCTS.hostent.h_aliases, 'aliasesBuf', 'i8**') }}}; var afinet = {{{ cDefine('AF_INET') }}}; - {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addrtype, 'afinet', 'i32') }}} - {{{ makeSetValue('ret', C_STRUCTS.hostent.h_length, '4', 'i32') }}} + {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addrtype, 'afinet', 'i32') }}}; + {{{ makeSetValue('ret', C_STRUCTS.hostent.h_length, '4', 'i32') }}}; var addrListBuf = _malloc(12); - {{{ makeSetValue('addrListBuf', '0', 'addrListBuf+8', 'i32*') }}} - {{{ makeSetValue('addrListBuf', '4', '0', 'i32*') }}} - {{{ makeSetValue('addrListBuf', '8', '__inet_pton4_raw(DNS.lookup_name(name))', 'i32') }}} - {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addr_list, 'addrListBuf', 'i8**') }}} + {{{ makeSetValue('addrListBuf', '0', 'addrListBuf+8', 'i32*') }}}; + {{{ makeSetValue('addrListBuf', '4', '0', 'i32*') }}}; + {{{ makeSetValue('addrListBuf', '8', '__inet_pton4_raw(DNS.lookup_name(name))', 'i32') }}}; + {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addr_list, 'addrListBuf', 'i8**') }}}; return ret; }, @@ -9176,6 +9170,30 @@ LibraryManager.library = { // misc shims for musl __lockfile: function() { return 1 }, __unlockfile: function(){}, + + // misc definitions to avoid unnecessary unresolved symbols from fastcomp + emscripten_prep_setjmp: true, + emscripten_check_longjmp: true, + emscripten_get_longjmp_result: true, + emscripten_setjmp: true, + emscripten_preinvoke: true, + emscripten_postinvoke: true, + emscripten_resume: true, + emscripten_landingpad: true, + getHigh32: true, + setHigh32: true, + FtoILow: true, + FtoIHigh: true, + DtoILow: true, + DtoIHigh: true, + BDtoILow: true, + BDtoIHigh: true, + SItoF: true, + UItoF: true, + SItoD: true, + UItoD: true, + BItoD: true, + llvm_dbg_value: true, }; function autoAddDeps(object, name) { @@ -9188,7 +9206,7 @@ function autoAddDeps(object, name) { } // Add aborting stubs for various libc stuff needed by libc++ -['pthread_cond_signal', 'pthread_equal', 'pthread_join', 'pthread_detach', 'catgets', 'catopen', 'catclose'].forEach(function(aborter) { +['pthread_cond_signal', 'pthread_equal', 'pthread_join', 'pthread_detach'].forEach(function(aborter) { LibraryManager.library[aborter] = function aborting_stub() { throw 'TODO: ' + aborter }; }); diff --git a/src/library_browser.js b/src/library_browser.js index d5e35339..458a8dd2 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -775,6 +775,15 @@ mergeInto(LibraryManager.library, { return; } + // Signal GL rendering layer that processing of a new frame is about to start. This helps it optimize + // VBO double-buffering and reduce GPU stalls. +#if FULL_ES2 + GL.newRenderingFrameStarted(); +#endif +#if LEGACY_GL_EMULATION + GL.newRenderingFrameStarted(); +#endif + if (Module['preMainLoop']) { Module['preMainLoop'](); } diff --git a/src/library_gl.js b/src/library_gl.js index a4da4220..3055309b 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -57,6 +57,7 @@ var LibraryGL = { unpackAlignment: 4, // default alignment is 4 bytes init: function() { + GL.createLog2ceilLookup(GL.MAX_TEMP_BUFFER_SIZE); Browser.moduleContextCreatedCallbacks.push(GL.initExtensions); }, @@ -81,36 +82,58 @@ var LibraryGL = { miniTempBuffer: null, miniTempBufferViews: [0], // index i has the view of size i+1 - // Large temporary buffers + // When user GL code wants to render from client-side memory, we need to upload the vertex data to a temp VBO + // for rendering. Maintain a set of temp VBOs that are created-on-demand to appropriate sizes, and never destroyed. + // Also, for best performance the VBOs are double-buffered, i.e. every second frame we switch the set of VBOs we + // upload to, so that rendering from the previous frame is not disturbed by uploading from new data to it, which + // could cause a GPU-CPU pipeline stall. + // Note that index buffers are not double-buffered (at the moment) in this manner. MAX_TEMP_BUFFER_SIZE: {{{ GL_MAX_TEMP_BUFFER_SIZE }}}, - tempBufferIndexLookup: null, - tempVertexBuffers: null, - tempIndexBuffers: null, + tempVertexBuffers1: [], + tempVertexBufferCounters1: [], + tempVertexBuffers2: [], + tempVertexBufferCounters2: [], + // Maximum number of temp VBOs of one size to maintain, after that we start reusing old ones, which is safe but can give + // a performance impact. If CPU-GPU stalls are a problem, increasing this might help. + numTempVertexBuffersPerSize: 64, // (const) + tempIndexBuffers: [], tempQuadIndexBuffer: null, - generateTempBuffers: function(quads) { - GL.tempBufferIndexLookup = new Uint8Array(GL.MAX_TEMP_BUFFER_SIZE+1); - GL.tempVertexBuffers = []; - GL.tempIndexBuffers = []; - var last = -1, curr = -1; - var size = 1; - for (var i = 0; i <= GL.MAX_TEMP_BUFFER_SIZE; i++) { - if (i > size) { - size <<= 1; + // Precompute a lookup table for the function ceil(log2(x)), i.e. how many bits are needed to represent x, or, + // if x was rounded up to next pow2, which index is the single '1' bit at? + // Then log2ceilLookup[x] returns ceil(log2(x)). + log2ceilLookup: null, + createLog2ceilLookup: function(maxValue) { + GL.log2ceilLookup = new Uint8Array(maxValue+1); + var log2 = 0; + var pow2 = 1; + GL.log2ceilLookup[0] = 0; + for(var i = 1; i <= maxValue; ++i) { + if (i > pow2) { + pow2 <<= 1; + ++log2; } - if (size != last) { - curr++; - GL.tempVertexBuffers[curr] = GLctx.createBuffer(); - GLctx.bindBuffer(GLctx.ARRAY_BUFFER, GL.tempVertexBuffers[curr]); - GLctx.bufferData(GLctx.ARRAY_BUFFER, size, GLctx.DYNAMIC_DRAW); - GLctx.bindBuffer(GLctx.ARRAY_BUFFER, null); - GL.tempIndexBuffers[curr] = GLctx.createBuffer(); - GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, GL.tempIndexBuffers[curr]); - GLctx.bufferData(GLctx.ELEMENT_ARRAY_BUFFER, size, GLctx.DYNAMIC_DRAW); - GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, null); - last = size; + GL.log2ceilLookup[i] = log2; + } + }, + + generateTempBuffers: function(quads) { + var largestIndex = GL.log2ceilLookup[GL.MAX_TEMP_BUFFER_SIZE]; + GL.tempVertexBufferCounters1.length = GL.tempVertexBufferCounters2.length = largestIndex+1; + GL.tempVertexBuffers1.length = GL.tempVertexBuffers2.length = largestIndex+1; + GL.tempIndexBuffers.length = largestIndex+1; + for(var i = 0; i <= largestIndex; ++i) { + GL.tempIndexBuffers[i] = null; // Created on-demand + GL.tempVertexBufferCounters1[i] = GL.tempVertexBufferCounters2[i] = 0; + var ringbufferLength = GL.numTempVertexBuffersPerSize; + GL.tempVertexBuffers1[i] = []; + GL.tempVertexBuffers2[i] = []; + var ringbuffer1 = GL.tempVertexBuffers1[i]; + var ringbuffer2 = GL.tempVertexBuffers2[i]; + ringbuffer1.length = ringbuffer2.length = ringbufferLength; + for(var j = 0; j < ringbufferLength; ++j) { + ringbuffer1[j] = ringbuffer2[j] = null; // Created on-demand } - GL.tempBufferIndexLookup[i] = curr; } if (quads) { @@ -140,6 +163,53 @@ var LibraryGL = { } }, + getTempVertexBuffer: function getTempVertexBuffer(sizeBytes) { + var idx = GL.log2ceilLookup[sizeBytes]; + var ringbuffer = GL.tempVertexBuffers1[idx]; + var nextFreeBufferIndex = GL.tempVertexBufferCounters1[idx]; + GL.tempVertexBufferCounters1[idx] = (GL.tempVertexBufferCounters1[idx]+1) & (GL.numTempVertexBuffersPerSize-1); + var vbo = ringbuffer[nextFreeBufferIndex]; + if (vbo) { + return vbo; + } + var prevVBO = GLctx.getParameter(GLctx.ARRAY_BUFFER_BINDING); + ringbuffer[nextFreeBufferIndex] = GLctx.createBuffer(); + GLctx.bindBuffer(GLctx.ARRAY_BUFFER, ringbuffer[nextFreeBufferIndex]); + GLctx.bufferData(GLctx.ARRAY_BUFFER, 1 << idx, GLctx.DYNAMIC_DRAW); + GLctx.bindBuffer(GLctx.ARRAY_BUFFER, prevVBO); + return ringbuffer[nextFreeBufferIndex]; + }, + + getTempIndexBuffer: function getTempIndexBuffer(sizeBytes) { + var idx = GL.log2ceilLookup[sizeBytes]; + var ibo = GL.tempIndexBuffers[idx]; + if (ibo) { + return ibo; + } + var prevIBO = GLctx.getParameter(GLctx.ELEMENT_ARRAY_BUFFER_BINDING); + GL.tempIndexBuffers[idx] = GLctx.createBuffer(); + GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, GL.tempIndexBuffers[idx]); + GLctx.bufferData(GLctx.ELEMENT_ARRAY_BUFFER, 1 << idx, GLctx.DYNAMIC_DRAW); + GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, prevIBO); + return GL.tempIndexBuffers[idx]; + }, + + // Called at start of each new WebGL rendering frame. This swaps the doublebuffered temp VB memory pointers, + // so that every second frame utilizes different set of temp buffers. The aim is to keep the set of buffers + // being rendered, and the set of buffers being updated disjoint. + newRenderingFrameStarted: function newRenderingFrameStarted() { + var vb = GL.tempVertexBuffers1; + GL.tempVertexBuffers1 = GL.tempVertexBuffers2; + GL.tempVertexBuffers2 = vb; + vb = GL.tempVertexBufferCounters1; + GL.tempVertexBufferCounters1 = GL.tempVertexBufferCounters2; + GL.tempVertexBufferCounters2 = vb; + var largestIndex = GL.log2ceilLookup[GL.MAX_TEMP_BUFFER_SIZE]; + for(var i = 0; i <= largestIndex; ++i) { + GL.tempVertexBufferCounters1[i] = 0; + } + }, + // Find a token in a shader source string findToken: function(source, token) { function isIdentChar(ch) { @@ -446,9 +516,6 @@ var LibraryGL = { preDrawHandleClientVertexAttribBindings: function preDrawHandleClientVertexAttribBindings(count) { GL.resetBufferBinding = false; - var used = GL.usedTempBuffers; - used.length = 0; - // TODO: initial pass to detect ranges we need to upload, might not need an upload per attrib for (var i = 0; i < GL.maxVertexAttribs; ++i) { var cb = GL.clientBuffers[i]; @@ -457,15 +524,7 @@ var LibraryGL = { GL.resetBufferBinding = true; var size = GL.calcBufLength(cb.size, cb.type, cb.stride, count); - var index = GL.tempBufferIndexLookup[size]; - var buf; - do { -#if ASSERTIONS - assert(index < GL.tempVertexBuffers.length); -#endif - buf = GL.tempVertexBuffers[index++]; - } while (used.indexOf(buf) >= 0); - used.push(buf); + var buf = GL.getTempVertexBuffer(size); GLctx.bindBuffer(GLctx.ARRAY_BUFFER, buf); GLctx.bufferSubData(GLctx.ARRAY_BUFFER, 0, @@ -2321,7 +2380,7 @@ var LibraryGL = { // GL Immediate mode // See comment in GLEmulation.init() -#if FULL_ES2 == 0 +#if !FULL_ES2 $GLImmediate__postset: 'GLImmediate.setupFuncs(); Browser.moduleContextCreatedCallbacks.push(function() { GLImmediate.init() });', #endif $GLImmediate__deps: ['$Browser', '$GL', '$GLEmulation'], @@ -2742,14 +2801,6 @@ var LibraryGL = { this.key0 = -1; // The key of this texture unit must be recomputed when rendering the next time. GLImmediate.currentRenderer = null; // The currently used renderer must be re-evaluated at next render. } - this.traverseState = function(keyView) { - if (this.key0 == -1) { - this.recomputeKey(); - } - keyView.next(this.key0); - keyView.next(this.key1); - keyView.next(this.key2); - }; } function CTexUnit() { @@ -2758,26 +2809,55 @@ var LibraryGL = { this.enabled_tex2D = false; this.enabled_tex3D = false; this.enabled_texCube = false; + this.texTypesEnabled = 0; // A bitfield combination of the four flags above, used for fast access to operations. this.traverseState = function CTexUnit_traverseState(keyView) { - var texUnitType = this.getTexType(); - keyView.next(texUnitType); - if (!texUnitType) return; - this.env.traverseState(keyView); + if (this.texTypesEnabled) { + if (this.env.key0 == -1) { + this.env.recomputeKey(); + } + keyView.next(this.texTypesEnabled | (this.env.key0 << 4)); + keyView.next(this.env.key1); + keyView.next(this.env.key2); + } else { + // For correctness, must traverse a zero value, theoretically a subsequent integer key could collide with this value otherwise. + keyView.next(0); + } }; }; // Class impls: CTexUnit.prototype.enabled = function CTexUnit_enabled() { - return this.getTexType() != 0; + return this.texTypesEnabled; } CTexUnit.prototype.genPassLines = function CTexUnit_genPassLines(passOutputVar, passInputVar, texUnitID) { if (!this.enabled()) { return ["vec4 " + passOutputVar + " = " + passInputVar + ";"]; } - - return this.env.genPassLines(passOutputVar, passInputVar, texUnitID); + var lines = this.env.genPassLines(passOutputVar, passInputVar, texUnitID).join('\n'); + + var texLoadLines = ''; + var texLoadRegex = /(texture.*?\(.*?\))/g; + var loadCounter = 0; + var load; + + // As an optimization, merge duplicate identical texture loads to one var. + while(load = texLoadRegex.exec(lines)) { + var texLoadExpr = load[1]; + var secondOccurrence = lines.slice(load.index+1).indexOf(texLoadExpr); + if (secondOccurrence != -1) { // And also has a second occurrence of same load expression.. + // Create new var to store the common load. + var prefix = TEXENVJIT_NAMESPACE_PREFIX + 'env' + texUnitID + "_"; + var texLoadVar = prefix + 'texload' + loadCounter++; + var texLoadLine = 'vec4 ' + texLoadVar + ' = ' + texLoadExpr + ';\n'; + texLoadLines += texLoadLine + '\n'; // Store the generated texture load statements in a temp string to not confuse regex search in progress. + lines = lines.split(texLoadExpr).join(texLoadVar); + // Reset regex search, since we modified the string. + texLoadRegex = /(texture.*\(.*\))/g; + } + } + return [texLoadLines + lines]; } CTexUnit.prototype.getTexType = function CTexUnit_getTexType() { @@ -2898,13 +2978,18 @@ var LibraryGL = { var alphaLines = this.genCombinerLines(false, alphaVar, passInputVar, texUnitID, this.alphaCombiner, this.alphaSrc, this.alphaOp); + + // Generate scale, but avoid generating an identity op that multiplies by one. + var scaledColor = (this.colorScale == 1) ? colorVar : (colorVar + " * " + valToFloatLiteral(this.colorScale)); + var scaledAlpha = (this.alphaScale == 1) ? alphaVar : (alphaVar + " * " + valToFloatLiteral(this.alphaScale)); + var line = [ "vec4 " + passOutputVar, " = ", "vec4(", - colorVar + " * " + valToFloatLiteral(this.colorScale), + scaledColor, ", ", - alphaVar + " * " + valToFloatLiteral(this.alphaScale), + scaledAlpha, ")", ";", ].join(""); @@ -3084,12 +3169,7 @@ var LibraryGL = { traverseState: function(keyView) { for (var i = 0; i < s_texUnits.length; i++) { - var texUnit = s_texUnits[i]; - var enabled = texUnit.enabled(); - keyView.next(enabled); - if (enabled) { - texUnit.traverseState(keyView); - } + s_texUnits[i].traverseState(keyView); } }, @@ -3113,24 +3193,28 @@ var LibraryGL = { if (!cur.enabled_tex1D) { GLImmediate.currentRenderer = null; // Renderer state changed, and must be recreated or looked up again. cur.enabled_tex1D = true; + cur.texTypesEnabled |= 1; } break; case GL_TEXTURE_2D: if (!cur.enabled_tex2D) { GLImmediate.currentRenderer = null; cur.enabled_tex2D = true; + cur.texTypesEnabled |= 2; } break; case GL_TEXTURE_3D: if (!cur.enabled_tex3D) { GLImmediate.currentRenderer = null; cur.enabled_tex3D = true; + cur.texTypesEnabled |= 4; } break; case GL_TEXTURE_CUBE_MAP: if (!cur.enabled_texCube) { GLImmediate.currentRenderer = null; cur.enabled_texCube = true; + cur.texTypesEnabled |= 8; } break; } @@ -3143,24 +3227,28 @@ var LibraryGL = { if (cur.enabled_tex1D) { GLImmediate.currentRenderer = null; // Renderer state changed, and must be recreated or looked up again. cur.enabled_tex1D = false; + cur.texTypesEnabled &= ~1; } break; case GL_TEXTURE_2D: if (cur.enabled_tex2D) { GLImmediate.currentRenderer = null; cur.enabled_tex2D = false; + cur.texTypesEnabled &= ~2; } break; case GL_TEXTURE_3D: if (cur.enabled_tex3D) { GLImmediate.currentRenderer = null; cur.enabled_tex3D = false; + cur.texTypesEnabled &= ~4; } break; case GL_TEXTURE_CUBE_MAP: if (cur.enabled_texCube) { GLImmediate.currentRenderer = null; cur.enabled_texCube = false; + cur.texTypesEnabled &= ~8; } break; } @@ -3514,6 +3602,11 @@ var LibraryGL = { GLImmediate.enabledClientAttributes[name] = true; GLImmediate.setClientAttribute(name, size, type, 0, GLImmediate.rendererComponentPointer); GLImmediate.rendererComponentPointer += size * GL.byteSizeByType[type - GL.byteSizeByTypeRoot]; +#if GL_FFP_ONLY + // We can enable the correct attribute stream index immediately here, since the same attribute in each shader + // will be bound to this same index. + GL.enableVertexAttribArray(name); +#endif } else { GLImmediate.rendererComponents[name]++; } @@ -3535,7 +3628,6 @@ var LibraryGL = { // we maintain a cache of renderers, optimized to not generate garbage var attributes = GLImmediate.liveClientAttributes; var cacheMap = GLImmediate.rendererCache; - var temp; var keyView = cacheMap.getStaticKeyView().reset(); // By attrib state: @@ -3543,7 +3635,6 @@ var LibraryGL = { for (var i = 0; i < attributes.length; i++) { enabledAttributesKey |= 1 << attributes[i].name; } - keyView.next(enabledAttributesKey); // By fog state: var fogParam = 0; @@ -3560,13 +3651,17 @@ var LibraryGL = { break; } } - keyView.next(fogParam); + keyView.next((enabledAttributesKey << 2) | fogParam); +#if !GL_FFP_ONLY // By cur program: keyView.next(GL.currProgram); if (!GL.currProgram) { +#endif GLImmediate.TexEnvJIT.traverseState(keyView); +#if !GL_FFP_ONLY } +#endif // If we don't already have it, create it. var renderer = keyView.get(); @@ -3772,7 +3867,7 @@ var LibraryGL = { this.texCoordLocations[i] = GLctx.getAttribLocation(this.program, aTexCoordPrefix + i); } } - + this.colorLocation = GLctx.getAttribLocation(this.program, 'a_color'); if (!useCurrProgram) { // Temporarily switch to the program so we can set our sampler uniforms early. var prevBoundProg = GLctx.getParameter(GLctx.CURRENT_PROGRAM); @@ -3784,6 +3879,9 @@ var LibraryGL = { GLctx.uniform1i(texSamplerLoc, texUnitID); } } + // The default color attribute value is not the same as the default for all other attribute streams (0,0,0,1) but (1,1,1,1), + // so explicitly set it right at start. + GLctx.vertexAttrib4fv(this.colorLocation, [1,1,1,1]); GLctx.useProgram(prevBoundProg); } @@ -3791,7 +3889,6 @@ var LibraryGL = { for (var i = 0; i < GLImmediate.MAX_TEXTURES; i++) { this.textureMatrixLocations[i] = GLctx.getUniformLocation(this.program, 'u_textureMatrix' + i); } - this.colorLocation = GLctx.getAttribLocation(this.program, 'a_color'); this.normalLocation = GLctx.getAttribLocation(this.program, 'a_normal'); this.modelViewLocation = GLctx.getUniformLocation(this.program, 'u_modelView'); @@ -3822,7 +3919,7 @@ var LibraryGL = { #if ASSERTIONS assert(end <= GL.MAX_TEMP_BUFFER_SIZE, 'too much vertex data'); #endif - arrayBuffer = GL.tempVertexBuffers[GL.tempBufferIndexLookup[end]]; + arrayBuffer = GL.getTempVertexBuffer(end); // TODO: consider using the last buffer we bound, if it was larger. downside is larger buffer, but we might avoid rebinding and preparing } else { arrayBuffer = GL.currArrayBuffer; @@ -3884,11 +3981,9 @@ var LibraryGL = { #if GL_FFP_ONLY if (!GL.currArrayBuffer) { GLctx.vertexAttribPointer(GLImmediate.VERTEX, posAttr.size, posAttr.type, false, GLImmediate.stride, posAttr.offset); - GL.enableVertexAttribArray(GLImmediate.VERTEX); if (this.hasNormal) { var normalAttr = clientAttributes[GLImmediate.NORMAL]; GLctx.vertexAttribPointer(GLImmediate.NORMAL, normalAttr.size, normalAttr.type, true, GLImmediate.stride, normalAttr.offset); - GL.enableVertexAttribArray(GLImmediate.NORMAL); } } #else @@ -3911,11 +4006,9 @@ var LibraryGL = { var texAttr = clientAttributes[attribLoc]; if (texAttr.size) { GLctx.vertexAttribPointer(attribLoc, texAttr.size, texAttr.type, false, GLImmediate.stride, texAttr.offset); - GL.enableVertexAttribArray(attribLoc); } else { // These two might be dangerous, but let's try them. GLctx.vertexAttrib4f(attribLoc, 0, 0, 0, 1); - GL.disableVertexAttribArray(attribLoc); } } #else @@ -3950,21 +4043,18 @@ var LibraryGL = { #if GL_FFP_ONLY if (!GL.currArrayBuffer) { GLctx.vertexAttribPointer(GLImmediate.COLOR, colorAttr.size, colorAttr.type, true, GLImmediate.stride, colorAttr.offset); - GL.enableVertexAttribArray(GLImmediate.COLOR); } #else GLctx.vertexAttribPointer(this.colorLocation, colorAttr.size, colorAttr.type, true, GLImmediate.stride, colorAttr.offset); GLctx.enableVertexAttribArray(this.colorLocation); #endif - } else if (this.hasColor) { -#if GL_FFP_ONLY - GL.disableVertexAttribArray(GLImmediate.COLOR); - GLctx.vertexAttrib4fv(GLImmediate.COLOR, GLImmediate.clientColor); -#else + } +#if !GL_FFP_ONLY + else if (this.hasColor) { GLctx.disableVertexAttribArray(this.colorLocation); GLctx.vertexAttrib4fv(this.colorLocation, GLImmediate.clientColor); -#endif } +#endif if (this.hasFog) { if (this.fogColorLocation) GLctx.uniform4fv(this.fogColorLocation, GLEmulation.fogColor); if (this.fogEndLocation) GLctx.uniform1f(this.fogEndLocation, GLEmulation.fogEnd); @@ -3991,6 +4081,7 @@ var LibraryGL = { } if (!GL.currProgram) { GLctx.useProgram(null); + GLImmediate.fixedFunctionProgram = 0; } if (!GL.currArrayBuffer) { GLctx.bindBuffer(GLctx.ARRAY_BUFFER, null); @@ -4138,11 +4229,12 @@ var LibraryGL = { if (!Module.useWebGL) return; // a 2D canvas may be currently used TODO: make sure we are actually called in that case - GLImmediate.TexEnvJIT.init(GLctx); - // User can override the maximum number of texture units that we emulate. Using fewer texture units increases runtime performance // slightly, so it is advantageous to choose as small value as needed. GLImmediate.MAX_TEXTURES = Module['GL_MAX_TEXTURE_IMAGE_UNITS'] || GLctx.getParameter(GLctx.MAX_TEXTURE_IMAGE_UNITS); + + GLImmediate.TexEnvJIT.init(GLctx, GLImmediate.MAX_TEXTURES); + GLImmediate.NUM_ATTRIBUTES = 3 /*pos+normal+color attributes*/ + GLImmediate.MAX_TEXTURES; GLImmediate.clientAttributes = []; GLEmulation.enabledClientAttribIndices = []; @@ -4331,7 +4423,7 @@ var LibraryGL = { #if ASSERTIONS assert(numProvidedIndexes << 1 <= GL.MAX_TEMP_BUFFER_SIZE, 'too many immediate mode indexes (a)'); #endif - var indexBuffer = GL.tempIndexBuffers[GL.tempBufferIndexLookup[numProvidedIndexes << 1]]; + var indexBuffer = GL.getTempIndexBuffer(numProvidedIndexes << 1); GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, indexBuffer); GLctx.bufferSubData(GLctx.ELEMENT_ARRAY_BUFFER, 0, {{{ makeHEAPView('U16', 'ptr', 'ptr + (numProvidedIndexes << 1)') }}}); ptr = 0; @@ -4367,7 +4459,7 @@ var LibraryGL = { GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, GL.buffers[GL.currElementArrayBuffer] || null); } -#if GL_UNSAFE_OPTS == 0 +#if !GL_UNSAFE_OPTS #if !GL_FFP_ONLY renderer.cleanup(); #endif @@ -4480,6 +4572,9 @@ var LibraryGL = { GLImmediate.clientColor[1] = g; GLImmediate.clientColor[2] = b; GLImmediate.clientColor[3] = a; +#if GL_FFP_ONLY + GLctx.vertexAttrib4fv(GLImmediate.COLOR, GLImmediate.clientColor); +#endif } }, glColor4d: 'glColor4f', @@ -4627,6 +4722,10 @@ var LibraryGL = { GLImmediate.enabledClientAttributes[attrib] = true; GLImmediate.totalEnabledClientAttributes++; GLImmediate.currentRenderer = null; // Will need to change current renderer, since the set of active vertex pointers changed. +#if GL_FFP_ONLY + // In GL_FFP_ONLY mode, attributes are bound to the same index in each FFP emulation shader, so we can immediately apply the change here. + GL.enableVertexAttribArray(attrib); +#endif if (GLEmulation.currentVao) GLEmulation.currentVao.enabledClientStates[cap] = 1; GLImmediate.modifiedClientAttributes = true; } @@ -4643,6 +4742,10 @@ var LibraryGL = { GLImmediate.enabledClientAttributes[attrib] = false; GLImmediate.totalEnabledClientAttributes--; GLImmediate.currentRenderer = null; // Will need to change current renderer, since the set of active vertex pointers changed. +#if GL_FFP_ONLY + // In GL_FFP_ONLY mode, attributes are bound to the same index in each FFP emulation shader, so we can immediately apply the change here. + GL.disableVertexAttribArray(attrib); +#endif if (GLEmulation.currentVao) delete GLEmulation.currentVao.enabledClientStates[cap]; GLImmediate.modifiedClientAttributes = true; } @@ -4654,7 +4757,6 @@ var LibraryGL = { #if GL_FFP_ONLY if (GL.currArrayBuffer) { GLctx.vertexAttribPointer(GLImmediate.VERTEX, size, type, false, stride, pointer); - GL.enableVertexAttribArray(GLImmediate.VERTEX); } #endif }, @@ -4664,7 +4766,6 @@ var LibraryGL = { if (GL.currArrayBuffer) { var loc = GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture; GLctx.vertexAttribPointer(loc, size, type, false, stride, pointer); - GL.enableVertexAttribArray(loc); } #endif }, @@ -4673,7 +4774,6 @@ var LibraryGL = { #if GL_FFP_ONLY if (GL.currArrayBuffer) { GLctx.vertexAttribPointer(GLImmediate.NORMAL, size, type, true, stride, pointer); - GL.enableVertexAttribArray(GLImmediate.NORMAL); } #endif }, @@ -4682,7 +4782,6 @@ var LibraryGL = { #if GL_FFP_ONLY if (GL.currArrayBuffer) { GLctx.vertexAttribPointer(GLImmediate.COLOR, size, type, true, stride, pointer); - GL.enableVertexAttribArray(GLImmediate.COLOR); } #endif }, @@ -5099,7 +5198,7 @@ var LibraryGL = { var buf; if (!GL.currElementArrayBuffer) { var size = GL.calcBufLength(1, type, 0, count); - buf = GL.tempIndexBuffers[GL.tempBufferIndexLookup[size]]; + buf = GL.getTempIndexBuffer(size); GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, buf); GLctx.bufferSubData(GLctx.ELEMENT_ARRAY_BUFFER, 0, diff --git a/src/library_glew.js b/src/library_glew.js new file mode 100644 index 00000000..f7da5f82 --- /dev/null +++ b/src/library_glew.js @@ -0,0 +1,135 @@ +/******************************************************************************* + * EMSCRIPTEN GLEW 1.10.0 emulation + * + * What it does: + * - Stubs init function. + * - GL Extensions support. + * + * Optional: + * - isLinaroFork variable to enable glew-es specific error strings. + * This is enabled by default, but should be disabled when upstream glew conflicts. + * + * Authors: + * - Jari Vetoniemi <mailroxas@gmail.com> + ******************************************************************************/ + +var LibraryGLEW = { + $GLEW__deps: ['glGetString'], + $GLEW: { + isLinaroFork: 1, + extensions: null, + + error: { + 0:null, // GLEW_OK || GLEW_NO_ERROR + 1:null, // GLEW_ERROR_NO_GL_VERSION + 2:null, // GLEW_ERROR_GL_VERSION_10_ONLY + 3:null, // GLEW_ERROR_GLX_VERSION_11_ONLY + + 4:null, // GLEW_ERROR_NOT_GLES_VERSION + 5:null, // GLEW_ERROR_GLES_VERSION + 6:null, // GLEW_ERROR_NO_EGL_VERSION + 7:null, // GLEW_ERROR_EGL_VERSION_10_ONLY + + 8:null, // Unknown error + }, + + version: { + 1:null, // GLEW_VERSION + 2:null, // GLEW_VERSION_MAJOR + 3:null, // GLEW_VERSION_MINOR + 4:null, // GLEW_VERSION_MICRO + }, + + errorStringConstantFromCode: function(error) { + if (GLEW.isLinaroFork) { + switch (error) { + case 4:return "OpenGL ES lib expected, found OpenGL lib"; // GLEW_ERROR_NOT_GLES_VERSION + case 5:return "OpenGL lib expected, found OpenGL ES lib"; // GLEW_ERROR_GLES_VERSION + case 6:return "Missing EGL version"; // GLEW_ERROR_NO_EGL_VERSION + case 7:return "EGL 1.1 and up are supported"; // GLEW_ERROR_EGL_VERSION_10_ONLY + default:break; + } + } + + switch (error) { + case 0:return "No error"; // GLEW_OK || GLEW_NO_ERROR + case 1:return "Missing GL version"; // GLEW_ERROR_NO_GL_VERSION + case 2:return "GL 1.1 and up are supported"; // GLEW_ERROR_GL_VERSION_10_ONLY + case 3:return "GLX 1.2 and up are supported"; // GLEW_ERROR_GLX_VERSION_11_ONLY + default:return null; + } + }, + + errorString: function(error) { + if (!GLEW.error[error]) { + var string = GLEW.errorStringConstantFromCode(error); + if (!string) { + string = "Unknown error"; + error = 8; // prevent array from growing more than this + } + GLEW.error[error] = allocate(intArrayFromString(string), 'i8', ALLOC_NORMAL); + } + return GLEW.error[error]; + }, + + versionStringConstantFromCode: function(name) { + switch (name) { + case 1:return "1.10.0"; // GLEW_VERSION + case 2:return "1"; // GLEW_VERSION_MAJOR + case 3:return "10"; // GLEW_VERSION_MINOR + case 4:return "0"; // GLEW_VERSION_MICRO + default:return null; + } + }, + + versionString: function(name) { + if (!GLEW.version[name]) { + var string = GLEW.versionStringConstantFromCode(name); + if (!string) + return 0; + GLEW.version[name] = allocate(intArrayFromString(string), 'i8', ALLOC_NORMAL); + } + return GLEW.version[name]; + }, + + extensionIsSupported: function(name) { + if (!GLEW.extensions) { + GLEW.extensions = Pointer_stringify(_glGetString(0x1F03)).split(' '); + } + + if (GLEW.extensions.indexOf(name) != -1) + return 1; + + // extensions from GLEmulations do not come unprefixed + // so, try with prefix + return (GLEW.extensions.indexOf("GL_" + name) != -1); + }, + }, + + glewInit: function() { return 0; }, + + glewIsSupported: function(name) { + var exts = Pointer_stringify(name).split(' '); + for (i in exts) { + if (!GLEW.extensionIsSupported(exts[i])) + return 0; + } + return 1; + }, + + glewGetExtension: function(name) { + return GLEW.extensionIsSupported(Pointer_stringify(name)); + }, + + glewGetErrorString: function(error) { + return GLEW.errorString(error); + }, + + glewGetString: function(name) { + return GLEW.versionString(name); + }, + +}; + +autoAddDeps(LibraryGLEW, '$GLEW'); +mergeInto(LibraryManager.library, LibraryGLEW); diff --git a/src/library_sdl.js b/src/library_sdl.js index fc38dd1c..80734d95 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -223,26 +223,26 @@ var LibrarySDL = { var is_SDL_HWPALETTE = flags & 0x00200000; var bpp = is_SDL_HWPALETTE ? 1 : 4; - {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.flags, 'flags', 'i32') }}} // SDL_Surface.flags - {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.format, 'pixelFormat', 'void*') }}} // SDL_Surface.format TODO - {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.w, 'width', 'i32') }}} // SDL_Surface.w - {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.h, 'height', 'i32') }}} // SDL_Surface.h - {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pitch, 'width * bpp', 'i32') }}} // SDL_Surface.pitch, assuming RGBA or indexed for now, + {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.flags, 'flags', 'i32') }}}; // SDL_Surface.flags + {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.format, 'pixelFormat', 'void*') }}};// SDL_Surface.format TODO + {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.w, 'width', 'i32') }}}; // SDL_Surface.w + {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.h, 'height', 'i32') }}}; // SDL_Surface.h + {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pitch, 'width * bpp', 'i32') }}}; // SDL_Surface.pitch, assuming RGBA or indexed for now, // since that is what ImageData gives us in browsers - {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pixels, 'buffer', 'void*') }}} // SDL_Surface.pixels - {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.clip_rect, '0', 'i32*') }}} // SDL_Surface.offset + {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pixels, 'buffer', 'void*') }}}; // SDL_Surface.pixels + {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.clip_rect, '0', 'i32*') }}}; // SDL_Surface.offset - {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.refcount, '1', 'i32') }}} + {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.refcount, '1', 'i32') }}}; - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.format, cDefine('SDL_PIXELFORMAT_RGBA8888'), 'i32') }}} // SDL_PIXELFORMAT_RGBA8888 - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.palette, '0', 'i32') }}} // TODO - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BitsPerPixel, 'bpp * 8', 'i8') }}} - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BytesPerPixel, 'bpp', 'i8') }}} + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.format, cDefine('SDL_PIXELFORMAT_RGBA8888'), 'i32') }}};// SDL_PIXELFORMAT_RGBA8888 + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.palette, '0', 'i32') }}};// TODO + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BitsPerPixel, 'bpp * 8', 'i8') }}}; + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BytesPerPixel, 'bpp', 'i8') }}}; - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Rmask, 'rmask || 0x000000ff', 'i32') }}} - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Gmask, 'gmask || 0x0000ff00', 'i32') }}} - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Bmask, 'bmask || 0x00ff0000', 'i32') }}} - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Amask, 'amask || 0xff000000', 'i32') }}} + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Rmask, 'rmask || 0x000000ff', 'i32') }}}; + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Gmask, 'gmask || 0x0000ff00', 'i32') }}}; + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Bmask, 'bmask || 0x00ff0000', 'i32') }}}; + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Amask, 'amask || 0xff000000', 'i32') }}}; // Decide if we want to use WebGL or not var useWebGL = (flags & 0x04000000) != 0; // SDL_OPENGL @@ -592,19 +592,19 @@ var LibrarySDL = { scan = SDL.scanCodes[key] || key; } - {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.state, 'down ? 1 : 0', 'i8') }}} - {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.repeat, '0', 'i8') }}} // TODO - {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.scancode, 'scan', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.sym, 'key', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.mod, 'SDL.modState', 'i16') }}} + {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}; + {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.state, 'down ? 1 : 0', 'i8') }}}; + {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.repeat, '0', 'i8') }}}; // TODO + {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.scancode, 'scan', 'i32') }}}; + {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.sym, 'key', 'i32') }}}; + {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.mod, 'SDL.modState', 'i16') }}}; // some non-character keys (e.g. backspace and tab) won't have keypressCharCode set, fill in with the keyCode. - {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.unicode, 'event.keypressCharCode || key', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.unicode, 'event.keypressCharCode || key', 'i32') }}}; break; } case 'keypress': { - {{{ makeSetValue('ptr', C_STRUCTS.SDL_TextInputEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.SDL_TextInputEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}; // Not filling in windowID for now var cStr = intArrayFromString(String.fromCharCode(event.charCode)); for (var i = 0; i < cStr.length; ++i) { @@ -819,9 +819,9 @@ var LibrarySDL = { SDL_Linked_Version: function() { if (SDL.version === null) { SDL.version = _malloc({{{ C_STRUCTS.SDL_version.__size__ }}}); - {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.major, '0', '1', 'i8') }}} - {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.minor, '0', '3', 'i8') }}} - {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.patch, '0', '0', 'i8') }}} + {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.major, '0', '1', 'i8') }}}; + {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.minor, '0', '3', 'i8') }}}; + {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.patch, '0', '0', 'i8') }}}; } return SDL.version; }, @@ -879,11 +879,11 @@ var LibrarySDL = { SDL_GetVideoInfo: function() { // %struct.SDL_VideoInfo = type { i32, i32, %struct.SDL_PixelFormat*, i32, i32 } - 5 fields of quantum size var ret = _malloc(5*Runtime.QUANTUM_SIZE); - {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*0', '0', '0', 'i32') }}} // TODO - {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*1', '0', '0', 'i32') }}} // TODO - {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*2', '0', '0', 'void*') }}} - {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*3', '0', 'Module["canvas"].width', 'i32') }}} - {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*4', '0', 'Module["canvas"].height', 'i32') }}} + {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*0', '0', '0', 'i32') }}}; // TODO + {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*1', '0', '0', 'i32') }}}; // TODO + {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*2', '0', '0', 'void*') }}}; + {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*3', '0', 'Module["canvas"].width', 'i32') }}}; + {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*4', '0', 'Module["canvas"].height', 'i32') }}}; return ret; }, diff --git a/src/modules.js b/src/modules.js index c0b98f6f..ad467ba7 100644 --- a/src/modules.js +++ b/src/modules.js @@ -424,7 +424,7 @@ var LibraryManager = { load: function() { if (this.library) return; - var libraries = ['library.js', 'library_path.js', 'library_fs.js', 'library_idbfs.js', 'library_memfs.js', 'library_nodefs.js', 'library_sockfs.js', 'library_tty.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js', 'library_uuid.js'].concat(additionalLibraries); + var libraries = ['library.js', 'library_path.js', 'library_fs.js', 'library_idbfs.js', 'library_memfs.js', 'library_nodefs.js', 'library_sockfs.js', 'library_tty.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js', 'library_uuid.js', 'library_glew.js'].concat(additionalLibraries); for (var i = 0; i < libraries.length; i++) { eval(processMacros(preprocess(read(libraries[i])))); } diff --git a/src/parseTools.js b/src/parseTools.js index b7f97a40..e09cd2e2 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -46,7 +46,11 @@ function preprocess(text) { error('unsupported preprecessor op ' + op); } } else { - showStack.push(ident in this && this[ident] > 0); + if (ident[0] === '!') { + showStack.push(!(this[ident.substr(1)] > 0)); + } else { + showStack.push(ident in this && this[ident] > 0); + } } } else if (line[2] == 'n') { // include var included = read(line.substr(line.indexOf(' ')+1)); @@ -1327,18 +1331,22 @@ 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); - return asmCoercion('SAFE_HEAP_LOAD(' + asmCoercion(offset, 'i32') + ', ' + (ASM_JS ? 0 : printType) + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')', type); - } else { - var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type, forceAsm) + ']'; - if (ASM_JS && (phase == 'funcs' || forceAsm)) { - ret = asmCoercion(ret, type); - } - if (ASM_HEAP_LOG) { - ret = makeInlineCalculation('(asmPrint' + (type in Runtime.FLOAT_TYPES ? 'Float' : 'Int') + '(' + (asmPrintCounter++) + ',' + asmCoercion('VALUE', type) + '), VALUE)', ret, - 'temp' + (type in Runtime.FLOAT_TYPES ? 'Double' : 'Int')); + 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); + // else fall through + } else { + return asmCoercion('SAFE_HEAP_LOAD(' + offset + ', ' + (ASM_JS ? 0 : printType) + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')', type); } - return ret; } + var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type, forceAsm) + ']'; + if (ASM_JS && (phase == 'funcs' || forceAsm)) { + ret = asmCoercion(ret, type); + } + if (ASM_HEAP_LOG) { + ret = makeInlineCalculation('(asmPrint' + (type in Runtime.FLOAT_TYPES ? 'Float' : 'Int') + '(' + (asmPrintCounter++) + ',' + asmCoercion('VALUE', type) + '), VALUE)', ret, + 'temp' + (type in Runtime.FLOAT_TYPES ? 'Double' : 'Int')); + } + return ret; } function makeGetValueAsm(ptr, pos, type, unsigned) { @@ -1435,10 +1443,14 @@ 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); - return 'SAFE_HEAP_STORE(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + (ASM_JS ? 0 : printType) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')'; - } else { - return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type, forceAsm) + ']=' + value }).join(sep); + 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); + // else fall through + } else { + return 'SAFE_HEAP_STORE(' + offset + ', ' + value + ', ' + (ASM_JS ? 0 : printType) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')'; + } } + return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type, forceAsm) + ']=' + value }).join(sep); } function makeSetValueAsm(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep, forcedAlign) { @@ -1781,31 +1793,12 @@ function makePointer(slab, pos, allocator, type, ptr, finalMemoryInitialization) types = 'i8'; } - // JS engines sometimes say array initializers are too large. Work around that by chunking and calling concat to combine at runtime - var chunkSize = JS_CHUNK_SIZE; - function chunkify(array) { - // break very large slabs into parts - var ret = ''; - var index = 0; - while (index < array.length) { - ret = (ret ? ret + '.concat(' : '') + '[' + array.slice(index, index + chunkSize).map(JSON.stringify) + ']' + (ret ? ')\n' : ''); - index += chunkSize; - } - return ret; - } - if (typeof slab == 'object' && slab.length > chunkSize) { - slab = chunkify(slab); - } if (typeof types == 'object') { while (types.length < slab.length) types.push(0); } - if (typeof types != 'string' && types.length > chunkSize) { - types = chunkify(types); - } else { - types = JSON.stringify(types); - } + types = JSON.stringify(types); if (typeof slab == 'object') slab = '[' + slab.join(',') + ']'; - return 'allocate(' + slab + ', ' + types + (allocator ? ', ' + allocator : '') + (allocator == 'ALLOC_NONE' ? ', ' + ptr : '') + ')'; + return 'allocate(' + slab + ', ' + types + (allocator ? ', ' + allocator : '') + (allocator == 'ALLOC_NONE' ? ', ' + ptr : '') + ');'; } function makeGetSlabs(ptr, type, allowMultiple, unsigned) { @@ -2150,9 +2143,9 @@ function makeRounding(value, bits, signed, floatConversion) { } } // Math.floor is reasonably fast if we don't care about corrections (and even correct if unsigned) - if (!correctRoundings() || !signed) return 'Math_floor(' + value + ')'; + if (!correctRoundings() || !signed) return '(+Math_floor(' + value + '))'; // We are left with >32 bits - return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math_floor(VALUE) : Math_ceil(VALUE)', value, 'tempBigIntR'); + return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? +Math_floor(VALUE) : +Math_ceil(VALUE)', value, 'tempBigIntR'); } } diff --git a/src/postamble.js b/src/postamble.js index d6c059b8..90a86474 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -121,12 +121,13 @@ function run(args) { if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame function doRun() { + if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening + Module['calledRun'] = true; + ensureInitRuntime(); preMain(); - assert(!Module['calledRun']); - Module['calledRun'] = true; if (Module['_main'] && shouldRunNow) { Module['callMain'](args); } diff --git a/src/preamble.js b/src/preamble.js index ac6ee7b3..d415b87e 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -21,6 +21,7 @@ Module.print = Module.printErr = function(){}; #endif #if SAFE_HEAP +#if ASM_JS == 0 //======================================== // Debugging tools - Heap //======================================== @@ -166,6 +167,41 @@ function SAFE_HEAP_FILL_HISTORY(from, to, type) { } //========================================== +#else +// ASM_JS safe heap + +function getSafeHeapType(bytes, isFloat) { + switch (bytes) { + case 1: return 'i8'; + case 2: return 'i16'; + case 4: return isFloat ? 'float' : 'i32'; + case 8: return 'double'; + default: assert(0); + } +} + +function SAFE_HEAP_STORE(dest, value, bytes, isFloat) { +#if SAFE_HEAP_LOG + Module.print('SAFE_HEAP store: ' + [dest, value, bytes, isFloat]); +#endif + assert(dest > 0, 'segmentation fault'); + assert(dest % bytes === 0); + setValue(dest, value, getSafeHeapType(bytes, isFloat), 1); +} + +function SAFE_HEAP_LOAD(dest, bytes, isFloat, unsigned) { +#if SAFE_HEAP_LOG + Module.print('SAFE_HEAP load: ' + [dest, bytes, isFloat, unsigned]); +#endif + assert(dest > 0, 'segmentation fault'); + assert(dest % bytes === 0); + var type = getSafeHeapType(bytes, isFloat); + var ret = getValue(dest, type, 1); + if (unsigned) ret = unSign(ret, parseInt(type.substr(1)), 1); + return ret; +} + +#endif #endif #if CHECK_HEAP_ALIGN diff --git a/src/relooper/Relooper.cpp b/src/relooper/Relooper.cpp index d5772c62..204986da 100644 --- a/src/relooper/Relooper.cpp +++ b/src/relooper/Relooper.cpp @@ -322,12 +322,26 @@ void MultipleShape::RenderLoopPostfix() { void MultipleShape::Render(bool InLoop) { RenderLoopPrefix(); - bool First = true; + + // We know that blocks with the same Id were split from the same source, so their contents are identical and they are logically the same, so re-merge them here + typedef std::map<int, Shape*> IdShapeMap; + IdShapeMap IdMap; for (BlockShapeMap::iterator iter = InnerMap.begin(); iter != InnerMap.end(); iter++) { + int Id = iter->first->Id; + IdShapeMap::iterator Test = IdMap.find(Id); + if (Test != IdMap.end()) { + assert(Shape::IsSimple(iter->second) && Shape::IsSimple(Test->second)); // we can only merge simple blocks, something horrible has gone wrong if we see anything else + continue; + } + IdMap[iter->first->Id] = iter->second; + } + + bool First = true; + for (IdShapeMap::iterator iter = IdMap.begin(); iter != IdMap.end(); iter++) { if (AsmJS) { - PrintIndented("%sif ((label|0) == %d) {\n", First ? "" : "else ", iter->first->Id); + PrintIndented("%sif ((label|0) == %d) {\n", First ? "" : "else ", iter->first); } else { - PrintIndented("%sif (label == %d) {\n", First ? "" : "else ", iter->first->Id); + PrintIndented("%sif (label == %d) {\n", First ? "" : "else ", iter->first); } First = false; Indenter::Indent(); @@ -391,8 +405,8 @@ Relooper::~Relooper() { for (unsigned i = 0; i < Shapes.size(); i++) delete Shapes[i]; } -void Relooper::AddBlock(Block *New) { - New->Id = BlockIdCounter++; +void Relooper::AddBlock(Block *New, int Id) { + New->Id = Id == -1 ? BlockIdCounter++ : Id; Blocks.push_back(New); } @@ -446,8 +460,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->AddBlock(Split); - PrintDebug(" to %d\n", Split->Id); + Parent->AddBlock(Split, Original->Id); Split->BranchesIn.insert(Prior); Branch *Details = Prior->BranchesOut[Original]; Prior->BranchesOut[Split] = new Branch(Details->Condition, Details->Code); diff --git a/src/relooper/Relooper.h b/src/relooper/Relooper.h index 6b9394db..85adf359 100644 --- a/src/relooper/Relooper.h +++ b/src/relooper/Relooper.h @@ -57,7 +57,7 @@ struct Block { BlockBranchMap ProcessedBranchesOut; BlockSet ProcessedBranchesIn; Shape *Parent; // The shape we are directly inside - int Id; // A unique identifier, defined when added to relooper + int Id; // A unique identifier, defined when added to relooper. Note that this uniquely identifies a *logical* block - if we split it, the two instances have the same content *and* the same Id const char *Code; // The string representation of the code in this block. Owning pointer (we copy the input) const char *BranchVar; // If we have more than one branch out, the variable whose value determines where we go bool IsCheckedMultipleEntry; // If true, we are a multiple entry, so reaching us requires setting the label variable @@ -191,7 +191,7 @@ struct Relooper { Relooper(); ~Relooper(); - void AddBlock(Block *New); + void AddBlock(Block *New, int Id=-1); // Calculates the shapes void Calculate(Block *Entry); diff --git a/src/relooper/test.txt b/src/relooper/test.txt index cb02b867..82b02ad7 100644 --- a/src/relooper/test.txt +++ b/src/relooper/test.txt @@ -91,7 +91,7 @@ } default: { var $x_1 = $x_0; - label = 8; + label = 7; break L1; } } @@ -106,7 +106,7 @@ } } } - if (label == 8) { + if (label == 7) { // code 7 } // code 4 diff --git a/src/runtime.js b/src/runtime.js index cd3afb4b..4fcca56b 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -49,7 +49,7 @@ var RuntimeGenerator = { stackExit: function(initial, force) { if (initial === 0 && SKIP_STACK_IN_SMALL && !force) return ''; var ret = ''; - if (SAFE_HEAP) { + 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'; @@ -393,7 +393,17 @@ var Runtime = { for (var i = 0; i < numArgs; i++) { args.push(String.fromCharCode(36) + i); // $0, $1 etc } - return Runtime.asmConstCache[code] = eval('(function(' + args.join(',') + '){ ' + Pointer_stringify(code) + ' })'); // new Function does not allow upvars in node + code = Pointer_stringify(code); + if (code[0] === '"') { + // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct + if (code.indexOf('"', 1) === code.length-1) { + code = code.substr(1, code.length-2); + } else { + // something invalid happened, e.g. EM_ASM("..code($0)..", input) + abort('invalid EM_ASM input |' + code + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)'); + } + } + return Runtime.asmConstCache[code] = eval('(function(' + args.join(',') + '){ ' + code + ' })'); // new Function does not allow upvars in node }, warnOnce: function(text) { diff --git a/src/shell.js b/src/shell.js index b41fbb51..84844c85 100644 --- a/src/shell.js +++ b/src/shell.js @@ -38,10 +38,10 @@ var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIR if (ENVIRONMENT_IS_NODE) { // Expose functionality in the same simple way that the shells work // Note that we pollute the global namespace here, otherwise we break in node - Module['print'] = function print(x) { + if (!Module['print']) Module['print'] = function print(x) { process['stdout'].write(x + '\n'); }; - Module['printErr'] = function printErr(x) { + if (!Module['printErr']) Module['printErr'] = function printErr(x) { process['stderr'].write(x + '\n'); }; @@ -71,7 +71,7 @@ if (ENVIRONMENT_IS_NODE) { module['exports'] = Module; } else if (ENVIRONMENT_IS_SHELL) { - Module['print'] = print; + if (!Module['print']) Module['print'] = print; if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm if (typeof read != 'undefined') { @@ -107,16 +107,16 @@ else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { } if (typeof console !== 'undefined') { - Module['print'] = function print(x) { + if (!Module['print']) Module['print'] = function print(x) { console.log(x); }; - Module['printErr'] = function printErr(x) { + if (!Module['printErr']) Module['printErr'] = function printErr(x) { console.log(x); }; } else { // Probably a worker, and without console.log. We can do very little here... var TRY_USE_DUMP = false; - Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) { + if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) { dump(x); }) : (function(x) { // self.postMessage(x); // enable this if you want stdout to be sent as messages diff --git a/system/include/GL/glew.h b/system/include/GL/glew.h index 324c6b29..8be23b60 100644 --- a/system/include/GL/glew.h +++ b/system/include/GL/glew.h @@ -1,6 +1,841 @@ +/* GLEW 1.10.0 emulation include header + * this include file provides neccessary stuff to function with most GLEW programs. + * library_glew.js is also provided to support extensions and error strings + * + * This file is based on GLEW (1.10.0) and linaro fork generated include files. + * + * What it lacks: + * - Some constants and function declarations that are in GLEW 1.10.0 might be missing. + * - The real glew-es fork also includes normal GL constants and function pointers, this does not. + * + * Authors: + * - Jari Vetoniemi <mailroxas@gmail.com> + */ -// Basically do nothing, just use existing symbols +#ifndef __glew_h__ +#define __glew_h__ +#define __GLEW_H__ -#include "SDL/SDL_opengl.h" -#define glewInit() {} +/* linaro fork (glew-es) support */ +#ifndef GLEW_USE_LIB_ES11 +# define __GLEW_VERSION_ES11 0 +#else +# define __GLEW_VERSION_ES11 1 +# include <SDL/SDL_opengles.h> +#endif +#ifndef GLEW_USE_LIB_ES20 +# define __GLEW_VERSION_ES20 0 +#else +# define __GLEW_VERSION_ES20 1 +# include <SDL/SDL_opengles2.h> +#endif + +#if !__GLEW_VERSION_ES11 && !__GLEW_VERSION_ES20 +# define __GLEW_NOT_ES 1 +# include <SDL/SDL_opengl.h> +#else +# define __GLEW_NOT_ES 0 +#endif + +/* report us up to GLEW_VERSION_2_1, when no GLEW_USE_LIB_ESXX is specified. + * in source, it's possible to #undef and redefine these constants, for + * better OpenGL path suitable for emscripten. */ +#define GLEW_VERSION_1_1 __GLEW_NOT_ES +#define GLEW_VERSION_1_2 __GLEW_NOT_ES +#define GLEW_VERSION_1_2_1 __GLEW_NOT_ES +#define GLEW_VERSION_1_3 __GLEW_NOT_ES +#define GLEW_VERSION_1_4 __GLEW_NOT_ES +#define GLEW_VERSION_1_5 __GLEW_NOT_ES +#define GLEW_VERSION_2_0 __GLEW_NOT_ES +#define GLEW_VERSION_2_1 __GLEW_NOT_ES +#define GLEW_VERSION_3_0 0 +#define GLEW_VERSION_3_1 0 +#define GLEW_VERSION_3_2 0 +#define GLEW_VERSION_3_3 0 +#define GLEW_VERSION_4_0 0 +#define GLEW_VERSION_4_1 0 +#define GLEW_VERSION_4_2 0 +#define GLEW_VERSION_4_3 0 +#define GLEW_VERSION_4_4 0 + +/* linaro-fork (glew-es) version constants */ +#define GLEW_ES_VERSION_1_0 __GLEW_VERSION_ES11 +#define GLEW_ES_VERSION_2_0 __GLEW_VERSION_ES20 + +/* string codes */ +#define GLEW_VERSION 1 +#define GLEW_VERSION_MAJOR 2 +#define GLEW_VERSION_MINOR 3 +#define GLEW_VERSION_MICRO 4 + +/* error codes */ +#define GLEW_OK 0 +#define GLEW_NO_ERROR 0 +#define GLEW_ERROR_NO_GL_VERSION 1 /* missing GL version */ +#define GLEW_ERROR_GL_VERSION_10_ONLY 2 /* Need at least OpenGL 1.1 */ +#define GLEW_ERROR_GLX_VERSION_11_ONLY 3 /* Need at least GLX 1.2 */ + +/* linaro-fork (glew-es) error codes */ +#define GLEW_ERROR_NOT_GLES_VERSION 4 /* Need to be OpenGL ES version */ +#define GLEW_ERROR_GLES_VERSION 5 /* Need to be desktop OpenGL version */ +#define GLEW_ERROR_NO_EGL_VERSION 6 /* missing EGL version */ +#define GLEW_ERROR_EGL_VERSION_10_ONLY 7 /* need at least EGL 1.1 */ + +/* maps to glewGetExtension */ +#define GLEW_GET_VAR(x) glewGetExtension(#x) + +/* support GLEW constants, wrangling is done by SDL_opengl.h */ +#define GLEW_3DFX_multisample GLEW_GET_VAR(GL_3DFX_multisample) +#define GLEW_3DFX_tbuffer GLEW_GET_VAR(GL_3DFX_tbuffer) +#define GLEW_3DFX_texture_compression_FXT1 GLEW_GET_VAR(GL_3DFX_texture_compression_FXT1) +#define GLEW_AMD_blend_minmax_factor GLEW_GET_VAR(GL_AMD_blend_minmax_factor) +#define GLEW_AMD_conservative_depth GLEW_GET_VAR(GL_AMD_conservative_depth) +#define GLEW_AMD_debug_output GLEW_GET_VAR(GL_AMD_debug_output) +#define GLEW_AMD_depth_clamp_separate GLEW_GET_VAR(GL_AMD_depth_clamp_separate) +#define GLEW_AMD_draw_buffers_blend GLEW_GET_VAR(GL_AMD_draw_buffers_blend) +#define GLEW_AMD_interleaved_elements GLEW_GET_VAR(GL_AMD_interleaved_elements) +#define GLEW_AMD_multi_draw_indirect GLEW_GET_VAR(GL_AMD_multi_draw_indirect) +#define GLEW_AMD_name_gen_delete GLEW_GET_VAR(GL_AMD_name_gen_delete) +#define GLEW_AMD_performance_monitor GLEW_GET_VAR(GL_AMD_performance_monitor) +#define GLEW_AMD_pinned_memory GLEW_GET_VAR(GL_AMD_pinned_memory) +#define GLEW_AMD_query_buffer_object GLEW_GET_VAR(GL_AMD_query_buffer_object) +#define GLEW_AMD_sample_positions GLEW_GET_VAR(GL_AMD_sample_positions) +#define GLEW_AMD_seamless_cubemap_per_texture GLEW_GET_VAR(GL_AMD_seamless_cubemap_per_texture) +#define GLEW_AMD_shader_atomic_counter_ops GLEW_GET_VAR(GL_AMD_shader_atomic_counter_ops) +#define GLEW_AMD_shader_stencil_export GLEW_GET_VAR(GL_AMD_shader_stencil_export) +#define GLEW_AMD_shader_trinary_minmax GLEW_GET_VAR(GL_AMD_shader_trinary_minmax) +#define GLEW_AMD_sparse_texture GLEW_GET_VAR(GL_AMD_sparse_texture) +#define GLEW_AMD_stencil_operation_extended GLEW_GET_VAR(GL_AMD_stencil_operation_extended) +#define GLEW_AMD_texture_texture4 GLEW_GET_VAR(GL_AMD_texture_texture4) +#define GLEW_AMD_transform_feedback3_lines_triangles GLEW_GET_VAR(GL_AMD_transform_feedback3_lines_triangles) +#define GLEW_AMD_vertex_shader_layer GLEW_GET_VAR(GL_AMD_vertex_shader_layer) +#define GLEW_AMD_vertex_shader_tessellator GLEW_GET_VAR(GL_AMD_vertex_shader_tessellator) +#define GLEW_AMD_vertex_shader_viewport_index GLEW_GET_VAR(GL_AMD_vertex_shader_viewport_index) +#define GLEW_ANGLE_depth_texture GLEW_GET_VAR(GL_ANGLE_depth_texture) +#define GLEW_ANGLE_framebuffer_blit GLEW_GET_VAR(GL_ANGLE_framebuffer_blit) +#define GLEW_ANGLE_framebuffer_multisample GLEW_GET_VAR(GL_ANGLE_framebuffer_multisample) +#define GLEW_ANGLE_instanced_arrays GLEW_GET_VAR(GL_ANGLE_instanced_arrays) +#define GLEW_ANGLE_pack_reverse_row_order GLEW_GET_VAR(GL_ANGLE_pack_reverse_row_order) +#define GLEW_ANGLE_program_binary GLEW_GET_VAR(GL_ANGLE_program_binary) +#define GLEW_ANGLE_texture_compression_dxt1 GLEW_GET_VAR(GL_ANGLE_texture_compression_dxt1) +#define GLEW_ANGLE_texture_compression_dxt3 GLEW_GET_VAR(GL_ANGLE_texture_compression_dxt3) +#define GLEW_ANGLE_texture_compression_dxt5 GLEW_GET_VAR(GL_ANGLE_texture_compression_dxt5) +#define GLEW_ANGLE_texture_usage GLEW_GET_VAR(GL_ANGLE_texture_usage) +#define GLEW_ANGLE_timer_query GLEW_GET_VAR(GL_ANGLE_timer_query) +#define GLEW_ANGLE_translated_shader_source GLEW_GET_VAR(GL_ANGLE_translated_shader_source) +#define GLEW_APPLE_aux_depth_stencil GLEW_GET_VAR(GL_APPLE_aux_depth_stencil) +#define GLEW_APPLE_client_storage GLEW_GET_VAR(GL_APPLE_client_storage) +#define GLEW_APPLE_element_array GLEW_GET_VAR(GL_APPLE_element_array) +#define GLEW_APPLE_fence GLEW_GET_VAR(GL_APPLE_fence) +#define GLEW_APPLE_float_pixels GLEW_GET_VAR(GL_APPLE_float_pixels) +#define GLEW_APPLE_flush_buffer_range GLEW_GET_VAR(GL_APPLE_flush_buffer_range) +#define GLEW_APPLE_object_purgeable GLEW_GET_VAR(GL_APPLE_object_purgeable) +#define GLEW_APPLE_pixel_buffer GLEW_GET_VAR(GL_APPLE_pixel_buffer) +#define GLEW_APPLE_rgb_422 GLEW_GET_VAR(GL_APPLE_rgb_422) +#define GLEW_APPLE_row_bytes GLEW_GET_VAR(GL_APPLE_row_bytes) +#define GLEW_APPLE_specular_vector GLEW_GET_VAR(GL_APPLE_specular_vector) +#define GLEW_APPLE_texture_range GLEW_GET_VAR(GL_APPLE_texture_range) +#define GLEW_APPLE_transform_hint GLEW_GET_VAR(GL_APPLE_transform_hint) +#define GLEW_APPLE_vertex_array_object GLEW_GET_VAR(GL_APPLE_vertex_array_object) +#define GLEW_APPLE_vertex_array_range GLEW_GET_VAR(GL_APPLE_vertex_array_range) +#define GLEW_APPLE_vertex_program_evaluators GLEW_GET_VAR(GL_APPLE_vertex_program_evaluators) +#define GLEW_APPLE_ycbcr_422 GLEW_GET_VAR(GL_APPLE_ycbcr_422) +#define GLEW_ARB_ES2_compatibility GLEW_GET_VAR(GL_ARB_ES2_compatibility) +#define GLEW_ARB_ES3_compatibility GLEW_GET_VAR(GL_ARB_ES3_compatibility) +#define GLEW_ARB_arrays_of_arrays GLEW_GET_VAR(GL_ARB_arrays_of_arrays) +#define GLEW_ARB_base_instance GLEW_GET_VAR(GL_ARB_base_instance) +#define GLEW_ARB_bindless_texture GLEW_GET_VAR(GL_ARB_bindless_texture) +#define GLEW_ARB_blend_func_extended GLEW_GET_VAR(GL_ARB_blend_func_extended) +#define GLEW_ARB_buffer_storage GLEW_GET_VAR(GL_ARB_buffer_storage) +#define GLEW_ARB_cl_event GLEW_GET_VAR(GL_ARB_cl_event) +#define GLEW_ARB_clear_buffer_object GLEW_GET_VAR(GL_ARB_clear_buffer_object) +#define GLEW_ARB_clear_texture GLEW_GET_VAR(GL_ARB_clear_texture) +#define GLEW_ARB_color_buffer_float GLEW_GET_VAR(GL_ARB_color_buffer_float) +#define GLEW_ARB_compatibility GLEW_GET_VAR(GL_ARB_compatibility) +#define GLEW_ARB_compressed_texture_pixel_storage GLEW_GET_VAR(GL_ARB_compressed_texture_pixel_storage) +#define GLEW_ARB_compute_shader GLEW_GET_VAR(GL_ARB_compute_shader) +#define GLEW_ARB_compute_variable_group_size GLEW_GET_VAR(GL_ARB_compute_variable_group_size) +#define GLEW_ARB_conservative_depth GLEW_GET_VAR(GL_ARB_conservative_depth) +#define GLEW_ARB_copy_buffer GLEW_GET_VAR(GL_ARB_copy_buffer) +#define GLEW_ARB_copy_image GLEW_GET_VAR(GL_ARB_copy_image) +#define GLEW_ARB_debug_output GLEW_GET_VAR(GL_ARB_debug_output) +#define GLEW_ARB_depth_buffer_float GLEW_GET_VAR(GL_ARB_depth_buffer_float) +#define GLEW_ARB_depth_clamp GLEW_GET_VAR(GL_ARB_depth_clamp) +#define GLEW_ARB_depth_texture GLEW_GET_VAR(GL_ARB_depth_texture) +#define GLEW_ARB_draw_buffers GLEW_GET_VAR(GL_ARB_draw_buffers) +#define GLEW_ARB_draw_buffers_blend GLEW_GET_VAR(GL_ARB_draw_buffers_blend) +#define GLEW_ARB_draw_elements_base_vertex GLEW_GET_VAR(GL_ARB_draw_elements_base_vertex) +#define GLEW_ARB_draw_indirect GLEW_GET_VAR(GL_ARB_draw_indirect) +#define GLEW_ARB_draw_instanced GLEW_GET_VAR(GL_ARB_draw_instanced) +#define GLEW_ARB_enhanced_layouts GLEW_GET_VAR(GL_ARB_enhanced_layouts) +#define GLEW_ARB_explicit_attrib_location GLEW_GET_VAR(GL_ARB_explicit_attrib_location) +#define GLEW_ARB_explicit_uniform_location GLEW_GET_VAR(GL_ARB_explicit_uniform_location) +#define GLEW_ARB_fragment_coord_conventions GLEW_GET_VAR(GL_ARB_fragment_coord_conventions) +#define GLEW_ARB_fragment_layer_viewport GLEW_GET_VAR(GL_ARB_fragment_layer_viewport) +#define GLEW_ARB_fragment_program GLEW_GET_VAR(GL_ARB_fragment_program) +#define GLEW_ARB_fragment_program_shadow GLEW_GET_VAR(GL_ARB_fragment_program_shadow) +#define GLEW_ARB_fragment_shader GLEW_GET_VAR(GL_ARB_fragment_shader) +#define GLEW_ARB_framebuffer_no_attachments GLEW_GET_VAR(GL_ARB_framebuffer_no_attachments) +#define GLEW_ARB_framebuffer_object GLEW_GET_VAR(GL_ARB_framebuffer_object) +#define GLEW_ARB_framebuffer_sRGB GLEW_GET_VAR(GL_ARB_framebuffer_sRGB) +#define GLEW_ARB_geometry_shader4 GLEW_GET_VAR(GL_ARB_geometry_shader4) +#define GLEW_ARB_get_program_binary GLEW_GET_VAR(GL_ARB_get_program_binary) +#define GLEW_ARB_gpu_shader5 GLEW_GET_VAR(GL_ARB_gpu_shader5) +#define GLEW_ARB_gpu_shader_fp64 GLEW_GET_VAR(GL_ARB_gpu_shader_fp64) +#define GLEW_ARB_half_float_pixel GLEW_GET_VAR(GL_ARB_half_float_pixel) +#define GLEW_ARB_half_float_vertex GLEW_GET_VAR(GL_ARB_half_float_vertex) +#define GLEW_ARB_imaging GLEW_GET_VAR(GL_ARB_imaging) +#define GLEW_ARB_indirect_parameters GLEW_GET_VAR(GL_ARB_indirect_parameters) +#define GLEW_ARB_instanced_arrays GLEW_GET_VAR(GL_ARB_instanced_arrays) +#define GLEW_ARB_internalformat_query GLEW_GET_VAR(GL_ARB_internalformat_query) +#define GLEW_ARB_internalformat_query2 GLEW_GET_VAR(GL_ARB_internalformat_query2) +#define GLEW_ARB_invalidate_subdata GLEW_GET_VAR(GL_ARB_invalidate_subdata) +#define GLEW_ARB_map_buffer_alignment GLEW_GET_VAR(GL_ARB_map_buffer_alignment) +#define GLEW_ARB_map_buffer_range GLEW_GET_VAR(GL_ARB_map_buffer_range) +#define GLEW_ARB_matrix_palette GLEW_GET_VAR(GL_ARB_matrix_palette) +#define GLEW_ARB_multi_bind GLEW_GET_VAR(GL_ARB_multi_bind) +#define GLEW_ARB_multi_draw_indirect GLEW_GET_VAR(GL_ARB_multi_draw_indirect) +#define GLEW_ARB_multisample GLEW_GET_VAR(GL_ARB_multisample) +#define GLEW_ARB_multitexture GLEW_GET_VAR(GL_ARB_multitexture) +#define GLEW_ARB_occlusion_query GLEW_GET_VAR(GL_ARB_occlusion_query) +#define GLEW_ARB_occlusion_query2 GLEW_GET_VAR(GL_ARB_occlusion_query2) +#define GLEW_ARB_pixel_buffer_object GLEW_GET_VAR(GL_ARB_pixel_buffer_object) +#define GLEW_ARB_point_parameters GLEW_GET_VAR(GL_ARB_point_parameters) +#define GLEW_ARB_point_sprite GLEW_GET_VAR(GL_ARB_point_sprite) +#define GLEW_ARB_program_interface_query GLEW_GET_VAR(GL_ARB_program_interface_query) +#define GLEW_ARB_provoking_vertex GLEW_GET_VAR(GL_ARB_provoking_vertex) +#define GLEW_ARB_query_buffer_object GLEW_GET_VAR(GL_ARB_query_buffer_object) +#define GLEW_ARB_robust_buffer_access_behavior GLEW_GET_VAR(GL_ARB_robust_buffer_access_behavior) +#define GLEW_ARB_robustness GLEW_GET_VAR(GL_ARB_robustness) +#define GLEW_ARB_robustness_application_isolation GLEW_GET_VAR(GL_ARB_robustness_application_isolation) +#define GLEW_ARB_robustness_share_group_isolation GLEW_GET_VAR(GL_ARB_robustness_share_group_isolation) +#define GLEW_ARB_sample_shading GLEW_GET_VAR(GL_ARB_sample_shading) +#define GLEW_ARB_sampler_objects GLEW_GET_VAR(GL_ARB_sampler_objects) +#define GLEW_ARB_seamless_cube_map GLEW_GET_VAR(GL_ARB_seamless_cube_map) +#define GLEW_ARB_seamless_cubemap_per_texture GLEW_GET_VAR(GL_ARB_seamless_cubemap_per_texture) +#define GLEW_ARB_separate_shader_objects GLEW_GET_VAR(GL_ARB_separate_shader_objects) +#define GLEW_ARB_shader_atomic_counters GLEW_GET_VAR(GL_ARB_shader_atomic_counters) +#define GLEW_ARB_shader_bit_encoding GLEW_GET_VAR(GL_ARB_shader_bit_encoding) +#define GLEW_ARB_shader_draw_parameters GLEW_GET_VAR(GL_ARB_shader_draw_parameters) +#define GLEW_ARB_shader_group_vote GLEW_GET_VAR(GL_ARB_shader_group_vote) +#define GLEW_ARB_shader_image_load_store GLEW_GET_VAR(GL_ARB_shader_image_load_store) +#define GLEW_ARB_shader_image_size GLEW_GET_VAR(GL_ARB_shader_image_size) +#define GLEW_ARB_shader_objects GLEW_GET_VAR(GL_ARB_shader_objects) +#define GLEW_ARB_shader_precision GLEW_GET_VAR(GL_ARB_shader_precision) +#define GLEW_ARB_shader_stencil_export GLEW_GET_VAR(GL_ARB_shader_stencil_export) +#define GLEW_ARB_shader_storage_buffer_object GLEW_GET_VAR(GL_ARB_shader_storage_buffer_object) +#define GLEW_ARB_shader_subroutine GLEW_GET_VAR(GL_ARB_shader_subroutine) +#define GLEW_ARB_shader_texture_lod GLEW_GET_VAR(GL_ARB_shader_texture_lod) +#define GLEW_ARB_shading_language_100 GLEW_GET_VAR(GL_ARB_shading_language_100) +#define GLEW_ARB_shading_language_420pack GLEW_GET_VAR(GL_ARB_shading_language_420pack) +#define GLEW_ARB_shading_language_include GLEW_GET_VAR(GL_ARB_shading_language_include) +#define GLEW_ARB_shading_language_packing GLEW_GET_VAR(GL_ARB_shading_language_packing) +#define GLEW_ARB_shadow GLEW_GET_VAR(GL_ARB_shadow) +#define GLEW_ARB_shadow_ambient GLEW_GET_VAR(GL_ARB_shadow_ambient) +#define GLEW_ARB_sparse_texture GLEW_GET_VAR(GL_ARB_sparse_texture) +#define GLEW_ARB_stencil_texturing GLEW_GET_VAR(GL_ARB_stencil_texturing) +#define GLEW_ARB_sync GLEW_GET_VAR(GL_ARB_sync) +#define GLEW_ARB_tessellation_shader GLEW_GET_VAR(GL_ARB_tessellation_shader) +#define GLEW_ARB_texture_border_clamp GLEW_GET_VAR(GL_ARB_texture_border_clamp) +#define GLEW_ARB_texture_buffer_object GLEW_GET_VAR(GL_ARB_texture_buffer_object) +#define GLEW_ARB_texture_buffer_object_rgb32 GLEW_GET_VAR(GL_ARB_texture_buffer_object_rgb32) +#define GLEW_ARB_texture_buffer_range GLEW_GET_VAR(GL_ARB_texture_buffer_range) +#define GLEW_ARB_texture_compression GLEW_GET_VAR(GL_ARB_texture_compression) +#define GLEW_ARB_texture_compression_bptc GLEW_GET_VAR(GL_ARB_texture_compression_bptc) +#define GLEW_ARB_texture_compression_rgtc GLEW_GET_VAR(GL_ARB_texture_compression_rgtc) +#define GLEW_ARB_texture_cube_map GLEW_GET_VAR(GL_ARB_texture_cube_map) +#define GLEW_ARB_texture_cube_map_array GLEW_GET_VAR(GL_ARB_texture_cube_map_array) +#define GLEW_ARB_texture_env_add GLEW_GET_VAR(GL_ARB_texture_env_add) +#define GLEW_ARB_texture_env_combine GLEW_GET_VAR(GL_ARB_texture_env_combine) +#define GLEW_ARB_texture_env_crossbar GLEW_GET_VAR(GL_ARB_texture_env_crossbar) +#define GLEW_ARB_texture_env_dot3 GLEW_GET_VAR(GL_ARB_texture_env_dot3) +#define GLEW_ARB_texture_float GLEW_GET_VAR(GL_ARB_texture_float) +#define GLEW_ARB_texture_gather GLEW_GET_VAR(GL_ARB_texture_gather) +#define GLEW_ARB_texture_mirror_clamp_to_edge GLEW_GET_VAR(GL_ARB_texture_mirror_clamp_to_edge) +#define GLEW_ARB_texture_mirrored_repeat GLEW_GET_VAR(GL_ARB_texture_mirrored_repeat) +#define GLEW_ARB_texture_multisample GLEW_GET_VAR(GL_ARB_texture_multisample) +#define GLEW_ARB_texture_non_power_of_two GLEW_GET_VAR(GL_ARB_texture_non_power_of_two) +#define GLEW_ARB_texture_query_levels GLEW_GET_VAR(GL_ARB_texture_query_levels) +#define GLEW_ARB_texture_query_lod GLEW_GET_VAR(GL_ARB_texture_query_lod) +#define GLEW_ARB_texture_rectangle GLEW_GET_VAR(GL_ARB_texture_rectangle) +#define GLEW_ARB_texture_rg GLEW_GET_VAR(GL_ARB_texture_rg) +#define GLEW_ARB_texture_rgb10_a2ui GLEW_GET_VAR(GL_ARB_texture_rgb10_a2ui) +#define GLEW_ARB_texture_stencil8 GLEW_GET_VAR(GL_ARB_texture_stencil8) +#define GLEW_ARB_texture_storage GLEW_GET_VAR(GL_ARB_texture_storage) +#define GLEW_ARB_texture_storage_multisample GLEW_GET_VAR(GL_ARB_texture_storage_multisample) +#define GLEW_ARB_texture_swizzle GLEW_GET_VAR(GL_ARB_texture_swizzle) +#define GLEW_ARB_texture_view GLEW_GET_VAR(GL_ARB_texture_view) +#define GLEW_ARB_timer_query GLEW_GET_VAR(GL_ARB_timer_query) +#define GLEW_ARB_transform_feedback2 GLEW_GET_VAR(GL_ARB_transform_feedback2) +#define GLEW_ARB_transform_feedback3 GLEW_GET_VAR(GL_ARB_transform_feedback3) +#define GLEW_ARB_transform_feedback_instanced GLEW_GET_VAR(GL_ARB_transform_feedback_instanced) +#define GLEW_ARB_transpose_matrix GLEW_GET_VAR(GL_ARB_transpose_matrix) +#define GLEW_ARB_uniform_buffer_object GLEW_GET_VAR(GL_ARB_uniform_buffer_object) +#define GLEW_ARB_vertex_array_bgra GLEW_GET_VAR(GL_ARB_vertex_array_bgra) +#define GLEW_ARB_vertex_array_object GLEW_GET_VAR(GL_ARB_vertex_array_object) +#define GLEW_ARB_vertex_attrib_64bit GLEW_GET_VAR(GL_ARB_vertex_attrib_64bit) +#define GLEW_ARB_vertex_attrib_binding GLEW_GET_VAR(GL_ARB_vertex_attrib_binding) +#define GLEW_ARB_vertex_blend GLEW_GET_VAR(GL_ARB_vertex_blend) +#define GLEW_ARB_vertex_buffer_object GLEW_GET_VAR(GL_ARB_vertex_buffer_object) +#define GLEW_ARB_vertex_program GLEW_GET_VAR(GL_ARB_vertex_program) +#define GLEW_ARB_vertex_shader GLEW_GET_VAR(GL_ARB_vertex_shader) +#define GLEW_ARB_vertex_type_10f_11f_11f_rev GLEW_GET_VAR(GL_ARB_vertex_type_10f_11f_11f_rev) +#define GLEW_ARB_vertex_type_2_10_10_10_rev GLEW_GET_VAR(GL_ARB_vertex_type_2_10_10_10_rev) +#define GLEW_ARB_viewport_array GLEW_GET_VAR(GL_ARB_viewport_array) +#define GLEW_ARB_window_pos GLEW_GET_VAR(GL_ARB_window_pos) +#define GLEW_ATIX_point_sprites GLEW_GET_VAR(GL_ATIX_point_sprites) +#define GLEW_ATIX_texture_env_combine3 GLEW_GET_VAR(GL_ATIX_texture_env_combine3) +#define GLEW_ATIX_texture_env_route GLEW_GET_VAR(GL_ATIX_texture_env_route) +#define GLEW_ATIX_vertex_shader_output_point_size GLEW_GET_VAR(GL_ATIX_vertex_shader_output_point_size) +#define GLEW_ATI_draw_buffers GLEW_GET_VAR(GL_ATI_draw_buffers) +#define GLEW_ATI_element_array GLEW_GET_VAR(GL_ATI_element_array) +#define GLEW_ATI_envmap_bumpmap GLEW_GET_VAR(GL_ATI_envmap_bumpmap) +#define GLEW_ATI_fragment_shader GLEW_GET_VAR(GL_ATI_fragment_shader) +#define GLEW_ATI_map_object_buffer GLEW_GET_VAR(GL_ATI_map_object_buffer) +#define GLEW_ATI_meminfo GLEW_GET_VAR(GL_ATI_meminfo) +#define GLEW_ATI_pn_triangles GLEW_GET_VAR(GL_ATI_pn_triangles) +#define GLEW_ATI_separate_stencil GLEW_GET_VAR(GL_ATI_separate_stencil) +#define GLEW_ATI_shader_texture_lod GLEW_GET_VAR(GL_ATI_shader_texture_lod) +#define GLEW_ATI_text_fragment_shader GLEW_GET_VAR(GL_ATI_text_fragment_shader) +#define GLEW_ATI_texture_compression_3dc GLEW_GET_VAR(GL_ATI_texture_compression_3dc) +#define GLEW_ATI_texture_env_combine3 GLEW_GET_VAR(GL_ATI_texture_env_combine3) +#define GLEW_ATI_texture_float GLEW_GET_VAR(GL_ATI_texture_float) +#define GLEW_ATI_texture_mirror_once GLEW_GET_VAR(GL_ATI_texture_mirror_once) +#define GLEW_ATI_vertex_array_object GLEW_GET_VAR(GL_ATI_vertex_array_object) +#define GLEW_ATI_vertex_attrib_array_object GLEW_GET_VAR(GL_ATI_vertex_attrib_array_object) +#define GLEW_ATI_vertex_streams GLEW_GET_VAR(GL_ATI_vertex_streams) +#define GLEW_EXT_422_pixels GLEW_GET_VAR(GL_EXT_422_pixels) +#define GLEW_EXT_Cg_shader GLEW_GET_VAR(GL_EXT_Cg_shader) +#define GLEW_EXT_abgr GLEW_GET_VAR(GL_EXT_abgr) +#define GLEW_EXT_bgra GLEW_GET_VAR(GL_EXT_bgra) +#define GLEW_EXT_bindable_uniform GLEW_GET_VAR(GL_EXT_bindable_uniform) +#define GLEW_EXT_blend_color GLEW_GET_VAR(GL_EXT_blend_color) +#define GLEW_EXT_blend_equation_separate GLEW_GET_VAR(GL_EXT_blend_equation_separate) +#define GLEW_EXT_blend_func_separate GLEW_GET_VAR(GL_EXT_blend_func_separate) +#define GLEW_EXT_blend_logic_op GLEW_GET_VAR(GL_EXT_blend_logic_op) +#define GLEW_EXT_blend_minmax GLEW_GET_VAR(GL_EXT_blend_minmax) +#define GLEW_EXT_blend_subtract GLEW_GET_VAR(GL_EXT_blend_subtract) +#define GLEW_EXT_clip_volume_hint GLEW_GET_VAR(GL_EXT_clip_volume_hint) +#define GLEW_EXT_cmyka GLEW_GET_VAR(GL_EXT_cmyka) +#define GLEW_EXT_color_subtable GLEW_GET_VAR(GL_EXT_color_subtable) +#define GLEW_EXT_compiled_vertex_array GLEW_GET_VAR(GL_EXT_compiled_vertex_array) +#define GLEW_EXT_convolution GLEW_GET_VAR(GL_EXT_convolution) +#define GLEW_EXT_coordinate_frame GLEW_GET_VAR(GL_EXT_coordinate_frame) +#define GLEW_EXT_copy_texture GLEW_GET_VAR(GL_EXT_copy_texture) +#define GLEW_EXT_cull_vertex GLEW_GET_VAR(GL_EXT_cull_vertex) +#define GLEW_EXT_debug_label GLEW_GET_VAR(GL_EXT_debug_label) +#define GLEW_EXT_debug_marker GLEW_GET_VAR(GL_EXT_debug_marker) +#define GLEW_EXT_depth_bounds_test GLEW_GET_VAR(GL_EXT_depth_bounds_test) +#define GLEW_EXT_direct_state_access GLEW_GET_VAR(GL_EXT_direct_state_access) +#define GLEW_EXT_draw_buffers2 GLEW_GET_VAR(GL_EXT_draw_buffers2) +#define GLEW_EXT_draw_instanced GLEW_GET_VAR(GL_EXT_draw_instanced) +#define GLEW_EXT_draw_range_elements GLEW_GET_VAR(GL_EXT_draw_range_elements) +#define GLEW_EXT_fog_coord GLEW_GET_VAR(GL_EXT_fog_coord) +#define GLEW_EXT_fragment_lighting GLEW_GET_VAR(GL_EXT_fragment_lighting) +#define GLEW_EXT_framebuffer_blit GLEW_GET_VAR(GL_EXT_framebuffer_blit) +#define GLEW_EXT_framebuffer_multisample GLEW_GET_VAR(GL_EXT_framebuffer_multisample) +#define GLEW_EXT_framebuffer_multisample_blit_scaled GLEW_GET_VAR(GL_EXT_framebuffer_multisample_blit_scaled) +#define GLEW_EXT_framebuffer_object GLEW_GET_VAR(GL_EXT_framebuffer_object) +#define GLEW_EXT_framebuffer_sRGB GLEW_GET_VAR(GL_EXT_framebuffer_sRGB) +#define GLEW_EXT_geometry_shader4 GLEW_GET_VAR(GL_EXT_geometry_shader4) +#define GLEW_EXT_gpu_program_parameters GLEW_GET_VAR(GL_EXT_gpu_program_parameters) +#define GLEW_EXT_gpu_shader4 GLEW_GET_VAR(GL_EXT_gpu_shader4) +#define GLEW_EXT_histogram GLEW_GET_VAR(GL_EXT_histogram) +#define GLEW_EXT_index_array_formats GLEW_GET_VAR(GL_EXT_index_array_formats) +#define GLEW_EXT_index_func GLEW_GET_VAR(GL_EXT_index_func) +#define GLEW_EXT_index_material GLEW_GET_VAR(GL_EXT_index_material) +#define GLEW_EXT_index_texture GLEW_GET_VAR(GL_EXT_index_texture) +#define GLEW_EXT_light_texture GLEW_GET_VAR(GL_EXT_light_texture) +#define GLEW_EXT_misc_attribute GLEW_GET_VAR(GL_EXT_misc_attribute) +#define GLEW_EXT_multi_draw_arrays GLEW_GET_VAR(GL_EXT_multi_draw_arrays) +#define GLEW_EXT_multisample GLEW_GET_VAR(GL_EXT_multisample) +#define GLEW_EXT_packed_depth_stencil GLEW_GET_VAR(GL_EXT_packed_depth_stencil) +#define GLEW_EXT_packed_float GLEW_GET_VAR(GL_EXT_packed_float) +#define GLEW_EXT_packed_pixels GLEW_GET_VAR(GL_EXT_packed_pixels) +#define GLEW_EXT_paletted_texture GLEW_GET_VAR(GL_EXT_paletted_texture) +#define GLEW_EXT_pixel_buffer_object GLEW_GET_VAR(GL_EXT_pixel_buffer_object) +#define GLEW_EXT_pixel_transform GLEW_GET_VAR(GL_EXT_pixel_transform) +#define GLEW_EXT_pixel_transform_color_table GLEW_GET_VAR(GL_EXT_pixel_transform_color_table) +#define GLEW_EXT_point_parameters GLEW_GET_VAR(GL_EXT_point_parameters) +#define GLEW_EXT_polygon_offset GLEW_GET_VAR(GL_EXT_polygon_offset) +#define GLEW_EXT_provoking_vertex GLEW_GET_VAR(GL_EXT_provoking_vertex) +#define GLEW_EXT_rescale_normal GLEW_GET_VAR(GL_EXT_rescale_normal) +#define GLEW_EXT_scene_marker GLEW_GET_VAR(GL_EXT_scene_marker) +#define GLEW_EXT_secondary_color GLEW_GET_VAR(GL_EXT_secondary_color) +#define GLEW_EXT_separate_shader_objects GLEW_GET_VAR(GL_EXT_separate_shader_objects) +#define GLEW_EXT_separate_specular_color GLEW_GET_VAR(GL_EXT_separate_specular_color) +#define GLEW_EXT_shader_image_load_store GLEW_GET_VAR(GL_EXT_shader_image_load_store) +#define GLEW_EXT_shader_integer_mix GLEW_GET_VAR(GL_EXT_shader_integer_mix) +#define GLEW_EXT_shadow_funcs GLEW_GET_VAR(GL_EXT_shadow_funcs) +#define GLEW_EXT_shared_texture_palette GLEW_GET_VAR(GL_EXT_shared_texture_palette) +#define GLEW_EXT_stencil_clear_tag GLEW_GET_VAR(GL_EXT_stencil_clear_tag) +#define GLEW_EXT_stencil_two_side GLEW_GET_VAR(GL_EXT_stencil_two_side) +#define GLEW_EXT_stencil_wrap GLEW_GET_VAR(GL_EXT_stencil_wrap) +#define GLEW_EXT_subtexture GLEW_GET_VAR(GL_EXT_subtexture) +#define GLEW_EXT_texture GLEW_GET_VAR(GL_EXT_texture) +#define GLEW_EXT_texture3D GLEW_GET_VAR(GL_EXT_texture3D) +#define GLEW_EXT_texture_array GLEW_GET_VAR(GL_EXT_texture_array) +#define GLEW_EXT_texture_buffer_object GLEW_GET_VAR(GL_EXT_texture_buffer_object) +#define GLEW_EXT_texture_compression_dxt1 GLEW_GET_VAR(GL_EXT_texture_compression_dxt1) +#define GLEW_EXT_texture_compression_latc GLEW_GET_VAR(GL_EXT_texture_compression_latc) +#define GLEW_EXT_texture_compression_rgtc GLEW_GET_VAR(GL_EXT_texture_compression_rgtc) +#define GLEW_EXT_texture_compression_s3tc GLEW_GET_VAR(GL_EXT_texture_compression_s3tc) +#define GLEW_EXT_texture_cube_map GLEW_GET_VAR(GL_EXT_texture_cube_map) +#define GLEW_EXT_texture_edge_clamp GLEW_GET_VAR(GL_EXT_texture_edge_clamp) +#define GLEW_EXT_texture_env GLEW_GET_VAR(GL_EXT_texture_env) +#define GLEW_EXT_texture_env_add GLEW_GET_VAR(GL_EXT_texture_env_add) +#define GLEW_EXT_texture_env_combine GLEW_GET_VAR(GL_EXT_texture_env_combine) +#define GLEW_EXT_texture_env_dot3 GLEW_GET_VAR(GL_EXT_texture_env_dot3) +#define GLEW_EXT_texture_filter_anisotropic GLEW_GET_VAR(GL_EXT_texture_filter_anisotropic) +#define GLEW_EXT_texture_integer GLEW_GET_VAR(GL_EXT_texture_integer) +#define GLEW_EXT_texture_lod_bias GLEW_GET_VAR(GL_EXT_texture_lod_bias) +#define GLEW_EXT_texture_mirror_clamp GLEW_GET_VAR(GL_EXT_texture_mirror_clamp) +#define GLEW_EXT_texture_object GLEW_GET_VAR(GL_EXT_texture_object) +#define GLEW_EXT_texture_perturb_normal GLEW_GET_VAR(GL_EXT_texture_perturb_normal) +#define GLEW_EXT_texture_rectangle GLEW_GET_VAR(GL_EXT_texture_rectangle) +#define GLEW_EXT_texture_sRGB GLEW_GET_VAR(GL_EXT_texture_sRGB) +#define GLEW_EXT_texture_sRGB_decode GLEW_GET_VAR(GL_EXT_texture_sRGB_decode) +#define GLEW_EXT_texture_shared_exponent GLEW_GET_VAR(GL_EXT_texture_shared_exponent) +#define GLEW_EXT_texture_snorm GLEW_GET_VAR(GL_EXT_texture_snorm) +#define GLEW_EXT_texture_swizzle GLEW_GET_VAR(GL_EXT_texture_swizzle) +#define GLEW_EXT_timer_query GLEW_GET_VAR(GL_EXT_timer_query) +#define GLEW_EXT_transform_feedback GLEW_GET_VAR(GL_EXT_transform_feedback) +#define GLEW_EXT_vertex_array GLEW_GET_VAR(GL_EXT_vertex_array) +#define GLEW_EXT_vertex_array_bgra GLEW_GET_VAR(GL_EXT_vertex_array_bgra) +#define GLEW_EXT_vertex_attrib_64bit GLEW_GET_VAR(GL_EXT_vertex_attrib_64bit) +#define GLEW_EXT_vertex_shader GLEW_GET_VAR(GL_EXT_vertex_shader) +#define GLEW_EXT_vertex_weighting GLEW_GET_VAR(GL_EXT_vertex_weighting) +#define GLEW_EXT_x11_sync_object GLEW_GET_VAR(GL_EXT_x11_sync_object) +#define GLEW_GREMEDY_frame_terminator GLEW_GET_VAR(GL_GREMEDY_frame_terminator) +#define GLEW_GREMEDY_string_marker GLEW_GET_VAR(GL_GREMEDY_string_marker) +#define GLEW_HP_convolution_border_modes GLEW_GET_VAR(GL_HP_convolution_border_modes) +#define GLEW_HP_image_transform GLEW_GET_VAR(GL_HP_image_transform) +#define GLEW_HP_occlusion_test GLEW_GET_VAR(GL_HP_occlusion_test) +#define GLEW_HP_texture_lighting GLEW_GET_VAR(GL_HP_texture_lighting) +#define GLEW_IBM_cull_vertex GLEW_GET_VAR(GL_IBM_cull_vertex) +#define GLEW_IBM_multimode_draw_arrays GLEW_GET_VAR(GL_IBM_multimode_draw_arrays) +#define GLEW_IBM_rasterpos_clip GLEW_GET_VAR(GL_IBM_rasterpos_clip) +#define GLEW_IBM_static_data GLEW_GET_VAR(GL_IBM_static_data) +#define GLEW_IBM_texture_mirrored_repeat GLEW_GET_VAR(GL_IBM_texture_mirrored_repeat) +#define GLEW_IBM_vertex_array_lists GLEW_GET_VAR(GL_IBM_vertex_array_lists) +#define GLEW_INGR_color_clamp GLEW_GET_VAR(GL_INGR_color_clamp) +#define GLEW_INGR_interlace_read GLEW_GET_VAR(GL_INGR_interlace_read) +#define GLEW_INTEL_fragment_shader_ordering GLEW_GET_VAR(GL_INTEL_fragment_shader_ordering) +#define GLEW_INTEL_map_texture GLEW_GET_VAR(GL_INTEL_map_texture) +#define GLEW_INTEL_parallel_arrays GLEW_GET_VAR(GL_INTEL_parallel_arrays) +#define GLEW_INTEL_texture_scissor GLEW_GET_VAR(GL_INTEL_texture_scissor) +#define GLEW_KHR_debug GLEW_GET_VAR(GL_KHR_debug) +#define GLEW_KHR_texture_compression_astc_hdr GLEW_GET_VAR(GL_KHR_texture_compression_astc_hdr) +#define GLEW_KHR_texture_compression_astc_ldr GLEW_GET_VAR(GL_KHR_texture_compression_astc_ldr) +#define GLEW_KTX_buffer_region GLEW_GET_VAR(GL_KTX_buffer_region) +#define GLEW_MESAX_texture_stack GLEW_GET_VAR(GL_MESAX_texture_stack) +#define GLEW_MESA_pack_invert GLEW_GET_VAR(GL_MESA_pack_invert) +#define GLEW_MESA_resize_buffers GLEW_GET_VAR(GL_MESA_resize_buffers) +#define GLEW_MESA_window_pos GLEW_GET_VAR(GL_MESA_window_pos) +#define GLEW_MESA_ycbcr_texture GLEW_GET_VAR(GL_MESA_ycbcr_texture) +#define GLEW_NVX_conditional_render GLEW_GET_VAR(GL_NVX_conditional_render) +#define GLEW_NVX_gpu_memory_info GLEW_GET_VAR(GL_NVX_gpu_memory_info) +#define GLEW_NV_bindless_multi_draw_indirect GLEW_GET_VAR(GL_NV_bindless_multi_draw_indirect) +#define GLEW_NV_bindless_texture GLEW_GET_VAR(GL_NV_bindless_texture) +#define GLEW_NV_blend_equation_advanced GLEW_GET_VAR(GL_NV_blend_equation_advanced) +#define GLEW_NV_blend_equation_advanced_coherent GLEW_GET_VAR(GL_NV_blend_equation_advanced_coherent) +#define GLEW_NV_blend_square GLEW_GET_VAR(GL_NV_blend_square) +#define GLEW_NV_compute_program5 GLEW_GET_VAR(GL_NV_compute_program5) +#define GLEW_NV_conditional_render GLEW_GET_VAR(GL_NV_conditional_render) +#define GLEW_NV_copy_depth_to_color GLEW_GET_VAR(GL_NV_copy_depth_to_color) +#define GLEW_NV_copy_image GLEW_GET_VAR(GL_NV_copy_image) +#define GLEW_NV_deep_texture3D GLEW_GET_VAR(GL_NV_deep_texture3D) +#define GLEW_NV_depth_buffer_float GLEW_GET_VAR(GL_NV_depth_buffer_float) +#define GLEW_NV_depth_clamp GLEW_GET_VAR(GL_NV_depth_clamp) +#define GLEW_NV_depth_range_unclamped GLEW_GET_VAR(GL_NV_depth_range_unclamped) +#define GLEW_NV_draw_texture GLEW_GET_VAR(GL_NV_draw_texture) +#define GLEW_NV_evaluators GLEW_GET_VAR(GL_NV_evaluators) +#define GLEW_NV_explicit_multisample GLEW_GET_VAR(GL_NV_explicit_multisample) +#define GLEW_NV_fence GLEW_GET_VAR(GL_NV_fence) +#define GLEW_NV_float_buffer GLEW_GET_VAR(GL_NV_float_buffer) +#define GLEW_NV_fog_distance GLEW_GET_VAR(GL_NV_fog_distance) +#define GLEW_NV_fragment_program GLEW_GET_VAR(GL_NV_fragment_program) +#define GLEW_NV_fragment_program2 GLEW_GET_VAR(GL_NV_fragment_program2) +#define GLEW_NV_fragment_program4 GLEW_GET_VAR(GL_NV_fragment_program4) +#define GLEW_NV_fragment_program_option GLEW_GET_VAR(GL_NV_fragment_program_option) +#define GLEW_NV_framebuffer_multisample_coverage GLEW_GET_VAR(GL_NV_framebuffer_multisample_coverage) +#define GLEW_NV_geometry_program4 GLEW_GET_VAR(GL_NV_geometry_program4) +#define GLEW_NV_geometry_shader4 GLEW_GET_VAR(GL_NV_geometry_shader4) +#define GLEW_NV_gpu_program4 GLEW_GET_VAR(GL_NV_gpu_program4) +#define GLEW_NV_gpu_program5 GLEW_GET_VAR(GL_NV_gpu_program5) +#define GLEW_NV_gpu_program5_mem_extended GLEW_GET_VAR(GL_NV_gpu_program5_mem_extended) +#define GLEW_NV_gpu_program_fp64 GLEW_GET_VAR(GL_NV_gpu_program_fp64) +#define GLEW_NV_gpu_shader5 GLEW_GET_VAR(GL_NV_gpu_shader5) +#define GLEW_NV_half_float GLEW_GET_VAR(GL_NV_half_float) +#define GLEW_NV_light_max_exponent GLEW_GET_VAR(GL_NV_light_max_exponent) +#define GLEW_NV_multisample_coverage GLEW_GET_VAR(GL_NV_multisample_coverage) +#define GLEW_NV_multisample_filter_hint GLEW_GET_VAR(GL_NV_multisample_filter_hint) +#define GLEW_NV_occlusion_query GLEW_GET_VAR(GL_NV_occlusion_query) +#define GLEW_NV_packed_depth_stencil GLEW_GET_VAR(GL_NV_packed_depth_stencil) +#define GLEW_NV_parameter_buffer_object GLEW_GET_VAR(GL_NV_parameter_buffer_object) +#define GLEW_NV_parameter_buffer_object2 GLEW_GET_VAR(GL_NV_parameter_buffer_object2) +#define GLEW_NV_path_rendering GLEW_GET_VAR(GL_NV_path_rendering) +#define GLEW_NV_pixel_data_range GLEW_GET_VAR(GL_NV_pixel_data_range) +#define GLEW_NV_point_sprite GLEW_GET_VAR(GL_NV_point_sprite) +#define GLEW_NV_present_video GLEW_GET_VAR(GL_NV_present_video) +#define GLEW_NV_primitive_restart GLEW_GET_VAR(GL_NV_primitive_restart) +#define GLEW_NV_register_combiners GLEW_GET_VAR(GL_NV_register_combiners) +#define GLEW_NV_register_combiners2 GLEW_GET_VAR(GL_NV_register_combiners2) +#define GLEW_NV_shader_atomic_counters GLEW_GET_VAR(GL_NV_shader_atomic_counters) +#define GLEW_NV_shader_atomic_float GLEW_GET_VAR(GL_NV_shader_atomic_float) +#define GLEW_NV_shader_buffer_load GLEW_GET_VAR(GL_NV_shader_buffer_load) +#define GLEW_NV_shader_storage_buffer_object GLEW_GET_VAR(GL_NV_shader_storage_buffer_object) +#define GLEW_NV_tessellation_program5 GLEW_GET_VAR(GL_NV_tessellation_program5) +#define GLEW_NV_texgen_emboss GLEW_GET_VAR(GL_NV_texgen_emboss) +#define GLEW_NV_texgen_reflection GLEW_GET_VAR(GL_NV_texgen_reflection) +#define GLEW_NV_texture_barrier GLEW_GET_VAR(GL_NV_texture_barrier) +#define GLEW_NV_texture_compression_vtc GLEW_GET_VAR(GL_NV_texture_compression_vtc) +#define GLEW_NV_texture_env_combine4 GLEW_GET_VAR(GL_NV_texture_env_combine4) +#define GLEW_NV_texture_expand_normal GLEW_GET_VAR(GL_NV_texture_expand_normal) +#define GLEW_NV_texture_multisample GLEW_GET_VAR(GL_NV_texture_multisample) +#define GLEW_NV_texture_rectangle GLEW_GET_VAR(GL_NV_texture_rectangle) +#define GLEW_NV_texture_shader GLEW_GET_VAR(GL_NV_texture_shader) +#define GLEW_NV_texture_shader2 GLEW_GET_VAR(GL_NV_texture_shader2) +#define GLEW_NV_texture_shader3 GLEW_GET_VAR(GL_NV_texture_shader3) +#define GLEW_NV_transform_feedback GLEW_GET_VAR(GL_NV_transform_feedback) +#define GLEW_NV_transform_feedback2 GLEW_GET_VAR(GL_NV_transform_feedback2) +#define GLEW_NV_vdpau_interop GLEW_GET_VAR(GL_NV_vdpau_interop) +#define GLEW_NV_vertex_array_range GLEW_GET_VAR(GL_NV_vertex_array_range) +#define GLEW_NV_vertex_array_range2 GLEW_GET_VAR(GL_NV_vertex_array_range2) +#define GLEW_NV_vertex_attrib_integer_64bit GLEW_GET_VAR(GL_NV_vertex_attrib_integer_64bit) +#define GLEW_NV_vertex_buffer_unified_memory GLEW_GET_VAR(GL_NV_vertex_buffer_unified_memory) +#define GLEW_NV_vertex_program GLEW_GET_VAR(GL_NV_vertex_program) +#define GLEW_NV_vertex_program1_1 GLEW_GET_VAR(GL_NV_vertex_program1_1) +#define GLEW_NV_vertex_program2 GLEW_GET_VAR(GL_NV_vertex_program2) +#define GLEW_NV_vertex_program2_option GLEW_GET_VAR(GL_NV_vertex_program2_option) +#define GLEW_NV_vertex_program3 GLEW_GET_VAR(GL_NV_vertex_program3) +#define GLEW_NV_vertex_program4 GLEW_GET_VAR(GL_NV_vertex_program4) +#define GLEW_NV_video_capture GLEW_GET_VAR(GL_NV_video_capture) +#define GLEW_OES_byte_coordinates GLEW_GET_VAR(GL_OES_byte_coordinates) +#define GLEW_OES_compressed_paletted_texture GLEW_GET_VAR(GL_OES_compressed_paletted_texture) +#define GLEW_OES_read_format GLEW_GET_VAR(GL_OES_read_format) +#define GLEW_OES_single_precision GLEW_GET_VAR(GL_OES_single_precision) +#define GLEW_OML_interlace GLEW_GET_VAR(GL_OML_interlace) +#define GLEW_OML_resample GLEW_GET_VAR(GL_OML_resample) +#define GLEW_OML_subsample GLEW_GET_VAR(GL_OML_subsample) +#define GLEW_PGI_misc_hints GLEW_GET_VAR(GL_PGI_misc_hints) +#define GLEW_PGI_vertex_hints GLEW_GET_VAR(GL_PGI_vertex_hints) +#define GLEW_REGAL_ES1_0_compatibility GLEW_GET_VAR(GL_REGAL_ES1_0_compatibility) +#define GLEW_REGAL_ES1_1_compatibility GLEW_GET_VAR(GL_REGAL_ES1_1_compatibility) +#define GLEW_REGAL_enable GLEW_GET_VAR(GL_REGAL_enable) +#define GLEW_REGAL_error_string GLEW_GET_VAR(GL_REGAL_error_string) +#define GLEW_REGAL_extension_query GLEW_GET_VAR(GL_REGAL_extension_query) +#define GLEW_REGAL_log GLEW_GET_VAR(GL_REGAL_log) +#define GLEW_REND_screen_coordinates GLEW_GET_VAR(GL_REND_screen_coordinates) +#define GLEW_S3_s3tc GLEW_GET_VAR(GL_S3_s3tc) +#define GLEW_SGIS_color_range GLEW_GET_VAR(GL_SGIS_color_range) +#define GLEW_SGIS_detail_texture GLEW_GET_VAR(GL_SGIS_detail_texture) +#define GLEW_SGIS_fog_function GLEW_GET_VAR(GL_SGIS_fog_function) +#define GLEW_SGIS_generate_mipmap GLEW_GET_VAR(GL_SGIS_generate_mipmap) +#define GLEW_SGIS_multisample GLEW_GET_VAR(GL_SGIS_multisample) +#define GLEW_SGIS_pixel_texture GLEW_GET_VAR(GL_SGIS_pixel_texture) +#define GLEW_SGIS_point_line_texgen GLEW_GET_VAR(GL_SGIS_point_line_texgen) +#define GLEW_SGIS_sharpen_texture GLEW_GET_VAR(GL_SGIS_sharpen_texture) +#define GLEW_SGIS_texture4D GLEW_GET_VAR(GL_SGIS_texture4D) +#define GLEW_SGIS_texture_border_clamp GLEW_GET_VAR(GL_SGIS_texture_border_clamp) +#define GLEW_SGIS_texture_edge_clamp GLEW_GET_VAR(GL_SGIS_texture_edge_clamp) +#define GLEW_SGIS_texture_filter4 GLEW_GET_VAR(GL_SGIS_texture_filter4) +#define GLEW_SGIS_texture_lod GLEW_GET_VAR(GL_SGIS_texture_lod) +#define GLEW_SGIS_texture_select GLEW_GET_VAR(GL_SGIS_texture_select) +#define GLEW_SGIX_async GLEW_GET_VAR(GL_SGIX_async) +#define GLEW_SGIX_async_histogram GLEW_GET_VAR(GL_SGIX_async_histogram) +#define GLEW_SGIX_async_pixel GLEW_GET_VAR(GL_SGIX_async_pixel) +#define GLEW_SGIX_blend_alpha_minmax GLEW_GET_VAR(GL_SGIX_blend_alpha_minmax) +#define GLEW_SGIX_clipmap GLEW_GET_VAR(GL_SGIX_clipmap) +#define GLEW_SGIX_convolution_accuracy GLEW_GET_VAR(GL_SGIX_convolution_accuracy) +#define GLEW_SGIX_depth_texture GLEW_GET_VAR(GL_SGIX_depth_texture) +#define GLEW_SGIX_flush_raster GLEW_GET_VAR(GL_SGIX_flush_raster) +#define GLEW_SGIX_fog_offset GLEW_GET_VAR(GL_SGIX_fog_offset) +#define GLEW_SGIX_fog_texture GLEW_GET_VAR(GL_SGIX_fog_texture) +#define GLEW_SGIX_fragment_specular_lighting GLEW_GET_VAR(GL_SGIX_fragment_specular_lighting) +#define GLEW_SGIX_framezoom GLEW_GET_VAR(GL_SGIX_framezoom) +#define GLEW_SGIX_interlace GLEW_GET_VAR(GL_SGIX_interlace) +#define GLEW_SGIX_ir_instrument1 GLEW_GET_VAR(GL_SGIX_ir_instrument1) +#define GLEW_SGIX_list_priority GLEW_GET_VAR(GL_SGIX_list_priority) +#define GLEW_SGIX_pixel_texture GLEW_GET_VAR(GL_SGIX_pixel_texture) +#define GLEW_SGIX_pixel_texture_bits GLEW_GET_VAR(GL_SGIX_pixel_texture_bits) +#define GLEW_SGIX_reference_plane GLEW_GET_VAR(GL_SGIX_reference_plane) +#define GLEW_SGIX_resample GLEW_GET_VAR(GL_SGIX_resample) +#define GLEW_SGIX_shadow GLEW_GET_VAR(GL_SGIX_shadow) +#define GLEW_SGIX_shadow_ambient GLEW_GET_VAR(GL_SGIX_shadow_ambient) +#define GLEW_SGIX_sprite GLEW_GET_VAR(GL_SGIX_sprite) +#define GLEW_SGIX_tag_sample_buffer GLEW_GET_VAR(GL_SGIX_tag_sample_buffer) +#define GLEW_SGIX_texture_add_env GLEW_GET_VAR(GL_SGIX_texture_add_env) +#define GLEW_SGIX_texture_coordinate_clamp GLEW_GET_VAR(GL_SGIX_texture_coordinate_clamp) +#define GLEW_SGIX_texture_lod_bias GLEW_GET_VAR(GL_SGIX_texture_lod_bias) +#define GLEW_SGIX_texture_multi_buffer GLEW_GET_VAR(GL_SGIX_texture_multi_buffer) +#define GLEW_SGIX_texture_range GLEW_GET_VAR(GL_SGIX_texture_range) +#define GLEW_SGIX_texture_scale_bias GLEW_GET_VAR(GL_SGIX_texture_scale_bias) +#define GLEW_SGIX_vertex_preclip GLEW_GET_VAR(GL_SGIX_vertex_preclip) +#define GLEW_SGIX_vertex_preclip_hint GLEW_GET_VAR(GL_SGIX_vertex_preclip_hint) +#define GLEW_SGIX_ycrcb GLEW_GET_VAR(GL_SGIX_ycrcb) +#define GLEW_SGI_color_matrix GLEW_GET_VAR(GL_SGI_color_matrix) +#define GLEW_SGI_color_table GLEW_GET_VAR(GL_SGI_color_table) +#define GLEW_SGI_texture_color_table GLEW_GET_VAR(GL_SGI_texture_color_table) +#define GLEW_SUNX_constant_data GLEW_GET_VAR(GL_SUNX_constant_data) +#define GLEW_SUN_convolution_border_modes GLEW_GET_VAR(GL_SUN_convolution_border_modes) +#define GLEW_SUN_global_alpha GLEW_GET_VAR(GL_SUN_global_alpha) +#define GLEW_SUN_mesh_array GLEW_GET_VAR(GL_SUN_mesh_array) +#define GLEW_SUN_read_video_pixels GLEW_GET_VAR(GL_SUN_read_video_pixels) +#define GLEW_SUN_slice_accum GLEW_GET_VAR(GL_SUN_slice_accum) +#define GLEW_SUN_triangle_list GLEW_GET_VAR(GL_SUN_triangle_list) +#define GLEW_SUN_vertex GLEW_GET_VAR(GL_SUN_vertex) +#define GLEW_WIN_phong_shading GLEW_GET_VAR(GL_WIN_phong_shading) +#define GLEW_WIN_specular_fog GLEW_GET_VAR(GL_WIN_specular_fog) +#define GLEW_WIN_swap_hint GLEW_GET_VAR(GL_WIN_swap_hint) + +/* and from linaro glew-oes fork */ +#define GLEW_OES_byte_coordinates GLEW_GET_VAR(GL_OES_byte_coordinates) +#define GLEW_OES_compressed_paletted_texture GLEW_GET_VAR(GL_OES_compressed_paletted_texture) +#define GLEW_OES_read_format GLEW_GET_VAR(GL_OES_read_format) +#define GLEW_OES_single_precision GLEW_GET_VAR(GL_OES_single_precision) +#define GLEW_OES_EGL_image GLEW_GET_VAR(GL_OES_EGL_image) +#define GLEW_OES_EGL_image_external GLEW_GET_VAR(GL_OES_EGL_image_external) +#define GLEW_OES_EGL_sync GLEW_GET_VAR(GL_OES_EGL_sync) +#define GLEW_OES_blend_equation_separate GLEW_GET_VAR(GL_OES_blend_equation_separate) +#define GLEW_OES_blend_func_separate GLEW_GET_VAR(GL_OES_blend_func_separate) +#define GLEW_OES_blend_subtract GLEW_GET_VAR(GL_OES_blend_subtract) +#define GLEW_OES_compressed_ETC1_RGB8_texture GLEW_GET_VAR(GL_OES_compressed_ETC1_RGB8_texture) +#define GLEW_OES_depth24 GLEW_GET_VAR(GL_OES_depth24) +#define GLEW_OES_depth32 GLEW_GET_VAR(GL_OES_depth32) +#define GLEW_OES_depth_texture GLEW_GET_VAR(GL_OES_depth_texture) +#define GLEW_OES_depth_texture_cube_map GLEW_GET_VAR(GL_OES_depth_texture_cube_map) +#define GLEW_OES_draw_texture GLEW_GET_VAR(GL_OES_draw_texture) +#define GLEW_OES_element_index_uint GLEW_GET_VAR(GL_OES_element_index_uint) +#define GLEW_OES_extended_matrix_palette GLEW_GET_VAR(GL_OES_extended_matrix_palette) +#define GLEW_OES_fbo_render_mipmap GLEW_GET_VAR(GL_OES_fbo_render_mipmap) +#define GLEW_OES_fragment_precision_high GLEW_GET_VAR(GL_OES_fragment_precision_high) +#define GLEW_OES_framebuffer_object GLEW_GET_VAR(GL_OES_framebuffer_object) +#define GLEW_OES_get_program_binary GLEW_GET_VAR(GL_OES_get_program_binary) +#define GLEW_OES_mapbuffer GLEW_GET_VAR(GL_OES_mapbuffer) +#define GLEW_OES_matrix_get GLEW_GET_VAR(GL_OES_matrix_get) +#define GLEW_OES_matrix_palette GLEW_GET_VAR(GL_OES_matrix_palette) +#define GLEW_OES_packed_depth_stencil GLEW_GET_VAR(GL_OES_packed_depth_stencil) +#define GLEW_OES_point_size_array GLEW_GET_VAR(GL_OES_point_size_array) +#define GLEW_OES_point_sprite GLEW_GET_VAR(GL_OES_point_sprite) +#define GLEW_OES_required_internalformat GLEW_GET_VAR(GL_OES_required_internalformat) +#define GLEW_OES_rgb8_rgba8 GLEW_GET_VAR(GL_OES_rgb8_rgba8) +#define GLEW_OES_standard_derivatives GLEW_GET_VAR(GL_OES_standard_derivatives) +#define GLEW_OES_stencil1 GLEW_GET_VAR(GL_OES_stencil1) +#define GLEW_OES_stencil4 GLEW_GET_VAR(GL_OES_stencil4) +#define GLEW_OES_stencil8 GLEW_GET_VAR(GL_OES_stencil8) +#define GLEW_OES_surfaceless_context GLEW_GET_VAR(GL_OES_surfaceless_context) +#define GLEW_OES_texture_3D GLEW_GET_VAR(GL_OES_texture_3D) +#define GLEW_OES_texture_cube_map GLEW_GET_VAR(GL_OES_texture_cube_map) +#define GLEW_OES_texture_env_crossbar GLEW_GET_VAR(GL_OES_texture_env_crossbar) +#define GLEW_OES_texture_mirrored_repeat GLEW_GET_VAR(GL_OES_texture_mirrored_repeat) +#define GLEW_OES_texture_npot GLEW_GET_VAR(GL_OES_texture_npot) +#define GLEW_OES_vertex_array_object GLEW_GET_VAR(GL_OES_vertex_array_object) +#define GLEW_OES_vertex_half_float GLEW_GET_VAR(GL_OES_vertex_half_float) +#define GLEW_OES_vertex_type_10_10_10_2 GLEW_GET_VAR(GL_OES_vertex_type_10_10_10_2) + +/* some of the missing constants in SDL_opengl.h + * XXX: Most likely doesn't have all. */ + +#ifndef GL_KHR_debug +#define GL_KHR_debug 1 + +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 +#define GL_DEBUG_SOURCE_API 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION 0x824A +#define GL_DEBUG_SOURCE_OTHER 0x824B +#define GL_DEBUG_TYPE_ERROR 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define GL_DEBUG_TYPE_OTHER 0x8251 +#define GL_DEBUG_TYPE_MARKER 0x8268 +#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP 0x826A +#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C +#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D +#define GL_BUFFER 0x82E0 +#define GL_SHADER 0x82E1 +#define GL_PROGRAM 0x82E2 +#define GL_QUERY 0x82E3 +#define GL_PROGRAM_PIPELINE 0x82E4 +#define GL_SAMPLER 0x82E6 +#define GL_DISPLAY_LIST 0x82E7 +#define GL_MAX_LABEL_LENGTH 0x82E8 +#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES 0x9145 +#define GL_DEBUG_SEVERITY_HIGH 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define GL_DEBUG_SEVERITY_LOW 0x9148 +#define GL_DEBUG_OUTPUT 0x92E0 + +#endif /* GL_KHR_debug */ + +#ifndef GL_ARB_shader_storage_buffer_object +#define GL_ARB_shader_storage_buffer_object 1 + +#define GL_SHADER_STORAGE_BARRIER_BIT 0x2000 +#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 +#define GL_SHADER_STORAGE_BUFFER 0x90D2 +#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 +#define GL_SHADER_STORAGE_BUFFER_START 0x90D4 +#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 +#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 +#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7 +#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8 +#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9 +#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA +#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB +#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC +#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD +#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE +#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF + +#endif /* GL_ARB_shader_storage_buffer_object */ + +#ifndef GL_ARB_shader_atomic_counters +#define GL_ARB_shader_atomic_counters 1 + +#define GL_ATOMIC_COUNTER_BUFFER 0x92C0 +#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 +#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 +#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 +#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 +#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 +#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB +#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE +#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF +#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 +#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 +#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 +#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 +#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 +#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 +#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 +#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 +#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA +#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB +#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC + +#endif /* GL_ARB_shader_atomic_counters */ + +#ifndef GL_ARB_shader_image_load_store +#define GL_ARB_shader_image_load_store 1 + +#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 +#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 +#define GL_UNIFORM_BARRIER_BIT 0x00000004 +#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 +#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 +#define GL_COMMAND_BARRIER_BIT 0x00000040 +#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 +#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 +#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 +#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 +#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 +#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 +#define GL_MAX_IMAGE_UNITS 0x8F38 +#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 +#define GL_IMAGE_BINDING_NAME 0x8F3A +#define GL_IMAGE_BINDING_LEVEL 0x8F3B +#define GL_IMAGE_BINDING_LAYERED 0x8F3C +#define GL_IMAGE_BINDING_LAYER 0x8F3D +#define GL_IMAGE_BINDING_ACCESS 0x8F3E +#define GL_IMAGE_1D 0x904C +#define GL_IMAGE_2D 0x904D +#define GL_IMAGE_3D 0x904E +#define GL_IMAGE_2D_RECT 0x904F +#define GL_IMAGE_CUBE 0x9050 +#define GL_IMAGE_BUFFER 0x9051 +#define GL_IMAGE_1D_ARRAY 0x9052 +#define GL_IMAGE_2D_ARRAY 0x9053 +#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 +#define GL_IMAGE_2D_MULTISAMPLE 0x9055 +#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 +#define GL_INT_IMAGE_1D 0x9057 +#define GL_INT_IMAGE_2D 0x9058 +#define GL_INT_IMAGE_3D 0x9059 +#define GL_INT_IMAGE_2D_RECT 0x905A +#define GL_INT_IMAGE_CUBE 0x905B +#define GL_INT_IMAGE_BUFFER 0x905C +#define GL_INT_IMAGE_1D_ARRAY 0x905D +#define GL_INT_IMAGE_2D_ARRAY 0x905E +#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F +#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 +#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 +#define GL_UNSIGNED_INT_IMAGE_1D 0x9062 +#define GL_UNSIGNED_INT_IMAGE_2D 0x9063 +#define GL_UNSIGNED_INT_IMAGE_3D 0x9064 +#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 +#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 +#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 +#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 +#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 +#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C +#define GL_MAX_IMAGE_SAMPLES 0x906D +#define GL_IMAGE_BINDING_FORMAT 0x906E +#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 +#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 +#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 +#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA +#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB +#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC +#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD +#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE +#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF +#define GL_ALL_BARRIER_BITS 0xFFFFFFFF + +#endif /* GL_ARB_shader_image_load_store */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* API */ +#ifdef GLEW_MX + +#define glewContextInit(x) glewInit() +#define glewContextIsSupported(x, y) glewIsSupported(y) + +#endif /* GLEW_MX */ + +GLenum glewInit (void); +GLboolean glewIsSupported (const char *name); +#define glewIsExtensionSupported(x) glewIsSupported(x) + +//GLboolean glewExperimental; +static GLboolean glewExperimental; // XXX Emscripten Added 'static' to work around a linkage issue. See https://github.com/kripken/emscripten/issues/2025 + +GLboolean glewGetExtension (const char *name); +const GLubyte * glewGetErrorString (GLenum error); +const GLubyte * glewGetString (GLenum name); + +#ifdef __cplusplus +} +#endif + +#endif /* __glew_h__ */ diff --git a/system/include/libcxx/exception b/system/include/libcxx/exception index ddd75bd4..cad802e0 100644 --- a/system/include/libcxx/exception +++ b/system/include/libcxx/exception @@ -91,8 +91,8 @@ class _LIBCPP_EXCEPTION_ABI exception { public: _LIBCPP_INLINE_VISIBILITY exception() _NOEXCEPT {} - virtual ~exception() _NOEXCEPT {} // XXX EMSCRIPTEN - implement in header - virtual const char* what() const _NOEXCEPT { return "std::exception"; } // XXX EMSCRIPTEN - implement in header + virtual ~exception() _NOEXCEPT; + virtual const char* what() const _NOEXCEPT; }; class _LIBCPP_EXCEPTION_ABI bad_exception diff --git a/system/lib/libc.symbols b/system/lib/libc.symbols index 04fb40d6..6f80ef90 100644 --- a/system/lib/libc.symbols +++ b/system/lib/libc.symbols @@ -41,32 +41,18 @@ W _ZnwjRKSt9nothrow_t T __floatscan T __overflow - T __seek_on_exit T __shgetc T __shlim W __strtod_l W __strtof_l W __strtold_l T __toread - W __towrite_used + T __towrite T __uflow - T _err - T _errx - T _verr - T _verrx - T _vwarn - T _vwarnx - T _warn - T _warnx T atof W bulk_free W calloc - W err - W errx W free - T getopt - T getopt_long - T getopt_long_only W independent_calloc W independent_comalloc W mallinfo @@ -80,11 +66,6 @@ W malloc_usable_size W mallopt W memalign - C optarg - D opterr - D optind - D optopt - C optreset W posix_memalign W pvalloc W realloc @@ -92,15 +73,9 @@ T scalbn T scalbnl T strtod - W strtod_l + T strtod_l T strtof - W strtof_l + T strtof_l T strtold - W strtold_l + T strtold_l W valloc - W verr - W verrx - W vwarn - W vwarnx - W warn - W warnx diff --git a/system/lib/libc/gen/err.c b/system/lib/libc/gen/err.c deleted file mode 100644 index 218a3bfc..00000000 --- a/system/lib/libc/gen/err.c +++ /dev/null @@ -1,49 +0,0 @@ -/* $OpenBSD: err.c,v 1.11 2012/12/05 23:19:59 deraadt Exp $ */ -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <err.h> -#include <stdarg.h> - -#define __dead __attribute__((__noreturn__)) - -/* PRINTFLIKE2 */ -__dead void -_err(int eval, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - _verr(eval, fmt, ap); - va_end(ap); -} - -/* PRINTFLIKE2 */ -__dead void -err(int eval, const char *fmt, ...) __attribute__((weak, alias("_err"))); diff --git a/system/lib/libc/gen/errx.c b/system/lib/libc/gen/errx.c deleted file mode 100644 index a16643c7..00000000 --- a/system/lib/libc/gen/errx.c +++ /dev/null @@ -1,49 +0,0 @@ -/* $OpenBSD: errx.c,v 1.10 2012/12/05 23:19:59 deraadt Exp $ */ -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <err.h> -#include <stdarg.h> - -#define __dead __attribute__((__noreturn__)) - -/* PRINTFLIKE2 */ -__dead void -_errx(int eval, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - _verrx(eval, fmt, ap); - va_end(ap); -} - -/* PRINTFLIKE2 */ -__dead void -errx(int eval, const char *fmt, ...) __attribute__((weak, alias("_errx"))); diff --git a/system/lib/libc/gen/verr.c b/system/lib/libc/gen/verr.c deleted file mode 100644 index 90f5870f..00000000 --- a/system/lib/libc/gen/verr.c +++ /dev/null @@ -1,58 +0,0 @@ -/* $OpenBSD: verr.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */ -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <err.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> - -extern char *__progname; /* Program name, from crt0. */ - -#define __dead __attribute__((__noreturn__)) - -__dead void -_verr(int eval, const char *fmt, va_list ap) -{ - int sverrno; - - sverrno = errno; - (void)fprintf(stderr, "%s: ", __progname); - if (fmt != NULL) { - (void)vfprintf(stderr, fmt, ap); - (void)fprintf(stderr, ": "); - } - (void)fprintf(stderr, "%s\n", strerror(sverrno)); - exit(eval); -} - -__dead void -verr(int eval, const char *fmt, va_list ap) __attribute__((weak, alias("_verr"))); diff --git a/system/lib/libc/gen/verrx.c b/system/lib/libc/gen/verrx.c deleted file mode 100644 index b712c65c..00000000 --- a/system/lib/libc/gen/verrx.c +++ /dev/null @@ -1,51 +0,0 @@ -/* $OpenBSD: verrx.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */ -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <err.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> - -extern char *__progname; /* Program name, from crt0. */ - -#define __dead __attribute__((__noreturn__)) - -__dead void -_verrx(int eval, const char *fmt, va_list ap) -{ - (void)fprintf(stderr, "%s: ", __progname); - if (fmt != NULL) - (void)vfprintf(stderr, fmt, ap); - (void)fprintf(stderr, "\n"); - exit(eval); -} - -__dead void -verrx(int eval, const char *fmt, va_list ap) __attribute__((weak, alias("_verrx"))); diff --git a/system/lib/libc/gen/vwarn.c b/system/lib/libc/gen/vwarn.c deleted file mode 100644 index 37acef35..00000000 --- a/system/lib/libc/gen/vwarn.c +++ /dev/null @@ -1,55 +0,0 @@ -/* $OpenBSD: vwarn.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */ -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <err.h> -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <stdarg.h> - -extern char *__progname; /* Program name, from crt0. */ - -void -_vwarn(const char *fmt, va_list ap) -{ - int sverrno; - - sverrno = errno; - (void)fprintf(stderr, "%s: ", __progname); - if (fmt != NULL) { - (void)vfprintf(stderr, fmt, ap); - (void)fprintf(stderr, ": "); - } - (void)fprintf(stderr, "%s\n", strerror(sverrno)); -} - -void -vwarn(const char *fmt, va_list ap) __attribute__((weak, alias("_vwarn"))); - diff --git a/system/lib/libc/gen/vwarnx.c b/system/lib/libc/gen/vwarnx.c deleted file mode 100644 index a81a5a0d..00000000 --- a/system/lib/libc/gen/vwarnx.c +++ /dev/null @@ -1,48 +0,0 @@ -/* $OpenBSD: vwarnx.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */ -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <err.h> -#include <stdio.h> -#include <stdarg.h> - -extern char *__progname; /* Program name, from crt0. */ - -void -_vwarnx(const char *fmt, va_list ap) -{ - (void)fprintf(stderr, "%s: ", __progname); - if (fmt != NULL) - (void)vfprintf(stderr, fmt, ap); - (void)fprintf(stderr, "\n"); -} - -void -vwarnx(const char *fmt, va_list ap) __attribute__((weak, alias("_vwarnx"))); - diff --git a/system/lib/libc/gen/warn.c b/system/lib/libc/gen/warn.c deleted file mode 100644 index c0dd2cd7..00000000 --- a/system/lib/libc/gen/warn.c +++ /dev/null @@ -1,49 +0,0 @@ -/* $OpenBSD: warn.c,v 1.10 2012/12/05 23:20:00 deraadt Exp $ */ -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <err.h> -#include <stdarg.h> - -#define __dead __attribute__((__noreturn__)) - -/* PRINTFLIKE1 */ -void -_warn(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - _vwarn(fmt, ap); - va_end(ap); -} - -/* PRINTFLIKE1 */ -void -warn(const char *fmt, ...) __attribute__((weak, alias("_warn"))); diff --git a/system/lib/libc/gen/warnx.c b/system/lib/libc/gen/warnx.c deleted file mode 100644 index 7909cf2c..00000000 --- a/system/lib/libc/gen/warnx.c +++ /dev/null @@ -1,49 +0,0 @@ -/* $OpenBSD: warnx.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */ -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <err.h> -#include <stdarg.h> - -#define __dead __attribute__((__noreturn__)) - -/* PRINTFLIKE1 */ -void -_warnx(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - _vwarnx(fmt, ap); - va_end(ap); -} - -/* PRINTFLIKE1 */ -void -warnx(const char *fmt, ...) __attribute__((weak, alias("_warnx"))); diff --git a/system/lib/libc/musl/readme.txt b/system/lib/libc/musl/readme.txt index 5e6f8389..9b9b6ad2 100644 --- a/system/lib/libc/musl/readme.txt +++ b/system/lib/libc/musl/readme.txt @@ -9,4 +9,6 @@ Differences from upstream musl include: * We flag __assert_fail as _Noreturn. * Disable FLOCK, FUNLOCK and FFINALLOCK * Simplify fputwc to not rely on musl stream internals - +* signgam is no longer a weak alias of __signgam. +* __toread and __towrite have had shutdown functionality removed. +* Expand aliases for strto*_l() to short functions to remove warnings about incompatible pointer types. diff --git a/system/lib/libc/musl/src/legacy/err.c b/system/lib/libc/musl/src/legacy/err.c new file mode 100644 index 00000000..0d6ab524 --- /dev/null +++ b/system/lib/libc/musl/src/legacy/err.c @@ -0,0 +1,67 @@ +#include <err.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> + +extern char *__progname; + +void vwarn(const char *fmt, va_list ap) +{ + fprintf (stderr, "%s: ", __progname); + if (fmt) { + vfprintf(stderr, fmt, ap); + fputs (": ", stderr); + } + perror(0); +} + +void vwarnx(const char *fmt, va_list ap) +{ + fprintf (stderr, "%s: ", __progname); + if (fmt) vfprintf(stderr, fmt, ap); + putc('\n', stderr); +} + +_Noreturn void verr(int status, const char *fmt, va_list ap) +{ + vwarn(fmt, ap); + exit(status); +} + +_Noreturn void verrx(int status, const char *fmt, va_list ap) +{ + vwarnx(fmt, ap); + exit(status); +} + +void warn(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarn(fmt, ap); + va_end(ap); +} + +void warnx(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarnx(fmt, ap); + va_end(ap); +} + +_Noreturn void err(int status, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verr(status, fmt, ap); + va_end(ap); +} + +_Noreturn void errx(int status, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verrx(status, fmt, ap); + va_end(ap); +} diff --git a/system/lib/libc/musl/src/math/__cos.c b/system/lib/libc/musl/src/math/__cos.c new file mode 100644 index 00000000..46cefb38 --- /dev/null +++ b/system/lib/libc/musl/src/math/__cos.c @@ -0,0 +1,71 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_cos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * __cos( x, y ) + * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * + * Algorithm + * 1. Since cos(-x) = cos(x), we need only to consider positive x. + * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. + * 3. cos(x) is approximated by a polynomial of degree 14 on + * [0,pi/4] + * 4 14 + * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x + * where the remez error is + * + * | 2 4 6 8 10 12 14 | -58 + * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 + * | | + * + * 4 6 8 10 12 14 + * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then + * cos(x) ~ 1 - x*x/2 + r + * since cos(x+y) ~ cos(x) - sin(x)*y + * ~ cos(x) - x*y, + * a correction term is necessary in cos(x) and hence + * cos(x+y) = 1 - (x*x/2 - (r - x*y)) + * For better accuracy, rearrange to + * cos(x+y) ~ w + (tmp + (r-x*y)) + * where w = 1 - x*x/2 and tmp is a tiny correction term + * (1 - x*x/2 == w + tmp exactly in infinite precision). + * The exactness of w + tmp in infinite precision depends on w + * and tmp having the same precision as x. If they have extra + * precision due to compiler bugs, then the extra precision is + * only good provided it is retained in all terms of the final + * expression for cos(). Retention happens in all cases tested + * under FreeBSD, so don't pessimize things by forcibly clipping + * any extra precision in w. + */ + +#include "libm.h" + +static const double +C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */ +C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */ +C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */ +C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */ +C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */ +C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +double __cos(double x, double y) +{ + double_t hz,z,r,w; + + z = x*x; + w = z*z; + r = z*(C1+z*(C2+z*C3)) + w*w*(C4+z*(C5+z*C6)); + hz = 0.5*z; + w = 1.0-hz; + return w + (((1.0-w)-hz) + (z*r-x*y)); +} diff --git a/system/lib/libc/musl/src/math/__sin.c b/system/lib/libc/musl/src/math/__sin.c new file mode 100644 index 00000000..40309496 --- /dev/null +++ b/system/lib/libc/musl/src/math/__sin.c @@ -0,0 +1,64 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* __sin( x, y, iy) + * kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input iy indicates whether y is 0. (if iy=0, y assume to be 0). + * + * Algorithm + * 1. Since sin(-x) = -sin(x), we need only to consider positive x. + * 2. Callers must return sin(-0) = -0 without calling here since our + * odd polynomial is not evaluated in a way that preserves -0. + * Callers may do the optimization sin(x) ~ x for tiny x. + * 3. sin(x) is approximated by a polynomial of degree 13 on + * [0,pi/4] + * 3 13 + * sin(x) ~ x + S1*x + ... + S6*x + * where + * + * |sin(x) 2 4 6 8 10 12 | -58 + * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 + * | x | + * + * 4. sin(x+y) = sin(x) + sin'(x')*y + * ~ sin(x) + (1-x*x/2)*y + * For better accuracy, let + * 3 2 2 2 2 + * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) + * then 3 2 + * sin(x) = x + (S1*x + (x *(r-y/2)+y)) + */ + +#include "libm.h" + +static const double +S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */ +S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */ +S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */ +S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */ +S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */ +S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +double __sin(double x, double y, int iy) +{ + double_t z,r,v,w; + + z = x*x; + w = z*z; + r = S2 + z*(S3 + z*S4) + z*w*(S5 + z*S6); + v = z*x; + if (iy == 0) + return x + v*(S1 + z*r); + else + return x - ((z*(0.5*y - v*r) - y) - v*S1); +} diff --git a/system/lib/libc/musl/src/misc/getopt.c b/system/lib/libc/musl/src/misc/getopt.c new file mode 100644 index 00000000..f1a1639c --- /dev/null +++ b/system/lib/libc/musl/src/misc/getopt.c @@ -0,0 +1,74 @@ +#include <unistd.h> +#include <wchar.h> +#include <string.h> +#include <limits.h> +#include <stdlib.h> +#include "libc.h" + +char *optarg; +int optind=1, opterr=1, optopt, __optpos, __optreset=0; + +#define optpos __optpos +weak_alias(__optreset, optreset); + +int getopt(int argc, char * const argv[], const char *optstring) +{ + int i; + wchar_t c, d; + int k, l; + char *optchar; + + if (!optind || __optreset) { + __optreset = 0; + __optpos = 0; + optind = 1; + } + + if (optind >= argc || !argv[optind] || argv[optind][0] != '-' || !argv[optind][1]) + return -1; + if (argv[optind][1] == '-' && !argv[optind][2]) + return optind++, -1; + + if (!optpos) optpos++; + if ((k = mbtowc(&c, argv[optind]+optpos, MB_LEN_MAX)) < 0) { + k = 1; + c = 0xfffd; /* replacement char */ + } + optchar = argv[optind]+optpos; + optopt = c; + optpos += k; + + if (!argv[optind][optpos]) { + optind++; + optpos = 0; + } + + for (i=0; (l = mbtowc(&d, optstring+i, MB_LEN_MAX)) && d!=c; i+=l>0?l:1); + + if (d != c) { + if (optstring[0] != ':' && opterr) { + write(2, argv[0], strlen(argv[0])); + write(2, ": illegal option: ", 18); + write(2, optchar, k); + write(2, "\n", 1); + } + return '?'; + } + if (optstring[i+1] == ':') { + if (optind >= argc) { + if (optstring[0] == ':') return ':'; + if (opterr) { + write(2, argv[0], strlen(argv[0])); + write(2, ": option requires an argument: ", 31); + write(2, optchar, k); + write(2, "\n", 1); + } + return '?'; + } + optarg = argv[optind++] + optpos; + optpos = 0; + } + return c; +} + +weak_alias(getopt, __posix_getopt); diff --git a/system/lib/libc/musl/src/misc/getopt_long.c b/system/lib/libc/musl/src/misc/getopt_long.c new file mode 100644 index 00000000..4ef5a5c7 --- /dev/null +++ b/system/lib/libc/musl/src/misc/getopt_long.c @@ -0,0 +1,59 @@ +#define _GNU_SOURCE +#include <stddef.h> +#include <getopt.h> +#include <stdio.h> + +extern int __optpos, __optreset; + +static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly) +{ + if (!optind || __optreset) { + __optreset = 0; + __optpos = 0; + optind = 1; + } + if (optind >= argc || !argv[optind] || argv[optind][0] != '-') return -1; + if ((longonly && argv[optind][1]) || + (argv[optind][1] == '-' && argv[optind][2])) + { + int i; + for (i=0; longopts[i].name; i++) { + const char *name = longopts[i].name; + char *opt = argv[optind]+1; + if (*opt == '-') opt++; + for (; *name && *name == *opt; name++, opt++); + if (*name || (*opt && *opt != '=')) continue; + if (*opt == '=') { + if (!longopts[i].has_arg) continue; + optarg = opt+1; + } else { + if (longopts[i].has_arg == required_argument) { + if (!(optarg = argv[++optind])) + return ':'; + } else optarg = NULL; + } + optind++; + if (idx) *idx = i; + if (longopts[i].flag) { + *longopts[i].flag = longopts[i].val; + return 0; + } + return longopts[i].val; + } + if (argv[optind][1] == '-') { + optind++; + return '?'; + } + } + return getopt(argc, argv, optstring); +} + +int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx) +{ + return __getopt_long(argc, argv, optstring, longopts, idx, 0); +} + +int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx) +{ + return __getopt_long(argc, argv, optstring, longopts, idx, 1); +} diff --git a/system/lib/libc/musl/src/regex/fnmatch.c b/system/lib/libc/musl/src/regex/fnmatch.c new file mode 100644 index 00000000..ffd3ea0d --- /dev/null +++ b/system/lib/libc/musl/src/regex/fnmatch.c @@ -0,0 +1,299 @@ +/* + * An implementation of what I call the "Sea of Stars" algorithm for + * POSIX fnmatch(). The basic idea is that we factor the pattern into + * a head component (which we match first and can reject without ever + * measuring the length of the string), an optional tail component + * (which only exists if the pattern contains at least one star), and + * an optional "sea of stars", a set of star-separated components + * between the head and tail. After the head and tail matches have + * been removed from the input string, the components in the "sea of + * stars" are matched sequentially by searching for their first + * occurrence past the end of the previous match. + * + * - Rich Felker, April 2012 + */ + +#include <string.h> +#include <fnmatch.h> +#include <stdlib.h> +#include <wchar.h> +#include <wctype.h> + +#define END -1 +#define UNMATCHABLE -2 +#define BRACKET -3 +#define QUESTION -4 +#define STAR -5 + +static int str_next(const char *str, size_t n, size_t *step) +{ + if (!n) { + *step = 0; + return 0; + } + if (str[0] >= 128U) { + wchar_t wc; + int k = mbtowc(&wc, str, n); + if (k<0) { + *step = 1; + return -1; + } + *step = k; + return wc; + } + *step = 1; + return str[0]; +} + +static int pat_next(const char *pat, size_t m, size_t *step, int flags) +{ + int esc = 0; + if (!m || !*pat) { + *step = 0; + return END; + } + *step = 1; + if (pat[0]=='\\' && !(flags & FNM_NOESCAPE)) { + *step = 2; + pat++; + esc = 1; + goto escaped; + } + if (pat[0]=='[') { + size_t k = 1; + if (k<m) if (pat[k] == '^' || pat[k] == '!') k++; + if (k<m) if (pat[k] == ']') k++; + for (; k<m && pat[k] && pat[k]!=']'; k++) { + if (k+1<m && pat[k+1] && pat[k]=='[' && (pat[k+1]==':' || pat[k+1]=='.' || pat[k+1]=='=')) { + int z = pat[k+1]; + k+=2; + if (k<m && pat[k]) k++; + while (k<m && pat[k] && (pat[k-1]!=z || pat[k]!=']')) k++; + if (k==m || !pat[k]) break; + } + } + if (k==m || !pat[k]) { + *step = 1; + return '['; + } + *step = k+1; + return BRACKET; + } + if (pat[0] == '*') + return STAR; + if (pat[0] == '?') + return QUESTION; +escaped: + if (pat[0] >= 128U) { + wchar_t wc; + int k = mbtowc(&wc, pat, m); + if (k<0) { + *step = 0; + return UNMATCHABLE; + } + *step = k + esc; + return wc; + } + return pat[0]; +} + +static int match_bracket(const char *p, int k) +{ + wchar_t wc; + int inv = 0; + p++; + if (*p=='^' || *p=='!') { + inv = 1; + p++; + } + if (*p==']') { + if (k==']') return !inv; + p++; + } else if (*p=='-') { + if (k=='-') return !inv; + p++; + } + wc = p[-1]; + for (; *p != ']'; p++) { + if (p[0]=='-' && p[1]!=']') { + wchar_t wc2; + int l = mbtowc(&wc2, p+1, 4); + if (l < 0) return 0; + if (wc<=wc2 && (unsigned)k-wc <= wc2-wc) return !inv; + p += l-1; + continue; + } + if (p[0]=='[' && (p[1]==':' || p[1]=='.' || p[1]=='=')) { + const char *p0 = p+2; + int z = p[1]; + p+=3; + while (p[-1]!=z || p[0]!=']') p++; + if (z == ':' && p-1-p0 < 16) { + char buf[16]; + memcpy(buf, p0, p-1-p0); + buf[p-1-p0] = 0; + if (iswctype(k, wctype(buf))) return !inv; + } + continue; + } + if (*p < 128U) { + wc = (unsigned char)*p; + } else { + int l = mbtowc(&wc, p, 4); + if (l < 0) return 0; + p += l-1; + } + if (wc==k) return !inv; + } + return inv; +} + +static int fnmatch_internal(const char *pat, size_t m, const char *str, size_t n, int flags) +{ + const char *p, *ptail, *endpat; + const char *s, *stail, *endstr; + size_t pinc, sinc, tailcnt=0; + int c, k; + + if (flags & FNM_PERIOD) { + if (*str == '.' && *pat != '.') + return FNM_NOMATCH; + } + for (;;) { + switch ((c = pat_next(pat, m, &pinc, flags))) { + case UNMATCHABLE: + return FNM_NOMATCH; + case STAR: + pat++; + m--; + break; + default: + k = str_next(str, n, &sinc); + if (k <= 0) + return (c==END) ? 0 : FNM_NOMATCH; + str += sinc; + n -= sinc; + if (c == BRACKET) { + if (!match_bracket(pat, k)) + return FNM_NOMATCH; + } else if (c != QUESTION && k != c) { + return FNM_NOMATCH; + } + pat+=pinc; + m-=pinc; + continue; + } + break; + } + + /* Compute real pat length if it was initially unknown/-1 */ + m = strnlen(pat, m); + endpat = pat + m; + + /* Find the last * in pat and count chars needed after it */ + for (p=ptail=pat; p<endpat; p+=pinc) { + switch (pat_next(p, endpat-p, &pinc, flags)) { + case UNMATCHABLE: + return FNM_NOMATCH; + case STAR: + tailcnt=0; + ptail = p+1; + break; + default: + tailcnt++; + break; + } + } + + /* Past this point we need not check for UNMATCHABLE in pat, + * because all of pat has already been parsed once. */ + + /* Compute real str length if it was initially unknown/-1 */ + n = strnlen(str, n); + endstr = str + n; + if (n < tailcnt) return FNM_NOMATCH; + + /* Find the final tailcnt chars of str, accounting for UTF-8. + * On illegal sequences we may get it wrong, but in that case + * we necessarily have a matching failure anyway. */ + for (s=endstr; s>str && tailcnt; tailcnt--) { + if (s[-1] < 128U) s--; + else while ((unsigned char)*--s-0x80U<0x40 && s>str); + } + if (tailcnt) return FNM_NOMATCH; + stail = s; + + /* Check that the pat and str tails match */ + p = ptail; + for (;;) { + c = pat_next(p, endpat-p, &pinc, flags); + p += pinc; + if ((k = str_next(s, endstr-s, &sinc)) <= 0) { + if (c != END) return FNM_NOMATCH; + break; + } + s += sinc; + if (c == BRACKET) { + if (!match_bracket(p-pinc, k)) + return FNM_NOMATCH; + } else if (c != QUESTION && k != c) { + return FNM_NOMATCH; + } + } + + /* We're all done with the tails now, so throw them out */ + endstr = stail; + endpat = ptail; + + /* Match pattern components until there are none left */ + while (pat<endpat) { + p = pat; + s = str; + for (;;) { + c = pat_next(p, endpat-p, &pinc, flags); + p += pinc; + /* Encountering * completes/commits a component */ + if (c == STAR) { + pat = p; + str = s; + break; + } + k = str_next(s, endstr-s, &sinc); + if (!k) + return FNM_NOMATCH; + if (c == BRACKET) { + if (!match_bracket(p-pinc, k)) + break; + } else if (c != QUESTION && k != c) { + break; + } + s += sinc; + } + if (c == STAR) continue; + /* If we failed, advance str, by 1 char if it's a valid + * char, or past all invalid bytes otherwise. */ + k = str_next(str, endstr-str, &sinc); + if (k > 0) str += sinc; + else for (str++; str_next(str, endstr-str, &sinc)<0; str++); + } + + return 0; +} + +int fnmatch(const char *pat, const char *str, int flags) +{ + const char *s, *p; + size_t inc; + int c; + if (flags & FNM_PATHNAME) for (;;) { + for (s=str; *s && *s!='/'; s++); + for (p=pat; (c=pat_next(p, -1, &inc, flags))!=END && c!='/'; p+=inc); + if (*s && *p!=*s) return FNM_NOMATCH; + if (fnmatch_internal(pat, p-pat, str, s-str, flags)) + return FNM_NOMATCH; + if (!*s && c==END) return 0; + str = s+1; + pat = p+1; + } + return fnmatch_internal(pat, -1, str, -1, flags); +} diff --git a/system/lib/libc/musl/src/stdio/__toread.c b/system/lib/libc/musl/src/stdio/__toread.c index 2e804f64..f00cc467 100644 --- a/system/lib/libc/musl/src/stdio/__toread.c +++ b/system/lib/libc/musl/src/stdio/__toread.c @@ -12,13 +12,3 @@ int __toread(FILE *f) f->rpos = f->rend = f->buf; return 0; } - -static const int dummy = 0; -weak_alias(dummy, __towrite_used); - -void __stdio_exit(void); - -void __seek_on_exit() -{ - if (!__towrite_used) __stdio_exit(); -} diff --git a/system/lib/libc/musl/src/stdio/__towrite.c b/system/lib/libc/musl/src/stdio/__towrite.c new file mode 100644 index 00000000..3698d8b7 --- /dev/null +++ b/system/lib/libc/musl/src/stdio/__towrite.c @@ -0,0 +1,18 @@ +#include "stdio_impl.h" + +int __towrite(FILE *f) +{ + f->mode |= f->mode-1; + if (f->flags & (F_NOWR)) { + f->flags |= F_ERR; + return EOF; + } + /* Clear read buffer (easier than summoning nasal demons) */ + f->rpos = f->rend = 0; + + /* Activate write through the buffer. */ + f->wpos = f->wbase = f->buf; + f->wend = f->buf + f->buf_size; + + return 0; +} diff --git a/system/lib/libc/musl/src/stdio/fputwc.c b/system/lib/libc/musl/src/stdio/fputwc.c index 11db2804..603fa615 100644 --- a/system/lib/libc/musl/src/stdio/fputwc.c +++ b/system/lib/libc/musl/src/stdio/fputwc.c @@ -8,23 +8,37 @@ wint_t __fputwc_unlocked(wchar_t c, FILE *f) char mbc[MB_LEN_MAX]; int l; +#if 0 // XXX EMSCRIPTEN f->mode |= f->mode+1; if (isascii(c)) { -#if 0 // XXX EMSCRIPTEN c = putc_unlocked(c, f); } else if (f->wpos + MB_LEN_MAX < f->wend) { l = wctomb((void *)f->wpos, c); if (l < 0) c = WEOF; else f->wpos += l; -#else - c = fputc(c, f); -#endif } else { l = wctomb(mbc, c); if (l < 0 || __fwritex((void *)mbc, l, f) < l) c = WEOF; } return c; +#else + if (isascii(c)) { + c = fputc(c, f); + } else { + l = wctomb(mbc, c); + if (l < 0) c = WEOF; + else { + for (int i = 0; i < l; i++) { + if (fputc(mbc[i], f) == EOF) { + c = WEOF; + break; + } + } + } + } +#endif + return c; } wint_t fputwc(wchar_t c, FILE *f) diff --git a/system/lib/libc/musl/src/stdio/fputws.c b/system/lib/libc/musl/src/stdio/fputws.c new file mode 100644 index 00000000..70e004c9 --- /dev/null +++ b/system/lib/libc/musl/src/stdio/fputws.c @@ -0,0 +1,30 @@ +#include "stdio_impl.h" +#include <wchar.h> + +int fputws(const wchar_t *restrict ws, FILE *restrict f) +{ + unsigned char buf[BUFSIZ]; + size_t l=0; + + FLOCK(f); + +#if 0 // XXX EMSCRIPTEN + f->mode |= f->mode+1; +#endif + + while (ws && (l = wcsrtombs((void *)buf, (void*)&ws, sizeof buf, 0))+1 > 1) +#if 0 // XXX EMSCRIPTEN + if (__fwritex(buf, l, f) < l) { +#else + if (fwrite(buf, 1, l, f) < l) { +#endif + FUNLOCK(f); + return -1; + } + + FUNLOCK(f); + + return l; /* 0 or -1 */ +} + +weak_alias(fputws, fputws_unlocked); diff --git a/system/lib/libc/musl/src/stdio/vswprintf.c b/system/lib/libc/musl/src/stdio/vswprintf.c index 7d237bae..e906f7ae 100644 --- a/system/lib/libc/musl/src/stdio/vswprintf.c +++ b/system/lib/libc/musl/src/stdio/vswprintf.c @@ -29,6 +29,7 @@ static size_t sw_write(FILE *f, const unsigned char *s, size_t l) int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, va_list ap) { +#if 0 // XXX EMSCRIPTEN int r; FILE f; unsigned char buf[256]; @@ -50,4 +51,20 @@ int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, va_lis r = vfwprintf(&f, fmt, ap); sw_write(&f, 0, 0); return r>=n ? -1 : r; +#else + // XXX EMSCRIPTEN: use memfs through libc fs + // we write to a file, which is in multibyte, then we read, then expand to widechar + #define TEMPFILE "emscripten.vswprintf.temp.buffer" + FILE *f = fopen(TEMPFILE, "wb"); + int r = vfwprintf(f, fmt, ap); + fclose(f); + f = fopen(TEMPFILE, "rb"); + char buffer[r+1]; + fread(buffer, 1, r, f); + fclose(f); + remove(TEMPFILE); + buffer[r] = 0; + r = mbstowcs(s, buffer, n); + return r>=n ? -1 : r; +#endif } diff --git a/system/lib/libc/musl/src/stdlib/strtod.c b/system/lib/libc/musl/src/stdlib/strtod.c index 461dcf85..35f640da 100644 --- a/system/lib/libc/musl/src/stdlib/strtod.c +++ b/system/lib/libc/musl/src/stdlib/strtod.c @@ -32,9 +32,21 @@ long double strtold(const char *restrict s, char **restrict p) return strtox(s, p, 2); } -weak_alias(strtof, strtof_l); -weak_alias(strtod, strtod_l); -weak_alias(strtold, strtold_l); -weak_alias(strtof, __strtof_l); -weak_alias(strtod, __strtod_l); -weak_alias(strtold, __strtold_l); +float strtof_l(const char *restrict s, char **restrict p, struct __locale_struct *loc) +{ + return strtof(s, p); +} + +double strtod_l(const char *restrict s, char **restrict p, struct __locale_struct *loc) +{ + return strtod(s, p); +} + +long double strtold_l(const char *restrict s, char **restrict p, struct __locale_struct *loc) +{ + return strtold(s, p); +} + +weak_alias(strtof_l, __strtof_l); +weak_alias(strtod_l, __strtod_l); +weak_alias(strtold_l, __strtold_l); diff --git a/system/lib/libc/stdlib/getopt_long.c b/system/lib/libc/stdlib/getopt_long.c deleted file mode 100644 index e149fe0a..00000000 --- a/system/lib/libc/stdlib/getopt_long.c +++ /dev/null @@ -1,511 +0,0 @@ -/* $OpenBSD: getopt_long.c,v 1.25 2011/03/05 22:10:11 guenther Exp $ */ -/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ - -/* - * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Sponsored in part by the Defense Advanced Research Projects - * Agency (DARPA) and Air Force Research Laboratory, Air Force - * Materiel Command, USAF, under agreement number F39502-99-1-0512. - */ -/*- - * Copyright (c) 2000 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Dieter Baron and Thomas Klausner. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <err.h> -#include <errno.h> -#include <getopt.h> -#include <stdlib.h> -#include <string.h> - -int opterr = 1; /* if error message should be printed */ -int optind = 1; /* index into parent argv vector */ -int optopt = '?'; /* character checked for validity */ -int optreset; /* reset getopt */ -char *optarg; /* argument associated with option */ - -#define PRINT_ERROR ((opterr) && (*options != ':')) - -#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ -#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ -#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ - -/* return values */ -#define BADCH (int)'?' -#define BADARG ((*options == ':') ? (int)':' : (int)'?') -#define INORDER (int)1 - -#define EMSG "" - -static int getopt_internal(int, char * const *, const char *, - const struct option *, int *, int); -static int parse_long_options(char * const *, const char *, - const struct option *, int *, int); -static int gcd(int, int); -static void permute_args(int, int, int, char * const *); - -static char *place = EMSG; /* option letter processing */ - -/* XXX: set optreset to 1 rather than these two */ -static int nonopt_start = -1; /* first non option argument (for permute) */ -static int nonopt_end = -1; /* first option after non options (for permute) */ - -/* Error messages */ -static const char recargchar[] = "option requires an argument -- %c"; -static const char recargstring[] = "option requires an argument -- %s"; -static const char ambig[] = "ambiguous option -- %.*s"; -static const char noarg[] = "option doesn't take an argument -- %.*s"; -static const char illoptchar[] = "unknown option -- %c"; -static const char illoptstring[] = "unknown option -- %s"; - -/* - * Compute the greatest common divisor of a and b. - */ -static int -gcd(int a, int b) -{ - int c; - - c = a % b; - while (c != 0) { - a = b; - b = c; - c = a % b; - } - - return (b); -} - -/* - * Exchange the block from nonopt_start to nonopt_end with the block - * from nonopt_end to opt_end (keeping the same order of arguments - * in each block). - */ -static void -permute_args(int panonopt_start, int panonopt_end, int opt_end, - char * const *nargv) -{ - int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; - char *swap; - - /* - * compute lengths of blocks and number and size of cycles - */ - nnonopts = panonopt_end - panonopt_start; - nopts = opt_end - panonopt_end; - ncycle = gcd(nnonopts, nopts); - cyclelen = (opt_end - panonopt_start) / ncycle; - - for (i = 0; i < ncycle; i++) { - cstart = panonopt_end+i; - pos = cstart; - for (j = 0; j < cyclelen; j++) { - if (pos >= panonopt_end) - pos -= nnonopts; - else - pos += nopts; - swap = nargv[pos]; - /* LINTED const cast */ - ((char **) nargv)[pos] = nargv[cstart]; - /* LINTED const cast */ - ((char **)nargv)[cstart] = swap; - } - } -} - -/* - * parse_long_options -- - * Parse long options in argc/argv argument vector. - * Returns -1 if short_too is set and the option does not match long_options. - */ -static int -parse_long_options(char * const *nargv, const char *options, - const struct option *long_options, int *idx, int short_too) -{ - char *current_argv, *has_equal; - size_t current_argv_len; - int i, match; - - current_argv = place; - match = -1; - - optind++; - - if ((has_equal = strchr(current_argv, '=')) != NULL) { - /* argument found (--option=arg) */ - current_argv_len = has_equal - current_argv; - has_equal++; - } else - current_argv_len = strlen(current_argv); - - for (i = 0; long_options[i].name; i++) { - /* find matching long option */ - if (strncmp(current_argv, long_options[i].name, - current_argv_len)) - continue; - - if (strlen(long_options[i].name) == current_argv_len) { - /* exact match */ - match = i; - break; - } - /* - * If this is a known short option, don't allow - * a partial match of a single character. - */ - if (short_too && current_argv_len == 1) - continue; - - if (match == -1) /* partial match */ - match = i; - else { - /* ambiguous abbreviation */ - if (PRINT_ERROR) - warnx(ambig, (int)current_argv_len, - current_argv); - optopt = 0; - return (BADCH); - } - } - if (match != -1) { /* option found */ - if (long_options[match].has_arg == no_argument - && has_equal) { - if (PRINT_ERROR) - warnx(noarg, (int)current_argv_len, - current_argv); - /* - * XXX: GNU sets optopt to val regardless of flag - */ - if (long_options[match].flag == NULL) - optopt = long_options[match].val; - else - optopt = 0; - return (BADARG); - } - if (long_options[match].has_arg == required_argument || - long_options[match].has_arg == optional_argument) { - if (has_equal) - optarg = has_equal; - else if (long_options[match].has_arg == - required_argument) { - /* - * optional argument doesn't use next nargv - */ - optarg = nargv[optind++]; - } - } - if ((long_options[match].has_arg == required_argument) - && (optarg == NULL)) { - /* - * Missing argument; leading ':' indicates no error - * should be generated. - */ - if (PRINT_ERROR) - warnx(recargstring, - current_argv); - /* - * XXX: GNU sets optopt to val regardless of flag - */ - if (long_options[match].flag == NULL) - optopt = long_options[match].val; - else - optopt = 0; - --optind; - return (BADARG); - } - } else { /* unknown option */ - if (short_too) { - --optind; - return (-1); - } - if (PRINT_ERROR) - warnx(illoptstring, current_argv); - optopt = 0; - return (BADCH); - } - if (idx) - *idx = match; - if (long_options[match].flag) { - *long_options[match].flag = long_options[match].val; - return (0); - } else - return (long_options[match].val); -} - -/* - * getopt_internal -- - * Parse argc/argv argument vector. Called by user level routines. - */ -static int -getopt_internal(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx, int flags) -{ - char *oli; /* option letter list index */ - int optchar, short_too; - static int posixly_correct = -1; - - if (options == NULL) - return (-1); - - /* - * XXX Some GNU programs (like cvs) set optind to 0 instead of - * XXX using optreset. Work around this braindamage. - */ - if (optind == 0) - optind = optreset = 1; - - /* - * Disable GNU extensions if POSIXLY_CORRECT is set or options - * string begins with a '+'. - */ - if (posixly_correct == -1 || optreset) - posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); - if (*options == '-') - flags |= FLAG_ALLARGS; - else if (posixly_correct || *options == '+') - flags &= ~FLAG_PERMUTE; - if (*options == '+' || *options == '-') - options++; - - optarg = NULL; - if (optreset) - nonopt_start = nonopt_end = -1; -start: - if (optreset || !*place) { /* update scanning pointer */ - optreset = 0; - if (optind >= nargc) { /* end of argument vector */ - place = EMSG; - if (nonopt_end != -1) { - /* do permutation, if we have to */ - permute_args(nonopt_start, nonopt_end, - optind, nargv); - optind -= nonopt_end - nonopt_start; - } - else if (nonopt_start != -1) { - /* - * If we skipped non-options, set optind - * to the first of them. - */ - optind = nonopt_start; - } - nonopt_start = nonopt_end = -1; - return (-1); - } - if (*(place = nargv[optind]) != '-' || - (place[1] == '\0' && strchr(options, '-') == NULL)) { - place = EMSG; /* found non-option */ - if (flags & FLAG_ALLARGS) { - /* - * GNU extension: - * return non-option as argument to option 1 - */ - optarg = nargv[optind++]; - return (INORDER); - } - if (!(flags & FLAG_PERMUTE)) { - /* - * If no permutation wanted, stop parsing - * at first non-option. - */ - return (-1); - } - /* do permutation */ - if (nonopt_start == -1) - nonopt_start = optind; - else if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, - optind, nargv); - nonopt_start = optind - - (nonopt_end - nonopt_start); - nonopt_end = -1; - } - optind++; - /* process next argument */ - goto start; - } - if (nonopt_start != -1 && nonopt_end == -1) - nonopt_end = optind; - - /* - * If we have "-" do nothing, if "--" we are done. - */ - if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { - optind++; - place = EMSG; - /* - * We found an option (--), so if we skipped - * non-options, we have to permute. - */ - if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, - optind, nargv); - optind -= nonopt_end - nonopt_start; - } - nonopt_start = nonopt_end = -1; - return (-1); - } - } - - /* - * Check long options if: - * 1) we were passed some - * 2) the arg is not just "-" - * 3) either the arg starts with -- we are getopt_long_only() - */ - if (long_options != NULL && place != nargv[optind] && - (*place == '-' || (flags & FLAG_LONGONLY))) { - short_too = 0; - if (*place == '-') - place++; /* --foo long option */ - else if (*place != ':' && strchr(options, *place) != NULL) - short_too = 1; /* could be short option too */ - - optchar = parse_long_options(nargv, options, long_options, - idx, short_too); - if (optchar != -1) { - place = EMSG; - return (optchar); - } - } - - if ((optchar = (int)*place++) == (int)':' || - (optchar == (int)'-' && *place != '\0') || - (oli = strchr(options, optchar)) == NULL) { - /* - * If the user specified "-" and '-' isn't listed in - * options, return -1 (non-option) as per POSIX. - * Otherwise, it is an unknown option character (or ':'). - */ - if (optchar == (int)'-' && *place == '\0') - return (-1); - if (!*place) - ++optind; - if (PRINT_ERROR) - warnx(illoptchar, optchar); - optopt = optchar; - return (BADCH); - } - if (long_options != NULL && optchar == 'W' && oli[1] == ';') { - /* -W long-option */ - if (*place) /* no space */ - /* NOTHING */; - else if (++optind >= nargc) { /* no arg */ - place = EMSG; - if (PRINT_ERROR) - warnx(recargchar, optchar); - optopt = optchar; - return (BADARG); - } else /* white space */ - place = nargv[optind]; - optchar = parse_long_options(nargv, options, long_options, - idx, 0); - place = EMSG; - return (optchar); - } - if (*++oli != ':') { /* doesn't take argument */ - if (!*place) - ++optind; - } else { /* takes (optional) argument */ - optarg = NULL; - if (*place) /* no white space */ - optarg = place; - else if (oli[1] != ':') { /* arg not optional */ - if (++optind >= nargc) { /* no arg */ - place = EMSG; - if (PRINT_ERROR) - warnx(recargchar, optchar); - optopt = optchar; - return (BADARG); - } else - optarg = nargv[optind]; - } - place = EMSG; - ++optind; - } - /* dump back option letter */ - return (optchar); -} - -/* - * getopt -- - * Parse argc/argv argument vector. - * - * [eventually this will replace the BSD getopt] - */ -int -getopt(int nargc, char * const *nargv, const char *options) -{ - - /* - * We don't pass FLAG_PERMUTE to getopt_internal() since - * the BSD getopt(3) (unlike GNU) has never done this. - * - * Furthermore, since many privileged programs call getopt() - * before dropping privileges it makes sense to keep things - * as simple (and bug-free) as possible. - */ - return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); -} - -/* - * getopt_long -- - * Parse argc/argv argument vector. - */ -int -getopt_long(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx) -{ - - return (getopt_internal(nargc, nargv, options, long_options, idx, - FLAG_PERMUTE)); -} - -/* - * getopt_long_only -- - * Parse argc/argv argument vector. - */ -int -getopt_long_only(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx) -{ - - return (getopt_internal(nargc, nargv, options, long_options, idx, - FLAG_PERMUTE|FLAG_LONGONLY)); -} diff --git a/system/lib/libc/stdlib/strtod.c b/system/lib/libc/stdlib/strtod.c deleted file mode 100644 index 7c441247..00000000 --- a/system/lib/libc/stdlib/strtod.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * strtod.c -- - * - * Source code for the "strtod" library procedure. - * - * Copyright (c) 1988-1993 The Regents of the University of California. - * Copyright (c) 1994 Sun Microsystems, Inc. - * - * Permission to use, copy, modify, and distribute this - * software and its documentation for any purpose and without - * fee is hereby granted, provided that the above copyright - * notice appear in all copies. The University of California - * makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without - * express or implied warranty. - * - * RCS: @(#) $Id$ - * - * Taken from http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_8/missing/strtod.c - */ - -#include <stdlib.h> -#include <ctype.h> -#include <errno.h> -#include <locale.h> -extern int errno; - -#ifndef __STDC__ -# ifdef __GNUC__ -# define const __const__ -# else -# define const -# endif -#endif - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif -#ifndef NULL -#define NULL 0 -#endif - -static int maxExponent = 511; /* Largest possible base 10 exponent. Any - * exponent larger than this will already - * produce underflow or overflow, so there's - * no need to worry about additional digits. - */ -static double powersOf10[] = { /* Table giving binary powers of 10. Entry */ - 10., /* is 10^2^i. Used to convert decimal */ - 100., /* exponents into floating-point numbers. */ - 1.0e4, - 1.0e8, - 1.0e16, - 1.0e32, - 1.0e64, - 1.0e128, - 1.0e256 -}; - -/* - *---------------------------------------------------------------------- - * - * strtod -- - * - * This procedure converts a floating-point number from an ASCII - * decimal representation to internal double-precision format. - * - * Results: - * The return value is the double-precision floating-point - * representation of the characters in string. If endPtr isn't - * NULL, then *endPtr is filled in with the address of the - * next character after the last one that was part of the - * floating-point number. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -double -strtod(string, endPtr) - const char *string; /* A decimal ASCII floating-point number, - * optionally preceded by white space. - * Must have form "-I.FE-X", where I is the - * integer part of the mantissa, F is the - * fractional part of the mantissa, and X - * is the exponent. Either of the signs - * may be "+", "-", or omitted. Either I - * or F may be omitted, or both. The decimal - * point isn't necessary unless F is present. - * The "E" may actually be an "e". E and X - * may both be omitted (but not just one). - */ - char **endPtr; /* If non-NULL, store terminating character's - * address here. */ -{ - int sign, expSign = FALSE; - double fraction, dblExp, *d; - register const char *p; - register int c; - int exp = 0; /* Exponent read from "EX" field. */ - int fracExp = 0; /* Exponent that derives from the fractional - * part. Under normal circumstatnces, it is - * the negative of the number of digits in F. - * However, if I is very long, the last digits - * of I get dropped (otherwise a long I with a - * large negative exponent could cause an - * unnecessary overflow on I alone). In this - * case, fracExp is incremented one for each - * dropped digit. */ - int mantSize; /* Number of digits in mantissa. */ - int decPt; /* Number of mantissa digits BEFORE decimal - * point. */ - const char *pExp; /* Temporarily holds location of exponent - * in string. */ - - /* - * Strip off leading blanks and check for a sign. - */ - - p = string; - while (isspace(*p)) { - p += 1; - } - if (*p == '-') { - sign = TRUE; - p += 1; - } else { - if (*p == '+') { - p += 1; - } - sign = FALSE; - } - - /* - * Count the number of digits in the mantissa (including the decimal - * point), and also locate the decimal point. - */ - - decPt = -1; - for (mantSize = 0; ; mantSize += 1) - { - c = *p; - if (!isdigit(c)) { - if ((c != '.') || (decPt >= 0)) { - break; - } - decPt = mantSize; - } - p += 1; - } - - /* - * Now suck up the digits in the mantissa. Use two integers to - * collect 9 digits each (this is faster than using floating-point). - * If the mantissa has more than 18 digits, ignore the extras, since - * they can't affect the value anyway. - */ - - pExp = p; - p -= mantSize; - if (decPt < 0) { - decPt = mantSize; - } else { - mantSize -= 1; /* One of the digits was the point. */ - } - if (mantSize > 18) { - fracExp = decPt - 18; - mantSize = 18; - } else { - fracExp = decPt - mantSize; - } - if (mantSize == 0) { - fraction = 0.0; - p = string; - goto done; - } else { - int frac1, frac2; - frac1 = 0; - for ( ; mantSize > 9; mantSize -= 1) - { - c = *p; - p += 1; - if (c == '.') { - c = *p; - p += 1; - } - frac1 = 10*frac1 + (c - '0'); - } - frac2 = 0; - for (; mantSize > 0; mantSize -= 1) - { - c = *p; - p += 1; - if (c == '.') { - c = *p; - p += 1; - } - frac2 = 10*frac2 + (c - '0'); - } - fraction = (1.0e9 * frac1) + frac2; - } - - /* - * Skim off the exponent. - */ - - p = pExp; - if ((*p == 'E') || (*p == 'e')) { - p += 1; - if (*p == '-') { - expSign = TRUE; - p += 1; - } else { - if (*p == '+') { - p += 1; - } - expSign = FALSE; - } - while (isdigit(*p)) { - exp = exp * 10 + (*p - '0'); - p += 1; - } - } - if (expSign) { - exp = fracExp - exp; - } else { - exp = fracExp + exp; - } - - /* - * Generate a floating-point number that represents the exponent. - * Do this by processing the exponent one bit at a time to combine - * many powers of 2 of 10. Then combine the exponent with the - * fraction. - */ - - if (exp < 0) { - expSign = TRUE; - exp = -exp; - } else { - expSign = FALSE; - } - if (exp > maxExponent) { - exp = maxExponent; - errno = ERANGE; - } - dblExp = 1.0; - for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { - if (exp & 01) { - dblExp *= *d; - } - } - if (expSign) { - fraction /= dblExp; - } else { - fraction *= dblExp; - } - -done: - if (endPtr != NULL) { - *endPtr = (char *) p; - } - - if (sign) { - return -fraction; - } - return fraction; -} - -/* - * Implementations added for emscripten. - */ -// XXX add real support for long double -long double -strtold(const char* nptr, char **endptr) -{ - return (long double) strtod(nptr, endptr); -} - -// use stdtod to handle strtof -float -strtof(const char* nptr, char **endptr) -{ - return (float) strtod(nptr, endptr); -} - -// XXX no locale support yet -double -strtod_l(const char* nptr, char **endptr, locale_t loc) -{ - return strtod(nptr, endptr); -} -long double -strtold_l(const char* nptr, char **endptr, locale_t loc) -{ - return strtold(nptr, endptr); -} - -double atof(const char* str) -{ - return strtod(str, (char **) NULL); -} diff --git a/system/lib/libcextra.symbols b/system/lib/libcextra.symbols index c3475e1c..54176b1d 100644 --- a/system/lib/libcextra.symbols +++ b/system/lib/libcextra.symbols @@ -1,10 +1,16 @@ + T __cos T __cosdf + T __fputwc_unlocked T __intscan W __iswctype_l T __lgamma_r T __lgammaf_r T __lgammal_r T __memrchr + C __optpos + D __optreset + W __posix_getopt + T __sin T __sindf T __strchrnul T __strxfrm_l @@ -18,9 +24,16 @@ W __wctype_l T btowc T ecvt + T err + T errx T fcvt + T fputwc + W fputwc_unlocked T fwprintf T gcvt + T getopt + T getopt_long + T getopt_long_only T iconv T iconv_close T iconv_open @@ -77,6 +90,12 @@ T memmem T mempcpy W memrchr + C optarg + D opterr + D optind + C optopt + W optreset + W putwc_unlocked T regcomp T regerror T regexec @@ -105,9 +124,15 @@ T towlower_l T towupper T towupper_l + T verr + T verrx T vfwprintf T vswprintf + T vwarn + T vwarnx T vwprintf + T warn + T warnx T wcpcpy T wcpncpy T wcrtomb @@ -162,3 +187,4 @@ T wmemmove T wmemset T wprintf + T fnmatch diff --git a/tests/cases/fptosi.ll b/tests/cases/fptosi.ll new file mode 100644 index 00000000..71bc6af8 --- /dev/null +++ b/tests/cases/fptosi.ll @@ -0,0 +1,28 @@ +; ModuleID = '/dev/shm/tmp/src.cpp.o' +target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:32" +target triple = "le32-unknown-nacl" + +@.str = private unnamed_addr constant [8 x i8] c"*%.3f*\0A\00", align 1 ; [#uses=1 type=[8 x i8]*] +@.str2 = private unnamed_addr constant [6 x i8] c"*%d*\0A\00", align 1 ; [#uses=1 type=[6 x i8]*] + +; [#uses=0] +define i32 @main() { +entry: + %f = fadd float 1.000, 0.500 + %d = fadd double 3.333, 0.444 + %fd = fpext float %f to double + %call1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([8 x i8]* @.str, i32 0, i32 0), double %fd) ; [#uses=0 type=i32] + %call2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([8 x i8]* @.str, i32 0, i32 0), double %d) ; [#uses=0 type=i32] + %fs = fptosi float %f to i64 + %fu = fptoui float %f to i64 + %ds = fptosi double %d to i64 + %du = fptoui double %d to i64 + %call3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0), i64 %fs) ; [#uses=0 type=i32] + %call4 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0), i64 %fu) ; [#uses=0 type=i32] + %call5 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0), i64 %ds) ; [#uses=0 type=i32] + %call6 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0), i64 %du) ; [#uses=0 type=i32] + ret i32 1 +} + +; [#uses=1] +declare i32 @printf(i8*, ...) diff --git a/tests/cases/fptosi.txt b/tests/cases/fptosi.txt new file mode 100644 index 00000000..eea925c4 --- /dev/null +++ b/tests/cases/fptosi.txt @@ -0,0 +1,6 @@ +*1.500* +*3.777* +*1* +*1* +*3* +*3* diff --git a/tests/cases/longjmp_tiny_invoke.ll b/tests/cases/longjmp_tiny_invoke.ll index e1a72e00..6f856d49 100644 --- a/tests/cases/longjmp_tiny_invoke.ll +++ b/tests/cases/longjmp_tiny_invoke.ll @@ -9,7 +9,7 @@ target triple = "i386-pc-linux-gnu" define i32 @main() { %retval = alloca i32, align 4 store i32 0, i32* %retval - %call = invoke i32 @setjmp(i16* getelementptr inbounds ([20 x i16]* @_ZL3buf, i32 0, i32 0)) returns_twice, !dbg !20 + %call = invoke i32 @setjmp(i16* getelementptr inbounds ([20 x i16]* @_ZL3buf, i32 0, i32 0)) returns_twice to label %allgood unwind label %awful allgood: @@ -29,9 +29,13 @@ if.end: ; preds = %if.else, %if.then ret i32 0, !dbg !28 awful: + %Z = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + cleanup ret i32 1 } +declare i32 @__gxx_personality_v0(...) + declare i32 @setjmp(i16*) returns_twice declare i32 @printf(i8*, ...) diff --git a/tests/cases/longjmp_tiny_invoke_phi.ll b/tests/cases/longjmp_tiny_invoke_phi.ll index 30c43339..0df3f924 100644 --- a/tests/cases/longjmp_tiny_invoke_phi.ll +++ b/tests/cases/longjmp_tiny_invoke_phi.ll @@ -35,6 +35,8 @@ if.end: ; preds = %if.else, %if.then ret i32 0 awful: + %Z = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + cleanup ret i32 1 } @@ -44,3 +46,5 @@ declare i32 @printf(i8*, ...) declare void @longjmp(i16*, i32) +declare i32 @__gxx_personality_v0(...) + diff --git a/tests/cases/longjmp_tiny_phi.ll b/tests/cases/longjmp_tiny_phi.ll index cced7cab..21b936dd 100644 --- a/tests/cases/longjmp_tiny_phi.ll +++ b/tests/cases/longjmp_tiny_phi.ll @@ -28,7 +28,7 @@ if.else: ; preds = %entry br label %if.end if.end: ; preds = %if.else, %if.then - %aaa = phi i32 [ -1, %if.then ], [ 0, %if.else ], [ 1, %two ], [ 2, %entry ] + %aaa = phi i32 [ -1, %if.then ], [ 0, %if.else ] %call3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0), i32 %aaa), !dbg !26 ret i32 %aaa, !dbg !28 } diff --git a/tests/cases/longjmp_tiny_phi2.ll b/tests/cases/longjmp_tiny_phi2.ll index 1d7761c3..88312fc6 100644 --- a/tests/cases/longjmp_tiny_phi2.ll +++ b/tests/cases/longjmp_tiny_phi2.ll @@ -24,7 +24,7 @@ if.then: ; preds = %entry br label %if.end, !dbg !25 if.end: ; preds = %if.else, %if.then - %aaa = phi i32 [ -1, %if.then ], [ 1, %two ], [ 2, %entry ] + %aaa = phi i32 [ -1, %if.then ], [ 1, %two ] %call3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0), i32 %aaa), !dbg !26 ret i32 %aaa, !dbg !28 } diff --git a/tests/core/fnmatch.c b/tests/core/fnmatch.c new file mode 100644 index 00000000..ebdb2009 --- /dev/null +++ b/tests/core/fnmatch.c @@ -0,0 +1,79 @@ +// Begin test_fnmatch.cpp +#include <fnmatch.h> +#include <iostream> +#include <vector> +#include <string> + +using namespace std; + +class TestCase { +public: + TestCase(const string& pattern, const string& testString, int flags, int expected) : + pattern(pattern), + testString(testString), + flags(flags), + expected(expected) + {} + string pattern; + string testString; + int flags; + int expected; +}; + +int main() +{ + vector<TestCase> testCases; + + testCases.push_back(TestCase("*","anything",0,0)); + testCases.push_back(TestCase("*.txt","readme.txt",0,0)); + testCases.push_back(TestCase("*.txt","readme.info",0,FNM_NOMATCH)); + testCases.push_back(TestCase("*.t?t","readme.txt",0,0)); + testCases.push_back(TestCase("*.t?t","readme.tot",0,0)); + testCases.push_back(TestCase("*.t?t","readme.txxt",0,FNM_NOMATCH)); + testCases.push_back(TestCase("[a-g]1","c1",0,0)); + testCases.push_back(TestCase("[a-g]1","i1",0,FNM_NOMATCH)); + testCases.push_back(TestCase("[!a-g]1","i1",0,0)); + testCases.push_back(TestCase("a\\*","anything",0,FNM_NOMATCH)); + testCases.push_back(TestCase("a\\*","a*",0,0)); + testCases.push_back(TestCase("a\\*","a*",FNM_NOESCAPE,FNM_NOMATCH)); + testCases.push_back(TestCase("a\\*","a\\*",FNM_NOESCAPE,0)); + testCases.push_back(TestCase("*readme","/etc/readme",0,0)); + testCases.push_back(TestCase("*readme","/etc/readme",FNM_PATHNAME,FNM_NOMATCH)); + testCases.push_back(TestCase("/*/readme","/etc/readme",FNM_PATHNAME,0)); + testCases.push_back(TestCase("*readme","/etc/.readme",0,0)); + testCases.push_back(TestCase("*readme",".readme",FNM_PERIOD,FNM_NOMATCH)); + testCases.push_back(TestCase("*.readme","/etc/.readme",FNM_PERIOD,0)); + testCases.push_back(TestCase("*.readme","/etc/.readme",FNM_PERIOD|FNM_PATHNAME,FNM_NOMATCH)); + testCases.push_back(TestCase("/*/.readme","/etc/.readme",FNM_PERIOD|FNM_PATHNAME,0)); + testCases.push_back(TestCase("ReAdME","readme",0,FNM_NOMATCH)); + + bool pass = true; + + for (vector<TestCase>::const_iterator it = testCases.begin(); it != testCases.end(); ++it) + { + int result = fnmatch(it->pattern.c_str(), it->testString.c_str(), it->flags); + if (result == it->expected) + cout << "Pass: "; + else + { + cout << "Fail: "; + pass = false; + } + + cout << "fnmatch(" << it->pattern << ", " << it->testString << ", " + << it->flags << ") returned " << result << ", expected " + << it->expected << endl; + } + + if (pass) + { + cout << "All tests passed." << endl; + return 0; + } + else + { + cout << "Some tests failed." << endl; + return 1; + } +} + diff --git a/tests/core/fnmatch.out b/tests/core/fnmatch.out new file mode 100644 index 00000000..303f7449 --- /dev/null +++ b/tests/core/fnmatch.out @@ -0,0 +1,23 @@ +Pass: fnmatch(*, anything, 0) returned 0, expected 0 +Pass: fnmatch(*.txt, readme.txt, 0) returned 0, expected 0 +Pass: fnmatch(*.txt, readme.info, 0) returned 1, expected 1 +Pass: fnmatch(*.t?t, readme.txt, 0) returned 0, expected 0 +Pass: fnmatch(*.t?t, readme.tot, 0) returned 0, expected 0 +Pass: fnmatch(*.t?t, readme.txxt, 0) returned 1, expected 1 +Pass: fnmatch([a-g]1, c1, 0) returned 0, expected 0 +Pass: fnmatch([a-g]1, i1, 0) returned 1, expected 1 +Pass: fnmatch([!a-g]1, i1, 0) returned 0, expected 0 +Pass: fnmatch(a\*, anything, 0) returned 1, expected 1 +Pass: fnmatch(a\*, a*, 0) returned 0, expected 0 +Pass: fnmatch(a\*, a*, 2) returned 1, expected 1 +Pass: fnmatch(a\*, a\*, 2) returned 0, expected 0 +Pass: fnmatch(*readme, /etc/readme, 0) returned 0, expected 0 +Pass: fnmatch(*readme, /etc/readme, 1) returned 1, expected 1 +Pass: fnmatch(/*/readme, /etc/readme, 1) returned 0, expected 0 +Pass: fnmatch(*readme, /etc/.readme, 0) returned 0, expected 0 +Pass: fnmatch(*readme, .readme, 4) returned 1, expected 1 +Pass: fnmatch(*.readme, /etc/.readme, 4) returned 0, expected 0 +Pass: fnmatch(*.readme, /etc/.readme, 5) returned 1, expected 1 +Pass: fnmatch(/*/.readme, /etc/.readme, 5) returned 0, expected 0 +Pass: fnmatch(ReAdME, readme, 0) returned 1, expected 1 +All tests passed. diff --git a/tests/core/test_alloca.in b/tests/core/test_alloca.in index bfad3324..d115880f 100644 --- a/tests/core/test_alloca.in +++ b/tests/core/test_alloca.in @@ -1,9 +1,14 @@ #include <stdio.h> #include <stdlib.h> +#include <assert.h> -int main() { - char *pc; - pc = (char *)alloca(5); - printf("z:%d*%d*\n", pc > 0, (int)pc); +int main(int argc, char **argv) { + char *pc, *pc2; + assert(argc == 1); + pc = (char *)alloca(4+argc); + assert(((int)pc) % 4 == 0); + pc2 = (char *)alloca(4+argc); + assert(((int)pc2) % 4 == 0); + printf("z:%d*%d*%d*\n", pc > 0, (int)pc, (int)pc2); return 0; } diff --git a/tests/core/test_exception_2.in b/tests/core/test_exceptions_2.in index 2eae3198..2eae3198 100644 --- a/tests/core/test_exception_2.in +++ b/tests/core/test_exceptions_2.in diff --git a/tests/core/test_exception_2.out b/tests/core/test_exceptions_2.out index aa89c67d..aa89c67d 100644 --- a/tests/core/test_exception_2.out +++ b/tests/core/test_exceptions_2.out diff --git a/tests/core/test_multiexception.in b/tests/core/test_exceptions_multi.in index 46acbbf3..5453d11c 100644 --- a/tests/core/test_multiexception.in +++ b/tests/core/test_exceptions_multi.in @@ -22,9 +22,9 @@ void setjmp_func(jmp_state* s, int level) { s->jmp = c_jmp; setjmp_func(s, level + 1); } - catch (int catched_eid) { - printf("caught %d\n", catched_eid); - if (catched_eid == c_jmp) { + catch (int caught_eid) { + printf("caught %d\n", caught_eid); + if (caught_eid == c_jmp) { printf("setjmp exception execution path, level: %d, prev_jmp: %d\n", level, prev_jmp); if (prev_jmp != -1) { diff --git a/tests/core/test_multiexception.out b/tests/core/test_exceptions_multi.out index 33efe46e..33efe46e 100644 --- a/tests/core/test_multiexception.out +++ b/tests/core/test_exceptions_multi.out diff --git a/tests/core/test_std_exception.in b/tests/core/test_exceptions_std.in index 4b5905d8..3b9f874b 100644 --- a/tests/core/test_std_exception.in +++ b/tests/core/test_exceptions_std.in @@ -7,6 +7,7 @@ int main() { throw e; } catch (std::exception e) { + printf("what? %s\n", e.what()); printf("caught std::exception\n"); } return 0; diff --git a/tests/core/test_exceptions_std.out b/tests/core/test_exceptions_std.out new file mode 100644 index 00000000..eddab21c --- /dev/null +++ b/tests/core/test_exceptions_std.out @@ -0,0 +1,2 @@ +what? std::exception +caught std::exception diff --git a/tests/exceptions/typed.cpp b/tests/core/test_exceptions_typed.in index a2b77fee..a2b77fee 100644 --- a/tests/exceptions/typed.cpp +++ b/tests/core/test_exceptions_typed.in diff --git a/tests/exceptions/output.txt b/tests/core/test_exceptions_typed.out index 718f189a..718f189a 100644 --- a/tests/exceptions/output.txt +++ b/tests/core/test_exceptions_typed.out diff --git a/tests/core/test_white_list_exception.in b/tests/core/test_exceptions_white_list.in index 2944f9fe..2944f9fe 100644 --- a/tests/core/test_white_list_exception.in +++ b/tests/core/test_exceptions_white_list.in diff --git a/tests/core/test_white_list_exception.out b/tests/core/test_exceptions_white_list.out index 62e1a81c..62e1a81c 100644 --- a/tests/core/test_white_list_exception.out +++ b/tests/core/test_exceptions_white_list.out diff --git a/tests/core/test_inlinejs3.in b/tests/core/test_inlinejs3.in index 3e1913ff..e21ed041 100644 --- a/tests/core/test_inlinejs3.in +++ b/tests/core/test_inlinejs3.in @@ -3,7 +3,7 @@ int main(int argc, char **argv) { EM_ASM(Module.print('hello dere1')); - EM_ASM(Module.print('hello dere2');); + EM_ASM("Module.print('hello dere2');"); for (int i = 0; i < 3; i++) { EM_ASM(Module.print('hello dere3'); Module.print('hello dere' + 4);); } diff --git a/tests/core/test_nl_types.in b/tests/core/test_nl_types.in new file mode 100644 index 00000000..666920ee --- /dev/null +++ b/tests/core/test_nl_types.in @@ -0,0 +1,8 @@ +#include <nl_types.h> +#include <stdio.h> + +int main(int argc, char ** argv) { + nl_catd c = catopen("none", 0); + printf("Hello, %s.\n", catgets(c, 0, 0, "world")); + return catclose(c); +} diff --git a/tests/core/test_nl_types.out b/tests/core/test_nl_types.out new file mode 100644 index 00000000..f75ba05f --- /dev/null +++ b/tests/core/test_nl_types.out @@ -0,0 +1 @@ +Hello, world. diff --git a/tests/core/test_std_exception.out b/tests/core/test_std_exception.out deleted file mode 100644 index c1660de4..00000000 --- a/tests/core/test_std_exception.out +++ /dev/null @@ -1 +0,0 @@ -caught std::exception
\ No newline at end of file diff --git a/tests/core/test_wprintf.c b/tests/core/test_wprintf.c index e938bf69..b5f8d6ab 100644 --- a/tests/core/test_wprintf.c +++ b/tests/core/test_wprintf.c @@ -1,7 +1,44 @@ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> #include <wchar.h> -int main() +void PrintWide ( const wchar_t * format, ... ) { + wchar_t buffer[256]; + memset(buffer, 0, 256); + va_list args; + va_start ( args, format ); + wprintf(L"format starts with 0x%x\n", *(int*)format); + wprintf(L"fmt continues with 0x%x\n", *(((int*)format) + 1)); + wprintf(L"fmt continues with 0x%x\n", *(((int*)format) + 2)); + int r = vswprintf ( buffer, 256, format, args ); + wprintf(L"vswprintf told us %d\n", r); + wprintf(L"vswoutput st-rts with 0x%x\n", *(int*)buffer); + wprintf(L"vsw continues with 0x%x\n", *(((int*)buffer) + 1)); + wprintf(L"vsw continues with 0x%x\n", *(((int*)buffer) + 2)); + wprintf(buffer); + va_end ( args ); +} + +int main () +{ + FILE *f = fopen("test.dat", "wb"); + int num = fwprintf(f, L"hello %d", 5); + wprintf(L"fwprintf told us %d\n", num); + fclose(f); + f = fopen("test.dat", "rb"); + fseek(f, 0, SEEK_END); + int size = ftell(f); + fclose(f); + wprintf(L"file size is %d\n", size); + + wchar_t str[] = L"test string has %d wide characters.\n"; + wprintf(L"str starts with 0x%x\n", *(int*)str); + wprintf(L"str continues with 0x%x\n", *(((int*)str) + 1)); + wprintf(L"str continues with 0x%x\n", *(((int*)str) + 2)); + PrintWide ( str, wcslen(str) ); + wprintf (L"Characters: %lc %lc \n", L'a', 65); wprintf (L"Decimals: %d %ld\n", 1977, 650000L); wprintf (L"Preceding with blanks: %10d \n", 1977); @@ -10,6 +47,17 @@ int main() wprintf (L"floats: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416); wprintf (L"Width trick: %*d \n", 5, 10); wprintf (L"%ls \n", L"A wide string"); + + wchar_t buffer [100]; + memset(buffer, 0, sizeof(buffer)); + int cx; + cx = swprintf(buffer, 100, L"The half of %d is %d", 80, 80/2); + wprintf(L"swprintf told us %d\n", cx); + for (int i = 0; i < 10; i++) wprintf(L"pre %d\n", ((int*)buffer)[i]); + swprintf (buffer+cx, 100-cx-1, L", and the half of that is %d.\n", 80/2/2); + for (int i = 0; i < 10; i++) wprintf(L"post %d\n", ((int*)buffer)[i]); + wprintf(buffer); + return 0; } diff --git a/tests/core/test_wprintf.out b/tests/core/test_wprintf.out index f85abebb..e074743d 100644 --- a/tests/core/test_wprintf.out +++ b/tests/core/test_wprintf.out @@ -1,3 +1,16 @@ +fwprintf told us 7 +file size is 7 +str starts with 0x74 +str continues with 0x65 +str continues with 0x73 +format starts with 0x74 +fmt continues with 0x65 +fmt continues with 0x73 +vswprintf told us 36 +vswoutput st-rts with 0x74 +vsw continues with 0x65 +vsw continues with 0x73 +test string has 36 wide characters. Characters: a A Decimals: 1977 650000 Preceding with blanks: 1977 @@ -6,3 +19,25 @@ Some different radixes: 100 64 144 0x64 0144 floats: 3.14 +3e+00 3.141600E+00 Width trick: 10 A wide string +swprintf told us 20 +pre 84 +pre 104 +pre 101 +pre 32 +pre 104 +pre 97 +pre 108 +pre 102 +pre 32 +pre 111 +post 84 +post 104 +post 101 +post 32 +post 104 +post 97 +post 108 +post 102 +post 32 +post 111 +The half of 80 is 40, and the half of that is 20. diff --git a/tests/doublestart.c b/tests/doublestart.c new file mode 100644 index 00000000..533e6308 --- /dev/null +++ b/tests/doublestart.c @@ -0,0 +1,23 @@ +#include <stdio.h> +#include <emscripten.h> + +int times = 0; + +void later(void* nada) { + int result = times; + REPORT_RESULT(); +} + +void main_loop(void) { + static int cnt = 0; + if (++cnt >= 10) emscripten_cancel_main_loop(); +} + +int main(void) { + emscripten_async_call(later, NULL, 2000); + times++; + printf("This should only appear once.\n"); + emscripten_set_main_loop(main_loop, 10, 0); + return 0; +} + diff --git a/tests/glew.c b/tests/glew.c new file mode 100644 index 00000000..3bf93fd9 --- /dev/null +++ b/tests/glew.c @@ -0,0 +1,51 @@ +#include <GL/glew.h> +#include <stdio.h> +#include <assert.h> +#include <string.h> + +/* for context creation */ +#include <SDL/SDL.h> + +int main() +{ + assert(SDL_Init(SDL_INIT_VIDEO) == 0); + assert(SDL_SetVideoMode(640, 480, 16, SDL_OPENGL) != NULL); + + assert(glewInit() == GLEW_OK); + assert(glewGetString(0) == NULL); + assert(!strcmp((const char*)glewGetString(1), "1.10.0")); + assert(!strcmp((const char*)glewGetString(2), "1")); + assert(!strcmp((const char*)glewGetString(3), "10")); + assert(!strcmp((const char*)glewGetString(4), "0")); + + for (int i = 0; i < 8; ++i) { + assert(glewGetErrorString(i) != NULL); + } + + assert(glewGetExtension("EXT_unexistant") == 0); + assert(glewIsSupported("EXT_unexistant EXT_foobar") == 0); + + /* we can't be sure about which extension exists, so lets do test on + * some of the common ones */ + if (GLEW_EXT_texture_filter_anisotropic) { + assert(glewGetExtension("EXT_texture_filter_anisotropic") == 1); + assert(glewGetExtension("GL_EXT_texture_filter_anisotropic") == 1); + } + + if (GLEW_EXT_framebuffer_object) { + assert(glewGetExtension("EXT_framebuffer_object") == 1); + assert(glewGetExtension("GL_EXT_framebuffer_object") == 1); + } + + if (GLEW_EXT_texture_filter_anisotropic && + GLEW_EXT_framebuffer_object) { + assert(glewIsSupported("EXT_texture_filter_anisotropic EXT_framebuffer_object") == 1); + assert(glewIsSupported("GL_EXT_texture_filter_anisotropic GL_EXT_framebuffer_object") == 1); + } + +#ifdef REPORT_RESULT + int result = 1; + REPORT_RESULT(); +#endif + return 0; +} diff --git a/tests/runner.py b/tests/runner.py index 7f0cbaed..f59d5cb9 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -36,7 +36,7 @@ except: # Core test runner class, shared between normal tests and benchmarks checked_sanity = False -test_modes = ['default', 'o1', 'o2', 'asm1', 'asm2', 'asm2f', 'asm2g', 'asm2x86', 's_0_0', 's_0_1'] +test_modes = ['default', 'o1', 'o2', 'asm1', 'asm2', 'asm3', 'asm2f', 'asm2g', 'asm2x86', 's_0_0', 's_0_1'] test_index = 0 class RunnerCore(unittest.TestCase): diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index 21a47178..1bf1c1d5 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -51,20 +51,21 @@ class Benchmarker: print class NativeBenchmarker(Benchmarker): - def __init__(self, name, cc, cxx): + def __init__(self, name, cc, cxx, args=['-O2']): self.name = name self.cc = cc self.cxx = cxx + self.args = args def build(self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder): self.parent = parent if lib_builder: native_args = native_args + lib_builder(self.name, native=True, env_init={ 'CC': self.cc, 'CXX': self.cxx }) if not native_exec: compiler = self.cxx if filename.endswith('cpp') else self.cc - process = Popen([compiler, '-O2', '-fno-math-errno', filename, '-o', filename+'.native'] + shared_args + native_args, stdout=PIPE, stderr=parent.stderr_redirect) + process = Popen([compiler, '-fno-math-errno', filename, '-o', filename+'.native'] + self.args + shared_args + native_args, stdout=PIPE, stderr=parent.stderr_redirect) output = process.communicate() if process.returncode is not 0: - print >> sys.stderr, "Building native executable with command '%s' failed with a return code %d!" % (' '.join([compiler, '-O2', filename, '-o', filename+'.native']), process.returncode) + print >> sys.stderr, "Building native executable with command failed" print "Output: " + output[0] else: shutil.copyfile(native_exec, filename + '.native') @@ -106,7 +107,7 @@ process(sys.argv[1]) final = os.path.dirname(filename) + os.path.sep + self.name+'_' + os.path.basename(filename) + '.js' try_delete(final) output = Popen([PYTHON, EMCC, filename, #'-O3', - '-O2', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0', + '-O3', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0', '--memory-init-file', '0', '--js-transform', 'python hardcode.py', '-s', 'TOTAL_MEMORY=128*1024*1024', #'--closure', '1', @@ -124,6 +125,7 @@ try: benchmarkers = [ #NativeBenchmarker('clang', CLANG_CC, CLANG), NativeBenchmarker('clang-3.2', os.path.join(LLVM_3_2, 'clang'), os.path.join(LLVM_3_2, 'clang++')), + #NativeBenchmarker('clang-3.2-O3', os.path.join(LLVM_3_2, 'clang'), os.path.join(LLVM_3_2, 'clang++'), ['-O3']), #NativeBenchmarker('clang-3.3', os.path.join(LLVM_3_3, 'clang'), os.path.join(LLVM_3_3, 'clang++')), #NativeBenchmarker('clang-3.4', os.path.join(LLVM_3_4, 'clang'), os.path.join(LLVM_3_4, 'clang++')), #NativeBenchmarker('gcc', 'gcc', 'g++'), @@ -472,7 +474,7 @@ class benchmark(RunnerCore): def lua(self, benchmark, expected, output_parser=None, args_processor=None): shutil.copyfile(path_from_root('tests', 'lua', benchmark + '.lua'), benchmark + '.lua') def lib_builder(name, native, env_init): - ret = self.get_library('lua', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None, native=native, cache_name_extra=name, env_init=env_init) + ret = self.get_library('lua_native' if native else 'lua', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None, native=native, cache_name_extra=name, env_init=env_init) if native: return ret shutil.copyfile(ret[0], ret[0] + '.bc') ret[0] += '.bc' diff --git a/tests/test_browser.py b/tests/test_browser.py index 27dffff2..02bcecbd 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -683,6 +683,9 @@ If manually bisecting: def test_sdl_canvas(self): self.btest('sdl_canvas.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1']) + # some extra coverage + self.btest('sdl_canvas.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1', '-s', '-O0', 'SAFE_HEAP=1']) + self.btest('sdl_canvas.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1', '-s', '-O2', 'SAFE_HEAP=1']) def test_sdl_canvas_proxy(self): def post(): @@ -1602,6 +1605,10 @@ keydown(100);keyup(100); // trigger the end shutil.copyfile(path_from_root('tests', 'screenshot.dds'), os.path.join(self.get_dir(), 'screenshot.dds')) self.btest('s3tc.c', reference='s3tc.png', args=['--preload-file', 'screenshot.dds', '-s', 'LEGACY_GL_EMULATION=1']) + def test_s3tc_ffp_only(self): + shutil.copyfile(path_from_root('tests', 'screenshot.dds'), os.path.join(self.get_dir(), 'screenshot.dds')) + self.btest('s3tc.c', reference='s3tc.png', args=['--preload-file', 'screenshot.dds', '-s', 'LEGACY_GL_EMULATION=1', '-s', 'GL_FFP_ONLY=1']) + def test_s3tc_crunch(self): shutil.copyfile(path_from_root('tests', 'ship.dds'), 'ship.dds') shutil.copyfile(path_from_root('tests', 'bloom.dds'), 'bloom.dds') @@ -1749,4 +1756,21 @@ keydown(100);keyup(100); // trigger the end # Now run test in browser self.btest(path_from_root('tests', 'uuid', 'test.c'), '1') + def test_glew(self): + self.btest(path_from_root('tests', 'glew.c'), expected='1') + self.btest(path_from_root('tests', 'glew.c'), args=['-s', 'LEGACY_GL_EMULATION=1'], expected='1') + self.btest(path_from_root('tests', 'glew.c'), args=['-DGLEW_MX'], expected='1') + self.btest(path_from_root('tests', 'glew.c'), args=['-s', 'LEGACY_GL_EMULATION=1', '-DGLEW_MX'], expected='1') + + def test_doublestart_bug(self): + open('pre.js', 'w').write(r''' +if (typeof Module === 'undefined') Module = eval('(function() { try { return Module || {} } catch(e) { return {} } })()'); +if (!Module['preRun']) Module['preRun'] = []; +Module["preRun"].push(function () { + Module['addRunDependency']('test_run_dependency'); + Module['removeRunDependency']('test_run_dependency'); +}); +''') + + self.btest('doublestart.c', args=['--pre-js', 'pre.js', '-o', 'test.html'], expected='1') diff --git a/tests/test_core.py b/tests/test_core.py index d7bebdc6..d25847d7 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1117,74 +1117,48 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co self.do_run_from_file(src, output) def test_longjmp(self): - if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') - - test_path = path_from_root('tests', 'core', 'test_longjmp') - src, output = (test_path + s for s in ('.in', '.out')) - - self.do_run_from_file(src, output) + test_path = path_from_root('tests', 'core', 'test_longjmp') + src, output = (test_path + s for s in ('.in', '.out')) + self.do_run_from_file(src, output) def test_longjmp2(self): - if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') - test_path = path_from_root('tests', 'core', 'test_longjmp2') src, output = (test_path + s for s in ('.in', '.out')) - self.do_run_from_file(src, output) def test_longjmp3(self): - if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') - test_path = path_from_root('tests', 'core', 'test_longjmp3') src, output = (test_path + s for s in ('.in', '.out')) - self.do_run_from_file(src, output) def test_longjmp4(self): - if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') - test_path = path_from_root('tests', 'core', 'test_longjmp4') src, output = (test_path + s for s in ('.in', '.out')) - self.do_run_from_file(src, output) def test_longjmp_funcptr(self): - if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') - test_path = path_from_root('tests', 'core', 'test_longjmp_funcptr') src, output = (test_path + s for s in ('.in', '.out')) - self.do_run_from_file(src, output) def test_longjmp_repeat(self): - if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') - - Settings.MAX_SETJMPS = 1 - - test_path = path_from_root('tests', 'core', 'test_longjmp_repeat') - src, output = (test_path + s for s in ('.in', '.out')) - - self.do_run_from_file(src, output) + Settings.MAX_SETJMPS = 1 + test_path = path_from_root('tests', 'core', 'test_longjmp_repeat') + src, output = (test_path + s for s in ('.in', '.out')) + self.do_run_from_file(src, output) def test_longjmp_stacked(self): - if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') - test_path = path_from_root('tests', 'core', 'test_longjmp_stacked') src, output = (test_path + s for s in ('.in', '.out')) - self.do_run_from_file(src, output) - def test_longjmp_exc(self): - if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') - test_path = path_from_root('tests', 'core', 'test_longjmp_exc') src, output = (test_path + s for s in ('.in', '.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') + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp: make MAX_SETJMPS take effect') src = r''' #include <stdio.h> @@ -1269,7 +1243,7 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co } catch (MyException & e) { - std::cout << "Catched..."; + std::cout << "Caught..."; } try @@ -1278,7 +1252,7 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co } catch (MyException e) { - std::cout << "Catched..."; + std::cout << "Caught..."; } return 0; @@ -1288,26 +1262,25 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co Settings.DISABLE_EXCEPTION_CATCHING = 0 if '-O2' in self.emcc_args: self.emcc_args.pop() ; self.emcc_args.pop() # disable closure to work around a closure bug - self.do_run(src, 'Throw...Construct...Catched...Destruct...Throw...Construct...Copy...Catched...Destruct...Destruct...') + self.do_run(src, 'Throw...Construct...Caught...Destruct...Throw...Construct...Copy...Caught...Destruct...Destruct...') - def test_exception_2(self): + 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 - test_path = path_from_root('tests', 'core', 'test_exception_2') + 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_white_list_exception(self): + def test_exceptions_white_list(self): if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') Settings.DISABLE_EXCEPTION_CATCHING = 2 Settings.EXCEPTION_CATCHING_WHITELIST = ["__Z12somefunctionv"] Settings.INLINING_LIMIT = 50 # otherwise it is inlined and not identified - test_path = path_from_root('tests', 'core', 'test_white_list_exception') + test_path = path_from_root('tests', 'core', 'test_exceptions_white_list') src, output = (test_path + s for s in ('.in', '.out')) self.do_run_from_file(src, output) @@ -1315,7 +1288,7 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co Settings.DISABLE_EXCEPTION_CATCHING = 0 Settings.EXCEPTION_CATCHING_WHITELIST = [] - def test_uncaught_exception(self): + def test_exceptions_uncaught(self): if self.emcc_args is None: return self.skip('no libcxx inclusion without emcc') Settings.DISABLE_EXCEPTION_CATCHING = 0 @@ -1354,29 +1327,27 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co ''' self.do_run(src, 'success') - def test_typed_exceptions(self): - Settings.DISABLE_EXCEPTION_CATCHING = 0 - Settings.SAFE_HEAP = 0 # Throwing null will cause an ignorable null pointer access. - src = open(path_from_root('tests', 'exceptions', 'typed.cpp'), 'r').read() - expected = open(path_from_root('tests', 'exceptions', 'output.txt'), 'r').read() - self.do_run(src, expected) - - def test_multiexception(self): - if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') - + def test_exceptions_typed(self): Settings.DISABLE_EXCEPTION_CATCHING = 0 + Settings.SAFE_HEAP = 0 # Throwing null will cause an ignorable null pointer access. - test_path = path_from_root('tests', 'core', 'test_multiexception') + test_path = path_from_root('tests', 'core', 'test_exceptions_typed') src, output = (test_path + s for s in ('.in', '.out')) self.do_run_from_file(src, output) - def test_std_exception(self): + def test_exceptions_multi(self): + Settings.DISABLE_EXCEPTION_CATCHING = 0 + test_path = path_from_root('tests', 'core', 'test_exceptions_multi') + src, output = (test_path + s for s in ('.in', '.out')) + self.do_run_from_file(src, output) + + def test_exceptions_std(self): if self.emcc_args is None: return self.skip('requires emcc') Settings.DISABLE_EXCEPTION_CATCHING = 0 self.emcc_args += ['-s', 'SAFE_HEAP=0'] - test_path = path_from_root('tests', 'core', 'test_std_exception') + test_path = path_from_root('tests', 'core', 'test_exceptions_std') src, output = (test_path + s for s in ('.in', '.out')) self.do_run_from_file(src, output) @@ -1486,7 +1457,7 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co def test_segfault(self): if self.emcc_args is None: return self.skip('SAFE_HEAP without ta2 means we check types too, which hide segfaults') - if Settings.ASM_JS: return self.skip('asm does not support safe heap') + if os.environ.get('EMCC_FAST_COMPILER') == '1' and '-O2' not in self.emcc_args: return self.skip('todo in non-jsopts-enabled fastcomp') Settings.SAFE_HEAP = 1 @@ -1606,6 +1577,8 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co self.do_run_from_file(src, output) def test_alloca(self): + if Settings.USE_TYPED_ARRAYS != 2: return self.skip('non-ta2 may have unaligned allocas') + test_path = path_from_root('tests', 'core', 'test_alloca') src, output = (test_path + s for s in ('.in', '.out')) @@ -3703,6 +3676,12 @@ ok self.do_run_from_file(src, output) + def test_fnmatch(self): + if self.emcc_args is None: return self.skip('requires linking in libc++') + test_path = path_from_root('tests', 'core', 'fnmatch') + src, output = (test_path + s for s in ('.c', '.out')) + self.do_run_from_file(src, output) + def test_sscanf(self): if self.emcc_args is None: return self.skip('needs emcc for libc') if not self.is_le32(): return self.skip('le32 needed for accurate math') @@ -4085,7 +4064,6 @@ def process(filename): def test_utf32(self): if self.emcc_args is None: return self.skip('need libc for wcslen()') if not self.is_le32(): return self.skip('this test uses inline js, which requires le32') - if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') self.do_run(open(path_from_root('tests', 'utf32.cpp')).read(), 'OK.') self.do_run(open(path_from_root('tests', 'utf32.cpp')).read(), 'OK.', args=['-fshort-wchar']) @@ -4284,6 +4262,12 @@ def process(filename): self.do_run_from_file(src, output) + def test_nl_types(self): + test_path = path_from_root('tests', 'core', 'test_nl_types') + src, output = (test_path + s for s in ('.in', '.out')) + + self.do_run_from_file(src, output) + def test_799(self): src = open(path_from_root('tests', '799.cpp'), 'r').read() self.do_run(src, '''Set PORT family: 0, port: 3979 @@ -4620,6 +4604,7 @@ return malloc(size); assert 'asm1' in test_modes if self.run_name == 'asm1': generated = open('src.cpp.o.js').read() + generated = re.sub(r'\n+[ \n]*\n+', '\n', generated) main = generated[generated.find('function runPostSets'):] main = main[:main.find('\n}')] assert main.count('\n') == 7, 'must not emit too many postSets: %d' % main.count('\n') @@ -4642,6 +4627,8 @@ return malloc(size); self.do_run_from_file(src, output) def test_simd3(self): + return self.skip('FIXME: this appears to be broken') + if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2') if Settings.ASM_JS: Settings.ASM_JS = 2 # does not validate @@ -4670,7 +4657,6 @@ return malloc(size); def test_lua(self): if self.emcc_args is None: return self.skip('requires emcc') if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: make this work') - if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') for aggro in ([0, 1] if Settings.ASM_JS and '-O2' in self.emcc_args else [0]): print aggro @@ -4691,7 +4677,6 @@ return malloc(size); def test_freetype(self): if self.emcc_args is None: return self.skip('requires emcc') if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: Figure out and try to fix') - if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') assert 'asm2g' in test_modes if self.run_name == 'asm2g': @@ -4837,7 +4822,6 @@ def process(filename): def test_poppler(self): if self.emcc_args is None: return self.skip('very slow, we only do this in emcc runs') - if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') Settings.CORRECT_OVERFLOWS = 1 Settings.CORRECT_SIGNS = 1 @@ -4999,7 +4983,9 @@ def process(filename): def clean(text): text = text.replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n').replace('{\n}', '{}') return '\n'.join(sorted(text.split('\n'))) - self.assertIdentical(clean(open('release.js').read()), clean(open('debug%d.js' % debug).read())) # EMCC_DEBUG=1 mode must not generate different code! + sizes = len(open('release.js').read()), len(open('debug%d.js' % debug).read()) + print >> sys.stderr, debug, 'sizes', sizes + assert abs(sizes[0] - sizes[1]) < 0.0001*sizes[0] # we can't check on identical output, compilation is not 100% deterministic (order of switch elements, etc.), but size should be ~identical print >> sys.stderr, 'debug check %d passed too' % debug try: @@ -5057,7 +5043,7 @@ def process(filename): 'structphiparam', 'callwithstructural_ta2', 'callwithstructural64_ta2', 'structinparam', # pnacl limitations in ExpandStructRegs '2xi40', # pnacl limitations in ExpandGetElementPtr 'legalizer_ta2', '514_ta2', # pnacl limitation in not legalizing i104, i96, etc. - 'longjmp_tiny', 'longjmp_tiny_invoke', 'longjmp_tiny_phi', 'longjmp_tiny_phi2', 'longjmp_tiny_invoke_phi', 'indirectbrphi', 'ptrtoint_blockaddr', 'quoted', # current fastcomp limitations FIXME + 'indirectbrphi', 'ptrtoint_blockaddr', 'quoted', # current fastcomp limitations FIXME 'sillyfuncast2', 'sillybitcast', 'atomicrmw_unaligned' # TODO XXX ]: continue if '_ta2' in shortname and not Settings.USE_TYPED_ARRAYS == 2: @@ -5968,7 +5954,7 @@ def process(filename): def test_debug(self): if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g') if self.emcc_args is not None: - if '-O1' in self.emcc_args or '-O2' in self.emcc_args: return self.skip('optimizations remove LLVM debug info') + if '-O1' in self.emcc_args or '-O2' in self.emcc_args or '-O3' in self.emcc_args: return self.skip('optimizations remove LLVM debug info') src = ''' #include <stdio.h> @@ -5999,7 +5985,6 @@ def process(filename): def test_source_map(self): if Settings.USE_TYPED_ARRAYS != 2: return self.skip("doesn't pass without typed arrays") - if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') if NODE_JS not in JS_ENGINES: return self.skip('sourcemapper requires Node to run') if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g') @@ -6046,6 +6031,7 @@ def process(filename): # optimizer can deal with both types. out_file = re.sub(' *//@.*$', '', out_file, flags=re.MULTILINE) def clean(code): + code = re.sub(r'\n+[ \n]*\n+', '\n', code) code = code.replace('{\n}', '{}') return '\n'.join(sorted(code.split('\n'))) self.assertIdentical(clean(no_maps_file), clean(out_file)) @@ -6083,7 +6069,6 @@ def process(filename): if Settings.USE_TYPED_ARRAYS != 2: return self.skip("doesn't pass without typed arrays") if '-g4' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g4') if NODE_JS not in JS_ENGINES: return self.skip('sourcemapper requires Node to run') - if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') src = ''' #include <stdio.h> @@ -6108,7 +6093,7 @@ def process(filename): tools.shared.NODE_JS, [map_filename])) with open(filename) as f: lines = f.readlines() for m in mappings: - if m['originalLine'] == 5 and '__cxa_throw' in lines[m['generatedLine']]: + if m['originalLine'] == 5 and '__cxa_throw' in lines[m['generatedLine']-1]: # -1 to fix 0-start vs 1-start return assert False, 'Must label throw statements with line numbers' @@ -6358,7 +6343,7 @@ def make_run(fullname, name=-1, compiler=-1, embetter=0, quantum_size=0, if self.emcc_args is not None: Settings.load(self.emcc_args) Building.LLVM_OPTS = 0 - if '-O2' in self.emcc_args: + if '-O2' in self.emcc_args or '-O3' in self.emcc_args: Building.COMPILER_TEST_OPTS = [] # remove -g in -O2 tests, for more coverage #Building.COMPILER_TEST_OPTS += self.emcc_args for arg in self.emcc_args: @@ -6412,8 +6397,12 @@ o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=0", "-s", "J # asm.js asm1 = make_run("asm1", compiler=CLANG, emcc_args=["-O1"]) asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2"]) +asm3 = make_run("asm3", compiler=CLANG, emcc_args=["-O3"]) asm2f = make_run("asm2f", compiler=CLANG, emcc_args=["-O2", "-s", "PRECISE_F32=1"]) -asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1", "-s", "CHECK_HEAP_ALIGN=1"]) +if os.environ.get('EMCC_FAST_COMPILER') == '1': + asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1", "-s", "SAFE_HEAP=1"]) +else: + asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1", "-s", "CHECK_HEAP_ALIGN=1"]) asm2x86 = make_run("asm2x86", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "CHECK_HEAP_ALIGN=1"], env={"EMCC_LLVM_TARGET": "i386-pc-linux-gnu"}) # Make custom runs with various options diff --git a/tests/test_other.py b/tests/test_other.py index f91b4683..53128391 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -134,13 +134,13 @@ Options that are modified or new in %s include: (['-o', 'something.js', '-O2'], 2, None, 0, 1), (['-o', 'something.js', '-O2', '-g'], 2, None, 0, 0), (['-o', 'something.js', '-Os'], 2, None, 0, 1), - (['-o', 'something.js', '-O3', '-s', 'ASM_JS=0'], 3, None, 1, 1), + (['-o', 'something.js', '-O3', '-s', 'ASM_JS=0'], 3, None, 0, 1), # and, test compiling to bitcode first (['-o', 'something.bc'], 0, [], 0, 0), (['-o', 'something.bc', '-O0'], 0, [], 0, 0), (['-o', 'something.bc', '-O1'], 1, ['-O1'], 0, 0), (['-o', 'something.bc', '-O2'], 2, ['-O2'], 0, 0), - (['-o', 'something.bc', '-O3'], 3, ['-O3', '-s', 'ASM_JS=0'], 1, 0), + (['-o', 'something.bc', '-O3'], 3, ['-O3', '-s', 'ASM_JS=0'], 0, 0), (['-O1', '-o', 'something.bc'], 1, [], 0, 0), ]: print params, opt_level, bc_params, closure, has_malloc @@ -157,7 +157,6 @@ Options that are modified or new in %s include: print '....', bc_args output = Popen(bc_args, stdout=PIPE, stderr=PIPE).communicate() assert os.path.exists('something.js'), output[1] - assert ('Applying some potentially unsafe optimizations!' in output[1]) == (opt_level >= 3), 'unsafe warning should appear in opt >= 3' self.assertContained('hello, world!', run_js('something.js')) # Verify optimization level etc. in the generated code @@ -196,7 +195,6 @@ Options that are modified or new in %s include: (['-O2', '-g3'], lambda generated: 'var b=0' not in generated and 'var b = 0' not in generated and 'function _main' in generated, 'registerize is cancelled by -g3'), #(['-O2', '-g4'], lambda generated: 'var b=0' not in generated and 'var b = 0' not in generated and 'function _main' in generated, 'same as -g3 for now'), (['-s', 'INLINING_LIMIT=0'], lambda generated: 'function _dump' in generated, 'no inlining without opts'), - (['-O3', '-s', 'INLINING_LIMIT=0', '--closure', '0'], lambda generated: 'function _dump' not in generated, 'lto/inlining'), (['-Os', '--llvm-lto', '1', '-s', 'ASM_JS=0', '-g2'], lambda generated: 'function _dump' in generated, '-Os disables inlining'), (['-s', 'USE_TYPED_ARRAYS=0'], lambda generated: 'new Int32Array' not in generated, 'disable typed arrays'), (['-s', 'USE_TYPED_ARRAYS=1'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'), @@ -284,9 +282,33 @@ f.close() if WINDOWS: generators = ['MinGW Makefiles', 'NMake Makefiles'] else: - generators = ['Unix Makefiles'] - - make_commands = { 'MinGW Makefiles': ['mingw32-make'], 'NMake Makefiles': ['nmake', '/NOLOGO'], 'Unix Makefiles': ['make'] } + generators = ['Unix Makefiles', 'Ninja', 'Eclipse CDT4 - Ninja'] + + def nmake_detect_error(configuration): + if Building.which(configuration['build'][0]): + return None + else: + return 'Skipping NMake test for CMake support, since nmake was not found in PATH. Run this test in Visual Studio command prompt to easily access nmake.' + + def check_makefile(configuration, dirname): + assert os.path.exists(dirname + '/Makefile'), 'CMake call did not produce a Makefile!' + + configurations = { 'MinGW Makefiles' : { 'prebuild': check_makefile, + 'build' : ['mingw32-make'], + + }, + 'NMake Makefiles' : { 'detect' : nmake_detect_error, + 'prebuild': check_makefile, + 'build' : ['nmake', '/NOLOGO'], + }, + 'Unix Makefiles' : { 'prebuild': check_makefile, + 'build' : ['make'], + }, + 'Ninja' : { 'build' : ['ninja'], + }, + 'Eclipse CDT4 - Ninja': { 'build' : ['ninja'], + } + } if os.name == 'nt': emconfigure = path_from_root('emconfigure.bat') @@ -294,11 +316,37 @@ f.close() emconfigure = path_from_root('emconfigure') for generator in generators: - if generator == 'NMake Makefiles' and not Building.which('nmake'): - print >> sys.stderr, 'Skipping NMake test for CMake support, since nmake was not found in PATH. Run this test in Visual Studio command prompt to easily access nmake.' + conf = configurations[generator] + + make = conf['build'] + + try: + detector = conf['detect'] + except KeyError: + detector = None + + if detector: + error = detector(conf) + elif len(make) == 1 and not Building.which(make[0]): + # Use simple test if applicable + error = 'Skipping %s test for CMake support, since it could not be detected.' % generator + else: + error = None + + if error: + logging.warning(error) continue - make = make_commands[generator] + try: + prebuild = conf['prebuild'] + except KeyError: + prebuild = None + + try: + postbuild = conf['postbuild'] + except KeyError: + postbuild = None + cmake_cases = ['target_js', 'target_html'] cmake_outputs = ['test_cmake.js', 'hello_world_gles.html'] for i in range(0, 2): @@ -331,7 +379,9 @@ f.close() logging.error('Failed command: ' + ' '.join(cmd)) logging.error('Result:\n' + ret[1]) raise Exception('cmake call failed!') - assert os.path.exists(tempdirname + '/Makefile'), 'CMake call did not produce a Makefile!' + + if prebuild: + prebuild(configuration, tempdirname) # Build cmd = make + (['VERBOSE=1'] if verbose_level >= 3 else []) @@ -344,6 +394,9 @@ f.close() raise Exception('make failed!') assert os.path.exists(tempdirname + '/' + cmake_outputs[i]), 'Building a cmake-generated Makefile failed to produce an output file %s!' % tempdirname + '/' + cmake_outputs[i] + if postbuild: + postbuild(configuration, tempdirname) + # Run through node, if CMake produced a .js file. if cmake_outputs[i].endswith('.js'): ret = Popen(listify(NODE_JS) + [tempdirname + '/' + cmake_outputs[i]], stdout=PIPE).communicate()[0] @@ -1721,7 +1774,7 @@ f.close() (path_from_root('tools', 'test-js-optimizer-asm-regs.js'), open(path_from_root('tools', 'test-js-optimizer-asm-regs-output.js')).read(), ['asm', 'registerize']), (path_from_root('tools', 'test-js-optimizer-asm-regs-min.js'), open(path_from_root('tools', 'test-js-optimizer-asm-regs-min-output.js')).read(), - ['asm', 'registerize']), + ['asm', 'registerize', 'minifyLocals']), (path_from_root('tools', 'test-js-optimizer-asm-pre.js'), open(path_from_root('tools', 'test-js-optimizer-asm-pre-output.js')).read(), ['asm', 'simplifyExpressions']), (path_from_root('tools', 'test-js-optimizer-asm-last.js'), open(path_from_root('tools', 'test-js-optimizer-asm-last-output.js')).read(), @@ -1736,6 +1789,8 @@ f.close() ['asm', 'outline']), (path_from_root('tools', 'test-js-optimizer-asm-minlast.js'), open(path_from_root('tools', 'test-js-optimizer-asm-minlast-output.js')).read(), ['asm', 'minifyWhitespace', 'last']), + (path_from_root('tools', 'test-js-optimizer-shiftsAggressive.js'), open(path_from_root('tools', 'test-js-optimizer-shiftsAggressive-output.js')).read(), + ['asm', 'aggressiveVariableElimination']), ]: print input output = Popen(listify(NODE_JS) + [path_from_root('tools', 'js-optimizer.js'), input] + passes, stdin=PIPE, stdout=PIPE).communicate()[0] @@ -2219,7 +2274,6 @@ mergeInto(LibraryManager.library, { process.communicate() assert(os.path.isfile(outdir + 'hello_world.obj')) - def test_doublestart_bug(self): open('code.cpp', 'w').write(r''' #include <stdio.h> @@ -2251,3 +2305,20 @@ Module["preRun"].push(function () { assert output.count('This should only appear once.') == 1, '\n'+output + def test_module_print(self): + open('code.cpp', 'w').write(r''' +#include <stdio.h> +int main(void) { + printf("123456789\n"); + return 0; +} +''') + + open('pre.js', 'w').write(r''' +var Module = { print: function(x) { throw '<{(' + x + ')}>' } }; +''') + + Popen([PYTHON, EMCC, 'code.cpp', '--pre-js', 'pre.js']).communicate() + 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 + diff --git a/tests/utf32.cpp b/tests/utf32.cpp index 6b75b244..d00338a6 100644 --- a/tests/utf32.cpp +++ b/tests/utf32.cpp @@ -16,11 +16,11 @@ int main() { if (sizeof(wchar_t) == 4) { utf32 *memory = new utf32[wstr.length()+1]; - asm("var str = Module.UTF32ToString(%0);" - "Module.print(str);" - "Module.stringToUTF32(str, %1);" - : - : "r"(wstr.c_str()), "r"(memory)); + EM_ASM_INT({ + var str = Module.UTF32ToString($0); + Module.print(str); + Module.stringToUTF32(str, $1); + }, wstr.c_str(), memory); // Compare memory to confirm that the string is intact after taking a route through JS side. const utf32 *srcPtr = reinterpret_cast<const utf32 *>(wstr.c_str()); @@ -33,11 +33,11 @@ int main() { } else { // sizeof(wchar_t) == 2, and we're building with -fshort-wchar. utf16 *memory = new utf16[2*wstr.length()+1]; - asm("var str = Module.UTF16ToString(%0);" - "Module.print(str);" - "Module.stringToUTF16(str, %1);" - : - : "r"(wstr.c_str()), "r"(memory)); + EM_ASM_INT({ + var str = Module.UTF16ToString($0); + Module.print(str); + Module.stringToUTF16(str, $1); + }, wstr.c_str(), memory); // Compare memory to confirm that the string is intact after taking a route through JS side. const utf16 *srcPtr = reinterpret_cast<const utf16 *>(wstr.c_str()); diff --git a/tools/eliminator/asm-eliminator-test-output.js b/tools/eliminator/asm-eliminator-test-output.js index a344fc35..7a8baef2 100644 --- a/tools/eliminator/asm-eliminator-test-output.js +++ b/tools/eliminator/asm-eliminator-test-output.js @@ -304,4 +304,510 @@ function binary(x) { memset(f(x)) | 0; +dmemset(f(x)); } +function cute($this, $outImage) { + $this = $this | 0; + $outImage = $outImage | 0; + var $retval = 0, $outImage_addr = 0, $width = 0, $height = 0, $bit_depth = 0, $color_type = 0, $data = 0, $bpl = 0, $y = 0, $i = 0, $y76 = 0, $p = 0, $end = 0, $this1 = 0, $call = 0, $call7 = 0, $call8 = 0, $3 = 0, $call17 = 0, $10 = 0, $call32 = 0, $call33 = 0, $17$0 = 0, $call34 = 0, $add_ptr = 0, $32 = 0, $call42 = 0, $35 = 0, $call45 = 0, $41 = 0, $call51 = 0, $43 = 0, $call55 = 0, $call57 = 0, $49 = 0, $call72 = 0, $call75 = 0, label = 0, setjmpLabel = 0, setjmpTable = 0, sp = 0; + sp = STACKTOP; + STACKTOP = STACKTOP + 32 | 0; + label = 1; + setjmpLabel = 0; + setjmpTable = STACKTOP; + STACKTOP = STACKTOP + 168 | 0; + HEAP32[setjmpTable >> 2] = 0; + while (1) switch (label | 0) { + case 1: + $width = sp | 0; + $height = sp + 8 | 0; + $bit_depth = sp + 16 | 0; + $color_type = sp + 24 | 0; + $outImage_addr = $outImage; + $this1 = $this; + if ((HEAP32[($this1 + 32 | 0) >> 2] | 0 | 0) == 3) { + label = 2; + break; + } else { + label = 3; + break; + } + case 2: + $retval = 0; + label = 37; + break; + case 3: + if ((HEAP32[($this1 + 32 | 0) >> 2] | 0 | 0) == 0) { + label = 4; + break; + } else { + label = 6; + break; + } + case 4: + $call = invoke_ii(900, $this1 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + if ($call) { + label = 6; + break; + } else { + label = 5; + break; + } + case 5: + HEAP32[($this1 + 32 | 0) >> 2] = 3; + $retval = 0; + label = 37; + break; + case 6: + HEAP32[($this1 + 28 | 0) >> 2] = 0; + $call7 = invoke_iiii(30, HEAP32[($this1 + 16 | 0) >> 2] | 0 | 0, 2638 | 0, 156 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $call8 = _saveSetjmp($call7 | 0 | 0, label, setjmpTable) | 0; + label = 38; + break; + case 38: + if (($call8 | 0) != 0) { + label = 7; + break; + } else { + label = 10; + break; + } + case 7: + invoke_viii(640, $this1 + 16 | 0 | 0, $this1 + 20 | 0 | 0, $this1 + 24 | 0 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $3 = HEAP32[($this1 + 28 | 0) >> 2] | 0; + if (($3 | 0) == 0) { + label = 9; + break; + } else { + label = 8; + break; + } + case 8: + invoke_vi(926, $3 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + label = 9; + break; + case 9: + HEAP32[($this1 + 16 | 0) >> 2] = 0; + HEAP32[($this1 + 32 | 0) >> 2] = 3; + $retval = 0; + label = 37; + break; + case 10: + invoke_viiif(2, $outImage_addr | 0, HEAP32[($this1 + 16 | 0) >> 2] | 0 | 0, HEAP32[($this1 + 20 | 0) >> 2] | 0 | 0, +(+HEAPF32[($this1 | 0) >> 2])); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $call17 = invoke_ii(832, $outImage_addr | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + if ($call17) { + label = 11; + break; + } else { + label = 14; + break; + } + case 11: + invoke_viii(640, $this1 + 16 | 0 | 0, $this1 + 20 | 0 | 0, $this1 + 24 | 0 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $10 = HEAP32[($this1 + 28 | 0) >> 2] | 0; + if (($10 | 0) == 0) { + label = 13; + break; + } else { + label = 12; + break; + } + case 12: + invoke_vi(926, $10 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + label = 13; + break; + case 13: + HEAP32[($this1 + 16 | 0) >> 2] = 0; + HEAP32[($this1 + 32 | 0) >> 2] = 3; + $retval = 0; + label = 37; + break; + case 14: + invoke_iiiiiiiiii(2, HEAP32[($this1 + 16 | 0) >> 2] | 0 | 0, HEAP32[($this1 + 20 | 0) >> 2] | 0 | 0, $width | 0, $height | 0, $bit_depth | 0, $color_type | 0, 0 | 0, 0 | 0, 0 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $call32 = invoke_ii(850, $outImage_addr | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $data = $call32; + $call33 = invoke_ii(284, $outImage_addr | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $bpl = $call33; + $17$0 = invoke_iii(860, HEAP32[$height >> 2] | 0 | 0, 4 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $call34 = invoke_ii(550, (tempRet0 ? -1 : $17$0) | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + HEAP32[($this1 + 28 | 0) >> 2] = $call34; + $y = 0; + label = 15; + break; + case 15: + if ($y >>> 0 < (HEAP32[$height >> 2] | 0) >>> 0) { + label = 16; + break; + } else { + label = 18; + break; + } + case 16: + $add_ptr = $data + (Math_imul($y, $bpl) | 0) | 0; + HEAP32[((HEAP32[($this1 + 28 | 0) >> 2] | 0) + ($y << 2) | 0) >> 2] = $add_ptr; + label = 17; + break; + case 17: + $y = $y + 1 | 0; + label = 15; + break; + case 18: + invoke_vii(858, HEAP32[($this1 + 16 | 0) >> 2] | 0 | 0, HEAP32[($this1 + 28 | 0) >> 2] | 0 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $32 = $outImage_addr; + $call42 = invoke_iii(690, HEAP32[($this1 + 16 | 0) >> 2] | 0 | 0, HEAP32[($this1 + 20 | 0) >> 2] | 0 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + invoke_vii(1890, $32 | 0, $call42 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $35 = $outImage_addr; + $call45 = invoke_iii(256, HEAP32[($this1 + 16 | 0) >> 2] | 0 | 0, HEAP32[($this1 + 20 | 0) >> 2] | 0 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + invoke_vii(2126, $35 | 0, $call45 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + HEAP32[($this1 + 32 | 0) >> 2] = 2; + invoke_vii(36, HEAP32[($this1 + 16 | 0) >> 2] | 0 | 0, HEAP32[($this1 + 24 | 0) >> 2] | 0 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + invoke_vii(2752, $this1 | 0, HEAP32[($this1 + 24 | 0) >> 2] | 0 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $i = 0; + label = 19; + break; + case 19: + $41 = $i; + $call51 = invoke_ii(618, $this1 + 12 | 0 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + if (($41 | 0) < ($call51 - 1 | 0 | 0)) { + label = 20; + break; + } else { + label = 22; + break; + } + case 20: + $43 = $outImage_addr; + $call55 = invoke_iii(502, $this1 + 12 | 0 | 0, $i | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $call57 = invoke_iii(502, $this1 + 12 | 0 | 0, $i + 1 | 0 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + invoke_viii(550, $43 | 0, $call55 | 0, $call57 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + label = 21; + break; + case 21: + $i = $i + 2 | 0; + label = 19; + break; + case 22: + invoke_viii(640, $this1 + 16 | 0 | 0, $this1 + 20 | 0 | 0, $this1 + 24 | 0 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $49 = HEAP32[($this1 + 28 | 0) >> 2] | 0; + if (($49 | 0) == 0) { + label = 24; + break; + } else { + label = 23; + break; + } + case 23: + invoke_vi(926, $49 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + label = 24; + break; + case 24: + HEAP32[($this1 + 16 | 0) >> 2] = 0; + HEAP32[($this1 + 32 | 0) >> 2] = 0; + if ((HEAP32[$color_type >> 2] | 0 | 0) == 3) { + label = 25; + break; + } else { + label = 36; + break; + } + case 25: + $call72 = invoke_ii(926, $outImage_addr | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + if (($call72 | 0) == 3) { + label = 26; + break; + } else { + label = 36; + break; + } + case 26: + $call75 = invoke_ii(860, $outImage_addr | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $y76 = 0; + label = 27; + break; + case 27: + if (($y76 | 0) < (HEAP32[$height >> 2] | 0 | 0)) { + label = 28; + break; + } else { + label = 35; + break; + } + case 28: + $p = $data + (Math_imul($y76, $bpl) | 0) | 0; + $end = $p + (HEAP32[$width >> 2] | 0) | 0; + label = 29; + break; + case 29: + if ($p >>> 0 < $end >>> 0) { + label = 30; + break; + } else { + label = 33; + break; + } + case 30: + if (((HEAP8[$p] | 0) & 255 | 0) >= ($call75 | 0)) { + label = 31; + break; + } else { + label = 32; + break; + } + case 31: + HEAP8[$p] = 0; + label = 32; + break; + case 32: + $p = $p + 1 | 0; + label = 29; + break; + case 33: + label = 34; + break; + case 34: + $y76 = $y76 + 1 | 0; + label = 27; + break; + case 35: + label = 36; + break; + case 36: + $retval = 1; + label = 37; + break; + case 37: + STACKTOP = sp; + return $retval | 0; + case -1: + if ((setjmpLabel | 0) == 6) { + $call8 = threwValue; + label = 38; + } + __THREW__ = threwValue = 0; + break; + } + return 0; +} diff --git a/tools/eliminator/asm-eliminator-test.js b/tools/eliminator/asm-eliminator-test.js index 4b45e4d4..ad1ed05e 100644 --- a/tools/eliminator/asm-eliminator-test.js +++ b/tools/eliminator/asm-eliminator-test.js @@ -378,5 +378,654 @@ function binary(x) { z = f(x); +dmemset(z); } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6", "looop7", "looop8", "multiloop", "multiloop2", "tempDouble2", "watIf", "select2", "binary"] +function cute($this, $outImage) { + $this = $this | 0; + $outImage = $outImage | 0; + var $retval = 0, $this_addr = 0, $outImage_addr = 0, $width = 0, $height = 0, $bit_depth = 0, $color_type = 0, $data = 0, $bpl = 0, $y = 0, $i = 0, $color_table_size = 0, $y76 = 0, $p = 0, $end = 0, $this1 = 0, $state = 0, $0 = 0, $cmp = 0, $state2 = 0; + var $1 = 0, $cmp3 = 0, $call = 0, $state5 = 0, $row_pointers = 0, $png_ptr = 0, $2 = 0, $call7 = 0, $arraydecay = 0, $call8 = 0, $tobool = 0, $png_ptr10 = 0, $info_ptr = 0, $end_info = 0, $row_pointers11 = 0, $3 = 0, $isnull = 0, $4 = 0, $png_ptr12 = 0, $state13 = 0; + var $5 = 0, $png_ptr15 = 0, $6 = 0, $info_ptr16 = 0, $7 = 0, $gamma = 0, $8 = +0, $9 = 0, $call17 = 0, $png_ptr19 = 0, $info_ptr20 = 0, $end_info21 = 0, $row_pointers22 = 0, $10 = 0, $isnull23 = 0, $11 = 0, $png_ptr26 = 0, $state27 = 0, $png_ptr29 = 0, $12 = 0; + var $info_ptr30 = 0, $13 = 0, $call31 = 0, $14 = 0, $call32 = 0, $15 = 0, $call33 = 0, $16 = 0, $17$0 = 0, $17$1 = 0, $18 = 0, $19 = 0, $20 = 0, $call34 = 0, $21 = 0, $row_pointers35 = 0, $22 = 0, $23 = 0, $cmp36 = 0, $24 = 0; + var $25 = 0, $26 = 0, $mul = 0, $add_ptr = 0, $27 = 0, $row_pointers37 = 0, $28 = 0, $arrayidx = 0, $29 = 0, $inc = 0, $png_ptr38 = 0, $30 = 0, $row_pointers39 = 0, $31 = 0, $32 = 0, $png_ptr40 = 0, $33 = 0, $info_ptr41 = 0, $34 = 0, $call42 = 0; + var $35 = 0, $png_ptr43 = 0, $36 = 0, $info_ptr44 = 0, $37 = 0, $call45 = 0, $state46 = 0, $png_ptr47 = 0, $38 = 0, $end_info48 = 0, $39 = 0, $end_info49 = 0, $40 = 0, $41 = 0, $readTexts = 0, $42 = 0, $call51 = 0, $sub = 0, $cmp52 = 0, $43 = 0; + var $readTexts54 = 0, $44 = 0, $45 = 0, $call55 = 0, $readTexts56 = 0, $46 = 0, $47 = 0, $add = 0, $call57 = 0, $48 = 0, $add59 = 0, $png_ptr61 = 0, $info_ptr62 = 0, $end_info63 = 0, $row_pointers64 = 0, $49 = 0, $isnull65 = 0, $50 = 0, $png_ptr68 = 0, $state69 = 0; + var $51 = 0, $cmp70 = 0, $52 = 0, $call72 = 0, $cmp73 = 0, $53 = 0, $call75 = 0, $54 = 0, $55 = 0, $cmp78 = 0, $56 = 0, $57 = 0, $58 = 0, $mul80 = 0, $add_ptr81 = 0, $59 = 0, $60 = 0, $add_ptr82 = 0, $61 = 0, $62 = 0; + var $cmp83 = 0, $63 = 0, $64 = 0, $conv = 0, $65 = 0, $cmp84 = 0, $66 = 0, $67 = 0, $incdec_ptr = 0, $68 = 0, $inc88 = 0, $69 = 0, label = 0, setjmpLabel = 0, setjmpTable = 0; + var sp = 0; + sp = STACKTOP; + STACKTOP = STACKTOP + 32 | 0; + label = 1; + setjmpLabel = 0; + setjmpTable = STACKTOP; + STACKTOP = STACKTOP + 168 | 0; + HEAP32[setjmpTable >> 2] = 0; + while (1) switch (label | 0) { + case 1: + $width = sp | 0; + $height = sp + 8 | 0; + $bit_depth = sp + 16 | 0; + $color_type = sp + 24 | 0; + $this_addr = $this; + $outImage_addr = $outImage; + $this1 = $this_addr; + $state = $this1 + 32 | 0; + $0 = HEAP32[$state >> 2] | 0; + $cmp = ($0 | 0) == 3; + if ($cmp) { + label = 2; + break; + } else { + label = 3; + break; + } + case 2: + $retval = 0; + label = 37; + break; + case 3: + $state2 = $this1 + 32 | 0; + $1 = HEAP32[$state2 >> 2] | 0; + $cmp3 = ($1 | 0) == 0; + if ($cmp3) { + label = 4; + break; + } else { + label = 6; + break; + } + case 4: + $call = invoke_ii(900, $this1 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + if ($call) { + label = 6; + break; + } else { + label = 5; + break; + } + case 5: + $state5 = $this1 + 32 | 0; + HEAP32[$state5 >> 2] = 3; + $retval = 0; + label = 37; + break; + case 6: + $row_pointers = $this1 + 28 | 0; + HEAP32[$row_pointers >> 2] = 0; + $png_ptr = $this1 + 16 | 0; + $2 = HEAP32[$png_ptr >> 2] | 0; + $call7 = invoke_iiii(30, $2 | 0, 2638 | 0, 156 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $arraydecay = $call7 | 0; + $call8 = _saveSetjmp($arraydecay | 0, label, setjmpTable) | 0; + label = 38; + break; + case 38: + $tobool = ($call8 | 0) != 0; + if ($tobool) { + label = 7; + break; + } else { + label = 10; + break; + } + case 7: + $png_ptr10 = $this1 + 16 | 0; + $info_ptr = $this1 + 20 | 0; + $end_info = $this1 + 24 | 0; + invoke_viii(640, $png_ptr10 | 0, $info_ptr | 0, $end_info | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $row_pointers11 = $this1 + 28 | 0; + $3 = HEAP32[$row_pointers11 >> 2] | 0; + $isnull = ($3 | 0) == 0; + if ($isnull) { + label = 9; + break; + } else { + label = 8; + break; + } + case 8: + $4 = $3; + invoke_vi(926, $4 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + label = 9; + break; + case 9: + $png_ptr12 = $this1 + 16 | 0; + HEAP32[$png_ptr12 >> 2] = 0; + $state13 = $this1 + 32 | 0; + HEAP32[$state13 >> 2] = 3; + $retval = 0; + label = 37; + break; + case 10: + $5 = $outImage_addr; + $png_ptr15 = $this1 + 16 | 0; + $6 = HEAP32[$png_ptr15 >> 2] | 0; + $info_ptr16 = $this1 + 20 | 0; + $7 = HEAP32[$info_ptr16 >> 2] | 0; + $gamma = $this1 | 0; + $8 = +HEAPF32[$gamma >> 2]; + invoke_viiif(2, $5 | 0, $6 | 0, $7 | 0, +$8); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $9 = $outImage_addr; + $call17 = invoke_ii(832, $9 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + if ($call17) { + label = 11; + break; + } else { + label = 14; + break; + } + case 11: + $png_ptr19 = $this1 + 16 | 0; + $info_ptr20 = $this1 + 20 | 0; + $end_info21 = $this1 + 24 | 0; + invoke_viii(640, $png_ptr19 | 0, $info_ptr20 | 0, $end_info21 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $row_pointers22 = $this1 + 28 | 0; + $10 = HEAP32[$row_pointers22 >> 2] | 0; + $isnull23 = ($10 | 0) == 0; + if ($isnull23) { + label = 13; + break; + } else { + label = 12; + break; + } + case 12: + $11 = $10; + invoke_vi(926, $11 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + label = 13; + break; + case 13: + $png_ptr26 = $this1 + 16 | 0; + HEAP32[$png_ptr26 >> 2] = 0; + $state27 = $this1 + 32 | 0; + HEAP32[$state27 >> 2] = 3; + $retval = 0; + label = 37; + break; + case 14: + $png_ptr29 = $this1 + 16 | 0; + $12 = HEAP32[$png_ptr29 >> 2] | 0; + $info_ptr30 = $this1 + 20 | 0; + $13 = HEAP32[$info_ptr30 >> 2] | 0; + $call31 = invoke_iiiiiiiiii(2, $12 | 0, $13 | 0, $width | 0, $height | 0, $bit_depth | 0, $color_type | 0, 0 | 0, 0 | 0, 0 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $14 = $outImage_addr; + $call32 = invoke_ii(850, $14 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $data = $call32; + $15 = $outImage_addr; + $call33 = invoke_ii(284, $15 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $bpl = $call33; + $16 = HEAP32[$height >> 2] | 0; + $17$0 = invoke_iii(860, $16 | 0, 4 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $17$1 = tempRet0; + $18 = $17$1; + $19 = $17$0; + $20 = $18 ? -1 : $19; + $call34 = invoke_ii(550, $20 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $21 = $call34; + $row_pointers35 = $this1 + 28 | 0; + HEAP32[$row_pointers35 >> 2] = $21; + $y = 0; + label = 15; + break; + case 15: + $22 = $y; + $23 = HEAP32[$height >> 2] | 0; + $cmp36 = $22 >>> 0 < $23 >>> 0; + if ($cmp36) { + label = 16; + break; + } else { + label = 18; + break; + } + case 16: + $24 = $data; + $25 = $y; + $26 = $bpl; + $mul = Math_imul($25, $26) | 0; + $add_ptr = $24 + $mul | 0; + $27 = $y; + $row_pointers37 = $this1 + 28 | 0; + $28 = HEAP32[$row_pointers37 >> 2] | 0; + $arrayidx = $28 + ($27 << 2) | 0; + HEAP32[$arrayidx >> 2] = $add_ptr; + label = 17; + break; + case 17: + $29 = $y; + $inc = $29 + 1 | 0; + $y = $inc; + label = 15; + break; + case 18: + $png_ptr38 = $this1 + 16 | 0; + $30 = HEAP32[$png_ptr38 >> 2] | 0; + $row_pointers39 = $this1 + 28 | 0; + $31 = HEAP32[$row_pointers39 >> 2] | 0; + invoke_vii(858, $30 | 0, $31 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $32 = $outImage_addr; + $png_ptr40 = $this1 + 16 | 0; + $33 = HEAP32[$png_ptr40 >> 2] | 0; + $info_ptr41 = $this1 + 20 | 0; + $34 = HEAP32[$info_ptr41 >> 2] | 0; + $call42 = invoke_iii(690, $33 | 0, $34 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + invoke_vii(1890, $32 | 0, $call42 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $35 = $outImage_addr; + $png_ptr43 = $this1 + 16 | 0; + $36 = HEAP32[$png_ptr43 >> 2] | 0; + $info_ptr44 = $this1 + 20 | 0; + $37 = HEAP32[$info_ptr44 >> 2] | 0; + $call45 = invoke_iii(256, $36 | 0, $37 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + invoke_vii(2126, $35 | 0, $call45 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $state46 = $this1 + 32 | 0; + HEAP32[$state46 >> 2] = 2; + $png_ptr47 = $this1 + 16 | 0; + $38 = HEAP32[$png_ptr47 >> 2] | 0; + $end_info48 = $this1 + 24 | 0; + $39 = HEAP32[$end_info48 >> 2] | 0; + invoke_vii(36, $38 | 0, $39 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $end_info49 = $this1 + 24 | 0; + $40 = HEAP32[$end_info49 >> 2] | 0; + invoke_vii(2752, $this1 | 0, $40 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $i = 0; + label = 19; + break; + case 19: + $41 = $i; + $readTexts = $this1 + 12 | 0; + $42 = $readTexts; + $call51 = invoke_ii(618, $42 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $sub = $call51 - 1 | 0; + $cmp52 = ($41 | 0) < ($sub | 0); + if ($cmp52) { + label = 20; + break; + } else { + label = 22; + break; + } + case 20: + $43 = $outImage_addr; + $readTexts54 = $this1 + 12 | 0; + $44 = $readTexts54; + $45 = $i; + $call55 = invoke_iii(502, $44 | 0, $45 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $readTexts56 = $this1 + 12 | 0; + $46 = $readTexts56; + $47 = $i; + $add = $47 + 1 | 0; + $call57 = invoke_iii(502, $46 | 0, $add | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + invoke_viii(550, $43 | 0, $call55 | 0, $call57 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + label = 21; + break; + case 21: + $48 = $i; + $add59 = $48 + 2 | 0; + $i = $add59; + label = 19; + break; + case 22: + $png_ptr61 = $this1 + 16 | 0; + $info_ptr62 = $this1 + 20 | 0; + $end_info63 = $this1 + 24 | 0; + invoke_viii(640, $png_ptr61 | 0, $info_ptr62 | 0, $end_info63 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $row_pointers64 = $this1 + 28 | 0; + $49 = HEAP32[$row_pointers64 >> 2] | 0; + $isnull65 = ($49 | 0) == 0; + if ($isnull65) { + label = 24; + break; + } else { + label = 23; + break; + } + case 23: + $50 = $49; + invoke_vi(926, $50 | 0); + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + label = 24; + break; + case 24: + $png_ptr68 = $this1 + 16 | 0; + HEAP32[$png_ptr68 >> 2] = 0; + $state69 = $this1 + 32 | 0; + HEAP32[$state69 >> 2] = 0; + $51 = HEAP32[$color_type >> 2] | 0; + $cmp70 = ($51 | 0) == 3; + if ($cmp70) { + label = 25; + break; + } else { + label = 36; + break; + } + case 25: + $52 = $outImage_addr; + $call72 = invoke_ii(926, $52 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $cmp73 = ($call72 | 0) == 3; + if ($cmp73) { + label = 26; + break; + } else { + label = 36; + break; + } + case 26: + $53 = $outImage_addr; + $call75 = invoke_ii(860, $53 | 0) | 0; + if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) { + setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0; + if ((setjmpLabel | 0) > 0) { + label = -1; + break; + } else return 0 | 0; + } + __THREW__ = threwValue = 0; + $color_table_size = $call75; + $y76 = 0; + label = 27; + break; + case 27: + $54 = $y76; + $55 = HEAP32[$height >> 2] | 0; + $cmp78 = ($54 | 0) < ($55 | 0); + if ($cmp78) { + label = 28; + break; + } else { + label = 35; + break; + } + case 28: + $56 = $data; + $57 = $y76; + $58 = $bpl; + $mul80 = Math_imul($57, $58) | 0; + $add_ptr81 = $56 + $mul80 | 0; + $p = $add_ptr81; + $59 = $p; + $60 = HEAP32[$width >> 2] | 0; + $add_ptr82 = $59 + $60 | 0; + $end = $add_ptr82; + label = 29; + break; + case 29: + $61 = $p; + $62 = $end; + $cmp83 = $61 >>> 0 < $62 >>> 0; + if ($cmp83) { + label = 30; + break; + } else { + label = 33; + break; + } + case 30: + $63 = $p; + $64 = HEAP8[$63] | 0; + $conv = $64 & 255; + $65 = $color_table_size; + $cmp84 = ($conv | 0) >= ($65 | 0); + if ($cmp84) { + label = 31; + break; + } else { + label = 32; + break; + } + case 31: + $66 = $p; + HEAP8[$66] = 0; + label = 32; + break; + case 32: + $67 = $p; + $incdec_ptr = $67 + 1 | 0; + $p = $incdec_ptr; + label = 29; + break; + case 33: + label = 34; + break; + case 34: + $68 = $y76; + $inc88 = $68 + 1 | 0; + $y76 = $inc88; + label = 27; + break; + case 35: + label = 36; + break; + case 36: + $retval = 1; + label = 37; + break; + case 37: + $69 = $retval; + STACKTOP = sp; + return $69 | 0; + case -1: + if ((setjmpLabel | 0) == 6) { + $call8 = threwValue; + label = 38; + } + __THREW__ = threwValue = 0; + break; + } + return 0; +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6", "looop7", "looop8", "multiloop", "multiloop2", "tempDouble2", "watIf", "select2", "binary", "cute"] diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index 5324e15c..b35da99d 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -1603,6 +1603,7 @@ function normalizeAsm(func) { node = node[1]; var name = node[2][1]; if (func[2] && func[2].indexOf(name) < 0) break; // not an assign into a parameter, but a global + if (name in data.params) break; // already done that param, must be starting function body data.params[name] = detectAsmCoercion(node[3]); stats[i] = emptyNode(); i++; @@ -1773,9 +1774,7 @@ function ensureMinifiedNames(n) { // make sure the nth index in minifiedNames ex } } -// Very simple 'registerization', coalescing of variables into a smaller number, -// as part of minification. Globals-level minification began in a previous pass, -// we receive extraInfo which tells us how to rename globals. (Only in asm.js.) +// Very simple 'registerization', coalescing of variables into a smaller number. // // We do not optimize when there are switches, so this pass only makes sense with // relooping. @@ -1811,6 +1810,7 @@ function registerize(ast) { // Replace all var definitions with assignments; we will add var definitions at the top after we registerize // We also mark local variables - i.e., having a var definition var localVars = {}; + var allVars = {}; var hasSwitch = false; // we cannot optimize variables if there is a switch, unless in asm mode traverse(fun, function(node, type) { if (type === 'var') { @@ -1823,74 +1823,25 @@ function registerize(ast) { } } else if (type === 'switch') { hasSwitch = true; + } else if (type === 'name') { + allVars[node[1]] = 1; } }); vacuum(fun); - if (extraInfo && extraInfo.globals) { - assert(asm); - var usedGlobals = {}; - var nextLocal = 0; - // Minify globals using the mapping we were given - traverse(fun, function(node, type) { - if (type === 'name') { - var name = node[1]; - var minified = extraInfo.globals[name]; - if (minified) { - assert(!localVars[name], name); // locals must not shadow globals, or else we don't know which is which - if (localVars[minified]) { - // trying to minify a global into a name used locally. rename all the locals - var newName = '$_newLocal_' + (nextLocal++); - assert(!localVars[newName]); - if (params[minified]) { - params[newName] = 1; - delete params[minified]; - } - localVars[newName] = 1; - delete localVars[minified]; - asmData.vars[newName] = asmData.vars[minified]; - delete asmData.vars[minified]; - asmData.params[newName] = asmData.params[minified]; - delete asmData.params[minified]; - traverse(fun, function(node, type) { - if (type === 'name' && node[1] === minified) { - node[1] = newName; - } - }); - if (fun[2]) { - for (var i = 0; i < fun[2].length; i++) { - if (fun[2][i] === minified) fun[2][i] = newName; - } - } - } - node[1] = minified; - usedGlobals[minified] = 1; - } - } - }); - if (fun[1] in extraInfo.globals) { // if fun was created by a previous optimization pass, it will not be here - fun[1] = extraInfo.globals[fun[1]]; - assert(fun[1]); - } - var nextRegName = 0; - } var regTypes = {}; function getNewRegName(num, name) { - if (!asm) return 'r' + num; - var type = asmData.vars[name]; - if (!extraInfo || !extraInfo.globals) { - var ret = (type ? 'd' : 'i') + num; + var ret; + if (!asm) { + ret = 'r' + num; + } else { + var type = asmData.vars[name]; + ret = (type ? 'd' : 'i') + num; regTypes[ret] = type; - return ret; } - // find the next free minified name that is not used by a global that shows up in this function - while (1) { - ensureMinifiedNames(nextRegName); - var ret = minifiedNames[nextRegName++]; - if (!usedGlobals[ret]) { - regTypes[ret] = type; - return ret; - } + if (ret in allVars) { + assert(ret in localVars, 'register shadows non-local name'); } + return ret; } // Find the # of uses of each variable. // While doing so, check if all a variable's uses are dominated in a simple @@ -2111,37 +2062,1070 @@ function registerize(ast) { } } denormalizeAsm(fun, finalAsmData); - if (extraInfo && extraInfo.globals) { - // minify in asm var definitions, that denormalizeAsm just generated - function minify(value) { - if (value && value[0] === 'call' && value[1][0] === 'name') { - var name = value[1][1]; - var minified = extraInfo.globals[name]; - if (minified) { - value[1][1] = minified; + } + }); +} + + +// Assign variables to 'registers', coalescing them onto a smaller number of shared +// variables. +// +// This does the same job as 'registerize' above, but burns a lot more cycles trying +// to reduce the total number of register variables. Key points about the operation: +// +// * we decompose the AST into a flow graph and perform a full liveness +// analysis, to determine which variables are live at each point. +// +// * variables that are live concurrently are assigned to different registers. +// +// * variables that are linked via 'x=y' style statements are assigned the same +// register if possible, so that the redundant assignment can be removed. +// (e.g. assignments used to pass state around through loops). +// +// * any code that cannot be reached through the flow-graph is removed. +// (e.g. redundant break statements like 'break L123; break;'). +// +// * any assignments that we can prove are not subsequently used are removed. +// (e.g. unnecessary assignments to the 'label' variable). +// +function registerizeHarder(ast) { + assert(asm); + + traverseGeneratedFunctions(ast, function(fun) { + + var asmData = normalizeAsm(fun); + + var localVars = asmData.vars; + for (var name in asmData.params) { + localVars[name] = asmData.params[name]; + } + + // Utilities for allocating register variables. + // We need distinct register pools for each type of variable. + + var allRegsByType = [{}, {}, {}]; + var regPrefixByType = ['i', 'd', 'f']; + var nextReg = 1; + + function createReg(forName) { + // Create a new register of type suitable for the given variable name. + var allRegs = allRegsByType[localVars[forName]]; + reg = nextReg++; + allRegs[reg] = regPrefixByType[localVars[forName]] + reg; + return reg; + } + + // Traverse the tree in execution order and synthesize a basic flow-graph. + // It's convenient to build a kind of "dual" graph where the nodes identify + // the junctions between blocks at which control-flow may branch, and each + // basic block is an edge connecting two such junctions. + // For each junction we store: + // * set of blocks that originate at the junction + // * set of blocks that terminate at the junction + // For each block we store: + // * a single entry junction + // * a single exit junction + // * any preconditions satisfied at entry to the block + // * a 'use' and 'kill' set of names for the block + // * full sequence of 'name' and 'assign' nodes in the block + // * whether each such node appears as part of a larger expression + // (and therefore cannot be safely eliminated) + + var junctions = []; + var blocks = []; + var currEntryJunction = null; + var nextBasicBlock = null; + var isInExpr = 0; + var activeLabels = [{}]; + var nextLoopLabel = null; + + var ENTRY_JUNCTION = 0; + var EXIT_JUNCTION = 1; + var ENTRY_BLOCK = 0; + + function addJunction() { + // Create a new junction, without inserting it into the graph. + // This is useful for e.g. pre-allocating an exit node. + var id = junctions.length; + junctions[id] = {id: id, inblocks: {}, outblocks: {}}; + return id; + } + + function markJunction(id) { + // Mark current traversal location as a junction. + // This makes a new basic block exiting at this position. + if (id === undefined || id === null) { + id = addJunction(); + } + joinJunction(id); + return id; + } + + function setJunction(id) { + // Set the next entry junction to the given id. + // This can be used to enter at a previously-declared point. + assert(nextBasicBlock.nodes.length === 0, 'refusing to abandon an in-progress basic block') + currEntryJunction = id; + } + + function joinJunction(id) { + // Complete the pending basic block by exiting at this position. + // This can be used to exit at a previously-declared point. + if (currEntryJunction !== null) { + nextBasicBlock.id = blocks.length; + nextBasicBlock.entry = currEntryJunction; + nextBasicBlock.exit = id; + junctions[currEntryJunction].outblocks[nextBasicBlock.id] = 1; + junctions[id].inblocks[nextBasicBlock.id] = 1; + blocks.push(nextBasicBlock); + } + nextBasicBlock = { id: null, entry: null, exit: null, pre: {}, nodes: [], isexpr: [], use: {}, kill: {} }; + currEntryJunction = id; + return id; + } + + function pushActiveLabels(onContinue, onBreak) { + // Push the target junctions for continuing/breaking a loop. + // This should be called before traversing into a loop. + var newLabels = copy(activeLabels[activeLabels.length-1]); + newLabels[null] = [onContinue, onBreak]; + if (nextLoopLabel) { + newLabels[nextLoopLabel] = [onContinue, onBreak]; + nextLoopLabel = null; + } + activeLabels.push(newLabels); + } + + function popActiveLabels() { + // Pop the target junctions for continuing/breaking a loop. + // This should be called after traversing into a loop. + activeLabels.pop(); + } + + function markNonLocalJump(type, label) { + // Complete a block via 'return', 'break' or 'continue'. + // This joins the targetted junction and then sets the current junction to null. + // Any code traversed before we get back an existing junction is dead code. + if (type === 'return') { + joinJunction(EXIT_JUNCTION); + } else { + label = label ? label : null; + var targets = activeLabels[activeLabels.length-1][label]; + assert(targets, 'jump to unknown label'); + if (type === 'continue') { + joinJunction(targets[0]); + } else if (type === 'break') { + joinJunction(targets[1]); + } else { + assert(false, 'unknown jump node type'); + } + } + setJunction(null); + } + + function addUseNode(node) { + // Mark a use of the given name node in the current basic block. + assert(node[0] === 'name', 'not a use node'); + var name = node[1]; + if (name in localVars) { + nextBasicBlock.nodes.push(node); + nextBasicBlock.isexpr.push(isInExpr); + if (!nextBasicBlock.kill[name]) { + nextBasicBlock.use[name] = 1; + } + } + } + + function addKillNode(node) { + // Mark an assignment to the given name node in the current basic block. + assert(node[0] === 'assign', 'not a kill node'); + assert(node[1] === true, 'not a kill node'); + assert(node[2][0] === 'name', 'not a kill node'); + var name = node[2][1]; + if (name in localVars) { + nextBasicBlock.nodes.push(node); + nextBasicBlock.isexpr.push(isInExpr); + nextBasicBlock.kill[name] = 1; + } + } + + function lookThroughCasts(node) { + // Look through value-preserving casts, like "x | 0" => "x" + if (node[0] === 'binary' && node[1] === '|') { + if (node[3][0] === 'num' && node[3][1] === 0) { + return lookThroughCasts(node[2]); + } + } + return node; + } + + function addPreCondTrue(node) { + // Add pre-conditions implied by truth of the + // given node to the current basic block. + assert(nextBasicBlock.nodes.length === 0, 'cant add preconditions to an in-progress basic block') + if (node[0] === 'binary' && node[1] === '==') { + var lhs = lookThroughCasts(node[2]); + var rhs = lookThroughCasts(node[3]); + if (lhs[0] === 'name' && rhs[0] === 'num') { + nextBasicBlock.pre[lhs[1]] = ['==', rhs[1]]; + } + } + } + + function addPreCondFalse(node) { + // Add pre-conditions implied by falsehood of the + // given node to the current basic block. + assert(nextBasicBlock.nodes.length === 0, 'cant add preconditions to an in-progress basic block') + if (node[0] === 'binary' && node[1] === '==') { + var lhs = lookThroughCasts(node[2]); + var rhs = lookThroughCasts(node[3]); + if (lhs[0] === 'name' && rhs[0] === 'num') { + nextBasicBlock.pre[lhs[1]] = ['!=', rhs[1]]; + } + } + } + + function isTrueNode(node) { + // Check if the given node is statically truthy. + return (node[0] === 'num' && node[1] != 0); + } + + function isFalseNode(node) { + // Check if the given node is statically falsy. + return (node[0] === 'num' && node[1] == 0); + } + + function morphNode(node, newNode) { + // In-place morph a node into some other type of node. + var i = 0; + while (i < node.length && i < newNode.length) { + node[i] = newNode[i]; + i++; + } + while (i < newNode.length) { + node.push(newNode[i]); + i++; + } + if (node.length > newNode.length) { + node.length = newNode.length; + } + } + + function buildFlowGraph(node) { + // Recursive function to build up the flow-graph. + // It walks the tree in execution order, calling the above state-management + // functions at appropriate points in the traversal. + var type = node[0]; + + // Any code traversed without an active entry junction must be dead, + // as the resulting block could never be entered. Let's remove it. + if (currEntryJunction === null && junctions.length > 0) { + morphNode(node, ['block', []]); + return; + } + + // Traverse each node type according to its particular control-flow semantics. + switch (type) { + case 'defun': + var jEntry = markJunction(); + assert(jEntry === ENTRY_JUNCTION); + var jExit = addJunction(); + assert(jExit === EXIT_JUNCTION); + for (var i = 0; i < node[3].length; i++) { + buildFlowGraph(node[3][i]); + } + joinJunction(jExit); + break; + case 'if': + isInExpr++; + buildFlowGraph(node[1]); + isInExpr--; + var jEnter = markJunction(); + addPreCondTrue(node[1]); + if (node[2]) { + buildFlowGraph(node[2]); + } + var jExit = markJunction(); + setJunction(jEnter); + addPreCondFalse(node[1]); + if (node[3]) { + buildFlowGraph(node[3]); + } + joinJunction(jExit); + break; + case 'conditional': + isInExpr++; + buildFlowGraph(node[1]); + var jEnter = markJunction(); + addPreCondTrue(node[1]); + if (node[2]) { + buildFlowGraph(node[2]); + } + var jExit = markJunction(); + setJunction(jEnter); + addPreCondFalse(node[1]); + if (node[3]) { + buildFlowGraph(node[3]); + } + joinJunction(jExit); + isInExpr--; + break; + case 'while': + // Special-case "while (1) {}" to use fewer junctions, + // since emscripten generates a lot of these. + if (isTrueNode(node[1])) { + var jLoop = markJunction(); + var jExit = addJunction(); + pushActiveLabels(jLoop, jExit); + buildFlowGraph(node[2]); + popActiveLabels(); + joinJunction(jLoop); + setJunction(jExit); + } else { + var jCond = markJunction(); + var jLoop = addJunction(); + var jExit = addJunction(); + isInExpr++; + buildFlowGraph(node[1]); + isInExpr--; + joinJunction(jLoop); + pushActiveLabels(jCond, jExit); + addPreCondTrue(node[1]); + buildFlowGraph(node[2]); + popActiveLabels(); + joinJunction(jCond); + // An empty basic-block linking condition exit to loop exit. + setJunction(jLoop); + joinJunction(jExit); + } + break; + case 'do': + // Special-case "do {} while (1)" and "do {} while (0)" to use + // fewer junctions, since emscripten generates a lot of these. + if (isFalseNode(node[1])) { + var jExit = addJunction(); + pushActiveLabels(jExit, jExit); + buildFlowGraph(node[2]); + popActiveLabels(); + joinJunction(jExit); + } else if (isTrueNode(node[1])) { + var jLoop = markJunction(); + var jExit = addJunction(); + pushActiveLabels(jLoop, jExit); + buildFlowGraph(node[2]); + popActiveLabels(); + joinJunction(jLoop); + setJunction(jExit); + } else { + var jLoop = markJunction(); + var jCond = addJunction(); + var jCondExit = addJunction(); + var jExit = addJunction(); + pushActiveLabels(jCond, jExit); + buildFlowGraph(node[2]); + popActiveLabels(); + joinJunction(jCond); + isInExpr++; + buildFlowGraph(node[1]); + isInExpr--; + joinJunction(jCondExit); + joinJunction(jLoop); + setJunction(jCondExit); + joinJunction(jExit) + } + break; + case 'for': + var jTest = addJunction(); + var jBody = addJunction(); + var jStep = addJunction(); + var jExit = addJunction(); + buildFlowGraph(node[1]); + joinJunction(jTest); + isInExpr++; + buildFlowGraph(node[2]); + isInExpr--; + joinJunction(jBody); + pushActiveLabels(jStep, jExit); + buildFlowGraph(node[4]); + popActiveLabels(); + joinJunction(jStep); + buildFlowGraph(node[3]); + joinJunction(jTest); + setJunction(jBody); + joinJunction(jExit); + break; + case 'label': + assert(node[2][0] in BREAK_CAPTURERS, 'label on non-loop, non-switch statement') + nextLoopLabel = node[1]; + buildFlowGraph(node[2]); + break; + case 'switch': + // This is horrific. It need to capture the default flow-through + // logic of sequential case bodies, as well as the theoretical + // sequential evaluation of each case clause. + // TODO: simplify based on asmjs switch-statement restrictions. + isInExpr++; + buildFlowGraph(node[1]); + isInExpr--; + var jCheckExit = markJunction(); + var jExit = addJunction(); + pushActiveLabels(null, jExit); + // Process all cases as a sequential chain of checks. + // Process all case bodies as one big flow-through statement. + // They might break themselves out of it but this implements the + // default fall-through case logic. + var hasDefault = false; + var jPrevCaseExit = jCheckExit; + var jPrevBodyExit = jCheckExit; + for (var i=0; i<node[2].length; i++) { + // In the general case we'll need a basic block for the case clause. + // Try to avoid it for common, simple, non-var-using cases. + if (!node[2][i][0]) { + hasDefault = true; + } else { + if (node[2][i][0][0] !== 'num') { + setJunction(jPrevCaseExit); + isInExpr++; + buildFlowGraph(node[2][i][0]); + isInExpr--; + jPrevCaseExit = markJunction(); + } + } + // The next case body flows from the exit of the prev one, + // or may be entered directly from the case statement exit. + setJunction(jPrevCaseExit); + if (jPrevBodyExit !== jCheckExit) { + joinJunction(jPrevBodyExit); + } + for (var j = 0; j < node[2][i][1].length; j++) { + buildFlowGraph(node[2][i][1][j]); } + jPrevBodyExit = markJunction(); } + markJunction(jExit); + // If there was no default case, we also need an empty block + // linking straight from entry to exit. + if (!hasDefault && jCheckExit !== jPrevBodyExit) { + setJunction(jCheckExit); + joinJunction(jExit); + } + popActiveLabels() + break; + case 'return': + if (node[1]) { + isInExpr++; + buildFlowGraph(node[1]); + isInExpr--; + } + markNonLocalJump(type); + break; + case 'break': + case 'continue': + markNonLocalJump(type, node[1]); + break; + case 'assign': + isInExpr++; + buildFlowGraph(node[3]); + isInExpr--; + if (node[1] === true && node[2][0] === 'name') { + addKillNode(node); + } else { + buildFlowGraph(node[2]); + } + break; + case 'name': + addUseNode(node); + break; + case 'block': + case 'toplevel': + if (node[1]) { + for (var i = 0; i < node[1].length; i++) { + buildFlowGraph(node[1][i]); + } + } + break; + case 'stat': + buildFlowGraph(node[1]); + break; + case 'unary-prefix': + case 'unary-postfix': + isInExpr++; + buildFlowGraph(node[2]); + isInExpr--; + break; + case 'binary': + isInExpr++; + buildFlowGraph(node[2]); + buildFlowGraph(node[3]); + isInExpr--; + break; + case 'call': + isInExpr++; + buildFlowGraph(node[1]); + if (node[2]) { + for (var i = 0; i < node[2].length; i++) { + buildFlowGraph(node[2][i]); + } + } + isInExpr--; + break; + case 'seq': + case 'sub': + isInExpr++; + buildFlowGraph(node[1]); + buildFlowGraph(node[2]); + isInExpr--; + break; + case 'dot': + case 'throw': + isInExpr++; + buildFlowGraph(node[1]); + isInExpr--; + break; + case 'num': + case 'string': + case 'var': + break; + default: + printErr(JSON.stringify(node)); + assert(false, 'unsupported node type: ' + type); + } + } + buildFlowGraph(fun); + + assert(setSize(junctions[ENTRY_JUNCTION].inblocks) === 0, 'function entry must have no incoming blocks'); + assert(setSize(junctions[EXIT_JUNCTION].outblocks) === 0, 'function exit must have no outgoing blocks'); + assert(blocks[ENTRY_BLOCK].entry === ENTRY_JUNCTION, 'block zero must be the initial block'); + + // Fix up implicit jumps done by assigning to the 'label' variable. + // If a block ends with an assignment to 'label' and there's another block + // with that value of 'label' as precondition, we tweak the flow graph so + // that the former jumps straight to the later. + + var labelledBlocks = {}; + var labelledJumps = []; + FINDLABELLEDBLOCKS: + for (var i = 0; i < blocks.length; i++) { + var block = blocks[i]; + // Does it have a specific label value as precondition? + var labelCond = block.pre['label']; + if (labelCond && labelCond[0] === '==') { + // If there are multiple blocks with the same label, all bets are off. + // This seems to happen sometimes for short blocks that end with a return. + if (labelCond[1] in labelledBlocks) { + labelledBlocks = {}; + labelledJumps = []; + break FINDLABELLEDBLOCKS; } - var stats = fun[3]; - for (var i = 0; i < stats.length; i++) { - var line = stats[i]; - if (i >= fun[2].length && line[0] !== 'var') break; // when we pass the arg and var coercions, break - if (line[0] === 'stat') { - assert(line[1][0] === 'assign'); - minify(line[1][3]); + labelledBlocks[labelCond[1]] = block; + } + // Does it assign a specific label value at exit? + if ('label' in block.kill) { + var finalNode = block.nodes[block.nodes.length - 1]; + if (finalNode[0] === 'assign' && finalNode[2][1] === 'label') { + // If labels are computed dynamically then all bets are off. + // This can happen due to indirect branching in llvm output. + if (finalNode[3][0] !== 'num') { + labelledBlocks = {}; + labelledJumps = []; + break FINDLABELLEDBLOCKS; + } + labelledJumps.push([finalNode[3][1], block]); + } else { + // If label is assigned a non-zero value elsewhere in the block + // then all bets are off. This can happen e.g. due to outlining + // saving/restoring label to the stack. + for (var j = 0; j < block.nodes.length - 1; j++) { + if (block.nodes[j][0] === 'assign' && block.nodes[j][2][1] === 'label') { + if (block.nodes[j][3][0] !== 'num' && block.nodes[j][3][1] !== 0) { + labelledBlocks = {}; + labelledJumps = []; + break FINDLABELLEDBLOCKS; + } + } + } + } + } + } + for (var labelVal in labelledBlocks) { + var block = labelledBlocks[labelVal]; + // Disconnect it from the graph, and create a + // new junction for jumps targetting this label. + delete junctions[block.entry].outblocks[block.id]; + block.entry = addJunction(); + junctions[block.entry].outblocks[block.id] = 1; + // Add a fake use of 'label' to keep it alive in predecessor. + block.use['label'] = 1; + block.nodes.unshift(['name', 'label']); + block.isexpr.unshift(1); + } + for (var i = 0; i < labelledJumps.length; i++) { + var labelVal = labelledJumps[i][0]; + var block = labelledJumps[i][1]; + var targetBlock = labelledBlocks[labelVal]; + if (targetBlock) { + // Redirect its exit to entry of the target block. + delete junctions[block.exit].inblocks[block.id]; + block.exit = targetBlock.entry; + junctions[block.exit].inblocks[block.id] = 1; + } + } + labelledBlocks = null; + labelledJumps = null; + + // Do a backwards data-flow analysis to determine the set of live + // variables at each junction, and to use this information to eliminate + // any unused assignments. + // We run two nested phases. The inner phase builds the live set for each + // junction. The outer phase uses this to try to eliminate redundant + // stores in each basic block, which might in turn affect liveness info. + + function analyzeJunction(junc) { + // Update the live set for this junction. + var live = {}; + for (var b in junc.outblocks) { + var block = blocks[b]; + var liveSucc = junctions[block.exit].live || {}; + for (var name in liveSucc) { + if (!(name in block.kill)) { + live[name] = 1; + } + } + for (var name in block.use) { + live[name] = 1; + } + } + junc.live = live; + } + + function analyzeBlock(block) { + // Update information about the behaviour of the block. + // This includes the standard 'use' and 'kill' information, + // plus a 'link' set naming values that flow through from entry + // to exit, possibly changing names via simple 'x=y' assignments. + // As we go, we eliminate assignments if the variable is not + // subsequently used. + var live = copy(junctions[block.exit].live); + var use = {}; + var kill = {}; + var link = {}; + var lastUseLoc = {}; + var firstDeadLoc = {}; + var lastKillLoc = {}; + for (var name in live) { + link[name] = name; + lastUseLoc[name] = block.nodes.length; + firstDeadLoc[name] = block.nodes.length; + } + for (var j = block.nodes.length - 1; j >=0 ; j--) { + var node = block.nodes[j]; + if (node[0] === 'name') { + var name = node[1]; + live[name] = 1; + use[name] = j; + if (lastUseLoc[name] === undefined) { + lastUseLoc[name] = j; + firstDeadLoc[name] = j; + } + } else { + var name = node[2][1]; + // We only keep assignments if they will be subsequently used. + if (name in live) { + kill[name] = 1; + delete use[name]; + delete live[name]; + firstDeadLoc[name] = j; + if (lastUseLoc[name] === undefined) { + lastUseLoc[name] = j; + } + if (lastKillLoc[name] === undefined) { + lastKillLoc[name] = j; + } + // If it's an "x=y" and "y" is not live, then we can create a + // flow-through link from "y" to "x". If not then there's no + // flow-through link for "x". + var oldLink = link[name]; + if (oldLink) { + delete link[name]; + if (node[3][0] === 'name') { + if (node[3][1] in localVars) { + link[node[3][1]] = oldLink; + } + } + } + } else { + // The result of this assignment is never used, so delete it. + // We may need to keep the RHS for its value or its side-effects. + function removeUnusedNodes(j, n) { + for (var name in lastUseLoc) { + lastUseLoc[name] -= n; + } + for (var name in lastKillLoc) { + lastKillLoc[name] -= n; + } + for (var name in firstDeadLoc) { + firstDeadLoc[name] -= n; + } + block.nodes.splice(j, n); + block.isexpr.splice(j, n); + } + if (block.isexpr[j] || hasSideEffects(node[3])) { + morphNode(node, node[3]); + removeUnusedNodes(j, 1); + } else { + var numUsesInExpr = 0; + traverse(node[3], function(node, type) { + if (type === 'name' && node[1] in localVars) { + numUsesInExpr++; + } + }); + morphNode(node, ['block', []]); + j = j - numUsesInExpr; + removeUnusedNodes(j, 1 + numUsesInExpr); + } + } + } + } + block.use = use; + block.kill = kill; + block.link = link; + block.lastUseLoc = lastUseLoc; + block.firstDeadLoc = firstDeadLoc; + block.lastKillLoc = lastKillLoc; + } + + var jWorklistMap = { EXIT_JUNCTION: 1 }; + var jWorklist = [EXIT_JUNCTION]; + var bWorklistMap = {}; + var bWorklist = []; + + // Be sure to visit every junction at least once. + // This avoids missing some vars because we disconnected them + // when processing the labelled jumps. + for (var i = junctions.length - 1; i >= EXIT_JUNCTION; i--) { + jWorklistMap[i] = 1; + jWorklist.push(i); + } + + while (jWorklist.length > 0) { + // 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. + while (jWorklist.length > 0) { + var junc = junctions[jWorklist.pop()]; + delete jWorklistMap[junc.id]; + var oldLive = junc.live || null; + analyzeJunction(junc); + if (!sortedJsonCompare(oldLive, junc.live)) { + // Live set changed, updated predecessor blocks and junctions. + for (var b in junc.inblocks) { + if (!(b in bWorklistMap)) { + bWorklistMap[b] = 1; + bWorklist.push(b); + } + var jPred = blocks[b].entry; + if (!(jPred in jWorklistMap)) { + jWorklistMap[jPred] = 1; + jWorklist.push(jPred); + } + } + } + } + // Now update the blocks based on the calculated live sets. + while (bWorklist.length > 0) { + var block = blocks[bWorklist.pop()]; + delete bWorklistMap[block.id]; + var oldUse = block.use; + analyzeBlock(block); + if (!sortedJsonCompare(oldUse, block.use)) { + // The use set changed, re-process the entry junction. + if (!(block.entry in jWorklistMap)) { + jWorklistMap[block.entry] = 1; + jWorklist.push(block.entry); + } + } + } + } + + // Insist that all function parameters are alive at function entry. + // This ensures they will be assigned independent registers, even + // if they happen to be unused. + + for (var name in asmData.params) { + junctions[ENTRY_JUNCTION].live[name] = 1; + } + + // For variables that are live at one or more junctions, we assign them + // a consistent register for the entire scope of the function. Find pairs + // of variable that cannot use the same register (the "conflicts") as well + // as pairs of variables that we'd like to have share the same register + // (the "links"). + + var junctionVariables = {}; + + function initializeJunctionVariable(name) { + junctionVariables[name] = { conf: {}, link: {}, excl: {}, reg: null }; + } + + for (var i = 0; i < junctions.length; i++) { + var junc = junctions[i]; + for (var name in junc.live) { + if (!junctionVariables[name]) initializeJunctionVariable(name); + // It conflicts with all other names live at this junction. + for (var otherName in junc.live) { + if (otherName == name) continue; + junctionVariables[name].conf[otherName] = 1; + } + for (var b in junc.outblocks) { + // It conflits with any output vars of successor blocks, + // if they're assigned before it goes dead in that block. + block = blocks[b]; + var jSucc = junctions[block.exit]; + for (var otherName in jSucc.live) { + if (junc.live[otherName]) continue; + if (block.lastKillLoc[otherName] < block.firstDeadLoc[name]) { + if (!junctionVariables[otherName]) initializeJunctionVariable(otherName); + junctionVariables[name].conf[otherName] = 1; + junctionVariables[otherName].conf[name] = 1; + } + } + // It links with any linkages in the outgoing blocks. + var linkName = block.link[name]; + if (linkName && linkName !== name) { + if (!junctionVariables[linkName]) initializeJunctionVariable(linkName); + junctionVariables[name].link[linkName] = 1; + junctionVariables[linkName].link[name] = 1; + } + } + } + } + + // Attempt to sort the junction variables to heuristically reduce conflicts. + // Simple starting point: handle the most-conflicted variables first. + // This seems to work pretty well. + + var sortedJunctionVariables = keys(junctionVariables); + sortedJunctionVariables.sort(function(name1, name2) { + var jv1 = junctionVariables[name1]; + var jv2 = junctionVariables[name2]; + if (jv1.numConfs === undefined) { + jv1.numConfs = setSize(jv1.conf); + } + if (jv2.numConfs === undefined) { + jv2.numConfs = setSize(jv2.conf); + } + return jv2.numConfs - jv1.numConfs; + }); + + // We can now assign a register to each junction variable. + // Process them in order, trying available registers until we find + // one that works, and propagating the choice to linked/conflicted + // variables as we go. + + function tryAssignRegister(name, reg) { + // Try to assign the given register to the given variable, + // and propagate that choice throughout the graph. + // Returns true if successful, false if there was a conflict. + var jv = junctionVariables[name]; + if (jv.reg !== null) { + return jv.reg === reg; + } + if (jv.excl[reg]) { + return false; + } + jv.reg = reg; + // Exclude use of this register at all conflicting variables. + for (var confName in jv.conf) { + junctionVariables[confName].excl[reg] = 1; + } + // Try to propagate it into linked variables. + // It's not an error if we can't. + for (var linkName in jv.link) { + tryAssignRegister(linkName, reg); + } + return true; + } + + NEXTVARIABLE: + for (var i = 0; i < sortedJunctionVariables.length; i++) { + var name = sortedJunctionVariables[i]; + // It may already be assigned due to linked-variable propagation. + if (junctionVariables[name].reg !== null) { + continue NEXTVARIABLE; + } + // Try to use existing registers first. + var allRegs = allRegsByType[localVars[name]]; + for (var reg in allRegs) { + if (tryAssignRegister(name, reg)) { + continue NEXTVARIABLE; + } + } + // They're all taken, create a new one. + tryAssignRegister(name, createReg(name)); + } + + // Each basic block can now be processed in turn. + // There may be internal-use-only variables that still need a register + // assigned, but they can be treated just for this block. We know + // that all inter-block variables are in a good state thanks to + // junction variable consistency. + + for (var i = 0; i < blocks.length; i++) { + var block = blocks[i]; + if (block.nodes.length === 0) continue; + var jEnter = junctions[block.entry]; + var jExit = junctions[block.exit]; + // Calculate the full internal liveness states for this block. + var liveness = [{}]; + for (var name in jExit.live) { + liveness[0][name] = 1; + } + for (var j=block.nodes.length-1; j>=0; j--) { + var node = block.nodes[j]; + liveness.unshift(copy(liveness[0])); + if (node[0] === 'assign') { + var name = node[2][1]; + delete liveness[0][name]; + } else if (node[0] === 'name') { + var name = node[1]; + liveness[0][name] = 1; + } else { + assert(false, 'unexpected node type: ' + node[0]); + } + } + assert(liveness.length == block.nodes.length + 1); + assert(setSize(setSub(liveness[0], jEnter.live)) == 0); + // Mark the point at which each output reg gets assigned. + // Variables that live past this point must not be assigned + // to that register. + var outputAssignLoc = {}; + var outputVars = {}; + for (var name in jExit.live) { + var reg = junctionVariables[name].reg; + assert(reg !== null, 'output variable doesnt have a register'); + outputAssignLoc[reg] = block.lastKillLoc[name]; + outputVars[reg] = name; + } + // Scan through in execution order, allocating registers on demand. + // Be careful to avoid conflicts with the output registers. + // We consume free registers in last-used order, which helps to + // eliminate "x=y" assignments that are the last use of "y". + var assignedRegs = {}; + var freeRegsByType = copy(allRegsByType); + // Begin with all live vars assigned per the entry-point. + for (var name in liveness[0]) { + var reg = junctionVariables[name].reg; + assert(reg !== null, 'input variable doesnt have a register'); + assignedRegs[name] = reg; + delete freeRegsByType[localVars[name]][reg]; + } + for (var j = 0; j < freeRegsByType.length; j++) { + freeRegsByType[j] = keys(freeRegsByType[j]); + } + // Scan through the nodes in sequence, modifying each node in-place + // and freeing registers according to the calculated liveness info. + for (var j = 0; j < block.nodes.length; j++) { + var node = block.nodes[j]; + var name = node[0] === 'assign' ? node[2][1] : node[1]; + var allRegs = allRegsByType[localVars[name]]; + var freeRegs = freeRegsByType[localVars[name]]; + var reg = assignedRegs[name]; + if (node[0] === 'name') { + // A use. It should already be in a register. + assert(liveness[j][name], 'use node, but name was not alive?') + assert(reg, 'live variable did not have a reg?') + node[1] = allRegs[reg]; + } else { + // A kill. This should assign it a new register. + assert(!liveness[j][name], 'kill node, but name was alive?') + assert(!reg, 'non-live variable still had a reg?') + if (name in jExit.live && j === block.lastKillLoc[name]) { + // Assignment to an output variable, must use pre-assigned reg. + reg = junctionVariables[name].reg; + assignedRegs[name] = reg; + for (var k = freeRegs.length - 1; k >= 0; k--) { + if (freeRegs[k] === reg) { + freeRegs.splice(k, 1); + break; + } + } } else { - assert(line[0] === 'var'); - var pairs = line[1]; - for (var j = 0; j < pairs.length; j++) { - minify(pairs[j][1]); + // Try to use one of the existing free registers. + // It must not conflict with an output register. + for (var k = freeRegs.length - 1; k >= 0; k--) { + reg = freeRegs[k]; + // Check for conflict with output registers. + if (block.lastUseLoc[name] > outputAssignLoc[reg]) { + if (name !== outputVars[reg]) { + continue; + } + } + // Found one! + assignedRegs[name] = reg; + freeRegs.splice(k, 1); + break; + } + // If we didn't find a suitable register, create a new one. + if (!assignedRegs[name]) { + reg = createReg(name); + assignedRegs[name] = reg; } } + // Modify assignment to use the new name. + // If we happen to create a "x=x" type do-nothing assignment, + // we can safely morph it into a no-op. + node[2][1] = allRegs[reg]; + if (node[3][0] === 'name' && node[3][1] === node[2][1]) { + morphNode(node, ['block', []]); + } } + // Free the reg if it's not live in the next step. + if (!liveness[j+1][name]) { + delete assignedRegs[name]; + freeRegs.push(reg); + } + } + } + + // Assign registers to function params based on entry junction + + var paramRegs = {} + if (fun[2]) { + for (var i = 0; i < fun[2].length; i++) { + var allRegs = allRegsByType[localVars[fun[2][i]]]; + fun[2][i] = allRegs[junctionVariables[fun[2][i]].reg]; + paramRegs[fun[2][i]] = 1; + } + } + + // That's it! + // Re-construct the function with appropriate variable definitions. + + var finalAsmData = { + params: {}, + vars: {}, + inlines: asmData.inlines, + }; + for (var i = 1; i < nextReg; i++) { + var reg; + for (var type=0; type<allRegsByType.length; type++) { + reg = allRegsByType[type][i]; + if (reg) break; + } + if (!paramRegs[reg]) { + finalAsmData.vars[reg] = type; + } else { + finalAsmData.params[reg] = type; } } + denormalizeAsm(fun, finalAsmData); + + vacuum(fun); + }); } + // Eliminator aka Expressionizer // // The goal of this pass is to eliminate unneeded variables (which represent one of the infinite registers in the LLVM @@ -2322,7 +3306,7 @@ function eliminate(ast, memSafe) { var memoryInvalidated = false; var callsInvalidated = false; function track(name, value, defNode) { // add a potential that has just been defined to the tracked list, we hope to eliminate it - var usesGlobals = false, usesMemory = false, deps = {}, doesCall = false; + var usesGlobals = false, usesMemory = false, deps = {}, doesCall = false, hasDeps = false; var ignoreName = false; // one-time ignorings of names, as first op in sub and call traverse(value, function(node, type) { if (type === 'name') { @@ -2333,6 +3317,7 @@ function eliminate(ast, memSafe) { } if (!(name in potentials)) { // deps do not matter for potentials - they are defined once, so no complexity deps[name] = 1; + hasDeps = true; } } else { ignoreName = false; @@ -2354,6 +3339,7 @@ function eliminate(ast, memSafe) { usesMemory: usesMemory, defNode: defNode, deps: deps, + hasDeps: hasDeps, doesCall: doesCall }; globalsInvalidated = false; @@ -2426,7 +3412,7 @@ function eliminate(ast, memSafe) { function traverseInOrder(node, ignoreSub, ignoreName) { if (abort) return; //nesting++; // printErr-related - //printErr(spaces(2*(nesting+1)) + 'trav: ' + JSON.stringify(node).substr(0, 50) + ' : ' + keys(tracked) + ' : ' + [allowTracking, ignoreSub, ignoreName]); + //printErr(JSON.stringify(node).substr(0, 50) + ' : ' + keys(tracked) + ' : ' + [allowTracking, ignoreSub, ignoreName]); var type = node[0]; if (type === 'assign') { var target = node[2]; @@ -2602,6 +3588,8 @@ function eliminate(ast, memSafe) { traverseInOrder(node[3]); } else if (type === 'switch') { traverseInOrder(node[1]); + var originalTracked = {}; + for (var o in tracked) originalTracked[o] = 1; var cases = node[2]; for (var i = 0; i < cases.length; i++) { var c = cases[i]; @@ -2610,6 +3598,15 @@ function eliminate(ast, memSafe) { for (var j = 0; j < stats.length; j++) { traverseInOrder(stats[j]); } + // We cannot track from one switch case into another, undo all new trackings TODO: general framework here, use in if-else as well + for (var t in tracked) { + if (!(t in originalTracked)) { + var info = tracked[t]; + if (info.usesGlobals || info.usesMemory || info.hasDeps) { + delete tracked[t]; + } + } + } } } else { if (!(type in ABORTING_ELIMINATOR_SCAN_NODES)) { @@ -2900,6 +3897,111 @@ function minifyGlobals(ast) { suffix = '// EXTRA_INFO:' + JSON.stringify(minified); } + +function minifyLocals(ast) { + assert(asm) + assert(extraInfo && extraInfo.globals) + + traverseGeneratedFunctions(ast, function(fun, type) { + + // Analyse the asmjs to figure out local variable names, + // but operate on the original source tree so that we don't + // miss any global names in e.g. variable initializers. + var asmData = normalizeAsm(fun); denormalizeAsm(fun, asmData); // TODO: we can avoid modifying at all here - we just need a list of local vars+params + var newNames = {}; + var usedNames = {}; + + // Find all the globals that we need to minify using + // pre-assigned names. Don't actually minify them yet + // as that might interfere with local variable names. + function isLocalName(name) { + return name in asmData.vars || name in asmData.params; + } + traverse(fun, function(node, type) { + if (type === 'name') { + var name = node[1]; + if (!isLocalName(name)) { + var minified = extraInfo.globals[name]; + if (minified){ + newNames[name] = minified; + usedNames[minified] = 1; + } + } + } + }); + + // The first time we encounter a local name, we assign it a + // minified name that's not currently in use. Allocating on + // demand means they're processed in a predicatable order, + // which is very handy for testing/debugging purposes. + var nextMinifiedName = 0; + function getNextMinifiedName() { + var minified; + while (1) { + ensureMinifiedNames(nextMinifiedName); + minified = minifiedNames[nextMinifiedName++]; + // TODO: we can probably remove !isLocalName here + if (!usedNames[minified] && !isLocalName(minified)) { + return minified; + } + } + } + + // We can also minify loop labels, using a separate namespace + // to the variable declarations. + var newLabels = {}; + var nextMinifiedLabel = 0; + function getNextMinifiedLabel() { + ensureMinifiedNames(nextMinifiedLabel); + return minifiedNames[nextMinifiedLabel++]; + } + + // Traverse and minify all names. + if (fun[1] in extraInfo.globals) { + fun[1] = extraInfo.globals[fun[1]]; + assert(fun[1]); + } + if (fun[2]) { + for (var i = 0; i < fun[2].length; i++) { + var minified = getNextMinifiedName(); + newNames[fun[2][i]] = minified; + fun[2][i] = minified; + } + } + traverse(fun[3], function(node, type) { + if (type === 'name') { + var name = node[1]; + var minified = newNames[name]; + if (minified) { + node[1] = minified; + } else if (isLocalName(name)) { + minified = getNextMinifiedName(); + newNames[name] = minified; + node[1] = minified; + } + } else if (type === 'var') { + node[1].forEach(function(defn) { + var name = defn[0]; + if (!(name in newNames)) { + newNames[name] = getNextMinifiedName(); + } + defn[0] = newNames[name]; + }); + } else if (type === 'label') { + if (!newLabels[node[1]]) { + newLabels[node[1]] = getNextMinifiedLabel(); + } + node[1] = newLabels[node[1]]; + } else if (type === 'break' || type === 'continue') { + if (node[1]) { + node[1] = newLabels[node[1]]; + } + } + }); + + }); +} + // Relocation pass for a shared module (for the functions part of the module) // // 1. Replace function names with alternate names as defined (to avoid colliding with @@ -3117,8 +4219,8 @@ function aggressiveVariableEliminationInternal(func, asmData) { var name = node[1]; if (name in trivials) { var value = values[name]; - if (!value) throw 'missing value: ' + [func[1], name, values[name]] + ' - faulty reliance on asm zero-init?'; - return copy(value); // must copy, or else the same object can be used multiple times + if (value) return copy(value); // must copy, or else the same object can be used multiple times + else return emptyNode(); } } }); @@ -3866,6 +4968,113 @@ function outline(ast) { }); } +function safeHeap(ast) { + function fixPtr(ptr, heap) { + switch (heap) { + case 'HEAP8': case 'HEAPU8': break; + case 'HEAP16': case 'HEAPU16': { + if (ptr[0] === 'binary') { + assert(ptr[1] === '>>' && ptr[3][0] === 'num' && ptr[3][1] === 1); + ptr = ptr[2]; // skip the shift + } else { + ptr = ['binary', '*', ptr, ['num', 2]]; // was unshifted, convert to absolute address + } + break; + } + case 'HEAP32': case 'HEAPU32': { + if (ptr[0] === 'binary') { + assert(ptr[1] === '>>' && ptr[3][0] === 'num' && ptr[3][1] === 2); + ptr = ptr[2]; // skip the shift + } else { + ptr = ['binary', '*', ptr, ['num', 4]]; // was unshifted, convert to absolute address + } + break; + } + case 'HEAPF32': { + if (ptr[0] === 'binary') { + assert(ptr[1] === '>>' && ptr[3][0] === 'num' && ptr[3][1] === 2); + ptr = ptr[2]; // skip the shift + } else { + ptr = ['binary', '*', ptr, ['num', 4]]; // was unshifted, convert to absolute address + } + break; + } + case 'HEAPF64': { + if (ptr[0] === 'binary') { + assert(ptr[1] === '>>' && ptr[3][0] === 'num' && ptr[3][1] === 3); + ptr = ptr[2]; // skip the shift + } else { + ptr = ['binary', '*', ptr, ['num', 8]]; // was unshifted, convert to absolute address + } + break; + } + default: throw 'bad heap ' + heap; + } + ptr = ['binary', '|', ptr, ['num', 0]]; + return ptr; + } + traverseGenerated(ast, function(node, type) { + if (type === 'assign') { + if (node[1] === true && node[2][0] === 'sub') { + var heap = node[2][1][1]; + var ptr = fixPtr(node[2][2], heap); + var value = node[3]; + // SAFE_HEAP_STORE(ptr, value, bytes, isFloat) + switch (heap) { + case 'HEAP8': case 'HEAPU8': { + return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_INT), ['num', 1], ['num', '0']]]; + } + case 'HEAP16': case 'HEAPU16': { + return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_INT), ['num', 2], ['num', '0']]]; + } + case 'HEAP32': case 'HEAPU32': { + return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_INT), ['num', 4], ['num', '0']]]; + } + case 'HEAPF32': { + return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_DOUBLE), ['num', 4], ['num', '1']]]; + } + case 'HEAPF64': { + return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_DOUBLE), ['num', 8], ['num', '1']]]; + } + default: throw 'bad heap ' + heap; + } + } + } else if (type === 'sub') { + var heap = node[1][1]; + if (heap[0] !== 'H') return; + var ptr = fixPtr(node[2], heap); + // SAFE_HEAP_LOAD(ptr, bytes, isFloat) + switch (heap) { + case 'HEAP8': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '0']]], ASM_INT); + } + case 'HEAPU8': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '1']]], ASM_INT); + } + case 'HEAP16': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '0']]], ASM_INT); + } + case 'HEAPU16': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '1']]], ASM_INT); + } + case 'HEAP32': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '0']]], ASM_INT); + } + case 'HEAPU32': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '1']]], ASM_INT); + } + case 'HEAPF32': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '1'], ['num', '0']]], ASM_DOUBLE); + } + case 'HEAPF64': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 8], ['num', '1'], ['num', '0']]], ASM_DOUBLE); + } + default: throw 'bad heap ' + heap; + } + } + }); +} + // Last pass utilities // Change +5 to DOT$ZERO(5). We then textually change 5 to 5.0 (uglify's ast cannot differentiate between 5 and 5.0 directly) @@ -3956,6 +5165,7 @@ function asmLastOpts(ast) { var minifyWhitespace = false, printMetadata = true, asm = false, last = false; var passes = { + // passes dumpAst: dumpAst, dumpSrc: dumpSrc, unGlobalize: unGlobalize, @@ -3967,12 +5177,17 @@ var passes = { hoistMultiples: hoistMultiples, loopOptimizer: loopOptimizer, registerize: registerize, + registerizeHarder: registerizeHarder, eliminate: eliminate, eliminateMemSafe: eliminateMemSafe, aggressiveVariableElimination: aggressiveVariableElimination, minifyGlobals: minifyGlobals, + minifyLocals: minifyLocals, relocate: relocate, outline: outline, + safeHeap: safeHeap, + + // flags minifyWhitespace: function() { minifyWhitespace = true }, noPrintMetadata: function() { printMetadata = false }, asm: function() { asm = true }, diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index d5b1df27..e030b707 100644 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -26,7 +26,7 @@ class Minifier: ''' asm.js minification support. We calculate minification of globals here, then pass that into the parallel js-optimizer.js runners which - during registerize perform minification of locals. + perform minification of locals. ''' def __init__(self, js, js_engine): @@ -117,9 +117,9 @@ def run_on_js(filename, passes, js_engine, jcache, source_map=False, extra_info= know_generated = suffix or start_funcs >= 0 - minify_globals = 'registerizeAndMinify' in passes and 'asm' in passes + minify_globals = 'minifyNames' in passes and 'asm' in passes if minify_globals: - passes = map(lambda p: p if p != 'registerizeAndMinify' else 'registerize', passes) + passes = map(lambda p: p if p != 'minifyNames' else 'minifyLocals', passes) start_asm = js.find(start_asm_marker) end_asm = js.rfind(end_asm_marker) assert (start_asm >= 0) == (end_asm >= 0) @@ -342,6 +342,7 @@ EMSCRIPTEN_FUNCS(); return filename def run(filename, passes, js_engine=shared.NODE_JS, jcache=False, source_map=False, extra_info=None): + js_engine = shared.listify(js_engine) return temp_files.run_and_clean(lambda: run_on_js(filename, passes, js_engine, jcache, source_map, extra_info)) if __name__ == '__main__': diff --git a/tools/shared.py b/tools/shared.py index 5f7e591c..e28a66c3 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.8.9' +EMSCRIPTEN_VERSION = '1.9.3' def generate_sanity(): return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT + '|' + get_clang_version() @@ -809,12 +809,6 @@ class Settings2(type): self.attrs['DISABLE_EXCEPTION_CATCHING'] = 1 self.attrs['RELOOP'] = 1 self.attrs['ALIASING_FUNCTION_POINTERS'] = 1 - if opt_level >= 3: - # Aside from these, -O3 also runs closure compiler and llvm lto - self.attrs['FORCE_ALIGNED_MEMORY'] = 1 - self.attrs['DOUBLE_MODE'] = 0 - self.attrs['PRECISE_I64_MATH'] = 0 - if noisy: logging.warning('Applying some potentially unsafe optimizations! (Use -O2 if this fails.)') def __getattr__(self, attr): if attr in self.attrs: @@ -1568,7 +1562,7 @@ JCache = cache.JCache(Cache) chunkify = cache.chunkify class JS: - memory_initializer_pattern = '/\* memory initializer \*/ allocate\(([\d,\.concat\(\)\[\]\\n ]+)"i8", ALLOC_NONE, ([\dRuntime\.GLOBAL_BASEH+]+)\)' + memory_initializer_pattern = '/\* memory initializer \*/ allocate\(\[([\d, ]+)\], "i8", ALLOC_NONE, ([\d+Runtime\.GLOBAL_BASEH]+)\);' no_memory_initializer_pattern = '/\* no memory initializer \*/' memory_staticbump_pattern = 'STATICTOP = STATIC_BASE \+ (\d+);' @@ -1652,6 +1646,75 @@ class JS: while x % by != 0: x += 1 return x + INITIALIZER_CHUNK_SIZE = 10240 + + @staticmethod + def collect_initializers(src): + ret = [] + max_offset = -1 + for init in re.finditer(JS.memory_initializer_pattern, src): + contents = init.group(1).split(',') + offset = sum([int(x) if x[0] != 'R' else 0 for x in init.group(2).split('+')]) + ret.append((offset, contents)) + assert offset > max_offset + max_offset = offset + return ret + + @staticmethod + def split_initializer(contents): + # given a memory initializer (see memory_initializer_pattern), split it up into multiple initializers to avoid long runs of zeros or a single overly-large allocator + ret = [] + l = len(contents) + maxx = JS.INITIALIZER_CHUNK_SIZE + i = 0 + start = 0 + while 1: + if i - start >= maxx or (i > start and i == l): + #print >> sys.stderr, 'new', start, i-start + ret.append((start, contents[start:i])) + start = i + if i == l: break + if contents[i] != '0': + i += 1 + else: + # look for a sequence of zeros + j = i + 1 + while j < l and contents[j] == '0': j += 1 + if j-i > maxx/10 or j-start >= maxx: + #print >> sys.stderr, 'skip', start, i-start, j-start + ret.append((start, contents[start:i])) # skip over the zeros starting at i and ending at j + start = j + i = j + return ret + + @staticmethod + def replace_initializers(src, inits): + class State: + first = True + def rep(m): + if not State.first: return '' + # write out all the new initializers in place of the first old one + State.first = False + def gen_init(init): + offset, contents = init + return '/* memory initializer */ allocate([%s], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE%s);' % ( + ','.join(contents), + '' if offset == 0 else ('+%d' % offset) + ) + return '\n'.join(map(gen_init, inits)) + return re.sub(JS.memory_initializer_pattern, rep, src) + + @staticmethod + def optimize_initializer(src): + inits = JS.collect_initializers(src) + if len(inits) == 0: return None + assert len(inits) == 1 + init = inits[0] + offset, contents = init + assert offset == 0 # offset 0, singleton + if len(contents) <= JS.INITIALIZER_CHUNK_SIZE: return None + return JS.replace_initializers(src, JS.split_initializer(contents)) + # Compression of code and data for smaller downloads class Compression: on = False diff --git a/tools/test-js-optimizer-asm-regs-min-output.js b/tools/test-js-optimizer-asm-regs-min-output.js index 3955e48a..748b8e0a 100644 --- a/tools/test-js-optimizer-asm-regs-min-output.js +++ b/tools/test-js-optimizer-asm-regs-min-output.js @@ -33,4 +33,9 @@ function cl(b) { a(c); i1(b); } +function cl(b) { + b = b | 0; + b = b + 4; + a(b); +} diff --git a/tools/test-js-optimizer-asm-regs-min.js b/tools/test-js-optimizer-asm-regs-min.js index a5b9427e..65d8d429 100644 --- a/tools/test-js-optimizer-asm-regs-min.js +++ b/tools/test-js-optimizer-asm-regs-min.js @@ -33,5 +33,10 @@ function collideLocal(i1) { aGlobal(a); // multiple collisions, a and i1 bGlobal(i1); } +function collideLocal(i1) { + i1 = i1 | 0; + i1 = i1 + 4; // statement is of similar shape to a param coercion + aGlobal(i1); +} // EMSCRIPTEN_GENERATED_FUNCTIONS // EXTRA_INFO: { "names": ["a", "b", "c", "d", "e", "f", "g", "h", "i", "i1", "cl"], "globals": { "aGlobal": "a", "bGlobal": "i1", "collideLocal": "cl" } } diff --git a/tools/test-js-optimizer-shiftsAggressive-output.js b/tools/test-js-optimizer-shiftsAggressive-output.js new file mode 100644 index 00000000..5b429786 --- /dev/null +++ b/tools/test-js-optimizer-shiftsAggressive-output.js @@ -0,0 +1,11 @@ +function __ZNSt3__111__call_onceERVmPvPFvS2_E($flag, $arg, $func) { + $flag = $flag | 0; + $arg = $arg | 0; + $func = $func | 0; + var $2 = 0; + $2 = cheez(); + whee1($flag + 1 | 0); + whee2($flag + 1 | 0); + whee3($flag + 1 | 0); +} + diff --git a/tools/test-js-optimizer-shiftsAggressive.js b/tools/test-js-optimizer-shiftsAggressive.js new file mode 100644 index 00000000..4218d04c --- /dev/null +++ b/tools/test-js-optimizer-shiftsAggressive.js @@ -0,0 +1,13 @@ +function __ZNSt3__111__call_onceERVmPvPFvS2_E($flag,$arg,$func){ + $flag=($flag)|0; + $arg=($arg)|0; + $func=($func)|0; + var $1=0,$2=0,$3=0; + $1; + $2 = cheez(); + $3 = $flag + 1 | 0; + whee1($3); + whee2($3); + whee3($3); +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["__ZNSt3__111__call_onceERVmPvPFvS2_E"] |