summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBrian White <mscdex@mscdex.net>2015-05-01 14:08:02 -0400
committerBrian White <mscdex@mscdex.net>2015-05-01 21:27:34 -0400
commitc7782c0af8a4e4ee26da6e44e07c3987d9d3ddb6 (patch)
treec34ab5332254a02afdfa73476c5ce742da981dca /src
parentea5195ccaf6d51262c9089c2ec5c6f5634bc12b5 (diff)
downloadandroid-node-v8-c7782c0af8a4e4ee26da6e44e07c3987d9d3ddb6.tar.gz
android-node-v8-c7782c0af8a4e4ee26da6e44e07c3987d9d3ddb6.tar.bz2
android-node-v8-c7782c0af8a4e4ee26da6e44e07c3987d9d3ddb6.zip
node: improve nextTick performance
This commit uses separate functions to isolate deopts caused by try-catches and avoids fn.apply() for callbacks with small numbers of arguments. These changes improve performance by ~1-40% in the various nextTick benchmarks. PR-URL: https://github.com/iojs/io.js/pull/1571 Reviewed-By: Trevor Norris <trev.norris@gmail.com> Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/node.js121
1 files changed, 99 insertions, 22 deletions
diff --git a/src/node.js b/src/node.js
index 1cb71c4927..5cf56f6242 100644
--- a/src/node.js
+++ b/src/node.js
@@ -328,22 +328,33 @@
// Run callbacks that have no domain.
// Using domains will cause this to be overridden.
function _tickCallback() {
- var callback, threw, tock;
+ var callback, args, tock;
do {
while (tickInfo[kIndex] < tickInfo[kLength]) {
tock = nextTickQueue[tickInfo[kIndex]++];
callback = tock.callback;
- threw = true;
- try {
- if (tock.args === undefined)
- callback();
- else
- callback.apply(null, tock.args);
- threw = false;
- } finally {
- if (threw)
- tickDone();
+ args = tock.args;
+ // Using separate callback execution functions helps to limit the
+ // scope of DEOPTs caused by using try blocks and allows direct
+ // callback invocation with small numbers of arguments to avoid the
+ // performance hit associated with using `fn.apply()`
+ if (args === undefined) {
+ doNTCallback0(callback);
+ } else {
+ switch (args.length) {
+ case 1:
+ doNTCallback1(callback, args[0]);
+ break;
+ case 2:
+ doNTCallback2(callback, args[0], args[1]);
+ break;
+ case 3:
+ doNTCallback3(callback, args[0], args[1], args[2]);
+ break;
+ default:
+ doNTCallbackMany(callback, args);
+ }
}
if (1e4 < tickInfo[kIndex])
tickDone();
@@ -355,25 +366,36 @@
}
function _tickDomainCallback() {
- var callback, domain, threw, tock;
+ var callback, domain, args, tock;
do {
while (tickInfo[kIndex] < tickInfo[kLength]) {
tock = nextTickQueue[tickInfo[kIndex]++];
callback = tock.callback;
domain = tock.domain;
+ args = tock.args;
if (domain)
domain.enter();
- threw = true;
- try {
- if (tock.args === undefined)
- callback();
- else
- callback.apply(null, tock.args);
- threw = false;
- } finally {
- if (threw)
- tickDone();
+ // Using separate callback execution functions helps to limit the
+ // scope of DEOPTs caused by using try blocks and allows direct
+ // callback invocation with small numbers of arguments to avoid the
+ // performance hit associated with using `fn.apply()`
+ if (args === undefined) {
+ doNTCallback0(callback);
+ } else {
+ switch (args.length) {
+ case 1:
+ doNTCallback1(callback, args[0]);
+ break;
+ case 2:
+ doNTCallback2(callback, args[0], args[1]);
+ break;
+ case 3:
+ doNTCallback3(callback, args[0], args[1], args[2]);
+ break;
+ default:
+ doNTCallbackMany(callback, args);
+ }
}
if (1e4 < tickInfo[kIndex])
tickDone();
@@ -386,6 +408,61 @@
} while (tickInfo[kLength] !== 0);
}
+ function doNTCallback0(callback) {
+ var threw = true;
+ try {
+ callback();
+ threw = false;
+ } finally {
+ if (threw)
+ tickDone();
+ }
+ }
+
+ function doNTCallback1(callback, arg1) {
+ var threw = true;
+ try {
+ callback(arg1);
+ threw = false;
+ } finally {
+ if (threw)
+ tickDone();
+ }
+ }
+
+ function doNTCallback2(callback, arg1, arg2) {
+ var threw = true;
+ try {
+ callback(arg1, arg2);
+ threw = false;
+ } finally {
+ if (threw)
+ tickDone();
+ }
+ }
+
+ function doNTCallback3(callback, arg1, arg2, arg3) {
+ var threw = true;
+ try {
+ callback(arg1, arg2, arg3);
+ threw = false;
+ } finally {
+ if (threw)
+ tickDone();
+ }
+ }
+
+ function doNTCallbackMany(callback, args) {
+ var threw = true;
+ try {
+ callback.apply(null, args);
+ threw = false;
+ } finally {
+ if (threw)
+ tickDone();
+ }
+ }
+
function TickObject(c, args) {
this.callback = c;
this.domain = process.domain || null;