feat(compiler) Make CallingConvention a paramter in SinglePass

This commit is contained in:
ptitSeb
2021-09-16 11:03:39 +02:00
parent 7b27a81221
commit 2e5dae0019
5 changed files with 306 additions and 271 deletions

View File

@ -8,9 +8,9 @@ use wasmer_compiler::wasmparser::{
MemoryImmediate, Operator, Type as WpType, TypeOrFuncType as WpTypeOrFuncType, MemoryImmediate, Operator, Type as WpType, TypeOrFuncType as WpTypeOrFuncType,
}; };
use wasmer_compiler::{ use wasmer_compiler::{
CompiledFunction, CompiledFunctionFrameInfo, CustomSection, CustomSectionProtection, CallingConvention, CompiledFunction, CompiledFunctionFrameInfo, CustomSection,
FunctionBody, FunctionBodyData, InstructionAddressMap, Relocation, RelocationKind, CustomSectionProtection, FunctionBody, FunctionBodyData, InstructionAddressMap, Relocation,
RelocationTarget, SectionBody, SectionIndex, SourceLoc, TrapInformation, RelocationKind, RelocationTarget, SectionBody, SectionIndex, SourceLoc, TrapInformation,
}; };
use wasmer_types::{ use wasmer_types::{
entity::{EntityRef, PrimaryMap, SecondaryMap}, entity::{EntityRef, PrimaryMap, SecondaryMap},
@ -1010,17 +1010,18 @@ impl<'a> FuncGen<'a> {
self.machine.state.stack_values.push(content); self.machine.state.stack_values.push(content);
} }
} }
let calling_convention = self.config.calling_convention;
#[cfg(target_os = "windows")] let stack_padding: usize = match calling_convention {
let stack_padding: usize = 32; CallingConvention::WindowsFastcall => 32,
#[cfg(not(target_os = "windows"))] _ => 0,
let stack_padding: usize = 0; };
let mut stack_offset: usize = 0; let mut stack_offset: usize = 0;
// Calculate stack offset. // Calculate stack offset.
for (i, _param) in params.iter().enumerate() { for (i, _param) in params.iter().enumerate() {
if let Location::Memory(_, _) = Machine::get_param_location(1 + i) { if let Location::Memory(_, _) = Machine::get_param_location(1 + i, calling_convention) {
stack_offset += 8; stack_offset += 8;
} }
} }
@ -1043,10 +1044,9 @@ impl<'a> FuncGen<'a> {
} }
let mut call_movs: Vec<(Location, GPR)> = vec![]; let mut call_movs: Vec<(Location, GPR)> = vec![];
// Prepare register & stack parameters. // Prepare register & stack parameters.
for (i, param) in params.iter().enumerate().rev() { for (i, param) in params.iter().enumerate().rev() {
let loc = Machine::get_param_location(1 + i); let loc = Machine::get_param_location(1 + i, calling_convention);
match loc { match loc {
Location::GPR(x) => { Location::GPR(x) => {
call_movs.push((*param, x)); call_movs.push((*param, x));
@ -1144,7 +1144,7 @@ impl<'a> FuncGen<'a> {
self.assembler.emit_mov( self.assembler.emit_mov(
Size::S64, Size::S64,
Location::GPR(Machine::get_vmctx_reg()), Location::GPR(Machine::get_vmctx_reg()),
Machine::get_param_location(0), Machine::get_param_location(0, calling_convention),
); // vmctx ); // vmctx
if (self.machine.state.stack_values.len() % 2) != 1 { if (self.machine.state.stack_values.len() % 2) != 1 {
@ -1756,6 +1756,7 @@ impl<'a> FuncGen<'a> {
&mut self.assembler, &mut self.assembler,
self.local_types.len(), self.local_types.len(),
self.signature.params().len(), self.signature.params().len(),
self.config.calling_convention,
); );
// Mark vmctx register. The actual loading of the vmctx value is handled by init_local. // Mark vmctx register. The actual loading of the vmctx value is handled by init_local.
@ -5403,6 +5404,7 @@ impl<'a> FuncGen<'a> {
self.vmoffsets.vmcaller_checked_anyfunc_func_ptr() as usize; self.vmoffsets.vmcaller_checked_anyfunc_func_ptr() as usize;
let vmcaller_checked_anyfunc_vmctx = let vmcaller_checked_anyfunc_vmctx =
self.vmoffsets.vmcaller_checked_anyfunc_vmctx() as usize; self.vmoffsets.vmcaller_checked_anyfunc_vmctx() as usize;
let calling_convention = self.config.calling_convention;
self.emit_call_native( self.emit_call_native(
|this| { |this| {
@ -5423,7 +5425,7 @@ impl<'a> FuncGen<'a> {
this.assembler.emit_mov( this.assembler.emit_mov(
Size::S64, Size::S64,
Location::Memory(GPR::RAX, vmcaller_checked_anyfunc_vmctx as i32), Location::Memory(GPR::RAX, vmcaller_checked_anyfunc_vmctx as i32),
Machine::get_param_location(0), Machine::get_param_location(0, calling_convention),
); );
this.assembler.emit_call_location(Location::Memory( this.assembler.emit_call_location(Location::Memory(
@ -8802,20 +8804,23 @@ fn sort_call_movs(movs: &mut [(Location, GPR)]) {
} }
// Standard entry trampoline. // Standard entry trampoline.
pub fn gen_std_trampoline(sig: &FunctionType) -> FunctionBody { pub fn gen_std_trampoline(
sig: &FunctionType,
calling_convention: CallingConvention,
) -> FunctionBody {
let mut a = Assembler::new().unwrap(); let mut a = Assembler::new().unwrap();
// Calculate stack offset. // Calculate stack offset.
let mut stack_offset: u32 = 0; let mut stack_offset: u32 = 0;
for (i, _param) in sig.params().iter().enumerate() { for (i, _param) in sig.params().iter().enumerate() {
if let Location::Memory(_, _) = Machine::get_param_location(1 + i) { if let Location::Memory(_, _) = Machine::get_param_location(1 + i, calling_convention) {
stack_offset += 8; stack_offset += 8;
} }
} }
#[cfg(target_os = "windows")] let stack_padding: u32 = match calling_convention {
let stack_padding: u32 = 32; CallingConvention::WindowsFastcall => 32,
#[cfg(not(target_os = "windows"))] _ => 0,
let stack_padding: u32 = 0; };
// Align to 16 bytes. We push two 8-byte registers below, so here we need to ensure stack_offset % 16 == 8. // Align to 16 bytes. We push two 8-byte registers below, so here we need to ensure stack_offset % 16 == 8.
if stack_offset % 16 != 8 { if stack_offset % 16 != 8 {
@ -8836,12 +8841,12 @@ pub fn gen_std_trampoline(sig: &FunctionType) -> FunctionBody {
// Arguments // Arguments
a.emit_mov( a.emit_mov(
Size::S64, Size::S64,
Machine::get_param_location(1), Machine::get_param_location(1, calling_convention),
Location::GPR(GPR::R15), Location::GPR(GPR::R15),
); // func_ptr ); // func_ptr
a.emit_mov( a.emit_mov(
Size::S64, Size::S64,
Machine::get_param_location(2), Machine::get_param_location(2, calling_convention),
Location::GPR(GPR::R14), Location::GPR(GPR::R14),
); // args_rets ); // args_rets
@ -8851,7 +8856,7 @@ pub fn gen_std_trampoline(sig: &FunctionType) -> FunctionBody {
let mut n_stack_args: usize = 0; let mut n_stack_args: usize = 0;
for (i, _param) in sig.params().iter().enumerate() { for (i, _param) in sig.params().iter().enumerate() {
let src_loc = Location::Memory(GPR::R14, (i * 16) as _); // args_rets[i] let src_loc = Location::Memory(GPR::R14, (i * 16) as _); // args_rets[i]
let dst_loc = Machine::get_param_location(1 + i); let dst_loc = Machine::get_param_location(1 + i, calling_convention);
match dst_loc { match dst_loc {
Location::GPR(_) => { Location::GPR(_) => {
@ -8911,15 +8916,16 @@ pub fn gen_std_trampoline(sig: &FunctionType) -> FunctionBody {
pub fn gen_std_dynamic_import_trampoline( pub fn gen_std_dynamic_import_trampoline(
vmoffsets: &VMOffsets, vmoffsets: &VMOffsets,
sig: &FunctionType, sig: &FunctionType,
calling_convention: CallingConvention,
) -> FunctionBody { ) -> FunctionBody {
let mut a = Assembler::new().unwrap(); let mut a = Assembler::new().unwrap();
// Allocate argument array. // Allocate argument array.
let stack_offset: usize = 16 * std::cmp::max(sig.params().len(), sig.results().len()) + 8; // 16 bytes each + 8 bytes sysv call padding let stack_offset: usize = 16 * std::cmp::max(sig.params().len(), sig.results().len()) + 8; // 16 bytes each + 8 bytes sysv call padding
#[cfg(target_os = "windows")] let stack_padding: usize = match calling_convention {
let stack_padding: usize = 32; CallingConvention::WindowsFastcall => 32,
#[cfg(not(target_os = "windows"))] _ => 0,
let stack_padding: usize = 0; };
a.emit_sub( a.emit_sub(
Size::S64, Size::S64,
Location::Imm32((stack_offset + stack_padding) as _), Location::Imm32((stack_offset + stack_padding) as _),
@ -8929,12 +8935,12 @@ pub fn gen_std_dynamic_import_trampoline(
// Copy arguments. // Copy arguments.
if !sig.params().is_empty() { if !sig.params().is_empty() {
let mut argalloc = ArgumentRegisterAllocator::default(); let mut argalloc = ArgumentRegisterAllocator::default();
argalloc.next(Type::I64).unwrap(); // skip VMContext argalloc.next(Type::I64, calling_convention).unwrap(); // skip VMContext
let mut stack_param_count: usize = 0; let mut stack_param_count: usize = 0;
for (i, ty) in sig.params().iter().enumerate() { for (i, ty) in sig.params().iter().enumerate() {
let source_loc = match argalloc.next(*ty) { let source_loc = match argalloc.next(*ty, calling_convention) {
Some(X64Register::GPR(gpr)) => Location::GPR(gpr), Some(X64Register::GPR(gpr)) => Location::GPR(gpr),
Some(X64Register::XMM(xmm)) => Location::XMM(xmm), Some(X64Register::XMM(xmm)) => Location::XMM(xmm),
None => { None => {
@ -8965,8 +8971,9 @@ pub fn gen_std_dynamic_import_trampoline(
} }
} }
match calling_convention {
CallingConvention::WindowsFastcall => {
// Load target address. // Load target address.
#[cfg(target_os = "windows")]
a.emit_mov( a.emit_mov(
Size::S64, Size::S64,
Location::Memory( Location::Memory(
@ -8975,7 +8982,15 @@ pub fn gen_std_dynamic_import_trampoline(
), ),
Location::GPR(GPR::RAX), Location::GPR(GPR::RAX),
); );
#[cfg(target_os = "linux")] // Load values array.
a.emit_lea(
Size::S64,
Location::Memory(GPR::RSP, stack_padding as i32),
Location::GPR(GPR::RDX),
);
}
_ => {
// Load target address.
a.emit_mov( a.emit_mov(
Size::S64, Size::S64,
Location::Memory( Location::Memory(
@ -8984,16 +8999,10 @@ pub fn gen_std_dynamic_import_trampoline(
), ),
Location::GPR(GPR::RAX), Location::GPR(GPR::RAX),
); );
// Load values array. // Load values array.
#[cfg(target_os = "windows")]
a.emit_lea(
Size::S64,
Location::Memory(GPR::RSP, stack_padding as i32),
Location::GPR(GPR::RDX),
);
#[cfg(target_os = "linux")]
a.emit_mov(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RSI)); a.emit_mov(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RSI));
}
};
// Call target. // Call target.
a.emit_call_location(Location::GPR(GPR::RAX)); a.emit_call_location(Location::GPR(GPR::RAX));
@ -9029,20 +9038,26 @@ pub fn gen_import_call_trampoline(
vmoffsets: &VMOffsets, vmoffsets: &VMOffsets,
index: FunctionIndex, index: FunctionIndex,
sig: &FunctionType, sig: &FunctionType,
calling_convention: CallingConvention,
) -> CustomSection { ) -> CustomSection {
let mut a = Assembler::new().unwrap(); let mut a = Assembler::new().unwrap();
// TODO: ARM entry trampoline is not emitted. // TODO: ARM entry trampoline is not emitted.
// Singlepass internally treats all arguments as integers, but the standard Windows calling convention requires // Singlepass internally treats all arguments as integers
// For the standard Windows calling convention requires
// floating point arguments to be passed in XMM registers for the 4 first arguments only // floating point arguments to be passed in XMM registers for the 4 first arguments only
// That's the only change to do, other arguments are not to be changed // That's the only change to do, other arguments are not to be changed
#[cfg(target_os = "windows")] // For the standard System V calling convention requires
// floating point arguments to be passed in XMM registers.
// Translation is expensive, so only do it if needed.
if sig if sig
.params() .params()
.iter() .iter()
.any(|&x| x == Type::F32 || x == Type::F64) .any(|&x| x == Type::F32 || x == Type::F64)
{ {
match calling_convention {
CallingConvention::WindowsFastcall => {
let mut param_locations: Vec<Location> = vec![]; let mut param_locations: Vec<Location> = vec![];
for i in 0..sig.params().len() { for i in 0..sig.params().len() {
let loc = match i { let loc = match i {
@ -9058,26 +9073,16 @@ pub fn gen_import_call_trampoline(
let mut argalloc = ArgumentRegisterAllocator::default(); let mut argalloc = ArgumentRegisterAllocator::default();
for (i, ty) in sig.params().iter().enumerate() { for (i, ty) in sig.params().iter().enumerate() {
let prev_loc = param_locations[i]; let prev_loc = param_locations[i];
match argalloc.next(*ty) { match argalloc.next(*ty, calling_convention) {
Some(X64Register::GPR(_gpr)) => continue, Some(X64Register::GPR(_gpr)) => continue,
Some(X64Register::XMM(xmm)) => a.emit_mov(Size::S64, prev_loc, Location::XMM(xmm)), Some(X64Register::XMM(xmm)) => {
a.emit_mov(Size::S64, prev_loc, Location::XMM(xmm))
}
None => continue, None => continue,
}; };
} }
} }
_ => {
// 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.
// Translation is expensive, so only do it if needed.
#[cfg(not(target_os = "windows"))]
if sig
.params()
.iter()
.any(|&x| x == Type::F32 || x == Type::F64)
{
let mut param_locations: Vec<Location> = vec![]; let mut param_locations: Vec<Location> = vec![];
// Allocate stack space for arguments. // Allocate stack space for arguments.
@ -9098,7 +9103,8 @@ pub fn gen_import_call_trampoline(
for i in 0..sig.params().len() { for i in 0..sig.params().len() {
let loc = match i { let loc = match i {
0..=4 => { 0..=4 => {
static PARAM_REGS: &[GPR] = &[GPR::RSI, GPR::RDX, GPR::RCX, GPR::R8, GPR::R9]; static PARAM_REGS: &[GPR] =
&[GPR::RSI, GPR::RDX, GPR::RCX, GPR::R8, GPR::R9];
let loc = Location::Memory(GPR::RSP, (i * 8) as i32); let loc = Location::Memory(GPR::RSP, (i * 8) as i32);
a.emit_mov(Size::S64, Location::GPR(PARAM_REGS[i]), loc); a.emit_mov(Size::S64, Location::GPR(PARAM_REGS[i]), loc);
loc loc
@ -9110,11 +9116,11 @@ pub fn gen_import_call_trampoline(
// Copy arguments. // Copy arguments.
let mut argalloc = ArgumentRegisterAllocator::default(); let mut argalloc = ArgumentRegisterAllocator::default();
argalloc.next(Type::I64).unwrap(); // skip VMContext argalloc.next(Type::I64, calling_convention).unwrap(); // skip VMContext
let mut caller_stack_offset: i32 = 0; let mut caller_stack_offset: i32 = 0;
for (i, ty) in sig.params().iter().enumerate() { for (i, ty) in sig.params().iter().enumerate() {
let prev_loc = param_locations[i]; let prev_loc = param_locations[i];
let target = match argalloc.next(*ty) { let targ = match argalloc.next(*ty, calling_convention) {
Some(X64Register::GPR(gpr)) => Location::GPR(gpr), Some(X64Register::GPR(gpr)) => Location::GPR(gpr),
Some(X64Register::XMM(xmm)) => Location::XMM(xmm), Some(X64Register::XMM(xmm)) => Location::XMM(xmm),
None => { None => {
@ -9133,7 +9139,7 @@ pub fn gen_import_call_trampoline(
continue; continue;
} }
}; };
a.emit_mov(Size::S64, prev_loc, target); a.emit_mov(Size::S64, prev_loc, targ);
} }
// Restore stack pointer. // Restore stack pointer.
@ -9145,14 +9151,16 @@ pub fn gen_import_call_trampoline(
); );
} }
} }
}
}
// Emits a tail call trampoline that loads the address of the target import function // Emits a tail call trampoline that loads the address of the target import function
// from Ctx and jumps to it. // from Ctx and jumps to it.
let offset = vmoffsets.vmctx_vmfunction_import(index); let offset = vmoffsets.vmctx_vmfunction_import(index);
#[cfg(target_os = "windows")] match calling_convention {
{ CallingConvention::WindowsFastcall => {
a.emit_mov( a.emit_mov(
Size::S64, Size::S64,
Location::Memory(GPR::RCX, offset as i32), // function pointer Location::Memory(GPR::RCX, offset as i32), // function pointer
@ -9164,8 +9172,7 @@ pub fn gen_import_call_trampoline(
Location::GPR(GPR::RCX), Location::GPR(GPR::RCX),
); );
} }
#[cfg(not(target_os = "windows"))] _ => {
{
a.emit_mov( a.emit_mov(
Size::S64, Size::S64,
Location::Memory(GPR::RDI, offset as i32), // function pointer Location::Memory(GPR::RDI, offset as i32), // function pointer
@ -9177,6 +9184,7 @@ pub fn gen_import_call_trampoline(
Location::GPR(GPR::RDI), Location::GPR(GPR::RDI),
); );
} }
}
a.emit_host_redirection(GPR::RAX); a.emit_host_redirection(GPR::RAX);
let section_body = SectionBody::new_with_vec(a.finalize().unwrap().to_vec()); let section_body = SectionBody::new_with_vec(a.finalize().unwrap().to_vec());

View File

@ -12,10 +12,10 @@ use loupe::MemoryUsage;
use rayon::prelude::{IntoParallelIterator, ParallelIterator}; use rayon::prelude::{IntoParallelIterator, ParallelIterator};
use std::sync::Arc; use std::sync::Arc;
use wasmer_compiler::{ use wasmer_compiler::{
Architecture, Compilation, CompileError, CompileModuleInfo, CompiledFunction, Compiler, Architecture, CallingConvention, Compilation, CompileError, CompileModuleInfo,
CompilerConfig, FunctionBinaryReader, FunctionBody, FunctionBodyData, MiddlewareBinaryReader, CompiledFunction, Compiler, CompilerConfig, FunctionBinaryReader, FunctionBody,
ModuleMiddleware, ModuleMiddlewareChain, ModuleTranslationState, OperatingSystem, SectionIndex, FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, ModuleMiddlewareChain,
Target, TrapInformation, ModuleTranslationState, OperatingSystem, SectionIndex, Target, TrapInformation,
}; };
use wasmer_types::entity::{EntityRef, PrimaryMap}; use wasmer_types::entity::{EntityRef, PrimaryMap};
use wasmer_types::{ use wasmer_types::{
@ -68,6 +68,13 @@ impl Compiler for SinglepassCompiler {
if compile_info.features.multi_value { if compile_info.features.multi_value {
return Err(CompileError::UnsupportedFeature("multivalue".to_string())); return Err(CompileError::UnsupportedFeature("multivalue".to_string()));
} }
let calling_convention = match target.triple().default_calling_convention() {
Ok(CallingConvention::WindowsFastcall) => CallingConvention::WindowsFastcall,
Ok(CallingConvention::SystemV) => CallingConvention::SystemV,
//Ok(CallingConvention::AppleAarch64) => AppleAarch64,
_ => panic!("Unsupported Calling convention for Singlepass compiler"),
};
let memory_styles = &compile_info.memory_styles; let memory_styles = &compile_info.memory_styles;
let table_styles = &compile_info.table_styles; let table_styles = &compile_info.table_styles;
let vmoffsets = VMOffsets::new(8, &compile_info.module); let vmoffsets = VMOffsets::new(8, &compile_info.module);
@ -77,7 +84,12 @@ impl Compiler for SinglepassCompiler {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_par_iter_if_rayon() .into_par_iter_if_rayon()
.map(|i| { .map(|i| {
gen_import_call_trampoline(&vmoffsets, i, &module.signatures[module.functions[i]]) gen_import_call_trampoline(
&vmoffsets,
i,
&module.signatures[module.functions[i]],
calling_convention,
)
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_iter() .into_iter()
@ -133,7 +145,7 @@ impl Compiler for SinglepassCompiler {
.values() .values()
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_par_iter_if_rayon() .into_par_iter_if_rayon()
.map(gen_std_trampoline) .map(|func_type| gen_std_trampoline(&func_type, calling_convention))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_iter() .into_iter()
.collect::<PrimaryMap<_, _>>(); .collect::<PrimaryMap<_, _>>();
@ -142,7 +154,9 @@ impl Compiler for SinglepassCompiler {
.imported_function_types() .imported_function_types()
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_par_iter_if_rayon() .into_par_iter_if_rayon()
.map(|func_type| gen_std_dynamic_import_trampoline(&vmoffsets, &func_type)) .map(|func_type| {
gen_std_dynamic_import_trampoline(&vmoffsets, &func_type, calling_convention)
})
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_iter() .into_iter()
.collect::<PrimaryMap<FunctionIndex, FunctionBody>>(); .collect::<PrimaryMap<FunctionIndex, FunctionBody>>();

View File

@ -4,7 +4,9 @@
use crate::compiler::SinglepassCompiler; use crate::compiler::SinglepassCompiler;
use loupe::MemoryUsage; use loupe::MemoryUsage;
use std::sync::Arc; use std::sync::Arc;
use wasmer_compiler::{Compiler, CompilerConfig, CpuFeature, ModuleMiddleware, Target}; use wasmer_compiler::{
CallingConvention, Compiler, CompilerConfig, CpuFeature, ModuleMiddleware, Target,
};
use wasmer_types::Features; use wasmer_types::Features;
#[derive(Debug, Clone, MemoryUsage)] #[derive(Debug, Clone, MemoryUsage)]
@ -13,6 +15,8 @@ pub struct Singlepass {
pub(crate) enable_stack_check: bool, pub(crate) enable_stack_check: bool,
/// The middleware chain. /// The middleware chain.
pub(crate) middlewares: Vec<Arc<dyn ModuleMiddleware>>, pub(crate) middlewares: Vec<Arc<dyn ModuleMiddleware>>,
#[loupe(skip)]
pub(crate) calling_convention: CallingConvention,
} }
impl Singlepass { impl Singlepass {
@ -23,6 +27,12 @@ impl Singlepass {
enable_nan_canonicalization: true, enable_nan_canonicalization: true,
enable_stack_check: false, enable_stack_check: false,
middlewares: vec![], middlewares: vec![],
calling_convention: match Target::default().triple().default_calling_convention() {
Ok(CallingConvention::WindowsFastcall) => CallingConvention::WindowsFastcall,
Ok(CallingConvention::SystemV) => CallingConvention::SystemV,
//Ok(CallingConvention::AppleAarch64) => AppleAarch64,
_ => panic!("Unsupported Calling convention for Singlepass"),
},
} }
} }

View File

@ -6,6 +6,7 @@ use smallvec::SmallVec;
use std::cmp; use std::cmp;
use std::collections::HashSet; use std::collections::HashSet;
use wasmer_compiler::wasmparser::Type as WpType; use wasmer_compiler::wasmparser::Type as WpType;
use wasmer_compiler::{CallingConvention, Target};
const NATIVE_PAGE_SIZE: usize = 4096; const NATIVE_PAGE_SIZE: usize = 4096;
@ -330,6 +331,7 @@ impl Machine {
a: &mut E, a: &mut E,
n: usize, n: usize,
n_params: usize, n_params: usize,
calling_convention: CallingConvention,
) -> Vec<Location> { ) -> Vec<Location> {
// Determine whether a local should be allocated on the stack. // Determine whether a local should be allocated on the stack.
fn is_local_on_stack(idx: usize) -> bool { fn is_local_on_stack(idx: usize) -> bool {
@ -432,7 +434,7 @@ impl Machine {
// Locals are allocated on the stack from higher address to lower address, // Locals are allocated on the stack from higher address to lower address,
// so we won't skip the stack guard page here. // so we won't skip the stack guard page here.
for i in 0..n_params { for i in 0..n_params {
let loc = Self::get_param_location(i + 1); let loc = Self::get_param_location(i + 1, calling_convention);
match loc { match loc {
Location::GPR(_) => { Location::GPR(_) => {
a.emit_mov(Size::S64, loc, locations[i]); a.emit_mov(Size::S64, loc, locations[i]);
@ -454,7 +456,7 @@ impl Machine {
// Load vmctx into R15. // Load vmctx into R15.
a.emit_mov( a.emit_mov(
Size::S64, Size::S64,
Self::get_param_location(0), Self::get_param_location(0, calling_convention),
Location::GPR(GPR::R15), Location::GPR(GPR::R15),
); );
@ -521,19 +523,16 @@ impl Machine {
} }
} }
#[cfg(target_os = "windows")] pub fn get_param_location(idx: usize, calling_convention: CallingConvention) -> Location {
pub fn get_param_location(idx: usize) -> Location { match calling_convention {
match idx { CallingConvention::WindowsFastcall => match idx {
0 => Location::GPR(GPR::RCX), 0 => Location::GPR(GPR::RCX),
1 => Location::GPR(GPR::RDX), 1 => Location::GPR(GPR::RDX),
2 => Location::GPR(GPR::R8), 2 => Location::GPR(GPR::R8),
3 => Location::GPR(GPR::R9), 3 => Location::GPR(GPR::R9),
_ => Location::Memory(GPR::RBP, (16 + 32 + (idx - 4) * 8) as i32), _ => Location::Memory(GPR::RBP, (16 + 32 + (idx - 4) * 8) as i32),
} },
} _ => match idx {
#[cfg(not(target_os = "windows"))]
pub fn get_param_location(idx: usize) -> Location {
match idx {
0 => Location::GPR(GPR::RDI), 0 => Location::GPR(GPR::RDI),
1 => Location::GPR(GPR::RSI), 1 => Location::GPR(GPR::RSI),
2 => Location::GPR(GPR::RDX), 2 => Location::GPR(GPR::RDX),
@ -541,6 +540,7 @@ impl Machine {
4 => Location::GPR(GPR::R8), 4 => Location::GPR(GPR::R8),
5 => Location::GPR(GPR::R9), 5 => Location::GPR(GPR::R9),
_ => Location::Memory(GPR::RBP, (16 + (idx - 6) * 8) as i32), _ => Location::Memory(GPR::RBP, (16 + (idx - 6) * 8) as i32),
},
} }
} }
} }

View File

@ -2,6 +2,7 @@
use crate::common_decl::{MachineState, MachineValue, RegisterIndex}; use crate::common_decl::{MachineState, MachineValue, RegisterIndex};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use wasmer_compiler::{CallingConvention, Target};
use wasmer_types::Type; use wasmer_types::Type;
/// General-purpose registers. /// General-purpose registers.
@ -170,8 +171,9 @@ pub struct ArgumentRegisterAllocator {
impl ArgumentRegisterAllocator { impl ArgumentRegisterAllocator {
/// Allocates a register for argument type `ty`. Returns `None` if no register is available for this type. /// Allocates a register for argument type `ty`. Returns `None` if no register is available for this type.
#[cfg(target_os = "windows")] pub fn next(&mut self, ty: Type, calling_convention: CallingConvention) -> Option<X64Register> {
pub fn next(&mut self, ty: Type) -> Option<X64Register> { match calling_convention {
CallingConvention::WindowsFastcall => {
static GPR_SEQ: &'static [GPR] = &[GPR::RCX, GPR::RDX, GPR::R8, GPR::R9]; static GPR_SEQ: &'static [GPR] = &[GPR::RCX, GPR::RDX, GPR::R8, GPR::R9];
static XMM_SEQ: &'static [XMM] = &[XMM::XMM0, XMM::XMM1, XMM::XMM2, XMM::XMM3]; static XMM_SEQ: &'static [XMM] = &[XMM::XMM0, XMM::XMM1, XMM::XMM2, XMM::XMM3];
let idx = self.n_gprs + self.n_xmms; let idx = self.n_gprs + self.n_xmms;
@ -200,8 +202,7 @@ impl ArgumentRegisterAllocator {
), ),
} }
} }
#[cfg(not(target_os = "windows"))] _ => {
pub fn next(&mut self, ty: Type) -> Option<X64Register> {
static GPR_SEQ: &'static [GPR] = static GPR_SEQ: &'static [GPR] =
&[GPR::RDI, GPR::RSI, GPR::RDX, GPR::RCX, GPR::R8, GPR::R9]; &[GPR::RDI, GPR::RSI, GPR::RDX, GPR::RCX, GPR::R8, GPR::R9];
static XMM_SEQ: &'static [XMM] = &[ static XMM_SEQ: &'static [XMM] = &[
@ -240,6 +241,8 @@ impl ArgumentRegisterAllocator {
} }
} }
} }
}
}
/// Create a new `MachineState` with default values. /// Create a new `MachineState` with default values.
pub fn new_machine_state() -> MachineState { pub fn new_machine_state() -> MachineState {