Calling conventions, value stack, and runtime stack layout.

This commit is contained in:
losfair 2019-02-12 23:15:57 +08:00
parent 2fbb5e3332
commit 4ebb22f8bc
5 changed files with 215 additions and 26 deletions

View File

@ -7,6 +7,7 @@ pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator> {
pub trait FunctionCodeGenerator {
fn feed_param(&mut self, ty: WpType) -> Result<(), CodegenError>;
fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError>;
fn begin_body(&mut self) -> Result<(), CodegenError>;
fn feed_opcode(&mut self, op: Operator) -> Result<(), CodegenError>;
fn finalize(&mut self) -> Result<(), CodegenError>;
}

View File

@ -1,5 +1,6 @@
use super::codegen::*;
use dynasmrt::{x64::Assembler, DynasmApi};
use super::stack::ValueStack;
use dynasmrt::{x64::Assembler, DynamicLabel, DynasmApi, DynasmLabelApi};
use wasmparser::{Operator, Type as WpType};
#[derive(Default)]
@ -8,11 +9,18 @@ pub struct X64ModuleCodeGenerator {
}
pub struct X64FunctionCode {
id: usize,
begin_label: DynamicLabel,
cleanup_label: DynamicLabel,
assembler: Option<Assembler>,
locals: Vec<Local>,
num_params: usize,
current_stack_offset: usize,
callee_managed_stack_offset: usize,
value_stack: ValueStack,
}
#[derive(Copy, Clone, Debug)]
struct Local {
ty: WpType,
stack_offset: usize,
@ -26,20 +34,32 @@ impl X64ModuleCodeGenerator {
impl ModuleCodeGenerator<X64FunctionCode> for X64ModuleCodeGenerator {
fn next_function(&mut self) -> Result<&mut X64FunctionCode, CodegenError> {
let mut assembler = match self.functions.last_mut() {
Some(x) => x.assembler.take().unwrap(),
None => match Assembler::new() {
Ok(x) => x,
Err(_) => {
return Err(CodegenError {
message: "cannot initialize assembler",
})
}
},
};
let begin_label = assembler.new_dynamic_label();
dynasm!(
assembler
; => begin_label
);
let code = X64FunctionCode {
assembler: Some(match self.functions.last_mut() {
Some(x) => x.assembler.take().unwrap(),
None => match Assembler::new() {
Ok(x) => x,
Err(_) => {
return Err(CodegenError {
message: "cannot initialize assembler",
})
}
},
}),
id: self.functions.len(),
begin_label: begin_label,
cleanup_label: assembler.new_dynamic_label(),
assembler: Some(assembler),
locals: vec![],
num_params: 0,
current_stack_offset: 0,
callee_managed_stack_offset: 0,
value_stack: ValueStack::new(13),
};
self.functions.push(code);
Ok(self.functions.last_mut().unwrap())
@ -49,41 +69,98 @@ impl ModuleCodeGenerator<X64FunctionCode> for X64ModuleCodeGenerator {
impl FunctionCodeGenerator for X64FunctionCode {
fn feed_param(&mut self, ty: WpType) -> Result<(), CodegenError> {
let size = get_size_of_type(&ty)?;
self.current_stack_offset -= size;
self.current_stack_offset += size;
self.locals.push(Local {
ty: ty,
stack_offset: self.current_stack_offset,
});
// TODO: load parameter values onto stack...
self.num_params += 1;
Ok(())
}
fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError> {
let size = get_size_of_type(&ty)?;
let assembler = self.assembler.as_mut().unwrap();
dynasm!(
assembler
; xor rax, rax
);
for _ in 0..n {
// FIXME: check range of n
self.current_stack_offset -= size;
self.current_stack_offset += size;
self.callee_managed_stack_offset += size;
self.locals.push(Local {
ty: ty,
stack_offset: self.current_stack_offset,
});
dynasm!(
assembler
; mov [rsp - (self.current_stack_offset as i32)], rax
);
}
Ok(())
}
fn begin_body(&mut self) -> Result<(), CodegenError> {
let assembler = self.assembler.as_mut().unwrap();
dynasm!(
assembler
; mov rax, rsp
; sub rsp, self.callee_managed_stack_offset as i32
; xor rcx, rcx
);
for local in &self.locals[self.num_params..] {
let size = get_size_of_type(&local.ty)?;
dynasm!(
assembler
; sub rax, size as i32
);
if size == 4 {
dynasm!(
assembler
; mov [rax], ecx
);
} else if size == 8 {
dynasm!(
assembler
; mov [rax], rcx
);
} else {
return Err(CodegenError {
message: "unsupported size for type",
});
}
}
dynasm!(
assembler
; push rbp
; mov rbp, rsp
);
Ok(())
}
fn feed_opcode(&mut self, op: Operator) -> Result<(), CodegenError> {
let assembler = self.assembler.as_mut().unwrap();
match op {
Operator::GetLocal { local_index } => {
let local_index = local_index as usize;
if local_index >= self.locals.len() {
return Err(CodegenError {
message: "local out of bounds",
});
}
let local = self.locals[local_index];
dynasm!(
assembler
; mov rax, rbp
; add rax, (self.current_stack_offset - local.stack_offset) as i32
// TODO: How should we dynamically specify a register?
);
}
_ => unimplemented!(),
}
Ok(())
}
fn finalize(&mut self) -> Result<(), CodegenError> {
let assembler = self.assembler.as_mut().unwrap();
dynasm!(
assembler
; ud2
; => self.cleanup_label
; mov rsp, rbp
; pop rbp
; add rsp, self.current_stack_offset as i32
; ret
);
Ok(())
}
}

View File

@ -9,3 +9,4 @@ extern crate dynasm;
mod codegen;
mod codegen_x64;
mod parse;
mod stack;

View File

@ -281,6 +281,7 @@ pub fn read_module<MCG: ModuleCodeGenerator<FCG>, FCG: FunctionCodeGenerator>(
let (count, ty) = local?;
fcg.feed_local(ty, count as usize)?;
}
fcg.begin_body()?;
for op in item.get_operators_reader()? {
let op = op?;
fcg.feed_opcode(op)?;

View File

@ -0,0 +1,109 @@
use dynasmrt::DynamicLabel;
use wasmparser::Type as WpType;
/*#[repr(u8)]
#[derive(Copy, Clone, Debug)]
pub enum RegisterName {
RDI,
RSI,
RDX,
RCX,
R8,
R9,
R10,
R11,
RBX,
R12,
R13,
R14,
R15,
Invalid,
}*/
#[derive(Debug)]
pub struct ControlFrame {
pub label: DynamicLabel,
pub loop_like: bool,
pub returns: Vec<WpType>,
pub value_stack_depth_before: usize,
}
#[derive(Debug)]
pub struct ControlStack {
pub frames: Vec<ControlFrame>,
}
#[derive(Debug)]
pub struct ValueStack {
pub num_regs: u8,
pub values: Vec<ValueInfo>,
}
#[derive(Copy, Clone, Debug)]
pub struct ValueInfo {
pub ty: WpType,
pub location: ValueLocation,
}
#[derive(Copy, Clone, Debug)]
pub enum ValueLocation {
Register(u8),
Stack,
}
impl ValueStack {
pub fn new(num_regs: u8) -> ValueStack {
ValueStack {
num_regs: num_regs,
values: vec![],
}
}
fn next_location(&self, loc: &ValueLocation) -> ValueLocation {
match *loc {
ValueLocation::Register(x) => {
if x >= self.num_regs - 1 {
ValueLocation::Stack
} else {
ValueLocation::Register(x + 1)
}
}
ValueLocation::Stack => ValueLocation::Stack,
}
}
pub fn push(&mut self, ty: WpType) -> ValueLocation {
let loc = self
.values
.last()
.map(|x| self.next_location(&x.location))
.unwrap_or(ValueLocation::Register(0));
self.values.push(ValueInfo {
ty: ty,
location: loc,
});
loc
}
pub fn pop(&mut self) -> Option<ValueInfo> {
self.values.pop()
}
pub fn pop2(&mut self) -> Option<(ValueInfo, ValueInfo)> {
if self.values.len() < 2 {
None
} else {
let v2 = self.values.pop().unwrap();
let v1 = self.values.pop().unwrap();
Some((v1, v2))
}
}
pub fn peek(&self) -> Option<ValueInfo> {
self.values.last().cloned()
}
pub fn reset_depth(&mut self, target_depth: usize) {
self.values.truncate(target_depth);
}
}