For debugging Tachyon, I have improved the function call tracing mechanism in the js2js preprocessor. I also added a makefile target, "make tachyon-debug.js", which generates a version of the compiler in one file which traces all the function calls. Here's an example:
% make tachyon-debug.js
parser/js2js -debug utility/debug.js utility/system.js utility/iterators.js utility/graph.js utility/arrays.js utility/heap.js utility/hashmap.js utility/hashset.js utility/linkedlist.js utility/strings.js utility/modules.js utility/misc.js utility/num.js utility/xml.js utility/html.js compiler/targets.js compiler/params.js compiler/config.js compiler/compiler.js compiler/init.js compiler/bootstrap.js parser/misc.js parser/scanner.js parser/parser.js parser/pp.js parser/ast-passes.js ir/types.js ir/static.js ir/instructions.js ir/constants.js ir/iir.js ir/cfg.js ir/functions.js ir/ast-to-ir.js ir/optpatterns.js ir/constprop.js ir/commelim.js ir/inlining.js ir/lowering.js platform/ffi.js platform/mcb.js runtime/layout.js runtime/context.js runtime/objects.js backend/asm.js backend/regalloc.js backend/linearscan.js backend/backend.js backend/x86/asm.js backend/x86/config.js backend/x86/ir-to-asm.js main.js > tachyon-debug.js
% d8 tachyon-debug.js
| (( "utility/iterators.js"@13.1-17.2: Iterator
| | (( "utility/debug.js"@73.1-77.2: assertNew
| | | (( "utility/debug.js"@62.1-68.2: isGlobal
| | | | (( "utility/debug.js"@65.19-65.47: isGlobal
| | | | )) "utility/debug.js"@65.33-65.45: isGlobal
| | | )) "utility/debug.js"@67.5-67.27: isGlobal
| | )) "utility/debug.js"@73.1-77.2: assertNew
| )) "utility/iterators.js"@16.5-16.17: Iterator
| (( "utility/iterators.js"@13.1-17.2: Iterator
| | (( "utility/debug.js"@73.1-77.2: assertNew
| | | (( "utility/debug.js"@62.1-68.2: isGlobal
| | | | (( "utility/debug.js"@65.19-65.47: isGlobal
| | | | )) "utility/debug.js"@65.33-65.45: isGlobal
| | | )) "utility/debug.js"@67.5-67.27: isGlobal
| | )) "utility/debug.js"@73.1-77.2: assertNew
| )) "utility/iterators.js"@16.5-16.17: Iterator
...
The symbol (( indicates a function entry and )) indicates a function return (this is convenient to navigate in an editor which matches parentheses, between the entry and return). The indentation indicates the call nesting. Finally, when it is known, the function name is printed.
The execution is rather slow because all the function are traced. To filter out some functions, you'll have to manually edit the file function filter_debug in parser/ast-passes.js . You can filter out all the functions in a file, or specific functions. Here's the current implementation of that function:
ast_pass1_ctx.prototype.filter_debug = function (ast)
{
// TODO: This filtering should be user configurable from a command line option.
if (ast.loc.filename === "parser/parser.js" ||
ast.loc.filename === "parser/scanner.js" ||
// ast.loc.filename === "utility/debug.js" ||
(this.fn_decl !== null &&
this.fn_decl.id.toString() === "assert"))
return false;
return true;
}
I'm thinking that we could extend the tracing facility to get timing information and also space usage information. The relevant functions to change are defined in the function walk_statement in parser/ast-passes.js :
ast_pass1_ctx.prototype.walk_statement = function (ast)
{
if (ast === null)
{
// no transformation
return ast;
}
else if (ast instanceof Program)
{
var debug_lib = " \
\
var debug$print = print; \
var debug$nesting = 0; \
\
function debug$nest(loc, fn, enter) \
{ var level = enter ? ++debug$nesting : debug$nesting--; \
var prefix = \"\"; \
if (level > 9) { prefix = \"|[\"+level+\"] \"; level = 8; } \
while (level-- > 0) prefix = \"| \" + prefix; \
debug$print(prefix+(enter?\"((\":\"))\")+\" \"+loc+\": \"+fn); \
} \
\
function debug$enter(loc, fn) \
{ debug$nest(loc, fn, true); } \
\
function debug$return0(loc, fn) \
{ debug$nest(loc, fn, false); } \
\
function debug$return1(loc, fn, result) \
{ debug$nest(loc, fn, false); \
return result; \
} \
\
";
Marc