mirror of
https://github.com/fluencelabs/wasmer
synced 2025-04-25 02:12:13 +00:00
Add a translation layer before import call in singlepass.
This commit is contained in:
parent
79613e42d7
commit
65962f0186
@ -209,7 +209,7 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn feed_import_function(&mut self) -> Result<(), CodegenError> {
|
||||
fn feed_import_function(&mut self, _sigindex: SigIndex) -> Result<(), CodegenError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -8984,7 +8984,7 @@ impl<'ctx> ModuleCodeGenerator<LLVMFunctionCodeGenerator<'ctx>, LLVMBackend, Cod
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn feed_import_function(&mut self) -> Result<(), CodegenError> {
|
||||
fn feed_import_function(&mut self, _sigindex: SigIndex) -> Result<(), CodegenError> {
|
||||
self.func_import_count += 1;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule,
|
||||
Ok(())
|
||||
}
|
||||
/// Adds an import function.
|
||||
fn feed_import_function(&mut self) -> Result<(), E>;
|
||||
fn feed_import_function(&mut self, _sigindex: SigIndex) -> Result<(), E>;
|
||||
/// Sets the signatures.
|
||||
fn feed_signatures(&mut self, signatures: Map<SigIndex, FuncSig>) -> Result<(), E>;
|
||||
/// Sets function signatures.
|
||||
|
@ -110,11 +110,46 @@ pub fn read_module<
|
||||
let mut namespace_builder = Some(StringTableBuilder::new());
|
||||
let mut name_builder = Some(StringTableBuilder::new());
|
||||
let mut func_count: usize = 0;
|
||||
let mut mcg_signatures_fed = false;
|
||||
let mut mcg_info_fed = false;
|
||||
|
||||
loop {
|
||||
use wasmparser::ParserState;
|
||||
let state = parser.read();
|
||||
|
||||
// Feed signature and namespace information as early as possible.
|
||||
match *state {
|
||||
ParserState::BeginFunctionBody { .. }
|
||||
| ParserState::ImportSectionEntry { .. }
|
||||
| ParserState::EndWasm => {
|
||||
if !mcg_signatures_fed {
|
||||
mcg_signatures_fed = true;
|
||||
let info_read = info.read().unwrap();
|
||||
mcg.feed_signatures(info_read.signatures.clone())
|
||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
match *state {
|
||||
ParserState::BeginFunctionBody { .. } | ParserState::EndWasm => {
|
||||
if !mcg_info_fed {
|
||||
mcg_info_fed = true;
|
||||
{
|
||||
let mut info_write = info.write().unwrap();
|
||||
info_write.namespace_table = namespace_builder.take().unwrap().finish();
|
||||
info_write.name_table = name_builder.take().unwrap().finish();
|
||||
}
|
||||
let info_read = info.read().unwrap();
|
||||
mcg.feed_function_signatures(info_read.func_assoc.clone())
|
||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||
mcg.check_precondition(&info_read)
|
||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match *state {
|
||||
ParserState::Error(ref err) => return Err(err.clone().into()),
|
||||
ParserState::TypeSectionEntry(ref ty) => {
|
||||
@ -136,7 +171,7 @@ pub fn read_module<
|
||||
let sigindex = SigIndex::new(sigindex as usize);
|
||||
info.write().unwrap().imported_functions.push(import_name);
|
||||
info.write().unwrap().func_assoc.push(sigindex);
|
||||
mcg.feed_import_function()
|
||||
mcg.feed_import_function(sigindex)
|
||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||
}
|
||||
ImportSectionEntryType::Table(table_ty) => {
|
||||
@ -218,22 +253,6 @@ pub fn read_module<
|
||||
}
|
||||
ParserState::BeginFunctionBody { range } => {
|
||||
let id = func_count;
|
||||
if !mcg_info_fed {
|
||||
mcg_info_fed = true;
|
||||
{
|
||||
let mut info_write = info.write().unwrap();
|
||||
info_write.namespace_table = namespace_builder.take().unwrap().finish();
|
||||
info_write.name_table = name_builder.take().unwrap().finish();
|
||||
}
|
||||
let info_read = info.read().unwrap();
|
||||
mcg.feed_signatures(info_read.signatures.clone())
|
||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||
mcg.feed_function_signatures(info_read.func_assoc.clone())
|
||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||
mcg.check_precondition(&info_read)
|
||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||
}
|
||||
|
||||
let fcg = mcg
|
||||
.next_function(
|
||||
Arc::clone(&info),
|
||||
@ -432,18 +451,6 @@ pub fn read_module<
|
||||
info.write().unwrap().globals.push(global_init);
|
||||
}
|
||||
ParserState::EndWasm => {
|
||||
// TODO Consolidate with BeginFunction body if possible
|
||||
if !mcg_info_fed {
|
||||
info.write().unwrap().namespace_table =
|
||||
namespace_builder.take().unwrap().finish();
|
||||
info.write().unwrap().name_table = name_builder.take().unwrap().finish();
|
||||
mcg.feed_signatures(info.read().unwrap().signatures.clone())
|
||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||
mcg.feed_function_signatures(info.read().unwrap().func_assoc.clone())
|
||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||
mcg.check_precondition(&info.read().unwrap())
|
||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||
}
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
|
@ -32,8 +32,9 @@ use wasmer_runtime_core::{
|
||||
memory::MemoryType,
|
||||
module::{ModuleInfo, ModuleInner},
|
||||
state::{
|
||||
x64::new_machine_state, x64::X64Register, FunctionStateMap, MachineState, MachineValue,
|
||||
ModuleStateMap, OffsetInfo, SuspendOffset, WasmAbstractValue,
|
||||
x64::new_machine_state, x64::X64Register, x64_decl::ArgumentRegisterAllocator,
|
||||
FunctionStateMap, MachineState, MachineValue, ModuleStateMap, OffsetInfo, SuspendOffset,
|
||||
WasmAbstractValue,
|
||||
},
|
||||
structures::{Map, TypedIndex},
|
||||
typed_func::{Trampoline, Wasm},
|
||||
@ -869,7 +870,7 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn feed_import_function(&mut self) -> Result<(), CodegenError> {
|
||||
fn feed_import_function(&mut self, sigindex: SigIndex) -> Result<(), CodegenError> {
|
||||
let labels = self.function_labels.as_mut().unwrap();
|
||||
let id = labels.len();
|
||||
|
||||
@ -880,6 +881,92 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
|
||||
a.emit_label(label);
|
||||
labels.insert(id, (label, Some(offset)));
|
||||
|
||||
// Singlepass internally treats all arguments as integers, but the standard System V calling convention requires
|
||||
// floating point arguments to be passed in XMM registers.
|
||||
//
|
||||
// FIXME: This is only a workaround. We should fix singlepass to use the standard CC.
|
||||
let sig = self
|
||||
.signatures
|
||||
.as_ref()
|
||||
.expect("signatures itself")
|
||||
.get(sigindex)
|
||||
.expect("signatures");
|
||||
// Translation is expensive, so only do it if needed.
|
||||
if sig
|
||||
.params()
|
||||
.iter()
|
||||
.find(|&&x| x == Type::F32 || x == Type::F64)
|
||||
.is_some()
|
||||
{
|
||||
let mut param_locations: Vec<Location> = vec![];
|
||||
|
||||
// Allocate stack space for arguments.
|
||||
let stack_offset: i32 = if sig.params().len() > 5 {
|
||||
5 * 8
|
||||
} else {
|
||||
(sig.params().len() as i32) * 8
|
||||
};
|
||||
if stack_offset > 0 {
|
||||
a.emit_sub(
|
||||
Size::S64,
|
||||
Location::Imm32(stack_offset as u32),
|
||||
Location::GPR(GPR::RSP),
|
||||
);
|
||||
}
|
||||
|
||||
// Store all arguments to the stack to prevent overwrite.
|
||||
for i in 0..sig.params().len() {
|
||||
let loc = match i {
|
||||
0..=4 => {
|
||||
static PARAM_REGS: &'static [GPR] =
|
||||
&[GPR::RSI, GPR::RDX, GPR::RCX, GPR::R8, GPR::R9];
|
||||
let loc = Location::Memory(GPR::RSP, (i * 8) as i32);
|
||||
a.emit_mov(Size::S64, Location::GPR(PARAM_REGS[i]), loc);
|
||||
loc
|
||||
}
|
||||
_ => Location::Memory(GPR::RSP, stack_offset + 8 + ((i - 5) * 8) as i32),
|
||||
};
|
||||
param_locations.push(loc);
|
||||
}
|
||||
|
||||
// Copy arguments.
|
||||
let mut argalloc = ArgumentRegisterAllocator::default();
|
||||
argalloc.next(Type::I32).unwrap(); // skip vm::Ctx
|
||||
let mut caller_stack_offset: i32 = 0;
|
||||
for (i, ty) in sig.params().iter().enumerate() {
|
||||
let prev_loc = param_locations[i];
|
||||
let target = match argalloc.next(*ty) {
|
||||
Some(X64Register::GPR(gpr)) => Location::GPR(gpr),
|
||||
Some(X64Register::XMM(xmm)) => Location::XMM(xmm),
|
||||
None => {
|
||||
// No register can be allocated. Put this argument on the stack.
|
||||
//
|
||||
// Since here we never use fewer registers than by the original call, on the caller's frame
|
||||
// we always have enough space to store the rearranged arguments, and the copy "backward" between different
|
||||
// slots in the caller argument region will always work.
|
||||
a.emit_mov(Size::S64, prev_loc, Location::GPR(GPR::RAX));
|
||||
a.emit_mov(
|
||||
Size::S64,
|
||||
Location::GPR(GPR::RAX),
|
||||
Location::Memory(GPR::RSP, stack_offset + 8 + caller_stack_offset),
|
||||
);
|
||||
caller_stack_offset += 8;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
a.emit_mov(Size::S64, prev_loc, target);
|
||||
}
|
||||
|
||||
// Restore stack pointer.
|
||||
if stack_offset > 0 {
|
||||
a.emit_add(
|
||||
Size::S64,
|
||||
Location::Imm32(stack_offset as u32),
|
||||
Location::GPR(GPR::RSP),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Emits a tail call trampoline that loads the address of the target import function
|
||||
// from Ctx and jumps to it.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user