node/lib/internal/heap_utils.js
Ruben Bridgewater c08a1d152b
v8: fix missing callback in heap utils destroy
This fixes the v8.getHeapSnapshot() calls not properly being
destroyed. Pipeline calls would for example not properly end
without the callback being in place.

PR-URL: https://github.com/nodejs/node/pull/58846
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Shelley Vohr <shelley.vohr@gmail.com>
2025-06-30 11:51:40 +00:00

96 lines
2.4 KiB
JavaScript

'use strict';
const {
ArrayPrototypeMap,
Symbol,
Uint8Array,
} = primordials;
const {
kUpdateTimer,
onStreamRead,
} = require('internal/stream_base_commons');
const { owner_symbol } = require('internal/async_hooks').symbols;
const { Readable } = require('stream');
const {
validateObject,
validateBoolean,
validateFunction,
} = require('internal/validators');
const {
codes: {
ERR_INVALID_ARG_VALUE,
},
} = require('internal/errors');
const { kEmptyObject, emitExperimentalWarning } = require('internal/util');
const {
queryObjects: _queryObjects,
} = internalBinding('internal_only_v8');
const {
inspect,
} = require('internal/util/inspect');
const kHandle = Symbol('kHandle');
function getHeapSnapshotOptions(options = kEmptyObject) {
validateObject(options, 'options');
const {
exposeInternals = false,
exposeNumericValues = false,
} = options;
validateBoolean(exposeInternals, 'options.exposeInternals');
validateBoolean(exposeNumericValues, 'options.exposeNumericValues');
return new Uint8Array([+exposeInternals, +exposeNumericValues]);
}
class HeapSnapshotStream extends Readable {
constructor(handle) {
super({ autoDestroy: true });
this[kHandle] = handle;
handle[owner_symbol] = this;
handle.onread = onStreamRead;
}
_read() {
if (this[kHandle])
this[kHandle].readStart();
}
_destroy(err, callback) {
// Release the references on the handle so that
// it can be garbage collected.
this[kHandle][owner_symbol] = undefined;
this[kHandle] = undefined;
callback(err);
}
[kUpdateTimer]() {
// Does nothing
}
}
const inspectOptions = {
__proto__: null,
depth: 0,
};
function queryObjects(ctor, options = kEmptyObject) {
validateFunction(ctor, 'constructor');
if (options !== kEmptyObject) {
validateObject(options, 'options');
}
const format = options.format || 'count';
if (format !== 'count' && format !== 'summary') {
throw new ERR_INVALID_ARG_VALUE('options.format', format);
}
emitExperimentalWarning('v8.queryObjects()');
// Matching the console API behavior - just access the .prototype.
const objects = _queryObjects(ctor.prototype);
if (format === 'count') {
return objects.length;
}
// options.format is 'summary'.
return ArrayPrototypeMap(objects, (object) => inspect(object, inspectOptions));
}
module.exports = {
getHeapSnapshotOptions,
HeapSnapshotStream,
queryObjects,
};