11#include < node.h>
22#include < mutex>
3- #include < map>
4- #include < sstream>
53#include < future>
64
75using namespace v8 ;
@@ -14,22 +12,18 @@ static std::unordered_map<v8::Isolate *, int> threads = {};
1412
1513static void ExecutionInterrupted (Isolate *isolate, void *data)
1614{
17- auto promise = static_cast <std::promise<std::string> *>(data);
18-
19- Local<StackTrace> stack = StackTrace::CurrentStackTrace (isolate, kMaxStackFrames , StackTrace::kDetailed );
15+ auto promise = static_cast <std::promise<Local<Array>> *>(data);
16+ auto stack = StackTrace::CurrentStackTrace (isolate, kMaxStackFrames , StackTrace::kDetailed );
2017
2118 if (stack.IsEmpty ())
2219 {
23- promise->set_value (" [] " );
20+ promise->set_value (Array::New (isolate, 0 ) );
2421 return ;
2522 }
2623
27- std::ostringstream out;
28-
29- out << " [" ;
30- auto count = stack->GetFrameCount ();
24+ auto frames = Array::New (isolate, stack->GetFrameCount ());
3125
32- for (auto i = 0 ; i < count ; i++)
26+ for (int i = 0 ; i < stack-> GetFrameCount () ; i++)
3327 {
3428 auto frame = stack->GetFrame (isolate, i);
3529 auto fn_name = frame->GetFunctionName ();
@@ -47,30 +41,36 @@ static void ExecutionInterrupted(Isolate *isolate, void *data)
4741 fn_name = String::NewFromUtf8 (isolate, " [constructor]" , NewStringType::kInternalized ).ToLocalChecked ();
4842 }
4943
50- String::Utf8Value function_name (isolate, fn_name);
51- String::Utf8Value script_name (isolate, frame->GetScriptName ());
52- auto line_number = frame->GetLineNumber ();
53- auto column = frame->GetColumn ();
44+ auto frame_obj = Object::New (isolate);
45+ frame_obj->Set (isolate->GetCurrentContext (),
46+ String::NewFromUtf8 (isolate, " function" , NewStringType::kInternalized ).ToLocalChecked (),
47+ fn_name)
48+ .Check ();
5449
55- out << " { \" function \" : \" " << *function_name
56- << " \" , \ " filename\" : \" " << *script_name
57- << " \" , \" lineno \" : " << line_number
58- << " , \" colno \" : " << column << " } " ;
50+ frame_obj-> Set (isolate-> GetCurrentContext (),
51+ String::NewFromUtf8 (isolate, " filename" , NewStringType:: kInternalized ). ToLocalChecked (),
52+ frame-> GetScriptName ())
53+ . Check () ;
5954
60- if (i < count - 1 )
61- {
62- out << " ," ;
63- }
64- }
55+ frame_obj->Set (isolate->GetCurrentContext (),
56+ String::NewFromUtf8 (isolate, " lineno" , NewStringType::kInternalized ).ToLocalChecked (),
57+ Integer::New (isolate, frame->GetLineNumber ()))
58+ .Check ();
59+
60+ frame_obj->Set (isolate->GetCurrentContext (),
61+ String::NewFromUtf8 (isolate, " colno" , NewStringType::kInternalized ).ToLocalChecked (),
62+ Integer::New (isolate, frame->GetColumn ()))
63+ .Check ();
6564
66- out << " ]" ;
65+ frames->Set (isolate->GetCurrentContext (), i, frame_obj).Check ();
66+ }
6767
68- promise->set_value (out. str () );
68+ promise->set_value (frames );
6969}
7070
71- std::string CaptureStackTrace (Isolate *isolate)
71+ Local<Array> CaptureStackTrace (Isolate *isolate)
7272{
73- std::promise<std::string > promise;
73+ std::promise<Local<Array> > promise;
7474 auto future = promise.get_future ();
7575
7676 isolate->RequestInterrupt (ExecutionInterrupted, &promise);
@@ -81,37 +81,28 @@ void CaptureStackTraces(const FunctionCallbackInfo<Value> &args)
8181{
8282 auto capture_from_isolate = args.GetIsolate ();
8383
84- std::vector<std::future<std::string>> futures;
84+ using ThreadResult = std::tuple<std::string, Local<Array>>;
85+ std::vector<std::future<ThreadResult>> futures;
8586
8687 std::lock_guard<std::mutex> lock (threads_mutex);
87- for (auto &thread : threads)
88+ for (auto [thread_isolate, thread_id] : threads)
8889 {
89- auto thread_isolate = thread.first ;
90- if (thread_isolate != capture_from_isolate)
91- {
92- int thread_id = thread.second ;
93- auto thread_name = thread_id == -1 ? " main" : " worker-" + std::to_string (thread_id);
94-
95- futures.emplace_back (std::async (std::launch::async, [thread_name](Isolate *isolate)
96- { return " \" " + thread_name + " \" :" + CaptureStackTrace (isolate); }, thread_isolate));
97- }
90+ if (thread_isolate == capture_from_isolate)
91+ continue ;
92+ auto thread_name = thread_id == -1 ? " main" : " worker-" + std::to_string (thread_id);
93+ futures.emplace_back (std::async (std::launch::async, [thread_name](Isolate *isolate) -> ThreadResult
94+ { return std::make_tuple (thread_name, CaptureStackTrace (isolate)); }, thread_isolate));
9895 }
9996
100- std::ostringstream out;
101-
102- auto count = futures.size ();
103- out << " {" ;
97+ Local<Object> result = Object::New (capture_from_isolate);
10498 for (auto &future : futures)
10599 {
106- out << future.get ();
107- if (--count > 0 )
108- {
109- out << " ," ;
110- }
100+ auto [thread_name, frames] = future.get ();
101+ auto key = String::NewFromUtf8 (capture_from_isolate, thread_name.c_str (), NewStringType::kNormal ).ToLocalChecked ();
102+ result->Set (capture_from_isolate->GetCurrentContext (), key, frames).Check ();
111103 }
112- out << " }" ;
113104
114- args.GetReturnValue ().Set (String::NewFromUtf8 (capture_from_isolate, out. str (). c_str (), NewStringType:: kNormal ). ToLocalChecked () );
105+ args.GetReturnValue ().Set (result );
115106}
116107
117108void Cleanup (void *arg)
@@ -131,7 +122,7 @@ void RegisterThread(const FunctionCallbackInfo<Value> &args)
131122 return ;
132123 }
133124
134- int thread_id = args[0 ].As <Number>()->Value ();
125+ auto thread_id = args[0 ].As <Number>()->Value ();
135126
136127 {
137128 std::lock_guard<std::mutex> lock (threads_mutex);
@@ -140,10 +131,9 @@ void RegisterThread(const FunctionCallbackInfo<Value> &args)
140131 node::AddEnvironmentCleanupHook (isolate, Cleanup, isolate);
141132}
142133
143- extern " C" NODE_MODULE_EXPORT void
144- NODE_MODULE_INITIALIZER (Local<Object> exports,
145- Local<Value> module ,
146- Local<Context> context)
134+ extern " C" NODE_MODULE_EXPORT void NODE_MODULE_INITIALIZER (Local<Object> exports,
135+ Local<Value> module ,
136+ Local<Context> context)
147137{
148138 auto isolate = context->GetIsolate ();
149139
0 commit comments