@@ -323,7 +323,7 @@ void SignalHandler::HandleProfilerSignal(int sig,
323
323
auto time_from = Now ();
324
324
old_handler (sig, info, context);
325
325
auto time_to = Now ();
326
- prof->PushContext (time_from, time_to, cpu_time);
326
+ prof->PushContext (time_from, time_to, cpu_time, isolate );
327
327
}
328
328
#else
329
329
class SignalHandler {
@@ -509,6 +509,8 @@ WallProfiler::WallProfiler(std::chrono::microseconds samplingPeriod,
509
509
#endif
510
510
jsArray_ = v8::Global<v8::Uint32Array>(isolate, jsArray);
511
511
std::fill (fields_, fields_ + kFieldCount , 0 );
512
+
513
+ cpedSymbol_ = v8::Global<v8::Symbol>(isolate, v8::Symbol::New (isolate));
512
514
}
513
515
514
516
WallProfiler::~WallProfiler () {
@@ -953,23 +955,65 @@ v8::CpuProfiler* WallProfiler::CreateV8CpuProfiler() {
953
955
}
954
956
955
957
v8::Local<v8::Value> WallProfiler::GetContext (Isolate* isolate) {
956
- auto context = GetContextPtr ();
958
+ auto context = GetContextPtr (isolate );
957
959
if (!context) return v8::Undefined (isolate);
958
960
return context->Get (isolate);
959
961
}
960
962
961
963
void WallProfiler::SetContext (Isolate* isolate, Local<Value> value) {
964
+ auto cped = isolate->GetContinuationPreservedEmbedderData ();
965
+ // No Node AsyncContextFrame in this continuation yet
966
+ if (!cped->IsObject ()) return ;
967
+
968
+ auto cpedObj = cped.As <Object>();
969
+ auto localSymbol = cpedSymbol_.Get (isolate);
970
+ auto v8Ctx = isolate->GetCurrentContext ();
971
+ auto maybeProfData = cpedObj->Get (v8Ctx, localSymbol);
972
+ if (maybeProfData.IsEmpty ()) return ;
973
+ auto profData = maybeProfData.ToLocalChecked ();
974
+
975
+ ContextPtr* contextPtr = nullptr ;
976
+ if (profData->IsUndefined ()) {
977
+ contextPtr = new ContextPtr ();
978
+ auto maybeSetResult = cpedObj->Set (v8Ctx, localSymbol, External::New (isolate, contextPtr));
979
+ if (maybeSetResult.IsNothing ()) {
980
+ delete contextPtr;
981
+ return ;
982
+ }
983
+
984
+ // Register a callback to delete contextPtr when the CPED object is GCed
985
+ Persistent<Object>(isolate, cpedObj).SetWeak (contextPtr, [](const WeakCallbackInfo<ContextPtr>& data) {
986
+ // Using SetSecondPassCallback as shared_ptr can trigger ~Global and any V8 API use needs to be in the second pass
987
+ data.SetSecondPassCallback ([](const WeakCallbackInfo<ContextPtr>& data) {
988
+ delete data.GetParameter ();
989
+ });
990
+ }, WeakCallbackType::kParameter );
991
+ } else {
992
+ contextPtr = reinterpret_cast <ContextPtr*>(profData.As <External>()->Value ());
993
+ }
994
+
962
995
std::atomic_signal_fence (std::memory_order_release);
963
996
std::atomic_store_explicit (
964
- &curContext_ ,
997
+ contextPtr ,
965
998
value->IsNullOrUndefined ()
966
999
? std::shared_ptr<Global<Value>>()
967
1000
: std::make_shared<Global<Value>>(isolate, value),
968
1001
std::memory_order_relaxed);
969
1002
}
970
1003
971
- ContextPtr WallProfiler::GetContextPtr () {
972
- auto contextPtr = atomic_load_explicit (&curContext_, std::memory_order_relaxed);
1004
+ ContextPtr WallProfiler::GetContextPtr (Isolate* isolate) {
1005
+ auto cped = isolate->GetContinuationPreservedEmbedderData (); // signal safe?
1006
+ if (!cped->IsObject ()) return std::shared_ptr<Global<Value>>();
1007
+
1008
+ auto cpedObj = cped.As <Object>();
1009
+ auto localSymbol = cpedSymbol_.Get (isolate); // signal safe?
1010
+ auto maybeProfData = cpedObj->Get (isolate->GetCurrentContext (), localSymbol); // signal safe?
1011
+ if (maybeProfData.IsEmpty ()) return std::shared_ptr<Global<Value>>();
1012
+ auto profData = maybeProfData.ToLocalChecked ();
1013
+
1014
+ if (profData->IsUndefined ()) return std::shared_ptr<Global<Value>>();
1015
+
1016
+ auto contextPtr = std::atomic_load_explicit (reinterpret_cast <ContextPtr*>(profData.As <External>()->Value ()), std::memory_order_relaxed);
973
1017
std::atomic_signal_fence (std::memory_order_acquire);
974
1018
return contextPtr;
975
1019
}
@@ -1001,12 +1045,14 @@ NAN_METHOD(WallProfiler::Dispose) {
1001
1045
1002
1046
void WallProfiler::PushContext (int64_t time_from,
1003
1047
int64_t time_to,
1004
- int64_t cpu_time) {
1048
+ int64_t cpu_time,
1049
+ Isolate* isolate) {
1005
1050
// Be careful this is called in a signal handler context therefore all
1006
1051
// operations must be async signal safe (in particular no allocations).
1007
1052
// Our ring buffer avoids allocations.
1008
1053
if (contexts_.size () < contexts_.capacity ()) {
1009
- contexts_.push_back ({GetContextPtr (), time_from, time_to, cpu_time});
1054
+ HandleScope handle_scope (isolate); // signal safe?
1055
+ contexts_.push_back ({GetContextPtr (isolate), time_from, time_to, cpu_time});
1010
1056
std::atomic_fetch_add_explicit (
1011
1057
reinterpret_cast <std::atomic<uint32_t >*>(&fields_[kSampleCount ]),
1012
1058
1U ,
0 commit comments