Struct wasmtime_runtime::Backtrace
source · pub struct Backtrace(_);
Expand description
A WebAssembly stack trace.
Implementations§
source§impl Backtrace
impl Backtrace
sourcepub fn trace(f: impl FnMut(Frame) -> ControlFlow<()>)
pub fn trace(f: impl FnMut(Frame) -> ControlFlow<()>)
Walk the current Wasm stack, calling f
for each frame we walk.
Examples found in repository?
src/externref.rs (lines 897-961)
856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967
pub unsafe fn gc(
module_info_lookup: &dyn ModuleInfoLookup,
externref_activations_table: &mut VMExternRefActivationsTable,
) {
log::debug!("start GC");
#[cfg(debug_assertions)]
assert!(externref_activations_table.gc_okay);
debug_assert!({
// This set is only non-empty within this function. It is built up when
// walking the stack and interpreting stack maps, and then drained back
// into the activations table's bump-allocated space at the
// end. Therefore, it should always be empty upon entering this
// function.
externref_activations_table.precise_stack_roots.is_empty()
});
// This function proceeds by:
//
// * walking the stack,
//
// * finding the precise set of roots inside Wasm frames via our stack maps,
// and
//
// * resetting our bump-allocated table's over-approximation to the
// newly-discovered precise set.
// The `activations_table_set` is used for `debug_assert!`s checking that
// every reference we read out from the stack via stack maps is actually in
// the table. If that weren't true, than either we forgot to insert a
// reference in the table when passing it into Wasm (a bug) or we are
// reading invalid references from the stack (another bug).
let mut activations_table_set: DebugOnly<HashSet<_>> = Default::default();
if cfg!(debug_assertions) {
externref_activations_table.elements(|elem| {
activations_table_set.insert(elem.as_raw() as *mut VMExternData);
});
}
log::trace!("begin GC trace");
Backtrace::trace(|frame| {
let pc = frame.pc();
debug_assert!(pc != 0, "we should always get a valid PC for Wasm frames");
let fp = frame.fp();
debug_assert!(
fp != 0,
"we should always get a valid frame pointer for Wasm frames"
);
let module_info = module_info_lookup
.lookup(pc)
.expect("should have module info for Wasm frame");
let stack_map = match module_info.lookup_stack_map(pc) {
Some(sm) => sm,
None => {
log::trace!("No stack map for this Wasm frame");
return std::ops::ControlFlow::Continue(());
}
};
log::trace!(
"We have a stack map that maps {} words in this Wasm frame",
stack_map.mapped_words()
);
let sp = fp - stack_map.mapped_words() as usize * mem::size_of::<usize>();
for i in 0..(stack_map.mapped_words() as usize) {
// Stack maps have one bit per word in the frame, and the
// zero^th bit is the *lowest* addressed word in the frame,
// i.e. the closest to the SP. So to get the `i`^th word in
// this frame, we add `i * sizeof(word)` to the SP.
let stack_slot = sp + i * mem::size_of::<usize>();
if !stack_map.get_bit(i) {
log::trace!(
"Stack slot @ {:p} does not contain externrefs",
stack_slot as *const (),
);
continue;
}
let stack_slot = stack_slot as *const *mut VMExternData;
let r = std::ptr::read(stack_slot);
log::trace!("Stack slot @ {:p} = {:p}", stack_slot, r);
debug_assert!(
r.is_null() || activations_table_set.contains(&r),
"every on-stack externref inside a Wasm frame should \
have an entry in the VMExternRefActivationsTable; \
{:?} is not in the table",
r
);
if let Some(r) = NonNull::new(r) {
VMExternRefActivationsTable::insert_precise_stack_root(
&mut externref_activations_table.precise_stack_roots,
r,
);
}
}
std::ops::ControlFlow::Continue(())
});
log::trace!("end GC trace");
externref_activations_table.sweep();
log::debug!("end GC");
}
sourcepub fn frames<'a>(&'a self) -> impl ExactSizeIterator<Item = &'a Frame> + 'a
pub fn frames<'a>(&'a self) -> impl ExactSizeIterator<Item = &'a Frame> + 'a
Iterate over the frames inside this backtrace.