Add caching. (#134)

* Allow a module to have a different signature registry than the process-specific

* Add core ability to build compiled code caches

* Remove timing printouts

* Serialize/Deserialize memories to reduce copies

* Work more on api

* Relocate local functions relatively before external functions

* Fix incorrect definition in test

* merge errors caused by merge

* Fix emscripten compile

* Fix review comments
This commit is contained in:
Lachlan Sneff
2019-02-06 16:26:45 -08:00
committed by GitHub
parent 2f2f86a4de
commit 8fe9b7eac2
34 changed files with 1768 additions and 291 deletions

View File

@ -1,11 +1,10 @@
use crate::{
backend::{FuncResolver, ProtectedCaller},
backend::{Backend, FuncResolver, ProtectedCaller},
error::Result,
import::ImportObject,
sig_registry::SigRegistry,
structures::Map,
structures::{Map, TypedIndex},
types::{
FuncIndex, GlobalDescriptor, GlobalIndex, GlobalInit, ImportedFuncIndex,
FuncIndex, FuncSig, GlobalDescriptor, GlobalIndex, GlobalInit, ImportedFuncIndex,
ImportedGlobalIndex, ImportedMemoryIndex, ImportedTableIndex, Initializer,
LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryDescriptor, MemoryIndex,
SigIndex, TableDescriptor, TableIndex,
@ -13,6 +12,7 @@ use crate::{
Instance,
};
use hashbrown::HashMap;
use indexmap::IndexMap;
use std::sync::Arc;
/// This is used to instantiate a new WebAssembly module.
@ -21,6 +21,11 @@ pub struct ModuleInner {
pub func_resolver: Box<dyn FuncResolver>,
pub protected_caller: Box<dyn ProtectedCaller>,
pub info: ModuleInfo,
}
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
pub struct ModuleInfo {
// This are strictly local and the typsystem ensures that.
pub memories: Map<LocalMemoryIndex, MemoryDescriptor>,
pub globals: Map<LocalGlobalIndex, GlobalInit>,
@ -40,7 +45,11 @@ pub struct ModuleInner {
pub start_func: Option<FuncIndex>,
pub func_assoc: Map<FuncIndex, SigIndex>,
pub sig_registry: SigRegistry,
pub signatures: Map<SigIndex, Arc<FuncSig>>,
pub backend: Backend,
pub namespace_table: StringTable<NamespaceIndex>,
pub name_table: StringTable<NameIndex>,
}
/// A compiled WebAssembly module.
@ -87,21 +96,14 @@ impl Module {
impl ModuleInner {}
#[doc(hidden)]
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct ImportName {
pub namespace: String,
pub name: String,
}
impl From<(String, String)> for ImportName {
fn from(n: (String, String)) -> Self {
ImportName {
namespace: n.0,
name: n.1,
}
}
pub namespace_index: NamespaceIndex,
pub name_index: NameIndex,
}
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExportIndex {
Func(FuncIndex),
@ -111,6 +113,7 @@ pub enum ExportIndex {
}
/// A data initializer for linear memory.
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct DataInitializer {
/// The index of the memory to initialize.
@ -118,10 +121,12 @@ pub struct DataInitializer {
/// Either a constant offset or a `get_global`
pub base: Initializer,
/// The initialization data.
#[cfg_attr(feature = "cache", serde(with = "serde_bytes"))]
pub data: Vec<u8>,
}
/// A WebAssembly table initializer.
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct TableInitializer {
/// The index of a table to initialize.
@ -131,3 +136,110 @@ pub struct TableInitializer {
/// The values to write into the table elements.
pub elements: Vec<FuncIndex>,
}
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
}
}