Files
node/lib/internal/trace_events.js
Shelley Vohr 48c90fffb7 src: support building with the V8 sandbox
With V8_ENABLE_SANDBOX every ArrayBuffer backing store has to be
allocated inside the sandbox, so memory that Node.js or a library
allocated itself cannot be wrapped and has to be copied in. Several
places already special-cased this, each with its own #ifdef, but a
build with the sandbox enabled still failed to compile
(`kMaxSafeBufferSizeForSandbox`), aborted in `crypto.randomUUID()`
(`SecureBuffer` was UNREACHABLE) and threw from every caller of the
malloc-owning `Buffer::New()` (v8.serialize, string transcoding, IPC,
the public `Buffer::New(isolate, data, length)`), and trace_events,
SEA assets and FFI still wrapped outside memory unconditionally.

Add `AdoptIntoBackingStore()`, which wraps the memory as before in
regular builds and copies it into an isolate-allocated backing store,
running the deleter right away, when the sandbox is enabled, and use it
at all of those sites so the #ifdef lives in one place. The trace
category flag cannot be copied since JS polls it, so under the sandbox
`getCategoryEnabledBuffer()` returns nothing and lib falls back to
`isTraceCategoryEnabled()`; FFI zero-copy views throw
ERR_OPERATION_FAILED there for the same reason.

Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/62237
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
2026-09-07 05:10:02 +00:00

72 lines
2.2 KiB
JavaScript

'use strict';
const {
getCategoryEnabledBuffer,
isTraceCategoryEnabled,
trace,
usePerfetto,
} = internalBinding('trace_events');
const {
CHAR_UPPERCASE_B,
CHAR_LOWERCASE_B,
CHAR_UPPERCASE_C,
CHAR_LOWERCASE_E,
CHAR_UPPERCASE_E,
CHAR_LOWERCASE_N,
} = require('internal/constants');
let nodeTraceEventCategory;
if (usePerfetto) {
nodeTraceEventCategory = (category) => `${category}`;
} else {
nodeTraceEventCategory = (category) => `node,${category}`;
}
// The returned function reads the category's enabled flag directly when the
// binding can expose it to JS, and asks the tracing controller otherwise.
function categoryEnabledChecker(category) {
const buffer = getCategoryEnabledBuffer(category);
if (buffer === undefined) {
return () => isTraceCategoryEnabled(category);
}
return () => buffer[0] > 0;
}
// The async events describe the execution of a single asynchronous operation, and are
// used to measure the time spent in a single asynchronous operation.
// Async events may overlap with each other. Different events do not have
// to be nested, or FILO (first in last out).
// TODO(legendecas): V8 `trace` API does not support async marks in perfetto yet.
const kAsyncBegin = usePerfetto ? CHAR_UPPERCASE_B : CHAR_LOWERCASE_B;
const kAsyncEnd = usePerfetto ? CHAR_UPPERCASE_E : CHAR_LOWERCASE_E;
// The sync events describe the execution of a single thread, and are
// used to measure the time spent in a function.
// Sync events must be nested, and are FILO (first in last out), in a stack
// manner.
const kSyncBegin = CHAR_UPPERCASE_B;
const kSyncEnd = CHAR_UPPERCASE_E;
// Counter events track a named numeric value as it changes over time. Each
// event records the value at a point in time, and the trace viewer renders the
// series as a graph.
// TODO(legendecas): V8 `trace` API does not support count marks in perfetto yet.
const kTraceCount = usePerfetto ? CHAR_LOWERCASE_N : CHAR_UPPERCASE_C;
// Instant events mark a single moment in time. They have no duration and do
// not need to be paired or nested.
const kTraceInstant = CHAR_LOWERCASE_N;
module.exports = {
usePerfetto,
categoryEnabledChecker,
trace,
nodeTraceEventCategory,
kAsyncBegin,
kAsyncEnd,
kSyncBegin,
kSyncEnd,
kTraceCount,
kTraceInstant,
};