1use super::instruction::ValueType;
6use super::objects::*;
7use super::value::{GosValue, RCQueue, RCount, IRC};
8use std::cell::Ref;
9use std::cell::RefCell;
10use std::convert::TryFrom;
11use std::rc::{Rc, Weak};
12
13pub struct GcContainer {
14 inner: Rc<RefCell<Vec<GcWeak>>>,
15}
16
17impl GcContainer {
18 pub fn new() -> GcContainer {
19 GcContainer {
20 inner: Rc::new(RefCell::new(Vec::new())),
21 }
22 }
23
24 pub fn add_array(&self, arr: &Rc<(GosArrayObj, RCount)>) {
25 self.add_weak(GcWeak::new_array(arr))
26 }
27
28 pub fn add_closure(&self, cls: &Rc<(ClosureObj, RCount)>) {
29 self.add_weak(GcWeak::new_closure(cls))
30 }
31
32 pub fn add_map(&self, m: &Rc<(MapObj, RCount)>) {
33 self.add_weak(GcWeak::new_map(m))
34 }
35
36 pub fn add_struct(&self, s: &Rc<(StructObj, RCount)>) {
37 self.add_weak(GcWeak::new_struct(s))
38 }
39
40 #[inline]
41 pub(crate) fn add_weak(&self, w: GcWeak) {
42 self.inner.borrow_mut().push(w);
43 }
44
45 fn borrow_data(&self) -> Ref<Vec<GcWeak>> {
46 self.inner.borrow()
47 }
48}
49
50#[derive(Clone)]
51pub(crate) enum GcWeak {
52 Array(Weak<(GosArrayObj, RCount)>),
53 Closure(Weak<(ClosureObj, RCount)>),
54 Map(Weak<(MapObj, RCount)>),
55 Struct(Weak<(StructObj, RCount)>),
56 }
64
65impl GcWeak {
66 pub fn new_array(arr: &Rc<(GosArrayObj, RCount)>) -> GcWeak {
67 GcWeak::Array(Rc::downgrade(arr))
68 }
69
70 pub fn new_closure(cls: &Rc<(ClosureObj, RCount)>) -> GcWeak {
71 GcWeak::Closure(Rc::downgrade(cls))
72 }
73
74 pub fn new_map(m: &Rc<(MapObj, RCount)>) -> GcWeak {
75 GcWeak::Map(Rc::downgrade(m))
76 }
77
78 pub fn new_struct(s: &Rc<(StructObj, RCount)>) -> GcWeak {
79 GcWeak::Struct(Rc::downgrade(s))
80 }
81
82 fn to_gosv(&self) -> Option<GosValue> {
83 match &self {
84 GcWeak::Array(w) => w.upgrade().map(|v| {
85 v.1.set(i32::try_from(w.strong_count()).unwrap() - 1);
86 GosValue::from_gos_array(v)
87 }),
88 GcWeak::Closure(w) => w.upgrade().map(|v| {
89 v.1.set(i32::try_from(w.strong_count()).unwrap() - 1);
90 GosValue::from_closure(Some(v))
91 }),
92 GcWeak::Map(w) => w.upgrade().map(|v| {
93 v.1.set(i32::try_from(w.strong_count()).unwrap() - 1);
94 GosValue::from_map(Some(v))
95 }),
96 GcWeak::Struct(w) => w.upgrade().map(|v| {
97 v.1.set(i32::try_from(w.strong_count()).unwrap() - 1);
98 GosValue::from_struct(v)
99 }),
100 }
101 }
102}
103
104fn children_ref_sub_one(val: &GosValue) {
105 match val.typ() {
106 ValueType::Array => val
107 .as_gos_array()
108 .0
109 .borrow_data_mut()
110 .iter()
111 .for_each(|obj| obj.ref_sub_one()),
112 ValueType::Closure => match val.as_closure() {
113 Some(cls) => cls.0.ref_sub_one(),
114 None => {}
115 },
116 ValueType::Map => match val.as_map() {
117 Some(m) => m.0.borrow_data().iter().for_each(|(k, v)| {
118 k.ref_sub_one();
119 v.ref_sub_one();
120 }),
121 None => {}
122 },
123 ValueType::Struct => val
124 .as_struct()
125 .0
126 .borrow_fields()
127 .iter()
128 .for_each(|obj| obj.ref_sub_one()),
129 _ => unreachable!(),
130 };
131}
132
133fn children_mark_dirty(val: &GosValue, queue: &mut RCQueue) {
134 match val.typ() {
135 ValueType::Array => val
136 .as_gos_array()
137 .0
138 .borrow_data_mut()
139 .iter()
140 .for_each(|obj| obj.mark_dirty(queue)),
141 ValueType::Closure => match val.as_closure() {
142 Some(cls) => cls.0.mark_dirty(queue),
143 None => {}
144 },
145 ValueType::Map => match val.as_map() {
146 Some(m) => m.0.borrow_data().iter().for_each(|(k, v)| {
147 k.mark_dirty(queue);
148 v.mark_dirty(queue);
149 }),
150 None => {}
151 },
152 ValueType::Struct => val
153 .as_struct()
154 .0
155 .borrow_fields()
156 .iter()
157 .for_each(|obj| obj.mark_dirty(queue)),
158 _ => unreachable!(),
159 };
160}
161
162fn break_cycle(val: &GosValue) {
164 match val.typ() {
165 ValueType::Array => val.as_gos_array().0.borrow_data_mut().clear(),
166 ValueType::Map => match val.as_map() {
167 Some(m) => m.0.borrow_data_mut().clear(),
168 None => {}
169 },
170 ValueType::Struct => val.as_struct().0.borrow_fields_mut().clear(),
171 ValueType::Closure => {}
172 _ => unreachable!(),
173 };
174}
175
176fn partition_to_scan(to_scan: &mut Vec<GosValue>) -> usize {
178 let len = to_scan.len();
179 if len == 0 {
180 return 0;
181 }
182 let mut p0 = 0;
183 let mut p1 = len - 1;
184 loop {
185 while p0 < len - 1 && to_scan[p0].rc() > 0 {
186 p0 += 1;
187 }
188 while p1 > 1 && to_scan[p1].rc() <= 0 {
189 p1 -= 1;
190 }
191 if p0 >= p1 {
192 break;
193 }
194 to_scan.swap(p0, p1);
195 }
196 p0
197}
198
199pub(crate) fn collect(objs: &GcContainer) {
200 let mut to_scan: Vec<GosValue> = objs
201 .borrow_data()
202 .iter()
203 .filter_map(|o| o.to_gosv())
204 .collect();
205 for v in to_scan.iter() {
207 children_ref_sub_one(v);
208 }
209
210 let boundary = partition_to_scan(&mut to_scan);
211 for i in boundary..to_scan.len() {
212 to_scan[i].set_rc(-(i as IRC));
213 }
214
215 let mut queue: RCQueue = RCQueue::new();
216 for i in 0..boundary {
217 children_mark_dirty(&to_scan[i], &mut queue);
218 }
219
220 loop {
221 if let Some(i) = queue.pop_front() {
222 let obj = &to_scan[(-i) as usize];
223 obj.set_rc(666);
224 children_mark_dirty(&obj, &mut queue);
225 } else {
226 break;
227 }
228 }
229
230 for obj in to_scan.into_iter() {
231 if obj.rc() <= 0 {
232 break_cycle(&obj);
233 }
234 }
235
236 let _result: Vec<GosValue> = objs
237 .borrow_data()
238 .iter()
239 .filter_map(|o| o.to_gosv())
240 .collect();
241 }