Implement memory.grow and memory.current (#9)

* Implement.

* Clean and doc

* Collect base addresses instead of leaking them

* Fix code for 1.25.

* Simplify $assert

* Use AbiParam::special.

* Use &mut self in base_addr
This commit is contained in:
Sergey Pepyakin
2018-08-11 15:52:43 +02:00
committed by Dan Gohman
parent 5379605737
commit e7c8d23a42
9 changed files with 210 additions and 38 deletions

View File

@@ -1,11 +1,14 @@
use cranelift_codegen::binemit::Reloc;
use cranelift_codegen::isa::TargetIsa;
use instance::Instance;
use memory::LinearMemory;
use region::protect;
use region::Protection;
use std::mem::transmute;
use std::ptr::write_unaligned;
use wasmtime_environ::{compile_module, Compilation, Module, ModuleTranslation, Relocation};
use wasmtime_environ::{
compile_module, Compilation, Module, ModuleTranslation, Relocation, RelocationTarget,
};
/// Executes a module that has been translated with the `wasmtime-environ` environment
/// implementation.
@@ -33,7 +36,12 @@ fn relocate(compilation: &mut Compilation, relocations: &[Vec<Relocation>]) {
// TODO: Support architectures other than x64, and other reloc kinds.
for (i, function_relocs) in relocations.iter().enumerate() {
for r in function_relocs {
let target_func_address: isize = compilation.functions[r.func_index].as_ptr() as isize;
let target_func_address: isize = match r.reloc_target {
RelocationTarget::UserFunc(index) => compilation.functions[index].as_ptr() as isize,
RelocationTarget::GrowMemory => grow_memory as isize,
RelocationTarget::CurrentMemory => current_memory as isize,
};
let body = &mut compilation.functions[i];
match r.reloc {
Reloc::Abs8 => unsafe {
@@ -56,16 +64,30 @@ fn relocate(compilation: &mut Compilation, relocations: &[Vec<Relocation>]) {
}
}
extern "C" fn grow_memory(size: u32, vmctx: *mut *mut u8) -> u32 {
unsafe {
let instance = (*vmctx.offset(2)) as *mut Instance;
(*instance)
.memory_mut(0)
.grow(size)
.unwrap_or(u32::max_value())
}
}
extern "C" fn current_memory(vmctx: *mut *mut u8) -> u32 {
unsafe {
let instance = (*vmctx.offset(2)) as *mut Instance;
(*instance).memory_mut(0).current_size()
}
}
/// Create the VmCtx data structure for the JIT'd code to use. This must
/// match the VmCtx layout in the environment.
fn make_vmctx(instance: &mut Instance) -> Vec<*mut u8> {
let mut memories = Vec::new();
fn make_vmctx(instance: &mut Instance, mem_base_addrs: &mut [*mut u8]) -> Vec<*mut u8> {
let mut vmctx = Vec::new();
vmctx.push(instance.globals.as_mut_ptr());
for mem in &mut instance.memories {
memories.push(mem.as_mut_ptr());
}
vmctx.push(memories.as_mut_ptr() as *mut u8);
vmctx.push(mem_base_addrs.as_mut_ptr() as *mut u8);
vmctx.push(instance as *mut Instance as *mut u8);
vmctx
}
@@ -100,7 +122,13 @@ pub fn execute(
let code_buf = &compilation.functions[start_index];
let vmctx = make_vmctx(instance);
// Collect all memory base addresses and Vec.
let mut mem_base_addrs = instance
.memories
.iter_mut()
.map(LinearMemory::base_addr)
.collect::<Vec<_>>();
let vmctx = make_vmctx(instance, &mut mem_base_addrs);
// Rather than writing inline assembly to jump to the code region, we use the fact that
// the Rust ABI for calling a function with no arguments and no return matches the one of