Commit 4486dce7097 for nodejs
commit 4486dce70979133ec1d7a9412807817de9608284
Author: Matteo Collina <hello@matteocollina.com>
Date: Fri Oct 2 16:45:34 2026 +0200
process: use a class for nextTick resources
The resource created for each `process.nextTick()` call was an object
literal with three computed symbol keys. V8 builds such literals from a
boilerplate that only covers the static keys, so the symbol-keyed
properties end up in a separate property array allocated per tick, and
each computed-key store goes through the runtime.
Construct the resource through a class instead, so that every tick
object shares one map with all five fields in-object.
process/next-tick-breadth-args.js: ~1.58M -> ~1.95M ops/s (+23%).
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66415
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
diff --git a/lib/internal/process/task_queues.js b/lib/internal/process/task_queues.js
index 484fa4ea2f9..c3f935cae38 100644
--- a/lib/internal/process/task_queues.js
+++ b/lib/internal/process/task_queues.js
@@ -110,6 +110,19 @@ function processTicksAndRejections() {
// `nextTick()` will not enqueue any callback when the process is about to
// exit since the callback would not have a chance to be executed.
+// The async resource behind each `process.nextTick()` call. A class keeps
+// every instance on one map with all fields in-object; an object literal
+// with computed symbol keys spills them into a separate property array.
+class TickObject {
+ constructor(callback, args, asyncId, triggerAsyncId) {
+ this[async_id_symbol] = asyncId;
+ this[trigger_async_id_symbol] = triggerAsyncId;
+ this[async_context_frame] = AsyncContextFrame.current();
+ this.callback = callback;
+ this.args = args;
+ }
+}
+
function nextTick(callback) {
validateFunction(callback, 'callback');
@@ -132,13 +145,7 @@ function nextTick(callback) {
setHasTickScheduled(true);
const asyncId = newAsyncId();
const triggerAsyncId = getDefaultTriggerAsyncId();
- const tickObject = {
- [async_id_symbol]: asyncId,
- [trigger_async_id_symbol]: triggerAsyncId,
- [async_context_frame]: AsyncContextFrame.current(),
- callback,
- args,
- };
+ const tickObject = new TickObject(callback, args, asyncId, triggerAsyncId);
if (initHooksExist())
emitInit(asyncId, 'TickObject', triggerAsyncId, tickObject);
queue.push(tickObject);