1use std::cell::UnsafeCell;
10use std::sync::atomic::{AtomicPtr, AtomicU64, AtomicUsize, Ordering};
11
12use catallaxy_gc::{GcVTable, Header, Tracer, HEADER_SIZE};
13use num_bigint::BigInt;
14
15use crate::buf::WordBuf;
16use crate::class::{heap_class, ObjKind};
17use crate::dict::DictTable;
18use crate::ownership::Access;
19use crate::value::Value;
20
21#[inline(always)]
22pub fn mark_value(t: &mut Tracer, v: Value) {
23 if v.is_ptr() {
24 t.mark(v.as_ptr());
25 }
26}
27
28#[repr(C)]
29pub struct InstanceObj {
30 pub header: Header,
31 fields: [AtomicU64; 0],
32}
33
34impl InstanceObj {
35 #[inline(always)]
36 pub fn field(&self, i: usize) -> &AtomicU64 {
37 unsafe { &*self.fields.as_ptr().add(i) }
39 }
40 #[inline(always)]
41 pub fn get(&self, i: usize) -> Value {
42 Value(self.field(i).load(Ordering::Relaxed))
43 }
44 #[inline(always)]
45 pub fn get_acquire(&self, i: usize) -> Value {
46 Value(self.field(i).load(Ordering::Acquire))
47 }
48 #[inline(always)]
49 pub fn set(&self, i: usize, v: Value) {
50 self.field(i).store(v.0, Ordering::Relaxed)
51 }
52 #[inline(always)]
53 pub fn set_release(&self, i: usize, v: Value) {
54 self.field(i).store(v.0, Ordering::Release)
55 }
56 pub fn nfields(&self) -> usize {
57 unsafe { heap_class(&self.header).nfields() }
58 }
59 pub fn size_for(nfields: usize) -> usize {
60 HEADER_SIZE + 8 * nfields
61 }
62}
63
64#[repr(C)]
65pub struct StrObj {
66 pub header: Header,
67 pub len: usize,
68 pub hash: AtomicU64,
70 pub chars: AtomicU64,
72 data: [u8; 0],
73}
74
75impl StrObj {
76 pub const BASE: usize = std::mem::size_of::<StrObj>();
77 pub fn as_str(&self) -> &str {
78 unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(self.data.as_ptr(), self.len)) }
80 }
81 pub(crate) fn data_ptr(&mut self) -> *mut u8 {
82 self.data.as_mut_ptr()
83 }
84 pub fn char_count(&self) -> usize {
85 let c = self.chars.load(Ordering::Relaxed);
86 if c != 0 {
87 return (c - 1) as usize;
88 }
89 let s = self.as_str();
90 let n = if s.is_ascii() { s.len() } else { s.chars().count() };
91 self.chars.store(n as u64 + 1, Ordering::Relaxed);
92 n
93 }
94 pub fn hash_code(&self) -> u64 {
95 let h = self.hash.load(Ordering::Relaxed);
96 if h != 0 {
97 return h;
98 }
99 let mut h = crate::ops::hash_bytes(self.as_str().as_bytes());
100 if h == 0 {
101 h = 1;
102 }
103 self.hash.store(h, Ordering::Relaxed);
104 h
105 }
106}
107
108#[repr(C)]
109pub struct BigIntObj {
110 pub header: Header,
111 pub value: BigInt,
112}
113
114#[repr(C)]
122pub struct ListObj {
123 pub header: Header,
124 len: AtomicUsize,
125 buf: AtomicPtr<WordBuf>,
126}
127
128impl ListObj {
129 pub(crate) unsafe fn init(p: *mut ListObj, items: Vec<Value>) {
132 let buf = WordBuf::alloc(items.capacity(), Value::NIL.0);
133 for (s, v) in WordBuf::slots(buf).iter().zip(&items) {
134 s.store(v.0, Ordering::Relaxed);
135 }
136 std::ptr::addr_of_mut!((*p).len).write(AtomicUsize::new(items.len()));
137 std::ptr::addr_of_mut!((*p).buf).write(AtomicPtr::new(buf));
138 }
139
140 #[inline(always)]
141 pub fn len(&self) -> usize {
142 self.len.load(Ordering::Acquire)
143 }
144
145 #[inline(always)]
146 pub fn is_empty(&self) -> bool {
147 self.len() == 0
148 }
149
150 #[inline(always)]
151 fn slots(&self) -> &[AtomicU64] {
152 unsafe { WordBuf::slots(self.buf.load(Ordering::Acquire)) }
153 }
154
155 #[inline(always)]
158 pub fn get(&self, i: usize) -> Option<Value> {
159 if i >= self.len() {
160 return None;
161 }
162 self.slots().get(i).map(|x| Value(x.load(Ordering::Acquire)))
163 }
164
165 #[inline(always)]
167 pub fn get_local(&self, i: usize) -> Option<Value> {
168 if i >= self.len.load(Ordering::Relaxed) {
169 return None;
170 }
171 let slots = unsafe { WordBuf::slots(self.buf.load(Ordering::Relaxed)) };
172 slots.get(i).map(|x| Value(x.load(Ordering::Relaxed)))
173 }
174
175 pub fn to_vec(&self) -> Vec<Value> {
177 let n = self.len();
178 let slots = self.slots();
179 slots[..n.min(slots.len())].iter().map(|x| Value(x.load(Ordering::Acquire))).collect()
180 }
181
182 pub fn capacity(&self) -> usize {
183 unsafe { WordBuf::cap(self.buf.load(Ordering::Acquire)) }
184 }
185
186 pub unsafe fn set(&self, i: usize, v: Value) -> bool {
193 if i >= self.len.load(Ordering::Relaxed) {
194 return false;
195 }
196 self.slots()[i].store(v.0, Ordering::Release);
197 true
198 }
199
200 pub unsafe fn push(&self, v: Value, access: Access) {
203 let n = self.len.load(Ordering::Relaxed);
204 if n == self.capacity() {
205 self.grow(n + 1, access);
206 }
207 self.slots()[n].store(v.0, Ordering::Release);
208 self.len.store(n + 1, Ordering::Release);
209 }
210
211 pub unsafe fn pop(&self) -> Option<Value> {
214 let n = self.len.load(Ordering::Relaxed);
215 if n == 0 {
216 return None;
217 }
218 let slot = &self.slots()[n - 1];
219 let v = Value(slot.load(Ordering::Relaxed));
220 self.len.store(n - 1, Ordering::Release);
221 slot.store(Value::NIL.0, Ordering::Release);
222 Some(v)
223 }
224
225 pub unsafe fn replace(&self, items: &[Value], access: Access) {
230 let old_len = self.len.load(Ordering::Relaxed);
231 let n = items.len();
232 if n > self.capacity() {
233 let buf = WordBuf::alloc(n.max(4), Value::NIL.0);
234 let slots = WordBuf::slots(buf);
235 for (s, v) in slots.iter().zip(items) {
236 s.store(v.0, Ordering::Relaxed);
237 }
238 self.swap_buf(buf, access);
239 self.len.store(n, Ordering::Release);
240 return;
241 }
242 let slots = self.slots();
243 if n < old_len {
244 self.len.store(n, Ordering::Release);
245 }
246 for (s, v) in slots.iter().zip(items) {
247 s.store(v.0, Ordering::Release);
248 }
249 for s in &slots[n..old_len.max(n)] {
250 s.store(Value::NIL.0, Ordering::Release);
251 }
252 if n >= old_len {
253 self.len.store(n, Ordering::Release);
254 }
255 }
256
257 pub unsafe fn modify<R>(&self, access: Access, f: impl FnOnce(&mut Vec<Value>) -> R) -> R {
262 let mut items = self.to_vec();
263 let r = f(&mut items);
264 self.replace(&items, access);
265 r
266 }
267
268 unsafe fn grow(&self, need: usize, access: Access) {
269 let n = self.len.load(Ordering::Relaxed);
270 let cap = need.max(self.capacity() * 2).max(4);
271 let buf = WordBuf::alloc(cap, Value::NIL.0);
272 let new = WordBuf::slots(buf);
273 for (d, s) in new.iter().zip(&self.slots()[..n]) {
274 d.store(s.load(Ordering::Relaxed), Ordering::Relaxed);
275 }
276 self.swap_buf(buf, access);
277 }
278
279 unsafe fn swap_buf(&self, buf: *mut WordBuf, access: Access) {
280 let old = self.buf.swap(buf, Ordering::AcqRel);
281 crate::buf::release(old, access);
282 }
283}
284
285#[repr(C)]
286pub struct DictObj {
287 pub header: Header,
288 pub table: DictTable,
289}
290
291impl DictObj {
292 #[inline(always)]
294 pub fn table(&self) -> &DictTable {
295 &self.table
296 }
297}
298
299#[repr(C)]
300pub struct TupleObj {
301 pub header: Header,
302 pub len: usize,
303 elems: [Value; 0],
304}
305
306impl TupleObj {
307 pub fn elems(&self) -> &[Value] {
308 unsafe { std::slice::from_raw_parts(self.elems.as_ptr(), self.len) }
309 }
310 pub(crate) fn elems_mut(&mut self) -> *mut Value {
311 self.elems.as_mut_ptr()
312 }
313 pub fn size_for(n: usize) -> usize {
314 std::mem::size_of::<TupleObj>() + 8 * n
315 }
316}
317
318#[repr(C)]
319pub struct ClosureObj {
320 pub header: Header,
321 pub func: u32,
322 pub ncaps: u32,
323 caps: [Value; 0],
324}
325
326impl ClosureObj {
327 pub fn caps(&self) -> &[Value] {
328 unsafe { std::slice::from_raw_parts(self.caps.as_ptr(), self.ncaps as usize) }
329 }
330 pub(crate) fn caps_mut(&mut self) -> *mut Value {
331 self.caps.as_mut_ptr()
332 }
333 pub fn size_for(n: usize) -> usize {
334 std::mem::size_of::<ClosureObj>() + 8 * n
335 }
336}
337
338#[repr(C)]
339pub struct CellObj {
340 pub header: Header,
341 pub value: AtomicU64,
342}
343
344#[repr(C)]
345pub struct StringBuilderObj {
346 pub header: Header,
347 pub buf: UnsafeCell<String>,
348}
349
350#[repr(C)]
351pub struct MutexObj {
352 pub header: Header,
353 pub raw: parking_lot::ReentrantMutex<()>,
354 pub value: AtomicU64,
355}
356
357#[repr(C)]
358pub struct AtomicObj {
359 pub header: Header,
360 pub value: AtomicU64,
361}
362
363pub struct ChannelInner {
364 pub queue: parking_lot::Mutex<ChannelState>,
365 pub not_empty: parking_lot::Condvar,
366 pub not_full: parking_lot::Condvar,
367 pub capacity: usize,
368 pub waiters: parking_lot::Mutex<Vec<Wake>>,
371}
372
373pub type Wake = std::sync::Arc<dyn Fn() + Send + Sync>;
375
376impl ChannelInner {
377 pub fn wake_fibers(&self) {
379 let ws = std::mem::take(&mut *self.waiters.lock());
380 for w in ws {
381 w();
382 }
383 }
384}
385
386pub struct ChannelState {
387 pub items: std::collections::VecDeque<Value>,
388 pub closed: bool,
389}
390
391#[repr(C)]
392pub struct ChannelObj {
393 pub header: Header,
394 pub inner: Box<ChannelInner>,
395}
396
397pub enum ThreadOutcome {
399 Running,
400 Done(Value),
401 Panicked(String),
402 Joined,
403}
404
405pub struct ThreadInner {
406 pub outcome: parking_lot::Mutex<ThreadOutcome>,
407 pub done: parking_lot::Condvar,
408 pub handle: parking_lot::Mutex<Option<std::thread::JoinHandle<()>>>,
409 pub tid: AtomicU64,
411}
412
413#[repr(C)]
414pub struct ThreadObj {
415 pub header: Header,
416 pub inner: std::sync::Arc<ThreadInner>,
417}
418
419pub trait NativeData: std::any::Any + Send + Sync {
420 fn as_any(&self) -> &dyn std::any::Any;
421}
422impl<T: std::any::Any + Send + Sync> NativeData for T {
423 fn as_any(&self) -> &dyn std::any::Any {
424 self
425 }
426}
427
428#[repr(C)]
429pub struct NativeObj {
430 pub header: Header,
431 pub data: Box<dyn NativeData>,
432}
433
434unsafe fn trace_nothing(_: *const Header, _: &mut Tracer) {}
438
439unsafe fn trace_instance(h: *const Header, t: &mut Tracer) {
440 let o = &*(h as *const InstanceObj);
441 for i in 0..heap_class(h).nfields() {
442 mark_value(t, o.get(i));
443 }
444}
445unsafe fn size_instance(h: *const Header) -> usize {
446 InstanceObj::size_for(heap_class(h).nfields())
447}
448
449unsafe fn size_str(h: *const Header) -> usize {
450 StrObj::BASE + (*(h as *const StrObj)).len
451}
452
453unsafe fn fin_bigint(h: *mut Header) {
454 std::ptr::drop_in_place(&mut (*(h as *mut BigIntObj)).value);
455}
456unsafe fn size_bigint(h: *const Header) -> usize {
457 std::mem::size_of::<BigIntObj>() + (*(h as *const BigIntObj)).value.bits() as usize / 8
458}
459
460unsafe fn trace_list(h: *const Header, t: &mut Tracer) {
461 for s in (*(h as *const ListObj)).slots() {
463 mark_value(t, Value(s.load(Ordering::Relaxed)));
464 }
465}
466unsafe fn fin_list(h: *mut Header) {
467 WordBuf::free(*(*(h as *mut ListObj)).buf.get_mut() as *mut u8);
468}
469unsafe fn size_list(h: *const Header) -> usize {
470 std::mem::size_of::<ListObj>() + 8 * (*(h as *const ListObj)).capacity()
471}
472
473unsafe fn trace_dict(h: *const Header, t: &mut Tracer) {
474 (*(h as *const DictObj)).table.trace(t);
475}
476unsafe fn fin_dict(h: *mut Header) {
477 std::ptr::drop_in_place(&mut (*(h as *mut DictObj)).table);
478}
479unsafe fn size_dict(h: *const Header) -> usize {
480 std::mem::size_of::<DictObj>() + (*(h as *const DictObj)).table.heap_bytes()
481}
482
483unsafe fn trace_tuple(h: *const Header, t: &mut Tracer) {
484 for &v in (*(h as *const TupleObj)).elems() {
485 mark_value(t, v);
486 }
487}
488unsafe fn size_tuple(h: *const Header) -> usize {
489 TupleObj::size_for((*(h as *const TupleObj)).len)
490}
491
492unsafe fn trace_closure(h: *const Header, t: &mut Tracer) {
493 for &v in (*(h as *const ClosureObj)).caps() {
494 mark_value(t, v);
495 }
496}
497unsafe fn size_closure(h: *const Header) -> usize {
498 ClosureObj::size_for((*(h as *const ClosureObj)).ncaps as usize)
499}
500
501unsafe fn trace_cell(h: *const Header, t: &mut Tracer) {
502 mark_value(t, Value((*(h as *const CellObj)).value.load(Ordering::Relaxed)));
503}
504unsafe fn size_cell(_: *const Header) -> usize {
505 std::mem::size_of::<CellObj>()
506}
507
508unsafe fn fin_sb(h: *mut Header) {
509 std::ptr::drop_in_place((*(h as *mut StringBuilderObj)).buf.get());
510}
511unsafe fn size_sb(h: *const Header) -> usize {
512 std::mem::size_of::<StringBuilderObj>() + (*(*(h as *const StringBuilderObj)).buf.get()).capacity()
513}
514
515unsafe fn trace_mutex(h: *const Header, t: &mut Tracer) {
516 mark_value(t, Value((*(h as *const MutexObj)).value.load(Ordering::Relaxed)));
517}
518unsafe fn fin_mutex(h: *mut Header) {
519 std::ptr::drop_in_place(&mut (*(h as *mut MutexObj)).raw);
520}
521unsafe fn size_mutex(_: *const Header) -> usize {
522 std::mem::size_of::<MutexObj>()
523}
524
525unsafe fn trace_atomic(h: *const Header, t: &mut Tracer) {
526 mark_value(t, Value((*(h as *const AtomicObj)).value.load(Ordering::Relaxed)));
527}
528unsafe fn size_atomic(_: *const Header) -> usize {
529 std::mem::size_of::<AtomicObj>()
530}
531
532unsafe fn trace_channel(h: *const Header, t: &mut Tracer) {
533 let inner = &(*(h as *const ChannelObj)).inner;
535 let q = inner.queue.data_ptr();
536 for &v in (*q).items.iter() {
537 mark_value(t, v);
538 }
539}
540unsafe fn fin_channel(h: *mut Header) {
541 std::ptr::drop_in_place(&mut (*(h as *mut ChannelObj)).inner);
542}
543unsafe fn size_channel(h: *const Header) -> usize {
544 std::mem::size_of::<ChannelObj>() + 8 * (*(*(h as *const ChannelObj)).inner.queue.data_ptr()).items.capacity()
545}
546
547unsafe fn trace_thread(h: *const Header, t: &mut Tracer) {
548 let inner = &(*(h as *const ThreadObj)).inner;
549 if let ThreadOutcome::Done(v) = &*inner.outcome.data_ptr() {
550 mark_value(t, *v);
551 }
552}
553unsafe fn fin_thread(h: *mut Header) {
554 std::ptr::drop_in_place(&mut (*(h as *mut ThreadObj)).inner);
555}
556unsafe fn size_thread(_: *const Header) -> usize {
557 std::mem::size_of::<ThreadObj>() + 128
558}
559
560unsafe fn fin_native(h: *mut Header) {
561 std::ptr::drop_in_place(&mut (*(h as *mut NativeObj)).data);
562}
563unsafe fn size_native(_: *const Header) -> usize {
564 std::mem::size_of::<NativeObj>()
565}
566
567unsafe fn size_zero(_: *const Header) -> usize {
568 0
569}
570
571#[allow(clippy::type_complexity)]
572pub(crate) fn vtable_for(kind: ObjKind) -> GcVTable {
573 let (trace, finalize, size): (
574 unsafe fn(*const Header, &mut Tracer),
575 Option<unsafe fn(*mut Header)>,
576 unsafe fn(*const Header) -> usize,
577 ) = match kind {
578 ObjKind::Immediate => (trace_nothing, None, size_zero),
579 ObjKind::Instance => (trace_instance, None, size_instance),
580 ObjKind::Str => (trace_nothing, None, size_str),
581 ObjKind::BigInt => (trace_nothing, Some(fin_bigint), size_bigint),
582 ObjKind::List => (trace_list, Some(fin_list), size_list),
583 ObjKind::Dict | ObjKind::Set => (trace_dict, Some(fin_dict), size_dict),
584 ObjKind::Tuple => (trace_tuple, None, size_tuple),
585 ObjKind::Closure => (trace_closure, None, size_closure),
586 ObjKind::Cell => (trace_cell, None, size_cell),
587 ObjKind::StringBuilder => (trace_nothing, Some(fin_sb), size_sb),
588 ObjKind::Mutex => (trace_mutex, Some(fin_mutex), size_mutex),
589 ObjKind::Atomic => (trace_atomic, None, size_atomic),
590 ObjKind::Channel => (trace_channel, Some(fin_channel), size_channel),
591 ObjKind::Thread => (trace_thread, Some(fin_thread), size_thread),
592 ObjKind::Native => (trace_nothing, Some(fin_native), size_native),
593 };
594 GcVTable { trace, finalize, size }
595}
596
597macro_rules! view {
601 ($fn:ident, $ty:ty) => {
602 #[inline(always)]
605 pub unsafe fn $fn<'a>(v: Value) -> &'a $ty {
606 &*(v.as_ptr() as *const $ty)
607 }
608 };
609}
610view!(as_instance, InstanceObj);
611view!(as_str_obj, StrObj);
612view!(as_bigint, BigIntObj);
613view!(as_list, ListObj);
614view!(as_dict, DictObj);
615view!(as_tuple, TupleObj);
616view!(as_closure, ClosureObj);
617view!(as_cell, CellObj);
618view!(as_sb, StringBuilderObj);
619view!(as_mutex, MutexObj);
620view!(as_atomic, AtomicObj);
621view!(as_channel, ChannelObj);
622view!(as_thread, ThreadObj);
623view!(as_native, NativeObj);
624
625#[inline]
627pub fn kind_of(v: Value) -> ObjKind {
628 if v.is_ptr() {
629 unsafe { heap_class(v.as_ptr()).kind }
630 } else {
631 ObjKind::Immediate
632 }
633}
634
635#[inline]
637pub fn str_of<'a>(v: Value) -> Option<&'a str> {
638 if kind_of(v) == ObjKind::Str {
639 Some(unsafe { as_str_obj(v) }.as_str())
640 } else {
641 None
642 }
643}