-
Notifications
You must be signed in to change notification settings - Fork 118
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow iterating over the frames of a CapturedJSStack (#539)
* Allow iterating over the frames in a SavedJSStack Signed-off-by: Simon Wülker <[email protected]> * Add test for CapturedJSStack::for_each_stack_frame Signed-off-by: Simon Wülker <[email protected]> * Move stack iteration test into its own file This prevents other tests from interfering with the js engine initialization Signed-off-by: Simon Wülker <[email protected]> --------- Signed-off-by: Simon Wülker <[email protected]>
- Loading branch information
1 parent
8ac1958
commit bb560b6
Showing
4 changed files
with
148 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,24 @@ use mozjs::rust::{JSEngine, RealmOptions, Runtime, SIMPLE_GLOBAL_CLASS}; | |
|
||
#[test] | ||
fn capture_stack() { | ||
unsafe extern "C" fn print_stack(context: *mut JSContext, argc: u32, vp: *mut Value) -> bool { | ||
let args = CallArgs::from_vp(vp, argc); | ||
|
||
capture_stack!(in(context) let stack); | ||
let str_stack = stack | ||
.unwrap() | ||
.as_string(None, StackFormat::SpiderMonkey) | ||
.unwrap(); | ||
println!("{}", str_stack); | ||
assert_eq!( | ||
"[email protected]:3:21\n[email protected]:5:17\n@test.js:8:16\n".to_string(), | ||
str_stack | ||
); | ||
|
||
args.rval().set(UndefinedValue()); | ||
true | ||
} | ||
|
||
let engine = JSEngine::init().unwrap(); | ||
let runtime = Runtime::new(engine.handle()); | ||
let context = runtime.cx(); | ||
|
@@ -59,21 +77,3 @@ fn capture_stack() { | |
.is_ok()); | ||
} | ||
} | ||
|
||
unsafe extern "C" fn print_stack(context: *mut JSContext, argc: u32, vp: *mut Value) -> bool { | ||
let args = CallArgs::from_vp(vp, argc); | ||
|
||
capture_stack!(in(context) let stack); | ||
let str_stack = stack | ||
.unwrap() | ||
.as_string(None, StackFormat::SpiderMonkey) | ||
.unwrap(); | ||
println!("{}", str_stack); | ||
assert_eq!( | ||
"[email protected]:3:21\n[email protected]:5:17\n@test.js:8:16\n".to_string(), | ||
str_stack | ||
); | ||
|
||
args.rval().set(UndefinedValue()); | ||
true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
use std::ptr; | ||
|
||
use mozjs::{ | ||
capture_stack, | ||
jsapi::{self, JSAutoRealm, JSContext, OnNewGlobalHookOption, Value}, | ||
jsval::UndefinedValue, | ||
rooted, | ||
rust::{JSEngine, RealmOptions, Runtime, SIMPLE_GLOBAL_CLASS}, | ||
}; | ||
|
||
#[test] | ||
fn iterate_stack_frames() { | ||
unsafe extern "C" fn assert_stack_state( | ||
context: *mut JSContext, | ||
_argc: u32, | ||
_vp: *mut Value, | ||
) -> bool { | ||
let mut function_names = vec![]; | ||
capture_stack!(in(context) let stack); | ||
stack.unwrap().for_each_stack_frame(|frame| { | ||
rooted!(in(context) let mut result: *mut jsapi::JSString = ptr::null_mut()); | ||
|
||
// Get function name | ||
unsafe { | ||
jsapi::GetSavedFrameFunctionDisplayName( | ||
context, | ||
ptr::null_mut(), | ||
frame.into(), | ||
result.handle_mut().into(), | ||
jsapi::SavedFrameSelfHosted::Include, | ||
); | ||
} | ||
let buffer = if !result.is_null() { | ||
let mut buffer = vec![0; 3]; | ||
jsapi::JS_EncodeStringToBuffer(context, *result, buffer.as_mut_ptr(), 3); | ||
Some(buffer.into_iter().map(|c| c as u8).collect()) | ||
} else { | ||
None | ||
}; | ||
function_names.push(buffer); | ||
}); | ||
|
||
assert_eq!(function_names.len(), 4); | ||
assert_eq!(function_names[0], Some(b"baz".to_vec())); | ||
assert_eq!(function_names[1], Some(b"bar".to_vec())); | ||
assert_eq!(function_names[2], Some(b"foo".to_vec())); | ||
assert_eq!(function_names[3], None); | ||
|
||
true | ||
} | ||
|
||
let engine = JSEngine::init().unwrap(); | ||
let runtime = Runtime::new(engine.handle()); | ||
let context = runtime.cx(); | ||
#[cfg(feature = "debugmozjs")] | ||
unsafe { | ||
mozjs::jsapi::SetGCZeal(context, 2, 1); | ||
} | ||
let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook; | ||
let c_option = RealmOptions::default(); | ||
|
||
unsafe { | ||
rooted!(in(context) let global = jsapi::JS_NewGlobalObject( | ||
context, | ||
&SIMPLE_GLOBAL_CLASS, | ||
ptr::null_mut(), | ||
h_option, | ||
&*c_option, | ||
)); | ||
let _ac = JSAutoRealm::new(context, global.get()); | ||
|
||
let function = jsapi::JS_DefineFunction( | ||
context, | ||
global.handle().into(), | ||
c"assert_stack_state".as_ptr(), | ||
Some(assert_stack_state), | ||
0, | ||
0, | ||
); | ||
assert!(!function.is_null()); | ||
|
||
let javascript = " | ||
function foo() { | ||
function bar() { | ||
function baz() { | ||
assert_stack_state(); | ||
} | ||
baz(); | ||
} | ||
bar(); | ||
} | ||
foo(); | ||
"; | ||
rooted!(in(context) let mut rval = UndefinedValue()); | ||
assert!(runtime | ||
.evaluate_script(global.handle(), javascript, "test.js", 0, rval.handle_mut()) | ||
.is_ok()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters