#[repr(C)]
pub struct VMExternRefActivationsTable { /* private fields */ }
Expand description

A table that over-approximizes the set of VMExternRefs that any Wasm activation on this thread is currently using.

Under the covers, this is a simple bump allocator that allows duplicate entries. Deduplication happens at GC time.

Implementations§

Create a new VMExternRefActivationsTable.

Get the available capacity in the bump allocation chunk.

Try and insert a VMExternRef into this table.

This is a fast path that only succeeds when the bump chunk has the capacity for the requested insertion.

If the insertion fails, then the VMExternRef is given back. Callers may attempt a GC to free up space and try again, or may call insert_slow_path to infallibly insert the reference (potentially allocating additional space in the table to hold it).

Examples found in repository?
src/externref.rs (line 658)
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
    pub unsafe fn insert_with_gc(
        &mut self,
        externref: VMExternRef,
        module_info_lookup: &dyn ModuleInfoLookup,
    ) {
        #[cfg(debug_assertions)]
        assert!(self.gc_okay);

        if let Err(externref) = self.try_insert(externref) {
            self.gc_and_insert_slow(externref, module_info_lookup);
        }
    }

    #[inline(never)]
    unsafe fn gc_and_insert_slow(
        &mut self,
        externref: VMExternRef,
        module_info_lookup: &dyn ModuleInfoLookup,
    ) {
        gc(module_info_lookup, self);

        // Might as well insert right into the hash set, rather than the bump
        // chunk, since we are already on a slow path and we get de-duplication
        // this way.
        self.over_approximated_stack_roots
            .insert(VMExternRefWithTraits(externref));
    }

    /// Insert a reference into the table, without ever performing GC.
    #[inline]
    pub fn insert_without_gc(&mut self, externref: VMExternRef) {
        if let Err(externref) = self.try_insert(externref) {
            self.insert_slow_without_gc(externref);
        }
    }

Insert a reference into the table, falling back on a GC to clear up space if the table is already full.

Unsafety

The same as gc.

Examples found in repository?
src/libcalls.rs (line 393)
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
unsafe fn activations_table_insert_with_gc(vmctx: *mut VMContext, externref: *mut u8) {
    let externref = VMExternRef::clone_from_raw(externref);
    let instance = (*vmctx).instance();
    let (activations_table, module_info_lookup) = (*instance.store()).externref_activations_table();

    // Invariant: all `externref`s on the stack have an entry in the activations
    // table. So we need to ensure that this `externref` is in the table
    // *before* we GC, even though `insert_with_gc` will ensure that it is in
    // the table *after* the GC. This technically results in one more hash table
    // look up than is strictly necessary -- which we could avoid by having an
    // additional GC method that is aware of these GC-triggering references --
    // but it isn't really a concern because this is already a slow path.
    activations_table.insert_without_gc(externref.clone());

    activations_table.insert_with_gc(externref, module_info_lookup);
}

// Perform a Wasm `global.get` for `externref` globals.
unsafe fn externref_global_get(vmctx: *mut VMContext, index: u32) -> *mut u8 {
    let index = GlobalIndex::from_u32(index);
    let instance = (*vmctx).instance();
    let global = instance.defined_or_imported_global_ptr(index);
    match (*global).as_externref().clone() {
        None => ptr::null_mut(),
        Some(externref) => {
            let raw = externref.as_raw();
            let (activations_table, module_info_lookup) =
                (*instance.store()).externref_activations_table();
            activations_table.insert_with_gc(externref, module_info_lookup);
            raw
        }
    }
}

Insert a reference into the table, without ever performing GC.

Examples found in repository?
src/libcalls.rs (line 391)
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
unsafe fn activations_table_insert_with_gc(vmctx: *mut VMContext, externref: *mut u8) {
    let externref = VMExternRef::clone_from_raw(externref);
    let instance = (*vmctx).instance();
    let (activations_table, module_info_lookup) = (*instance.store()).externref_activations_table();

    // Invariant: all `externref`s on the stack have an entry in the activations
    // table. So we need to ensure that this `externref` is in the table
    // *before* we GC, even though `insert_with_gc` will ensure that it is in
    // the table *after* the GC. This technically results in one more hash table
    // look up than is strictly necessary -- which we could avoid by having an
    // additional GC method that is aware of these GC-triggering references --
    // but it isn't really a concern because this is already a slow path.
    activations_table.insert_without_gc(externref.clone());

    activations_table.insert_with_gc(externref, module_info_lookup);
}

Set whether it is okay to GC or not right now.

This is provided as a helper for enabling various debug-only assertions and checking places where the wasmtime-runtime user expects there not to be any GCs.

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.