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 heap_ptr(&self) -> *mut LocalHeap {
61 self.heap
62 }
63
64 pub fn release_pages(&mut self) {
66 unsafe { (*self.heap).release_pages() }
70 }
71
72 pub fn scope<R>(&mut self, f: impl FnOnce(&mut Mutator) -> R) -> R {
76 let base = self.handles_len();
77 let r = f(self);
78 unsafe { (*self.handles).truncate(base) };
80 r
81 }
82 pub fn root(&mut self, v: Value) -> Handle {
83 unsafe {
84 (*self.handles).push(v);
85 Handle((*self.handles).len() - 1)
86 }
87 }
88 pub fn get(&self, h: Handle) -> Value {
89 unsafe { (&(*self.handles))[h.0] }
90 }
91 pub fn set(&mut self, h: Handle, v: Value) {
92 unsafe { (&mut (*self.handles))[h.0] = v };
93 }
94 fn handles_len(&self) -> usize {
95 unsafe { (*self.handles).len() }
96 }
97 pub fn handle_values(&self) -> &[Value] {
99 unsafe { &*self.handles }
100 }
101 pub fn handles_ptr(&self) -> *const Vec<Value> {
103 self.handles
104 }
105
106 #[inline]
109 pub fn alloc_raw(&mut self, size: usize, cls: &'static Class) -> *mut Header {
110 unsafe { (*self.heap).alloc(size, &cls.gc as *const _) }
112 }
113
114 pub fn alloc_instance(&mut self, cls: &'static Class) -> Value {
115 let n = cls.nfields();
116 let h = self.alloc_raw(InstanceObj::size_for(n), cls);
117 let inst = unsafe { &*(h as *const InstanceObj) };
118 for i in 0..n {
119 inst.set(i, Value::NIL);
120 }
121 Value::from_ptr(h)
122 }
123
124 pub fn alloc_str(&mut self, s: &str) -> Value {
125 let h = self.alloc_raw(StrObj::BASE + s.len(), BUILTINS.string);
126 unsafe {
127 let o = &mut *(h as *mut StrObj);
128 o.len = s.len();
129 std::ptr::copy_nonoverlapping(s.as_ptr(), o.data_ptr(), s.len());
130 (*h).set_state(ObjState::Frozen);
131 }
132 Value::from_ptr(h)
133 }
134
135 pub fn int_from_big(&mut self, b: BigInt) -> Value {
137 if let Some(i) = b.to_i64() {
138 if fits_small(i) {
139 return Value::small_int(i);
140 }
141 }
142 let h = self.alloc_raw(std::mem::size_of::<BigIntObj>(), BUILTINS.bigint);
143 unsafe {
144 std::ptr::write(&mut (*(h as *mut BigIntObj)).value, b);
145 (*h).set_state(ObjState::Frozen);
146 }
147 Value::from_ptr(h)
148 }
149
150 #[inline]
151 pub fn int(&mut self, i: i64) -> Value {
152 if fits_small(i) {
153 Value::small_int(i)
154 } else {
155 self.int_from_big(BigInt::from(i))
156 }
157 }
158
159 pub fn alloc_list(&mut self, items: Vec<Value>) -> Value {
160 crate::note_external(items.capacity() * 8);
161 let h = self.alloc_raw(std::mem::size_of::<ListObj>(), BUILTINS.list);
162 unsafe { ListObj::init(h as *mut ListObj, items) };
163 Value::from_ptr(h)
164 }
165
166 pub fn alloc_dict(&mut self, table: DictTable) -> Value {
167 self.alloc_table(table, BUILTINS.dict)
168 }
169
170 pub fn alloc_set(&mut self, table: DictTable) -> Value {
171 self.alloc_table(table, BUILTINS.set)
172 }
173
174 fn alloc_table(&mut self, table: DictTable, cls: &'static Class) -> Value {
175 crate::note_external(table.heap_bytes());
176 let h = self.alloc_raw(std::mem::size_of::<DictObj>(), cls);
177 unsafe { std::ptr::write((*(h as *mut DictObj)).table.get(), table) };
178 Value::from_ptr(h)
179 }
180
181 pub fn alloc_tuple(&mut self, items: &[Value]) -> Value {
182 let h = self.alloc_raw(TupleObj::size_for(items.len()), BUILTINS.tuple);
183 unsafe {
184 let t = &mut *(h as *mut TupleObj);
185 t.len = items.len();
186 std::ptr::copy_nonoverlapping(items.as_ptr(), t.elems_mut(), items.len());
187 }
188 Value::from_ptr(h)
189 }
190
191 pub fn alloc_closure(&mut self, func: u32, caps: &[Value]) -> Value {
192 let h = self.alloc_raw(ClosureObj::size_for(caps.len()), BUILTINS.closure);
193 unsafe {
194 let c = &mut *(h as *mut ClosureObj);
195 c.func = func;
196 c.ncaps = caps.len() as u32;
197 std::ptr::copy_nonoverlapping(caps.as_ptr(), c.caps_mut(), caps.len());
198 }
199 Value::from_ptr(h)
200 }
201
202 pub fn alloc_cell(&mut self, v: Value) -> Value {
203 let h = self.alloc_raw(std::mem::size_of::<CellObj>(), BUILTINS.cell);
204 unsafe { (*(h as *mut CellObj)).value = AtomicU64::new(v.0) };
205 Value::from_ptr(h)
206 }
207
208 pub fn alloc_string_builder(&mut self, s: String) -> Value {
209 let h = self.alloc_raw(std::mem::size_of::<StringBuilderObj>(), BUILTINS.string_builder);
210 unsafe { std::ptr::write((*(h as *mut StringBuilderObj)).buf.get(), s) };
211 Value::from_ptr(h)
212 }
213
214 pub fn alloc_mutex(&mut self, v: Value) -> Value {
215 let h = self.alloc_raw(std::mem::size_of::<MutexObj>(), BUILTINS.mutex);
216 unsafe {
217 std::ptr::write(&mut (*(h as *mut MutexObj)).raw, parking_lot::ReentrantMutex::new(()));
218 (*(h as *mut MutexObj)).value = AtomicU64::new(v.0);
219 (*h).set_state(ObjState::Shared);
220 }
221 Value::from_ptr(h)
222 }
223
224 pub fn alloc_atomic(&mut self, v: Value) -> Value {
225 let h = self.alloc_raw(std::mem::size_of::<AtomicObj>(), BUILTINS.atomic);
226 unsafe {
227 (*(h as *mut AtomicObj)).value = AtomicU64::new(v.0);
228 (*h).set_state(ObjState::Shared);
229 }
230 Value::from_ptr(h)
231 }
232
233 pub fn alloc_channel(&mut self, capacity: usize) -> Value {
234 let h = self.alloc_raw(std::mem::size_of::<ChannelObj>(), BUILTINS.channel);
235 let inner = Box::new(ChannelInner {
236 queue: parking_lot::Mutex::new(ChannelState { items: Default::default(), closed: false }),
237 not_empty: parking_lot::Condvar::new(),
238 not_full: parking_lot::Condvar::new(),
239 capacity,
240 });
241 unsafe {
242 std::ptr::write(&mut (*(h as *mut ChannelObj)).inner, inner);
243 (*h).set_state(ObjState::Shared);
244 }
245 Value::from_ptr(h)
246 }
247
248 pub fn alloc_thread(&mut self) -> Value {
249 let h = self.alloc_raw(std::mem::size_of::<ThreadObj>(), BUILTINS.thread);
250 let inner = std::sync::Arc::new(ThreadInner {
251 outcome: parking_lot::Mutex::new(ThreadOutcome::Running),
252 done: parking_lot::Condvar::new(),
253 handle: parking_lot::Mutex::new(None),
254 tid: AtomicU64::new(0),
255 });
256 unsafe {
257 std::ptr::write(&mut (*(h as *mut ThreadObj)).inner, inner);
258 (*h).set_state(ObjState::Shared);
259 }
260 Value::from_ptr(h)
261 }
262
263 pub fn alloc_native(&mut self, data: Box<dyn NativeData>) -> Value {
264 let h = self.alloc_raw(std::mem::size_of::<NativeObj>(), BUILTINS.native);
265 unsafe { std::ptr::write(&mut (*(h as *mut NativeObj)).data, data) };
266 Value::from_ptr(h)
267 }
268
269 pub fn alloc_range(&mut self, first: Value, last: Value, exclusive: bool) -> Value {
270 let v = self.alloc_instance(BUILTINS.range);
271 let r = unsafe { as_instance(v) };
272 r.set(0, first);
273 r.set(1, last);
274 r.set(2, Value::bool(exclusive));
275 unsafe { (*v.as_ptr()).set_state(ObjState::Frozen) };
276 v
277 }
278}
279
280pub fn note_external(bytes: usize) {
282 if bytes > 0 {
283 catallaxy_gc::stats::note_allocated(bytes);
284 }
285}
286
287pub struct HandleScope<'m> {
298 m: *mut Mutator,
299 base: usize,
300 _borrow: std::marker::PhantomData<&'m mut Mutator>,
301}
302
303#[derive(Copy, Clone)]
305pub struct Local<'s> {
306 index: usize,
307 _scope: std::marker::PhantomData<&'s ()>,
308}
309
310impl<'m> HandleScope<'m> {
311 pub fn new(m: &'m mut Mutator) -> Self {
312 let base = m.handles_len();
313 HandleScope { m, base, _borrow: std::marker::PhantomData }
314 }
315
316 pub unsafe fn detached(m: *mut Mutator) -> HandleScope<'static> {
322 let base = (*m).handles_len();
323 HandleScope { m, base, _borrow: std::marker::PhantomData }
324 }
325
326 pub fn root<'s>(&'s self, v: Value) -> Local<'s> {
328 let hs = unsafe { &mut *(*self.m).handles };
331 hs.push(v);
332 Local { index: hs.len() - 1, _scope: std::marker::PhantomData }
333 }
334
335 pub fn get(&self, h: Local<'_>) -> Value {
336 unsafe { (&(*(*self.m).handles))[h.index] }
337 }
338
339 pub fn set(&self, h: Local<'_>, v: Value) {
340 unsafe { (&mut (*(*self.m).handles))[h.index] = v }
341 }
342
343 #[allow(clippy::mut_from_ref)]
345 pub fn mutator(&self) -> &mut Mutator {
346 unsafe { &mut *self.m }
347 }
348}
349
350impl Drop for HandleScope<'_> {
351 fn drop(&mut self) {
352 unsafe { (*(*self.m).handles).truncate(self.base) };
353 }
354}