diff options
author | Alon Zakai <alonzakai@gmail.com> | 2014-01-03 15:16:17 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2014-01-03 15:16:17 -0800 |
commit | 8478d6aee54d6c52de16d8c58309534afbf5bf9e (patch) | |
tree | bec73fd8e0cd6888d2dfb6b9e6a1423cc2432f61 /src/library.js | |
parent | 1a007b1631509b9d72499a8f4402294017ee04dc (diff) | |
parent | a8e26049c1a72fa6b19dac45fa2b44616f94241a (diff) |
Merge branch 'incoming'
Diffstat (limited to 'src/library.js')
-rw-r--r-- | src/library.js | 283 |
1 files changed, 279 insertions, 4 deletions
diff --git a/src/library.js b/src/library.js index 26d766e9..354e5549 100644 --- a/src/library.js +++ b/src/library.js @@ -1868,14 +1868,13 @@ LibraryManager.library = { #endif #if USE_TYPED_ARRAYS == 2 } else if (type == 'i64') { - -#if TARGET_LE32 +#if TARGET_LE32 == 1 ret = [{{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}}, {{{ makeGetValue('varargs', 'argIndex+8', 'i32', undefined, undefined, true) }}}]; argIndex += {{{ STACK_ALIGN }}}; // each 32-bit chunk is in a 64-bit block #else - ret = [{{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}}, - {{{ makeGetValue('varargs', 'argIndex+4', 'i32', undefined, undefined, true) }}}]; + ret = [{{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true, 4) }}}, + {{{ makeGetValue('varargs', 'argIndex+4', 'i32', undefined, undefined, true, 4) }}}]; #endif #else @@ -7702,6 +7701,94 @@ LibraryManager.library = { return _gai_strerror.buffer; }, + // Implement netdb.h protocol entry (getprotoent, getprotobyname, getprotobynumber, setprotoent, endprotoent) + // http://pubs.opengroup.org/onlinepubs/9699919799/functions/getprotobyname.html + // The Protocols object holds our 'fake' protocols 'database'. + $Protocols: { + list: [], + map: {} + }, + setprotoent__deps: ['$Protocols'], + setprotoent: function(stayopen) { + // void setprotoent(int stayopen); + + // Allocate and populate a protoent structure given a name, protocol number and array of aliases + function allocprotoent(name, proto, aliases) { + // write name into buffer + var nameBuf = _malloc(name.length + 1); + writeAsciiToMemory(name, nameBuf); + + // write aliases into buffer + var j = 0; + var length = aliases.length; + var aliasListBuf = _malloc((length + 1) * 4); // Use length + 1 so we have space for the terminating NULL ptr. + + for (var i = 0; i < length; i++, j += 4) { + var alias = aliases[i]; + var aliasBuf = _malloc(alias.length + 1); + writeAsciiToMemory(alias, aliasBuf); + {{{ makeSetValue('aliasListBuf', 'j', 'aliasBuf', 'i8*') }}}; + } + {{{ makeSetValue('aliasListBuf', 'j', '0', 'i8*') }}}; // Terminating NULL pointer. + + // generate protoent + var pe = _malloc({{{ C_STRUCTS.protoent.__size__ }}}); + {{{ makeSetValue('pe', C_STRUCTS.protoent.p_name, 'nameBuf', 'i8*') }}}; + {{{ makeSetValue('pe', C_STRUCTS.protoent.p_aliases, 'aliasListBuf', 'i8**') }}}; + {{{ makeSetValue('pe', C_STRUCTS.protoent.p_proto, 'proto', 'i32') }}}; + return pe; + }; + + // Populate the protocol 'database'. The entries are limited to tcp and udp, though it is fairly trivial + // to add extra entries from /etc/protocols if desired - though not sure if that'd actually be useful. + var list = Protocols.list; + var map = Protocols.map; + if (list.length === 0) { + var entry = allocprotoent('tcp', 6, ['TCP']); + list.push(entry); + map['tcp'] = map['6'] = entry; + entry = allocprotoent('udp', 17, ['UDP']); + list.push(entry); + map['udp'] = map['17'] = entry; + } + + _setprotoent.index = 0; + }, + + endprotoent: function() { + // void endprotoent(void); + // We're not using a real protocol database so we don't do a real close. + }, + + getprotoent__deps: ['setprotoent', '$Protocols'], + getprotoent: function(number) { + // struct protoent *getprotoent(void); + // reads the next entry from the protocols 'database' or return NULL if 'eof' + if (_setprotoent.index === Protocols.list.length) { + return 0; + } else { + var result = Protocols.list[_setprotoent.index++]; + return result; + } + }, + + getprotobyname__deps: ['setprotoent', '$Protocols'], + getprotobyname: function(name) { + // struct protoent *getprotobyname(const char *); + name = Pointer_stringify(name); + _setprotoent(true); + var result = Protocols.map[name]; + return result; + }, + + getprotobynumber__deps: ['setprotoent', '$Protocols'], + getprotobynumber: function(number) { + // struct protoent *getprotobynumber(int proto); + _setprotoent(true); + var result = Protocols.map[number]; + return result; + }, + // ========================================================================== // sockets. Note that the implementation assumes all sockets are always // nonblocking @@ -8748,6 +8835,194 @@ LibraryManager.library = { } }, + // Returns [parentFuncArguments, functionName, paramListName] + _emscripten_traverse_stack: function(args) { + if (!args || !args.callee || !args.callee.name) { + return [null, '', '']; + } + + var funstr = args.callee.toString(); + var funcname = args.callee.name; + var str = '('; + var first = true; + for(i in args) { + var a = args[i]; + if (!first) { + str += ", "; + } + first = false; + if (typeof a === 'number' || typeof a === 'string') { + str += a; + } else { + str += '(' + typeof a + ')'; + } + } + str += ')'; + var caller = args.callee.caller; + args = caller ? caller.arguments : []; + if (first) + str = ''; + return [args, funcname, str]; + }, + + emscripten_get_callstack_js__deps: ['_emscripten_traverse_stack'], + emscripten_get_callstack_js: function(flags) { + var err = new Error(); + if (!err.stack) { + Runtime.warnOnce('emscripten_get_callstack_js is not supported on this browser!'); + return ''; + } + var callstack = new Error().stack.toString(); + + // Find the symbols in the callstack that corresponds to the functions that report callstack information, and remove everyhing up to these from the output. + var iThisFunc = callstack.lastIndexOf('_emscripten_log'); + var iThisFunc2 = callstack.lastIndexOf('_emscripten_get_callstack'); + var iNextLine = callstack.indexOf('\n', Math.max(iThisFunc, iThisFunc2))+1; + callstack = callstack.slice(iNextLine); + + // If user requested to see the original source stack, but no source map information is available, just fall back to showing the JS stack. + if (flags & 8/*EM_LOG_C_STACK*/ && typeof emscripten_source_map === 'undefined') { + Runtime.warnOnce('Source map information is not available, emscripten_log with EM_LOG_C_STACK will be ignored. Build with "--pre-js $EMSCRIPTEN/src/emscripten-source-map.min.js" linker flag to add source map loading to code.'); + flags ^= 8/*EM_LOG_C_STACK*/; + flags |= 16/*EM_LOG_JS_STACK*/; + } + + var stack_args = null; + if (flags & 128 /*EM_LOG_FUNC_PARAMS*/) { + // To get the actual parameters to the functions, traverse the stack via the unfortunately deprecated 'arguments.callee' method, if it works: + var stack_args = __emscripten_traverse_stack(arguments); + while (stack_args[1].indexOf('_emscripten_') >= 0) + stack_args = __emscripten_traverse_stack(stack_args[0]); + } + + // Process all lines: + lines = callstack.split('\n'); + callstack = ''; + var firefoxRe = new RegExp('\\s*(.*?)@(.*):(.*)'); // Extract components of form ' Object._main@http://server.com:4324' + var chromeRe = new RegExp('\\s*at (.*?) \\\((.*):(.*):(.*)\\\)'); // Extract components of form ' at Object._main (http://server.com/file.html:4324:12)' + + for(l in lines) { + var line = lines[l]; + + var jsSymbolName = ''; + var file = ''; + var lineno = 0; + var column = 0; + + var parts = chromeRe.exec(line); + if (parts && parts.length == 5) { + jsSymbolName = parts[1]; + file = parts[2]; + lineno = parts[3]; + column = parts[4]; + } else { + parts = firefoxRe.exec(line); + if (parts && parts.length == 4) { + jsSymbolName = parts[1]; + file = parts[2]; + lineno = parts[3]; + column = 0; // Firefox doesn't carry column information. See https://bugzilla.mozilla.org/show_bug.cgi?id=762556 + } else { + // Was not able to extract this line for demangling/sourcemapping purposes. Output it as-is. + callstack += line + '\n'; + continue; + } + } + + // Try to demangle the symbol, but fall back to showing the original JS symbol name if not available. + var cSymbolName = (flags & 32/*EM_LOG_DEMANGLE*/) ? demangle(jsSymbolName) : jsSymbolName; + if (!cSymbolName) { + cSymbolName = jsSymbolName; + } + + var haveSourceMap = false; + + if (flags & 8/*EM_LOG_C_STACK*/) { + var orig = emscripten_source_map.originalPositionFor({line: lineno, column: column}); + haveSourceMap = (orig && orig.source); + if (haveSourceMap) { + if (flags & 64/*EM_LOG_NO_PATHS*/) { + orig.source = orig.source.substring(orig.source.replace(/\\/g, "/").lastIndexOf('/')+1); + } + callstack += ' at ' + cSymbolName + ' (' + orig.source + ':' + orig.line + ':' + orig.column + ')\n'; + } + } + if ((flags & 16/*EM_LOG_JS_STACK*/) || !haveSourceMap) { + if (flags & 64/*EM_LOG_NO_PATHS*/) { + file = file.substring(file.replace(/\\/g, "/").lastIndexOf('/')+1); + } + callstack += (haveSourceMap ? (' = '+jsSymbolName) : (' at '+cSymbolName)) + ' (' + file + ':' + lineno + ':' + column + ')\n'; + } + + // If we are still keeping track with the callstack by traversing via 'arguments.callee', print the function parameters as well. + if (flags & 128 /*EM_LOG_FUNC_PARAMS*/ && stack_args[0]) { + if (stack_args[1] == jsSymbolName && stack_args[2].length > 0) { + callstack = callstack.replace(/\s+$/, ''); + callstack += ' with values: ' + stack_args[1] + stack_args[2] + '\n'; + } + stack_args = __emscripten_traverse_stack(stack_args[0]); + } + } + // Trim extra whitespace at the end of the output. + callstack = callstack.replace(/\s+$/, ''); + return callstack; + }, + + emscripten_get_callstack__deps: ['emscripten_get_callstack_js'], + emscripten_get_callstack: function(flags, str, maxbytes) { + var callstack = _emscripten_get_callstack_js(flags); + // User can query the required amount of bytes to hold the callstack. + if (!str || maxbytes <= 0) { + return callstack.length+1; + } + // Truncate output to avoid writing past bounds. + if (callstack.length > maxbytes-1) { + callstack.slice(0, maxbytes-1); + } + // Output callstack string as C string to HEAP. + writeStringToMemory(callstack, str, false); + + // Return number of bytes written. + return callstack.length+1; + }, + + emscripten_log_js__deps: ['emscripten_get_callstack_js'], + emscripten_log_js: function(flags, str) { + if (flags & 24/*EM_LOG_C_STACK | EM_LOG_JS_STACK*/) { + str = str.replace(/\s+$/, ''); // Ensure the message and the callstack are joined cleanly with exactly one newline. + str += (str.length > 0 ? '\n' : '') + _emscripten_get_callstack_js(flags); + } + + if (flags & 1 /*EM_LOG_CONSOLE*/) { + if (flags & 4 /*EM_LOG_ERROR*/) { + console.error(str); + } else if (flags & 2 /*EM_LOG_WARN*/) { + console.warn(str); + } else { + console.log(str); + } + } else if (flags & 6 /*EM_LOG_ERROR|EM_LOG_WARN*/) { + Module.printErr(str); + } else { + Module.print(str); + } + }, + + emscripten_log__deps: ['_formatString', 'emscripten_log_js'], + emscripten_log: function(flags, varargs) { + // Extract the (optionally-existing) printf format specifier field from varargs. + var format = {{{ makeGetValue('varargs', '0', 'i32', undefined, undefined, true) }}}; + varargs += Math.max(Runtime.getNativeFieldSize('i32'), Runtime.getAlignSize('i32', null, true)); + var str = ''; + if (format) { + var result = __formatString(format, varargs); + for(var i = 0 ; i < result.length; ++i) { + str += String.fromCharCode(result[i]); + } + } + _emscripten_log_js(flags, str); + }, + //============================ // emscripten vector ops //============================ |