1use std::cell::UnsafeCell;
9use std::sync::atomic::{AtomicU64, Ordering};
10
11use catallaxy_gc::{GcVTable, Header, Tracer, HEADER_SIZE};
12use num_bigint::BigInt;
13
14use crate::class::{heap_class, ObjKind};
15use crate::dict::DictTable;
16use crate::value::Value;
17
18#[inline(always)]
19pub fn mark_value(t: &mut Tracer, v: Value) {
20 if v.is_ptr() {
21 t.mark(v.as_ptr());
22 }
23}
24
25#[repr(C)]
26pub struct InstanceObj {
27 pub header: Header,
28 fields: [AtomicU64; 0],
29}
30
31impl InstanceObj {
32 #[inline(always)]
33 pub fn field(&self, i: usize) -> &AtomicU64 {
34 unsafe { &*self.fields.as_ptr().add(i) }
36 }
37 #[inline(always)]
38 pub fn get(&self, i: usize) -> Value {
39 Value(self.field(i).load(Ordering::Relaxed))
40 }
41 #[inline(always)]
42 pub fn get_acquire(&self, i: usize) -> Value {
43 Value(self.field(i).load(Ordering::Acquire))
44 }
45 #[inline(always)]
46 pub fn set(&self, i: usize, v: Value) {
47 self.field(i).store(v.0, Ordering::Relaxed)
48 }
49 #[inline(always)]
50 pub fn set_release(&self, i: usize, v: Value) {
51 self.field(i).store(v.0, Ordering::Release)
52 }
53 pub fn nfields(&self) -> usize {
54 unsafe { heap_class(&self.header).nfields() }
55 }
56 pub fn size_for(nfields: usize) -> usize {
57 HEADER_SIZE + 8 * nfields
58 }
59}
60
61#[repr(C)]
62pub struct StrObj {
63 pub header: Header,
64 pub len: usize,
65 pub hash: AtomicU64,
67 pub chars: AtomicU64,
69 data: [u8; 0],
70}
71
72impl StrObj {
73 pub const BASE: usize = std::mem::size_of::<StrObj>();
74 pub fn as_str(&self) -> &str {
75 unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(self.data.as_ptr(), self.len)) }
77 }
78 pub(crate) fn data_ptr(&mut self) -> *mut u8 {
79 self.data.as_mut_ptr()
80 }
81 pub fn char_count(&self) -> usize {
82 let c = self.chars.load(Ordering::Relaxed);
83 if c != 0 {
84 return (c - 1) as usize;
85 }
86 let s = self.as_str();
87 let n = if s.is_ascii() { s.len() } else { s.chars().count() };
88 self.chars.store(n as u64 + 1, Ordering::Relaxed);
89 n
90 }
91 pub fn hash_code(&self) -> u64 {
92 let h = self.hash.load(Ordering::Relaxed);
93 if h != 0 {
94 return h;
95 }
96 let mut h = crate::ops::hash_bytes(self.as_str().as_bytes());
97 if h == 0 {
98 h = 1;
99 }
100 self.hash.store(h, Ordering::Relaxed);
101 h
102 }
103}
104
105#[repr(C)]
106pub struct BigIntObj {
107 pub header: Header,
108 pub value: BigInt,
109}
110
111#[repr(C)]
112pub struct ListObj {
113 pub header: Header,
114 pub vec: UnsafeCell<Vec<Value>>,
115}
116
117impl ListObj {
118 #[inline(always)]
121 pub unsafe fn items(&self) -> &Vec<Value> {
122 &*self.vec.get()
123 }
124 #[inline(always)]
128 #[allow(clippy::mut_from_ref)]
129 pub unsafe fn items_mut(&self) -> &mut Vec<Value> {
130 &mut *self.vec.get()
131 }
132}
133
134#[repr(C)]
135pub struct DictObj {
136 pub header: Header,
137 pub table: UnsafeCell<DictTable>,
138}
139
140impl DictObj {
141 #[inline(always)]
144 pub unsafe fn table(&self) -> &DictTable {
145 &*self.table.get()
146 }
147 #[inline(always)]
150 #[allow(clippy::mut_from_ref)]
151 pub unsafe fn table_mut(&self) -> &mut DictTable {
152 &mut *self.table.get()
153 }
154}
155
156#[repr(C)]
157pub struct TupleObj {
158 pub header: Header,
159 pub len: usize,
160 elems: [Value; 0],
161}
162
163impl TupleObj {
164 pub fn elems(&self) -> &[Value] {
165 unsafe { std::slice::from_raw_parts(self.elems.as_ptr(), self.len) }
166 }
167 pub(crate) fn elems_mut(&mut self) -> *mut Value {
168 self.elems.as_mut_ptr()
169 }
170 pub fn size_for(n: usize) -> usize {
171 std::mem::size_of::<TupleObj>() + 8 * n
172 }
173}
174
175#[repr(C)]
176pub struct ClosureObj {
177 pub header: Header,
178 pub func: u32,
179 pub ncaps: u32,
180 caps: [Value; 0],
181}
182
183impl ClosureObj {
184 pub fn caps(&self) -> &[Value] {
185 unsafe { std::slice::from_raw_parts(self.caps.as_ptr(), self.ncaps as usize) }
186 }
187 pub(crate) fn caps_mut(&mut self) -> *mut Value {
188 self.caps.as_mut_ptr()
189 }
190 pub fn size_for(n: usize) -> usize {
191 std::mem::size_of::<ClosureObj>() + 8 * n
192 }
193}
194
195#[repr(C)]
196pub struct CellObj {
197 pub header: Header,
198 pub value: AtomicU64,
199}
200
201#[repr(C)]
202pub struct StringBuilderObj {
203 pub header: Header,
204 pub buf: UnsafeCell<String>,
205}
206
207#[repr(C)]
208pub struct MutexObj {
209 pub header: Header,
210 pub raw: parking_lot::ReentrantMutex<()>,
211 pub value: AtomicU64,
212}
213
214#[repr(C)]
215pub struct AtomicObj {
216 pub header: Header,
217 pub value: AtomicU64,
218}
219
220pub struct ChannelInner {
221 pub queue: parking_lot::Mutex<ChannelState>,
222 pub not_empty: parking_lot::Condvar,
223 pub not_full: parking_lot::Condvar,
224 pub capacity: usize,
225}
226
227pub struct ChannelState {
228 pub items: std::collections::VecDeque<Value>,
229 pub closed: bool,
230}
231
232#[repr(C)]
233pub struct ChannelObj {
234 pub header: Header,
235 pub inner: Box<ChannelInner>,
236}
237
238pub enum ThreadOutcome {
240 Running,
241 Done(Value),
242 Panicked(String),
243 Joined,
244}
245
246pub struct ThreadInner {
247 pub outcome: parking_lot::Mutex<ThreadOutcome>,
248 pub done: parking_lot::Condvar,
249 pub handle: parking_lot::Mutex<Option<std::thread::JoinHandle<()>>>,
250 pub tid: AtomicU64,
252}
253
254#[repr(C)]
255pub struct ThreadObj {
256 pub header: Header,
257 pub inner: std::sync::Arc<ThreadInner>,
258}
259
260pub trait NativeData: std::any::Any + Send + Sync {
261 fn as_any(&self) -> &dyn std::any::Any;
262}
263impl<T: std::any::Any + Send + Sync> NativeData for T {
264 fn as_any(&self) -> &dyn std::any::Any {
265 self
266 }
267}
268
269#[repr(C)]
270pub struct NativeObj {
271 pub header: Header,
272 pub data: Box<dyn NativeData>,
273}
274
275unsafe fn trace_nothing(_: *const Header, _: &mut Tracer) {}
279
280unsafe fn trace_instance(h: *const Header, t: &mut Tracer) {
281 let o = &*(h as *const InstanceObj);
282 for i in 0..heap_class(h).nfields() {
283 mark_value(t, o.get(i));
284 }
285}
286unsafe fn size_instance(h: *const Header) -> usize {
287 InstanceObj::size_for(heap_class(h).nfields())
288}
289
290unsafe fn size_str(h: *const Header) -> usize {
291 StrObj::BASE + (*(h as *const StrObj)).len
292}
293
294unsafe fn fin_bigint(h: *mut Header) {
295 std::ptr::drop_in_place(&mut (*(h as *mut BigIntObj)).value);
296}
297unsafe fn size_bigint(h: *const Header) -> usize {
298 std::mem::size_of::<BigIntObj>() + (*(h as *const BigIntObj)).value.bits() as usize / 8
299}
300
301unsafe fn trace_list(h: *const Header, t: &mut Tracer) {
302 for &v in (*(*(h as *const ListObj)).vec.get()).iter() {
303 mark_value(t, v);
304 }
305}
306unsafe fn fin_list(h: *mut Header) {
307 std::ptr::drop_in_place((*(h as *mut ListObj)).vec.get());
308}
309unsafe fn size_list(h: *const Header) -> usize {
310 std::mem::size_of::<ListObj>() + 8 * (*(*(h as *const ListObj)).vec.get()).capacity()
311}
312
313unsafe fn trace_dict(h: *const Header, t: &mut Tracer) {
314 (*(*(h as *const DictObj)).table.get()).trace(t);
315}
316unsafe fn fin_dict(h: *mut Header) {
317 std::ptr::drop_in_place((*(h as *mut DictObj)).table.get());
318}
319unsafe fn size_dict(h: *const Header) -> usize {
320 std::mem::size_of::<DictObj>() + (*(*(h as *const DictObj)).table.get()).heap_bytes()
321}
322
323unsafe fn trace_tuple(h: *const Header, t: &mut Tracer) {
324 for &v in (*(h as *const TupleObj)).elems() {
325 mark_value(t, v);
326 }
327}
328unsafe fn size_tuple(h: *const Header) -> usize {
329 TupleObj::size_for((*(h as *const TupleObj)).len)
330}
331
332unsafe fn trace_closure(h: *const Header, t: &mut Tracer) {
333 for &v in (*(h as *const ClosureObj)).caps() {
334 mark_value(t, v);
335 }
336}
337unsafe fn size_closure(h: *const Header) -> usize {
338 ClosureObj::size_for((*(h as *const ClosureObj)).ncaps as usize)
339}
340
341unsafe fn trace_cell(h: *const Header, t: &mut Tracer) {
342 mark_value(t, Value((*(h as *const CellObj)).value.load(Ordering::Relaxed)));
343}
344unsafe fn size_cell(_: *const Header) -> usize {
345 std::mem::size_of::<CellObj>()
346}
347
348unsafe fn fin_sb(h: *mut Header) {
349 std::ptr::drop_in_place((*(h as *mut StringBuilderObj)).buf.get());
350}
351unsafe fn size_sb(h: *const Header) -> usize {
352 std::mem::size_of::<StringBuilderObj>() + (*(*(h as *const StringBuilderObj)).buf.get()).capacity()
353}
354
355unsafe fn trace_mutex(h: *const Header, t: &mut Tracer) {
356 mark_value(t, Value((*(h as *const MutexObj)).value.load(Ordering::Relaxed)));
357}
358unsafe fn fin_mutex(h: *mut Header) {
359 std::ptr::drop_in_place(&mut (*(h as *mut MutexObj)).raw);
360}
361unsafe fn size_mutex(_: *const Header) -> usize {
362 std::mem::size_of::<MutexObj>()
363}
364
365unsafe fn trace_atomic(h: *const Header, t: &mut Tracer) {
366 mark_value(t, Value((*(h as *const AtomicObj)).value.load(Ordering::Relaxed)));
367}
368unsafe fn size_atomic(_: *const Header) -> usize {
369 std::mem::size_of::<AtomicObj>()
370}
371
372unsafe fn trace_channel(h: *const Header, t: &mut Tracer) {
373 let inner = &(*(h as *const ChannelObj)).inner;
375 let q = inner.queue.data_ptr();
376 for &v in (*q).items.iter() {
377 mark_value(t, v);
378 }
379}
380unsafe fn fin_channel(h: *mut Header) {
381 std::ptr::drop_in_place(&mut (*(h as *mut ChannelObj)).inner);
382}
383unsafe fn size_channel(h: *const Header) -> usize {
384 std::mem::size_of::<ChannelObj>() + 8 * (*(*(h as *const ChannelObj)).inner.queue.data_ptr()).items.capacity()
385}
386
387unsafe fn trace_thread(h: *const Header, t: &mut Tracer) {
388 let inner = &(*(h as *const ThreadObj)).inner;
389 if let ThreadOutcome::Done(v) = &*inner.outcome.data_ptr() {
390 mark_value(t, *v);
391 }
392}
393unsafe fn fin_thread(h: *mut Header) {
394 std::ptr::drop_in_place(&mut (*(h as *mut ThreadObj)).inner);
395}
396unsafe fn size_thread(_: *const Header) -> usize {
397 std::mem::size_of::<ThreadObj>() + 128
398}
399
400unsafe fn fin_native(h: *mut Header) {
401 std::ptr::drop_in_place(&mut (*(h as *mut NativeObj)).data);
402}
403unsafe fn size_native(_: *const Header) -> usize {
404 std::mem::size_of::<NativeObj>()
405}
406
407unsafe fn size_zero(_: *const Header) -> usize {
408 0
409}
410
411#[allow(clippy::type_complexity)]
412pub(crate) fn vtable_for(kind: ObjKind) -> GcVTable {
413 let (trace, finalize, size): (
414 unsafe fn(*const Header, &mut Tracer),
415 Option<unsafe fn(*mut Header)>,
416 unsafe fn(*const Header) -> usize,
417 ) = match kind {
418 ObjKind::Immediate => (trace_nothing, None, size_zero),
419 ObjKind::Instance => (trace_instance, None, size_instance),
420 ObjKind::Str => (trace_nothing, None, size_str),
421 ObjKind::BigInt => (trace_nothing, Some(fin_bigint), size_bigint),
422 ObjKind::List => (trace_list, Some(fin_list), size_list),
423 ObjKind::Dict | ObjKind::Set => (trace_dict, Some(fin_dict), size_dict),
424 ObjKind::Tuple => (trace_tuple, None, size_tuple),
425 ObjKind::Closure => (trace_closure, None, size_closure),
426 ObjKind::Cell => (trace_cell, None, size_cell),
427 ObjKind::StringBuilder => (trace_nothing, Some(fin_sb), size_sb),
428 ObjKind::Mutex => (trace_mutex, Some(fin_mutex), size_mutex),
429 ObjKind::Atomic => (trace_atomic, None, size_atomic),
430 ObjKind::Channel => (trace_channel, Some(fin_channel), size_channel),
431 ObjKind::Thread => (trace_thread, Some(fin_thread), size_thread),
432 ObjKind::Native => (trace_nothing, Some(fin_native), size_native),
433 };
434 GcVTable { trace, finalize, size }
435}
436
437macro_rules! view {
441 ($fn:ident, $ty:ty) => {
442 #[inline(always)]
445 pub unsafe fn $fn<'a>(v: Value) -> &'a $ty {
446 &*(v.as_ptr() as *const $ty)
447 }
448 };
449}
450view!(as_instance, InstanceObj);
451view!(as_str_obj, StrObj);
452view!(as_bigint, BigIntObj);
453view!(as_list, ListObj);
454view!(as_dict, DictObj);
455view!(as_tuple, TupleObj);
456view!(as_closure, ClosureObj);
457view!(as_cell, CellObj);
458view!(as_sb, StringBuilderObj);
459view!(as_mutex, MutexObj);
460view!(as_atomic, AtomicObj);
461view!(as_channel, ChannelObj);
462view!(as_thread, ThreadObj);
463view!(as_native, NativeObj);
464
465#[inline]
467pub fn kind_of(v: Value) -> ObjKind {
468 if v.is_ptr() {
469 unsafe { heap_class(v.as_ptr()).kind }
470 } else {
471 ObjKind::Immediate
472 }
473}
474
475#[inline]
477pub fn str_of<'a>(v: Value) -> Option<&'a str> {
478 if kind_of(v) == ObjKind::Str {
479 Some(unsafe { as_str_obj(v) }.as_str())
480 } else {
481 None
482 }
483}