#[repr(C)]pub struct VMExternRefActivationsTable { /* private fields */ }
Expand description
A table that over-approximizes the set of VMExternRef
s 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§
source§impl VMExternRefActivationsTable
impl VMExternRefActivationsTable
sourcepub fn bump_capacity_remaining(&self) -> usize
pub fn bump_capacity_remaining(&self) -> usize
Get the available capacity in the bump allocation chunk.
sourcepub fn try_insert(&mut self, externref: VMExternRef) -> Result<(), VMExternRef>
pub fn try_insert(&mut self, externref: VMExternRef) -> Result<(), VMExternRef>
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?
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);
}
}
sourcepub unsafe fn insert_with_gc(
&mut self,
externref: VMExternRef,
module_info_lookup: &dyn ModuleInfoLookup
)
pub unsafe fn insert_with_gc(
&mut self,
externref: VMExternRef,
module_info_lookup: &dyn ModuleInfoLookup
)
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?
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
}
}
}
sourcepub fn insert_without_gc(&mut self, externref: VMExternRef)
pub fn insert_without_gc(&mut self, externref: VMExternRef)
Insert a reference into the table, without ever performing GC.
Examples found in repository?
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);
}
sourcepub fn set_gc_okay(&mut self, okay: bool) -> bool
pub fn set_gc_okay(&mut self, okay: bool) -> bool
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.