Skip to content

Commit

Permalink
node: improve process.nextTick performance
Browse files Browse the repository at this point in the history
Prevent deoptimization of process.nextTick by removing the try finally
block. This is not necessary as the next tick queue will be reset
anyway, no matter if the callback throws or not.

Use a predefined array size prevents resizing the array and is therefor
faster.

PR-URL: #5092
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
Ruben Bridgewater authored and trevnorris committed Feb 9, 2016
1 parent 7764b6c commit 8830797
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 104 deletions.
121 changes: 26 additions & 95 deletions src/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,26 @@
scheduleMicrotasks();
}

function _combinedTickCallback(args, callback) {
if (args === undefined) {
callback();
} else {
switch (args.length) {
case 1:
callback(args[0]);
break;
case 2:
callback(args[0], args[1]);
break;
case 3:
callback(args[0], args[1], args[2]);
break;
default:
callback.apply(null, args);
}
}
}

// Run callbacks that have no domain.
// Using domains will cause this to be overridden.
function _tickCallback() {
Expand All @@ -384,27 +404,10 @@
tock = nextTickQueue[tickInfo[kIndex]++];
callback = tock.callback;
args = tock.args;
// Using separate callback execution functions helps to limit the
// scope of DEOPTs caused by using try blocks and allows direct
// Using separate callback execution functions allows direct
// callback invocation with small numbers of arguments to avoid the
// performance hit associated with using `fn.apply()`
if (args === undefined) {
nextTickCallbackWith0Args(callback);
} else {
switch (args.length) {
case 1:
nextTickCallbackWith1Arg(callback, args[0]);
break;
case 2:
nextTickCallbackWith2Args(callback, args[0], args[1]);
break;
case 3:
nextTickCallbackWith3Args(callback, args[0], args[1], args[2]);
break;
default:
nextTickCallbackWithManyArgs(callback, args);
}
}
_combinedTickCallback(args, callback);
if (1e4 < tickInfo[kIndex])
tickDone();
}
Expand All @@ -425,27 +428,10 @@
args = tock.args;
if (domain)
domain.enter();
// Using separate callback execution functions helps to limit the
// scope of DEOPTs caused by using try blocks and allows direct
// Using separate callback execution functions allows direct
// callback invocation with small numbers of arguments to avoid the
// performance hit associated with using `fn.apply()`
if (args === undefined) {
nextTickCallbackWith0Args(callback);
} else {
switch (args.length) {
case 1:
nextTickCallbackWith1Arg(callback, args[0]);
break;
case 2:
nextTickCallbackWith2Args(callback, args[0], args[1]);
break;
case 3:
nextTickCallbackWith3Args(callback, args[0], args[1], args[2]);
break;
default:
nextTickCallbackWithManyArgs(callback, args);
}
}
_combinedTickCallback(args, callback);
if (1e4 < tickInfo[kIndex])
tickDone();
if (domain)
Expand All @@ -457,61 +443,6 @@
} while (tickInfo[kLength] !== 0);
}

function nextTickCallbackWith0Args(callback) {
var threw = true;
try {
callback();
threw = false;
} finally {
if (threw)
tickDone();
}
}

function nextTickCallbackWith1Arg(callback, arg1) {
var threw = true;
try {
callback(arg1);
threw = false;
} finally {
if (threw)
tickDone();
}
}

function nextTickCallbackWith2Args(callback, arg1, arg2) {
var threw = true;
try {
callback(arg1, arg2);
threw = false;
} finally {
if (threw)
tickDone();
}
}

function nextTickCallbackWith3Args(callback, arg1, arg2, arg3) {
var threw = true;
try {
callback(arg1, arg2, arg3);
threw = false;
} finally {
if (threw)
tickDone();
}
}

function nextTickCallbackWithManyArgs(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;
Expand All @@ -527,9 +458,9 @@

var args;
if (arguments.length > 1) {
args = [];
args = new Array(arguments.length - 1);
for (var i = 1; i < arguments.length; i++)
args.push(arguments[i]);
args[i - 1] = arguments[i];
}

nextTickQueue.push(new TickObject(callback, args));
Expand Down
8 changes: 4 additions & 4 deletions test/message/eval_messages.out
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ SyntaxError: Strict mode code may not include a with statement
at Object.<anonymous> ([eval]-wrapper:*:*)
at Module._compile (module.js:*:*)
at node.js:*:*
at nextTickCallbackWith0Args (node.js:*:*)
at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*)
42
42
Expand All @@ -20,7 +20,7 @@ Error: hello
at Object.<anonymous> ([eval]-wrapper:*:*)
at Module._compile (module.js:*:*)
at node.js:*:*
at nextTickCallbackWith0Args (node.js:*:*)
at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*)
[eval]:1
throw new Error("hello")
Expand All @@ -31,7 +31,7 @@ Error: hello
at Object.<anonymous> ([eval]-wrapper:*:*)
at Module._compile (module.js:*:*)
at node.js:*:*
at nextTickCallbackWith0Args (node.js:*:*)
at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*)
100
[eval]:1
Expand All @@ -43,7 +43,7 @@ ReferenceError: y is not defined
at Object.<anonymous> ([eval]-wrapper:*:*)
at Module._compile (module.js:*:*)
at node.js:*:*
at nextTickCallbackWith0Args (node.js:*:*)
at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*)
[eval]:1
var ______________________________________________; throw 10
Expand Down
2 changes: 1 addition & 1 deletion test/message/nexttick_throw.out
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
^
ReferenceError: undefined_reference_error_maker is not defined
at *test*message*nexttick_throw.js:*:*
at nextTickCallbackWith0Args (node.js:*:*)
at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*)
at Function.Module.runMain (module.js:*:*)
at startup (node.js:*:*)
Expand Down
8 changes: 4 additions & 4 deletions test/message/stdin_messages.out
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ SyntaxError: Strict mode code may not include a with statement
at Object.<anonymous> ([stdin]-wrapper:*:*)
at Module._compile (module.js:*:*)
at node.js:*:*
at nextTickCallbackWith0Args (node.js:*:*)
at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*)
42
42
Expand All @@ -22,7 +22,7 @@ Error: hello
at Object.<anonymous> ([stdin]-wrapper:*:*)
at Module._compile (module.js:*:*)
at node.js:*:*
at nextTickCallbackWith0Args (node.js:*:*)
at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*)

[stdin]:1
Expand All @@ -34,7 +34,7 @@ Error: hello
at Object.<anonymous> ([stdin]-wrapper:*:*)
at Module._compile (module.js:*:*)
at node.js:*:*
at nextTickCallbackWith0Args (node.js:*:*)
at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*)
100

Expand All @@ -47,7 +47,7 @@ ReferenceError: y is not defined
at Object.<anonymous> ([stdin]-wrapper:*:*)
at Module._compile (module.js:*:*)
at node.js:*:*
at nextTickCallbackWith0Args (node.js:*:*)
at _combinedTickCallback (node.js:*:*)
at process._tickCallback (node.js:*:*)

[stdin]:1
Expand Down

0 comments on commit 8830797

Please sign in to comment.