summaryrefslogtreecommitdiff
path: root/lib/timers.js
diff options
context:
space:
mode:
authorAndras <andras@kinvey.com>2016-04-27 20:31:59 -0400
committerJeremiah Senkpiel <fishrock123@rocketmail.com>2016-06-29 11:02:25 +0200
commit6f75b6672ca08c2bc3bf5fe14abb1a9648601e28 (patch)
treefc67efa679a469f0ddfd8c46a4f03ee0bb457c2b /lib/timers.js
parent6b0f86a8d519fd0780d2f6db2e7f28c2715dd795 (diff)
downloadandroid-node-v8-6f75b6672ca08c2bc3bf5fe14abb1a9648601e28.tar.gz
android-node-v8-6f75b6672ca08c2bc3bf5fe14abb1a9648601e28.tar.bz2
android-node-v8-6f75b6672ca08c2bc3bf5fe14abb1a9648601e28.zip
timers: optimize `setImmediate()`
Save the setImmediate() callback arguments into an array instead of a closure, and invoke the callback on the arguments from an optimizable function. 60% faster setImmediate with 0 args (15% if self-recursive) 4x faster setImmediate with 1-3 args, 2x with > 3 seems to be faster with less memory pressure when memory is tight Changes: - use L.create() to build faster lists - use runCallback() from within tryOnImmediate() - save the arguments and do not build closures for the callbacks PR-URL: https://github.com/nodejs/node/pull/6436 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Diffstat (limited to 'lib/timers.js')
-rw-r--r--lib/timers.js79
1 files changed, 47 insertions, 32 deletions
diff --git a/lib/timers.js b/lib/timers.js
index 7ae25f6a32..9dbae32405 100644
--- a/lib/timers.js
+++ b/lib/timers.js
@@ -506,7 +506,7 @@ var immediateQueue = L.create();
function processImmediate() {
- var queue = immediateQueue;
+ const queue = immediateQueue;
var domain, immediate;
immediateQueue = L.create();
@@ -515,9 +515,13 @@ function processImmediate() {
immediate = L.shift(queue);
domain = immediate.domain;
+ if (!immediate._onImmediate)
+ continue;
+
if (domain)
domain.enter();
+ immediate._callback = immediate._onImmediate;
tryOnImmediate(immediate, queue);
if (domain)
@@ -538,7 +542,8 @@ function processImmediate() {
function tryOnImmediate(immediate, queue) {
var threw = true;
try {
- immediate._onImmediate();
+ // make the actual call outside the try/catch to allow it to be optimized
+ runCallback(immediate);
threw = false;
} finally {
if (threw && !L.isEmpty(queue)) {
@@ -552,14 +557,36 @@ function tryOnImmediate(immediate, queue) {
}
}
+function runCallback(timer) {
+ const argv = timer._argv;
+ const argc = argv ? argv.length : 0;
+ switch (argc) {
+ // fast-path callbacks with 0-3 arguments
+ case 0:
+ return timer._callback();
+ case 1:
+ return timer._callback(argv[0]);
+ case 2:
+ return timer._callback(argv[0], argv[1]);
+ case 3:
+ return timer._callback(argv[0], argv[1], argv[2]);
+ // more than 3 arguments run slower with .apply
+ default:
+ return timer._callback.apply(timer, argv);
+ }
+}
-function Immediate() { }
-
-Immediate.prototype.domain = undefined;
-Immediate.prototype._onImmediate = undefined;
-Immediate.prototype._idleNext = undefined;
-Immediate.prototype._idlePrev = undefined;
+function Immediate() {
+ // assigning the callback here can cause optimize/deoptimize thrashing
+ // so have caller annotate the object (node v6.0.0, v8 5.0.71.35)
+ this._idleNext = null;
+ this._idlePrev = null;
+ this._callback = null;
+ this._argv = null;
+ this._onImmediate = null;
+ this.domain = process.domain;
+}
exports.setImmediate = function(callback, arg1, arg2, arg3) {
if (typeof callback !== 'function') {
@@ -567,52 +594,40 @@ exports.setImmediate = function(callback, arg1, arg2, arg3) {
}
var i, args;
- var len = arguments.length;
- var immediate = new Immediate();
-
- L.init(immediate);
- switch (len) {
+ switch (arguments.length) {
// fast cases
case 0:
case 1:
- immediate._onImmediate = callback;
break;
case 2:
- immediate._onImmediate = function() {
- callback.call(immediate, arg1);
- };
+ args = [arg1];
break;
case 3:
- immediate._onImmediate = function() {
- callback.call(immediate, arg1, arg2);
- };
+ args = [arg1, arg2];
break;
case 4:
- immediate._onImmediate = function() {
- callback.call(immediate, arg1, arg2, arg3);
- };
+ args = [arg1, arg2, arg3];
break;
// slow case
default:
- args = new Array(len - 1);
- for (i = 1; i < len; i++)
+ args = [arg1, arg2, arg3];
+ for (i = 4; i < arguments.length; i++)
+ // extend array dynamically, makes .apply run much faster in v6.0.0
args[i - 1] = arguments[i];
-
- immediate._onImmediate = function() {
- callback.apply(immediate, args);
- };
break;
}
+ // declaring it `const immediate` causes v6.0.0 to deoptimize this function
+ var immediate = new Immediate();
+ immediate._callback = callback;
+ immediate._argv = args;
+ immediate._onImmediate = callback;
if (!process._needImmediateCallback) {
process._needImmediateCallback = true;
process._immediateCallback = processImmediate;
}
- if (process.domain)
- immediate.domain = process.domain;
-
L.append(immediateQueue, immediate);
return immediate;