To protect your data, the CISO officer has suggested users to enable GitLab 2FA as soon as possible.

frame.rs 4.95 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
use ast::ir::*;
use ast::ptr::*;
use ast::types::*;
use runtime::ValueLocation;

use std::fmt;
use std::collections::HashMap;
use utils::POINTER_SIZE;
use vm::VM;

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

#[derive(RustcEncodable, RustcDecodable, Clone)]
pub struct Frame {
    func_ver_id: MuID,
    cur_offset: isize, // offset to frame base pointer

    pub argument_by_reg: HashMap<MuID, P<Value>>,
    pub argument_by_stack: HashMap<MuID, P<Value>>,
    
    pub allocated: HashMap<MuID, FrameSlot>,
    // (callsite, destination address)
    exception_callsites: Vec<(ValueLocation, ValueLocation)>
}

impl fmt::Display for Frame {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "\nFrame 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();
        for &(ref callsite, ref dest) in self.exception_callsites.iter() {
            writeln!(f, "    callsite: {} -> {}", callsite, dest).unwrap()
        }
        writeln!(f, "  cur offset: {}", self.cur_offset).unwrap();
        writeln!(f, "}}")
    }
}

impl Frame {
    pub fn new(func_ver_id: MuID) -> Frame {
        Frame {
            func_ver_id: func_ver_id,
            cur_offset: - (POINTER_SIZE as isize * 1), // reserve for old RBP

            argument_by_reg: HashMap::new(),
            argument_by_stack: HashMap::new(),

            allocated: HashMap::new(),
            exception_callsites: vec![]
        }
    }

    #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
    pub fn cur_size(&self) -> usize {
        // frame size is a multiple of 16 bytes
        let size = self.cur_offset.abs() as usize;

        // align size to a multiple of 16 bytes
        let size = (size + 16 - 1) & !(16 - 1);

        debug_assert!(size % 16 == 0);

        size
    }

    pub fn add_argument_by_reg(&mut self, temp: MuID, reg: P<Value>) {
        self.argument_by_reg.insert(temp, reg);
    }

    pub fn add_argument_by_stack(&mut self, temp: MuID, stack_slot: P<Value>) {
        self.argument_by_stack.insert(temp, stack_slot);
    }
    
    pub fn alloc_slot_for_callee_saved_reg(&mut self, reg: P<Value>, vm: &VM) -> P<Value> {
        let slot = self.alloc_slot(&reg, vm);

        slot.make_memory_op(reg.ty.clone(), vm)
    }

    pub fn remove_record_for_callee_saved_reg(&mut self, reg: MuID) {
        self.allocated.remove(&reg);
    }
    
    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)
    }
    
    pub fn get_exception_callsites(&self) -> &Vec<(ValueLocation, ValueLocation)> {
        &self.exception_callsites
    }
    
    pub fn add_exception_callsite(&mut self, callsite: ValueLocation, dest: ValueLocation) {
        trace!("add exception callsite: {} to dest {}", callsite, dest);
        self.exception_callsites.push((callsite, dest));
    }
    
    fn alloc_slot(&mut self, val: &P<Value>, vm: &VM) -> &FrameSlot {
        let id = val.id();
        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()
    }
}

#[derive(RustcEncodable, RustcDecodable, Clone)]
pub struct FrameSlot {
    pub offset: isize,
    pub value: P<Value>
}

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

impl FrameSlot {
    #[cfg(target_arch = "x86_64")]
    pub fn make_memory_op(&self, ty: P<MuType>, vm: &VM) -> P<Value> {
        use compiler::backend::x86_64;

        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
                }
            )
        })
    }
    #[cfg(target_arch = "aarch64")]
    pub fn make_memory_op(&self, ty: P<MuType>, vm: &VM) -> P<Value> {
        use compiler::backend::aarch64;

        P(Value{
            hdr: MuEntityHeader::unnamed(vm.next_id()),
            ty: ty.clone(),
            v: Value_::Memory(
                MemoryLocation::Address{
                    base: aarch64::FP.clone(),
                    offset: Some(Value::make_int_const(vm.next_id(), self.offset as u64)),
                    shift: 0,
                    signed: false
                }
            )
        })
    }
}