diff options
-rwxr-xr-x | emcc | 2 | ||||
-rwxr-xr-x | emscripten.py | 43 | ||||
-rw-r--r-- | src/library_fs.js | 14 | ||||
-rw-r--r-- | src/library_sdl.js | 40 | ||||
-rw-r--r-- | src/modules.js | 12 | ||||
-rw-r--r-- | src/runtime.js | 7 | ||||
-rw-r--r-- | src/settings.js | 8 | ||||
-rwxr-xr-x | tests/runner.py | 9 | ||||
-rw-r--r-- | tests/test_core.py | 7 | ||||
-rw-r--r-- | tools/asm_module.py | 2 |
10 files changed, 90 insertions, 54 deletions
@@ -1239,7 +1239,7 @@ try: extra_files_to_link = [] - if not LEAVE_INPUTS_RAW and not AUTODEBUG and \ + if not LEAVE_INPUTS_RAW and \ not shared.Settings.BUILD_AS_SHARED_LIB == 2 and \ not shared.Settings.SIDE_MODULE: # shared libraries/side modules link no C libraries, need them in parent diff --git a/emscripten.py b/emscripten.py index b70f2abb..2b62c93a 100755 --- a/emscripten.py +++ b/emscripten.py @@ -329,8 +329,9 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, # calculations on merged forwarded data forwarded_json['Functions']['indexedFunctions'] = {} - i = 2 # universal counter - if settings['ASM_JS']: i += 2*settings['RESERVED_FUNCTION_POINTERS'] + i = settings['FUNCTION_POINTER_ALIGNMENT'] # universal counter + if settings['ASM_JS']: i += settings['RESERVED_FUNCTION_POINTERS']*settings['FUNCTION_POINTER_ALIGNMENT'] + base_fp = i table_counters = {} # table-specific counters alias = settings['ASM_JS'] and settings['ALIASING_FUNCTION_POINTERS'] sig = None @@ -339,12 +340,12 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, sig = forwarded_json['Functions']['implementedFunctions'].get(indexed) or forwarded_json['Functions']['unimplementedFunctions'].get(indexed) assert sig, indexed if sig not in table_counters: - table_counters[sig] = 2 + 2*settings['RESERVED_FUNCTION_POINTERS'] + table_counters[sig] = base_fp curr = table_counters[sig] - table_counters[sig] += 2 + table_counters[sig] += settings['FUNCTION_POINTER_ALIGNMENT'] else: curr = i - i += 2 + i += settings['FUNCTION_POINTER_ALIGNMENT'] #logging.debug('function indexing', indexed, curr, sig) forwarded_json['Functions']['indexedFunctions'][indexed] = curr # make sure not to modify this python object later - we use it in indexize @@ -353,17 +354,18 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, return '%d,%d,%d,%d' % (x&255, (x >> 8)&255, (x >> 16)&255, (x >> 24)&255) indexing = forwarded_json['Functions']['indexedFunctions'] + def indexize_mem(js): + return re.sub(r"\"?'?{{ FI_([\w\d_$]+) }}'?\"?,0,0,0", lambda m: split_32(indexing.get(m.groups(0)[0]) or 0), js) def indexize(js): - # In the global initial allocation, we need to split up into Uint8 format - ret = re.sub(r"\"?'?{{ FI_([\w\d_$]+) }}'?\"?,0,0,0", lambda m: split_32(indexing.get(m.groups(0)[0]) or 0), js) - return re.sub(r"'{{ FI_([\w\d_$]+) }}'", lambda m: str(indexing.get(m.groups(0)[0]) or 0), ret) + return re.sub(r"'{{ FI_([\w\d_$]+) }}'", lambda m: str(indexing.get(m.groups(0)[0]) or 0), js) blockaddrs = forwarded_json['Functions']['blockAddresses'] + def blockaddrsize_mem(js): + return re.sub(r'"?{{{ BA_([\w\d_$]+)\|([\w\d_$]+) }}}"?,0,0,0', lambda m: split_32(blockaddrs[m.groups(0)[0]][m.groups(0)[1]]), js) def blockaddrsize(js): - ret = re.sub(r'"?{{{ BA_([\w\d_$]+)\|([\w\d_$]+) }}}"?,0,0,0', lambda m: split_32(blockaddrs[m.groups(0)[0]][m.groups(0)[1]]), js) - return re.sub(r'"?{{{ BA_([\w\d_$]+)\|([\w\d_$]+) }}}"?', lambda m: str(blockaddrs[m.groups(0)[0]][m.groups(0)[1]]), ret) + return re.sub(r'"?{{{ BA_([\w\d_$]+)\|([\w\d_$]+) }}}"?', lambda m: str(blockaddrs[m.groups(0)[0]][m.groups(0)[1]]), js) - pre = blockaddrsize(indexize(pre)) + pre = blockaddrsize(blockaddrsize_mem(indexize(indexize_mem(pre)))) if settings.get('ASM_JS'): # move postsets into the asm module @@ -410,6 +412,7 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, simple = os.environ.get('EMCC_SIMPLE_ASM') class Counter: i = 0 + j = 0 pre_tables = last_forwarded_json['Functions']['tables']['pre'] del last_forwarded_json['Functions']['tables']['pre'] @@ -424,13 +427,18 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, end = raw.rindex(']') body = raw[start+1:end].split(',') for j in range(settings['RESERVED_FUNCTION_POINTERS']): - body[2 + 2*j] = 'jsCall_%s_%s' % (sig, j) + body[settings['FUNCTION_POINTER_ALIGNMENT'] * (1 + j)] = 'jsCall_%s_%s' % (sig, j) + Counter.j = 0 def fix_item(item): - newline = '\n' in item - return (bad if item.replace('\n', '') == '0' else item) + ('\n' if newline else '') + Counter.j += 1 + newline = Counter.j % 30 == 29 + if item == '0': return bad if not newline else (bad + '\n') + return item if not newline else (item + '\n') body = ','.join(map(fix_item, body)) - return ('function %s(%s) { %s %s(%d); %s }' % (bad, params, coercions, 'abort' if not settings['ASSERTIONS'] else 'nullFunc', i, ret), raw[:start+1] + body + raw[end:]) + return ('function %s(%s) { %s %s(%d); %s }' % (bad, params, coercions, 'abort' if not settings['ASSERTIONS'] else 'nullFunc', i, ret), ''.join([raw[:start+1], body, raw[end:]])) + infos = [make_table(sig, raw) for sig, raw in last_forwarded_json['Functions']['tables'].iteritems()] + function_tables_defs = '\n'.join([info[0] for info in infos]) + '\n// EMSCRIPTEN_END_FUNCS\n' + '\n'.join([info[1] for info in infos]) asm_setup = '' @@ -470,6 +478,7 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, function_tables = ['dynCall_' + table for table in last_forwarded_json['Functions']['tables']] function_tables_impls = [] + for sig in last_forwarded_json['Functions']['tables'].iterkeys(): args = ','.join(['a' + str(i) for i in range(1, len(sig))]) arg_coercions = ' '.join(['a' + str(i) + '=' + asm_coerce('a' + str(i), sig[i]) + ';' for i in range(1, len(sig))]) @@ -685,7 +694,9 @@ Runtime.stackRestore = function(top) { asm['stackRestore'](top) }; symbol_table[value] = str(i) outfile.write("var SYMBOL_TABLE = %s;" % json.dumps(symbol_table).replace('"', '')) - for funcs_js_item in funcs_js: # do this loop carefully to save memory + for i in range(len(funcs_js)): # do this loop carefully to save memory + funcs_js_item = funcs_js[i] + funcs_js[i] = None funcs_js_item = indexize(funcs_js_item) funcs_js_item = blockaddrsize(funcs_js_item) outfile.write(funcs_js_item) diff --git a/src/library_fs.js b/src/library_fs.js index c4b29227..dc5c20f8 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -120,6 +120,11 @@ mergeInto(LibraryManager.library, { // hashName: function(parentid, name) { var hash = 0; + +#if CASE_INSENSITIVE_FS + name = name.toLowerCase(); +#endif + for (var i = 0; i < name.length; i++) { hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0; } @@ -151,8 +156,15 @@ mergeInto(LibraryManager.library, { throw new FS.ErrnoError(err); } var hash = FS.hashName(parent.id, name); +#if CASE_INSENSITIVE_FS + name = name.toLowerCase(); +#endif for (var node = FS.nameTable[hash]; node; node = node.name_next) { - if (node.parent.id === parent.id && node.name === name) { + var nodeName = node.name; +#if CASE_INSENSITIVE_FS + nodeName = nodeName.toLowerCase(); +#endif + if (node.parent.id === parent.id && nodeName === name) { return node; } } diff --git a/src/library_sdl.js b/src/library_sdl.js index 1d6a00b6..27f2c0da 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1383,12 +1383,12 @@ var LibrarySDL = { SDL_OpenAudio: function(desired, obtained) { try { SDL.audio = { - freq: {{{ makeGetValue('desired', 'C_STRUCTS.SDL_AudioSpec.freq', 'i32', 0, 1) }}}, - format: {{{ makeGetValue('desired', 'C_STRUCTS.SDL_AudioSpec.format', 'i16', 0, 1) }}}, - channels: {{{ makeGetValue('desired', 'C_STRUCTS.SDL_AudioSpec.channels', 'i8', 0, 1) }}}, - samples: {{{ makeGetValue('desired', 'C_STRUCTS.SDL_AudioSpec.samples', 'i16', 0, 1) }}}, // Samples in the CB buffer per single sound channel. - callback: {{{ makeGetValue('desired', 'C_STRUCTS.SDL_AudioSpec.callback', 'void*', 0, 1) }}}, - userdata: {{{ makeGetValue('desired', 'C_STRUCTS.SDL_AudioSpec.userdata', 'void*', 0, 1) }}}, + freq: {{{ makeGetValue('desired', C_STRUCTS.SDL_AudioSpec.freq, 'i32', 0, 1) }}}, + format: {{{ makeGetValue('desired', C_STRUCTS.SDL_AudioSpec.format, 'i16', 0, 1) }}}, + channels: {{{ makeGetValue('desired', C_STRUCTS.SDL_AudioSpec.channels, 'i8', 0, 1) }}}, + samples: {{{ makeGetValue('desired', C_STRUCTS.SDL_AudioSpec.samples, 'i16', 0, 1) }}}, // Samples in the CB buffer per single sound channel. + callback: {{{ makeGetValue('desired', C_STRUCTS.SDL_AudioSpec.callback, 'void*', 0, 1) }}}, + userdata: {{{ makeGetValue('desired', C_STRUCTS.SDL_AudioSpec.userdata, 'void*', 0, 1) }}}, paused: true, timer: null }; @@ -1569,13 +1569,13 @@ var LibrarySDL = { if (obtained) { // Report back the initialized audio parameters. - {{{ makeSetValue('obtained', 'C_STRUCTS.SDL_AudioSpec.freq', 'SDL.audio.freq', 'i32') }}}; - {{{ makeSetValue('obtained', 'C_STRUCTS.SDL_AudioSpec.format', 'SDL.audio.format', 'i16') }}}; - {{{ makeSetValue('obtained', 'C_STRUCTS.SDL_AudioSpec.channels', 'SDL.audio.channels', 'i8') }}}; - {{{ makeSetValue('obtained', 'C_STRUCTS.SDL_AudioSpec.silence', 'SDL.audio.silence', 'i8') }}}; - {{{ makeSetValue('obtained', 'C_STRUCTS.SDL_AudioSpec.samples', 'SDL.audio.samples', 'i16') }}}; - {{{ makeSetValue('obtained', 'C_STRUCTS.SDL_AudioSpec.callback', 'SDL.audio.callback', '*') }}}; - {{{ makeSetValue('obtained', 'C_STRUCTS.SDL_AudioSpec.userdata', 'SDL.audio.userdata', '*') }}}; + {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.freq, 'SDL.audio.freq', 'i32') }}}; + {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.format, 'SDL.audio.format', 'i16') }}}; + {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.channels, 'SDL.audio.channels', 'i8') }}}; + {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.silence, 'SDL.audio.silence', 'i8') }}}; + {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.samples, 'SDL.audio.samples', 'i16') }}}; + {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.callback, 'SDL.audio.callback', '*') }}}; + {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.userdata, 'SDL.audio.userdata', '*') }}}; } SDL.allocateChannels(32); @@ -1584,13 +1584,13 @@ var LibrarySDL = { SDL.audio = null; SDL.allocateChannels(0); if (obtained) { - {{{ makeSetValue('obtained', 'C_STRUCTS.SDL_AudioSpec.freq', 0, 'i32') }}}; - {{{ makeSetValue('obtained', 'C_STRUCTS.SDL_AudioSpec.format', 0, 'i16') }}}; - {{{ makeSetValue('obtained', 'C_STRUCTS.SDL_AudioSpec.channels', 0, 'i8') }}}; - {{{ makeSetValue('obtained', 'C_STRUCTS.SDL_AudioSpec.silence', 0, 'i8') }}}; - {{{ makeSetValue('obtained', 'C_STRUCTS.SDL_AudioSpec.samples', 0, 'i16') }}}; - {{{ makeSetValue('obtained', 'C_STRUCTS.SDL_AudioSpec.callback', 0, '*') }}}; - {{{ makeSetValue('obtained', 'C_STRUCTS.SDL_AudioSpec.userdata', 0, '*') }}}; + {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.freq, 0, 'i32') }}}; + {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.format, 0, 'i16') }}}; + {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.channels, 0, 'i8') }}}; + {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.silence, 0, 'i8') }}}; + {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.samples, 0, 'i16') }}}; + {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.callback, 0, '*') }}}; + {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.userdata, 0, '*') }}}; } } if (!SDL.audio) { diff --git a/src/modules.js b/src/modules.js index 2757c2cb..d9888c24 100644 --- a/src/modules.js +++ b/src/modules.js @@ -234,7 +234,7 @@ var Types = { preciseI64MathUsed: (PRECISE_I64_MATH == 2) }; -var firstTableIndex = (ASM_JS ? 2*RESERVED_FUNCTION_POINTERS : 0) + 2; +var firstTableIndex = FUNCTION_POINTER_ALIGNMENT * ((ASM_JS ? RESERVED_FUNCTION_POINTERS : 0) + 1); var Functions = { // All functions that will be implemented in this file. Maps id to signature @@ -287,7 +287,7 @@ var Functions = { ret = this.indexedFunctions[ident]; if (!ret) { ret = this.nextIndex; - this.nextIndex += 2; // Need to have indexes be even numbers, see |polymorph| test + this.nextIndex += FUNCTION_POINTER_ALIGNMENT; this.indexedFunctions[ident] = ret; } ret = ret.toString(); @@ -373,14 +373,6 @@ var Functions = { } } } - if (table.length > 20) { - // add some newlines in the table, for readability - var j = 10; - while (j+10 < table.length) { - table[j] += '\n'; - j += 10; - } - } maxTable = Math.max(maxTable, table.length); } if (ASM_JS) maxTable = ceilPowerOfTwo(maxTable); diff --git a/src/runtime.js b/src/runtime.js index 00031fed..a281045b 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -347,22 +347,23 @@ var Runtime = { for (var i = 0; i < Runtime.functionPointers.length; i++) { if (!Runtime.functionPointers[i]) { Runtime.functionPointers[i] = func; - return 2 + 2*i; + return {{{ FUNCTION_POINTER_ALIGNMENT }}}*(1 + i); } } throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.'; #else var table = FUNCTION_TABLE; var ret = table.length; + assert(ret % {{{ FUNCTION_POINTER_ALIGNMENT }}} === 0); table.push(func); - table.push(0); + for (var i = 0; i < {{{ FUNCTION_POINTER_ALIGNMENT }}}-1; i++) table.push(0); return ret; #endif }, removeFunction: function(index) { #if ASM_JS - Runtime.functionPointers[(index-2)/2] = null; + Runtime.functionPointers[(index-{{{ FUNCTION_POINTER_ALIGNMENT }}})/{{{ FUNCTION_POINTER_ALIGNMENT }}}] = null; #else var table = FUNCTION_TABLE; table[index] = null; diff --git a/src/settings.js b/src/settings.js index 6e2b9e6c..7a9e6b76 100644 --- a/src/settings.js +++ b/src/settings.js @@ -170,6 +170,12 @@ var ALIASING_FUNCTION_POINTERS = 0; // Whether to allow function pointers to ali // a different type. This can greatly decrease table sizes // in asm.js, but can break code that compares function // pointers across different types. +var FUNCTION_POINTER_ALIGNMENT = 2; // Byte alignment of function pointers - we will fill the + // tables with zeros on aligned values. 1 means all values + // are aligned and all will be used (which is optimal). + // Sadly 1 breaks on &Class::method function pointer calls, + // which llvm assumes have the lower bit zero (see + // test_polymorph and issue #1692). var ASM_HEAP_LOG = 0; // Simple heap logging, like SAFE_HEAP_LOG but cheaper, and in asm.js @@ -266,6 +272,8 @@ var CORRECT_ROUNDINGS = 1; // C rounds to 0 (-5.5 to -5, +5.5 to 5), while JS ha var FS_LOG = 0; // Log all FS operations. This is especially helpful when you're porting // a new project and want to see a list of file system operations happening // so that you can create a virtual file system with all of the required files. +var CASE_INSENSITIVE_FS = 0; // If set to nonzero, the provided virtual filesystem if treated case-insensitive, like + // Windows and OSX do. If set to 0, the VFS is case-sensitive, like on Linux. var USE_BSS = 1; // https://en.wikipedia.org/wiki/.bss // When enabled, 0-initialized globals are sorted to the end of the globals list, diff --git a/tests/runner.py b/tests/runner.py index ddc97ea4..867f7113 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -737,13 +737,15 @@ if __name__ == '__main__': print ''' ============================================================================== Running the main part of the test suite. Don't forget to run the other parts! +A recommended order is: - other - tests separate from the main suite sanity - tests for first run, etc., modifies ~/.emscripten - benchmark - run before and after each set of changes before pushing to - master, verify no regressions + (the main test suite) + other - tests separate from the main suite browser - runs pages in a web browser sockets - runs websocket networking tests + benchmark - run before and after each set of changes before pushing to + master, verify no regressions There are also commands to run specific subsets of the test suite: @@ -799,3 +801,4 @@ an individual test with # Return the number of failures as the process exit code for automating success/failure reporting. exit(numFailures) + diff --git a/tests/test_core.py b/tests/test_core.py index d35bec4e..11ec8fd2 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -7743,6 +7743,8 @@ def process(filename): Settings.INCLUDE_FULL_LIBRARY = 0 def test_fs_nodefs_rw(self): + if self.emcc_args is None: return self.skip('requires emcc') + if not self.is_le32(): return self.skip('le32 needed for inline js') src = open(path_from_root('tests', 'fs', 'test_nodefs_rw.c'), 'r').read() self.do_run(src, 'success', force_c=True, js_engines=[NODE_JS]) @@ -7815,6 +7817,8 @@ def process(filename): self.do_run(src, expected) def test_unistd_unlink(self): + if self.emcc_args is None: return self.skip('requires emcc') + if not self.is_le32(): return self.skip('le32 needed for inline js') for fs in ['MEMFS', 'NODEFS']: src = open(path_from_root('tests', 'unistd', 'unlink.c'), 'r').read() Building.COMPILER_TEST_OPTS += ['-D' + fs] @@ -7838,6 +7842,7 @@ def process(filename): if Settings.ASM_JS: Settings.ASM_JS = 2 # skip validation, asm does not support random code if not self.is_le32(): return self.skip('le32 needed for inline js') if self.run_name == 'o2': return self.skip('non-asm optimized builds can fail with inline js') + if self.emcc_args is None: return self.skip('requires emcc') for fs in ['MEMFS', 'NODEFS']: src = open(path_from_root('tests', 'unistd', 'io.c'), 'r').read() expected = open(path_from_root('tests', 'unistd', 'io.out'), 'r').read() @@ -7845,6 +7850,8 @@ def process(filename): self.do_run(src, expected, js_engines=[NODE_JS]) def test_unistd_misc(self): + if self.emcc_args is None: return self.skip('requires emcc') + if not self.is_le32(): return self.skip('le32 needed for inline js') for fs in ['MEMFS', 'NODEFS']: src = open(path_from_root('tests', 'unistd', 'misc.c'), 'r').read() expected = open(path_from_root('tests', 'unistd', 'misc.out'), 'r').read() diff --git a/tools/asm_module.py b/tools/asm_module.py index 226b66b8..f383eba6 100644 --- a/tools/asm_module.py +++ b/tools/asm_module.py @@ -248,12 +248,14 @@ class AsmModule(): def merge_tables(self, table, main, side, replacements, f_bases, f_sizes): sig = table.split('_')[-1] side = side[1:-1].split(',') + side = map(lambda s: s.strip(), side) side = map(lambda f: replacements[f] if f in replacements else f, side) if not main: f_bases[sig] = 0 f_sizes[table] = len(side) return '[' + ','.join(side) + ']' main = main[1:-1].split(',') + main = map(lambda m: m.strip(), main) # TODO: handle non-aliasing case too assert len(main) % 2 == 0 f_bases[sig] = len(main) |