Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: v8::StackTrace::CurrentStackTrace() bindings #800

Merged
merged 4 commits into from
Dec 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1658,6 +1658,12 @@ const v8::Value* v8__ReturnValue__Get(const v8::ReturnValue<v8::Value>& self) {
return local_to_ptr(self.Get());
}

// Note: StackTraceOptions is deprecated, kDetailed is always used
const v8::StackTrace* v8__StackTrace__CurrentStackTrace(v8::Isolate* isolate,
int frame_limit) {
return local_to_ptr(v8::StackTrace::CurrentStackTrace(isolate, frame_limit));
}

int v8__StackTrace__GetFrameCount(const v8::StackTrace& self) {
return self.GetFrameCount();
}
Expand Down
19 changes: 19 additions & 0 deletions src/exception.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![allow(non_snake_case)]

use std::convert::TryInto;

use crate::isolate::Isolate;
use crate::support::int;
use crate::Context;
Expand Down Expand Up @@ -32,6 +34,10 @@ extern "C" {
fn v8__Message__IsOpaque(this: *const Message) -> bool;
fn v8__Message__GetStackTrace(this: *const Message) -> *const StackTrace;

fn v8__StackTrace__CurrentStackTrace(
isolate: *mut Isolate,
frame_limit: int,
) -> *const StackTrace;
fn v8__StackTrace__GetFrameCount(this: *const StackTrace) -> int;
fn v8__StackTrace__GetFrame(
this: *const StackTrace,
Expand Down Expand Up @@ -67,6 +73,19 @@ extern "C" {
}

impl StackTrace {
/// Grab a snapshot of the current JavaScript execution stack.
pub fn current_stack_trace<'s>(
scope: &mut HandleScope<'s>,
frame_limit: usize,
) -> Option<Local<'s, StackTrace>> {
let frame_limit = frame_limit.try_into().ok()?;
unsafe {
scope.cast_local(|sd| {
v8__StackTrace__CurrentStackTrace(sd.get_isolate_ptr(), frame_limit)
})
}
}

/// Returns the number of StackFrames.
pub fn get_frame_count(&self) -> usize {
unsafe { v8__StackTrace__GetFrameCount(self) as usize }
Expand Down
47 changes: 47 additions & 0 deletions tests/test_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5675,3 +5675,50 @@ fn backing_store_from_empty_boxed_slice() {
.make_shared();
let _ = v8::ArrayBuffer::with_backing_store(&mut scope, &store);
}

#[test]
fn current_stack_trace() {
// Setup isolate
let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope);
let scope = &mut v8::ContextScope::new(scope, context);

// A simple JS-facing function that returns its call depth, max of 5
fn call_depth(
scope: &mut v8::HandleScope,
_args: v8::FunctionCallbackArguments,
mut rv: v8::ReturnValue,
) {
let stack = v8::StackTrace::current_stack_trace(scope, 5).unwrap();
let count = stack.get_frame_count();
rv.set(v8::Integer::new(scope, count as i32).into())
}

let key = v8::String::new(scope, "callDepth").unwrap();
let tmpl = v8::FunctionTemplate::new(scope, call_depth);
let func = tmpl.get_function(scope).unwrap();
let global = context.global(scope);
global.set(scope, key.into(), func.into());

let top_level = eval(scope, "callDepth()")
.unwrap()
.uint32_value(scope)
.unwrap();
assert_eq!(top_level, 1);

let nested = eval(scope, "(_ => (_ => callDepth())())()")
.unwrap()
.uint32_value(scope)
.unwrap();
assert_eq!(nested, 3);

let too_deep = eval(
scope,
"(_ => (_ => (_ => (_ => (_ => (_ => (_ => callDepth())())())())())())())()",
)
.unwrap()
.uint32_value(scope)
.unwrap();
assert_eq!(too_deep, 5);
}