Add a translation layer before import call in singlepass.

This commit is contained in:
losfair 2020-03-10 02:46:13 +08:00
parent 79613e42d7
commit 65962f0186
5 changed files with 129 additions and 35 deletions

View File

@ -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(())
}

View File

@ -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(())
}

View File

@ -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.

View File

@ -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;
}
_ => {}

View File

@ -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.