16
16
17
17
#include < nan.h>
18
18
#include < node.h>
19
+ #include < v8-internal.h>
19
20
#include < v8-profiler.h>
20
21
#include < cinttypes>
21
22
#include < cstdint>
@@ -41,6 +42,13 @@ struct TimeTicks {
41
42
static int64_t Now ();
42
43
};
43
44
} // 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
44
52
} // namespace v8
45
53
46
54
static int64_t Now () {
@@ -1206,14 +1214,31 @@ ContextPtr WallProfiler::GetContextPtrSignalSafe(Isolate* isolate) {
1206
1214
return GetContextPtr (isolate);
1207
1215
}
1208
1216
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
+
1209
1231
ContextPtr WallProfiler::GetContextPtr (Isolate* isolate) {
1210
1232
#if NODE_MAJOR_VERSION >= 23
1211
1233
if (!useCPED_) {
1212
1234
return curContext_;
1213
1235
}
1214
1236
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.
1217
1242
return ContextPtr ();
1218
1243
}
1219
1244
HandleScope scope (isolate);
@@ -1271,8 +1296,10 @@ NAN_METHOD(WallProfiler::Dispose) {
1271
1296
}
1272
1297
1273
1298
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.
1276
1303
return -1 ;
1277
1304
}
1278
1305
#if NODE_MAJOR_VERSION >= 24
0 commit comments