aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xemcc24
-rwxr-xr-xemscripten.py114
-rw-r--r--src/jsifier.js29
-rw-r--r--src/library.js178
-rw-r--r--src/library_gl.js15
-rw-r--r--src/library_sdl.js32
-rw-r--r--src/modules.js1
-rw-r--r--src/parseTools.js9
-rw-r--r--src/settings.js7
-rw-r--r--src/shell_sharedlib.js19
-rw-r--r--tests/browser_main.cpp42
-rw-r--r--tests/browser_module.cpp15
-rw-r--r--tests/dlmalloc_proxy.c85
-rw-r--r--tests/gl_vertex_buffer.c195
-rw-r--r--tests/gl_vertex_buffer.pngbin0 -> 47668 bytes
-rw-r--r--tests/gl_vertex_buffer_pre.c177
-rw-r--r--tests/gl_vertex_buffer_pre.pngbin0 -> 83534 bytes
-rw-r--r--tests/test_browser.py11
-rw-r--r--tests/test_core.py539
-rw-r--r--tests/test_other.py9
-rw-r--r--tools/jsrun.py1
-rw-r--r--tools/shared.py61
22 files changed, 1315 insertions, 248 deletions
diff --git a/emcc b/emcc
index a07ce4f1..958ed7cd 100755
--- a/emcc
+++ b/emcc
@@ -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