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