diff --git a/lib/execute/src/lib.rs b/lib/execute/src/lib.rs index e9ba6f6640..72657df20e 100644 --- a/lib/execute/src/lib.rs +++ b/lib/execute/src/lib.rs @@ -13,10 +13,10 @@ use region::protect; use region::Protection; use std::mem::transmute; use std::ptr::write_unaligned; -use wasmtime_runtime::{Compilation, Relocation}; +use wasmtime_runtime::{Compilation, Relocation, compile_module}; /// Executes a module that has been translated with the `standalone::Runtime` runtime implementation. -pub fn compile_module<'data, 'module>( +pub fn compile_and_link_module<'data, 'module>( isa: &TargetIsa, translation: &wasmtime_runtime::ModuleTranslation<'data, 'module>, ) -> Result, String> { @@ -26,7 +26,7 @@ pub fn compile_module<'data, 'module>( "imported start functions not supported yet" ); - let (mut compilation, relocations) = translation.compile(isa)?; + let (mut compilation, relocations) = compile_module(&translation, isa)?; // Apply relocations, now that we have virtual addresses for everything. relocate(&mut compilation, &relocations); diff --git a/lib/runtime/src/compilation.rs b/lib/runtime/src/compilation.rs index 6fd4a578d9..12687b1d5d 100644 --- a/lib/runtime/src/compilation.rs +++ b/lib/runtime/src/compilation.rs @@ -1,6 +1,13 @@ //! A `Compilation` contains the compiled function bodies for a WebAssembly //! module. +use cranelift_codegen::binemit; +use cranelift_codegen::ir; +use cranelift_codegen::ir::ExternalName; +use cranelift_codegen::isa; +use cranelift_codegen::Context; +use cranelift_wasm::{FuncTranslator, FunctionIndex}; +use environ::{get_func_name, ModuleTranslation}; use module::Module; /// An Instance of a WebAssemby module. @@ -19,3 +26,106 @@ impl<'module> Compilation<'module> { Self { module, functions } } } + +/// Implementation of a relocation sink that just saves all the information for later +pub struct RelocSink { + /// Relocations recorded for the function. + pub func_relocs: Vec, +} + +impl binemit::RelocSink for RelocSink { + fn reloc_ebb( + &mut self, + _offset: binemit::CodeOffset, + _reloc: binemit::Reloc, + _ebb_offset: binemit::CodeOffset, + ) { + // This should use the `offsets` field of `ir::Function`. + panic!("ebb headers not yet implemented"); + } + fn reloc_external( + &mut self, + offset: binemit::CodeOffset, + reloc: binemit::Reloc, + name: &ExternalName, + addend: binemit::Addend, + ) { + // FIXME: Handle grow_memory/current_memory. + let func_index = if let ExternalName::User { namespace, index } = *name { + debug_assert!(namespace == 0); + index + } else { + panic!("unrecognized external name") + } as usize; + self.func_relocs.push(Relocation { + reloc, + func_index, + offset, + addend, + }); + } + fn reloc_jt( + &mut self, + _offset: binemit::CodeOffset, + _reloc: binemit::Reloc, + _jt: ir::JumpTable, + ) { + panic!("jump tables not yet implemented"); + } +} + +impl RelocSink { + fn new() -> RelocSink { + RelocSink { + func_relocs: Vec::new(), + } + } +} + +/// A record of a relocation to perform. +#[derive(Debug)] +pub struct Relocation { + /// The relocation code. + pub reloc: binemit::Reloc, + /// The function index. + pub func_index: FunctionIndex, + /// The offset where to apply the relocation. + pub offset: binemit::CodeOffset, + /// The addend to add to the relocation value. + pub addend: binemit::Addend, +} + +/// Relocations to apply to function bodies. +pub type Relocations = Vec>; + +/// Compile the module, producing a compilation result with associated +/// relocations. +pub fn compile_module<'data, 'module>( + translation: &ModuleTranslation<'data, 'module>, + isa: &isa::TargetIsa, +) -> Result<(Compilation<'module>, Relocations), String> { + let mut functions = Vec::new(); + let mut relocations = Vec::new(); + for (i, input) in translation.lazy.function_body_inputs.iter().enumerate() { + let func_index = i + translation.module.imported_funcs.len(); + let mut context = Context::new(); + context.func.name = get_func_name(func_index); + context.func.signature = + translation.module.signatures[translation.module.functions[func_index]].clone(); + + let mut trans = FuncTranslator::new(); + trans + .translate(input, &mut context.func, &mut translation.func_env()) + .map_err(|e| e.to_string())?; + + let mut code_buf: Vec = Vec::new(); + let mut reloc_sink = RelocSink::new(); + let mut trap_sink = binemit::NullTrapSink {}; + context + .compile_and_emit(isa, &mut code_buf, &mut reloc_sink, &mut trap_sink) + .map_err(|e| e.to_string())?; + functions.push(code_buf); + relocations.push(reloc_sink.func_relocs); + } + Ok((Compilation::new(translation.module, functions), relocations)) +} diff --git a/lib/runtime/src/environ.rs b/lib/runtime/src/environ.rs index 9c928be41c..4895f5f86e 100644 --- a/lib/runtime/src/environ.rs +++ b/lib/runtime/src/environ.rs @@ -16,7 +16,6 @@ use cranelift_wasm::{ use module; use module::Module; use target_lexicon::Triple; -use ModuleTranslation; /// Compute a `ir::ExternalName` for a given wasm function index. pub fn get_func_name(func_index: FunctionIndex) -> ir::ExternalName { @@ -458,3 +457,23 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap()) } } + +/// The result of translating via `ModuleEnvironment`. +pub struct ModuleTranslation<'data, 'module> { + /// Compilation setting flags. + pub isa: &'module isa::TargetIsa, + + /// Module information. + pub module: &'module Module, + + /// Pointers into the raw data buffer. + pub lazy: LazyContents<'data>, +} + +/// Convenience functions for the user to be called after execution for debug purposes. +impl<'data, 'module> ModuleTranslation<'data, 'module> { + /// Return a new `FuncEnvironment` for translation a function. + pub fn func_env(&self) -> FuncEnvironment { + FuncEnvironment::new(self.isa, &self.module) + } +} diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 1699bcde0a..aec78f8b45 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -14,148 +14,7 @@ mod environ; mod instance; mod module; -pub use compilation::Compilation; -pub use environ::ModuleEnvironment; +pub use compilation::{Compilation, compile_module, Relocation, Relocations}; +pub use environ::{ModuleEnvironment, ModuleTranslation}; pub use instance::Instance; pub use module::Module; - -use cranelift_codegen::binemit; -use cranelift_codegen::ir; -use cranelift_codegen::ir::ExternalName; -use cranelift_codegen::isa; -use cranelift_wasm::{FuncTranslator, FunctionIndex, GlobalIndex, MemoryIndex, TableIndex}; -use environ::{FuncEnvironment, LazyContents, get_func_name}; - -/// An entity to export. -pub enum Export { - /// Function export. - Function(FunctionIndex), - /// Table export. - Table(TableIndex), - /// Memory export. - Memory(MemoryIndex), - /// Global export. - Global(GlobalIndex), -} - -/// Implementation of a relocation sink that just saves all the information for later -pub struct RelocSink { - /// Relocations recorded for the function. - pub func_relocs: Vec, -} - -impl binemit::RelocSink for RelocSink { - fn reloc_ebb( - &mut self, - _offset: binemit::CodeOffset, - _reloc: binemit::Reloc, - _ebb_offset: binemit::CodeOffset, - ) { - // This should use the `offsets` field of `ir::Function`. - panic!("ebb headers not yet implemented"); - } - fn reloc_external( - &mut self, - offset: binemit::CodeOffset, - reloc: binemit::Reloc, - name: &ExternalName, - addend: binemit::Addend, - ) { - // FIXME: Handle grow_memory/current_memory. - let func_index = if let ExternalName::User { namespace, index } = *name { - debug_assert!(namespace == 0); - index - } else { - panic!("unrecognized external name") - } as usize; - self.func_relocs.push(Relocation { - reloc, - func_index, - offset, - addend, - }); - } - fn reloc_jt( - &mut self, - _offset: binemit::CodeOffset, - _reloc: binemit::Reloc, - _jt: ir::JumpTable, - ) { - panic!("jump tables not yet implemented"); - } -} - -impl RelocSink { - fn new() -> RelocSink { - RelocSink { - func_relocs: Vec::new(), - } - } -} - -/// A record of a relocation to perform. -#[derive(Debug)] -pub struct Relocation { - /// The relocation code. - pub reloc: binemit::Reloc, - /// The function index. - pub func_index: FunctionIndex, - /// The offset where to apply the relocation. - pub offset: binemit::CodeOffset, - /// The addend to add to the relocation value. - pub addend: binemit::Addend, -} - -/// Relocations to apply to function bodies. -pub type Relocations = Vec>; - -/// The result of translating via `ModuleEnvironment`. -pub struct ModuleTranslation<'data, 'module> { - /// Compilation setting flags. - pub isa: &'module isa::TargetIsa, - - /// Module information. - pub module: &'module Module, - - /// Pointers into the raw data buffer. - pub lazy: LazyContents<'data>, -} - -/// Convenience functions for the user to be called after execution for debug purposes. -impl<'data, 'module> ModuleTranslation<'data, 'module> { - fn func_env(&self) -> FuncEnvironment { - FuncEnvironment::new(self.isa, &self.module) - } - - /// Compile the module, producing a compilation result with associated - /// relocations. - pub fn compile( - &self, - isa: &isa::TargetIsa, - ) -> Result<(Compilation<'module>, Relocations), String> { - let mut functions = Vec::new(); - let mut relocations = Vec::new(); - for (i, input) in self.lazy.function_body_inputs.iter().enumerate() { - let func_index = i + self.module.imported_funcs.len(); - let mut context = cranelift_codegen::Context::new(); - context.func.name = get_func_name(func_index); - context.func.signature = - self.module.signatures[self.module.functions[func_index]].clone(); - - let mut trans = FuncTranslator::new(); - trans - .translate(input, &mut context.func, &mut self.func_env()) - .map_err(|e| e.to_string())?; - - let mut code_buf: Vec = Vec::new(); - let mut reloc_sink = RelocSink::new(); - let mut trap_sink = binemit::NullTrapSink {}; - context - .compile_and_emit(isa, &mut code_buf, &mut reloc_sink, &mut trap_sink) - .map_err(|e| e.to_string())?; - functions.push(code_buf); - relocations.push(reloc_sink.func_relocs); - } - Ok((Compilation::new(self.module, functions), relocations)) - } -} diff --git a/lib/runtime/src/module.rs b/lib/runtime/src/module.rs index cc0d4fc62d..9c7bfbc725 100644 --- a/lib/runtime/src/module.rs +++ b/lib/runtime/src/module.rs @@ -1,5 +1,5 @@ //! A `Module` contains all the relevant information translated from a -//! WebAssembly module. +//! WebAssembly module, except for the function bodies and data initializers. use cranelift_codegen::ir; use cranelift_wasm::{ diff --git a/src/main.rs b/src/main.rs index faca992fff..f82ce4d223 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,7 +29,7 @@ use std::path::Path; use std::path::PathBuf; use std::process::{exit, Command}; use tempdir::TempDir; -use wasmtime_execute::{compile_module, execute}; +use wasmtime_execute::{compile_and_link_module, execute}; use wasmtime_runtime::{Instance, Module, ModuleEnvironment}; const USAGE: &str = " @@ -122,7 +122,7 @@ fn handle_module(args: &Args, path: PathBuf, isa: &TargetIsa) -> Result<(), Stri let mut environ = ModuleEnvironment::new(isa, &mut module); translate_module(&data, &mut environ).map_err(|e| e.to_string())?; let translation = environ.finish_translation(); - let instance = match compile_module(isa, &translation) { + let instance = match compile_and_link_module(isa, &translation) { Ok(compilation) => { let mut instance = Instance::new(compilation.module, &translation.lazy.data_initializers); diff --git a/src/wasm2obj.rs b/src/wasm2obj.rs index 2cda07662c..25856058ba 100644 --- a/src/wasm2obj.rs +++ b/src/wasm2obj.rs @@ -27,6 +27,7 @@ use std::path::Path; use std::path::PathBuf; use std::process; use wasmtime_obj::emit_module; +use wasmtime_runtime::compile_module; const USAGE: &str = " Wasm to native object translation utility. @@ -105,7 +106,7 @@ fn handle_module(path: PathBuf, output: &str) -> Result<(), String> { let translation = environ.finish_translation(); - let (compilation, relocations) = translation.compile(&*isa)?; + let (compilation, relocations) = compile_module(&translation, &*isa)?; emit_module(&mut obj, &compilation, &relocations)?;