1use std::sync::atomic::AtomicU64;
5use std::sync::Arc;
6
7unsafe impl Send for Mutator {}
9
10use catallaxy_gc::{Header, LocalHeap, ObjState, ThreadRecord};
11use num_bigint::BigInt;
12use num_traits::ToPrimitive;
13
14use crate::class::{Class, BUILTINS};
15use crate::dict::DictTable;
16use crate::object::*;
17use crate::value::{fits_small, Value};
18
19#[derive(Debug)]
21pub enum Trap {
22 Panic(String),
24 Unwind { frame: u64, kind: u8, value: Value },
26 Exit(i32),
28}
29
30pub type RtResult<T> = Result<T, Trap>;
31
32pub fn panic<T>(msg: impl Into<String>) -> RtResult<T> {
33 Err(Trap::Panic(msg.into()))
34}
35
36pub struct Mutator {
37 pub tid: u16,
38 pub rec: Arc<ThreadRecord>,
39 heap: *mut LocalHeap,
42 handles: *mut Vec<Value>,
45}
46
47#[derive(Copy, Clone)]
49pub struct Handle(usize);
50
51impl Mutator {
52 pub fn new(rec: Arc<ThreadRecord>) -> Self {
54 let heap = Box::into_raw(Box::new(LocalHeap::new(rec.tid)));
55 let handles = Box::into_raw(Box::new(Vec::new()));
56 Mutator { tid: rec.tid, rec, heap, handles }
57 }
58
59 pub fn set_young_alloc(&mut self, on: bool) {
61 unsafe { (*self.heap).set_young_alloc(on) }
62 }
63
64 pub fn sharing(other: &Mutator) -> Self {
67 Mutator { tid: other.tid, rec: other.rec.clone(), heap: other.heap, handles: Box::into_raw(Box::new(Vec::new())) }
68 }
69
70 pub unsafe fn free_handles(&mut self) {
75 drop(Box::from_raw(self.handles));
76 self.handles = std::ptr::null_mut();
77 }
78
79 pub fn heap_ptr(&self) -> *mut LocalHeap {
81 self.heap
82 }
83
84 pub fn release_pages(&mut self) {
86 unsafe { (*self.heap).release_pages() }
90 }
91
92 pub fn scope<R>(&mut self, f: impl FnOnce(&mut Mutator) -> R) -> R {
96 let base = self.handles_len();
97 let r = f(self);
98 unsafe { (*self.handles).truncate(base) };
100 r
101 }
102 pub fn root(&mut self, v: Value) -> Handle {
103 unsafe {
104 (*self.handles).push(v);
105 Handle((*self.handles).len() - 1)
106 }
107 }
108 pub fn get(&self, h: Handle) -> Value {
109 unsafe { (&(*self.handles))[h.0] }
110 }
111 pub fn set(&mut self, h: Handle, v: Value) {
112 unsafe { (&mut (*self.handles))[h.0] = v };
113 }
114 fn handles_len(&self) -> usize {
115 unsafe { (*self.handles).len() }
116 }
117 pub fn handle_mark(&self) -> usize {
120 self.handles_len()
121 }
122 pub fn release_handles(&mut self, mark: usize) {
124 unsafe { (*self.handles).truncate(mark) };
125 }
126 pub fn handle_values(&self) -> &[Value] {
128 unsafe { &*self.handles }
129 }
130 pub fn handles_ptr(&self) -> *const Vec<Value> {
132 self.handles
133 }
134
135 #[inline]
138 pub fn alloc_raw(&mut self, size: usize, cls: &'static Class) -> *mut Header {
139 unsafe { (*self.heap).alloc(size, &cls.gc as *const _) }
141 }
142
143 pub fn alloc_instance(&mut self, cls: &'static Class) -> Value {
144 let n = cls.nfields();
145 let h = self.alloc_raw(InstanceObj::size_for(n), cls);
146 let inst = unsafe { &*(h as *const InstanceObj) };
147 for i in 0..n {
148 inst.set(i, Value::NIL);
149 }
150 Value::from_ptr(h)
151 }
152
153 pub fn alloc_str(&mut self, s: &str) -> Value {
154 let h = self.alloc_raw(StrObj::BASE + s.len(), BUILTINS.string);
155 unsafe {
156 let o = &mut *(h as *mut StrObj);
157 o.len = s.len();
158 std::ptr::copy_nonoverlapping(s.as_ptr(), o.data_ptr(), s.len());
159 (*h).set_state(ObjState::Frozen);
160 }
161 Value::from_ptr(h)
162 }
163
164 pub fn int_from_big(&mut self, b: BigInt) -> Value {
166 if let Some(i) = b.to_i64() {
167 if fits_small(i) {
168 return Value::small_int(i);
169 }
170 }
171 let h = self.alloc_raw(std::mem::size_of::<BigIntObj>(), BUILTINS.bigint);
172 unsafe {
173 std::ptr::write(&mut (*(h as *mut BigIntObj)).value, b);
174 (*h).set_state(ObjState::Frozen);
175 }
176 Value::from_ptr(h)
177 }
178
179 #[inline]
180 pub fn int(&mut self, i: i64) -> Value {
181 if fits_small(i) {
182 Value::small_int(i)
183 } else {
184 self.int_from_big(BigInt::from(i))
185 }
186 }
187
188 pub fn alloc_list(&mut self, items: Vec<Value>) -> Value {
189 let h = self.alloc_raw(std::mem::size_of::<ListObj>(), BUILTINS.list);
190 unsafe { ListObj::init(h as *mut ListObj, items) };
191 Value::from_ptr(h)
192 }
193
194 pub fn alloc_dict(&mut self, table: DictTable) -> Value {
195 self.alloc_table(table, BUILTINS.dict)
196 }
197
198 pub fn alloc_set(&mut self, table: DictTable) -> Value {
199 self.alloc_table(table, BUILTINS.set)
200 }
201
202 fn alloc_table(&mut self, table: DictTable, cls: &'static Class) -> Value {
203 let h = self.alloc_raw(std::mem::size_of::<DictObj>(), cls);
204 unsafe { std::ptr::write(std::ptr::addr_of_mut!((*(h as *mut DictObj)).table), table) };
205 Value::from_ptr(h)
206 }
207
208 pub fn alloc_tuple(&mut self, items: &[Value]) -> Value {
209 let h = self.alloc_raw(TupleObj::size_for(items.len()), BUILTINS.tuple);
210 unsafe {
211 let t = &mut *(h as *mut TupleObj);
212 t.len = items.len();
213 std::ptr::copy_nonoverlapping(items.as_ptr(), t.elems_mut(), items.len());
214 }
215 Value::from_ptr(h)
216 }
217
218 pub fn alloc_closure(&mut self, func: u32, caps: &[Value]) -> Value {
219 let h = self.alloc_raw(ClosureObj::size_for(caps.len()), BUILTINS.closure);
220 unsafe {
221 let c = &mut *(h as *mut ClosureObj);
222 c.func = func;
223 c.ncaps = caps.len() as u32;
224 std::ptr::copy_nonoverlapping(caps.as_ptr(), c.caps_mut(), caps.len());
225 }
226 Value::from_ptr(h)
227 }
228
229 pub fn alloc_cell(&mut self, v: Value) -> Value {
230 let h = self.alloc_raw(std::mem::size_of::<CellObj>(), BUILTINS.cell);
231 unsafe { (*(h as *mut CellObj)).value = AtomicU64::new(v.0) };
232 Value::from_ptr(h)
233 }
234
235 pub fn alloc_string_builder(&mut self, s: String) -> Value {
236 let h = self.alloc_raw(std::mem::size_of::<StringBuilderObj>(), BUILTINS.string_builder);
237 unsafe { std::ptr::write((*(h as *mut StringBuilderObj)).buf.get(), s) };
238 Value::from_ptr(h)
239 }
240
241 pub fn alloc_mutex(&mut self, v: Value) -> Value {
242 let h = self.alloc_raw(std::mem::size_of::<MutexObj>(), BUILTINS.mutex);
243 unsafe {
244 std::ptr::write(&mut (*(h as *mut MutexObj)).raw, parking_lot::ReentrantMutex::new(()));
245 (*(h as *mut MutexObj)).value = AtomicU64::new(v.0);
246 (*h).set_state(ObjState::Shared);
247 }
248 Value::from_ptr(h)
249 }
250
251 pub fn alloc_atomic(&mut self, v: Value) -> Value {
252 let h = self.alloc_raw(std::mem::size_of::<AtomicObj>(), BUILTINS.atomic);
253 unsafe {
254 (*(h as *mut AtomicObj)).value = AtomicU64::new(v.0);
255 (*h).set_state(ObjState::Shared);
256 }
257 Value::from_ptr(h)
258 }
259
260 pub fn alloc_channel(&mut self, capacity: usize) -> Value {
261 let h = self.alloc_raw(std::mem::size_of::<ChannelObj>(), BUILTINS.channel);
262 let inner = Box::new(ChannelInner {
263 queue: parking_lot::Mutex::new(ChannelState { items: Default::default(), closed: false }),
264 not_empty: parking_lot::Condvar::new(),
265 not_full: parking_lot::Condvar::new(),
266 capacity,
267 waiters: parking_lot::Mutex::new(Vec::new()),
268 });
269 unsafe {
270 std::ptr::write(&mut (*(h as *mut ChannelObj)).inner, inner);
271 (*h).set_state(ObjState::Shared);
272 }
273 Value::from_ptr(h)
274 }
275
276 pub fn alloc_thread(&mut self) -> Value {
277 let h = self.alloc_raw(std::mem::size_of::<ThreadObj>(), BUILTINS.thread);
278 let inner = std::sync::Arc::new(ThreadInner {
279 outcome: parking_lot::Mutex::new(ThreadOutcome::Running),
280 done: parking_lot::Condvar::new(),
281 handle: parking_lot::Mutex::new(None),
282 tid: AtomicU64::new(0),
283 });
284 unsafe {
285 std::ptr::write(&mut (*(h as *mut ThreadObj)).inner, inner);
286 (*h).set_state(ObjState::Shared);
287 }
288 Value::from_ptr(h)
289 }
290
291 pub fn alloc_native(&mut self, data: Box<dyn NativeData>) -> Value {
292 let h = self.alloc_raw(std::mem::size_of::<NativeObj>(), BUILTINS.native);
293 unsafe { std::ptr::write(&mut (*(h as *mut NativeObj)).data, data) };
294 Value::from_ptr(h)
295 }
296
297 pub fn alloc_range(&mut self, first: Value, last: Value, exclusive: bool) -> Value {
298 let v = self.alloc_instance(BUILTINS.range);
299 let r = unsafe { as_instance(v) };
300 r.set(0, first);
301 r.set(1, last);
302 r.set(2, Value::bool(exclusive));
303 unsafe { (*v.as_ptr()).set_state(ObjState::Frozen) };
304 v
305 }
306}
307
308pub fn note_external(bytes: usize) {
310 if bytes > 0 {
311 catallaxy_gc::stats::note_allocated(bytes);
312 }
313}
314
315pub struct HandleScope<'m> {
326 m: *mut Mutator,
327 base: usize,
328 _borrow: std::marker::PhantomData<&'m mut Mutator>,
329}
330
331#[derive(Copy, Clone)]
333pub struct Local<'s> {
334 index: usize,
335 _scope: std::marker::PhantomData<&'s ()>,
336}
337
338impl<'m> HandleScope<'m> {
339 pub fn new(m: &'m mut Mutator) -> Self {
340 let base = m.handles_len();
341 HandleScope { m, base, _borrow: std::marker::PhantomData }
342 }
343
344 pub unsafe fn detached(m: *mut Mutator) -> HandleScope<'static> {
350 let base = (*m).handles_len();
351 HandleScope { m, base, _borrow: std::marker::PhantomData }
352 }
353
354 pub fn root<'s>(&'s self, v: Value) -> Local<'s> {
356 let hs = unsafe { &mut *(*self.m).handles };
359 hs.push(v);
360 Local { index: hs.len() - 1, _scope: std::marker::PhantomData }
361 }
362
363 pub fn get(&self, h: Local<'_>) -> Value {
364 unsafe { (&(*(*self.m).handles))[h.index] }
365 }
366
367 pub fn set(&self, h: Local<'_>, v: Value) {
368 unsafe { (&mut (*(*self.m).handles))[h.index] = v }
369 }
370
371 #[allow(clippy::mut_from_ref)]
373 pub fn mutator(&self) -> &mut Mutator {
374 unsafe { &mut *self.m }
375 }
376}
377
378impl Drop for HandleScope<'_> {
379 fn drop(&mut self) {
380 unsafe { (*(*self.m).handles).truncate(self.base) };
381 }
382}