pub struct Backtrace(_);
Expand description

A WebAssembly stack trace.

Implementations§

Returns an empty backtrace

Capture the current Wasm stack in a backtrace.

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");
}

Iterate over the frames inside this backtrace.

Trait Implementations§

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.