Implement lowered-then-lifted functions (#4327)
* Implement lowered-then-lifted functions This commit is a few features bundled into one, culminating in the implementation of lowered-then-lifted functions for the component model. It's probably not going to be used all that often but this is possible within a valid component so Wasmtime needs to do something relatively reasonable. The main things implemented in this commit are: * Component instances are now assigned a `RuntimeComponentInstanceIndex` to differentiate each one. This will be used in the future to detect fusion (one instance lowering a function from another instance). For now it's used to allocate separate `VMComponentFlags` for each internal component instance. * The `CoreExport<FuncIndex>` of lowered functions was changed to a `CoreDef` since technically a lowered function can use another lowered function as the callee. This ended up being not too difficult to plumb through as everything else was already in place. * A need arose to compile host-to-wasm trampolines which weren't already present. Currently wasm in a component is always entered through a host-to-wasm trampoline but core wasm modules are the source of all the trampolines. In the case of a lowered-then-lifted function there may not actually be any core wasm modules, so component objects now contain necessary trampolines not otherwise provided by the core wasm objects. This feature required splitting a new function into the `Compiler` trait for creating a host-to-wasm trampoline. After doing this core wasm compilation was also updated to leverage this which further enabled compiling trampolines in parallel as opposed to the previous synchronous compilation. * Review comments
This commit is contained in:
@@ -288,11 +288,19 @@ impl wasmtime_environ::Compiler for Compiler {
|
||||
}))
|
||||
}
|
||||
|
||||
fn compile_host_to_wasm_trampoline(
|
||||
&self,
|
||||
ty: &WasmFuncType,
|
||||
) -> Result<Box<dyn Any + Send>, CompileError> {
|
||||
self.host_to_wasm_trampoline(ty)
|
||||
.map(|x| Box::new(x) as Box<_>)
|
||||
}
|
||||
|
||||
fn emit_obj(
|
||||
&self,
|
||||
translation: &ModuleTranslation,
|
||||
types: &ModuleTypes,
|
||||
funcs: PrimaryMap<DefinedFuncIndex, Box<dyn Any + Send>>,
|
||||
compiled_trampolines: Vec<Box<dyn Any + Send>>,
|
||||
tunables: &Tunables,
|
||||
obj: &mut Object<'static>,
|
||||
) -> Result<(PrimaryMap<DefinedFuncIndex, FunctionInfo>, Vec<Trampoline>)> {
|
||||
@@ -300,6 +308,10 @@ impl wasmtime_environ::Compiler for Compiler {
|
||||
.into_iter()
|
||||
.map(|(_i, f)| *f.downcast().unwrap())
|
||||
.collect();
|
||||
let compiled_trampolines: Vec<CompiledFunction> = compiled_trampolines
|
||||
.into_iter()
|
||||
.map(|f| *f.downcast().unwrap())
|
||||
.collect();
|
||||
|
||||
let mut builder = ModuleTextBuilder::new(obj, &translation.module, &*self.isa);
|
||||
if self.linkopts.force_jump_veneers {
|
||||
@@ -307,11 +319,6 @@ impl wasmtime_environ::Compiler for Compiler {
|
||||
}
|
||||
let mut addrs = AddressMapSection::default();
|
||||
let mut traps = TrapEncodingBuilder::default();
|
||||
let compiled_trampolines = translation
|
||||
.exported_signatures
|
||||
.iter()
|
||||
.map(|i| self.host_to_wasm_trampoline(&types[*i]))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let mut func_starts = Vec::with_capacity(funcs.len());
|
||||
for (i, func) in funcs.iter() {
|
||||
@@ -325,6 +332,10 @@ impl wasmtime_environ::Compiler for Compiler {
|
||||
}
|
||||
|
||||
// Build trampolines for every signature that can be used by this module.
|
||||
assert_eq!(
|
||||
translation.exported_signatures.len(),
|
||||
compiled_trampolines.len()
|
||||
);
|
||||
let mut trampolines = Vec::with_capacity(translation.exported_signatures.len());
|
||||
for (i, func) in translation
|
||||
.exported_signatures
|
||||
|
||||
@@ -10,9 +10,9 @@ use object::write::Object;
|
||||
use std::any::Any;
|
||||
use wasmtime_environ::component::{
|
||||
CanonicalOptions, Component, ComponentCompiler, ComponentTypes, LowerImport, LoweredIndex,
|
||||
TrampolineInfo, VMComponentOffsets,
|
||||
LoweringInfo, VMComponentOffsets,
|
||||
};
|
||||
use wasmtime_environ::PrimaryMap;
|
||||
use wasmtime_environ::{PrimaryMap, SignatureIndex, Trampoline};
|
||||
|
||||
impl ComponentCompiler for Compiler {
|
||||
fn compile_lowered_trampoline(
|
||||
@@ -52,6 +52,7 @@ impl ComponentCompiler for Compiler {
|
||||
let mut host_sig = ir::Signature::new(crate::wasmtime_call_conv(isa));
|
||||
|
||||
let CanonicalOptions {
|
||||
instance,
|
||||
memory,
|
||||
realloc,
|
||||
post_return,
|
||||
@@ -71,6 +72,14 @@ impl ComponentCompiler for Compiler {
|
||||
i32::try_from(offsets.lowering_data(lowering.index)).unwrap(),
|
||||
));
|
||||
|
||||
// flags: *mut VMComponentFlags
|
||||
host_sig.params.push(ir::AbiParam::new(pointer_type));
|
||||
callee_args.push(
|
||||
builder
|
||||
.ins()
|
||||
.iadd_imm(vmctx, i64::from(offsets.flags(instance))),
|
||||
);
|
||||
|
||||
// memory: *mut VMMemoryDefinition
|
||||
host_sig.params.push(ir::AbiParam::new(pointer_type));
|
||||
callee_args.push(match memory {
|
||||
@@ -145,32 +154,42 @@ impl ComponentCompiler for Compiler {
|
||||
|
||||
fn emit_obj(
|
||||
&self,
|
||||
trampolines: PrimaryMap<LoweredIndex, Box<dyn Any + Send>>,
|
||||
lowerings: PrimaryMap<LoweredIndex, Box<dyn Any + Send>>,
|
||||
trampolines: Vec<(SignatureIndex, Box<dyn Any + Send>)>,
|
||||
obj: &mut Object<'static>,
|
||||
) -> Result<PrimaryMap<LoweredIndex, TrampolineInfo>> {
|
||||
let trampolines: PrimaryMap<LoweredIndex, CompiledFunction> = trampolines
|
||||
) -> Result<(PrimaryMap<LoweredIndex, LoweringInfo>, Vec<Trampoline>)> {
|
||||
let lowerings: PrimaryMap<LoweredIndex, CompiledFunction> = lowerings
|
||||
.into_iter()
|
||||
.map(|(_, f)| *f.downcast().unwrap())
|
||||
.collect();
|
||||
let trampolines: Vec<(SignatureIndex, CompiledFunction)> = trampolines
|
||||
.into_iter()
|
||||
.map(|(i, f)| (i, *f.downcast().unwrap()))
|
||||
.collect();
|
||||
|
||||
let module = Default::default();
|
||||
let mut text = ModuleTextBuilder::new(obj, &module, &*self.isa);
|
||||
let mut ret = PrimaryMap::new();
|
||||
for (idx, trampoline) in trampolines.iter() {
|
||||
for (idx, lowering) in lowerings.iter() {
|
||||
let (_symbol, range) = text.append_func(
|
||||
false,
|
||||
format!("_wasm_component_host_trampoline{}", idx.as_u32()).into_bytes(),
|
||||
&trampoline,
|
||||
format!("_wasm_component_lowering_trampoline{}", idx.as_u32()).into_bytes(),
|
||||
&lowering,
|
||||
);
|
||||
|
||||
let i = ret.push(TrampolineInfo {
|
||||
let i = ret.push(LoweringInfo {
|
||||
start: u32::try_from(range.start).unwrap(),
|
||||
length: u32::try_from(range.end - range.start).unwrap(),
|
||||
});
|
||||
assert_eq!(i, idx);
|
||||
}
|
||||
let ret_trampolines = trampolines
|
||||
.iter()
|
||||
.map(|(i, func)| text.trampoline(*i, func))
|
||||
.collect();
|
||||
|
||||
text.finish()?;
|
||||
|
||||
Ok(ret)
|
||||
Ok((ret, ret_trampolines))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user