Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions lib/internal/main/mksnapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ const { emitExperimentalWarning } = require('internal/util');
const { emitWarningSync } = require('internal/process/warning');

const {
initializeCallbacks,
namespace: {
addDeserializeCallback,
isBuildingSnapshot,
Expand Down Expand Up @@ -139,7 +138,6 @@ function requireForUserSnapshot(id) {

function main() {
prepareMainThreadExecution(false, false);
initializeCallbacks();

// In a context created for building snapshots, V8 does not install Error.stackTraceLimit and as
// a result, if an error is created during the snapshot building process, error.stack would be
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/v8/startup_snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ function setDeserializeMainFunction(callback, data) {
});
}

initializeCallbacks();
module.exports = {
initializeCallbacks,
runDeserializeCallbacks,
throwIfBuildingSnapshot,
// Exposed to require('v8').startupSnapshot
Expand Down
9 changes: 7 additions & 2 deletions src/api/environment.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "node.h"
#include "node_builtins.h"
#include "node_context_data.h"
#include "node_debug.h"
#include "node_errors.h"
#include "node_exit_code.h"
#include "node_internals.h"
Expand Down Expand Up @@ -112,17 +113,21 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,

void* NodeArrayBufferAllocator::Allocate(size_t size) {
void* ret;
if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers) {
COUNT_GENERIC_USAGE("NodeArrayBufferAllocator.Allocate.ZeroFilled");
ret = allocator_->Allocate(size);
else
} else {
COUNT_GENERIC_USAGE("NodeArrayBufferAllocator.Allocate.Uninitialized");
ret = allocator_->AllocateUninitialized(size);
}
if (ret != nullptr) [[likely]] {
total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
}
return ret;
}

void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) {
COUNT_GENERIC_USAGE("NodeArrayBufferAllocator.Allocate.Uninitialized");
void* ret = allocator_->AllocateUninitialized(size);
if (ret != nullptr) [[likely]] {
total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
Expand Down
24 changes: 24 additions & 0 deletions src/node_debug.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "v8-fast-api-calls.h"
#include "v8.h"

#include <string>
#include <string_view>
#include <unordered_map>
#endif // DEBUG
Expand All @@ -23,9 +24,20 @@ using v8::Number;
using v8::Object;
using v8::Value;

thread_local std::unordered_map<std::string, int> generic_usage_counters;
thread_local std::unordered_map<FastStringKey, int, FastStringKey::Hash>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make this use FastStringKey as well, that is useful here for the same reason as it is for fast API call count tracking

v8_fast_api_call_counts;

void CountGenericUsage(const char* counter_name) {
if (generic_usage_counters.find(counter_name) == generic_usage_counters.end())
generic_usage_counters[counter_name] = 0;
Comment on lines +32 to +33
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (generic_usage_counters.find(counter_name) == generic_usage_counters.end())
generic_usage_counters[counter_name] = 0;

... since this doesn't actually do anything, right? operator[] creates the element for you if it doesn't exist

Copy link
Member

@addaleax addaleax Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do a separate PR – #60447

generic_usage_counters[counter_name]++;
}

int GetGenericUsageCount(const char* counter_name) {
return generic_usage_counters[counter_name];
}

void TrackV8FastApiCall(FastStringKey key) {
v8_fast_api_call_counts[key]++;
}
Expand All @@ -34,6 +46,17 @@ int GetV8FastApiCallCount(FastStringKey key) {
return v8_fast_api_call_counts[key];
}

void GetGenericUsageCount(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
if (!args[0]->IsString()) {
env->ThrowError("getGenericUsageCount must be called with a string");
return;
}
Utf8Value utf8_key(env->isolate(), args[0]);
args.GetReturnValue().Set(
GetGenericUsageCount(utf8_key.ToStringView().data()));
}

void GetV8FastApiCallCount(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
if (!args[0]->IsString()) {
Expand Down Expand Up @@ -89,6 +112,7 @@ void Initialize(Local<Object> target,
Local<Context> context,
void* priv) {
SetMethod(context, target, "getV8FastApiCallCount", GetV8FastApiCallCount);
SetMethod(context, target, "getGenericUsageCount", GetGenericUsageCount);
SetFastMethod(context, target, "isEven", SlowIsEven, &fast_is_even);
SetFastMethod(context, target, "isOdd", SlowIsOdd, &fast_is_odd);
}
Expand Down
4 changes: 4 additions & 0 deletions src/node_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ namespace debug {
void TrackV8FastApiCall(FastStringKey key);
int GetV8FastApiCallCount(FastStringKey key);

void CountGenericUsage(const char* counter_name);
#define COUNT_GENERIC_USAGE(name) node::debug::CountGenericUsage(name)

#define TRACK_V8_FAST_API_CALL(key) \
node::debug::TrackV8FastApiCall(FastStringKey(key))
#else // !DEBUG
#define TRACK_V8_FAST_API_CALL(key)
#define COUNT_GENERIC_USAGE(name)
#endif // DEBUG

} // namespace debug
Expand Down
17 changes: 17 additions & 0 deletions test/parallel/test-buffer-alloc-unsafe-is-uninitialized.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Flags: --expose-internals
// Verifies that Buffer.allocUnsafe() indeed allocates uninitialized memory by checking
// the usage count of the relevant native allocator code path.
'use strict';

const common = require('../common');
if (!common.isDebug) {
common.skip('Only works in debug mode');
}
const { internalBinding } = require('internal/test/binding');
const { getGenericUsageCount } = internalBinding('debug');
const assert = require('assert');

const initialCount = getGenericUsageCount('NodeArrayBufferAllocator.Allocate.Uninitialized');
Buffer.allocUnsafe(Buffer.poolSize + 1);
const newCount = getGenericUsageCount('NodeArrayBufferAllocator.Allocate.Uninitialized');
assert.notStrictEqual(newCount, initialCount);
Loading