2019-01-08 17:09:47 +00:00
|
|
|
use crate::{
|
2019-02-07 00:26:45 +00:00
|
|
|
backend::{Backend, FuncResolver, ProtectedCaller},
|
2019-01-18 18:54:16 +00:00
|
|
|
error::Result,
|
2019-01-21 22:43:04 +00:00
|
|
|
import::ImportObject,
|
2019-02-07 00:26:45 +00:00
|
|
|
structures::{Map, TypedIndex},
|
2019-02-08 21:08:03 +00:00
|
|
|
typed_func::EARLY_TRAPPER,
|
2019-01-08 17:09:47 +00:00
|
|
|
types::{
|
2019-02-07 00:26:45 +00:00
|
|
|
FuncIndex, FuncSig, GlobalDescriptor, GlobalIndex, GlobalInit, ImportedFuncIndex,
|
2019-01-29 21:04:42 +00:00
|
|
|
ImportedGlobalIndex, ImportedMemoryIndex, ImportedTableIndex, Initializer,
|
|
|
|
LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryDescriptor, MemoryIndex,
|
|
|
|
SigIndex, TableDescriptor, TableIndex,
|
2019-01-08 17:09:47 +00:00
|
|
|
},
|
2019-01-11 03:59:57 +00:00
|
|
|
Instance,
|
2019-01-08 17:09:47 +00:00
|
|
|
};
|
|
|
|
use hashbrown::HashMap;
|
2019-02-07 00:26:45 +00:00
|
|
|
use indexmap::IndexMap;
|
2019-01-28 19:55:44 +00:00
|
|
|
use std::sync::Arc;
|
2019-01-08 17:09:47 +00:00
|
|
|
|
2019-01-19 07:03:07 +00:00
|
|
|
/// This is used to instantiate a new WebAssembly module.
|
2019-01-13 03:02:19 +00:00
|
|
|
#[doc(hidden)]
|
2019-01-08 17:09:47 +00:00
|
|
|
pub struct ModuleInner {
|
|
|
|
pub func_resolver: Box<dyn FuncResolver>,
|
2019-01-18 20:13:01 +00:00
|
|
|
pub protected_caller: Box<dyn ProtectedCaller>,
|
2019-01-18 22:30:15 +00:00
|
|
|
|
2019-02-07 00:26:45 +00:00
|
|
|
pub info: ModuleInfo,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
|
|
|
pub struct ModuleInfo {
|
2019-01-16 18:26:10 +00:00
|
|
|
// This are strictly local and the typsystem ensures that.
|
2019-01-29 21:04:42 +00:00
|
|
|
pub memories: Map<LocalMemoryIndex, MemoryDescriptor>,
|
2019-01-28 19:55:44 +00:00
|
|
|
pub globals: Map<LocalGlobalIndex, GlobalInit>,
|
2019-01-29 21:04:42 +00:00
|
|
|
pub tables: Map<LocalTableIndex, TableDescriptor>,
|
2019-01-08 17:09:47 +00:00
|
|
|
|
2019-01-16 18:26:10 +00:00
|
|
|
// These are strictly imported and the typesystem ensures that.
|
|
|
|
pub imported_functions: Map<ImportedFuncIndex, ImportName>,
|
2019-01-29 21:04:42 +00:00
|
|
|
pub imported_memories: Map<ImportedMemoryIndex, (ImportName, MemoryDescriptor)>,
|
|
|
|
pub imported_tables: Map<ImportedTableIndex, (ImportName, TableDescriptor)>,
|
|
|
|
pub imported_globals: Map<ImportedGlobalIndex, (ImportName, GlobalDescriptor)>,
|
2019-01-08 17:09:47 +00:00
|
|
|
|
2019-01-11 03:59:57 +00:00
|
|
|
pub exports: HashMap<String, ExportIndex>,
|
2019-01-08 17:09:47 +00:00
|
|
|
|
|
|
|
pub data_initializers: Vec<DataInitializer>,
|
2019-01-17 01:59:12 +00:00
|
|
|
pub elem_initializers: Vec<TableInitializer>,
|
|
|
|
|
2019-01-08 17:09:47 +00:00
|
|
|
pub start_func: Option<FuncIndex>,
|
|
|
|
|
|
|
|
pub func_assoc: Map<FuncIndex, SigIndex>,
|
2019-02-07 00:26:45 +00:00
|
|
|
pub signatures: Map<SigIndex, Arc<FuncSig>>,
|
|
|
|
pub backend: Backend,
|
|
|
|
|
|
|
|
pub namespace_table: StringTable<NamespaceIndex>,
|
|
|
|
pub name_table: StringTable<NameIndex>,
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
|
2019-01-23 20:34:15 +00:00
|
|
|
/// A compiled WebAssembly module.
|
|
|
|
///
|
|
|
|
/// `Module` is returned by the [`compile`] and
|
|
|
|
/// [`compile_with`] functions.
|
|
|
|
///
|
|
|
|
/// [`compile`]: fn.compile.html
|
|
|
|
/// [`compile_with`]: fn.compile_with.html
|
2019-01-28 19:55:44 +00:00
|
|
|
pub struct Module(#[doc(hidden)] pub Arc<ModuleInner>);
|
2019-01-08 17:09:47 +00:00
|
|
|
|
|
|
|
impl Module {
|
2019-01-28 19:55:44 +00:00
|
|
|
pub(crate) fn new(inner: Arc<ModuleInner>) -> Self {
|
2019-02-08 21:08:03 +00:00
|
|
|
unsafe {
|
|
|
|
EARLY_TRAPPER
|
|
|
|
.with(|ucell| *ucell.get() = Some(inner.protected_caller.get_early_trapper()));
|
|
|
|
}
|
2019-01-13 03:02:19 +00:00
|
|
|
Module(inner)
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
|
2019-01-23 20:34:15 +00:00
|
|
|
/// Instantiate a WebAssembly module with the provided [`ImportObject`].
|
|
|
|
///
|
|
|
|
/// [`ImportObject`]: struct.ImportObject.html
|
|
|
|
///
|
|
|
|
/// # Note:
|
|
|
|
/// Instantiating a `Module` will also call the function designated as `start`
|
|
|
|
/// in the WebAssembly module, if there is one.
|
|
|
|
///
|
|
|
|
/// # Usage:
|
|
|
|
/// ```
|
|
|
|
/// # use wasmer_runtime_core::error::Result;
|
|
|
|
/// # use wasmer_runtime_core::Module;
|
|
|
|
/// # use wasmer_runtime_core::imports;
|
|
|
|
/// # fn instantiate(module: &Module) -> Result<()> {
|
|
|
|
/// let import_object = imports! {
|
|
|
|
/// // ...
|
|
|
|
/// };
|
2019-02-03 00:02:28 +00:00
|
|
|
/// let instance = module.instantiate(&import_object)?;
|
2019-01-23 20:34:15 +00:00
|
|
|
/// // ...
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2019-02-02 23:58:33 +00:00
|
|
|
pub fn instantiate(&self, import_object: &ImportObject) -> Result<Instance> {
|
|
|
|
Instance::new(Arc::clone(&self.0), import_object)
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-16 18:26:10 +00:00
|
|
|
impl ModuleInner {}
|
2019-01-08 17:09:47 +00:00
|
|
|
|
2019-01-13 03:02:19 +00:00
|
|
|
#[doc(hidden)]
|
2019-02-07 00:26:45 +00:00
|
|
|
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
2019-01-08 17:09:47 +00:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct ImportName {
|
2019-02-07 00:26:45 +00:00
|
|
|
pub namespace_index: NamespaceIndex,
|
|
|
|
pub name_index: NameIndex,
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 00:26:45 +00:00
|
|
|
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
2019-01-08 17:09:47 +00:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
2019-01-11 03:59:57 +00:00
|
|
|
pub enum ExportIndex {
|
2019-01-08 17:09:47 +00:00
|
|
|
Func(FuncIndex),
|
|
|
|
Memory(MemoryIndex),
|
|
|
|
Global(GlobalIndex),
|
|
|
|
Table(TableIndex),
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A data initializer for linear memory.
|
2019-02-07 00:26:45 +00:00
|
|
|
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
2019-01-16 18:26:10 +00:00
|
|
|
#[derive(Debug, Clone)]
|
2019-01-08 17:09:47 +00:00
|
|
|
pub struct DataInitializer {
|
|
|
|
/// The index of the memory to initialize.
|
|
|
|
pub memory_index: MemoryIndex,
|
2019-01-17 01:59:12 +00:00
|
|
|
/// Either a constant offset or a `get_global`
|
|
|
|
pub base: Initializer,
|
2019-01-08 17:09:47 +00:00
|
|
|
/// The initialization data.
|
2019-02-07 00:26:45 +00:00
|
|
|
#[cfg_attr(feature = "cache", serde(with = "serde_bytes"))]
|
2019-01-08 17:09:47 +00:00
|
|
|
pub data: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A WebAssembly table initializer.
|
2019-02-07 00:26:45 +00:00
|
|
|
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
2019-01-16 18:26:10 +00:00
|
|
|
#[derive(Debug, Clone)]
|
2019-01-08 17:09:47 +00:00
|
|
|
pub struct TableInitializer {
|
|
|
|
/// The index of a table to initialize.
|
|
|
|
pub table_index: TableIndex,
|
2019-01-16 18:26:10 +00:00
|
|
|
/// Either a constant offset or a `get_global`
|
|
|
|
pub base: Initializer,
|
2019-01-08 17:09:47 +00:00
|
|
|
/// The values to write into the table elements.
|
|
|
|
pub elements: Vec<FuncIndex>,
|
|
|
|
}
|
2019-02-07 00:26:45 +00:00
|
|
|
|
|
|
|
pub struct StringTableBuilder<K: TypedIndex> {
|
|
|
|
map: IndexMap<String, (K, u32, u32)>,
|
|
|
|
buffer: String,
|
|
|
|
count: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<K: TypedIndex> StringTableBuilder<K> {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
map: IndexMap::new(),
|
|
|
|
buffer: String::new(),
|
|
|
|
count: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn register<S>(&mut self, s: S) -> K
|
|
|
|
where
|
|
|
|
S: Into<String> + AsRef<str>,
|
|
|
|
{
|
|
|
|
let s_str = s.as_ref();
|
|
|
|
|
|
|
|
if self.map.contains_key(s_str) {
|
|
|
|
self.map[s_str].0
|
|
|
|
} else {
|
|
|
|
let offset = self.buffer.len();
|
|
|
|
let length = s_str.len();
|
|
|
|
let index = TypedIndex::new(self.count as _);
|
|
|
|
|
|
|
|
self.buffer.push_str(s_str);
|
|
|
|
self.map
|
|
|
|
.insert(s.into(), (index, offset as u32, length as u32));
|
|
|
|
self.count += 1;
|
|
|
|
|
|
|
|
index
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn finish(self) -> StringTable<K> {
|
|
|
|
let table = self
|
|
|
|
.map
|
|
|
|
.values()
|
|
|
|
.map(|(_, offset, length)| (*offset, *length))
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
StringTable {
|
|
|
|
table,
|
|
|
|
buffer: self.buffer,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct StringTable<K: TypedIndex> {
|
|
|
|
table: Map<K, (u32, u32)>,
|
|
|
|
buffer: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<K: TypedIndex> StringTable<K> {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
table: Map::new(),
|
|
|
|
buffer: String::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get(&self, index: K) -> &str {
|
|
|
|
let (offset, length) = self.table[index];
|
|
|
|
let offset = offset as usize;
|
|
|
|
let length = length as usize;
|
|
|
|
|
|
|
|
&self.buffer[offset..offset + length]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
|
|
|
pub struct NamespaceIndex(u32);
|
|
|
|
|
|
|
|
impl TypedIndex for NamespaceIndex {
|
|
|
|
#[doc(hidden)]
|
|
|
|
fn new(index: usize) -> Self {
|
|
|
|
NamespaceIndex(index as _)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
fn index(&self) -> usize {
|
|
|
|
self.0 as usize
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
|
|
|
pub struct NameIndex(u32);
|
|
|
|
|
|
|
|
impl TypedIndex for NameIndex {
|
|
|
|
#[doc(hidden)]
|
|
|
|
fn new(index: usize) -> Self {
|
|
|
|
NameIndex(index as _)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
fn index(&self) -> usize {
|
|
|
|
self.0 as usize
|
|
|
|
}
|
|
|
|
}
|