@@ -22,6 +22,7 @@ using v8::Integer;
2222using v8::Isolate;
2323using v8::KeyCollectionMode;
2424using v8::Local;
25+ using v8::LocalVector;
2526using v8::Object;
2627using v8::ObjectTemplate;
2728using v8::ONLY_CONFIGURABLE;
@@ -254,12 +255,60 @@ static void ParseEnv(const FunctionCallbackInfo<Value>& args) {
254255 args.GetReturnValue ().Set (dotenv.ToObject (env));
255256}
256257
258+ static void GetCallSite (const FunctionCallbackInfo<Value>& args) {
259+ Environment* env = Environment::GetCurrent (args);
260+ Isolate* isolate = env->isolate ();
261+
262+ CHECK_EQ (args.Length (), 1 );
263+ CHECK (args[0 ]->IsNumber ());
264+ const uint32_t frames = args[0 ].As <Uint32>()->Value ();
265+ DCHECK (frames >= 1 && frames <= 200 );
266+
267+ // +1 for disregarding node:util
268+ Local<StackTrace> stack = StackTrace::CurrentStackTrace (isolate, frames + 1 );
269+ const int frame_count = stack->GetFrameCount ();
270+ LocalVector<Value> callsite_objects (isolate);
271+
272+ // Frame 0 is node:util. It should be skipped.
273+ for (int i = 1 ; i < frame_count; ++i) {
274+ Local<Object> obj = Object::New (isolate);
275+ Local<StackFrame> stack_frame = stack->GetFrame (isolate, i);
276+
277+ Utf8Value function_name (isolate, stack_frame->GetFunctionName ());
278+ Utf8Value script_name (isolate, stack_frame->GetScriptName ());
279+
280+ obj->Set (env->context (),
281+ env->function_name_string (),
282+ String::NewFromUtf8 (isolate, *function_name).ToLocalChecked ())
283+ .Check ();
284+ obj->Set (env->context (),
285+ env->script_name_string (),
286+ String::NewFromUtf8 (isolate, *script_name).ToLocalChecked ())
287+ .Check ();
288+ obj->Set (env->context (),
289+ env->line_number_string (),
290+ Integer::NewFromUnsigned (isolate, stack_frame->GetLineNumber ()))
291+ .Check ();
292+ obj->Set (env->context (),
293+ env->column_string (),
294+ Integer::NewFromUnsigned (isolate, stack_frame->GetColumn ()))
295+ .Check ();
296+
297+ callsite_objects.push_back (obj);
298+ }
299+
300+ Local<Array> callsites =
301+ Array::New (isolate, callsite_objects.data (), callsite_objects.size ());
302+ args.GetReturnValue ().Set (callsites);
303+ }
304+
257305void RegisterExternalReferences (ExternalReferenceRegistry* registry) {
258306 registry->Register (GetPromiseDetails);
259307 registry->Register (GetProxyDetails);
260308 registry->Register (GetCallerLocation);
261309 registry->Register (IsArrayBufferDetached);
262310 registry->Register (PreviewEntries);
311+ registry->Register (GetCallSite);
263312 registry->Register (GetOwnNonIndexProperties);
264313 registry->Register (GetConstructorName);
265314 registry->Register (GetExternalValue);
@@ -365,6 +414,7 @@ void Initialize(Local<Object> target,
365414 SetMethodNoSideEffect (
366415 context, target, " getConstructorName" , GetConstructorName);
367416 SetMethodNoSideEffect (context, target, " getExternalValue" , GetExternalValue);
417+ SetMethodNoSideEffect (context, target, " getCallSite" , GetCallSite);
368418 SetMethod (context, target, " sleep" , Sleep);
369419 SetMethod (context, target, " parseEnv" , ParseEnv);
370420
0 commit comments