]> Witch of Git - ivy/blob - rt/src/lam.rs
[rt] Split the runtime into multiple modules
[ivy] / rt / src / lam.rs
1 use crate::{sys, trace, Obj, ObjTag};
2 use std::sync::atomic::AtomicU32;
3
4 #[repr(C)]
5 pub struct ObjLam {
6 tag: ObjTag,
7 _pad: [u8; 1],
8 upvars: u16,
9 rc: AtomicU32,
10 func: extern "C" fn(&ObjLam) -> Obj,
11 params: u16,
12 filled: u16,
13 }
14
15 #[no_mangle]
16 pub unsafe extern "C" fn ivy_check_lam(obj: Obj) {
17 if !obj.is_lam() {
18 panic!(
19 "ivy_check_lam called with non-lambda object {:016x}.",
20 obj.int
21 );
22 }
23 }
24
25 #[no_mangle]
26 pub unsafe extern "C" fn ivy_make_lam(
27 func: extern "C" fn(&ObjLam) -> Obj,
28 params: u16,
29 upvars: u16,
30 ) -> Obj {
31 let size = ObjLam::size_of(params, upvars);
32 let box_lam = sys::malloc(size) as *mut ObjLam;
33 box_lam.write(ObjLam {
34 tag: ObjTag::Lam,
35 _pad: [0; 1],
36 upvars,
37 rc: AtomicU32::new(0),
38 func,
39 params,
40 filled: 0,
41 });
42 (*box_lam)
43 .raw_fields_mut()
44 .write_bytes(0, (params + upvars) as usize);
45 trace!("MAKE {:016x} {:016x}", box_lam as usize, func as usize);
46 Obj { box_lam }
47 }
48
49 #[no_mangle]
50 pub unsafe extern "C" fn ivy_app(fun: Obj, arg: Obj) -> Obj {
51 ivy_app_mut(crate::ivy_clone(fun), arg)
52 }
53
54 #[no_mangle]
55 pub unsafe extern "C" fn ivy_app_mut(fun: Obj, arg: Obj) -> Obj {
56 trace!("APP {:016x} {:016x}", fun.int, arg.int);
57 if !fun.is_lam() {
58 panic!(
59 "ivy_app called with a non-lam as the function: {:016x}.",
60 fun.int
61 );
62 }
63 let lam = &mut *fun.box_lam;
64 if lam.filled < lam.params {
65 if arg.is_null() {
66 println!(
67 "Lam @ {:016x} ({:016x}) has {} of {} arguments filled.",
68 fun.int, lam.func as usize, lam.filled, lam.params
69 );
70 panic!("ivy_app called with a null arg.");
71 }
72 arg.incref();
73 let idx = lam.filled as usize;
74 lam.params_mut()[idx] = arg;
75 lam.filled += 1;
76 } else if lam.params == lam.filled {
77 if !arg.is_null() {
78 panic!("ivy_app called for a 0-arity application with a non-null arg.");
79 }
80 }
81
82 if lam.params == lam.filled {
83 trace!("RUN {:016x}", fun.int);
84 (lam.func)(lam)
85 } else {
86 trace!("UPD8 {:016x}", fun.int);
87 fun.incref();
88 fun
89 }
90 }
91
92 impl ObjLam {
93 pub(crate) fn size_of(params: u16, upvars: u16) -> usize {
94 core::mem::size_of::<ObjLam>() + params as usize * 8 + upvars as usize * 8
95 }
96
97 pub(crate) fn size(&self) -> usize {
98 ObjLam::size_of(self.params, self.upvars)
99 }
100
101 pub(crate) unsafe fn raw_fields_mut(&mut self) -> *mut Obj {
102 (self as *mut ObjLam).add(1) as *mut Obj
103 }
104
105 pub(crate) unsafe fn params_mut(&mut self) -> &mut [Obj] {
106 let ptr = self.raw_fields_mut();
107 core::slice::from_raw_parts_mut(ptr, self.params as usize)
108 }
109
110 pub(crate) unsafe fn upvars_mut(&mut self) -> &mut [Obj] {
111 let ptr = self.raw_fields_mut().add(self.params as usize);
112 core::slice::from_raw_parts_mut(ptr, self.upvars as usize)
113 }
114 }