Skip to main content

cgc_single_threaded/
space.rs

1use crate::mem::*;
2pub struct Space {
3    pub top: Address,
4    pub limit: Address,
5    pub pages: Vec<Page>,
6    pub size: usize,
7    pub size_limit: usize,
8    pub page_size: usize,
9    pub pages_count: usize,
10    pub allocated_size: usize,
11}
12
13impl Space {
14    pub fn empty() -> Self {
15        Self {
16            top: Address::null(),
17            limit: Address::null(),
18            pages: Vec::new(),
19            size: 0,
20            allocated_size: 0,
21            page_size: 0,
22            pages_count: 0,
23            size_limit: 0,
24        }
25    }
26    pub fn new(page_size: usize) -> Self {
27        let mut pages = Vec::new();
28        let page = Page::new(page_size);
29        pages.push(page);
30        let top = Address::from_ptr(&pages.last().unwrap().top);
31        let limit = Address::from_ptr(&pages.last().unwrap().limit);
32        let mut space = Space {
33            top,
34            limit,
35            pages,
36            size: 0,
37            page_size,
38            size_limit: 0,
39            pages_count: 1,
40            allocated_size: 0,
41        };
42        space.compute_size_limit();
43        space
44    }
45
46    pub fn compute_size_limit(&mut self) {
47        self.size_limit = self.size << 1;
48    }
49    pub fn may_allocate_in_current(&mut self, size: usize) -> bool {
50        let even_bytes = size + (size & 0x01);
51        let place_in_current = self.top.deref().offset(even_bytes) <= self.limit.deref();
52        place_in_current
53    }
54    pub fn add_page(&mut self, size: usize) {
55        let real_size = align_usize(size, page_size());
56        let page = Page::new(real_size);
57        self.pages.push(page);
58        self.pages_count += 1;
59        let page = self.pages.last().unwrap();
60        self.size += real_size;
61        self.top = Address::from_ptr(&page.top);
62        self.limit = Address::from_ptr(&page.limit);
63    }
64
65    pub fn fast_allocate(&mut self, bytes: usize, needs_gc: &mut bool) -> Address {
66        let even_bytes = bytes + (bytes & 0x01);
67        let place_in_current = self.top.deref().offset(even_bytes) < self.limit.deref();
68
69        if !place_in_current {
70            *needs_gc = true;
71            log::debug!("Add new page");
72            self.add_page(even_bytes);
73        }
74        self.allocated_size += even_bytes;
75        let result = self.top.deref();
76        unsafe {
77            *self.top.to_mut_ptr::<*mut u8>() =
78                self.top.deref().offset(even_bytes).to_mut_ptr::<u8>();
79        }
80        result
81    }
82    pub fn try_find_page_for(&self, size: usize) -> Option<(Address, Address)> {
83        for page in self.pages.iter() {
84            if page.top.offset(size) < page.limit {
85                return Some((Address::from_ptr(&page.top), Address::from_ptr(&page.limit)));
86            }
87        }
88
89        return None;
90    }
91    pub fn allocate(&mut self, bytes: usize, needs_gc: &mut bool) -> Address {
92        let even_bytes = bytes + (bytes & 0x01);
93        let place_in_current = self.top.deref().offset(even_bytes) < self.limit.deref();
94
95        if !place_in_current {
96            let head = self.try_find_page_for(even_bytes);
97
98            if let None = head {
99                *needs_gc = true;
100                self.add_page(even_bytes);
101            } else if let Some((top, limit)) = head {
102                self.top = top;
103                self.limit = limit;
104            }
105        }
106        self.allocated_size += even_bytes;
107        let result = self.top.deref();
108        unsafe {
109            *self.top.to_mut_ptr::<*mut u8>() =
110                self.top.deref().offset(even_bytes).to_mut_ptr::<u8>();
111        }
112        result
113    }
114
115    pub fn swap(&mut self, space: &mut Space) {
116        self.clear();
117        assert!(space.pages.is_empty() == false);
118        while space.pages.is_empty() != true {
119            self.pages.push(space.pages.pop().unwrap());
120            self.size += self.pages.last().unwrap().size;
121        }
122        self.allocated_size = space.allocated_size;
123        let page = self.pages.last().unwrap();
124        self.top = Address::from_ptr(&page.top);
125        self.limit = Address::from_ptr(&page.limit);
126    }
127
128    pub fn contains(&self, addr: Address) -> bool {
129        for page in self.pages.iter() {
130            let page: &Page = page;
131            if addr >= page.data && addr <= page.limit {
132                return true;
133            }
134        }
135
136        false
137    }
138    pub fn clear(&mut self) {
139        self.size = 0;
140        while let Some(page) = self.pages.pop() {
141            page.uncommit();
142        }
143    }
144}
145
146pub struct Page {
147    pub data: Address,
148    pub top: Address,
149    pub limit: Address,
150    pub size: usize,
151}
152
153impl Page {
154    pub fn new(size: usize) -> Self {
155        let data = commit(size, false);
156        let top = data;
157        let limit = data.offset(size);
158        Self {
159            top,
160            data,
161            limit,
162            size,
163        }
164    }
165
166    pub fn uncommit(&self) {
167        uncommit(self.data, self.size)
168    }
169}