diff options
-rwxr-xr-x | emcc | 24 | ||||
-rwxr-xr-x | emscripten.py | 114 | ||||
-rw-r--r-- | src/jsifier.js | 29 | ||||
-rw-r--r-- | src/library.js | 178 | ||||
-rw-r--r-- | src/library_gl.js | 15 | ||||
-rw-r--r-- | src/library_sdl.js | 32 | ||||
-rw-r--r-- | src/modules.js | 1 | ||||
-rw-r--r-- | src/parseTools.js | 9 | ||||
-rw-r--r-- | src/settings.js | 7 | ||||
-rw-r--r-- | src/shell_sharedlib.js | 19 | ||||
-rw-r--r-- | tests/browser_main.cpp | 42 | ||||
-rw-r--r-- | tests/browser_module.cpp | 15 | ||||
-rw-r--r-- | tests/dlmalloc_proxy.c | 85 | ||||
-rw-r--r-- | tests/gl_vertex_buffer.c | 195 | ||||
-rw-r--r-- | tests/gl_vertex_buffer.png | bin | 0 -> 47668 bytes | |||
-rw-r--r-- | tests/gl_vertex_buffer_pre.c | 177 | ||||
-rw-r--r-- | tests/gl_vertex_buffer_pre.png | bin | 0 -> 83534 bytes | |||
-rw-r--r-- | tests/test_browser.py | 11 | ||||
-rw-r--r-- | tests/test_core.py | 539 | ||||
-rw-r--r-- | tests/test_other.py | 9 | ||||
-rw-r--r-- | tools/jsrun.py | 1 | ||||
-rw-r--r-- | tools/shared.py | 61 |
22 files changed, 1315 insertions, 248 deletions
@@ -663,6 +663,12 @@ if '-M' in sys.argv or '-MM' in sys.argv: logging.debug('just dependencies: ' + ' '.join(cmd)) exit(subprocess.call(cmd)) +if '-E' in sys.argv: + # Just run the preprocessor + cmd = [CC] + sys.argv[1:] + logging.debug('just preprocssor ' + ' '.join(cmd)) + exit(subprocess.call(cmd)) + # Check if a target is specified target = None for i in range(len(sys.argv)-1): @@ -1070,9 +1076,6 @@ try: shared.Settings.CORRECT_OVERFLOWS = 1 assert not shared.Settings.PGO, 'cannot run PGO in ASM_JS mode' - if shared.Settings.ASSERTIONS and shared.Settings.ALIASING_FUNCTION_POINTERS: - logging.warning('ALIASING_FUNCTION_POINTERS is on, function pointer comparisons may be invalid across types') - 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 @@ -1107,13 +1110,24 @@ try: shared.Settings.LINKABLE = 1 # TODO: add FORCE_DCE option for the brave people that do want to dce here and in side modules debug_level = max(debug_level, 2) - if shared.Settings.DLOPEN_SUPPORT: - shared.Settings.LINKABLE = 1 + if shared.Settings.ASSERTIONS and shared.Settings.ALIASING_FUNCTION_POINTERS: + logging.warning('ALIASING_FUNCTION_POINTERS is on, function pointer comparisons may be invalid across types') if shared.Settings.STB_IMAGE and final_suffix in JS_CONTAINING_SUFFIXES: input_files.append(shared.path_from_root('third_party', 'stb_image.c')) shared.Settings.EXPORTED_FUNCTIONS += ['_stbi_load', '_stbi_load_from_memory', '_stbi_image_free'] + if type(shared.Settings.EXPORTED_FUNCTIONS) in (list, tuple): + # always need malloc and free to be kept alive and exported, for internal use and other modules + for required_export in ['_malloc', '_free']: + if required_export not in shared.Settings.EXPORTED_FUNCTIONS: + shared.Settings.EXPORTED_FUNCTIONS.append(required_export) + else: + logging.debug('using response file for EXPORTED_FUNCTIONS, make sure it includes _malloc and _free') + + if shared.Settings.ASM_JS and shared.Settings.DLOPEN_SUPPORT: + assert shared.Settings.DISABLE_EXCEPTION_CATCHING, 'no exceptions support with dlopen in asm yet' + ## Compile source code to bitcode logging.debug('compiling to bitcode') diff --git a/emscripten.py b/emscripten.py index c5e235d8..257527fe 100755 --- a/emscripten.py +++ b/emscripten.py @@ -444,6 +444,11 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, forwarded_json['Functions']['libraryFunctions'].get('llvm_ctlz_i32'): basic_vars += ['cttz_i8', 'ctlz_i8'] + if settings.get('DLOPEN_SUPPORT'): + for sig in last_forwarded_json['Functions']['tables'].iterkeys(): + basic_vars.append('F_BASE_%s' % sig) + asm_setup += ' var F_BASE_%s = %s;\n' % (sig, 'FUNCTION_TABLE_OFFSET' if settings.get('SIDE_MODULE') else '0') + '\n' + asm_runtime_funcs = ['stackAlloc', 'stackSave', 'stackRestore', 'setThrew'] + ['setTempRet%d' % i for i in range(10)] # function tables def asm_coerce(value, sig): @@ -475,8 +480,12 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, ''' % (sig, i, args, arg_coercions, jsret)) from tools import shared + shared.Settings.copy(settings) asm_setup += '\n' + shared.JS.make_invoke(sig) + '\n' basic_funcs.append('invoke_%s' % sig) + if settings.get('DLOPEN_SUPPORT'): + asm_setup += '\n' + shared.JS.make_extcall(sig) + '\n' + basic_funcs.append('extCall_%s' % sig) # calculate exports exported_implemented_functions = list(exported_implemented_functions) @@ -606,23 +615,36 @@ function setTempRet%d(value) { // EMSCRIPTEN_END_ASM (%s, %s, buffer); %s; +''' % (pre_tables + '\n'.join(function_tables_impls) + '\n' + function_tables_defs.replace('\n', '\n '), exports, the_global, sending, receiving)] + + if not settings.get('SIDE_MODULE'): + funcs_js.append(''' Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) }; Runtime.stackSave = function() { return asm['stackSave']() }; Runtime.stackRestore = function(top) { asm['stackRestore'](top) }; -''' % (pre_tables + '\n'.join(function_tables_impls) + '\n' + function_tables_defs.replace('\n', '\n '), exports, the_global, sending, receiving)] +''') # Set function table masks - def function_table_maskize(js): - masks = {} - default = None - for sig, table in last_forwarded_json['Functions']['tables'].iteritems(): - masks[sig] = str(table.count(',')) - default = sig + masks = {} + max_mask = 0 + for sig, table in last_forwarded_json['Functions']['tables'].iteritems(): + mask = table.count(',') + masks[sig] = str(mask) + max_mask = max(mask, max_mask) + def function_table_maskize(js, masks): def fix(m): sig = m.groups(0)[0] return masks[sig] return re.sub(r'{{{ FTM_([\w\d_$]+) }}}', lambda m: fix(m), js) # masks[m.groups(0)[0]] - funcs_js = map(function_table_maskize, funcs_js) + funcs_js = map(lambda js: function_table_maskize(js, masks), funcs_js) + + if settings.get('DLOPEN_SUPPORT'): + funcs_js.append(''' + asm.maxFunctionIndex = %(max_mask)d; + DLFCN.registerFunctions(asm, %(max_mask)d+1, %(sigs)s, Module); + Module.SYMBOL_TABLE = SYMBOL_TABLE; +''' % { 'max_mask': max_mask, 'sigs': str(map(str, last_forwarded_json['Functions']['tables'].keys())) }) + else: function_tables_defs = '\n'.join([table for table in last_forwarded_json['Functions']['tables'].itervalues()]) outfile.write(function_tables_defs) @@ -637,13 +659,18 @@ Runtime.stackRestore = function(top) { asm['stackRestore'](top) }; symbol_table = {} for k, v in forwarded_json['Variables']['indexedGlobals'].iteritems(): if forwarded_json['Variables']['globals'][k]['named']: - symbol_table[k] = v + forwarded_json['Runtime']['GLOBAL_BASE'] + symbol_table[k] = str(v + forwarded_json['Runtime']['GLOBAL_BASE']) for raw in last_forwarded_json['Functions']['tables'].itervalues(): if raw == '': continue table = map(string.strip, raw[raw.find('[')+1:raw.find(']')].split(",")) - symbol_table.update(map(lambda x: (x[1], x[0]), - filter(lambda x: x[1] != '0', enumerate(table)))) - outfile.write("var SYMBOL_TABLE = %s;" % json.dumps(symbol_table)) + for i in range(len(table)): + value = table[i] + if value != '0': + if settings.get('SIDE_MODULE'): + symbol_table[value] = 'FUNCTION_TABLE_OFFSET+' + str(i) + else: + 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 funcs_js_item = indexize(funcs_js_item) @@ -663,69 +690,6 @@ def main(args, compiler_engine, cache, jcache, relooper, temp_files, DEBUG, DEBU name, value = setting.strip().split('=', 1) settings[name] = json.loads(value) - # Add header defines to settings - defines = {} - include_root = path_from_root('system', 'include') - headers = args.headers[0].split(',') if len(args.headers) > 0 else [] - seen_headers = set() - while len(headers) > 0: - header = headers.pop(0) - if not os.path.isabs(header): - header = os.path.join(include_root, header) - seen_headers.add(header) - for line in open(header, 'r'): - line = line.replace('\t', ' ') - m = re.match('^ *# *define +(?P<name>[-\w_.]+) +\(?(?P<value>[-\w_.|]+)\)?.*', line) - if not m: - # Catch enum defines of a very limited sort - m = re.match('^ +(?P<name>[A-Z_\d]+) += +(?P<value>\d+).*', line) - if m: - if m.group('name') != m.group('value'): - defines[m.group('name')] = m.group('value') - #else: - # print 'Warning: %s #defined to itself' % m.group('name') # XXX this can happen if we are set to be equal to an enum (with the same name) - m = re.match('^ *# *include *["<](?P<name>[\w_.-/]+)[">].*', line) - if m: - # Find this file - found = False - for w in [w for w in os.walk(include_root)]: - for f in w[2]: - curr = os.path.join(w[0], f) - if curr.endswith(m.group('name')) and curr not in seen_headers: - headers.append(curr) - found = True - break - if found: break - #assert found, 'Could not find header: ' + m.group('name') - if len(defines) > 0: - def lookup(value): - try: - while not unicode(value).isnumeric(): - value = defines[value] - return value - except: - pass - try: # 0x300 etc. - value = eval(value) - return value - except: - pass - try: # CONST1|CONST2 - parts = map(lookup, value.split('|')) - value = reduce(lambda a, b: a|b, map(eval, parts)) - return value - except: - pass - return None - for key, value in defines.items(): - value = lookup(value) - if value is not None: - defines[key] = str(value) - else: - del defines[key] - #print >> sys.stderr, 'new defs:', str(defines).replace(',', ',\n '), '\n\n' - settings.setdefault('C_DEFINES', {}).update(defines) - # libraries libraries = args.libraries[0].split(',') if len(args.libraries) > 0 else [] diff --git a/src/jsifier.js b/src/jsifier.js index da2ba749..f5682a1b 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -338,6 +338,7 @@ function JSify(data, functionsOnly, givenFunctions) { // External variables in shared libraries should not be declared as // they would shadow similarly-named globals in the parent, so do nothing here. if (BUILD_AS_SHARED_LIB) return ret; + if (SIDE_MODULE) return []; // Library items need us to emit something, but everything else requires nothing. if (!LibraryManager.library[item.ident.slice(1)]) return ret; } @@ -1405,7 +1406,10 @@ function JSify(data, functionsOnly, givenFunctions) { // We cannot compile assembly. See comment in intertyper.js:'Call' assert(ident != 'asm', 'Inline assembly cannot be compiled to JavaScript!'); + var extCall = false; + if (ASM_JS && funcData.setjmpTable) forceByPointer = true; // in asm.js mode, we must do an invoke for each call + if (ASM_JS && DLOPEN_SUPPORT && !invoke && !funcData.setjmpTable) extCall = true; // go out, to be able to access other modules TODO: optimize ident = Variables.resolveAliasToIdent(ident); var shortident = ident.slice(1); @@ -1466,7 +1470,7 @@ function JSify(data, functionsOnly, givenFunctions) { args = args.map(function(arg, i) { return indexizeFunctions(arg, argsTypes[i]) }); if (ASM_JS) { - if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced || invoke || funcData.setjmpTable) { + if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced || invoke || extCall || funcData.setjmpTable) { args = args.map(function(arg, i) { return asmCoercion(arg, argsTypes[i]) }); } else { args = args.map(function(arg, i) { return asmEnsureFloat(arg, argsTypes[i]) }); @@ -1556,17 +1560,17 @@ function JSify(data, functionsOnly, givenFunctions) { var sig = Functions.getSignature(returnType, argsTypes, hasVarArgs); if (ASM_JS) { assert(returnType.search(/\("'\[,/) == -1); // XXX need isFunctionType(type, out) - var functionTableCall = !byPointerForced && !funcData.setjmpTable && !invoke; + Functions.neededTables[sig] = 1; + var functionTableCall = !byPointerForced && !funcData.setjmpTable && !invoke && !extCall; if (functionTableCall) { // normal asm function pointer call callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py - Functions.neededTables[sig] = 1; } else { - // This is a call through an invoke_*, either a forced one, or a setjmp-required one + // This is a call through an invoke_* or extCall, either a forced one, or a setjmp-required one // note: no need to update argsTypes at this point if (byPointerForced) Functions.unimplementedFunctions[callIdent] = sig; args.unshift(byPointerForced ? Functions.getIndex(callIdent, sig) : asmCoercion(callIdent, 'i32')); - callIdent = 'invoke_' + sig; + callIdent = (extCall ? 'extCall' : 'invoke') + '_' + sig; } } else if (SAFE_DYNCALLS) { assert(!ASM_JS, 'cannot emit safe dyncalls in asm'); @@ -1660,8 +1664,13 @@ function JSify(data, functionsOnly, givenFunctions) { Variables.generatedGlobalBase = true; // Globals are done, here is the rest of static memory assert((TARGET_LE32 && Runtime.GLOBAL_BASE == 8) || (TARGET_X86 && Runtime.GLOBAL_BASE == 4)); // this is assumed in e.g. relocations for linkable modules - print('STATIC_BASE = ' + Runtime.GLOBAL_BASE + ';\n'); - print('STATICTOP = STATIC_BASE + ' + Runtime.alignMemory(Variables.nextIndexedOffset) + ';\n'); + if (!SIDE_MODULE) { + print('STATIC_BASE = ' + Runtime.GLOBAL_BASE + ';\n'); + print('STATICTOP = STATIC_BASE + ' + Runtime.alignMemory(Variables.nextIndexedOffset) + ';\n'); + } else { + print('H_BASE = parentModule["_malloc"](' + Runtime.alignMemory(Variables.nextIndexedOffset) + ' + Runtime.GLOBAL_BASE);\n'); + print('// STATICTOP = STATIC_BASE + ' + Runtime.alignMemory(Variables.nextIndexedOffset) + ';\n'); // comment as metadata only + } } var generated = itemsDict.function.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.GlobalVariable); print(generated.map(function(item) { return item.JS; }).join('\n')); @@ -1688,7 +1697,7 @@ function JSify(data, functionsOnly, givenFunctions) { return true; }); // write out the singleton big memory initialization value - print('/* memory initializer */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'Runtime.GLOBAL_BASE', true)); + print('/* memory initializer */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'Runtime.GLOBAL_BASE' + (SIDE_MODULE ? '+H_BASE' : ''), true)); } else { print('/* no memory initializer */'); // test purposes } @@ -1700,7 +1709,7 @@ function JSify(data, functionsOnly, givenFunctions) { print('}\n'); if (USE_TYPED_ARRAYS == 2) { - if (!BUILD_AS_SHARED_LIB) { + if (!BUILD_AS_SHARED_LIB && !SIDE_MODULE) { print('var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);\n'); print('assert(tempDoublePtr % 8 == 0);\n'); print('function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much\n'); @@ -1754,7 +1763,7 @@ function JSify(data, functionsOnly, givenFunctions) { legalizedI64s = legalizedI64sDefault; - if (!BUILD_AS_SHARED_LIB) { + if (!BUILD_AS_SHARED_LIB && !SIDE_MODULE) { print('STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);\n'); print('staticSealed = true; // seal the static portion of memory\n'); print('STACK_MAX = STACK_BASE + ' + TOTAL_STACK + ';\n'); diff --git a/src/library.js b/src/library.js index 9d0c65d5..3008a055 100644 --- a/src/library.js +++ b/src/library.js @@ -4273,9 +4273,11 @@ LibraryManager.library = { __cxa_guard_release: function() {}, __cxa_guard_abort: function() {}, +#if USE_TYPED_ARRAYS != 2 _ZTVN10__cxxabiv119__pointer_type_infoE: [0], // is a pointer _ZTVN10__cxxabiv117__class_type_infoE: [1], // no inherited classes _ZTVN10__cxxabiv120__si_class_type_infoE: [2], // yes inherited classes +#endif // Exceptions __cxa_allocate_exception: function(size) { @@ -4732,16 +4734,22 @@ LibraryManager.library = { erff: 'erf', log: 'Math.log', logf: 'Math.log', + logl: 'Math.log', sqrt: 'Math.sqrt', sqrtf: 'Math.sqrt', + sqrtl: 'Math.sqrt', fabs: 'Math.abs', fabsf: 'Math.abs', + fabsl: 'Math.abs', ceil: 'Math.ceil', ceilf: 'Math.ceil', + ceill: 'Math.ceil', floor: 'Math.floor', floorf: 'Math.floor', + floorl: 'Math.floor', pow: 'Math.pow', powf: 'Math.pow', + powl: 'Math.pow', llvm_sqrt_f32: 'Math.sqrt', llvm_sqrt_f64: 'Math.sqrt', llvm_pow_f32: 'Math.pow', @@ -5012,24 +5020,74 @@ LibraryManager.library = { // being compiled. Not sure how to tell LLVM to not do so. // ========================================================================== - // Data for dlfcn.h. - $DLFCN_DATA: { + $DLFCN: { +#if DLOPEN_SUPPORT + // extra asm.js dlopen support + functionTable: [], // will contain objects mapping sigs to js functions that call into the right asm module with the right index + + registerFunctions: function(asm, num, sigs, jsModule) { + // use asm module dynCall_* from functionTable + if (num % 2 == 1) num++; // keep pointers even + var table = DLFCN.functionTable; + var from = table.length; + assert(from % 2 == 0); + for (var i = 0; i < num; i++) { + table[from + i] = {}; + sigs.forEach(function(sig) { // TODO: new Function etc. + var full = 'dynCall_' + sig; + table[from + i][sig] = function() { + arguments[0] -= from; + return asm[full].apply(null, arguments); + } + }); + } + + if (jsModule.cleanups) { + var newLength = table.length; + jsModule.cleanups.push(function() { + if (table.length === newLength) { + table.length = from; // nothing added since, just shrink + } else { + // something was added above us, clear and leak the span + for (var i = 0; i < num; i++) { + table[from + i] = null; + } + } + while (table.length > 0 && table[table.length-1] === null) table.pop(); + }); + } + + // patch js module dynCall_* to use functionTable + sigs.forEach(function(sig) { + jsModule['dynCall_' + sig] = function() { + return table[arguments[0]][sig].apply(null, arguments); + }; + }); + }, +#endif + error: null, errorMsg: null, loadedLibs: {}, // handle -> [refcount, name, lib_object] loadedLibNames: {}, // name -> handle }, // void* dlopen(const char* filename, int flag); - dlopen__deps: ['$DLFCN_DATA', '$FS', '$ENV'], + dlopen__deps: ['$DLFCN', '$FS', '$ENV'], dlopen: function(filename, flag) { // void *dlopen(const char *file, int mode); // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlopen.html filename = filename === 0 ? '__self__' : (ENV['LD_LIBRARY_PATH'] || '/') + Pointer_stringify(filename); - if (DLFCN_DATA.loadedLibNames[filename]) { +#if ASM_JS +#if DLOPEN_SUPPORT == 0 + abort('need to build with DLOPEN_SUPPORT=1 to get dlopen support in asm.js'); +#endif +#endif + + if (DLFCN.loadedLibNames[filename]) { // Already loaded; increment ref count and return. - var handle = DLFCN_DATA.loadedLibNames[filename]; - DLFCN_DATA.loadedLibs[handle].refcount++; + var handle = DLFCN.loadedLibNames[filename]; + DLFCN.loadedLibs[handle].refcount++; return handle; } @@ -5040,7 +5098,7 @@ LibraryManager.library = { } else { var target = FS.findObject(filename); if (!target || target.isFolder || target.isDevice) { - DLFCN_DATA.errorMsg = 'Could not find dynamic lib: ' + filename; + DLFCN.errorMsg = 'Could not find dynamic lib: ' + filename; return 0; } else { FS.forceLoadFile(target); @@ -5048,19 +5106,26 @@ LibraryManager.library = { } try { - var lib_module = eval(lib_data)({{{ Functions.getTable('x') }}}.length); + var lib_module = eval(lib_data)( +#if ASM_JS + DLFCN.functionTable.length, +#else + {{{ Functions.getTable('x') }}}.length, +#endif + Module + ); } catch (e) { #if ASSERTIONS Module.printErr('Error in loading dynamic library: ' + e); #endif - DLFCN_DATA.errorMsg = 'Could not evaluate dynamic lib: ' + filename; + DLFCN.errorMsg = 'Could not evaluate dynamic lib: ' + filename; return 0; } // Not all browsers support Object.keys(). var handle = 1; - for (var key in DLFCN_DATA.loadedLibs) { - if (DLFCN_DATA.loadedLibs.hasOwnProperty(key)) handle++; + for (var key in DLFCN.loadedLibs) { + if (DLFCN.loadedLibs.hasOwnProperty(key)) handle++; } // We don't care about RTLD_NOW and RTLD_LAZY. @@ -5074,60 +5139,66 @@ LibraryManager.library = { var cached_functions = {}; } - DLFCN_DATA.loadedLibs[handle] = { + DLFCN.loadedLibs[handle] = { refcount: 1, name: filename, module: lib_module, cached_functions: cached_functions }; - DLFCN_DATA.loadedLibNames[filename] = handle; + DLFCN.loadedLibNames[filename] = handle; return handle; }, // int dlclose(void* handle); - dlclose__deps: ['$DLFCN_DATA'], + dlclose__deps: ['$DLFCN'], dlclose: function(handle) { // int dlclose(void *handle); // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlclose.html - if (!DLFCN_DATA.loadedLibs[handle]) { - DLFCN_DATA.errorMsg = 'Tried to dlclose() unopened handle: ' + handle; + if (!DLFCN.loadedLibs[handle]) { + DLFCN.errorMsg = 'Tried to dlclose() unopened handle: ' + handle; return 1; } else { - var lib_record = DLFCN_DATA.loadedLibs[handle]; + var lib_record = DLFCN.loadedLibs[handle]; if (--lib_record.refcount == 0) { - delete DLFCN_DATA.loadedLibNames[lib_record.name]; - delete DLFCN_DATA.loadedLibs[handle]; + if (lib_record.module.cleanups) { + lib_record.module.cleanups.forEach(function(cleanup) { cleanup() }); + } + delete DLFCN.loadedLibNames[lib_record.name]; + delete DLFCN.loadedLibs[handle]; } return 0; } }, // void* dlsym(void* handle, const char* symbol); - dlsym__deps: ['$DLFCN_DATA'], + dlsym__deps: ['$DLFCN'], dlsym: function(handle, symbol) { // void *dlsym(void *restrict handle, const char *restrict name); // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html symbol = '_' + Pointer_stringify(symbol); - if (!DLFCN_DATA.loadedLibs[handle]) { - DLFCN_DATA.errorMsg = 'Tried to dlsym() from an unopened handle: ' + handle; + if (!DLFCN.loadedLibs[handle]) { + DLFCN.errorMsg = 'Tried to dlsym() from an unopened handle: ' + handle; return 0; } else { - var lib = DLFCN_DATA.loadedLibs[handle]; + var lib = DLFCN.loadedLibs[handle]; // self-dlopen means that lib.module is not a superset of // cached_functions, so check the latter first if (lib.cached_functions.hasOwnProperty(symbol)) { return lib.cached_functions[symbol]; } else { if (!lib.module.hasOwnProperty(symbol)) { - DLFCN_DATA.errorMsg = ('Tried to lookup unknown symbol "' + symbol + + DLFCN.errorMsg = ('Tried to lookup unknown symbol "' + symbol + '" in dynamic lib: ' + lib.name); return 0; } else { var result = lib.module[symbol]; if (typeof result == 'function') { - {{{ Functions.getTable('x') }}}.push(result); - {{{ Functions.getTable('x') }}}.push(0); - result = {{{ Functions.getTable('x') }}}.length - 2; +#if ASM_JS + result = lib.module.SYMBOL_TABLE[symbol]; + assert(result); +#else + result = Runtime.addFunction(result); +#endif lib.cached_functions = result; } return result; @@ -5136,18 +5207,18 @@ LibraryManager.library = { } }, // char* dlerror(void); - dlerror__deps: ['$DLFCN_DATA'], + dlerror__deps: ['$DLFCN'], dlerror: function() { // char *dlerror(void); // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlerror.html - if (DLFCN_DATA.errorMsg === null) { + if (DLFCN.errorMsg === null) { return 0; } else { - if (DLFCN_DATA.error) _free(DLFCN_DATA.error); - var msgArr = intArrayFromString(DLFCN_DATA.errorMsg); - DLFCN_DATA.error = allocate(msgArr, 'i8', ALLOC_NORMAL); - DLFCN_DATA.errorMsg = null; - return DLFCN_DATA.error; + if (DLFCN.error) _free(DLFCN.error); + var msgArr = intArrayFromString(DLFCN.errorMsg); + DLFCN.error = allocate(msgArr, 'i8', ALLOC_NORMAL); + DLFCN.errorMsg = null; + return DLFCN.error; } }, @@ -5227,8 +5298,8 @@ LibraryManager.library = { ['i32', 'tm_zone']]), // Statically allocated time struct. __tm_current: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STATIC)', - // Statically allocated timezone strings. - __tm_timezones: {}, + // Statically allocated timezone string. We only use GMT as a timezone. + __tm_timezone: 'allocate(intArrayFromString("GMT"), "i8", ALLOC_STATIC)', // Statically allocated time strings. __tm_formatted: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STATIC)', @@ -5256,7 +5327,7 @@ LibraryManager.library = { return _gmtime_r(time, ___tm_current); }, - gmtime_r__deps: ['__tm_struct_layout', '__tm_timezones'], + gmtime_r__deps: ['__tm_struct_layout', '__tm_timezone'], gmtime_r: function(time, tmPtr) { var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000); var offsets = ___tm_struct_layout; @@ -5278,12 +5349,7 @@ LibraryManager.library = { start.setUTCMilliseconds(0); var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); {{{ makeSetValue('tmPtr', 'offsets.tm_yday', 'yday', 'i32') }}} - - var timezone = "GMT"; - if (!(timezone in ___tm_timezones)) { - ___tm_timezones[timezone] = allocate(intArrayFromString(timezone), 'i8', ALLOC_NORMAL); - } - {{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezones[timezone]', 'i32') }}} + {{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezone', 'i32') }}} return tmPtr; }, @@ -5302,7 +5368,7 @@ LibraryManager.library = { return _localtime_r(time, ___tm_current); }, - localtime_r__deps: ['__tm_struct_layout', '__tm_timezones', 'tzset'], + localtime_r__deps: ['__tm_struct_layout', '__tm_timezone', 'tzset'], localtime_r: function(time, tmPtr) { _tzset(); var offsets = ___tm_struct_layout; @@ -5323,11 +5389,7 @@ LibraryManager.library = { var dst = Number(start.getTimezoneOffset() != date.getTimezoneOffset()); {{{ makeSetValue('tmPtr', 'offsets.tm_isdst', 'dst', 'i32') }}} - var timezone = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | date.toString().match(/\(([A-Z]+)\)/)[1]; - if (!(timezone in ___tm_timezones)) { - ___tm_timezones[timezone] = allocate(intArrayFromString(timezone), 'i8', ALLOC_NORMAL); - } - {{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezones[timezone]', 'i32') }}} + {{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezone', 'i32') }}} return tmPtr; }, @@ -7193,7 +7255,25 @@ LibraryManager.library = { } }, + // ========================================================================== + // net/if.h + // ========================================================================== + + if_nametoindex: function(a) { + return 0; + }, + if_indextoname: function(a, b) { + return 0; + }, + if_nameindex: function() { + return 0; + }, + if_freenameindex: function(a) { + }, + + // ========================================================================== // netinet/in.h + // ========================================================================== _in6addr_any: 'allocate([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "i8", ALLOC_STATIC)', diff --git a/src/library_gl.js b/src/library_gl.js index c134ad97..16ea5531 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -657,6 +657,20 @@ var LibraryGL = { glBufferData__sig: 'viiii', glBufferData: function(target, size, data, usage) { + switch (usage) { // fix usages, WebGL only has *_DRAW + case 0x88E1: // GL_STREAM_READ + case 0x88E2: // GL_STREAM_COPY + usage = 0x88E0; // GL_STREAM_DRAW + break; + case 0x88E5: // GL_STATIC_READ + case 0x88E6: // GL_STATIC_COPY + usage = 0x88E4; // GL_STATIC_DRAW + break; + case 0x88E9: // GL_DYNAMIC_READ + case 0x88EA: // GL_DYNAMIC_COPY + usage = 0x88E8; // GL_DYNAMIC_DRAW + break; + } Module.ctx.bufferData(target, HEAPU8.subarray(data, data+size), usage); }, @@ -3398,6 +3412,7 @@ var LibraryGL = { // does not work for glBegin/End, where we generate renderer components dynamically and then // disable them ourselves, but it does help with glDrawElements/Arrays. if (!this.modifiedClientAttributes) { + GL.immediate.vertexCounter = (GL.immediate.stride * count) / 4; // XXX assuming float return; } this.modifiedClientAttributes = false; diff --git a/src/library_sdl.js b/src/library_sdl.js index d6cb6d18..9231f41b 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -2191,11 +2191,37 @@ var LibrarySDL = { // Joysticks - SDL_NumJoysticks: function() { return 0 }, + SDL_NumJoysticks: function() { return 0; }, - SDL_JoystickOpen: function(deviceIndex) { return 0 }, + SDL_JoystickName: function(deviceIndex) { return 0; }, - SDL_JoystickGetButton: function(joystick, button) { return 0 }, + SDL_JoystickOpen: function(deviceIndex) { return 0; }, + + SDL_JoystickOpened: function(deviceIndex) { return 0; }, + + SDL_JoystickIndex: function(joystick) { return 0; }, + + SDL_JoystickNumAxes: function(joystick) { return 0; }, + + SDL_JoystickNumBalls: function(joystick) { return 0; }, + + SDL_JoystickNumHats: function(joystick) { return 0; }, + + SDL_JoystickNumButtons: function(joystick) { return 0; }, + + SDL_JoystickUpdate: function() {}, + + SDL_JoystickEventState: function(state) { return 0; }, + + SDL_JoystickGetAxis: function(joystick, axis) { return 0; }, + + SDL_JoystickGetHat: function(joystick, hat) { return 0; }, + + SDL_JoystickGetBall: function(joystick, ball, dxptr, dyptr) { return -1; }, + + SDL_JoystickGetButton: function(joystick, button) { return 0; }, + + SDL_JoystickClose: function(joystick) {}, // Misc diff --git a/src/modules.js b/src/modules.js index fa6c0983..373e60d9 100644 --- a/src/modules.js +++ b/src/modules.js @@ -443,6 +443,7 @@ var LibraryManager = { }, isStubFunction: function(ident) { + if (SIDE_MODULE == 1) return false; // cannot eliminate these, as may be implement in the main module and imported by us var libCall = LibraryManager.library[ident.substr(1)]; return typeof libCall === 'function' && libCall.toString().replace(/\s/g, '') === 'function(){}' && !(ident in Functions.implementedFunctions); diff --git a/src/parseTools.js b/src/parseTools.js index 66354dca..90c5acab 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -35,8 +35,13 @@ function preprocess(text) { var op = parts[2]; var value = parts[3]; if (op) { - assert(op === '==') - showStack.push(ident in this && this[ident] == value); + if (op === '==') { + showStack.push(ident in this && this[ident] == v |