diff --git a/.buildbot.sh b/.buildbot.sh index f7697b77..818219e1 100644 --- a/.buildbot.sh +++ b/.buildbot.sh @@ -9,20 +9,13 @@ export CARGO_HOME="`pwd`/.cargo" export RUSTUP_HOME="`pwd`/.rustup" curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh -sh rustup.sh --default-host x86_64-unknown-linux-gnu --default-toolchain nightly -y --no-modify-path +# Install no toolchain initially to ensure toolchain rollback. +sh rustup.sh --default-host x86_64-unknown-linux-gnu --default-toolchain none -y --no-modify-path export PATH=`pwd`/.cargo/bin/:$PATH +rustup install nightly -# Sometimes rustfmt is so broken that there is no way to install it at all. -# Rather than refusing to merge, we just can't rust rustfmt at such a point. -rustup component add --toolchain nightly rustfmt-preview \ - || cargo +nightly install --force rustfmt-nightly \ - || true -rustfmt=0 -cargo fmt 2>&1 | grep "not installed for the toolchain" > /dev/null || rustfmt=1 -if [ $rustfmt -eq 1 ]; then - cargo +nightly fmt --all -- --check -fi +cargo +nightly fmt --all -- --check cargo test cargo test --release diff --git a/src/lib/mod.rs b/src/lib/mod.rs index 9975297c..4570f477 100644 --- a/src/lib/mod.rs +++ b/src/lib/mod.rs @@ -12,8 +12,10 @@ #![feature(alloc_layout_extra)] #![feature(allocator_api)] +#![feature(arbitrary_self_types)] #![feature(box_patterns)] #![feature(coerce_unsized)] +#![feature(dispatch_from_dyn)] #![feature(unsize)] #![allow(clippy::cognitive_complexity)] #![allow(clippy::float_cmp)] diff --git a/src/lib/vm/core.rs b/src/lib/vm/core.rs index 14a4ec14..f0f32834 100644 --- a/src/lib/vm/core.rs +++ b/src/lib/vm/core.rs @@ -494,12 +494,13 @@ impl VM { } Instr::InstVarLookup(n) => { let inst = stry!(rcv.tobj(self)); - self.stack.push(unsafe { inst.unchecked_inst_var_get(n) }); + self.stack + .push(unsafe { inst.as_gc().unchecked_inst_var_get(n) }); pc += 1; } Instr::InstVarSet(n) => { let inst = stry!(rcv.tobj(self)); - unsafe { inst.unchecked_inst_var_set(n, self.stack.peek()) }; + unsafe { inst.as_gc().unchecked_inst_var_set(n, self.stack.peek()) }; pc += 1; } Instr::Int(i) => { @@ -674,7 +675,7 @@ impl VM { } Primitive::At => { let rcv_tobj = stry!(rcv.tobj(self)); - let arr = stry!(rcv_tobj.to_array()); + let arr = stry!(rcv_tobj.as_gc().to_array()); let idx = stry!(self.stack.pop().as_usize(self)); let v = stry!(arr.at(self, idx)); self.stack.push(v); @@ -682,7 +683,7 @@ impl VM { } Primitive::AtPut => { let rcv_tobj = stry!(rcv.tobj(self)); - let arr = stry!(rcv_tobj.to_array()); + let arr = stry!(rcv_tobj.as_gc().to_array()); let v = self.stack.pop(); let idx = stry!(self.stack.pop().as_usize(self)); stry!(arr.at_put(self, idx, v)); @@ -824,7 +825,7 @@ impl VM { Primitive::InstVarAt => { let n = stry!(self.stack.pop().as_usize(self)); let inst = stry!(rcv.tobj(self)); - let v = stry!(inst.inst_var_at(self, n)); + let v = stry!(inst.as_gc().inst_var_at(self, n)); self.stack.push(v); SendReturn::Val } @@ -832,7 +833,7 @@ impl VM { let v = self.stack.pop(); let n = stry!(self.stack.pop().as_usize(self)); let inst = stry!(rcv.tobj(self)); - stry!(inst.inst_var_at_put(self, n, v)); + stry!(inst.as_gc().inst_var_at_put(self, n, v)); self.stack.push(rcv); SendReturn::Val } @@ -854,7 +855,7 @@ impl VM { // Only Arrays and Strings can have this primitive installed. debug_assert!(rcv.valkind() == ValKind::GCBOX); let tobj = rcv.tobj(self).unwrap(); - let v = Val::from_usize(self, tobj.length()); + let v = Val::from_usize(self, tobj.as_gc().length()); self.stack.push(v); SendReturn::Val } @@ -1088,17 +1089,17 @@ impl VM { } let args_tobj = stry!(args_val.tobj(self)); - let args = stry!(args_tobj.to_array()); + let args = stry!(args_tobj.as_gc().to_array()); let sig = stry!(String_::symbol_to_string_(self, sig_val)); let cls = stry!(cls_val.downcast::(self)); match cls.get_method(self, sig.as_str()) { Ok(m) => { - if args_tobj.length() != m.num_params() { + if args_tobj.as_gc().length() != m.num_params() { return SendReturn::Err(VMError::new( self, VMErrorKind::WrongNumberOfArgs { wanted: m.num_params(), - got: args_tobj.length(), + got: args_tobj.as_gc().length(), }, )); } diff --git a/src/lib/vm/objects/array.rs b/src/lib/vm/objects/array.rs index c37f5219..bd5b6aef 100644 --- a/src/lib/vm/objects/array.rs +++ b/src/lib/vm/objects/array.rs @@ -2,6 +2,8 @@ use std::{cell::UnsafeCell, collections::hash_map::DefaultHasher, hash::Hasher}; +use rboehm::Gc; + use crate::vm::{ core::VM, error::{VMError, VMErrorKind}, @@ -12,18 +14,18 @@ use crate::vm::{ pub trait Array { /// Return the item at index `idx` (using SOM indexing starting at 1) or an error if the index /// is invalid. - fn at(&self, vm: &VM, idx: usize) -> Result>; + fn at(self: Gc, vm: &VM, idx: usize) -> Result>; /// Return the item at index `idx` (using SOM indexing starting at 1). This will lead to /// undefined behaviour if the index is invalid. - unsafe fn unchecked_at(&self, idx: usize) -> Val; + unsafe fn unchecked_at(self: Gc, idx: usize) -> Val; /// Set the item at index `idx` (using SOM indexing starting at 1) to `val` or return an error /// if the index is invalid. - fn at_put(&self, vm: &mut VM, idx: usize, val: Val) -> Result<(), Box>; + fn at_put(self: Gc, vm: &mut VM, idx: usize, val: Val) -> Result<(), Box>; /// Iterate over this array's values. - fn iter(&self) -> ArrayIterator<'_>; + fn iter(self: Gc) -> ArrayIterator; } #[derive(Debug)] @@ -32,25 +34,25 @@ pub struct NormalArray { } impl Obj for NormalArray { - fn dyn_objtype(&self) -> ObjType { + fn dyn_objtype(self: Gc) -> ObjType { ObjType::Array } - fn get_class(&self, vm: &mut VM) -> Val { + fn get_class(self: Gc, vm: &mut VM) -> Val { vm.array_cls } - fn to_array(&self) -> Result<&dyn Array, Box> { + fn to_array(self: Gc) -> Result, Box> { Ok(self) } - fn hashcode(&self) -> u64 { + fn hashcode(self: Gc) -> u64 { let mut hasher = DefaultHasher::new(); - hasher.write_usize(self as *const _ as usize); + hasher.write_usize(Gc::into_raw(self) as *const _ as usize); hasher.finish() } - fn length(&self) -> usize { + fn length(self: Gc) -> usize { let store = unsafe { &*self.store.get() }; store.len() } @@ -65,7 +67,7 @@ impl StaticObjType for NormalArray { } impl Array for NormalArray { - fn at(&self, vm: &VM, mut idx: usize) -> Result> { + fn at(self: Gc, vm: &VM, mut idx: usize) -> Result> { let store = unsafe { &*self.store.get() }; if idx > 0 && idx <= store.len() { idx -= 1; @@ -81,7 +83,7 @@ impl Array for NormalArray { } } - unsafe fn unchecked_at(&self, mut idx: usize) -> Val { + unsafe fn unchecked_at(self: Gc, mut idx: usize) -> Val { debug_assert!(idx > 0); let store = &*self.store.get(); debug_assert!(idx <= store.len()); @@ -89,7 +91,7 @@ impl Array for NormalArray { *store.get_unchecked(idx) } - fn at_put(&self, vm: &mut VM, mut idx: usize, val: Val) -> Result<(), Box> { + fn at_put(self: Gc, vm: &mut VM, mut idx: usize, val: Val) -> Result<(), Box> { let store = unsafe { &mut *self.store.get() }; if idx > 0 && idx <= store.len() { idx -= 1; @@ -106,7 +108,7 @@ impl Array for NormalArray { } } - fn iter(&self) -> ArrayIterator<'_> { + fn iter(self: Gc) -> ArrayIterator { ArrayIterator { arr: self, len: self.length(), @@ -143,25 +145,25 @@ pub struct MethodsArray { } impl Obj for MethodsArray { - fn dyn_objtype(&self) -> ObjType { + fn dyn_objtype(self: Gc) -> ObjType { ObjType::Array } - fn get_class(&self, vm: &mut VM) -> Val { + fn get_class(self: Gc, vm: &mut VM) -> Val { vm.array_cls } - fn to_array(&self) -> Result<&dyn Array, Box> { + fn to_array(self: Gc) -> Result, Box> { Ok(self) } - fn hashcode(&self) -> u64 { + fn hashcode(self: Gc) -> u64 { let mut hasher = DefaultHasher::new(); - hasher.write_usize(self as *const _ as usize); + hasher.write_usize(Gc::into_raw(self) as *const _ as usize); hasher.finish() } - fn length(&self) -> usize { + fn length(self: Gc) -> usize { let store = unsafe { &*self.store.get() }; store.len() } @@ -176,7 +178,7 @@ impl StaticObjType for MethodsArray { } impl Array for MethodsArray { - fn at(&self, vm: &VM, mut idx: usize) -> Result> { + fn at(self: Gc, vm: &VM, mut idx: usize) -> Result> { let store = unsafe { &*self.store.get() }; if idx > 0 && idx <= store.len() { idx -= 1; @@ -192,7 +194,7 @@ impl Array for MethodsArray { } } - unsafe fn unchecked_at(&self, mut idx: usize) -> Val { + unsafe fn unchecked_at(self: Gc, mut idx: usize) -> Val { debug_assert!(idx > 0); let store = &*self.store.get(); debug_assert!(idx <= store.len()); @@ -200,7 +202,7 @@ impl Array for MethodsArray { *store.get_unchecked(idx) } - fn at_put(&self, vm: &mut VM, mut idx: usize, val: Val) -> Result<(), Box> { + fn at_put(self: Gc, vm: &mut VM, mut idx: usize, val: Val) -> Result<(), Box> { let store = unsafe { &mut *self.store.get() }; if idx > 0 && idx <= store.len() { idx -= 1; @@ -218,7 +220,7 @@ impl Array for MethodsArray { } } - fn iter(&self) -> ArrayIterator<'_> { + fn iter(self: Gc) -> ArrayIterator { ArrayIterator { arr: self, len: self.length(), @@ -238,13 +240,13 @@ impl MethodsArray { } } -pub struct ArrayIterator<'a> { - arr: &'a dyn Array, +pub struct ArrayIterator { + arr: Gc, len: usize, i: usize, } -impl<'a> Iterator for ArrayIterator<'a> { +impl Iterator for ArrayIterator { type Item = Val; fn next(&mut self) -> Option { diff --git a/src/lib/vm/objects/block.rs b/src/lib/vm/objects/block.rs index 8a2eb006..c7fd4cc6 100644 --- a/src/lib/vm/objects/block.rs +++ b/src/lib/vm/objects/block.rs @@ -33,17 +33,17 @@ pub struct Block { } impl Obj for Block { - fn dyn_objtype(&self) -> ObjType { + fn dyn_objtype(self: Gc) -> ObjType { ObjType::Block } - fn get_class(&self, _: &mut VM) -> Val { + fn get_class(self: Gc, _: &mut VM) -> Val { self.blockn_cls } - fn hashcode(&self) -> u64 { + fn hashcode(self: Gc) -> u64 { let mut hasher = DefaultHasher::new(); - hasher.write_usize(self as *const _ as usize); + hasher.write_usize(Gc::into_raw(self) as *const _ as usize); hasher.finish() } } diff --git a/src/lib/vm/objects/class.rs b/src/lib/vm/objects/class.rs index 0db9f6c3..feabc580 100644 --- a/src/lib/vm/objects/class.rs +++ b/src/lib/vm/objects/class.rs @@ -38,35 +38,35 @@ pub struct Class { } impl Obj for Class { - fn dyn_objtype(&self) -> ObjType { + fn dyn_objtype(self: Gc) -> ObjType { ObjType::Class } - fn get_class(&self, _: &mut VM) -> Val { + fn get_class(self: Gc, _: &mut VM) -> Val { debug_assert!(self.metacls.get().valkind() != ValKind::ILLEGAL); self.metacls.get() } - fn num_inst_vars(&self) -> usize { + fn num_inst_vars(self: Gc) -> usize { let inst_vars = unsafe { &*self.inst_vars.get() }; inst_vars.len() } - unsafe fn unchecked_inst_var_get(&self, n: usize) -> Val { + unsafe fn unchecked_inst_var_get(self: Gc, n: usize) -> Val { debug_assert!(n < self.num_inst_vars()); let inst_vars = &mut *self.inst_vars.get(); inst_vars[n] } - unsafe fn unchecked_inst_var_set(&self, n: usize, v: Val) { + unsafe fn unchecked_inst_var_set(self: Gc, n: usize, v: Val) { debug_assert!(n < self.num_inst_vars()); let inst_vars = &mut *self.inst_vars.get(); inst_vars[n] = v; } - fn hashcode(&self) -> u64 { + fn hashcode(self: Gc) -> u64 { let mut hasher = DefaultHasher::new(); - hasher.write_usize(self as *const _ as usize); + hasher.write_usize(Gc::into_raw(self) as *const _ as usize); hasher.finish() } } diff --git a/src/lib/vm/objects/double.rs b/src/lib/vm/objects/double.rs index 313b51f9..23546077 100644 --- a/src/lib/vm/objects/double.rs +++ b/src/lib/vm/objects/double.rs @@ -4,6 +4,7 @@ use std::{collections::hash_map::DefaultHasher, hash::Hasher}; use num_bigint::BigInt; use num_traits::{FromPrimitive, ToPrimitive, Zero}; +use rboehm::Gc; use smartstring::alias::String as SmartString; use crate::vm::{ @@ -22,15 +23,15 @@ pub struct Double { impl NotUnboxable for Double {} impl Obj for Double { - fn dyn_objtype(&self) -> ObjType { + fn dyn_objtype(self: Gc) -> ObjType { ObjType::Double } - fn get_class(&self, vm: &mut VM) -> Val { + fn get_class(self: Gc, vm: &mut VM) -> Val { vm.double_cls } - fn to_strval(&self, vm: &mut VM) -> Result> { + fn to_strval(self: Gc, vm: &mut VM) -> Result> { let mut buf = ryu::Buffer::new(); Ok(String_::new_str( vm, @@ -38,13 +39,13 @@ impl Obj for Double { )) } - fn hashcode(&self) -> u64 { + fn hashcode(self: Gc) -> u64 { let mut hasher = DefaultHasher::new(); hasher.write_u64(self.val.to_bits()); hasher.finish() } - fn add(&self, vm: &mut VM, other: Val) -> Result> { + fn add(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { Ok(Double::new(vm, self.val + (rhs as f64))) } else if let Some(rhs) = other.try_downcast::(vm) { @@ -60,7 +61,7 @@ impl Obj for Double { } } - fn double_div(&self, vm: &mut VM, other: Val) -> Result> { + fn double_div(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { if rhs == 0 { Err(VMError::new(vm, VMErrorKind::DivisionByZero)) @@ -88,7 +89,7 @@ impl Obj for Double { } } - fn modulus(&self, vm: &mut VM, other: Val) -> Result> { + fn modulus(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { Ok(Double::new(vm, self.val % (rhs as f64))) } else if let Some(rhs) = other.try_downcast::(vm) { @@ -104,7 +105,7 @@ impl Obj for Double { } } - fn mul(&self, vm: &mut VM, other: Val) -> Result> { + fn mul(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { Ok(Double::new(vm, self.val * (rhs as f64))) } else if let Some(rhs) = other.try_downcast::(vm) { @@ -120,11 +121,11 @@ impl Obj for Double { } } - fn sqrt(&self, vm: &mut VM) -> Result> { + fn sqrt(self: Gc, vm: &mut VM) -> Result> { Ok(Double::new(vm, self.val.sqrt())) } - fn sub(&self, vm: &mut VM, other: Val) -> Result> { + fn sub(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { Ok(Double::new(vm, self.val - (rhs as f64))) } else if let Some(rhs) = other.try_downcast::(vm) { @@ -140,11 +141,11 @@ impl Obj for Double { } } - fn ref_equals(&self, vm: &mut VM, other: Val) -> Result> { + fn ref_equals(self: Gc, vm: &mut VM, other: Val) -> Result> { self.equals(vm, other) } - fn equals(&self, vm: &mut VM, other: Val) -> Result> { + fn equals(self: Gc, vm: &mut VM, other: Val) -> Result> { let b = if let Some(rhs) = other.as_isize(vm) { self.val == (rhs as f64) } else if let Some(rhs) = other.try_downcast::(vm) { @@ -161,7 +162,7 @@ impl Obj for Double { Ok(Val::from_bool(vm, b)) } - fn less_than(&self, vm: &mut VM, other: Val) -> Result> { + fn less_than(self: Gc, vm: &mut VM, other: Val) -> Result> { let b = if let Some(rhs) = other.as_isize(vm) { self.val < (rhs as f64) } else if let Some(rhs) = other.try_downcast::(vm) { diff --git a/src/lib/vm/objects/instance.rs b/src/lib/vm/objects/instance.rs index 0e804ade..2a74af51 100644 --- a/src/lib/vm/objects/instance.rs +++ b/src/lib/vm/objects/instance.rs @@ -18,34 +18,34 @@ pub struct Inst { } impl Obj for Inst { - fn dyn_objtype(&self) -> ObjType { + fn dyn_objtype(self: Gc) -> ObjType { ObjType::Inst } - fn get_class(&self, _: &mut VM) -> Val { + fn get_class(self: Gc, _: &mut VM) -> Val { self.class } - fn num_inst_vars(&self) -> usize { + fn num_inst_vars(self: Gc) -> usize { unsafe { &*self.inst_vars.get() }.len() } - unsafe fn unchecked_inst_var_get(&self, n: usize) -> Val { + unsafe fn unchecked_inst_var_get(self: Gc, n: usize) -> Val { let inst_vars = &mut *self.inst_vars.get(); debug_assert!(n < inst_vars.len()); debug_assert!(inst_vars[n].valkind() != ValKind::ILLEGAL); inst_vars[n] } - unsafe fn unchecked_inst_var_set(&self, n: usize, v: Val) { + unsafe fn unchecked_inst_var_set(self: Gc, n: usize, v: Val) { let inst_vars = &mut *self.inst_vars.get(); debug_assert!(n < inst_vars.len()); inst_vars[n] = v; } - fn hashcode(&self) -> u64 { + fn hashcode(self: Gc) -> u64 { let mut hasher = DefaultHasher::new(); - hasher.write_usize(self as *const _ as usize); + hasher.write_usize(Gc::into_raw(self) as *const _ as usize); hasher.finish() } } diff --git a/src/lib/vm/objects/integers.rs b/src/lib/vm/objects/integers.rs index d4e5326b..5ade809e 100644 --- a/src/lib/vm/objects/integers.rs +++ b/src/lib/vm/objects/integers.rs @@ -15,6 +15,7 @@ use std::convert::TryFrom; use num_bigint::BigInt; use num_traits::{FromPrimitive, Signed, ToPrimitive, Zero}; +use rboehm::Gc; use crate::vm::{ core::VM, @@ -32,19 +33,19 @@ pub struct ArbInt { impl NotUnboxable for ArbInt {} impl Obj for ArbInt { - fn dyn_objtype(&self) -> ObjType { + fn dyn_objtype(self: Gc) -> ObjType { ObjType::ArbInt } - fn get_class(&self, vm: &mut VM) -> Val { + fn get_class(self: Gc, vm: &mut VM) -> Val { vm.int_cls } - fn to_strval(&self, vm: &mut VM) -> Result> { + fn to_strval(self: Gc, vm: &mut VM) -> Result> { Ok(String_::new_str(vm, self.val.to_string().into())) } - fn add(&self, vm: &mut VM, other: Val) -> Result> { + fn add(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { Ok(ArbInt::new(vm, &self.val + rhs)) } else if let Some(rhs) = other.try_downcast::(vm) { @@ -60,7 +61,7 @@ impl Obj for ArbInt { } } - fn and(&self, vm: &mut VM, other: Val) -> Result> { + fn and(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { Ok(ArbInt::new( vm, @@ -78,7 +79,7 @@ impl Obj for ArbInt { } } - fn div(&self, vm: &mut VM, other: Val) -> Result> { + fn div(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { if rhs == 0 { Err(VMError::new(vm, VMErrorKind::DivisionByZero)) @@ -105,7 +106,7 @@ impl Obj for ArbInt { } } - fn double_div(&self, vm: &mut VM, other: Val) -> Result> { + fn double_div(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { if rhs == 0 { Err(VMError::new(vm, VMErrorKind::DivisionByZero)) @@ -140,7 +141,7 @@ impl Obj for ArbInt { } } - fn modulus(&self, vm: &mut VM, other: Val) -> Result> { + fn modulus(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { Ok(ArbInt::new(vm, ((&self.val % rhs) + rhs) % rhs)) } else if let Some(rhs) = other.try_downcast::(vm) { @@ -162,7 +163,7 @@ impl Obj for ArbInt { } } - fn mul(&self, vm: &mut VM, other: Val) -> Result> { + fn mul(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { Ok(ArbInt::new(vm, &self.val * rhs)) } else if let Some(rhs) = other.try_downcast::(vm) { @@ -178,11 +179,11 @@ impl Obj for ArbInt { } } - fn remainder(&self, _vm: &mut VM, _other: Val) -> Result> { + fn remainder(self: Gc, _vm: &mut VM, _other: Val) -> Result> { todo!(); } - fn shl(&self, vm: &mut VM, other: Val) -> Result> { + fn shl(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { if rhs < 0 { Err(VMError::new(vm, VMErrorKind::NegativeShift)) @@ -199,7 +200,7 @@ impl Obj for ArbInt { } } - fn shr(&self, vm: &mut VM, other: Val) -> Result> { + fn shr(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { if rhs < 0 { Err(VMError::new(vm, VMErrorKind::NegativeShift)) @@ -220,7 +221,7 @@ impl Obj for ArbInt { } } - fn sqrt(&self, vm: &mut VM) -> Result> { + fn sqrt(self: Gc, vm: &mut VM) -> Result> { if self.val < Zero::zero() { Err(VMError::new(vm, VMErrorKind::DomainError)) } else { @@ -233,7 +234,7 @@ impl Obj for ArbInt { } } - fn sub(&self, vm: &mut VM, other: Val) -> Result> { + fn sub(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { Ok(ArbInt::new(vm, &self.val - rhs)) } else if let Some(rhs) = other.try_downcast::(vm) { @@ -249,7 +250,7 @@ impl Obj for ArbInt { } } - fn xor(&self, vm: &mut VM, other: Val) -> Result> { + fn xor(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { Ok(ArbInt::new( vm, @@ -267,7 +268,7 @@ impl Obj for ArbInt { } } - fn ref_equals(&self, vm: &mut VM, other: Val) -> Result> { + fn ref_equals(self: Gc, vm: &mut VM, other: Val) -> Result> { let b = if let Some(rhs) = other.try_downcast::(vm) { self.val == rhs.val } else { @@ -276,7 +277,7 @@ impl Obj for ArbInt { Ok(Val::from_bool(vm, b)) } - fn equals(&self, vm: &mut VM, other: Val) -> Result> { + fn equals(self: Gc, vm: &mut VM, other: Val) -> Result> { let b = if other.dyn_objtype(vm) == ObjType::Int { debug_assert!(self.val != BigInt::from_isize(other.as_isize(vm).unwrap()).unwrap()); false @@ -288,7 +289,7 @@ impl Obj for ArbInt { Ok(Val::from_bool(vm, b)) } - fn not_equals(&self, vm: &mut VM, other: Val) -> Result> { + fn not_equals(self: Gc, vm: &mut VM, other: Val) -> Result> { let b = if other.dyn_objtype(vm) == ObjType::Int { debug_assert!(self.val != BigInt::from_isize(other.as_isize(vm).unwrap()).unwrap()); true @@ -300,7 +301,7 @@ impl Obj for ArbInt { Ok(Val::from_bool(vm, b)) } - fn greater_than(&self, vm: &mut VM, other: Val) -> Result> { + fn greater_than(self: Gc, vm: &mut VM, other: Val) -> Result> { let b = if other.dyn_objtype(vm) == ObjType::Int { debug_assert!( !self.val.is_positive() @@ -316,7 +317,7 @@ impl Obj for ArbInt { Ok(Val::from_bool(vm, b)) } - fn greater_than_equals(&self, vm: &mut VM, other: Val) -> Result> { + fn greater_than_equals(self: Gc, vm: &mut VM, other: Val) -> Result> { let b = if other.dyn_objtype(vm) == ObjType::Int { debug_assert!( !self.val.is_positive() @@ -332,7 +333,7 @@ impl Obj for ArbInt { Ok(Val::from_bool(vm, b)) } - fn less_than(&self, vm: &mut VM, other: Val) -> Result> { + fn less_than(self: Gc, vm: &mut VM, other: Val) -> Result> { let b = if other.dyn_objtype(vm) == ObjType::Int { debug_assert!( !self.val.is_negative() @@ -348,7 +349,7 @@ impl Obj for ArbInt { Ok(Val::from_bool(vm, b)) } - fn less_than_equals(&self, vm: &mut VM, other: Val) -> Result> { + fn less_than_equals(self: Gc, vm: &mut VM, other: Val) -> Result> { let b = if other.dyn_objtype(vm) == ObjType::Int { debug_assert!( !self.val.is_negative() @@ -396,19 +397,19 @@ pub struct Int { } impl Obj for Int { - fn dyn_objtype(&self) -> ObjType { + fn dyn_objtype(self: Gc) -> ObjType { ObjType::Int } - fn get_class(&self, vm: &mut VM) -> Val { + fn get_class(self: Gc, vm: &mut VM) -> Val { vm.int_cls } - fn to_strval(&self, vm: &mut VM) -> Result> { + fn to_strval(self: Gc, vm: &mut VM) -> Result> { Ok(String_::new_str(vm, self.val.to_string().into())) } - fn add(&self, vm: &mut VM, other: Val) -> Result> { + fn add(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { match self.val.checked_add(rhs) { Some(i) => Ok(Val::from_isize(vm, i)), @@ -427,7 +428,7 @@ impl Obj for Int { } } - fn div(&self, vm: &mut VM, other: Val) -> Result> { + fn div(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { if rhs == 0 { Err(VMError::new(vm, VMErrorKind::DivisionByZero)) @@ -457,7 +458,7 @@ impl Obj for Int { } } - fn mul(&self, vm: &mut VM, other: Val) -> Result> { + fn mul(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { match self.val.checked_mul(rhs) { Some(i) => Ok(Val::from_isize(vm, i)), @@ -476,7 +477,7 @@ impl Obj for Int { } } - fn sub(&self, vm: &mut VM, other: Val) -> Result> { + fn sub(self: Gc, vm: &mut VM, other: Val) -> Result> { if let Some(rhs) = other.as_isize(vm) { match self.val.checked_sub(rhs) { Some(i) => Ok(Val::from_isize(vm, i)), @@ -593,12 +594,22 @@ mod tests { assert!(bi.downcast::(&mut vm).is_ok()); let v = Val::from_isize(&mut vm, 1 << (TAG_BITSIZE + 2)); assert_eq!( - bi.tobj(&mut vm).unwrap().sub(&mut vm, v).unwrap().valkind(), + bi.tobj(&mut vm) + .unwrap() + .as_gc() + .sub(&mut vm, v) + .unwrap() + .valkind(), ValKind::GCBOX ); let v = Val::from_isize(&mut vm, isize::max_value()); assert_eq!( - bi.tobj(&mut vm).unwrap().sub(&mut vm, v).unwrap().valkind(), + bi.tobj(&mut vm) + .unwrap() + .as_gc() + .sub(&mut vm, v) + .unwrap() + .valkind(), ValKind::INT ); // Different LHS and RHS types diff --git a/src/lib/vm/objects/method.rs b/src/lib/vm/objects/method.rs index b571858e..ff301335 100644 --- a/src/lib/vm/objects/method.rs +++ b/src/lib/vm/objects/method.rs @@ -2,6 +2,8 @@ use std::{cell::Cell, collections::hash_map::DefaultHasher, hash::Hasher}; +use rboehm::Gc; + use crate::{ compiler::instrs::Primitive, vm::{ @@ -34,17 +36,17 @@ pub enum MethodBody { } impl Obj for Method { - fn dyn_objtype(&self) -> ObjType { + fn dyn_objtype(self: Gc) -> ObjType { ObjType::Method } - fn get_class(&self, vm: &mut VM) -> Val { + fn get_class(self: Gc, vm: &mut VM) -> Val { vm.method_cls } - fn hashcode(&self) -> u64 { + fn hashcode(self: Gc) -> u64 { let mut hasher = DefaultHasher::new(); - hasher.write_usize(self as *const _ as usize); + hasher.write_usize(Gc::into_raw(self) as *const _ as usize); hasher.finish() } } diff --git a/src/lib/vm/objects/mod.rs b/src/lib/vm/objects/mod.rs index 5ba87ffd..112656ed 100644 --- a/src/lib/vm/objects/mod.rs +++ b/src/lib/vm/objects/mod.rs @@ -82,28 +82,28 @@ impl ObjType { #[narrowable_rboehm(ThinObj)] pub trait Obj: std::fmt::Debug { /// What `ObjType` does this `Val` represent? - fn dyn_objtype(&self) -> ObjType; + fn dyn_objtype(self: Gc) -> ObjType; /// What class is this object an instance of? - fn get_class(&self, vm: &mut VM) -> Val; + fn get_class(self: Gc, vm: &mut VM) -> Val; /// If (and only if) this object implements the [Array] trait then return a reference to this /// object as an [Array] trait object. - fn to_array(&self) -> Result<&dyn Array, Box> { + fn to_array(self: Gc) -> Result, Box> { todo!(); } /// Convert this object to a `Val` that represents a SOM string. - fn to_strval(&self, _: &mut VM) -> Result> { + fn to_strval(self: Gc, _: &mut VM) -> Result> { unreachable!(); } /// How many instance variables does this object contain? - fn num_inst_vars(&self) -> usize { + fn num_inst_vars(self: Gc) -> usize { unreachable!(); } /// Return the instance variable at `i` (using SOM indexing). - fn inst_var_at(&self, vm: &VM, i: usize) -> Result> { + fn inst_var_at(self: Gc, vm: &VM, i: usize) -> Result> { if i > 0 && i <= self.num_inst_vars() { Ok(unsafe { self.unchecked_inst_var_get(i - 1) }) } else { @@ -118,7 +118,7 @@ pub trait Obj: std::fmt::Debug { } /// Return the instance variable at `i` (using SOM indexing). - fn inst_var_at_put(&self, vm: &VM, i: usize, v: Val) -> Result<(), Box> { + fn inst_var_at_put(self: Gc, vm: &VM, i: usize, v: Val) -> Result<(), Box> { if i > 0 && i <= self.num_inst_vars() { unsafe { self.unchecked_inst_var_set(i - 1, v) }; Ok(()) @@ -135,125 +135,125 @@ pub trait Obj: std::fmt::Debug { /// Lookup an instance variable in this object. If `usize` exceeds the number of instance /// variables this will lead to undefined behaviour. - unsafe fn unchecked_inst_var_get(&self, _: usize) -> Val { + unsafe fn unchecked_inst_var_get(self: Gc, _: usize) -> Val { unreachable!(); } /// Set an instance variable in this object. If `usize` exceeds the number of instance /// variables this will lead to undefined behaviour. - unsafe fn unchecked_inst_var_set(&self, _: usize, _: Val) { + unsafe fn unchecked_inst_var_set(self: Gc, _: usize, _: Val) { unreachable!(); } /// What is this object's length? - fn length(&self) -> usize { + fn length(self: Gc) -> usize { unreachable!(); } /// What is this object's hashcode? - fn hashcode(&self) -> u64 { + fn hashcode(self: Gc) -> u64 { unreachable!(); } /// Produce a new `Val` which adds `other` to this. - fn add(&self, _: &mut VM, _: Val) -> Result> { + fn add(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } /// Produce a new `Val` which performs a bitwise and with `other` and this. - fn and(&self, _: &mut VM, _: Val) -> Result> { + fn and(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } /// Produce a new `Val` which divides `other` from this. - fn div(&self, _: &mut VM, _: Val) -> Result> { + fn div(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } - fn double_div(&self, _: &mut VM, _: Val) -> Result> { + fn double_div(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } /// Produce a new `Val` which performs a mod operation on this with `other`. - fn modulus(&self, _: &mut VM, _: Val) -> Result> { + fn modulus(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } /// Produce a new `Val` which multiplies `other` to this. - fn mul(&self, _: &mut VM, _: Val) -> Result> { + fn mul(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } /// Produce a new `Val` which returns the remainder of dividing this with `other`. - fn remainder(&self, _: &mut VM, _: Val) -> Result> { + fn remainder(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } /// Produce a new `Val` which shifts `self` `other` bits to the left. - fn shl(&self, _: &mut VM, _: Val) -> Result> { + fn shl(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } /// Produce a new `Val` which shifts `self` `other` bits to the right, treating `self` as if it /// did not have a sign bit. - fn shr(&self, _: &mut VM, _: Val) -> Result> { + fn shr(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } /// Produces a new `Val` which is the square root of this. - fn sqrt(&self, _: &mut VM) -> Result> { + fn sqrt(self: Gc, _: &mut VM) -> Result> { unreachable!(); } /// Produce a new `Val` which subtracts `other` from this. - fn sub(&self, _: &mut VM, _: Val) -> Result> { + fn sub(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } /// Produce a new `Val` which performs a bitwise xor with `other` and this - fn xor(&self, _: &mut VM, _: Val) -> Result> { + fn xor(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } /// Is this `Val` reference equality equal to `other`? Only immutable SOM types are likely to /// want to override this. - fn ref_equals(&self, vm: &mut VM, other: Val) -> Result> { + fn ref_equals(self: Gc, vm: &mut VM, other: Val) -> Result> { let other_tobj = other.tobj(vm)?; let other_data = unsafe { std::mem::transmute::<&dyn Obj, (*const u8, usize)>(&**other_tobj).0 }; Ok(Val::from_bool( vm, - (self as *const _ as *const u8) == other_data, + (Gc::into_raw(self) as *const _ as *const u8) == other_data, )) } /// Does this `Val` equal `other`? - fn equals(&self, _: &mut VM, _: Val) -> Result> { + fn equals(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } /// Does this `Val` not equal `other`? - fn not_equals(&self, _: &mut VM, _: Val) -> Result> { + fn not_equals(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } /// Is this `Val` greater than `other`? - fn greater_than(&self, _: &mut VM, _: Val) -> Result> { + fn greater_than(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } /// Is this `Val` greater than or equal to `other`? - fn greater_than_equals(&self, _: &mut VM, _: Val) -> Result> { + fn greater_than_equals(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } /// Is this `Val` less than `other`? - fn less_than(&self, _: &mut VM, _: Val) -> Result> { + fn less_than(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } /// Is this `Val` less than or equal to `other`? - fn less_than_equals(&self, _: &mut VM, _: Val) -> Result> { + fn less_than_equals(self: Gc, _: &mut VM, _: Val) -> Result> { unreachable!(); } } diff --git a/src/lib/vm/objects/string_.rs b/src/lib/vm/objects/string_.rs index 4d0b013a..d71ba675 100644 --- a/src/lib/vm/objects/string_.rs +++ b/src/lib/vm/objects/string_.rs @@ -24,11 +24,11 @@ pub struct String_ { } impl Obj for String_ { - fn dyn_objtype(&self) -> ObjType { + fn dyn_objtype(self: Gc) -> ObjType { ObjType::String_ } - fn get_class(&self, _: &mut VM) -> Val { + fn get_class(self: Gc, _: &mut VM) -> Val { debug_assert!( self.cls.get().valkind() != crate::vm::val::ValKind::ILLEGAL, "{}", @@ -37,7 +37,7 @@ impl Obj for String_ { self.cls.get() } - fn to_strval(&self, vm: &mut VM) -> Result> { + fn to_strval(self: Gc, vm: &mut VM) -> Result> { Ok(Val::from_obj( vm, String_ { @@ -47,21 +47,21 @@ impl Obj for String_ { )) } - fn hashcode(&self) -> u64 { + fn hashcode(self: Gc) -> u64 { let mut s = DefaultHasher::new(); self.s.hash(&mut s); s.finish() } - fn length(&self) -> usize { + fn length(self: Gc) -> usize { self.s.chars().count() } - fn ref_equals(&self, vm: &mut VM, other: Val) -> Result> { + fn ref_equals(self: Gc, vm: &mut VM, other: Val) -> Result> { self.equals(vm, other) } - fn equals(&self, vm: &mut VM, other: Val) -> Result> { + fn equals(self: Gc, vm: &mut VM, other: Val) -> Result> { let b = match other.downcast::(vm) { Ok(other_str) => (self.cls == other_str.cls) && (self.s == other_str.s), Err(_) => false, @@ -122,7 +122,7 @@ impl String_ { } /// Concatenate this string with another string and return the result. - pub fn concatenate(&self, vm: &mut VM, other: Val) -> Result> { + pub fn concatenate(self: Gc, vm: &mut VM, other: Val) -> Result> { let other_str: Gc = other.downcast(vm)?; // Since strings are immutable, concatenating an empty string means we don't need to diff --git a/src/lib/vm/val.rs b/src/lib/vm/val.rs index 4bb91ec8..998500e5 100644 --- a/src/lib/vm/val.rs +++ b/src/lib/vm/val.rs @@ -88,9 +88,9 @@ impl Val { /// Convert `obj` into a `Val`. `Obj` must previously have been created via `Val::from_obj` and /// then turned into an actual object with `tobj`: failure to follow these steps will result in /// undefined behaviour. - pub fn recover(obj: &dyn Obj) -> Self { + pub fn recover(obj: Gc) -> Self { unsafe { - let ptr = Gc::into_raw(ThinObj::recover(obj)); + let ptr = Gc::into_raw(ThinObj::recover_gc(obj)); Val { val: transmute::<*const ThinObj, usize>(ptr) | (ValKind::GCBOX as usize), } @@ -144,7 +144,7 @@ impl Val { vm, VMErrorKind::BuiltinTypeError { expected: T::static_objtype(), - got: tobj.deref().dyn_objtype(), + got: tobj.deref().as_gc().dyn_objtype(), }, ) }) @@ -274,7 +274,7 @@ impl Val { pub fn dyn_objtype(&self, vm: &mut VM) -> ObjType { match self.valkind() { ValKind::INT => ObjType::Int, - ValKind::GCBOX => self.tobj(vm).unwrap().dyn_objtype(), + ValKind::GCBOX => self.tobj(vm).unwrap().as_gc().dyn_objtype(), ValKind::ILLEGAL => unreachable!(), } } @@ -283,7 +283,7 @@ impl Val { pub fn get_class(&self, vm: &mut VM) -> Val { match self.valkind() { ValKind::INT => vm.int_cls, - ValKind::GCBOX => self.tobj(vm).unwrap().get_class(vm), + ValKind::GCBOX => self.tobj(vm).unwrap().as_gc().get_class(vm), ValKind::ILLEGAL => unreachable!(), } } @@ -294,7 +294,7 @@ impl Val { let s = self.as_isize(vm).unwrap().to_string(); Ok(String_::new_str(vm, s.into())) } - ValKind::GCBOX => self.tobj(vm).unwrap().to_strval(vm), + ValKind::GCBOX => self.tobj(vm).unwrap().as_gc().to_strval(vm), ValKind::ILLEGAL => unreachable!(), } } @@ -308,7 +308,7 @@ impl Val { unreachable!() } ValKind::GCBOX => { - let hc = self.tobj(vm).unwrap().hashcode(); + let hc = self.tobj(vm).unwrap().as_gc().hashcode(); Val::from_u64(vm, hc) } ValKind::ILLEGAL => unreachable!(), @@ -323,7 +323,7 @@ impl Val { return Ok(Val { val }); } } - self.tobj(vm).unwrap().add(vm, other) + self.tobj(vm).unwrap().as_gc().add(vm, other) } /// Produce a new `Val` which performs a bitwise and operation with `other` and this. @@ -344,7 +344,7 @@ impl Val { VMErrorKind::BuiltinTypeError { expected, got }, )); } - self.tobj(vm).unwrap().and(vm, other) + self.tobj(vm).unwrap().as_gc().and(vm, other) } /// Produce a new `Val` which divides `other` from this. @@ -371,7 +371,7 @@ impl Val { let got = other.dyn_objtype(vm); return Err(VMError::new(vm, VMErrorKind::NotANumber { got })); } - self.tobj(vm).unwrap().div(vm, other) + self.tobj(vm).unwrap().as_gc().div(vm, other) } /// Produce a new `Val` which perfoms a Double divide on `other` with this. @@ -399,7 +399,7 @@ impl Val { let got = other.dyn_objtype(vm); return Err(VMError::new(vm, VMErrorKind::NotANumber { got })); } - self.tobj(vm).unwrap().double_div(vm, other) + self.tobj(vm).unwrap().as_gc().double_div(vm, other) } /// Produce a new `Val` which performs a mod operation on this with `other`. @@ -420,7 +420,7 @@ impl Val { let got = other.dyn_objtype(vm); return Err(VMError::new(vm, VMErrorKind::NotANumber { got })); } - self.tobj(vm).unwrap().modulus(vm, other) + self.tobj(vm).unwrap().as_gc().modulus(vm, other) } /// Produce a new `Val` which multiplies `other` to this. @@ -431,7 +431,7 @@ impl Val { return Ok(Val { val }); } } - self.tobj(vm).unwrap().mul(vm, other) + self.tobj(vm).unwrap().as_gc().mul(vm, other) } /// Produce a new `Val` which performs a mod operation on this with `other`. @@ -450,7 +450,7 @@ impl Val { let got = other.dyn_objtype(vm); return Err(VMError::new(vm, VMErrorKind::NotANumber { got })); } - self.tobj(vm).unwrap().remainder(vm, other) + self.tobj(vm).unwrap().as_gc().remainder(vm, other) } /// Produce a new `Val` which shifts `self` `other` bits to the left. @@ -485,7 +485,7 @@ impl Val { let got = other.dyn_objtype(vm); return Err(VMError::new(vm, VMErrorKind::NotANumber { got })); } - self.tobj(vm).unwrap().shl(vm, other) + self.tobj(vm).unwrap().as_gc().shl(vm, other) } /// Produce a new `Val` which shifts `self` `other` bits to the right, treating `self` as if it @@ -507,7 +507,7 @@ impl Val { let got = other.dyn_objtype(vm); return Err(VMError::new(vm, VMErrorKind::NotANumber { got })); } - self.tobj(vm).unwrap().shr(vm, other) + self.tobj(vm).unwrap().as_gc().shr(vm, other) } /// Produces a new `Val` which is the square root of this. @@ -524,7 +524,7 @@ impl Val { } } } - self.tobj(vm).unwrap().sqrt(vm) + self.tobj(vm).unwrap().as_gc().sqrt(vm) } /// Produce a new `Val` which subtracts `other` from this. @@ -535,7 +535,7 @@ impl Val { return Ok(Val { val }); } } - self.tobj(vm).unwrap().sub(vm, other) + self.tobj(vm).unwrap().as_gc().sub(vm, other) } /// Produce a new `Val` which performs a bitwise xor operation with `other` and this. @@ -556,7 +556,7 @@ impl Val { VMErrorKind::BuiltinTypeError { expected, got }, )); } - self.tobj(vm).unwrap().xor(vm, other) + self.tobj(vm).unwrap().as_gc().xor(vm, other) } /// Is this `Val` reference equal to `other`? Notice that for integers (but not Doubles) @@ -564,7 +564,7 @@ impl Val { pub fn ref_equals(&self, vm: &mut VM, other: Val) -> Result> { match self.valkind() { ValKind::INT => self.equals(vm, other), - ValKind::GCBOX => self.tobj(vm)?.ref_equals(vm, other), + ValKind::GCBOX => self.tobj(vm)?.as_gc().ref_equals(vm, other), ValKind::ILLEGAL => unreachable!(), } } @@ -586,7 +586,7 @@ macro_rules! binop_all { Ok(vm.$tf) } } else { - self.tobj(vm).unwrap().$name(vm, other) + self.tobj(vm).unwrap().as_gc().$name(vm, other) } } } @@ -610,7 +610,7 @@ macro_rules! binop_typeerror { })) } } else { - self.tobj(vm).unwrap().$name(vm, other) + self.tobj(vm).unwrap().as_gc().$name(vm, other) } } } @@ -634,7 +634,6 @@ mod tests { use serial_test::serial; use smartstring::alias::String as SmartString; - use std::ops::Deref; #[test] #[serial] @@ -717,8 +716,8 @@ mod tests { let v = { let v = String_::new_str(&mut vm, SmartString::from("s")); let v_tobj = v.tobj(&mut vm).unwrap(); - let v_int: &dyn Obj = v_tobj.deref().deref(); - let v_recovered = Val::recover(v_int); + let v_str: Gc = v_tobj.downcast().unwrap(); + let v_recovered = Val::recover(v_str); assert_eq!(v_recovered.val, v.val); v_recovered };