diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/intertyper.js | 10 | ||||
-rw-r--r-- | src/jsifier.js | 35 | ||||
-rw-r--r-- | src/library.js | 1630 | ||||
-rw-r--r-- | src/library_fs.js | 1399 | ||||
-rw-r--r-- | src/library_gl.js | 15 | ||||
-rw-r--r-- | src/library_openal.js | 17 | ||||
-rw-r--r-- | src/library_sdl.js | 32 | ||||
-rw-r--r-- | src/library_sockfs.js | 568 | ||||
-rw-r--r-- | src/library_tty.js | 32 | ||||
-rw-r--r-- | src/modules.js | 1 | ||||
-rw-r--r-- | src/parseTools.js | 9 | ||||
-rw-r--r-- | src/preamble.js | 4 | ||||
-rw-r--r-- | src/settings.js | 40 | ||||
-rw-r--r-- | src/shell_sharedlib.js | 19 |
14 files changed, 2541 insertions, 1270 deletions
diff --git a/src/intertyper.js b/src/intertyper.js index 31e97bd0..ddb93d71 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -707,16 +707,24 @@ function intertyper(data, sidePass, baseLineNums) { var tokensLeft = item.tokens.slice(2); item.ident = eatLLVMIdent(tokensLeft); if (item.ident == 'asm') { + if (ASM_JS) { + warnOnce('inline JS in asm.js mode can cause the code to no longer fall in the asm.js subset of JavaScript'); + } + assert(TARGET_LE32, 'inline js is only supported in le32'); // Inline assembly is just JavaScript that we paste into the code item.intertype = 'value'; if (tokensLeft[0].text == 'sideeffect') tokensLeft.splice(0, 1); item.ident = tokensLeft[0].text.substr(1, tokensLeft[0].text.length-2) || ';'; // use ; for empty inline assembly var i = 0; + var params = [], args = []; splitTokenList(tokensLeft[3].item.tokens).map(function(element) { var ident = toNiceIdent(element[1].text); var type = element[0].text; - item.ident = item.ident.replace(new RegExp('\\$' + i++, 'g'), ident); + params.push('$' + (i++)); + args.push(ident); }); + if (item.assignTo) item.ident = 'return ' + item.ident; + item.ident = '(function(' + params + ') { ' + item.ident + ' })(' + args + ');'; return { forward: null, ret: [item], item: item }; } if (item.ident.substr(-2) == '()') { diff --git a/src/jsifier.js b/src/jsifier.js index 7273f54c..38f3bd5e 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; } @@ -1142,8 +1143,8 @@ function JSify(data, functionsOnly, givenFunctions) { }); var range = maxx - minn; var useIfs = (item.switchLabels.length+1) < 6 || range > 10*1024 || (range/item.switchLabels.length) > 1024; // heuristics - if (VERBOSE && useIfs && item.switchLabels.length > 2) { - warn('not optimizing llvm switch into js switch because ' + [range, range/item.switchLabels.length]); + if (VERBOSE && useIfs && item.switchLabels.length >= 6) { + warn('not optimizing llvm switch into js switch because range of values is ' + range + ', density is ' + range/item.switchLabels.length); } var phiSets = calcPhiSets(item); @@ -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'); @@ -1779,7 +1788,7 @@ function JSify(data, functionsOnly, givenFunctions) { } } - if (abortExecution) throw 'Aborting compilation due to previous warnings'; + if (abortExecution) throw 'Aborting compilation due to previous errors'; if (phase == 'pre' || phase == 'funcs') { PassManager.serialize(); diff --git a/src/library.js b/src/library.js index f6b3d5ef..f3c3c1ec 100644 --- a/src/library.js +++ b/src/library.js @@ -323,10 +323,16 @@ LibraryManager.library = { path = Pointer_stringify(path); // we don't want this in the JS API as the JS API // uses mknod to create all nodes. - var err = FS.mayMknod(mode); - if (err) { - ___setErrNo(err); - return -1; + switch (mode & {{{ cDefine('S_IFMT') }}}) { + case {{{ cDefine('S_IFREG') }}}: + case {{{ cDefine('S_IFCHR') }}}: + case {{{ cDefine('S_IFBLK') }}}: + case {{{ cDefine('S_IFIFO') }}}: + case {{{ cDefine('S_IFSOCK') }}}: + break; + default: + ___setErrNo(ERRNO_CODES.EINVAL); + return -1; } try { FS.mknod(path, mode, dev); @@ -600,31 +606,32 @@ LibraryManager.library = { // poll.h // ========================================================================== + __DEFAULT_POLLMASK: {{{ cDefine('POLLIN') }}} | {{{ cDefine('POLLOUT') }}}, __pollfd_struct_layout: Runtime.generateStructInfo([ ['i32', 'fd'], ['i16', 'events'], ['i16', 'revents']]), - poll__deps: ['$FS', '__pollfd_struct_layout'], + poll__deps: ['$FS', '__DEFAULT_POLLMASK', '__pollfd_struct_layout'], poll: function(fds, nfds, timeout) { // int poll(struct pollfd fds[], nfds_t nfds, int timeout); // http://pubs.opengroup.org/onlinepubs/009695399/functions/poll.html - // NOTE: This is pretty much a no-op mimicking glibc. var offsets = ___pollfd_struct_layout; var nonzero = 0; for (var i = 0; i < nfds; i++) { var pollfd = fds + ___pollfd_struct_layout.__size__ * i; var fd = {{{ makeGetValue('pollfd', 'offsets.fd', 'i32') }}}; var events = {{{ makeGetValue('pollfd', 'offsets.events', 'i16') }}}; - var revents = 0; + var mask = {{{ cDefine('POLLNVAL') }}}; var stream = FS.getStream(fd); if (stream) { - if (events & {{{ cDefine('POLLIN') }}}) revents |= {{{ cDefine('POLLIN') }}}; - if (events & {{{ cDefine('POLLOUT') }}}) revents |= {{{ cDefine('POLLOUT') }}}; - } else { - if (events & {{{ cDefine('POLLNVAL') }}}) revents |= {{{ cDefine('POLLNVAL') }}}; + mask = ___DEFAULT_POLLMASK; + if (stream.stream_ops.poll) { + mask = stream.stream_ops.poll(stream); + } } - if (revents) nonzero++; - {{{ makeSetValue('pollfd', 'offsets.revents', 'revents', 'i16') }}} + mask &= events | {{{ cDefine('POLLERR') }}} | {{{ cDefine('POLLHUP') }}}; + if (mask) nonzero++; + {{{ makeSetValue('pollfd', 'offsets.revents', 'mask', 'i16') }}} } return nonzero; }, @@ -723,7 +730,7 @@ LibraryManager.library = { FS.close(stream); return 0; } catch (e) { - FS.handleFSError(e);; + FS.handleFSError(e); return -1; } }, @@ -1006,9 +1013,11 @@ LibraryManager.library = { return -1; } +#if SOCKET_WEBRTC if (stream && ('socket' in stream)) { return _recv(fildes, buf, nbyte, 0); } +#endif try { var slab = {{{ makeGetSlabs('buf', 'i8', true) }}}; @@ -1139,9 +1148,11 @@ LibraryManager.library = { return -1; } +#if SOCKET_WEBRTC if (stream && ('socket' in stream)) { return _send(fildes, buf, nbyte, 0); } +#endif try { var slab = {{{ makeGetSlabs('buf', 'i8', true) }}}; @@ -4268,9 +4279,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) { @@ -4652,20 +4665,28 @@ LibraryManager.library = { cos: 'Math.cos', cosf: 'Math.cos', + cosl: 'Math.cos', sin: 'Math.sin', sinf: 'Math.sin', + sinl: 'Math.sin', tan: 'Math.tan', tanf: 'Math.tan', + tanl: 'Math.tan', acos: 'Math.acos', acosf: 'Math.acos', + acosl: 'Math.acos', asin: 'Math.asin', asinf: 'Math.asin', + asinl: 'Math.asin', atan: 'Math.atan', atanf: 'Math.atan', + atanl: 'Math.atan', atan2: 'Math.atan2', atan2f: 'Math.atan2', + atan2l: 'Math.atan2', exp: 'Math.exp', expf: 'Math.exp', + expl: 'Math.exp', // The erf and erfc functions are inspired from // http://www.digitalmars.com/archives/cplusplus/3634.html @@ -4701,7 +4722,8 @@ LibraryManager.library = { } while (Math.abs(q1 - q2) / q2 > MATH_TOLERANCE); return (ONE_SQRTPI * Math.exp(- x * x) * q2); }, - erfcf: 'erfcf', + erfcf: 'erfc', + erfcl: 'erfc', erf__deps: ['erfc'], erf: function(x) { var MATH_TOLERANCE = 1E-12; @@ -4725,18 +4747,25 @@ LibraryManager.library = { return (TWO_SQRTPI * sum); }, erff: 'erf', + erfl: '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', @@ -4807,6 +4836,7 @@ LibraryManager.library = { return __reallyNegative(a) === __reallyNegative(b) ? a : -a; }, copysignf: 'copysign', + copysignl: 'copysign', __signbit__deps: ['copysign'], __signbit: function(x) { // We implement using copysign so that we get support @@ -4819,56 +4849,70 @@ LibraryManager.library = { return Math.sqrt(a*a + b*b); }, hypotf: 'hypot', + hypotl: 'hypot', sinh: function(x) { var p = Math.pow(Math.E, x); return (p - (1 / p)) / 2; }, sinhf: 'sinh', + sinhl: 'sinh', cosh: function(x) { var p = Math.pow(Math.E, x); return (p + (1 / p)) / 2; }, coshf: 'cosh', + coshl: 'cosh', tanh__deps: ['sinh', 'cosh'], tanh: function(x) { return _sinh(x) / _cosh(x); }, tanhf: 'tanh', + tanhl: 'tanh', asinh: function(x) { return Math.log(x + Math.sqrt(x * x + 1)); }, asinhf: 'asinh', + asinhl: 'asinh', acosh: function(x) { return Math.log(x * 1 + Math.sqrt(x * x - 1)); }, acoshf: 'acosh', + acoshl: 'acosh', atanh: function(x) { return Math.log((1 + x) / (1 - x)) / 2; }, atanhf: 'atanh', + atanhl: 'atanh', exp2: function(x) { return Math.pow(2, x); }, exp2f: 'exp2', + exp2l: 'exp2', expm1: function(x) { return Math.exp(x) - 1; }, expm1f: 'expm1', + expm1l: 'expm1', round: function(x) { return (x < 0) ? -Math.round(-x) : Math.round(x); }, roundf: 'round', + roundl: 'round', lround: 'round', lroundf: 'round', + lroundl: 'round', llround: 'round', llroundf: 'round', + llroundl: 'round', rint: function(x) { if (Math.abs(x % 1) !== 0.5) return Math.round(x); return x + x % 2 + ((x < 0) ? 1 : -1); }, rintf: 'rint', + rintl: 'rint', lrint: 'rint', lrintf: 'rint', + lrintl: 'rint', #if USE_TYPED_ARRAYS == 2 llrint: function(x) { x = (x < 0) ? -Math.round(-x) : Math.round(x); @@ -4878,50 +4922,63 @@ LibraryManager.library = { llrint: 'rint', #endif llrintf: 'llrint', + llrintl: 'llrint', nearbyint: 'rint', nearbyintf: 'rint', + nearbyintl: 'rint', trunc: function(x) { return (x < 0) ? Math.ceil(x) : Math.floor(x); }, truncf: 'trunc', + truncl: 'trunc', fdim: function(x, y) { return (x > y) ? x - y : 0; }, fdimf: 'fdim', + fdiml: 'fdim', fmax: function(x, y) { return isNaN(x) ? y : isNaN(y) ? x : Math.max(x, y); }, fmaxf: 'fmax', + fmaxl: 'fmax', fmin: function(x, y) { return isNaN(x) ? y : isNaN(y) ? x : Math.min(x, y); }, fminf: 'fmin', + fminl: 'fmin', fma: function(x, y, z) { return x * y + z; }, fmaf: 'fma', + fmal: 'fma', fmod: function(x, y) { return x % y; }, fmodf: 'fmod', + fmodl: 'fmod', remainder: 'fmod', remainderf: 'fmod', + remainderl: 'fmod', log10: function(x) { return Math.log(x) / Math.LN10; }, log10f: 'log10', + log10l: 'log10', log1p: function(x) { return Math.log(1 + x); }, log1pf: 'log1p', + log1pl: 'log1p', log2: function(x) { return Math.log(x) / Math.LN2; }, log2f: 'log2', + log2l: 'log2', nan: function(x) { return NaN; }, nanf: 'nan', + nanl: 'nan', sincos: function(x, sine, cosine) { var sineVal = Math.sin(x), @@ -4929,6 +4986,7 @@ LibraryManager.library = { {{{ makeSetValue('sine', '0', 'sineVal', 'double') }}}; {{{ makeSetValue('cosine', '0', 'cosineVal', 'double') }}}; }, + sincosl: 'sincos', sincosf: function(x, sine, cosine) { var sineVal = Math.sin(x), @@ -5007,24 +5065,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; } @@ -5035,7 +5143,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); @@ -5043,19 +5151,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. @@ -5069,60 +5184,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; @@ -5131,18 +5252,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; } }, @@ -5222,8 +5343,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)', @@ -5251,7 +5372,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; @@ -5273,12 +5394,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; }, @@ -5297,7 +5413,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; @@ -5318,11 +5434,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; }, @@ -6004,7 +6116,7 @@ LibraryManager.library = { // int clock_gettime(clockid_t clk_id, struct timespec *tp); var now = Date.now(); {{{ makeSetValue('tp', '___timespec_struct_layout.tv_sec', 'Math.floor(now/1000)', 'i32') }}}; // seconds - {{{ makeSetValue('tp', '___timespec_struct_layout.tv_nsec', '0', 'i32') }}}; // nanoseconds - not supported + {{{ makeSetValue('tp', '___timespec_struct_layout.tv_nsec', '(now % 1000) * 1000 * 1000', 'i32') }}}; // nanoseconds (really milliseconds) return 0; }, clock_settime: function(clk_id, tp) { @@ -6016,7 +6128,7 @@ LibraryManager.library = { clock_getres: function(clk_id, res) { // int clock_getres(clockid_t clk_id, struct timespec *res); {{{ makeSetValue('res', '___timespec_struct_layout.tv_sec', '1', 'i32') }}} - {{{ makeSetValue('res', '___timespec_struct_layout.tv_nsec', '0', 'i32') }}} + {{{ makeSetValue('res', '___timespec_struct_layout.tv_nsec', '1000 * 1000', 'i32') }}} // resolution is milliseconds return 0; }, @@ -6910,7 +7022,6 @@ LibraryManager.library = { // ========================================================================== // arpa/inet.h // ========================================================================== - htonl: function(value) { return ((value & 0xff) << 24) + ((value & 0xff00) << 8) + ((value & 0xff0000) >>> 8) + ((value & 0xff000000) >>> 24); @@ -6921,75 +7032,43 @@ LibraryManager.library = { ntohl: 'htonl', ntohs: 'htons', - // http://pubs.opengroup.org/onlinepubs/9699919799/functions/inet_ntop.html - inet_ntop__deps: ['__setErrNo', '$ERRNO_CODES', 'inet_ntop4', 'inet_ntop6'], - inet_ntop: function(af, src, dst, size) { - switch (af) { - case {{{ cDefine('AF_INET') }}}: - return _inet_ntop4(src, dst, size); - case {{{ cDefine('AF_INET6') }}}: - return _inet_ntop6(src, dst, size); - default: - ___setErrNo(ERRNO_CODES.EAFNOSUPPORT); - return 0; - } - }, - inet_pton__deps: ['__setErrNo', '$ERRNO_CODES', 'inet_pton4', 'inet_pton6'], - inet_pton: function(af, src, dst) { - switch (af) { - case {{{ cDefine('AF_INET') }}}: - return _inet_pton4(src, dst); - case {{{ cDefine('AF_INET6') }}}: - return _inet_pton6(src, dst); - default: - ___setErrNo(ERRNO_CODES.EAFNOSUPPORT); - return -1; - } - }, + // old ipv4 only functions + inet_addr__deps: ['_inet_pton4_raw'], inet_addr: function(ptr) { - var b = Pointer_stringify(ptr).split("."); - if (b.length !== 4) return -1; // we return -1 for error, and otherwise a uint32. this helps inet_pton differentiate - return (Number(b[0]) | (Number(b[1]) << 8) | (Number(b[2]) << 16) | (Number(b[3]) << 24)) >>> 0; - }, - _inet_aton_raw: function(str) { - var b = str.split("."); - return (Number(b[0]) | (Number(b[1]) << 8) | (Number(b[2]) << 16) | (Number(b[3]) << 24)) >>> 0; - }, - _inet_ntoa_raw: function(addr) { - return (addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 0xff) + var addr = __inet_pton4_raw(Pointer_stringify(ptr)); + if (addr === null) { + return -1; + } + return addr; }, - inet_ntoa__deps: ['_inet_ntoa_raw'], + inet_ntoa__deps: ['_inet_ntop4_raw'], inet_ntoa: function(in_addr) { if (!_inet_ntoa.buffer) { _inet_ntoa.buffer = _malloc(1024); } - var addr = getValue(in_addr, 'i32'); - var str = __inet_ntoa_raw(addr); + var addr = {{{ makeGetValue('in_addr', '0', 'i32') }}}; + var str = __inet_ntop4_raw(addr); writeStringToMemory(str.substr(0, 1024), _inet_ntoa.buffer); return _inet_ntoa.buffer; }, - inet_aton__deps: ['inet_addr'], + inet_aton__deps: ['_inet_pton4_raw'], inet_aton: function(cp, inp) { - var addr = _inet_addr(cp); - setValue(inp, addr, 'i32'); - if (addr < 0) return 0; - return 1; - }, - - inet_ntop4__deps: ['__setErrNo', '$ERRNO_CODES', '_inet_ntoa_raw'], - inet_ntop4: function(src, dst, size) { - var str = __inet_ntoa_raw(getValue(src, 'i32')); - if (str.length+1 > size) { - ___setErrNo(ERRNO_CODES.ENOSPC); + var addr = __inet_pton4_raw(Pointer_stringify(cp)); + if (addr === null) { return 0; } - writeStringToMemory(str, dst); - return dst; + {{{ makeSetValue('inp', '0', 'addr', 'i32') }}} + return 1; }, - inet_ntop6__deps: ['__setErrNo', '$ERRNO_CODES', 'inet_ntop6_raw'], - inet_ntop6: function(src, dst, size) { - var str = _inet_ntop6_raw(src); + // new ipv4 / ipv6 functions + _inet_ntop4_raw: function(addr) { + return (addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 0xff) + }, + _inet_ntop4__deps: ['__setErrNo', '$ERRNO_CODES', '_inet_ntop4_raw'], + _inet_ntop4: function(src, dst, size) { + var addr = {{{ makeGetValue('src', '0', 'i32') }}}; + var str = __inet_ntop4_raw(addr); if (str.length+1 > size) { ___setErrNo(ERRNO_CODES.ENOSPC); return 0; @@ -6997,9 +7076,8 @@ LibraryManager.library = { writeStringToMemory(str, dst); return dst; }, - inet_ntop6_raw__deps: ['ntohs'], - inet_ntop6_raw: function(src) { - + _inet_ntop6_raw__deps: ['ntohs', '_inet_ntop4_raw'], + _inet_ntop6_raw: function(ints) { // ref: http://www.ietf.org/rfc/rfc2373.txt - section 2.5.4 // Format for IPv4 compatible and mapped 128-bit IPv6 Addresses // 128-bits are split into eight 16-bit words @@ -7014,7 +7092,6 @@ LibraryManager.library = { // +--------------------------------------+----+---------------------+ // |0000.... |