use crate::arena::*; use crate::atom_table::*; use crate::forms::*; use crate::machine::machine_indices::*; use crate::machine::partial_string::PartialString; use crate::machine::streams::*; use crate::parser::ast::Fixnum; use std::cmp::Ordering; use std::convert::TryFrom; use std::fmt; use std::mem; use std::ops::{Add, Sub, SubAssign}; #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[bits = 6] pub enum HeapCellValueTag { Str = 0b000011, Lis = 0b000101, Var = 0b000111, StackVar = 0b001001, AttrVar = 0b001011, PStrLoc = 0b001101, PStrOffset = 0b001111, // constants. Cons = 0b0, F64 = 0b010001, Fixnum = 0b010011, Char = 0b010101, Atom = 0b010111, PStr = 0b011001, CStr = 0b011011, } #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[bits = 6] pub enum HeapCellValueView { Str = 0b000011, Lis = 0b000101, Var = 0b000111, StackVar = 0b001001, AttrVar = 0b001011, PStrLoc = 0b001101, PStrOffset = 0b001111, // constants. Cons = 0b0, F64 = 0b010001, Fixnum = 0b010011, Char = 0b010101, Atom = 0b010111, PStr = 0b011001, CStr = 0b011011, // trail elements. TrailedHeapVar = 0b011101, TrailedStackVar = 0b011111, TrailedAttrVarListLink = 0b100011, TrailedAttachedValue = 0b100101, TrailedBlackboardEntry = 0b100111, TrailedBlackboardOffset = 0b101001, } #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[bits = 1] pub enum ConsPtrMaskTag { Cons = 0b0, } #[bitfield] #[repr(u64)] #[derive(Copy, Clone, Debug)] pub struct ConsPtr { ptr: B61, f: bool, m: bool, tag: ConsPtrMaskTag, } impl ConsPtr { #[inline(always)] pub fn build_with(ptr: *const ArenaHeader, tag: ConsPtrMaskTag) -> Self { ConsPtr::new() .with_ptr(ptr as *const u8 as u64) .with_f(false) .with_m(false) .with_tag(tag) } #[inline(always)] pub fn as_ptr(self) -> *mut u8 { self.ptr() as *mut _ } #[inline(always)] pub fn get_tag(self) -> ConsPtrMaskTag { self.tag() } } #[derive(BitfieldSpecifier, Copy, Clone, Debug)] #[bits = 6] pub(crate) enum RefTag { HeapCell = 0b000111, StackCell = 0b001001, AttrVar = 0b001011, } #[bitfield] #[repr(u64)] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct Ref { val: B56, #[allow(unused)] m: bool, #[allow(unused)] f: bool, tag: RefTag, } impl Ord for Ref { fn cmp(&self, rhs: &Ref) -> Ordering { match self.get_tag() { RefTag::HeapCell | RefTag::AttrVar => { match rhs.get_tag() { RefTag::StackCell => Ordering::Less, _ => self.get_value().cmp(&rhs.get_value()), } } RefTag::StackCell => { match rhs.get_tag() { RefTag::StackCell => self.get_value().cmp(&rhs.get_value()), _ => Ordering::Greater, } } } } } impl PartialOrd for Ref { fn partial_cmp(&self, rhs: &Self) -> Option { Some(self.cmp(rhs)) } } impl Ref { #[inline(always)] pub(crate) fn build_with(tag: RefTag, value: u64) -> Self { Ref::new().with_tag(tag).with_val(value) } #[inline(always)] pub(crate) fn get_tag(self) -> RefTag { self.tag() } #[inline(always)] pub(crate) fn get_value(self) -> u64 { self.val() } #[inline(always)] pub(crate) fn as_heap_cell_value(self) -> HeapCellValue { HeapCellValue::from_bytes(self.into_bytes()) } #[inline(always)] pub(crate) fn heap_cell(h: usize) -> Self { Ref::build_with(RefTag::HeapCell, h as u64) } #[inline(always)] pub(crate) fn stack_cell(h: usize) -> Self { Ref::build_with(RefTag::StackCell, h as u64) } #[inline(always)] pub(crate) fn attr_var(h: usize) -> Self { Ref::build_with(RefTag::AttrVar, h as u64) } } #[derive(Debug, Clone, Copy)] pub enum TrailRef { Ref(Ref), AttrVarListLink(usize, usize), BlackboardEntry(Atom), BlackboardOffset(Atom, HeapCellValue), // key atom, key value } #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[bits = 6] pub(crate) enum TrailEntryTag { TrailedHeapVar = 0b011110, TrailedStackVar = 0b011111, TrailedAttrVar = 0b101110, TrailedAttrVarListLink = 0b100011, TrailedAttachedValue = 0b101010, TrailedBlackboardEntry = 0b100110, TrailedBlackboardOffset = 0b100111, } #[bitfield] #[derive(Copy, Clone, Debug)] #[repr(u64)] pub(crate) struct TrailEntry { val: B56, #[allow(unused)] f: bool, #[allow(unused)] m: bool, #[allow(unused)] tag: TrailEntryTag, } impl TrailEntry { #[inline(always)] pub(crate) fn build_with(tag: TrailEntryTag, value: u64) -> Self { TrailEntry::new() .with_tag(tag) .with_m(false) .with_f(false) .with_val(value) } #[inline(always)] pub(crate) fn get_tag(self) -> TrailEntryTag { match self.tag_or_err() { Ok(tag) => tag, Err(_) => TrailEntryTag::TrailedAttachedValue, } } #[inline] pub(crate) fn get_value(self) -> u64 { self.val() } } #[repr(u64)] #[bitfield] #[derive(Copy, Clone, Hash, PartialEq, Eq)] pub struct HeapCellValue { val: B56, f: bool, m: bool, tag: HeapCellValueTag, } impl fmt::Debug for HeapCellValue { fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result { match self.get_tag() { HeapCellValueTag::F64 => { f.debug_struct("HeapCellValue") .field("tag", &HeapCellValueTag::F64) .field("offset", &self.get_value()) .field("m", &self.m()) .field("f", &self.f()) .finish() } HeapCellValueTag::Cons => { let cons_ptr = ConsPtr::from_bytes(self.into_bytes()); f.debug_struct("HeapCellValue") .field("tag", &HeapCellValueTag::Cons) .field("ptr", &cons_ptr.ptr()) .field("m", &cons_ptr.m()) .field("f", &cons_ptr.f()) .finish() } HeapCellValueTag::Atom => { let (name, arity) = cell_as_atom_cell!(self) .get_name_and_arity(); f.debug_struct("HeapCellValue") .field("tag", &HeapCellValueTag::Atom) .field("name", &name.as_str()) .field("arity", &arity) .field("m", &self.m()) .field("f", &self.f()) .finish() } HeapCellValueTag::PStr => { let (name, _) = cell_as_atom_cell!(self) .get_name_and_arity(); f.debug_struct("HeapCellValue") .field("tag", &HeapCellValueTag::PStr) .field("contents", &name.as_str()) .field("m", &self.m()) .field("f", &self.f()) .finish() } tag => { f.debug_struct("HeapCellValue") .field("tag", &tag) .field("value", &self.get_value()) .field("m", &self.get_mark_bit()) .field("f", &self.get_forwarding_bit()) .finish() } } } } impl From> for HeapCellValue { #[inline] fn from(arena_ptr: TypedArenaPtr) -> HeapCellValue { HeapCellValue::from(arena_ptr.header_ptr() as u64) } } impl From for HeapCellValue { #[inline] fn from(f64_ptr: F64Ptr) -> HeapCellValue { HeapCellValue::build_with( HeapCellValueTag::F64, f64_ptr.as_offset().to_u64(), ) } } impl From for HeapCellValue { #[inline(always)] fn from(cons_ptr: ConsPtr) -> HeapCellValue { HeapCellValue::from_bytes( ConsPtr::from(cons_ptr.as_ptr() as u64) .with_tag(ConsPtrMaskTag::Cons) .with_m(false) .into_bytes(), ) } } impl<'a> From<(Number, &mut Arena)> for HeapCellValue { #[inline(always)] fn from((n, arena): (Number, &mut Arena)) -> HeapCellValue { use ordered_float::OrderedFloat; match n { Number::Float(OrderedFloat(n)) => HeapCellValue::from(float_alloc!(n, arena)), Number::Integer(n) => HeapCellValue::from(n), Number::Rational(n) => HeapCellValue::from(n), Number::Fixnum(n) => fixnum_as_cell!(n), } } } impl HeapCellValue { #[inline(always)] pub fn build_with(tag: HeapCellValueTag, value: u64) -> Self { HeapCellValue::new() .with_tag(tag) .with_val(value) .with_m(false) .with_f(false) } #[inline] pub fn is_string_terminator(mut self, heap: &[HeapCellValue]) -> bool { use crate::machine::heap::*; loop { return read_heap_cell!(self, (HeapCellValueTag::Atom, (name, arity)) => { name == atom!("[]") && arity == 0 } (HeapCellValueTag::CStr) => { true } (HeapCellValueTag::PStrLoc, h) => { self = heap[h]; continue; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { let cell = heap_bound_store(heap, heap_bound_deref(heap, heap[h])); if cell.is_var() { return false; } self = cell; continue; } (HeapCellValueTag::PStrOffset, pstr_offset) => { heap[pstr_offset].get_tag() == HeapCellValueTag::CStr } _ => { false } ); } } #[inline] pub fn is_ref(self) -> bool { match self.get_tag() { HeapCellValueTag::Str | HeapCellValueTag::Lis | HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar | HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset => true, _ => false, } } #[inline] pub fn as_char(self) -> Option { read_heap_cell!(self, (HeapCellValueTag::Char, c) => { Some(c) } (HeapCellValueTag::Atom, (name, arity)) => { if arity > 0 { return None; } name.as_char() } _ => { None } ) } #[inline] pub fn is_constant(self) -> bool { match self.get_tag() { HeapCellValueTag::Cons | HeapCellValueTag::F64 | HeapCellValueTag::Fixnum | HeapCellValueTag::Char | HeapCellValueTag::CStr => { true } HeapCellValueTag::Atom => { cell_as_atom_cell!(self).get_arity() == 0 } _ => { false } } } #[inline(always)] pub fn is_stack_var(self) -> bool { self.get_tag() == HeapCellValueTag::StackVar } #[inline] pub fn is_compound(self, heap: &[HeapCellValue]) -> bool { match self.get_tag() { HeapCellValueTag::Str => { cell_as_atom_cell!(heap[self.get_value()]).get_arity() > 0 } HeapCellValueTag::Lis | HeapCellValueTag::CStr | HeapCellValueTag::PStr | HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset => { true } HeapCellValueTag::Atom => { cell_as_atom_cell!(self).get_arity() > 0 } _ => { false } } } #[inline] pub fn is_var(self) -> bool { read_heap_cell!(self, (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { true } _ => { false } ) } #[inline] pub(crate) fn as_var(self) -> Option { read_heap_cell!(self, (HeapCellValueTag::Var, h) => { Some(Ref::heap_cell(h)) } (HeapCellValueTag::AttrVar, h) => { Some(Ref::attr_var(h)) } (HeapCellValueTag::StackVar, s) => { Some(Ref::stack_cell(s)) } _ => { None } ) } #[inline] pub fn get_value(self) -> usize { self.val() as usize } #[inline] pub fn set_value(&mut self, val: usize) { self.set_val(val as u64); } #[inline] pub fn get_tag(self) -> HeapCellValueTag { match self.tag_or_err() { Ok(tag) => tag, Err(_) => match ConsPtr::from_bytes(self.into_bytes()).tag() { ConsPtrMaskTag::Cons => HeapCellValueTag::Cons, }, } } #[inline] pub fn to_atom(self) -> Option { match self.tag() { HeapCellValueTag::Atom => Some(Atom::from((self.val() << 3) as usize)), _ => None, } } #[inline] pub fn to_pstr(self) -> Option { match self.tag() { HeapCellValueTag::PStr => { Some(PartialString::from(Atom::from((self.val() as usize) << 3))) } _ => None, } } #[inline] pub fn to_fixnum(self) -> Option { match self.get_tag() { HeapCellValueTag::Fixnum => Some(Fixnum::from_bytes(self.into_bytes())), _ => None, } } #[inline] pub fn to_untyped_arena_ptr(self) -> Option { match self.tag() { HeapCellValueTag::Cons => Some(UntypedArenaPtr::from_bytes(self.into_bytes())), _ => None, } } #[inline(always)] pub fn get_forwarding_bit(self) -> bool { match self.get_tag() { HeapCellValueTag::Cons => ConsPtr::from_bytes(self.into_bytes()).f(), _ => self.f() } } #[inline(always)] pub fn set_forwarding_bit(&mut self, f: bool) { match self.get_tag() { HeapCellValueTag::Cons => { let value = ConsPtr::from_bytes(self.into_bytes()).with_f(f); *self = HeapCellValue::from_bytes(value.into_bytes()); } _ => self.set_f(f), } } #[inline(always)] pub fn get_mark_bit(self) -> bool { match self.get_tag() { HeapCellValueTag::Cons => { ConsPtr::from_bytes(self.into_bytes()).m() } _ => self.m(), } } #[inline(always)] pub fn set_mark_bit(&mut self, m: bool) { match self.get_tag() { HeapCellValueTag::Cons => { let value = ConsPtr::from_bytes(self.into_bytes()).with_m(m); *self = HeapCellValue::from_bytes(value.into_bytes()); } _ => self.set_m(m), } } pub fn order_category(self, heap: &[HeapCellValue]) -> Option { match Number::try_from(self).ok() { Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => { Some(TermOrderCategory::Integer) } Some(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint), None => match self.get_tag() { HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar => { Some(TermOrderCategory::Variable) } HeapCellValueTag::Char => Some(TermOrderCategory::Atom), HeapCellValueTag::Atom => { Some(if cell_as_atom_cell!(self).get_arity() > 0 { TermOrderCategory::Compound } else { TermOrderCategory::Atom }) } HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr => { Some(TermOrderCategory::Compound) } HeapCellValueTag::Str => { let value = heap[self.get_value()]; let arity = cell_as_atom_cell!(value).get_arity(); if arity == 0 { Some(TermOrderCategory::Atom) } else { Some(TermOrderCategory::Compound) } } _ => { None } }, } } #[inline(always)] pub fn is_protected(self, e: usize) -> bool { read_heap_cell!(self, (HeapCellValueTag::StackVar, s) => { s < e } _ => { true } ) } } const_assert!(mem::size_of::() == 8); #[bitfield] #[repr(u64)] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct UntypedArenaPtr { ptr: B61, m: bool, #[allow(unused)] padding: B2, } const_assert!(mem::size_of::() == 8); impl From<*const ArenaHeader> for UntypedArenaPtr { #[inline] fn from(ptr: *const ArenaHeader) -> UntypedArenaPtr { unsafe { mem::transmute(ptr) } } } impl From<*const IndexPtr> for UntypedArenaPtr { #[inline] fn from(ptr: *const IndexPtr) -> UntypedArenaPtr { unsafe { mem::transmute(ptr) } } } impl From for *const ArenaHeader { #[inline] fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader { unsafe { mem::transmute(ptr) } } } impl UntypedArenaPtr { #[inline] pub fn set_mark_bit(&mut self, m: bool) { self.set_m(m); } #[inline] pub fn get_ptr(self) -> *const u8 { self.ptr() as *const u8 } #[inline] pub fn get_tag(self) -> ArenaHeaderTag { unsafe { let header = *(self.ptr() as *const ArenaHeader); header.get_tag() } } #[inline] pub fn payload_offset(self) -> *const u8 { unsafe { self.get_ptr() .offset(mem::size_of::() as isize) } } #[inline] pub fn get_mark_bit(self) -> bool { self.m() } } impl Add for HeapCellValue { type Output = HeapCellValue; fn add(self, rhs: usize) -> Self::Output { match self.get_tag() { tag @ HeapCellValueTag::Str | tag @ HeapCellValueTag::Lis | tag @ HeapCellValueTag::PStrOffset | tag @ HeapCellValueTag::PStrLoc | tag @ HeapCellValueTag::Var | tag @ HeapCellValueTag::AttrVar => { HeapCellValue::build_with(tag, (self.get_value() + rhs) as u64) } _ => { self } } } } impl Sub for HeapCellValue { type Output = HeapCellValue; fn sub(self, rhs: usize) -> Self::Output { match self.get_tag() { tag @ HeapCellValueTag::Str | tag @ HeapCellValueTag::Lis | tag @ HeapCellValueTag::PStrOffset | tag @ HeapCellValueTag::PStrLoc | tag @ HeapCellValueTag::Var | tag @ HeapCellValueTag::AttrVar => { HeapCellValue::build_with(tag, (self.get_value() - rhs) as u64) } _ => { self } } } } impl SubAssign for HeapCellValue { #[inline(always)] fn sub_assign(&mut self, rhs: usize) { *self = *self - rhs; } } impl Sub for HeapCellValue { type Output = HeapCellValue; fn sub(self, rhs: i64) -> Self::Output { if rhs < 0 { match self.get_tag() { tag @ HeapCellValueTag::Str | tag @ HeapCellValueTag::Lis | tag @ HeapCellValueTag::PStrOffset | tag @ HeapCellValueTag::PStrLoc | tag @ HeapCellValueTag::Var | tag @ HeapCellValueTag::AttrVar => { HeapCellValue::build_with(tag, (self.get_value() + rhs.abs() as usize) as u64) } _ => { self } } } else { self.sub(rhs as usize) } } }