diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-12-20 17:22:51 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-12-20 17:22:51 -0800 |
commit | 702cf8f1e8a173a15a745c5ac3bae654c99fe33c (patch) | |
tree | 5046a3c593d3d990c824a82c30a666918a8844a6 /src/library.js | |
parent | 4afedfb8ed66cc1aa95ff515baee3f2c762f63c2 (diff) | |
parent | eb27ff87ae15d0dd9855b06a055b590235d8c3a6 (diff) |
Merge pull request #1635 from juj/emscripten_log
emscripten_log() and emscripten_get_callstack()
Diffstat (limited to 'src/library.js')
-rw-r--r-- | src/library.js | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/src/library.js b/src/library.js index bdc0a39e..fc731e01 100644 --- a/src/library.js +++ b/src/library.js @@ -8835,6 +8835,193 @@ 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 += ')'; + args = args.callee.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 //============================ |