Reverse trampoline static generation now works! 🎉

This commit is contained in:
Syrus
2020-05-14 19:28:36 -07:00
parent 33cd21b3d8
commit f38720337f
9 changed files with 112 additions and 88 deletions

View File

@@ -590,9 +590,7 @@ impl Function {
ty: ty.clone(),
func: Box::new(func),
};
let address = store
.engine()
.reverse_trampoline(&ty, func_wrapper as *const () as usize);
let address = std::ptr::null() as *const () as *const VMFunctionBody;
// let vmctx = std::ptr::null_mut() as *mut _ as *mut VMContext;
let vmctx = Box::leak(Box::new(dynamic_ctx)) as *mut _ as *mut VMContext;
let signature = store.engine().register_signature(&ty);

View File

@@ -16,7 +16,8 @@ use cranelift_codegen::{binemit, isa, Context};
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
use wasm_common::entity::PrimaryMap;
use wasm_common::{
Features, FunctionType, LocalFunctionIndex, MemoryIndex, SignatureIndex, TableIndex,
Features, FunctionIndex, FunctionType, LocalFunctionIndex, MemoryIndex, SignatureIndex,
TableIndex,
};
use wasmer_compiler::CompileError;
use wasmer_compiler::{
@@ -169,18 +170,38 @@ impl Compiler for CraneliftCompiler {
.collect::<Result<Vec<_>, CompileError>>()
}
fn compile_wasm2host_trampoline(
fn compile_wasm2host_trampolines(
&self,
signature: &FunctionType,
callee_address: usize,
) -> Result<FunctionBody, CompileError> {
let mut cx = FunctionBuilderContext::new();
make_wasm2host_trampoline(&*self.isa, &mut cx, signature, callee_address as _)
// signatures
// .par_iter()
// .map_init(FunctionBuilderContext::new, |mut cx, sig| {
// make_wasm2host_trampoline(&*self.isa, &mut cx, sig)
// })
// .collect::<Result<Vec<_>, CompileError>>()
module: &Module,
) -> Result<PrimaryMap<FunctionIndex, FunctionBody>, CompileError> {
use wasmer_runtime::VMOffsets;
let isa = self.isa();
let frontend_config = isa.frontend_config();
let offsets = VMOffsets::new(frontend_config.pointer_bytes(), module);
Ok(module
.functions
.iter()
.take(module.num_imported_funcs)
.map(|(function_index, signature)| {
let func_type = &module.signatures[*signature];
(function_index, func_type)
})
.collect::<Vec<_>>()
.par_iter()
.map_init(
FunctionBuilderContext::new,
|mut cx, (function_index, func_type)| {
make_wasm2host_trampoline(
&*self.isa,
&offsets,
&mut cx,
&function_index,
&func_type,
)
},
)
.collect::<Result<Vec<_>, CompileError>>()?
.into_iter()
.collect::<PrimaryMap<FunctionIndex, FunctionBody>>())
}
}

View File

@@ -12,31 +12,33 @@ use cranelift_codegen::print_errors::pretty_error;
use cranelift_codegen::Context;
use cranelift_codegen::{binemit, ir};
use std::cmp;
use std::convert::TryFrom;
use std::mem;
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use wasm_common::FunctionType;
use wasm_common::{FunctionIndex, FunctionType};
use wasmer_compiler::{CompileError, FunctionBody};
use wasmer_runtime::VMFunctionBody;
use wasmer_runtime::VMOffsets;
/// Create a trampoline for invoking a WebAssembly function.
pub fn make_wasm2host_trampoline(
isa: &dyn TargetIsa,
offsets: &VMOffsets,
fn_builder_ctx: &mut FunctionBuilderContext,
callee_index: &FunctionIndex,
func_type: &FunctionType,
callee_address: *const VMFunctionBody,
) -> Result<FunctionBody, CompileError> {
let pointer_type = isa.pointer_type();
let frontend_config = isa.frontend_config();
let signature = signature_to_cranelift_ir(func_type, &frontend_config);
let mut stub_sig = ir::Signature::new(frontend_config.default_call_conv);
// Add the caller/callee `vmctx` parameters.
// Add the caller `vmctx` parameter.
stub_sig.params.push(ir::AbiParam::special(
pointer_type,
ir::ArgumentPurpose::VMContext,
));
// Add the caller `vmctx` parameter.
// Add the caller/callee `vmctx` parameter.
stub_sig.params.push(ir::AbiParam::new(pointer_type));
// Add the `values_vec` parameter.
@@ -87,15 +89,14 @@ pub fn make_wasm2host_trampoline(
let new_sig = builder.import_signature(stub_sig);
let callee_value = builder.ins().iconst(pointer_type, callee_address as i64);
// let vmctx = self.vmctx(&mut pos.func);
// let base = builder.ins().global_value(pointer_type, vmctx);
// let mem_flags = ir::MemFlags::trusted();
// // Load the callee address.
// let body_offset =
// i32::try_from(self.offsets.vmctx_vmfunction_import_body(callee_index)).unwrap();
// let callee_value = builder.ins().load(pointer_type, mem_flags, base, body_offset);
let mem_flags = ir::MemFlags::trusted();
// Load the callee address.
let body_offset =
i32::try_from(offsets.vmctx_vmfunction_import_dynamic_body(*callee_index)).unwrap();
let callee_value =
builder
.ins()
.load(pointer_type, mem_flags, caller_vmctx_ptr_val, body_offset);
builder
.ins()
@@ -116,6 +117,7 @@ pub fn make_wasm2host_trampoline(
builder.finalize()
}
// println!("{:?}", context.func);
let mut code_buf = Vec::new();
let mut reloc_sink = TrampolineRelocSink {};
let mut trap_sink = binemit::NullTrapSink {};

View File

@@ -9,7 +9,9 @@ use crate::target::Target;
use crate::FunctionBodyData;
use crate::ModuleTranslationState;
use wasm_common::entity::PrimaryMap;
use wasm_common::{Features, FunctionType, LocalFunctionIndex, MemoryIndex, TableIndex};
use wasm_common::{
Features, FunctionIndex, FunctionType, LocalFunctionIndex, MemoryIndex, TableIndex,
};
use wasmer_runtime::Module;
use wasmer_runtime::{MemoryPlan, TablePlan};
use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig};
@@ -102,13 +104,8 @@ pub trait Compiler {
/// }
/// }
/// ```
fn compile_wasm2host_trampoline(
fn compile_wasm2host_trampolines(
&self,
signature: &FunctionType,
callee_address: usize,
) -> Result<FunctionBody, CompileError>;
// fn compile_wasm2host_trampolines(
// &self,
// signatures: &[FunctionType],
// ) -> Result<Vec<FunctionBody>, CompileError>;
module: &Module,
) -> Result<PrimaryMap<FunctionIndex, FunctionBody>, CompileError>;
}

View File

@@ -4,7 +4,7 @@ use crate::{CodeMemory, CompiledModule};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use wasm_common::entity::PrimaryMap;
use wasm_common::{FunctionType, LocalFunctionIndex, SignatureIndex};
use wasm_common::{FunctionIndex, FunctionType, LocalFunctionIndex, SignatureIndex};
use wasmer_compiler::{CompileError, FunctionBody};
#[cfg(feature = "compiler")]
use wasmer_compiler::{Compiler, CompilerConfig};
@@ -111,17 +111,6 @@ impl Engine for JITEngine {
self.compiler().trampoline(sig)
}
/// Retrieves the reverse trampoline
fn reverse_trampoline(
&self,
func_type: &FunctionType,
address: usize,
) -> *const VMFunctionBody {
self.compiler_mut()
.reverse_trampoline(func_type, address)
.expect("Can't construct trampoline")
}
/// Validates a WebAssembly module
fn validate(&self, binary: &[u8]) -> Result<(), CompileError> {
self.compiler().validate(binary)
@@ -223,7 +212,14 @@ impl JITEngineInner {
module: &Module,
functions: &PrimaryMap<LocalFunctionIndex, FunctionBody>,
trampolines: &PrimaryMap<SignatureIndex, FunctionBody>,
) -> Result<PrimaryMap<LocalFunctionIndex, *mut [VMFunctionBody]>, CompileError> {
reverse_trampolines: &PrimaryMap<FunctionIndex, FunctionBody>,
) -> Result<
(
PrimaryMap<LocalFunctionIndex, *mut [VMFunctionBody]>,
PrimaryMap<FunctionIndex, *const VMFunctionBody>,
),
CompileError,
> {
// Allocate all of the compiled functions into executable memory,
// copying over their contents.
let allocated_functions =
@@ -258,18 +254,10 @@ impl JITEngineInner {
unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr) };
self.trampolines.insert(index, trampoline);
}
Ok(allocated_functions)
}
/// Retrieves the reverse trampoline
fn reverse_trampoline(
&mut self,
func_type: &FunctionType,
address: usize,
) -> Result<*const VMFunctionBody, CompileError> {
let compiled_function = self
.compiler()?
.compile_wasm2host_trampoline(&func_type, address)?;
let allocated_reverse_trampolines = reverse_trampolines
.iter()
.map(|(func_index, compiled_function)| {
let ptr = self
.code_memory
.allocate_for_function(&compiled_function)
@@ -280,8 +268,11 @@ impl JITEngineInner {
))
})?
.as_ptr();
self.code_memory.publish();
Ok(ptr)
})
.collect::<Result<PrimaryMap<FunctionIndex, _>, CompileError>>()?;
Ok((allocated_functions, allocated_reverse_trampolines))
}
/// Make memory containing compiled code executable.

View File

@@ -8,8 +8,8 @@ use std::any::Any;
use std::sync::{Arc, Mutex};
use wasm_common::entity::{BoxedSlice, PrimaryMap};
use wasm_common::{
DataInitializer, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex,
TableIndex,
DataInitializer, FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer,
SignatureIndex, TableIndex,
};
use wasmer_compiler::CompileError;
#[cfg(feature = "compiler")]
@@ -30,6 +30,7 @@ pub struct CompiledModule {
serializable: SerializableModule,
finished_functions: BoxedSlice<LocalFunctionIndex, *mut [VMFunctionBody]>,
finished_reverse_trampolines: BoxedSlice<FunctionIndex, *const VMFunctionBody>,
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
frame_info_registration: Mutex<Option<Option<GlobalFrameInfoRegistration>>>,
}
@@ -82,6 +83,8 @@ impl CompiledModule {
.into_iter()
.collect::<PrimaryMap<SignatureIndex, _>>();
let reverse_trampolines = compiler.compile_wasm2host_trampolines(&translation.module)?;
let data_initializers = translation
.data_initializers
.iter()
@@ -101,6 +104,7 @@ impl CompiledModule {
function_jt_offsets: compilation.get_jt_offsets(),
function_frame_info: frame_infos,
trampolines,
reverse_trampolines,
custom_sections: compilation.get_custom_sections(),
};
let serializable = SerializableModule {
@@ -148,10 +152,11 @@ impl CompiledModule {
jit_compiler: &mut JITEngineInner,
serializable: SerializableModule,
) -> Result<Self, CompileError> {
let finished_functions = jit_compiler.allocate(
let (finished_functions, finished_reverse_trampolines) = jit_compiler.allocate(
&serializable.module,
&serializable.compilation.function_bodies,
&serializable.compilation.trampolines,
&serializable.compilation.reverse_trampolines,
)?;
link_module(
@@ -179,6 +184,7 @@ impl CompiledModule {
Ok(Self {
serializable,
finished_functions: finished_functions.into_boxed_slice(),
finished_reverse_trampolines: finished_reverse_trampolines.into_boxed_slice(),
signatures: signatures.into_boxed_slice(),
frame_info_registration: Mutex::new(None),
})
@@ -210,6 +216,7 @@ impl CompiledModule {
&self.module(),
&sig_registry,
resolver,
&self.finished_reverse_trampolines,
self.memory_plans(),
self.table_plans(),
)

View File

@@ -2,7 +2,8 @@ use serde::{Deserialize, Serialize};
use std::sync::Arc;
use wasm_common::entity::PrimaryMap;
use wasm_common::{
Features, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex, TableIndex,
Features, FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex,
TableIndex,
};
use wasmer_compiler::{FunctionBody, JumpTableOffsets, Relocation, SectionBody, SectionIndex};
use wasmer_engine::SerializableFunctionFrameInfo;
@@ -20,6 +21,7 @@ pub struct SerializableCompilation {
// format upon serialization.
pub function_frame_info: PrimaryMap<LocalFunctionIndex, SerializableFunctionFrameInfo>,
pub trampolines: PrimaryMap<SignatureIndex, FunctionBody>,
pub reverse_trampolines: PrimaryMap<FunctionIndex, FunctionBody>,
pub custom_sections: PrimaryMap<SectionIndex, SectionBody>,
}

View File

@@ -26,10 +26,6 @@ pub trait Engine {
/// Retrieves a trampoline given a signature
fn trampoline(&self, sig: VMSharedSignatureIndex) -> Option<VMTrampoline>;
/// Retrieves the reverse trampoline
fn reverse_trampoline(&self, func_type: &FunctionType, address: usize)
-> *const VMFunctionBody;
/// Validates a WebAssembly module
fn validate(&self, binary: &[u8]) -> Result<(), CompileError>;

View File

@@ -3,11 +3,11 @@
use crate::error::{ImportError, LinkError};
use more_asserts::assert_ge;
use wasm_common::entity::PrimaryMap;
use wasm_common::{ExternType, ImportIndex, MemoryIndex, TableIndex};
use wasm_common::entity::{BoxedSlice, EntityRef, PrimaryMap};
use wasm_common::{ExternType, FunctionIndex, ImportIndex, MemoryIndex, TableIndex};
use wasmer_runtime::{
Export, Imports, SignatureRegistry, VMFunctionImport, VMGlobalImport, VMMemoryImport,
VMTableImport,
Export, Imports, SignatureRegistry, VMFunctionBody, VMFunctionImport, VMGlobalImport,
VMMemoryImport, VMTableImport,
};
use wasmer_runtime::{MemoryPlan, TablePlan};
@@ -91,6 +91,7 @@ pub fn resolve_imports(
module: &Module,
signatures: &SignatureRegistry,
resolver: &dyn Resolver,
finished_reverse_trampolines: &BoxedSlice<FunctionIndex, *const VMFunctionBody>,
memory_plans: &PrimaryMap<MemoryIndex, MemoryPlan>,
_table_plans: &PrimaryMap<TableIndex, TablePlan>,
) -> Result<Imports, LinkError> {
@@ -122,8 +123,17 @@ pub fn resolve_imports(
}
match resolved {
Export::Function(ref f) => {
let address = if f.dynamic_address.is_null() {
f.address
} else {
// If this is a dynamic imported function,
// the address of the funciton is the address of the
// reverse trampoline.
let index = FunctionIndex::new(function_imports.len());
finished_reverse_trampolines[index]
};
function_imports.push(VMFunctionImport {
body: f.address,
body: address,
dynamic_body: f.dynamic_address,
vmctx: f.vmctx,
});