mirror of
https://github.com/fluencelabs/wasmer
synced 2025-03-16 16:20:49 +00:00
Calling conventions, value stack, and runtime stack layout.
This commit is contained in:
parent
2fbb5e3332
commit
4ebb22f8bc
@ -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>;
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -9,3 +9,4 @@ extern crate dynasm;
|
||||
mod codegen;
|
||||
mod codegen_x64;
|
||||
mod parse;
|
||||
mod stack;
|
||||
|
@ -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)?;
|
||||
|
109
lib/dynasm-backend/src/stack.rs
Normal file
109
lib/dynasm-backend/src/stack.rs
Normal 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);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user