frame.rs 3.66 KB
Newer Older
qinsoon's avatar
qinsoon committed
1 2
use ast::ir::*;
use ast::ptr::*;
qinsoon's avatar
qinsoon committed
3
use ast::types::*;
qinsoon's avatar
qinsoon committed
4
use runtime::ValueLocation;
qinsoon's avatar
qinsoon committed
5

6
use std::fmt;
qinsoon's avatar
qinsoon committed
7
use std::collections::HashMap;
qinsoon's avatar
qinsoon committed
8
use utils::POINTER_SIZE;
qinsoon's avatar
qinsoon committed
9
use vm::VM;
qinsoon's avatar
qinsoon committed
10 11 12 13 14 15 16 17 18 19

// | previous frame ...
// |---------------
// | return address
// | old RBP        <- RBP
// | callee saved
// | spilled
// |---------------
// | alloca area

20
#[derive(RustcEncodable, RustcDecodable, Clone)]
qinsoon's avatar
qinsoon committed
21
pub struct Frame {
22
    func_ver_id: MuID,
qinsoon's avatar
qinsoon committed
23 24
    cur_offset: isize, // offset to rbp
    
25
    pub allocated: HashMap<MuID, FrameSlot>,
qinsoon's avatar
qinsoon committed
26 27
    // (callsite, destination address)
    exception_callsites: Vec<(ValueLocation, ValueLocation)>
qinsoon's avatar
qinsoon committed
28 29
}

30 31 32 33 34 35 36 37
impl fmt::Display for Frame {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "Frame for FuncVer {} {{", self.func_ver_id).unwrap();
        writeln!(f, "  allocated slots:").unwrap();
        for slot in self.allocated.values() {
            writeln!(f, "    {}", slot).unwrap();
        }
        writeln!(f, "  exception callsites:").unwrap();
qinsoon's avatar
qinsoon committed
38
        for &(ref callsite, ref dest) in self.exception_callsites.iter() {
39 40 41 42 43 44
            writeln!(f, "    callsite: {} -> {}", callsite, dest).unwrap()
        }
        writeln!(f, "}}")
    }
}

qinsoon's avatar
qinsoon committed
45
impl Frame {
46
    pub fn new(func_ver_id: MuID) -> Frame {
qinsoon's avatar
qinsoon committed
47
        Frame {
48
            func_ver_id: func_ver_id,
qinsoon's avatar
qinsoon committed
49
            cur_offset: - (POINTER_SIZE as isize * 1), // reserve for old RBP
qinsoon's avatar
qinsoon committed
50
            allocated: HashMap::new(),
qinsoon's avatar
qinsoon committed
51
            exception_callsites: vec![]
qinsoon's avatar
qinsoon committed
52 53 54
        }
    }
    
qinsoon's avatar
qinsoon committed
55 56 57
    pub fn cur_offset(&self) -> isize {
        self.cur_offset
    }
qinsoon's avatar
qinsoon committed
58 59 60 61

    pub fn cur_size(&self) -> usize {
        self.cur_offset.abs() as usize
    }
qinsoon's avatar
qinsoon committed
62
    
qinsoon's avatar
qinsoon committed
63
    pub fn alloc_slot_for_callee_saved_reg(&mut self, reg: P<Value>, vm: &VM) -> P<Value> {
qinsoon's avatar
qinsoon committed
64 65 66
        let slot = self.alloc_slot(&reg, vm);
        slot.make_memory_op(reg.ty.clone(), vm)
    }
qinsoon's avatar
qinsoon committed
67 68 69 70

    pub fn remove_record_for_callee_saved_reg(&mut self, reg: MuID) {
        self.allocated.remove(&reg);
    }
qinsoon's avatar
qinsoon committed
71 72 73 74
    
    pub fn alloc_slot_for_spilling(&mut self, reg: P<Value>, vm: &VM) -> P<Value> {
        let slot = self.alloc_slot(&reg, vm);
        slot.make_memory_op(reg.ty.clone(), vm)
qinsoon's avatar
qinsoon committed
75 76
    }
    
qinsoon's avatar
qinsoon committed
77 78 79 80
    pub fn get_exception_callsites(&self) -> &Vec<(ValueLocation, ValueLocation)> {
        &self.exception_callsites
    }
    
qinsoon's avatar
qinsoon committed
81
    pub fn add_exception_callsite(&mut self, callsite: ValueLocation, dest: ValueLocation) {
82
        trace!("add exception callsite: {} to dest {}", callsite, dest);
qinsoon's avatar
qinsoon committed
83
        self.exception_callsites.push((callsite, dest));
qinsoon's avatar
qinsoon committed
84 85
    }
    
qinsoon's avatar
qinsoon committed
86
    fn alloc_slot(&mut self, val: &P<Value>, vm: &VM) -> &FrameSlot {
87
        let id = val.id();
qinsoon's avatar
qinsoon committed
88 89 90 91 92 93 94 95 96
        let ret = FrameSlot {
            offset: self.cur_offset,
            value: val.clone()
        };
        
        self.cur_offset -= vm.get_type_size(val.ty.id()) as isize;
        
        self.allocated.insert(id, ret);
        self.allocated.get(&id).unwrap()
qinsoon's avatar
qinsoon committed
97 98 99
    }
}

100
#[derive(RustcEncodable, RustcDecodable, Clone)]
101 102 103
pub struct FrameSlot {
    pub offset: isize,
    pub value: P<Value>
qinsoon's avatar
qinsoon committed
104 105
}

106 107 108 109 110 111
impl fmt::Display for FrameSlot {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}(RBP): {}", self.offset, self.value)
    }
}

qinsoon's avatar
qinsoon committed
112 113
impl FrameSlot {
    #[cfg(target_arch = "x86_64")]
qinsoon's avatar
qinsoon committed
114
    pub fn make_memory_op(&self, ty: P<MuType>, vm: &VM) -> P<Value> {
qinsoon's avatar
qinsoon committed
115
        use compiler::backend::x86_64;
qinsoon's avatar
qinsoon committed
116 117 118 119 120 121 122 123 124 125 126 127 128

        P(Value{
            hdr: MuEntityHeader::unnamed(vm.next_id()),
            ty: ty.clone(),
            v: Value_::Memory(
                MemoryLocation::Address{
                    base: x86_64::RBP.clone(),
                    offset: Some(Value::make_int_const(vm.next_id(), self.offset as u64)),
                    index: None,
                    scale: None
                }
            )
        })
qinsoon's avatar
qinsoon committed
129 130
    }
}