mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-22 05:01:33 +00:00
Improve machine state abstraction.
This commit is contained in:
@ -2,44 +2,38 @@ use crate::emitter_x64::*;
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use wasmparser::Type as WpType;
|
use wasmparser::Type as WpType;
|
||||||
|
|
||||||
pub struct Machine<E: Emitter> {
|
struct MachineStackOffset(usize);
|
||||||
|
|
||||||
|
pub struct Machine {
|
||||||
used_gprs: HashSet<GPR>,
|
used_gprs: HashSet<GPR>,
|
||||||
used_xmms: HashSet<XMM>,
|
used_xmms: HashSet<XMM>,
|
||||||
control: Vec<ControlFrame<E>>,
|
stack_offset: MachineStackOffset
|
||||||
stack_offset: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl Machine {
|
||||||
pub struct ControlFrame<E: Emitter> {
|
pub fn new() -> Self {
|
||||||
pub label: E::Label,
|
Machine {
|
||||||
pub loop_like: bool,
|
used_gprs: HashSet::new(),
|
||||||
pub returns: Vec<WpType>,
|
used_xmms: HashSet::new(),
|
||||||
pub stack_offset_snapshot: usize,
|
stack_offset: MachineStackOffset(0),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Emitter> Machine<E> {
|
/// Picks an unused general purpose register for local/stack/argument use.
|
||||||
/// Picks an unused general purpose register.
|
|
||||||
///
|
///
|
||||||
/// This method does not mark the register as used.
|
/// This method does not mark the register as used.
|
||||||
pub fn pick_gpr(&self) -> Option<GPR> {
|
pub fn pick_gpr(&self) -> Option<GPR> {
|
||||||
use GPR::*;
|
use GPR::*;
|
||||||
static REGS: &'static [GPR] = &[
|
static REGS: &'static [GPR] = &[
|
||||||
//RAX,
|
|
||||||
RCX,
|
RCX,
|
||||||
RDX,
|
RDX,
|
||||||
RBX,
|
RBX,
|
||||||
RSP,
|
|
||||||
RBP,
|
|
||||||
RSI,
|
RSI,
|
||||||
RDI,
|
RDI,
|
||||||
R8,
|
R8,
|
||||||
R9,
|
R9,
|
||||||
R10,
|
R10,
|
||||||
R11,
|
R11,
|
||||||
//R12,
|
|
||||||
//R13,
|
|
||||||
//R14,
|
|
||||||
//R15
|
|
||||||
];
|
];
|
||||||
for r in REGS {
|
for r in REGS {
|
||||||
if !self.used_gprs.contains(r) {
|
if !self.used_gprs.contains(r) {
|
||||||
@ -49,15 +43,46 @@ impl<E: Emitter> Machine<E> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Picks an unused general purpose register for internal temporary use.
|
||||||
|
///
|
||||||
|
/// This method does not mark the register as used.
|
||||||
|
pub fn pick_temp_gpr(&self) -> Option<GPR> {
|
||||||
|
use GPR::*;
|
||||||
|
static REGS: &'static [GPR] = &[
|
||||||
|
RAX,
|
||||||
|
R12,
|
||||||
|
R13,
|
||||||
|
R14,
|
||||||
|
R15
|
||||||
|
];
|
||||||
|
for r in REGS {
|
||||||
|
if !self.used_gprs.contains(r) {
|
||||||
|
return Some(*r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Acquires a temporary GPR.
|
||||||
|
pub fn acquire_temp_gpr(&mut self) -> Option<GPR> {
|
||||||
|
let gpr = self.pick_temp_gpr();
|
||||||
|
if let Some(x) = gpr {
|
||||||
|
self.used_gprs.insert(x);
|
||||||
|
}
|
||||||
|
gpr
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Releases a temporary GPR.
|
||||||
|
pub fn release_temp_gpr(&mut self, gpr: GPR) {
|
||||||
|
assert_eq!(self.used_gprs.remove(&gpr), true);
|
||||||
|
}
|
||||||
|
|
||||||
/// Picks an unused XMM register.
|
/// Picks an unused XMM register.
|
||||||
///
|
///
|
||||||
/// This method does not mark the register as used.
|
/// This method does not mark the register as used.
|
||||||
pub fn pick_xmm(&self) -> Option<XMM> {
|
pub fn pick_xmm(&self) -> Option<XMM> {
|
||||||
use XMM::*;
|
use XMM::*;
|
||||||
static REGS: &'static [XMM] = &[
|
static REGS: &'static [XMM] = &[
|
||||||
//XMM0,
|
|
||||||
//XMM1,
|
|
||||||
//XMM2,
|
|
||||||
XMM3,
|
XMM3,
|
||||||
XMM4,
|
XMM4,
|
||||||
XMM5,
|
XMM5,
|
||||||
@ -72,14 +97,47 @@ impl<E: Emitter> Machine<E> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Picks an unused XMM register for internal temporary use.
|
||||||
|
///
|
||||||
|
/// This method does not mark the register as used.
|
||||||
|
pub fn pick_temp_xmm(&self) -> Option<XMM> {
|
||||||
|
use XMM::*;
|
||||||
|
static REGS: &'static [XMM] = &[
|
||||||
|
XMM0,
|
||||||
|
XMM1,
|
||||||
|
XMM2,
|
||||||
|
];
|
||||||
|
for r in REGS {
|
||||||
|
if !self.used_xmms.contains(r) {
|
||||||
|
return Some(*r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Acquires a temporary XMM register.
|
||||||
|
pub fn acquire_temp_xmm(&mut self) -> Option<XMM> {
|
||||||
|
let xmm = self.pick_temp_xmm();
|
||||||
|
if let Some(x) = xmm {
|
||||||
|
self.used_xmms.insert(x);
|
||||||
|
}
|
||||||
|
xmm
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Releases a temporary XMM register.
|
||||||
|
pub fn release_temp_xmm(&mut self, xmm: XMM) {
|
||||||
|
assert_eq!(self.used_xmms.remove(&xmm), true);
|
||||||
|
}
|
||||||
|
|
||||||
/// Acquires locations from the machine state.
|
/// Acquires locations from the machine state.
|
||||||
///
|
///
|
||||||
/// If the returned locations are used for stack value, `release_location` needs to be called on them;
|
/// If the returned locations are used for stack value, `release_location` needs to be called on them;
|
||||||
/// Otherwise, if the returned locations are used for locals, `release_location` does not need to be called on them.
|
/// Otherwise, if the returned locations are used for locals, `release_location` does not need to be called on them.
|
||||||
pub fn acquire_locations(
|
pub fn acquire_locations<E: Emitter>(
|
||||||
&mut self,
|
&mut self,
|
||||||
assembler: &mut E,
|
assembler: &mut E,
|
||||||
tys: &[WpType],
|
tys: &[WpType],
|
||||||
|
zeroed: bool,
|
||||||
) -> Vec<Location> {
|
) -> Vec<Location> {
|
||||||
let mut ret = vec![];
|
let mut ret = vec![];
|
||||||
let mut delta_stack_offset: usize = 0;
|
let mut delta_stack_offset: usize = 0;
|
||||||
@ -100,9 +158,9 @@ impl<E: Emitter> Machine<E> {
|
|||||||
let loc = if let Some(x) = loc {
|
let loc = if let Some(x) = loc {
|
||||||
x
|
x
|
||||||
} else {
|
} else {
|
||||||
self.stack_offset += 8;
|
self.stack_offset.0 += 8;
|
||||||
delta_stack_offset += 8;
|
delta_stack_offset += 8;
|
||||||
Location::Memory(GPR::RBP, -(self.stack_offset as i32))
|
Location::Memory(GPR::RBP, -(self.stack_offset.0 as i32))
|
||||||
};
|
};
|
||||||
if let Location::GPR(x) = loc {
|
if let Location::GPR(x) = loc {
|
||||||
self.used_gprs.insert(x);
|
self.used_gprs.insert(x);
|
||||||
@ -113,11 +171,16 @@ impl<E: Emitter> Machine<E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assembler.emit_sub(Size::S64, Location::Imm32(delta_stack_offset as u32), Location::GPR(GPR::RSP));
|
assembler.emit_sub(Size::S64, Location::Imm32(delta_stack_offset as u32), Location::GPR(GPR::RSP));
|
||||||
|
if zeroed {
|
||||||
|
for i in 0..tys.len() {
|
||||||
|
assembler.emit_mov(Size::S64, Location::Imm32(0), Location::Memory(GPR::RSP, (i * 8) as i32));
|
||||||
|
}
|
||||||
|
}
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Releases locations used for stack value.
|
/// Releases locations used for stack value.
|
||||||
pub fn release_locations(
|
pub fn release_locations<E: Emitter>(
|
||||||
&mut self,
|
&mut self,
|
||||||
assembler: &mut E,
|
assembler: &mut E,
|
||||||
locs: &[Location]
|
locs: &[Location]
|
||||||
@ -137,10 +200,10 @@ impl<E: Emitter> Machine<E> {
|
|||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
let offset = (-x) as usize;
|
let offset = (-x) as usize;
|
||||||
if offset != self.stack_offset {
|
if offset != self.stack_offset.0 {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
self.stack_offset -= 8;
|
self.stack_offset.0 -= 8;
|
||||||
delta_stack_offset += 8;
|
delta_stack_offset += 8;
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
|
Reference in New Issue
Block a user