aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xemcc2
-rwxr-xr-xemscripten.py43
-rw-r--r--src/library_fs.js14
-rw-r--r--src/library_sdl.js40
-rw-r--r--src/modules.js12
-rw-r--r--src/runtime.js7
-rw-r--r--src/settings.js8
-rwxr-xr-xtests/runner.py9
-rw-r--r--tests/test_core.py7
-rw-r--r--tools/asm_module.py2
10 files changed, 90 insertions, 54 deletions
diff --git a/emcc b/emcc
index c528fb9e..5049648a 100755
--- a/emcc
+++ b/emcc
@@ -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)