1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#![allow(clippy::new_ret_no_self)]
use std::{alloc::Layout, collections::hash_map::DefaultHasher, hash::Hasher, mem::size_of};
use std::gc::Gc;
use crate::vm::{
core::VM,
objects::{Class, Obj, ObjType, StaticObjType},
val::{NotUnboxable, Val, ValKind},
};
#[derive(Debug)]
pub struct Inst {
class: Val,
}
macro_rules! inst_vars {
($self:ident) => {
(Gc::into_raw($self) as *mut u8).add(::std::mem::size_of::<Inst>()) as *mut Val
};
}
impl Obj for Inst {
fn dyn_objtype(self: Gc<Self>) -> ObjType {
ObjType::Inst
}
fn get_class(self: Gc<Self>, _: &mut VM) -> Val {
self.class
}
fn num_inst_vars(self: Gc<Self>, vm: &VM) -> usize {
let cls: Gc<Class> = self.class.downcast(vm).unwrap();
cls.inst_vars_map.len()
}
unsafe fn unchecked_inst_var_get(self: Gc<Self>, vm: &VM, n: usize) -> Val {
debug_assert!(n < self.num_inst_vars(vm));
let v = inst_vars!(self).add(n).read();
debug_assert!(v.valkind() != ValKind::ILLEGAL);
v
}
unsafe fn unchecked_inst_var_set(self: Gc<Self>, vm: &VM, n: usize, v: Val) {
debug_assert!(n < self.num_inst_vars(vm));
inst_vars!(self).add(n).write(v);
}
fn hashcode(self: Gc<Self>) -> u64 {
let mut hasher = DefaultHasher::new();
hasher.write_usize(Gc::into_raw(self) as *const _ as usize);
hasher.finish()
}
}
impl NotUnboxable for Inst {}
impl StaticObjType for Inst {
fn static_objtype() -> ObjType {
ObjType::Inst
}
}
impl Inst {
pub fn new(vm: &mut VM, class: Val) -> Val {
let cls: Gc<Class> = class.downcast(vm).unwrap();
let len = cls.inst_vars_map.len();
debug_assert!(vm.nil.valkind() != ValKind::ILLEGAL || len == 0);
let (vals_layout, vals_dist) = Layout::new::<Val>().repeat(len).unwrap();
debug_assert_eq!(vals_dist, size_of::<Val>());
let (layout, inst_vars_off) = Layout::new::<Inst>().extend(vals_layout).unwrap();
debug_assert_eq!(inst_vars_off, size_of::<Inst>());
unsafe {
Val::new_from_layout(layout, |basep: *mut Inst| {
*basep = Inst { class };
let mut inst_vars = (basep as *mut u8).add(size_of::<Inst>()) as *mut Val;
for _ in 0..len {
inst_vars.write(vm.nil);
inst_vars = inst_vars.add(1);
}
})
}
}
}