Add importable memories and dynamic memories

This commit is contained in:
Lachlan Sneff
2019-01-25 15:28:54 -08:00
parent a20627964c
commit e4686e67c4
26 changed files with 992 additions and 694 deletions

View File

@ -1,17 +1,20 @@
use crate::{module::Converter, module_env::ModuleEnv};
use crate::{module::Converter, module_env::ModuleEnv, relocation::call_names};
use cranelift_codegen::{
cursor::FuncCursor,
ir::{self, InstBuilder},
isa,
};
use cranelift_wasm::{self, FuncEnvironment, ModuleEnvironment};
use std::mem;
use wasmer_runtime_core::{
memory::LinearMemory,
memory::MemoryType,
structures::TypedIndex,
types::{FuncIndex, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex},
vm,
};
const WASM_PAGE_SIZE: usize = 65_536;
pub struct FuncEnv<'env, 'module, 'isa> {
env: &'env ModuleEnv<'module, 'isa>,
}
@ -140,7 +143,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
let ptr_type = self.pointer_type();
match mem_index.local_or_import(self.env.module) {
let (local_memory_ptr_ptr, description) = match mem_index.local_or_import(self.env.module) {
LocalOrImport::Local(local_mem_index) => {
let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load {
base: vmctx,
@ -149,75 +152,88 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
readonly: true,
});
let memory_offset = local_mem_index.index() * vm::LocalMemory::size() as usize;
let local_memory_ptr_offset =
local_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>();
let memory_struct_addr = func.create_global_value(ir::GlobalValueData::IAddImm {
base: memories_base_addr,
offset: (memory_offset as i64).into(),
global_type: ptr_type,
});
let memory_base_addr = func.create_global_value(ir::GlobalValueData::Load {
base: memory_struct_addr,
offset: (vm::LocalMemory::offset_base() as i32).into(),
global_type: ptr_type,
readonly: true,
});
func.create_heap(ir::HeapData {
base: memory_base_addr,
min_size: (self.env.module.memories[local_mem_index].min as u64).into(),
offset_guard_size: (LinearMemory::DEFAULT_GUARD_SIZE as u64).into(),
style: ir::HeapStyle::Static {
bound: (LinearMemory::DEFAULT_HEAP_SIZE as u64).into(),
},
index_type: ir::types::I32,
})
(
func.create_global_value(ir::GlobalValueData::IAddImm {
base: memories_base_addr,
offset: (local_memory_ptr_offset as i64).into(),
global_type: ptr_type,
}),
self.env.module.memories[local_mem_index],
)
}
LocalOrImport::Import(imported_mem_index) => {
let imported_memories_base = func.create_global_value(ir::GlobalValueData::Load {
LocalOrImport::Import(import_mem_index) => {
let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load {
base: vmctx,
offset: (vm::Ctx::offset_imported_memories() as i32).into(),
global_type: ptr_type,
readonly: true,
});
let imported_memory_offset =
imported_mem_index.index() * vm::ImportedMemory::size() as usize;
let local_memory_ptr_offset =
import_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>();
let imported_memory_struct_addr =
(
func.create_global_value(ir::GlobalValueData::IAddImm {
base: imported_memories_base,
offset: (imported_memory_offset as i64).into(),
base: memories_base_addr,
offset: (local_memory_ptr_offset as i64).into(),
global_type: ptr_type,
});
}),
self.env.module.imported_memories[import_mem_index].1,
)
}
};
let local_memory_struct_addr =
func.create_global_value(ir::GlobalValueData::Load {
base: imported_memory_struct_addr,
offset: (vm::ImportedMemory::offset_memory() as i32).into(),
global_type: ptr_type,
readonly: true,
});
let (local_memory_ptr, local_memory_base) = {
let local_memory_ptr = func.create_global_value(ir::GlobalValueData::Load {
base: local_memory_ptr_ptr,
offset: 0.into(),
global_type: ptr_type,
readonly: true,
});
let local_memory_base = func.create_global_value(ir::GlobalValueData::Load {
base: local_memory_struct_addr,
(
local_memory_ptr,
func.create_global_value(ir::GlobalValueData::Load {
base: local_memory_ptr,
offset: (vm::LocalMemory::offset_base() as i32).into(),
global_type: ptr_type,
readonly: true,
readonly: false,
}),
)
};
match description.memory_type() {
mem_type @ MemoryType::Dynamic => {
let local_memory_bound = func.create_global_value(ir::GlobalValueData::Load {
base: local_memory_ptr,
offset: (vm::LocalMemory::offset_bound() as i32).into(),
global_type: ptr_type,
readonly: false,
});
func.create_heap(ir::HeapData {
base: local_memory_base,
min_size: (self.env.module.imported_memories[imported_mem_index].1.min as u64)
.into(),
offset_guard_size: (LinearMemory::DEFAULT_GUARD_SIZE as u64).into(),
style: ir::HeapStyle::Static {
bound: (LinearMemory::DEFAULT_HEAP_SIZE as u64).into(),
min_size: ((description.min as u64) * (WASM_PAGE_SIZE as u64)).into(),
offset_guard_size: mem_type.guard_size().into(),
style: ir::HeapStyle::Dynamic {
bound_gv: local_memory_bound,
},
index_type: ir::types::I32,
})
}
mem_type @ MemoryType::Static | mem_type @ MemoryType::SharedStatic => func
.create_heap(ir::HeapData {
base: local_memory_base,
min_size: ((description.min as u64) * (WASM_PAGE_SIZE as u64)).into(),
offset_guard_size: mem_type.guard_size().into(),
style: ir::HeapStyle::Static {
bound: mem_type.bounds().unwrap().into(),
},
index_type: ir::types::I32,
}),
}
}
@ -539,23 +555,27 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
let (name, mem_index) = match mem_index.local_or_import(self.env.module) {
LocalOrImport::Local(local_mem_index) => {
(
// local_static_memory_grow
ir::ExternalName::user(1, 0),
local_mem_index.index(),
)
}
LocalOrImport::Import(imported_mem_index) => {
(
// imported_static_memory_grow
ir::ExternalName::user(1, 2),
imported_mem_index.index(),
)
}
let (namespace, mem_index, description) = match mem_index.local_or_import(self.env.module) {
LocalOrImport::Local(local_mem_index) => (
call_names::LOCAL_NAMESPACE,
local_mem_index.index(),
self.env.module.memories[local_mem_index],
),
LocalOrImport::Import(import_mem_index) => (
call_names::IMPORT_NAMESPACE,
import_mem_index.index(),
self.env.module.imported_memories[import_mem_index].1,
),
};
let name_index = match description.memory_type() {
MemoryType::Dynamic => call_names::DYNAMIC_MEM_GROW,
MemoryType::Static => call_names::STATIC_MEM_GROW,
MemoryType::SharedStatic => call_names::SHARED_STATIC_MEM_GROW,
};
let name = ir::ExternalName::user(namespace, name_index);
let mem_grow_func = pos.func.import_function(ir::ExtFuncData {
name,
signature,
@ -587,37 +607,6 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
clif_mem_index: cranelift_wasm::MemoryIndex,
_heap: ir::Heap,
) -> cranelift_wasm::WasmResult<ir::Value> {
// let signature = pos.func.import_signature(ir::Signature {
// call_conv: self.target_config().default_call_conv,
// params: vec![
// ir::AbiParam::new(ir::types::I32),
// ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
// ],
// returns: vec![ir::AbiParam::new(ir::types::I32)],
// });
// let size_mem_func = pos.func.import_function(ir::ExtFuncData {
// // `ir::ExternalName` for static_grow_memory`
// name: ir::ExternalName::user(1, 1),
// signature,
// colocated: false,
// });
// // Create a memory index value.
// let memory_index = pos.ins().iconst(ir::types::I32, index.index() as i64);
// // Create a VMContext value.
// let vmctx = pos
// .func
// .special_param(ir::ArgumentPurpose::VMContext)
// .expect("missing vmctx parameter");
// // Insert call instructions for `grow_memory`.
// let call_inst = pos.ins().call(size_mem_func, &[memory_index, vmctx]);
// // Return value.
// Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
let signature = pos.func.import_signature(ir::Signature {
call_conv: self.target_config().default_call_conv,
params: vec![
@ -629,23 +618,27 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
let (name, mem_index) = match mem_index.local_or_import(self.env.module) {
LocalOrImport::Local(local_mem_index) => {
(
// local_static_memory_size
ir::ExternalName::user(1, 1),
local_mem_index.index(),
)
}
LocalOrImport::Import(imported_mem_index) => {
(
// imported_static_memory_size
ir::ExternalName::user(1, 3),
imported_mem_index.index(),
)
}
let (namespace, mem_index, description) = match mem_index.local_or_import(self.env.module) {
LocalOrImport::Local(local_mem_index) => (
call_names::LOCAL_NAMESPACE,
local_mem_index.index(),
self.env.module.memories[local_mem_index],
),
LocalOrImport::Import(import_mem_index) => (
call_names::IMPORT_NAMESPACE,
import_mem_index.index(),
self.env.module.imported_memories[import_mem_index].1,
),
};
let name_index = match description.memory_type() {
MemoryType::Dynamic => call_names::DYNAMIC_MEM_SIZE,
MemoryType::Static => call_names::STATIC_MEM_SIZE,
MemoryType::SharedStatic => call_names::SHARED_STATIC_MEM_SIZE,
};
let name = ir::ExternalName::user(namespace, name_index);
let mem_grow_func = pos.func.import_function(ir::ExtFuncData {
name,
signature,

View File

@ -10,7 +10,7 @@ use wasmer_runtime_core::{
structures::{Map, TypedIndex},
types::{
ElementType, Global, GlobalDesc, GlobalIndex, Initializer, LocalFuncIndex, LocalOrImport,
Memory, SigIndex, Table, Value,
MemoryDesc, SigIndex, TableDesc, Value,
},
};
@ -160,7 +160,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
fn declare_table(&mut self, table: cranelift_wasm::Table) {
use cranelift_wasm::TableElementType;
// Add table ir to the list of tables
self.module.tables.push(Table {
self.module.tables.push(TableDesc {
ty: match table.ty {
TableElementType::Func => ElementType::Anyfunc,
_ => unimplemented!(),
@ -184,7 +184,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
name: name.to_string(),
};
let imported_table = Table {
let imported_table = TableDesc {
ty: match table.ty {
TableElementType::Func => ElementType::Anyfunc,
_ => unimplemented!(),
@ -235,7 +235,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
/// Declares a memory to the environment
fn declare_memory(&mut self, memory: cranelift_wasm::Memory) {
self.module.memories.push(Memory {
self.module.memories.push(MemoryDesc {
min: memory.minimum,
max: memory.maximum,
shared: memory.shared,
@ -254,7 +254,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
name: name.to_string(),
};
let memory = Memory {
let memory = MemoryDesc {
min: memory.minimum,
max: memory.maximum,
shared: memory.shared,

View File

@ -8,6 +8,18 @@ use cranelift_codegen::ir::{self, ExternalName, LibCall, SourceLoc, TrapCode};
use hashbrown::HashMap;
use wasmer_runtime_core::{structures::TypedIndex, types::LocalFuncIndex};
pub mod call_names {
pub const LOCAL_NAMESPACE: u32 = 1;
pub const IMPORT_NAMESPACE: u32 = 2;
pub const STATIC_MEM_GROW: u32 = 0;
pub const STATIC_MEM_SIZE: u32 = 1;
pub const SHARED_STATIC_MEM_GROW: u32 = 2;
pub const SHARED_STATIC_MEM_SIZE: u32 = 3;
pub const DYNAMIC_MEM_GROW: u32 = 4;
pub const DYNAMIC_MEM_SIZE: u32 = 5;
}
#[derive(Debug, Clone)]
pub struct Relocation {
/// The relocation code.
@ -20,12 +32,22 @@ pub struct Relocation {
pub target: RelocationType,
}
#[derive(Debug, Clone, Copy)]
pub enum VmCallKind {
StaticMemoryGrow,
StaticMemorySize,
SharedStaticMemoryGrow,
SharedStaticMemorySize,
DynamicMemoryGrow,
DynamicMemorySize,
}
#[derive(Debug, Clone, Copy)]
pub enum VmCall {
LocalStaticMemoryGrow,
LocalStaticMemorySize,
ImportedStaticMemoryGrow,
ImportedStaticMemorySize,
Local(VmCallKind),
Import(VmCallKind),
}
/// Specify the type of relocation
@ -72,15 +94,31 @@ impl binemit::RelocSink for RelocSink {
target: RelocationType::Normal(LocalFuncIndex::new(index as usize)),
});
}
ExternalName::User {
namespace: 1,
index,
} => {
let target = RelocationType::VmCall(match index {
0 => VmCall::LocalStaticMemoryGrow,
1 => VmCall::LocalStaticMemorySize,
2 => VmCall::ImportedStaticMemoryGrow,
3 => VmCall::ImportedStaticMemorySize,
ExternalName::User { namespace, index } => {
use self::call_names::*;
let target = RelocationType::VmCall(match namespace {
LOCAL_NAMESPACE => VmCall::Local(match index {
STATIC_MEM_GROW => VmCallKind::StaticMemoryGrow,
STATIC_MEM_SIZE => VmCallKind::StaticMemorySize,
SHARED_STATIC_MEM_GROW => VmCallKind::SharedStaticMemoryGrow,
SHARED_STATIC_MEM_SIZE => VmCallKind::SharedStaticMemorySize,
DYNAMIC_MEM_GROW => VmCallKind::DynamicMemoryGrow,
DYNAMIC_MEM_SIZE => VmCallKind::DynamicMemorySize,
_ => unimplemented!(),
}),
IMPORT_NAMESPACE => VmCall::Import(match index {
STATIC_MEM_GROW => VmCallKind::StaticMemoryGrow,
STATIC_MEM_SIZE => VmCallKind::StaticMemorySize,
SHARED_STATIC_MEM_GROW => VmCallKind::SharedStaticMemoryGrow,
SHARED_STATIC_MEM_SIZE => VmCallKind::SharedStaticMemorySize,
DYNAMIC_MEM_GROW => VmCallKind::DynamicMemoryGrow,
DYNAMIC_MEM_SIZE => VmCallKind::DynamicMemorySize,
_ => unimplemented!(),
}),
_ => unimplemented!(),
});
self.func_relocs.push(Relocation {
@ -109,9 +147,6 @@ impl binemit::RelocSink for RelocSink {
target: relocation_type,
});
}
_ => {
unimplemented!();
}
}
}
fn reloc_jt(

View File

@ -1,7 +1,7 @@
use crate::call::HandlerData;
use crate::libcalls;
use crate::relocation::{
LocalTrapSink, Reloc, RelocSink, Relocation, RelocationType, TrapSink, VmCall,
LocalTrapSink, Reloc, RelocSink, Relocation, RelocationType, TrapSink, VmCall, VmCallKind,
};
use byteorder::{ByteOrder, LittleEndian};
use cranelift_codegen::{ir, isa, Context};
@ -133,14 +133,38 @@ impl FuncResolverBuilder {
msg: format!("unexpected intrinsic: {}", name),
})?,
RelocationType::VmCall(vmcall) => match vmcall {
VmCall::LocalStaticMemoryGrow => vmcalls::local_static_memory_grow as _,
VmCall::LocalStaticMemorySize => vmcalls::local_static_memory_size as _,
VmCall::ImportedStaticMemoryGrow => {
vmcalls::imported_static_memory_grow as _
}
VmCall::ImportedStaticMemorySize => {
vmcalls::imported_static_memory_size as _
}
VmCall::Local(kind) => match kind {
VmCallKind::StaticMemoryGrow => vmcalls::local_static_memory_grow as _,
VmCallKind::StaticMemorySize => vmcalls::local_static_memory_size as _,
VmCallKind::SharedStaticMemoryGrow => unimplemented!(),
VmCallKind::SharedStaticMemorySize => unimplemented!(),
VmCallKind::DynamicMemoryGrow => {
vmcalls::local_dynamic_memory_grow as _
}
VmCallKind::DynamicMemorySize => {
vmcalls::local_dynamic_memory_size as _
}
},
VmCall::Import(kind) => match kind {
VmCallKind::StaticMemoryGrow => {
vmcalls::imported_static_memory_grow as _
}
VmCallKind::StaticMemorySize => {
vmcalls::imported_static_memory_size as _
}
VmCallKind::SharedStaticMemoryGrow => unimplemented!(),
VmCallKind::SharedStaticMemorySize => unimplemented!(),
VmCallKind::DynamicMemoryGrow => {
vmcalls::imported_dynamic_memory_grow as _
}
VmCallKind::DynamicMemorySize => {
vmcalls::imported_dynamic_memory_size as _
}
},
},
};