Trait wasmtime_runtime::GcHeap

source ·
pub unsafe trait GcHeap: 'static + Send + Sync {
Show 16 methods // Required methods fn as_any(&self) -> &dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any; fn enter_no_gc_scope(&mut self); fn exit_no_gc_scope(&mut self); fn header(&self, gc_ref: &VMGcRef) -> &VMGcHeader; fn clone_gc_ref(&mut self, gc_ref: &VMGcRef) -> VMGcRef; fn write_gc_ref( &mut self, host_data_table: &mut ExternRefHostDataTable, destination: &mut Option<VMGcRef>, source: Option<&VMGcRef> ); fn expose_gc_ref_to_wasm(&mut self, gc_ref: VMGcRef); fn need_gc_before_entering_wasm(&self, num_gc_refs: NonZeroUsize) -> bool; fn alloc_externref( &mut self, host_data: ExternRefHostDataId ) -> Result<Option<VMExternRef>>; fn externref_host_data( &self, externref: &VMExternRef ) -> ExternRefHostDataId; fn gc<'a>( &'a mut self, roots: GcRootsIter<'a>, host_data_table: &'a mut ExternRefHostDataTable ) -> Box<dyn GarbageCollection<'a> + 'a>; unsafe fn vmctx_gc_heap_base(&self) -> *mut u8; unsafe fn vmctx_gc_heap_bound(&self) -> usize; unsafe fn vmctx_gc_heap_data(&self) -> *mut u8; // Provided method fn drop_gc_ref( &mut self, host_data_table: &mut ExternRefHostDataTable, gc_ref: VMGcRef ) { ... }
}
Expand description

A heap that manages garbage-collected objects.

Each wasmtime::Store is associated with a single GcHeap, and a GcHeap is only ever used with one store at a time, but GcHeaps may be reused with new stores after its original store is dropped. The reset method will be called in between each such reuse. (This reuse allows for better integration with the pooling allocator).

If a GcHeap mapped any memory, its Drop implementation should unmap that memory.

§Safety

The trait methods below are all safe: implementations of this trait must ensure that these methods cannot be misused to create memory unsafety. The expectation is that – given that VMGcRef is a newtype over an index – implementations perform similar tricks as Wasm linear memory implementations. The heap should internally be a contiguous region of memory and VMGcRef indices into the heap must be bounds checked (explicitly or implicitly via virtual memory tricks).

Furthermore, if heap corruption occurs because (for example) a VMGcRef from a different heap is used with this heap, then that corruption must be limited to within this heap. Every heap is a mini sandbox. It follows that native pointers should never be written into or read out from the GC heap, since that could spread corruption from inside the GC heap out to the native host heap. The host data for an externref, therefore, is stored in a side table (ExternRefHostDataTable) and never inside the heap. Only an id referencing a slot in that table should ever be written into the GC heap.

These constraints give us great amounts of safety compared to working with raw pointers. The worst that could happen is corruption local to heap and a panic, or perhaps reading stale heap data from a previous Wasm instance. A corrupt GcHeap can never result in the native host’s corruption.

The downside is that we are introducing heap_base + index computations and bounds checking to access GC memory, adding performance overhead. This is deemed to be a worthy trade off. Furthermore, it isn’t even a clear cut performance degradation since this allows us to use 32-bit “pointers”, giving us more compact data representations and the improved cache utilization that implies.

Required Methods§

source

fn as_any(&self) -> &dyn Any

Get this heap as an &Any.

source

fn as_any_mut(&mut self) -> &mut dyn Any

Get this heap as an &mut Any.

source

fn enter_no_gc_scope(&mut self)

Enter a no-GC scope.

Calling the gc method when we are inside a no-GC scope should panic.

We can enter multiple, nested no-GC scopes and this method should account for that.

source

fn exit_no_gc_scope(&mut self)

Exit a no-GC scope.

Dual to enter_no_gc_scope.

source

fn header(&self, gc_ref: &VMGcRef) -> &VMGcHeader

Get a shared borrow of the VMGcHeader that this GC reference is pointing to.

source

fn clone_gc_ref(&mut self, gc_ref: &VMGcRef) -> VMGcRef

Read barrier called every time the runtime clones a GC reference.

Callers should pass a valid VMGcRef that belongs to the given heap. Failure to do so is memory safe, but may result in general failures such as panics or incorrect results.

source

fn write_gc_ref( &mut self, host_data_table: &mut ExternRefHostDataTable, destination: &mut Option<VMGcRef>, source: Option<&VMGcRef> )

Write barrier called every time the runtime overwrites a GC reference.

The source is a borrowed GC reference, and should not have been cloned already for this write operation. This allows implementations to fuse the source’s read barrier into this write barrier.

If an externref is reclaimed, then its associated entry in the host_data_table should be removed.

Callers should pass a valid VMGcRef that belongs to the given heap for both the source and destination. Failure to do so is memory safe, but may result in general failures such as panics or incorrect results.

source

fn expose_gc_ref_to_wasm(&mut self, gc_ref: VMGcRef)

Read barrier called whenever a GC reference is passed from the runtime to Wasm: an argument to a host-to-Wasm call, or a return from a Wasm-to-host call.

Callers should pass a valid VMGcRef that belongs to the given heap. Failure to do so is memory safe, but may result in general failures such as panics or incorrect results.

source

fn need_gc_before_entering_wasm(&self, num_gc_refs: NonZeroUsize) -> bool

Predicate invoked before calling into or returning to Wasm to determine whether we should GC first.

num_gc_refs is the number of non-i31ref GC references that will be passed into Wasm.

source

fn alloc_externref( &mut self, host_data: ExternRefHostDataId ) -> Result<Option<VMExternRef>>

Allocate a VMExternRef with space for host data described by the given layout.

Return values:

  • Ok(Some(_)): The allocation was successful.

  • Ok(None): There is currently no available space for this allocation. The caller should call self.gc(), run the GC to completion so the collector can reclaim space, and then try allocating again.

  • Err(_): The collector cannot satisfy this allocation request, and would not be able to even after the caller were to trigger a collection. This could be because, for example, the requested allocation is larger than this collector’s implementation limit for object size.

source

fn externref_host_data(&self, externref: &VMExternRef) -> ExternRefHostDataId

Get the host data ID associated with the given externref.

Callers should pass a valid externref that belongs to the given heap. Failure to do so is memory safe, but may result in general failures such as panics or incorrect results.

source

fn gc<'a>( &'a mut self, roots: GcRootsIter<'a>, host_data_table: &'a mut ExternRefHostDataTable ) -> Box<dyn GarbageCollection<'a> + 'a>

Start a new garbage collection process.

The given roots are GC roots and should not be collected (nor anything transitively reachable from them).

Upon reclaiming an externref, its associated entry in the host_data_table is removed.

Callers should pass valid GC roots that belongs to this heap, and the host data table associated with this heap’s externrefs. Failure to do so is memory safe, but may result in general failures such as panics or incorrect results.

This method should panic if we are in a no-GC scope.

source

unsafe fn vmctx_gc_heap_base(&self) -> *mut u8

Get the GC heap’s base pointer.

§Safety

The memory region

self.vmctx_gc_heap_base..self.vmctx_gc_heap_base + self.vmctx_gc_heap_bound

must be the GC heap region, and must remain valid for JIT code as long as self is not dropped.

source

unsafe fn vmctx_gc_heap_bound(&self) -> usize

Get the GC heap’s bound.

§Safety

The memory region

self.vmctx_gc_heap_base..self.vmctx_gc_heap_base + self.vmctx_gc_heap_bound

must be the GC heap region, and must remain valid for JIT code as long as self is not dropped.

source

unsafe fn vmctx_gc_heap_data(&self) -> *mut u8

Get the pointer that will be stored in the VMContext::gc_heap_data field and be accessible from JIT code via collaboration with the corresponding GcCompiler trait.

§Safety

The returned pointer, if any, must remain valid as long as self is not dropped.

Provided Methods§

source

fn drop_gc_ref( &mut self, host_data_table: &mut ExternRefHostDataTable, gc_ref: VMGcRef )

Write barrier called whenever the runtime is nulling out a GC reference.

Default implemented in terms of the write_gc_ref barrier.

If an externref is reclaimed, then its associated entry in the host_data_table should be removed.

Callers should pass a valid VMGcRef that belongs to the given heap. Failure to do so is memory safe, but may result in general failures such as panics or incorrect results.

The given gc_ref should not be used again.

Implementors§