Skip to content

Commit

Permalink
Merge pull request #2574 from wasmerio/feature/singlepass_windows
Browse files Browse the repository at this point in the history
Feature/singlepass windows
  • Loading branch information
syrusakbary authored Sep 23, 2021
2 parents 6ee5540 + d11ef79 commit 8f855cf
Show file tree
Hide file tree
Showing 9 changed files with 425 additions and 210 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ ifneq ($(ENABLE_SINGLEPASS), 0)
ifeq ($(ENABLE_SINGLEPASS), 1)
compilers += singlepass
# … otherwise, we try to check whether Singlepass works on this host.
else ifneq (, $(filter 1, $(IS_DARWIN) $(IS_LINUX)))
else ifneq (, $(filter 1, $(IS_DARWIN) $(IS_LINUX) $(IS_WINDOWS)))
ifeq ($(IS_AMD64), 1)
compilers += singlepass
endif
Expand Down
402 changes: 253 additions & 149 deletions lib/compiler-singlepass/src/codegen_x64.rs

Large diffs are not rendered by default.

38 changes: 26 additions & 12 deletions lib/compiler-singlepass/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ use loupe::MemoryUsage;
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
use std::sync::Arc;
use wasmer_compiler::{
Architecture, Compilation, CompileError, CompileModuleInfo, CompiledFunction, Compiler,
CompilerConfig, FunctionBinaryReader, FunctionBody, FunctionBodyData, MiddlewareBinaryReader,
ModuleMiddleware, ModuleMiddlewareChain, ModuleTranslationState, OperatingSystem, SectionIndex,
Target, TrapInformation,
Architecture, CallingConvention, Compilation, CompileError, CompileModuleInfo,
CompiledFunction, Compiler, CompilerConfig, FunctionBinaryReader, FunctionBody,
FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, ModuleMiddlewareChain,
ModuleTranslationState, OperatingSystem, SectionIndex, Target, TrapInformation,
};
use wasmer_types::entity::{EntityRef, PrimaryMap};
use wasmer_types::{
Expand Down Expand Up @@ -57,17 +57,24 @@ impl Compiler for SinglepassCompiler {
_module_translation: &ModuleTranslationState,
function_body_inputs: PrimaryMap<LocalFunctionIndex, FunctionBodyData<'_>>,
) -> Result<Compilation, CompileError> {
if target.triple().operating_system == OperatingSystem::Windows {
/*if target.triple().operating_system == OperatingSystem::Windows {
return Err(CompileError::UnsupportedTarget(
OperatingSystem::Windows.to_string(),
));
}
}*/
if let Architecture::X86_32(arch) = target.triple().architecture {
return Err(CompileError::UnsupportedTarget(arch.to_string()));
}
if compile_info.features.multi_value {
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 table_styles = &compile_info.table_styles;
let vmoffsets = VMOffsets::new(8, &compile_info.module);
Expand All @@ -77,7 +84,12 @@ impl Compiler for SinglepassCompiler {
.collect::<Vec<_>>()
.into_par_iter_if_rayon()
.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<_>>()
.into_iter()
Expand Down Expand Up @@ -133,7 +145,7 @@ impl Compiler for SinglepassCompiler {
.values()
.collect::<Vec<_>>()
.into_par_iter_if_rayon()
.map(gen_std_trampoline)
.map(|func_type| gen_std_trampoline(&func_type, calling_convention))
.collect::<Vec<_>>()
.into_iter()
.collect::<PrimaryMap<_, _>>();
Expand All @@ -142,7 +154,9 @@ impl Compiler for SinglepassCompiler {
.imported_function_types()
.collect::<Vec<_>>()
.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<_>>()
.into_iter()
.collect::<PrimaryMap<FunctionIndex, FunctionBody>>();
Expand Down Expand Up @@ -219,13 +233,13 @@ mod tests {
let compiler = SinglepassCompiler::new(Singlepass::default());

// Compile for win64
let win64 = Target::new(triple!("x86_64-pc-windows-msvc"), CpuFeature::for_host());
/*let win64 = Target::new(triple!("x86_64-pc-windows-msvc"), CpuFeature::for_host());
let (mut info, translation, inputs) = dummy_compilation_ingredients();
let result = compiler.compile_module(&win64, &mut info, &translation, inputs);
match result.unwrap_err() {
CompileError::UnsupportedTarget(name) => assert_eq!(name, "windows"),
error => panic!("Unexpected error: {:?}", error),
};
};*/

// Compile for 32bit Linux
let linux32 = Target::new(triple!("i686-unknown-linux-gnu"), CpuFeature::for_host());
Expand All @@ -241,7 +255,7 @@ mod tests {
let (mut info, translation, inputs) = dummy_compilation_ingredients();
let result = compiler.compile_module(&win32, &mut info, &translation, inputs);
match result.unwrap_err() {
CompileError::UnsupportedTarget(name) => assert_eq!(name, "windows"), // Windows should be checked before architecture
CompileError::UnsupportedTarget(name) => assert_eq!(name, "i686"), // Windows should be checked before architecture
error => panic!("Unexpected error: {:?}", error),
};
}
Expand Down
12 changes: 11 additions & 1 deletion lib/compiler-singlepass/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
use crate::compiler::SinglepassCompiler;
use loupe::MemoryUsage;
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;

#[derive(Debug, Clone, MemoryUsage)]
Expand All @@ -13,6 +15,8 @@ pub struct Singlepass {
pub(crate) enable_stack_check: bool,
/// The middleware chain.
pub(crate) middlewares: Vec<Arc<dyn ModuleMiddleware>>,
#[loupe(skip)]
pub(crate) calling_convention: CallingConvention,
}

impl Singlepass {
Expand All @@ -23,6 +27,12 @@ impl Singlepass {
enable_nan_canonicalization: true,
enable_stack_check: false,
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"),
},
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/compiler-singlepass/src/emitter_x64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1400,7 +1400,7 @@ impl Emitter for Assembler {
}

fn emit_bkpt(&mut self) {
dynasm!(self ; int 0x3);
dynasm!(self ; int3);
}

fn emit_host_redirection(&mut self, target: GPR) {
Expand Down
73 changes: 61 additions & 12 deletions lib/compiler-singlepass/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use smallvec::SmallVec;
use std::cmp;
use std::collections::HashSet;
use wasmer_compiler::wasmparser::Type as WpType;
use wasmer_compiler::CallingConvention;

const NATIVE_PAGE_SIZE: usize = 4096;

Expand Down Expand Up @@ -330,6 +331,7 @@ impl Machine {
a: &mut E,
n: usize,
n_params: usize,
calling_convention: CallingConvention,
) -> Vec<Location> {
// Determine whether a local should be allocated on the stack.
fn is_local_on_stack(idx: usize) -> bool {
Expand Down Expand Up @@ -367,6 +369,11 @@ impl Machine {
// Callee-saved R15 for vmctx.
static_area_size += 8;

// For Windows ABI, save RDI and RSI
if calling_convention == CallingConvention::WindowsFastcall {
static_area_size += 8 * 2;
}

// Total size of callee saved registers.
let callee_saved_regs_size = static_area_size;

Expand Down Expand Up @@ -411,6 +418,29 @@ impl Machine {
X64Register::GPR(GPR::R15).to_index(),
));

if calling_convention == CallingConvention::WindowsFastcall {
// Save RDI
self.stack_offset.0 += 8;
a.emit_mov(
Size::S64,
Location::GPR(GPR::RDI),
Location::Memory(GPR::RBP, -(self.stack_offset.0 as i32)),
);
self.state.stack_values.push(MachineValue::PreserveRegister(
X64Register::GPR(GPR::RDI).to_index(),
));
// Save RSI
self.stack_offset.0 += 8;
a.emit_mov(
Size::S64,
Location::GPR(GPR::RSI),
Location::Memory(GPR::RBP, -(self.stack_offset.0 as i32)),
);
self.state.stack_values.push(MachineValue::PreserveRegister(
X64Register::GPR(GPR::RSI).to_index(),
));
}

// Save the offset of register save area.
self.save_area_offset = Some(MachineStackOffset(self.stack_offset.0));

Expand All @@ -432,7 +462,7 @@ impl Machine {
// Locals are allocated on the stack from higher address to lower address,
// so we won't skip the stack guard page here.
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 {
Location::GPR(_) => {
a.emit_mov(Size::S64, loc, locations[i]);
Expand All @@ -454,7 +484,7 @@ impl Machine {
// Load vmctx into R15.
a.emit_mov(
Size::S64,
Self::get_param_location(0),
Self::get_param_location(0, calling_convention),
Location::GPR(GPR::R15),
);

Expand Down Expand Up @@ -499,7 +529,12 @@ impl Machine {
locations
}

pub fn finalize_locals<E: Emitter>(&mut self, a: &mut E, locations: &[Location]) {
pub fn finalize_locals<E: Emitter>(
&mut self,
a: &mut E,
locations: &[Location],
calling_convention: CallingConvention,
) {
// Unwind stack to the "save area".
a.emit_lea(
Size::S64,
Expand All @@ -510,6 +545,11 @@ impl Machine {
Location::GPR(GPR::RSP),
);

if calling_convention == CallingConvention::WindowsFastcall {
// Restore RSI and RDI
a.emit_pop(Size::S64, Location::GPR(GPR::RSI));
a.emit_pop(Size::S64, Location::GPR(GPR::RDI));
}
// Restore R15 used by vmctx.
a.emit_pop(Size::S64, Location::GPR(GPR::R15));

Expand All @@ -521,15 +561,24 @@ impl Machine {
}
}

pub fn get_param_location(idx: usize) -> Location {
match idx {
0 => Location::GPR(GPR::RDI),
1 => Location::GPR(GPR::RSI),
2 => Location::GPR(GPR::RDX),
3 => Location::GPR(GPR::RCX),
4 => Location::GPR(GPR::R8),
5 => Location::GPR(GPR::R9),
_ => Location::Memory(GPR::RBP, (16 + (idx - 6) * 8) as i32),
pub fn get_param_location(idx: usize, calling_convention: CallingConvention) -> Location {
match calling_convention {
CallingConvention::WindowsFastcall => match idx {
0 => Location::GPR(GPR::RCX),
1 => Location::GPR(GPR::RDX),
2 => Location::GPR(GPR::R8),
3 => Location::GPR(GPR::R9),
_ => Location::Memory(GPR::RBP, (16 + 32 + (idx - 4) * 8) as i32),
},
_ => match idx {
0 => Location::GPR(GPR::RDI),
1 => Location::GPR(GPR::RSI),
2 => Location::GPR(GPR::RDX),
3 => Location::GPR(GPR::RCX),
4 => Location::GPR(GPR::R8),
5 => Location::GPR(GPR::R9),
_ => Location::Memory(GPR::RBP, (16 + (idx - 6) * 8) as i32),
},
}
}
}
Expand Down
Loading

0 comments on commit 8f855cf

Please sign in to comment.