Browse Source
* Make module ids unique per-process, not per-engine Currently all instances of `wasmtime::Module` have a unique 64-bit id embedded into them. This ID was originally only used for affinity in the pooling allocator as a quick check of module equality. This use case only required engine-local ids so the initial implementation had an ID allocator per-engine. Later, however, this id was reused for `wasmtime::ModuleExport` which was intended to skip the string lookup for an export at runtime. This also stored a module id but it did not store an engine identifier. This meant that it's possible to mix these up and pass the wrong export to the wrong engine. This behavior can lead to a runtime panic in Wasmtime. This commit fixes this by making the module identifier be global per-process instead of per-engine. This mirrors how store IDs are allocated where they're per-process instead of per-engine. The same logic for why store IDs are unlikely to be exhausted applies here too where this 64-bit space of identifiers is unlikely to be exhausted. * Fix warnings * Fix testspull/8761/head
Alex Crichton
5 months ago
committed by
GitHub
8 changed files with 51 additions and 69 deletions
@ -1,43 +1,19 @@ |
|||
//! Unique IDs for modules in the runtime.
|
|||
|
|||
use core::{ |
|||
num::NonZeroU64, |
|||
sync::atomic::{AtomicU64, Ordering}, |
|||
}; |
|||
use core::num::NonZeroU64; |
|||
|
|||
/// A unique identifier (within an engine or similar) for a compiled
|
|||
/// module.
|
|||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
|||
pub struct CompiledModuleId(NonZeroU64); |
|||
|
|||
/// An allocator for compiled module IDs.
|
|||
pub struct CompiledModuleIdAllocator { |
|||
next: AtomicU64, |
|||
} |
|||
|
|||
impl CompiledModuleIdAllocator { |
|||
/// Create a compiled-module ID allocator.
|
|||
impl CompiledModuleId { |
|||
/// Allocates a new ID which will be unique within this process.
|
|||
pub fn new() -> Self { |
|||
Self { |
|||
next: AtomicU64::new(1), |
|||
} |
|||
} |
|||
|
|||
/// Allocate a new ID.
|
|||
pub fn alloc(&self) -> CompiledModuleId { |
|||
// Note: why is `Relaxed` OK here?
|
|||
//
|
|||
// The only requirement we have is that IDs are unique. We
|
|||
// don't care how one module's ID compares to another, i.e.,
|
|||
// what order they come in. `Relaxed` means that this
|
|||
// `fetch_add` operation does not have any particular
|
|||
// synchronization (ordering) with respect to any other memory
|
|||
// access in the program. However, `fetch_add` is always
|
|||
// atomic with respect to other accesses to this variable
|
|||
// (`self.next`). So we will always hand out separate, unique
|
|||
// IDs correctly, just in some possibly arbitrary order (which
|
|||
// is fine).
|
|||
let id = self.next.fetch_add(1, Ordering::Relaxed); |
|||
CompiledModuleId(NonZeroU64::new(id).unwrap()) |
|||
// As an implementation detail this is implemented on the same
|
|||
// allocator as stores. It's ok if there are "holes" in the store id
|
|||
// space as it's not required to be compact, it's just used for
|
|||
// uniqueness.
|
|||
CompiledModuleId(crate::store::StoreId::allocate().as_raw()) |
|||
} |
|||
} |
|||
|
Loading…
Reference in new issue