cgc_single_threaded/
space.rs1use 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}