From 71dd73d672deb325664e3c9cd4ee7acebed5fb95 Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Mon, 28 Oct 2019 18:12:11 +0100 Subject: [PATCH] Expose some more internals publicly (#340) --- misc/wasmtime-py/src/code_memory.rs | 83 ---------------------- misc/wasmtime-py/src/import.rs | 2 +- misc/wasmtime-py/src/lib.rs | 1 - wasmtime-api/src/trampoline/code_memory.rs | 83 ---------------------- wasmtime-api/src/trampoline/func.rs | 2 +- wasmtime-api/src/trampoline/mod.rs | 1 - wasmtime-jit/src/code_memory.rs | 2 +- wasmtime-jit/src/context.rs | 18 ++++- wasmtime-jit/src/instantiate.rs | 10 +++ wasmtime-jit/src/lib.rs | 1 + 10 files changed, 30 insertions(+), 173 deletions(-) delete mode 100644 misc/wasmtime-py/src/code_memory.rs delete mode 100644 wasmtime-api/src/trampoline/code_memory.rs diff --git a/misc/wasmtime-py/src/code_memory.rs b/misc/wasmtime-py/src/code_memory.rs deleted file mode 100644 index b117f52289..0000000000 --- a/misc/wasmtime-py/src/code_memory.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! Memory management for executable code. -// Copy of wasmtime's wasmtime-jit/src/code_memory.rs - -use core::{cmp, mem}; -use region; -use std::string::String; -use std::vec::Vec; -use wasmtime_runtime::{Mmap, VMFunctionBody}; - -/// Memory manager for executable code. -pub(crate) struct CodeMemory { - current: Mmap, - mmaps: Vec, - position: usize, - published: usize, -} - -impl CodeMemory { - /// Create a new `CodeMemory` instance. - pub fn new() -> Self { - Self { - current: Mmap::new(), - mmaps: Vec::new(), - position: 0, - published: 0, - } - } - - /// Allocate `size` bytes of memory which can be made executable later by - /// calling `publish()`. Note that we allocate the memory as writeable so - /// that it can be written to and patched, though we make it readonly before - /// actually executing from it. - /// - /// TODO: Add an alignment flag. - fn allocate(&mut self, size: usize) -> Result<&mut [u8], String> { - if self.current.len() - self.position < size { - self.mmaps.push(mem::replace( - &mut self.current, - Mmap::with_at_least(cmp::max(0x10000, size))?, - )); - self.position = 0; - } - let old_position = self.position; - self.position += size; - Ok(&mut self.current.as_mut_slice()[old_position..self.position]) - } - - /// Convert mut a slice from u8 to VMFunctionBody. - fn view_as_mut_vmfunc_slice(slice: &mut [u8]) -> &mut [VMFunctionBody] { - let byte_ptr: *mut [u8] = slice; - let body_ptr = byte_ptr as *mut [VMFunctionBody]; - unsafe { &mut *body_ptr } - } - - /// Allocate enough memory to hold a copy of `slice` and copy the data into it. - /// TODO: Reorganize the code that calls this to emit code directly into the - /// mmap region rather than into a Vec that we need to copy in. - pub fn allocate_copy_of_byte_slice( - &mut self, - slice: &[u8], - ) -> Result<&mut [VMFunctionBody], String> { - let new = self.allocate(slice.len())?; - new.copy_from_slice(slice); - Ok(Self::view_as_mut_vmfunc_slice(new)) - } - - /// Make all allocated memory executable. - pub fn publish(&mut self) { - self.mmaps - .push(mem::replace(&mut self.current, Mmap::new())); - self.position = 0; - - for m in &mut self.mmaps[self.published..] { - if m.len() != 0 { - unsafe { - region::protect(m.as_mut_ptr(), m.len(), region::Protection::ReadExecute) - } - .expect("unable to make memory readonly and executable"); - } - } - self.published = self.mmaps.len(); - } -} diff --git a/misc/wasmtime-py/src/import.rs b/misc/wasmtime-py/src/import.rs index d744193247..9268bc5b07 100644 --- a/misc/wasmtime-py/src/import.rs +++ b/misc/wasmtime-py/src/import.rs @@ -5,7 +5,6 @@ extern crate alloc; use pyo3::prelude::*; use pyo3::types::{PyAny, PyDict, PyTuple}; -use crate::code_memory::CodeMemory; use crate::function::Function; use crate::memory::Memory; use crate::value::{read_value_from, write_value_to}; @@ -18,6 +17,7 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use cranelift_wasm::{DefinedFuncIndex, FuncIndex}; use target_lexicon::HOST; use wasmtime_environ::{Export, Module}; +use wasmtime_jit::CodeMemory; use wasmtime_runtime::{Imports, InstanceHandle, VMContext, VMFunctionBody}; use alloc::rc::Rc; diff --git a/misc/wasmtime-py/src/lib.rs b/misc/wasmtime-py/src/lib.rs index 69a1af5218..cbc69b81b9 100644 --- a/misc/wasmtime-py/src/lib.rs +++ b/misc/wasmtime-py/src/lib.rs @@ -11,7 +11,6 @@ use core::cell::RefCell; use std::rc::Rc; use wasmtime_interface_types::ModuleData; -mod code_memory; mod function; mod import; mod instance; diff --git a/wasmtime-api/src/trampoline/code_memory.rs b/wasmtime-api/src/trampoline/code_memory.rs deleted file mode 100644 index 87d1422944..0000000000 --- a/wasmtime-api/src/trampoline/code_memory.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! Memory management for executable code. -// Copy of wasmtime's wasmtime-jit/src/code_memory.rs - -use alloc::string::String; -use alloc::vec::Vec; -use core::{cmp, mem}; -use region; -use wasmtime_runtime::{Mmap, VMFunctionBody}; - -/// Memory manager for executable code. -pub(crate) struct CodeMemory { - current: Mmap, - mmaps: Vec, - position: usize, - published: usize, -} - -impl CodeMemory { - /// Create a new `CodeMemory` instance. - pub fn new() -> Self { - Self { - current: Mmap::new(), - mmaps: Vec::new(), - position: 0, - published: 0, - } - } - - /// Allocate `size` bytes of memory which can be made executable later by - /// calling `publish()`. Note that we allocate the memory as writeable so - /// that it can be written to and patched, though we make it readonly before - /// actually executing from it. - /// - /// TODO: Add an alignment flag. - fn allocate(&mut self, size: usize) -> Result<&mut [u8], String> { - if self.current.len() - self.position < size { - self.mmaps.push(mem::replace( - &mut self.current, - Mmap::with_at_least(cmp::max(0x10000, size))?, - )); - self.position = 0; - } - let old_position = self.position; - self.position += size; - Ok(&mut self.current.as_mut_slice()[old_position..self.position]) - } - - /// Convert mut a slice from u8 to VMFunctionBody. - fn view_as_mut_vmfunc_slice(slice: &mut [u8]) -> &mut [VMFunctionBody] { - let byte_ptr: *mut [u8] = slice; - let body_ptr = byte_ptr as *mut [VMFunctionBody]; - unsafe { &mut *body_ptr } - } - - /// Allocate enough memory to hold a copy of `slice` and copy the data into it. - /// TODO: Reorganize the code that calls this to emit code directly into the - /// mmap region rather than into a Vec that we need to copy in. - pub fn allocate_copy_of_byte_slice( - &mut self, - slice: &[u8], - ) -> Result<&mut [VMFunctionBody], String> { - let new = self.allocate(slice.len())?; - new.copy_from_slice(slice); - Ok(Self::view_as_mut_vmfunc_slice(new)) - } - - /// Make all allocated memory executable. - pub fn publish(&mut self) { - self.mmaps - .push(mem::replace(&mut self.current, Mmap::new())); - self.position = 0; - - for m in &mut self.mmaps[self.published..] { - if m.len() != 0 { - unsafe { - region::protect(m.as_mut_ptr(), m.len(), region::Protection::ReadExecute) - } - .expect("unable to make memory readonly and executable"); - } - } - self.published = self.mmaps.len(); - } -} diff --git a/wasmtime-api/src/trampoline/func.rs b/wasmtime-api/src/trampoline/func.rs index 8b87f91ae8..cc6668409f 100644 --- a/wasmtime-api/src/trampoline/func.rs +++ b/wasmtime-api/src/trampoline/func.rs @@ -1,7 +1,6 @@ //! Support for a calling of an imported function. use crate::r#ref::HostRef; -use crate::trampoline::code_memory::CodeMemory; use cranelift_codegen::ir::types; use cranelift_codegen::ir::{InstBuilder, StackSlotData, StackSlotKind, TrapCode}; use cranelift_codegen::Context; @@ -12,6 +11,7 @@ use cranelift_wasm::{DefinedFuncIndex, FuncIndex}; //use target_lexicon::HOST; use failure::Error; use wasmtime_environ::{Export, Module}; +use wasmtime_jit::CodeMemory; use wasmtime_runtime::{InstanceHandle, VMContext, VMFunctionBody}; use alloc::boxed::Box; diff --git a/wasmtime-api/src/trampoline/mod.rs b/wasmtime-api/src/trampoline/mod.rs index 23e5b799b9..7d34d4d823 100644 --- a/wasmtime-api/src/trampoline/mod.rs +++ b/wasmtime-api/src/trampoline/mod.rs @@ -1,6 +1,5 @@ //! Utility module to create trampolines in/out WebAssembly module. -mod code_memory; mod create_handle; mod func; mod global; diff --git a/wasmtime-jit/src/code_memory.rs b/wasmtime-jit/src/code_memory.rs index 48b86a6cda..4a9b3a3142 100644 --- a/wasmtime-jit/src/code_memory.rs +++ b/wasmtime-jit/src/code_memory.rs @@ -8,7 +8,7 @@ use region; use wasmtime_runtime::{Mmap, VMFunctionBody}; /// Memory manager for executable code. -pub(crate) struct CodeMemory { +pub struct CodeMemory { current: Mmap, mmaps: Vec, position: usize, diff --git a/wasmtime-jit/src/context.rs b/wasmtime-jit/src/context.rs index 8ab7454ce8..7c633ea857 100644 --- a/wasmtime-jit/src/context.rs +++ b/wasmtime-jit/src/context.rs @@ -1,8 +1,8 @@ use crate::action::{get, inspect_memory, invoke}; use crate::HashMap; use crate::{ - instantiate, ActionError, ActionOutcome, CompilationStrategy, Compiler, InstanceHandle, - Namespace, RuntimeValue, SetupError, + instantiate, ActionError, ActionOutcome, CompilationStrategy, CompiledModule, Compiler, + InstanceHandle, Namespace, RuntimeValue, SetupError, }; use alloc::boxed::Box; use alloc::rc::Rc; @@ -160,6 +160,20 @@ impl Context { Ok(instance) } + /// Compile a module. + pub fn compile_module(&mut self, data: &[u8]) -> Result { + self.validate(&data).map_err(SetupError::Validate)?; + let debug_info = self.debug_info(); + + CompiledModule::new( + &mut *self.compiler, + data, + &mut self.namespace, + Rc::clone(&self.global_exports), + debug_info, + ) + } + /// If `name` isn't None, register it for the given instance. pub fn optionally_name_instance(&mut self, name: Option, instance: InstanceHandle) { if let Some(name) = name { diff --git a/wasmtime-jit/src/instantiate.rs b/wasmtime-jit/src/instantiate.rs index 77b3e30edd..b91931750e 100644 --- a/wasmtime-jit/src/instantiate.rs +++ b/wasmtime-jit/src/instantiate.rs @@ -223,6 +223,16 @@ impl CompiledModule { Box::new(()), ) } + + /// Return a reference-counting pointer to a module. + pub fn module(&self) -> Rc { + self.module.clone() + } + + /// Return a reference to a module. + pub fn module_ref(&self) -> &Module { + &self.module + } } /// Similar to `DataInitializer`, but owns its own copy of the data rather diff --git a/wasmtime-jit/src/lib.rs b/wasmtime-jit/src/lib.rs index 7d3ab62dad..b55b2916f2 100644 --- a/wasmtime-jit/src/lib.rs +++ b/wasmtime-jit/src/lib.rs @@ -44,6 +44,7 @@ mod resolver; mod target_tunables; pub use crate::action::{ActionError, ActionOutcome, RuntimeValue}; +pub use crate::code_memory::CodeMemory; pub use crate::compiler::{CompilationStrategy, Compiler}; pub use crate::context::{Context, ContextError, Features, UnknownInstance}; pub use crate::instantiate::{instantiate, CompiledModule, SetupError};