mirror of
https://github.com/fluencelabs/wasmer
synced 2025-03-30 22:41:03 +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 {
|
pub trait FunctionCodeGenerator {
|
||||||
fn feed_param(&mut self, ty: WpType) -> Result<(), CodegenError>;
|
fn feed_param(&mut self, ty: WpType) -> Result<(), CodegenError>;
|
||||||
fn feed_local(&mut self, ty: WpType, n: usize) -> 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 feed_opcode(&mut self, op: Operator) -> Result<(), CodegenError>;
|
||||||
fn finalize(&mut self) -> Result<(), CodegenError>;
|
fn finalize(&mut self) -> Result<(), CodegenError>;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::codegen::*;
|
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};
|
use wasmparser::{Operator, Type as WpType};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -8,11 +9,18 @@ pub struct X64ModuleCodeGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct X64FunctionCode {
|
pub struct X64FunctionCode {
|
||||||
|
id: usize,
|
||||||
|
begin_label: DynamicLabel,
|
||||||
|
cleanup_label: DynamicLabel,
|
||||||
assembler: Option<Assembler>,
|
assembler: Option<Assembler>,
|
||||||
locals: Vec<Local>,
|
locals: Vec<Local>,
|
||||||
|
num_params: usize,
|
||||||
current_stack_offset: usize,
|
current_stack_offset: usize,
|
||||||
|
callee_managed_stack_offset: usize,
|
||||||
|
value_stack: ValueStack,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
struct Local {
|
struct Local {
|
||||||
ty: WpType,
|
ty: WpType,
|
||||||
stack_offset: usize,
|
stack_offset: usize,
|
||||||
@ -26,20 +34,32 @@ impl X64ModuleCodeGenerator {
|
|||||||
|
|
||||||
impl ModuleCodeGenerator<X64FunctionCode> for X64ModuleCodeGenerator {
|
impl ModuleCodeGenerator<X64FunctionCode> for X64ModuleCodeGenerator {
|
||||||
fn next_function(&mut self) -> Result<&mut X64FunctionCode, CodegenError> {
|
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 {
|
let code = X64FunctionCode {
|
||||||
assembler: Some(match self.functions.last_mut() {
|
id: self.functions.len(),
|
||||||
Some(x) => x.assembler.take().unwrap(),
|
begin_label: begin_label,
|
||||||
None => match Assembler::new() {
|
cleanup_label: assembler.new_dynamic_label(),
|
||||||
Ok(x) => x,
|
assembler: Some(assembler),
|
||||||
Err(_) => {
|
|
||||||
return Err(CodegenError {
|
|
||||||
message: "cannot initialize assembler",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
locals: vec![],
|
locals: vec![],
|
||||||
|
num_params: 0,
|
||||||
current_stack_offset: 0,
|
current_stack_offset: 0,
|
||||||
|
callee_managed_stack_offset: 0,
|
||||||
|
value_stack: ValueStack::new(13),
|
||||||
};
|
};
|
||||||
self.functions.push(code);
|
self.functions.push(code);
|
||||||
Ok(self.functions.last_mut().unwrap())
|
Ok(self.functions.last_mut().unwrap())
|
||||||
@ -49,41 +69,98 @@ impl ModuleCodeGenerator<X64FunctionCode> for X64ModuleCodeGenerator {
|
|||||||
impl FunctionCodeGenerator for X64FunctionCode {
|
impl FunctionCodeGenerator for X64FunctionCode {
|
||||||
fn feed_param(&mut self, ty: WpType) -> Result<(), CodegenError> {
|
fn feed_param(&mut self, ty: WpType) -> Result<(), CodegenError> {
|
||||||
let size = get_size_of_type(&ty)?;
|
let size = get_size_of_type(&ty)?;
|
||||||
self.current_stack_offset -= size;
|
self.current_stack_offset += size;
|
||||||
self.locals.push(Local {
|
self.locals.push(Local {
|
||||||
ty: ty,
|
ty: ty,
|
||||||
stack_offset: self.current_stack_offset,
|
stack_offset: self.current_stack_offset,
|
||||||
});
|
});
|
||||||
// TODO: load parameter values onto stack...
|
self.num_params += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError> {
|
fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError> {
|
||||||
let size = get_size_of_type(&ty)?;
|
let size = get_size_of_type(&ty)?;
|
||||||
let assembler = self.assembler.as_mut().unwrap();
|
|
||||||
|
|
||||||
dynasm!(
|
|
||||||
assembler
|
|
||||||
; xor rax, rax
|
|
||||||
);
|
|
||||||
|
|
||||||
for _ in 0..n {
|
for _ in 0..n {
|
||||||
// FIXME: check range of 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 {
|
self.locals.push(Local {
|
||||||
ty: ty,
|
ty: ty,
|
||||||
stack_offset: self.current_stack_offset,
|
stack_offset: self.current_stack_offset,
|
||||||
});
|
});
|
||||||
dynasm!(
|
|
||||||
assembler
|
|
||||||
; mov [rsp - (self.current_stack_offset as i32)], rax
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Ok(())
|
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> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn finalize(&mut self) -> Result<(), CodegenError> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,3 +9,4 @@ extern crate dynasm;
|
|||||||
mod codegen;
|
mod codegen;
|
||||||
mod codegen_x64;
|
mod codegen_x64;
|
||||||
mod parse;
|
mod parse;
|
||||||
|
mod stack;
|
||||||
|
@ -281,6 +281,7 @@ pub fn read_module<MCG: ModuleCodeGenerator<FCG>, FCG: FunctionCodeGenerator>(
|
|||||||
let (count, ty) = local?;
|
let (count, ty) = local?;
|
||||||
fcg.feed_local(ty, count as usize)?;
|
fcg.feed_local(ty, count as usize)?;
|
||||||
}
|
}
|
||||||
|
fcg.begin_body()?;
|
||||||
for op in item.get_operators_reader()? {
|
for op in item.get_operators_reader()? {
|
||||||
let op = op?;
|
let op = op?;
|
||||||
fcg.feed_opcode(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