This page serves as a test case for the Mozilla bug report concerning tail-call optimization (TCO) in Javascript. It should highlight strange interferences between the proposed TCO and JIT. Turn JIT on or off, and you'll see the results vary.
System: windows 7 professional, dell optiplex 760, intel core quad cpu Q9650 3.00GHz, RAM 8.00 GB, 64 bits
Results: Duration of a single call, in seconds: the lower, the better.
Stack depth: case name Firefox 3.6 (JIT on) Firefox 3.6 (JIT off) Your browser & system
n: treeforeach_rec() 1.834e-4 s (100: base) 1.834e-4 s (100: base) *
n: treeforeach_tail() 2.220e-4 s (121) 2.192e-4 s (119) *
1: treeforeach_tailopt() 5.438e-4 s (296) 1.871e-4 s (102) *
n: DOMtreeforeach_rec() 2.156e-3 s (100: base) 1.905e-3 s (100: base) *
1: DOMtreeforeach_tail() 1.629e-3 s (76) 1.899e-3 s (100) *
1: DOMtreeforeach_tailopt() 2.904e-3 s (135) 1.823e-3 s (96) *
---
// treeforeach_rec: global.list[9].fun.toString():
function treeforeach_rec(tree, node_id, fun) {
// Execute fun on all nodes of the subtree tree[node_id]
var a, b, node = tree[node_id];
// Breadth
fun(tree, node_id);
// Depth
for (b = 0; b < node.children.length; b++) {
treeforeach_rec(tree, node.children[b], fun);
}
}
---
// treeforeach_tail: global.list[10].fun.toString():
function treeforeach_tail(tree, node_id, fun) {
// Execute fun on all nodes of the subtree tree[node_id]
return (function sub(_tree, _node_id, _fun, _from_below) {
var _node = _tree[_node_id];
if (! _from_below) { // _fun is called one and only one time per node
_fun(_tree, _node_id);
if (_node.firstChild) return sub(_tree, _node.firstChild, _fun, false);
}
if (_node_id === node_id) return; // Done
if (_node.nextSibling) return sub(_tree, _node.nextSibling, _fun, false);
if (_node.parent) return sub(_tree, _node.parent, _fun, true);
return;
})(tree, node_id, fun, false);
}
---
// treeforeach_tailopt: global.list[11].fun.toString():
function treeforeach_tail(tree, node_id, fun){
var _tree = tree, _tree_new, _node_id = node_id, _node_id_new, _fun = fun, _fun_new, _from_below = false, _from_below_new;
L_sub: while (true) {
var _node = _tree[_node_id];
if (! _from_below) {
_fun(_tree, _node_id);
if (_node.firstChild) { _node_id_new = _node.firstChild;
_from_below_new = false;
_node_id = _node_id_new;
_from_below = _from_below_new;
continue L_sub;
}
}
if (_node_id === node_id) return;
if (_node.nextSibling) { _node_id_new = _node.nextSibling;
_from_below_new = false;
_node_id = _node_id_new;
_from_below = _from_below_new;
continue L_sub;
}
if (_node.parent) { _node_id_new = _node.parent;
_from_below_new = true;
_node_id = _node_id_new;
_from_below = _from_below_new;
continue L_sub;
}
return;
};
}
---
// DOMtreeforeach_rec: global.list[12].fun.toString():
function DOMtreeforeach_rec(node, fun) {
fun(node);
var a, c = node.childNodes;
for (a = 0; a < c.length; a++) {
DOMtreeforeach_rec(c[a], fun);
}
}
---
// DOMtreeforeach_tail: global.list[13].fun.toString():
function DOMtreeforeach_tail(node, fun) {
return (function sub(_node, _fun, _from_below) {
if (! _from_below) { // _fun is called one and only one time per node
_fun(_node);
if (_node.firstChild) return sub(_node.firstChild, _fun, false);
}
if (_node.nextSibling) return sub(_node.nextSibling, _fun, false);
if (_node.parentNode) return sub(_node.parentNode, _fun, true);
return;
})(node, fun, false);
}
---
// DOMtreeforeach_tailopt: global.list[14].fun.toString():
function DOMtreeforeach_tail(node, fun){
var _node = node, _node_new, _fun = fun, _fun_new, _from_below = false, _from_below_new;
L_sub: while (true) {
if (! _from_below) {
_fun(_node);
if (_node.firstChild) { _node_new = _node.firstChild;
_from_below_new = false;
_node = _node_new;
_from_below = _from_below_new;
continue L_sub;
}
}
if (_node.nextSibling) { _node_new = _node.nextSibling;
_from_below_new = false;
_node = _node_new;
_from_below = _from_below_new;
continue L_sub;
}
if (_node.parentNode) { _node_new = _node.parentNode;
_from_below_new = true;
_node = _node_new;
_from_below = _from_below_new;
continue L_sub;
}
return;
};
}
_tailopt
*sometimes* runs slower than _tail
and/or _rec
. fact_rec
and gcd_rec
).For the treeforeach_tail we need some text nodes with .js in them.
For the treeforeach_tail we need some text nodes with .js in them.
For the treeforeach_tail we need some text nodes with .js in them.
For the treeforeach_tail we need some text nodes with .js in them.
For the treeforeach_tail we need some text nodes with .js in them.
Produced on 2010-02-04 by mozilla-bug-report.scm - by Guillaume Lathoud (glathoud _at_ yahoo _dot_ fr)