Tail call optimization
JavaScript performance comparison
Info
Preparation code
<script>
function tco1(f) {
var active = false, value, accumulated, args
return function accumulator() {
accumulated = arguments
if (!active) {
active = true
while (accumulated) {
args = accumulated
accumulated = null
value = f.apply(this, args)
}
active = false
return value
}
}
}
function tco2(fn) {
var active, nextArgs;
return function() {
var result;
nextArgs = arguments;
if (!active) {
active = true;
while (nextArgs) {
result = fn.apply(this, [nextArgs, nextArgs = null][0]);
}
active = false;
}
return result;
};
}
function tco3(fn) {
var active, nextArgs;
return function() {
var args, result;
nextArgs = arguments;
if (!active) {
active = true;
while (nextArgs) {
args = nextArgs;
nextArgs = null;
result = fn.apply(this, args);
}
active = false;
}
return result;
};
}
function tco4(fn) {
var queue;
return function() {
var args, result;
if (queue) {
queue.push(arguments);
} else {
queue = [arguments];
while ((args = queue.pop())) {
result = fn.apply(this, args);
}
queue = null;
}
return result;
};
}
function tco5(fn) {
var queue;
return function() {
var args, result, index = 0;
if (queue) {
queue[queue.length] = arguments;
} else {
queue = [arguments];
while ((args = queue[index++])) {
result = fn.apply(this, args);
}
queue = null;
}
return result;
};
}
function tco6(f) {
var value, active = false, accumulated = []
return function accumulator() {
accumulated.push(arguments)
if (!active) {
active = true
while (accumulated.length) value = f.apply(this, accumulated.shift())
active = false
return value
}
}
}
function nonRecursiveSum1(x, y) {
var args, queue = [{ 'x': x, 'y': y }];
do {
args = queue.pop();
x = args.x;
y = args.y;
if (y > 0) {
queue.push({ 'x': x + 1, 'y': y - 1 });
} else if (y < 0) {
queue.push({ 'x': x - 1, 'y': y + 1 });
} else {
return x;
}
} while (true);
}
function nonRecursiveSum2(x, y) {
var args, index = 0, queue = [{ 'x': x, 'y': y }];
do {
args = queue[index++];
x = args.x;
y = args.y;
if (y > 0) {
queue[queue.length] = { 'x': x + 1, 'y': y - 1 };
} else if (y < 0) {
queue[queue.length] = { 'x': x - 1, 'y': y + 1 };
} else {
return x;
}
} while (true);
}
function nonRecursiveSum3(x, y) {
var args, index = 0, queue = [[x, y]];
do {
args = queue[index++];
x = args[0];
y = args[1];
if (y > 0) {
queue[queue.length] = [x + 1, y - 1];
} else if (y < 0) {
queue[queue.length] = [x - 1, y + 1];
} else {
return x;
}
} while (true);
}
function nonRecursiveSum4(x, y) {
var args, queue = [[x, y]];
do {
args = queue.pop();
x = args[0];
y = args[1];
if (y > 0) {
queue.push([x + 1, y - 1]);
} else if (y < 0) {
queue.push([x - 1, y + 1]);
} else {
return x;
}
} while (true);
}
</script>
<script>
Benchmark.prototype.setup = function() {
var sum1 = tco1(function(x, y) {
return y > 0 ? sum1(x + 1, y - 1) :
y < 0 ? sum1(x - 1, y + 1) :
x
});
var sum2 = tco2(function(x, y) {
return y > 0 ? sum2(x + 1, y - 1) :
y < 0 ? sum2(x - 1, y + 1) :
x
});
var sum3 = tco3(function(x, y) {
return y > 0 ? sum3(x + 1, y - 1) :
y < 0 ? sum3(x - 1, y + 1) :
x
});
var sum4 = tco4(function(x, y) {
return y > 0 ? sum4(x + 1, y - 1) :
y < 0 ? sum4(x - 1, y + 1) :
x
});
var sum5 = tco5(function(x, y) {
return y > 0 ? sum5(x + 1, y - 1) :
y < 0 ? sum5(x - 1, y + 1) :
x
});
var sum6 = tco6(function(x, y) {
return y > 0 ? sum6(x + 1, y - 1) :
y < 0 ? sum6(x - 1, y + 1) :
x
});
var nonRecursiveSum1 = window.nonRecursiveSum1;
var nonRecursiveSum2 = window.nonRecursiveSum2;
var nonRecursiveSum3 = window.nonRecursiveSum3;
var nonRecursiveSum4 = window.nonRecursiveSum4;
};
</script>
Test runner
Warning! For accurate results, please disable Firebug before running the tests. (Why?)
Java applet disabled.
| Test | Ops/sec | |
|---|---|---|
tco1 |
|
pending… |
tco2 |
|
pending… |
tco3 |
|
pending… |
tco4 |
|
pending… |
tco5 |
|
pending… |
tco6 |
|
pending… |
nrs1 |
|
pending… |
nrs2 |
|
pending… |
nrs3 |
|
pending… |
nrs4 |
|
pending… |
You can edit these tests or add even more tests to this page by appending /edit to the URL.
0 comments