Skip to content

Commit 8830797

Browse files
Ruben Bridgewatertrevnorris
Ruben Bridgewater
authored andcommitted
node: improve process.nextTick performance
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 <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 7764b6c commit 8830797

File tree

4 files changed

+35
-104
lines changed

4 files changed

+35
-104
lines changed

src/node.js

+26-95
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,26 @@
374374
scheduleMicrotasks();
375375
}
376376

377+
function _combinedTickCallback(args, callback) {
378+
if (args === undefined) {
379+
callback();
380+
} else {
381+
switch (args.length) {
382+
case 1:
383+
callback(args[0]);
384+
break;
385+
case 2:
386+
callback(args[0], args[1]);
387+
break;
388+
case 3:
389+
callback(args[0], args[1], args[2]);
390+
break;
391+
default:
392+
callback.apply(null, args);
393+
}
394+
}
395+
}
396+
377397
// Run callbacks that have no domain.
378398
// Using domains will cause this to be overridden.
379399
function _tickCallback() {
@@ -384,27 +404,10 @@
384404
tock = nextTickQueue[tickInfo[kIndex]++];
385405
callback = tock.callback;
386406
args = tock.args;
387-
// Using separate callback execution functions helps to limit the
388-
// scope of DEOPTs caused by using try blocks and allows direct
407+
// Using separate callback execution functions allows direct
389408
// callback invocation with small numbers of arguments to avoid the
390409
// performance hit associated with using `fn.apply()`
391-
if (args === undefined) {
392-
nextTickCallbackWith0Args(callback);
393-
} else {
394-
switch (args.length) {
395-
case 1:
396-
nextTickCallbackWith1Arg(callback, args[0]);
397-
break;
398-
case 2:
399-
nextTickCallbackWith2Args(callback, args[0], args[1]);
400-
break;
401-
case 3:
402-
nextTickCallbackWith3Args(callback, args[0], args[1], args[2]);
403-
break;
404-
default:
405-
nextTickCallbackWithManyArgs(callback, args);
406-
}
407-
}
410+
_combinedTickCallback(args, callback);
408411
if (1e4 < tickInfo[kIndex])
409412
tickDone();
410413
}
@@ -425,27 +428,10 @@
425428
args = tock.args;
426429
if (domain)
427430
domain.enter();
428-
// Using separate callback execution functions helps to limit the
429-
// scope of DEOPTs caused by using try blocks and allows direct
431+
// Using separate callback execution functions allows direct
430432
// callback invocation with small numbers of arguments to avoid the
431433
// performance hit associated with using `fn.apply()`
432-
if (args === undefined) {
433-
nextTickCallbackWith0Args(callback);
434-
} else {
435-
switch (args.length) {
436-
case 1:
437-
nextTickCallbackWith1Arg(callback, args[0]);
438-
break;
439-
case 2:
440-
nextTickCallbackWith2Args(callback, args[0], args[1]);
441-
break;
442-
case 3:
443-
nextTickCallbackWith3Args(callback, args[0], args[1], args[2]);
444-
break;
445-
default:
446-
nextTickCallbackWithManyArgs(callback, args);
447-
}
448-
}
434+
_combinedTickCallback(args, callback);
449435
if (1e4 < tickInfo[kIndex])
450436
tickDone();
451437
if (domain)
@@ -457,61 +443,6 @@
457443
} while (tickInfo[kLength] !== 0);
458444
}
459445

460-
function nextTickCallbackWith0Args(callback) {
461-
var threw = true;
462-
try {
463-
callback();
464-
threw = false;
465-
} finally {
466-
if (threw)
467-
tickDone();
468-
}
469-
}
470-
471-
function nextTickCallbackWith1Arg(callback, arg1) {
472-
var threw = true;
473-
try {
474-
callback(arg1);
475-
threw = false;
476-
} finally {
477-
if (threw)
478-
tickDone();
479-
}
480-
}
481-
482-
function nextTickCallbackWith2Args(callback, arg1, arg2) {
483-
var threw = true;
484-
try {
485-
callback(arg1, arg2);
486-
threw = false;
487-
} finally {
488-
if (threw)
489-
tickDone();
490-
}
491-
}
492-
493-
function nextTickCallbackWith3Args(callback, arg1, arg2, arg3) {
494-
var threw = true;
495-
try {
496-
callback(arg1, arg2, arg3);
497-
threw = false;
498-
} finally {
499-
if (threw)
500-
tickDone();
501-
}
502-
}
503-
504-
function nextTickCallbackWithManyArgs(callback, args) {
505-
var threw = true;
506-
try {
507-
callback.apply(null, args);
508-
threw = false;
509-
} finally {
510-
if (threw)
511-
tickDone();
512-
}
513-
}
514-
515446
function TickObject(c, args) {
516447
this.callback = c;
517448
this.domain = process.domain || null;
@@ -527,9 +458,9 @@
527458

528459
var args;
529460
if (arguments.length > 1) {
530-
args = [];
461+
args = new Array(arguments.length - 1);
531462
for (var i = 1; i < arguments.length; i++)
532-
args.push(arguments[i]);
463+
args[i - 1] = arguments[i];
533464
}
534465

535466
nextTickQueue.push(new TickObject(callback, args));

test/message/eval_messages.out

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ SyntaxError: Strict mode code may not include a with statement
77
at Object.<anonymous> ([eval]-wrapper:*:*)
88
at Module._compile (module.js:*:*)
99
at node.js:*:*
10-
at nextTickCallbackWith0Args (node.js:*:*)
10+
at _combinedTickCallback (node.js:*:*)
1111
at process._tickCallback (node.js:*:*)
1212
42
1313
42
@@ -20,7 +20,7 @@ Error: hello
2020
at Object.<anonymous> ([eval]-wrapper:*:*)
2121
at Module._compile (module.js:*:*)
2222
at node.js:*:*
23-
at nextTickCallbackWith0Args (node.js:*:*)
23+
at _combinedTickCallback (node.js:*:*)
2424
at process._tickCallback (node.js:*:*)
2525
[eval]:1
2626
throw new Error("hello")
@@ -31,7 +31,7 @@ Error: hello
3131
at Object.<anonymous> ([eval]-wrapper:*:*)
3232
at Module._compile (module.js:*:*)
3333
at node.js:*:*
34-
at nextTickCallbackWith0Args (node.js:*:*)
34+
at _combinedTickCallback (node.js:*:*)
3535
at process._tickCallback (node.js:*:*)
3636
100
3737
[eval]:1
@@ -43,7 +43,7 @@ ReferenceError: y is not defined
4343
at Object.<anonymous> ([eval]-wrapper:*:*)
4444
at Module._compile (module.js:*:*)
4545
at node.js:*:*
46-
at nextTickCallbackWith0Args (node.js:*:*)
46+
at _combinedTickCallback (node.js:*:*)
4747
at process._tickCallback (node.js:*:*)
4848
[eval]:1
4949
var ______________________________________________; throw 10

test/message/nexttick_throw.out

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
^
55
ReferenceError: undefined_reference_error_maker is not defined
66
at *test*message*nexttick_throw.js:*:*
7-
at nextTickCallbackWith0Args (node.js:*:*)
7+
at _combinedTickCallback (node.js:*:*)
88
at process._tickCallback (node.js:*:*)
99
at Function.Module.runMain (module.js:*:*)
1010
at startup (node.js:*:*)

test/message/stdin_messages.out

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ SyntaxError: Strict mode code may not include a with statement
88
at Object.<anonymous> ([stdin]-wrapper:*:*)
99
at Module._compile (module.js:*:*)
1010
at node.js:*:*
11-
at nextTickCallbackWith0Args (node.js:*:*)
11+
at _combinedTickCallback (node.js:*:*)
1212
at process._tickCallback (node.js:*:*)
1313
42
1414
42
@@ -22,7 +22,7 @@ Error: hello
2222
at Object.<anonymous> ([stdin]-wrapper:*:*)
2323
at Module._compile (module.js:*:*)
2424
at node.js:*:*
25-
at nextTickCallbackWith0Args (node.js:*:*)
25+
at _combinedTickCallback (node.js:*:*)
2626
at process._tickCallback (node.js:*:*)
2727

2828
[stdin]:1
@@ -34,7 +34,7 @@ Error: hello
3434
at Object.<anonymous> ([stdin]-wrapper:*:*)
3535
at Module._compile (module.js:*:*)
3636
at node.js:*:*
37-
at nextTickCallbackWith0Args (node.js:*:*)
37+
at _combinedTickCallback (node.js:*:*)
3838
at process._tickCallback (node.js:*:*)
3939
100
4040

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

5353
[stdin]:1

0 commit comments

Comments
 (0)