Skip to content

Commit 49d022a

Browse files
committed
Observe the number of free handles
1 parent f9a66d5 commit 49d022a

File tree

1 file changed

+31
-4
lines changed

1 file changed

+31
-4
lines changed

bindings/profilers/wall.cc

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include <nan.h>
1818
#include <node.h>
19+
#include <v8-internal.h>
1920
#include <v8-profiler.h>
2021
#include <cinttypes>
2122
#include <cstdint>
@@ -41,6 +42,13 @@ struct TimeTicks {
4142
static int64_t Now();
4243
};
4344
} // namespace base
45+
namespace internal {
46+
struct HandleScopeData {
47+
v8::internal::Address* next;
48+
v8::internal::Address* limit;
49+
};
50+
constexpr int kHandleBlockSize = v8::internal::KB - 2;
51+
} // namespace internal
4452
} // namespace v8
4553

4654
static int64_t Now() {
@@ -1206,14 +1214,31 @@ ContextPtr WallProfiler::GetContextPtrSignalSafe(Isolate* isolate) {
12061214
return GetContextPtr(isolate);
12071215
}
12081216

1217+
// Returns the number of free Address slots for Locals that can be returned by
1218+
// the isolate without triggering memory allocation.
1219+
int GetFreeLocalSlotCount(Isolate* isolate) {
1220+
v8::internal::HandleScopeData* data =
1221+
reinterpret_cast<v8::internal::HandleScopeData*>(
1222+
reinterpret_cast<uint64_t>(isolate) +
1223+
v8::internal::Internals::kIsolateHandleScopeDataOffset);
1224+
auto diff = data->limit - data->next;
1225+
// sanity check: diff can be at most kHandleBlockSize. If it is larger,
1226+
// something is suspicious. See
1227+
// https://github.com/v8/v8/blob/6fcfeccda2d8bcb7397f89bf5bbacd0c2eb2fb7f/src/handles/handles.cc#L195
1228+
return diff > v8::internal::kHandleBlockSize ? 0 : diff;
1229+
}
1230+
12091231
ContextPtr WallProfiler::GetContextPtr(Isolate* isolate) {
12101232
#if NODE_MAJOR_VERSION >= 23
12111233
if (!useCPED_) {
12121234
return curContext_;
12131235
}
12141236

1215-
if (!isolate->IsInUse()) {
1216-
// Must not try to create a handle scope if isolate is not in use.
1237+
if (!isolate->IsInUse() || GetFreeLocalSlotCount(isolate) < 4) {
1238+
// Must not try to create a handle scope if isolate is not in use or if we
1239+
// don't have at least 4 free slots to create local handles. The 4 handles
1240+
// are return values of GetCPED, GetEnteredOrMicrotaskContext,
1241+
// cpedSymbol_.Get, and GetPrivate.
12171242
return ContextPtr();
12181243
}
12191244
HandleScope scope(isolate);
@@ -1271,8 +1296,10 @@ NAN_METHOD(WallProfiler::Dispose) {
12711296
}
12721297

12731298
double GetAsyncIdNoGC(v8::Isolate* isolate) {
1274-
if (!isolate->IsInUse()) {
1275-
// Must not try to create a handle scope if isolate is not in use.
1299+
if (!isolate->IsInUse() || GetFreeLocalSlotCount(isolate) < 1) {
1300+
// Must not try to create a handle scope if isolate is not in use or if
1301+
// we can't create one local handle (return value of
1302+
// GetEnteredOrMicrotaskContext) without allocation.
12761303
return -1;
12771304
}
12781305
#if NODE_MAJOR_VERSION >= 24

0 commit comments

Comments
 (0)