]> Repositorios git - scryer-prolog.git/commitdiff
move CodeIndex to F64Table-like table
authorMark Thom <[email protected]>
Sun, 6 Apr 2025 19:11:57 +0000 (12:11 -0700)
committerMark Thom <[email protected]>
Wed, 23 Apr 2025 06:33:11 +0000 (23:33 -0700)
21 files changed:
Cargo.toml
src/arena.rs
src/arithmetic.rs
src/heap_print.rs
src/lib.rs
src/machine/arithmetic_ops.rs
src/machine/dispatch.rs
src/machine/lib_machine/mod.rs
src/machine/load_state.rs
src/machine/loader.rs
src/machine/machine_indices.rs
src/machine/machine_state_impl.rs
src/machine/mod.rs
src/machine/system_calls.rs
src/machine/unify.rs
src/macros.rs
src/offset_table.rs [new file with mode: 0644]
src/parser/ast.rs
src/parser/lexer.rs
src/parser/parser.rs
src/types.rs

index 536e57931b510bfaaabe821914030f80db44a85c..aeb66eb94e13ad51d47b159ede6736367aecdb54 100644 (file)
@@ -137,6 +137,7 @@ opt-level = 3
 [profile.release]
 lto = true
 opt-level = 3
+debug = 2
 
 [profile.wasm-dev]
 inherits = "dev"
index f9c2f274bab20ac9c19ffcbca8d14b9afafbf824..47de6fa3d7ad2910ea57d7ebabdc74a1fc798f2a 100644 (file)
@@ -3,20 +3,14 @@
 #[cfg(feature = "http")]
 use crate::http::{HttpListener, HttpResponse};
 use crate::machine::loader::LiveLoadState;
-use crate::machine::machine_indices::*;
 use crate::machine::streams::*;
-use crate::raw_block::*;
+use crate::offset_table::*;
 use crate::read::*;
 use crate::types::UntypedArenaPtr;
 
 use crate::parser::dashu::{Integer, Rational};
-use arcu::atomic::Arcu;
-use arcu::epoch_counters::GlobalEpochCounterPool;
-use arcu::rcu_ref::RcuRef;
-use arcu::Rcu;
 use ordered_float::OrderedFloat;
 
-use std::cell::UnsafeCell;
 use std::fmt;
 use std::fmt::Debug;
 use std::hash::{Hash, Hasher};
@@ -27,7 +21,7 @@ use std::ops::{Deref, DerefMut};
 use std::ptr;
 use std::ptr::addr_of_mut;
 use std::ptr::NonNull;
-use std::sync::RwLock;
+use std::sync::Arc;
 
 macro_rules! arena_alloc {
     ($e:expr, $arena:expr) => {{
@@ -39,7 +33,7 @@ macro_rules! arena_alloc {
 macro_rules! float_alloc {
     ($e:expr, $arena:expr) => {{
         let result = $e;
-        unsafe { $arena.f64_tbl.build_with(result).as_ptr() }
+        unsafe { $arena.f64_tbl.build_with(OrderedFloat(result)).as_ptr() }
     }};
 }
 
@@ -55,116 +49,6 @@ where
     payload_offset - header_offset
 }
 
-use std::sync::Arc;
-use std::sync::Mutex;
-use std::sync::Weak;
-
-const F64_TABLE_INIT_SIZE: usize = 1 << 16;
-const F64_TABLE_ALIGN: usize = 8;
-
-#[inline(always)]
-fn global_f64table() -> &'static RwLock<Weak<F64Table>> {
-    static GLOBAL_ATOM_TABLE: RwLock<Weak<F64Table>> = RwLock::new(Weak::new());
-    &GLOBAL_ATOM_TABLE
-}
-
-impl RawBlockTraits for F64Table {
-    #[inline]
-    fn init_size() -> usize {
-        F64_TABLE_INIT_SIZE
-    }
-
-    #[inline]
-    fn align() -> usize {
-        F64_TABLE_ALIGN
-    }
-}
-
-#[derive(Debug)]
-pub struct F64Table {
-    block: Arcu<RawBlock<F64Table>, GlobalEpochCounterPool>,
-    update: Mutex<()>,
-}
-
-#[inline(always)]
-pub fn lookup_float(
-    offset: F64Offset,
-) -> RcuRef<RawBlock<F64Table>, UnsafeCell<OrderedFloat<f64>>> {
-    let f64table = global_f64table()
-        .read()
-        .unwrap()
-        .upgrade()
-        .expect("We should only be looking up floats while there is a float table");
-
-    RcuRef::try_map(f64table.block.read(), |raw_block| unsafe {
-        raw_block
-            .base
-            .add(offset.0)
-            .cast_mut()
-            .cast::<UnsafeCell<OrderedFloat<f64>>>()
-            .as_ref()
-    })
-    .expect("The offset should result in a non-null pointer")
-}
-
-impl F64Table {
-    #[inline]
-    pub fn new() -> Arc<Self> {
-        let upgraded = global_f64table().read().unwrap().upgrade();
-        // don't inline upgraded, otherwise temporary will be dropped too late in case of None
-        if let Some(atom_table) = upgraded {
-            atom_table
-        } else {
-            let mut guard = global_f64table().write().unwrap();
-            // try to upgrade again in case we lost the race on the write lock
-            if let Some(atom_table) = guard.upgrade() {
-                atom_table
-            } else {
-                let atom_table = Arc::new(Self {
-                    block: Arcu::new(RawBlock::new(), GlobalEpochCounterPool),
-                    update: Mutex::new(()),
-                });
-                *guard = Arc::downgrade(&atom_table);
-                atom_table
-            }
-        }
-    }
-
-    #[allow(clippy::missing_safety_doc)]
-    pub unsafe fn build_with(&self, value: f64) -> F64Offset {
-        let update_guard = self.update.lock();
-
-        // we don't have an index table for lookups as AtomTable does so
-        // just get the epoch after we take the upgrade lock
-        let mut block_epoch = self.block.read();
-
-        let mut ptr;
-
-        loop {
-            ptr = block_epoch.alloc(mem::size_of::<f64>());
-
-            if ptr.is_null() {
-                let new_block = block_epoch.grow_new().unwrap();
-                self.block.replace(new_block);
-                block_epoch = self.block.read();
-            } else {
-                break;
-            }
-        }
-
-        ptr::write(ptr as *mut OrderedFloat<f64>, OrderedFloat(value));
-
-        let float = F64Offset(ptr as usize - block_epoch.base as usize);
-
-        // atometable would have to update the index table at this point
-
-        // expicit drop to ensure we don't accidentally drop it early
-        drop(update_guard);
-
-        float
-    }
-}
-
 #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)]
 #[bits = 7]
 pub enum ArenaHeaderTag {
@@ -190,10 +74,6 @@ pub enum ArenaHeaderTag {
     HttpListener = 0b1000001,
     HttpResponse = 0b1000010,
     Dropped = 0b1000100,
-    IndexPtrDynamicUndefined = 0b1000101,
-    IndexPtrDynamicIndex = 0b1000110,
-    IndexPtrIndex = 0b1000111,
-    IndexPtrUndefined = 0b1001000,
 }
 
 #[bitfield]
@@ -432,137 +312,6 @@ pub trait ArenaAllocated {
     }
 }
 
-#[derive(Debug)]
-pub struct F64Ptr(RcuRef<RawBlock<F64Table>, UnsafeCell<OrderedFloat<f64>>>);
-
-impl Clone for F64Ptr {
-    fn clone(&self) -> Self {
-        Self(RcuRef::clone(&self.0))
-    }
-}
-
-impl PartialEq for F64Ptr {
-    fn eq(&self, other: &F64Ptr) -> bool {
-        RcuRef::ptr_eq(&self.0, &other.0) || self.deref() == other.deref()
-    }
-}
-
-impl Eq for F64Ptr {}
-
-impl PartialOrd for F64Ptr {
-    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl Ord for F64Ptr {
-    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
-        (**self).cmp(&**other)
-    }
-}
-
-impl Hash for F64Ptr {
-    #[inline(always)]
-    fn hash<H: Hasher>(&self, hasher: &mut H) {
-        (self as &OrderedFloat<f64>).hash(hasher)
-    }
-}
-
-impl fmt::Display for F64Ptr {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", self as &OrderedFloat<f64>)
-    }
-}
-
-impl Deref for F64Ptr {
-    type Target = OrderedFloat<f64>;
-
-    #[inline]
-    fn deref(&self) -> &Self::Target {
-        unsafe { self.0.get().as_ref().unwrap() }
-    }
-}
-
-impl DerefMut for F64Ptr {
-    #[inline]
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        unsafe { &mut *self.0.get().as_mut().unwrap() }
-    }
-}
-
-impl F64Ptr {
-    #[inline(always)]
-    pub fn from_offset(offset: F64Offset) -> Self {
-        Self(lookup_float(offset))
-    }
-
-    #[inline(always)]
-    pub fn as_offset(&self) -> F64Offset {
-        F64Offset(self.0.get() as usize - RcuRef::get_root(&self.0).base as usize)
-    }
-}
-
-#[derive(Clone, Copy, Debug)]
-pub struct F64Offset(usize);
-
-impl F64Offset {
-    #[inline(always)]
-    pub fn new(offset: usize) -> Self {
-        Self(offset)
-    }
-
-    #[inline(always)]
-    pub fn from_ptr(ptr: F64Ptr) -> Self {
-        ptr.as_offset()
-    }
-
-    #[inline(always)]
-    pub fn as_ptr(self) -> F64Ptr {
-        F64Ptr::from_offset(self)
-    }
-
-    #[inline(always)]
-    pub fn to_u64(self) -> u64 {
-        self.0 as u64
-    }
-}
-
-impl PartialEq for F64Offset {
-    #[inline(always)]
-    fn eq(&self, other: &F64Offset) -> bool {
-        self.as_ptr() == other.as_ptr()
-    }
-}
-
-impl Eq for F64Offset {}
-
-impl PartialOrd for F64Offset {
-    #[inline(always)]
-    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl Ord for F64Offset {
-    #[inline(always)]
-    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
-        self.as_ptr().cmp(&other.as_ptr())
-    }
-}
-
-impl Hash for F64Offset {
-    #[inline(always)]
-    fn hash<H: Hasher>(&self, hasher: &mut H) {
-        self.as_ptr().hash(hasher)
-    }
-}
-
-impl fmt::Display for F64Offset {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "F64Offset({})", self.0)
-    }
-}
-
 impl ArenaAllocated for Integer {
     type Payload = Self;
     #[inline]
@@ -640,46 +389,6 @@ impl ArenaAllocated for HttpResponse {
     }
 }
 
-impl ArenaAllocated for IndexPtr {
-    type Payload = Self;
-    #[inline]
-    fn tag() -> ArenaHeaderTag {
-        ArenaHeaderTag::IndexPtrUndefined
-    }
-
-    #[inline]
-    fn header_offset_from_payload() -> usize {
-        0
-    }
-
-    /// #  Safety
-    /// - the caller must guarantee that the pointee type of UntypedArenaPtr is T
-    /// - the pointer must be non-null
-    unsafe fn typed_ptr(ptr: UntypedArenaPtr) -> TypedArenaPtr<Self> {
-        TypedArenaPtr(NonNull::new_unchecked(
-            ptr.get_ptr().cast_mut().cast::<IndexPtr>(),
-        ))
-    }
-
-    #[inline]
-    fn alloc(arena: &mut Arena, value: Self) -> TypedArenaPtr<Self> {
-        let slab = Box::new(IndexPtrSlab {
-            next: arena.base.take(),
-            index_ptr: value,
-        });
-
-        let (allocated_ptr, untyped_slab) = slab.to_untyped();
-        arena.base = Some(untyped_slab);
-        allocated_ptr
-    }
-
-    /// # Safety
-    /// - ptr points to an allocated slab of the correct kind
-    unsafe fn dealloc(ptr: NonNull<TypedAllocSlab<Self>>) {
-        drop(unsafe { Box::from_raw(ptr.as_ptr().cast::<IndexPtrSlab>()) });
-    }
-}
-
 #[repr(C)]
 #[derive(Debug)]
 pub struct AllocSlab {
@@ -687,13 +396,6 @@ pub struct AllocSlab {
     header: ArenaHeader,
 }
 
-#[repr(C)]
-#[derive(Debug)]
-pub struct IndexPtrSlab {
-    next: Option<UntypedArenaSlab>,
-    index_ptr: IndexPtr,
-}
-
 const _: () = {
     if std::mem::align_of::<AllocSlab>() < std::mem::align_of::<*const ()>() {
         panic!("alignment of AllocSlab is too low");
@@ -702,34 +404,8 @@ const _: () = {
     if std::mem::offset_of!(AllocSlab, header) % std::mem::align_of::<*const ()>() != 0 {
         panic!("alignment of header not a multiple of pointers alignment");
     }
-
-    if std::mem::offset_of!(AllocSlab, header) != std::mem::offset_of!(IndexPtrSlab, index_ptr) {
-        panic!("IndexPtrSlab.index_ptr and AllocSlab.header are at different offsets");
-    }
 };
 
-impl IndexPtrSlab {
-    #[inline]
-    pub fn to_untyped(self: Box<Self>) -> (TypedArenaPtr<IndexPtr>, UntypedArenaSlab) {
-        let raw_box = Box::into_raw(self);
-
-        // safety: the pointer from Box::into_raw fullfills addr_of_mut's saftey requirements
-        let index_ptr_ptr = unsafe { ptr::addr_of_mut!((*raw_box).index_ptr) };
-        let allocated_ptr = TypedArenaPtr(
-            // safety: the pointer points into a valid allocation so it is non null
-            unsafe { NonNull::new_unchecked(index_ptr_ptr) },
-        );
-
-        let untyped_arena = UntypedArenaSlab {
-            // safety: pointer from Box::into_raw is never null
-            slab: unsafe { NonNull::new_unchecked(raw_box.cast::<AllocSlab>()) },
-            tag: <IndexPtr as ArenaAllocated>::tag(),
-        };
-
-        (allocated_ptr, untyped_arena)
-    }
-}
-
 #[repr(C)]
 #[derive(Debug)]
 pub struct TypedAllocSlab<T: ?Sized + ArenaAllocated> {
@@ -783,6 +459,7 @@ impl Drop for UntypedArenaSlab {
 pub struct Arena {
     base: Option<UntypedArenaSlab>,
     pub f64_tbl: Arc<F64Table>,
+    pub code_index_tbl: Arc<CodeIndexTable>,
 }
 
 unsafe impl Send for Arena {}
@@ -795,6 +472,7 @@ impl Arena {
         Arena {
             base: None,
             f64_tbl: F64Table::new(),
+            code_index_tbl: CodeIndexTable::new(),
         }
     }
 }
@@ -870,12 +548,6 @@ unsafe fn drop_slab_in_place(value: NonNull<AllocSlab>, tag: ArenaHeaderTag) {
         ArenaHeaderTag::StandardErrorStream => {
             drop_typed_slab_in_place!(StandardErrorStream, value);
         }
-        ArenaHeaderTag::IndexPtrUndefined
-        | ArenaHeaderTag::IndexPtrDynamicUndefined
-        | ArenaHeaderTag::IndexPtrDynamicIndex
-        | ArenaHeaderTag::IndexPtrIndex => {
-            drop_typed_slab_in_place!(IndexPtr, value);
-        }
         ArenaHeaderTag::NullStream => {
             unreachable!("NullStream is never arena allocated!");
         }
index 4863932a5558644de821bcc8bd0b78097b7b3f51..2bdcc3153872a88e9a3481a4a880d73d3c9b1124 100644 (file)
@@ -7,6 +7,7 @@ use crate::debray_allocator::*;
 use crate::forms::*;
 use crate::instructions::*;
 use crate::iterators::*;
+use crate::offset_table::*;
 use crate::targets::QueryInstruction;
 use crate::types::*;
 
index 8c39b41e72a6e6d8d2388af57f8ad027ebd3346a..f11fb4d57c419721ed0d151957b62f1a7353b5b5 100644 (file)
@@ -12,6 +12,7 @@ use crate::machine::machine_indices::*;
 use crate::machine::partial_string::*;
 use crate::machine::stack::*;
 use crate::machine::streams::*;
+use crate::offset_table::*;
 use crate::types::*;
 
 use dashu::base::Signed;
@@ -1506,21 +1507,23 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
         }
     }
 
-    fn print_index_ptr(&mut self, index_ptr: IndexPtr, max_depth: usize) {
+    fn print_index_ptr(&mut self, idx: CodeIndex, max_depth: usize) {
         if self.format_struct(max_depth, 1, atom!("$index_ptr")) {
             let atom = self.state_stack.pop().unwrap();
 
             self.state_stack.pop();
             self.state_stack.pop();
 
-            let offset = if index_ptr.is_undefined() || index_ptr.is_dynamic_undefined() {
+            let idx_ptr = idx.as_ptr();
+
+            let offset = if idx_ptr.is_undefined() || idx_ptr.is_dynamic_undefined() {
                 TokenOrRedirect::Atom(atom!("undefined"))
             } else {
-                let idx = index_ptr.p() as i64;
+                let idx_ptr_p = idx_ptr.p() as i64;
 
                 TokenOrRedirect::NumberFocus(
                     max_depth,
-                    NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(idx))),
+                    NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(idx_ptr_p))),
                     None,
                 )
             };
@@ -1707,6 +1710,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
                     });
                 }
             }
+            (HeapCellValueTag::CodeIndex, idx) => {
+                self.print_index_ptr(idx, self.max_depth);
+            }
             (HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint, n) => {
                 self.print_number(max_depth, NumberFocus::Unfocused(Number::Fixnum(n)), &op);
             }
@@ -1750,9 +1756,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
                    (ArenaHeaderTag::Dropped, _value) => {
                        self.print_impromptu_atom(atom!("$dropped_value"));
                    }
-                   (ArenaHeaderTag::IndexPtr, index_ptr) => {
-                       self.print_index_ptr(*index_ptr, max_depth);
-                   }
                    _ => {
                    }
                );
index 1926c7df5265d166be0b2ef29ede9f9f7bbf06fd..598110ad4d17d2e499b0f768c9afd5a6ac37a8b5 100644 (file)
@@ -11,6 +11,7 @@ pub(crate) mod macros;
 pub(crate) mod atom_table;
 #[macro_use]
 pub(crate) mod arena;
+pub(crate) mod offset_table;
 #[macro_use]
 pub(crate) mod parser;
 #[macro_use]
index f7bd69eff253a69ec4c37d6cefd51fe0f035bba9..43bb37234e7bacc4c21410da980f59fe1f7450c3 100644 (file)
@@ -11,6 +11,7 @@ use crate::forms::*;
 use crate::heap_iter::*;
 use crate::machine::machine_errors::*;
 use crate::machine::machine_state::*;
+use crate::offset_table::*;
 use crate::parser::ast::*;
 use crate::parser::dashu::{Integer, Rational};
 use crate::types::*;
index f1519986fc17becb139fb5391636a8cc26876fa0..4c9db0e8680376378f7a93d4c6b7a01ef579341f 100644 (file)
@@ -610,7 +610,7 @@ impl Machine {
                             .indices
                             .code_dir
                             .get_index(predicate_idx)
-                            .map(|x| x.1.p() as usize)
+                            .map(|x| x.1.as_ptr().p() as usize)
                             .unwrap();
 
                         debug_assert!(current_pred_start <= p);
@@ -619,7 +619,7 @@ impl Machine {
                             .indices
                             .code_dir
                             .get_index(predicate_idx + 1)
-                            .map(|x| x.1.p() as usize)
+                            .map(|x| x.1.as_ptr().p() as usize)
                             .unwrap_or(self.code.len());
 
                         debug_assert!(current_pred_end >= p);
index 66c1783ab248f37e40cf65abbec7625e82119ce8..d11419e01b03ef78b25cbd389a88fedff881db79 100644 (file)
@@ -7,9 +7,9 @@ use crate::heap_iter::{stackful_post_order_iter, NonListElider};
 use crate::machine::machine_indices::VarKey;
 use crate::machine::mock_wam::CompositeOpDir;
 use crate::machine::{
-    ArenaHeaderTag, F64Offset, F64Ptr, Fixnum, Number, BREAK_FROM_DISPATCH_LOOP_LOC,
-    LIB_QUERY_SUCCESS,
+    ArenaHeaderTag, Fixnum, Number, BREAK_FROM_DISPATCH_LOOP_LOC, LIB_QUERY_SUCCESS,
 };
+use crate::offset_table::*;
 use crate::parser::ast::{Var, VarPtr};
 use crate::parser::parser::{Parser, Tokens};
 use crate::read::{write_term_to_heap, TermWriteResult};
index 64d0bb827c43010890a21012da7bc74760dc6235..0a712c1a7b56b541645bab3b2796b240d4c8bb81 100644 (file)
@@ -147,7 +147,7 @@ pub(super) fn import_module_exports<'a, LS: LoadState<'a>>(
                         src_code_index.get(),
                     );
 
-                    if src_code_index.is_dynamic_undefined() {
+                    if src_code_index.as_ptr().is_dynamic_undefined() {
                         code_dir.insert(key, src_code_index);
                     }
                 } else {
@@ -486,7 +486,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
                 continue;
             }
 
-            if !code_index.is_undefined() && !code_index.is_dynamic_undefined() {
+            if !code_index.as_ptr().is_undefined() && !code_index.as_ptr().is_dynamic_undefined() {
                 let old_index_ptr = code_index.replace(IndexPtr::undefined());
 
                 self.payload.retraction_info.push_record(
index c117887b0a3d09e20cb216df738f391dbf1d0869..89b83ed3158f630fa9546022c1618506b0d3be88 100644 (file)
@@ -1219,7 +1219,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
 
         let code_index = self.get_or_insert_code_index(key, compilation_target);
 
-        if code_index.is_undefined() {
+        if code_index.as_ptr().is_undefined() {
             set_code_index(
                 &mut self.payload.retraction_info,
                 &compilation_target,
@@ -1378,73 +1378,72 @@ impl MachineState {
         while let Some(addr) = iter.next() {
             let addr = unmark_cell_bits!(addr);
 
-            if let Ok(literal) = Literal::try_from(addr) {
-                term_stack.push(Term::Literal(Cell::default(), literal));
-            } else {
-                read_heap_cell!(addr,
-                    (HeapCellValueTag::Lis) => {
-                        use crate::parser::parser::as_partial_string;
+            read_heap_cell!(addr,
+                (HeapCellValueTag::Lis) => {
+                    use crate::parser::parser::as_partial_string;
 
-                        let tail = term_stack.pop().unwrap();
-                        let head = term_stack.pop().unwrap();
+                    let tail = term_stack.pop().unwrap();
+                    let head = term_stack.pop().unwrap();
 
-                        match as_partial_string(head, tail) {
-                            Ok((string, Some(tail))) => {
-                                term_stack.push(Term::PartialString(Cell::default(), Rc::new(string), tail));
-                            }
-                            Ok((string, None)) => {
-                                term_stack.push(Term::CompleteString(Cell::default(), Rc::new(string)));
-                            }
-                            Err(cons_term) => term_stack.push(cons_term),
+                    match as_partial_string(head, tail) {
+                        Ok((string, Some(tail))) => {
+                            term_stack.push(Term::PartialString(Cell::default(), Rc::new(string), tail));
                         }
+                        Ok((string, None)) => {
+                            term_stack.push(Term::CompleteString(Cell::default(), Rc::new(string)));
+                        }
+                        Err(cons_term) => term_stack.push(cons_term),
                     }
-                    (HeapCellValueTag::StackVar, h) => {
-                        term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("s_{}", h))));
-                    }
-                    (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
-                        term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{}", h))));
+                }
+                (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | HeapCellValueTag::F64) => {
+                    term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
+                }
+                (HeapCellValueTag::StackVar, h) => {
+                    term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("s_{}", h))));
+                }
+                (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
+                    term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{}", h))));
+                }
+                (HeapCellValueTag::Atom, (name, arity)) => {
+                    let h = iter.focus().value() as usize;
+                    let mut arity = arity;
+                    let value = iter.heap[h.saturating_sub(1)];
+
+                    if let Some(idx) = get_structure_index(value) {
+                        term_stack.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx)));
+                        arity += 1;
                     }
-                    (HeapCellValueTag::Atom, (name, arity)) => {
-                        let h = iter.focus().value() as usize;
-                        let mut arity = arity;
-                        let value = iter.heap[h.saturating_sub(1)];
-
-                        if let Some(idx) = get_structure_index(value) {
-                            term_stack.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx)));
-                            arity += 1;
-                        }
 
-                        if arity == 0 {
-                            term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
-                        } else {
-                            let subterms = term_stack
-                                .drain(term_stack.len() - arity ..)
-                                .collect();
+                    if arity == 0 {
+                        term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
+                    } else {
+                        let subterms = term_stack
+                            .drain(term_stack.len() - arity ..)
+                            .collect();
 
-                            term_stack.push(Term::Clause(Cell::default(), name, subterms));
-                        }
-                    }
-                    (HeapCellValueTag::PStrLoc, h) => {
-                        let HeapStringScan { string, .. } = iter.heap.scan_slice_to_str(h);
-                        let tail = term_stack.pop().unwrap();
-
-                        term_stack.push(if matches!(tail, Term::Literal(_, Literal::Atom(atom!("[]")))) {
-                            Term::CompleteString(
-                                Cell::default(),
-                                Rc::new(string.to_owned()),
-                            )
-                        } else {
-                            Term::PartialString(
-                                Cell::default(),
-                                Rc::new(string.to_owned()),
-                                Box::new(tail),
-                            )
-                        });
-                    }
-                    _ => {
+                        term_stack.push(Term::Clause(Cell::default(), name, subterms));
                     }
-                );
-            }
+                }
+                (HeapCellValueTag::PStrLoc, h) => {
+                    let HeapStringScan { string, .. } = iter.heap.scan_slice_to_str(h);
+                    let tail = term_stack.pop().unwrap();
+
+                    term_stack.push(if matches!(tail, Term::Literal(_, Literal::Atom(atom!("[]")))) {
+                        Term::CompleteString(
+                            Cell::default(),
+                            Rc::new(string.to_owned()),
+                        )
+                    } else {
+                        Term::PartialString(
+                            Cell::default(),
+                            Rc::new(string.to_owned()),
+                            Box::new(tail),
+                        )
+                    });
+                }
+                _ => {
+                }
+            );
         }
 
         debug_assert!(term_stack.len() == 1);
index d4a10a8c19e9d50d4c515d6322672d2f20af7700..8dc5291f0d6dfd93a37d8a2c9dbc166806dfac02 100644 (file)
@@ -10,6 +10,7 @@ use crate::machine::machine_state::*;
 use crate::machine::streams::{Stream, StreamOptions};
 use crate::machine::ClauseType;
 use crate::machine::MachineStubGen;
+use crate::offset_table::*;
 
 use fxhash::FxBuildHasher;
 use indexmap::{IndexMap, IndexSet};
@@ -18,7 +19,7 @@ use scryer_modular_bitfield::{bitfield, BitfieldSpecifier};
 
 use std::cmp::Ordering;
 use std::collections::BTreeSet;
-use std::ops::{Deref, DerefMut};
+use std::ops::Deref;
 
 use crate::types::*;
 
@@ -129,7 +130,7 @@ impl IndexPtr {
 }
 
 #[derive(Debug, Clone, Copy, Ord, Hash, PartialOrd, Eq, PartialEq)]
-pub struct CodeIndex(TypedArenaPtr<IndexPtr>);
+pub struct CodeIndex(CodeIndexOffset);
 
 #[cfg(target_pointer_width = "32")]
 const_assert!(std::mem::align_of::<CodeIndex>() == 4);
@@ -137,47 +138,24 @@ const_assert!(std::mem::align_of::<CodeIndex>() == 4);
 #[cfg(target_pointer_width = "64")]
 const_assert!(std::mem::align_of::<CodeIndex>() == 8);
 
-impl Deref for CodeIndex {
-    type Target = TypedArenaPtr<IndexPtr>;
-
-    #[inline(always)]
-    fn deref(&self) -> &TypedArenaPtr<IndexPtr> {
-        &self.0
-    }
-}
-
-impl DerefMut for CodeIndex {
-    #[inline(always)]
-    fn deref_mut(&mut self) -> &mut TypedArenaPtr<IndexPtr> {
-        &mut self.0
-    }
-}
-
-impl From<CodeIndex> for UntypedArenaPtr {
-    #[inline(always)]
-    fn from(ptr: CodeIndex) -> UntypedArenaPtr {
-        UntypedArenaPtr::build_with(ptr.0.as_ptr() as usize)
-    }
-}
-
-impl From<TypedArenaPtr<IndexPtr>> for CodeIndex {
+impl From<CodeIndex> for HeapCellValue {
     #[inline(always)]
-    fn from(ptr: TypedArenaPtr<IndexPtr>) -> CodeIndex {
-        CodeIndex(ptr)
+    fn from(idx: CodeIndex) -> HeapCellValue {
+        HeapCellValue::from(idx.as_ptr())
     }
 }
 
-impl From<CodeIndex> for HeapCellValue {
+impl From<CodeIndexOffset> for CodeIndex {
     #[inline(always)]
-    fn from(idx: CodeIndex) -> HeapCellValue {
-        untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx))
+    fn from(offset: CodeIndexOffset) -> CodeIndex {
+        CodeIndex(offset)
     }
 }
 
 impl CodeIndex {
     #[inline]
     pub(crate) fn new(ptr: IndexPtr, arena: &mut Arena) -> Self {
-        CodeIndex(arena_alloc!(ptr, arena))
+        unsafe { CodeIndex(arena.code_index_tbl.build_with(ptr)) }
     }
 
     #[inline(always)]
@@ -186,39 +164,37 @@ impl CodeIndex {
     }
 
     pub(crate) fn local(&self) -> Option<usize> {
-        match self.0.tag() {
-            IndexPtrTag::Index => Some(self.0.p() as usize),
-            IndexPtrTag::DynamicIndex => Some(self.0.p() as usize),
+        match self.0.as_ptr().tag() {
+            IndexPtrTag::Index => Some(self.get().p() as usize),
+            IndexPtrTag::DynamicIndex => Some(self.get().p() as usize),
             _ => None,
         }
     }
 
     #[inline(always)]
     pub(crate) fn get(&self) -> IndexPtr {
-        *self.0.deref()
+        *self.as_ptr().deref()
     }
 
     #[inline(always)]
     pub(crate) fn set(&mut self, value: IndexPtr) {
-        *self.0.deref_mut() = value;
+        self.as_ptr().set(value);
     }
 
     #[inline(always)]
     pub(crate) fn get_tag(self) -> IndexPtrTag {
-        self.0.tag()
+        self.get().tag()
     }
 
     #[inline(always)]
     pub(crate) fn replace(&mut self, value: IndexPtr) -> IndexPtr {
-        std::mem::replace(self.0.deref_mut(), value)
+        self.as_ptr().replace(value)
     }
 
-    /*
     #[inline(always)]
-    pub(crate) fn as_ptr(&self) -> *const IndexPtr {
+    pub(crate) fn as_ptr(&self) -> CodeIndexPtr {
         self.0.as_ptr()
     }
-    */
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
index bd041f36b0016306bf355b6bbae8228b14895710..66d3237bcd01135f1bc0ca067165e5f2fce8761e 100644 (file)
@@ -11,6 +11,7 @@ use crate::machine::machine_state::*;
 use crate::machine::partial_string::*;
 use crate::machine::stack::*;
 use crate::machine::unify::*;
+use crate::offset_table::*;
 use crate::parser::ast::*;
 use crate::parser::dashu::{Integer, Rational};
 use crate::types::*;
index 5c4056a743f13345a705b2b348da755d9d83795b..989ff489f7ae207829f17e39195c946eb745b197 100644 (file)
@@ -45,6 +45,7 @@ use crate::machine::machine_indices::*;
 use crate::machine::machine_state::*;
 use crate::machine::stack::*;
 use crate::machine::streams::*;
+use crate::offset_table::*;
 use crate::parser::ast::*;
 use crate::parser::dashu::{Integer, Rational};
 use crate::types::*;
@@ -233,13 +234,8 @@ pub(crate) fn import_builtin_impls(code_dir: &CodeDir, builtins: &mut Module) {
 #[inline]
 pub(crate) fn get_structure_index(value: HeapCellValue) -> Option<CodeIndex> {
     read_heap_cell!(value,
-        (HeapCellValueTag::Cons, cons_ptr) => {
-             match_untyped_arena_ptr!(cons_ptr,
-                 (ArenaHeaderTag::IndexPtr, ip) => {
-                     return Some(CodeIndex::from(ip));
-                 }
-                 _ => {}
-             );
+        (HeapCellValueTag::CodeIndex, ip) => {
+            return Some(ip);
         }
         _ => {
         }
index 0b1b835f9b187d5764fbe1548470d5518535a180..fb2849780e8de6601ae6fcf56d87be8346fac7b1 100644 (file)
@@ -1468,7 +1468,7 @@ impl Machine {
         };
 
         if let Some(code_index) = index_cell {
-            if !code_index.is_undefined() {
+            if !code_index.as_ptr().is_undefined() {
                 load_registers(&mut self.machine_st, goal, goal_arity);
                 self.machine_st.neck_cut();
                 return call_at_index(self, name, arity, code_index.get());
@@ -1617,8 +1617,7 @@ impl Machine {
 
         let expanded_term = if result.is_simple_goal {
             let idx = self.get_or_insert_qualified_code_index(module_name, result.key);
-            self.machine_st.heap[result.index_ptr_loc] =
-                untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx));
+            self.machine_st.heap[result.index_ptr_loc] = HeapCellValue::from(idx);
             result.goal
         } else {
             let mut unexpanded_vars = IndexSet::with_hasher(FxBuildHasher::default());
@@ -1656,7 +1655,7 @@ impl Machine {
                     );
 
                     writer.write_with(|section| {
-                        section.push_cell(untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx)));
+                        section.push_cell(HeapCellValue::from(idx));
                         section.push_cell(atom_as_cell!(atom!("$aux"), 0));
 
                         for value in unexpanded_vars.difference(&result.supp_vars).cloned() {
@@ -1693,14 +1692,8 @@ impl Machine {
 
             let idx_cell = self.machine_st.heap[s.saturating_sub(1)];
 
-            if HeapCellValueTag::Cons == idx_cell.get_tag() {
-                match_untyped_arena_ptr!(cell_as_untyped_arena_ptr!(idx_cell),
-                     (ArenaHeaderTag::IndexPtr, _ip) => {
-                         return true;
-                     }
-                     _ => {
-                     }
-                );
+            if HeapCellValueTag::CodeIndex == idx_cell.get_tag() {
+                return true;
             }
         }
 
index b9aae0e6ea46accc293504b5918ffa250869aae0..7d451fc8e9d2c5bcd20ba216a65a3402b7dc1a79 100644 (file)
@@ -3,6 +3,7 @@ use crate::forms::*;
 use crate::heap_iter::{stackful_preorder_iter, NonListElider};
 use crate::machine::machine_state::*;
 use crate::machine::*;
+use crate::offset_table::*;
 use crate::types::*;
 
 use std::ops::{Deref, DerefMut};
index e23980f3e1fbdf60636091cdadc2a1c50ac31e26..73c36b0df58c58a36668edfd3e48c952e1d62b22 100644 (file)
@@ -62,7 +62,14 @@ macro_rules! cell_as_atom_cell {
 macro_rules! cell_as_f64_ptr {
     ($cell:expr) => {{
         let offset = $cell.get_value() as usize;
-        F64Ptr::from_offset(F64Offset::new(offset))
+        F64Ptr::from_offset(F64Offset::from(offset))
+    }};
+}
+
+macro_rules! cell_as_code_index {
+    ($cell:expr) => {{
+        let offset = $cell.get_value() as usize;
+        CodeIndex::from(CodeIndexOffset::from(offset))
     }};
 }
 
@@ -140,7 +147,7 @@ macro_rules! raw_ptr_as_cell {
     ($ptr:expr) => {{
         // Cell is 64-bit, but raw ptr is 32-bit in 32-bit systems
         // TODO use <*{const,mut} _>::addr instead of as when the strict_provenance feature is stable rust-lang/rust#95228
-        // we might need <*{const,mut} _>::expose_provenance for strict provenance, dependening on how we recreate a pointer later
+        // we might need <*{const,mut} _>::expose_provenance for strict provenance, depending on how we recreate a pointer later
         let ptr : *const _ = $ptr;
         HeapCellValue::from_ptr_addr(ptr as usize)
     }};
@@ -216,12 +223,6 @@ macro_rules! match_untyped_arena_ptr_pat_body {
         #[allow(unused_braces)]
         $code
     }};
-    ($ptr:ident, IndexPtr, $ip:ident, $code:expr) => {{
-        #[allow(unused_mut)]
-        let mut $ip = unsafe { $ptr.as_typed_ptr::<IndexPtr>() };
-        #[allow(unused_braces)]
-        $code
-    }};
     ($ptr:ident, $($tags:tt)|+, $s:ident, $code:expr) => {{
         let $s = Stream::from_tag($ptr.get_tag(), $ptr);
         #[allow(unused_braces)]
@@ -245,12 +246,6 @@ macro_rules! match_untyped_arena_ptr_pat {
             | ArenaHeaderTag::StandardOutputStream
             | ArenaHeaderTag::StandardErrorStream
     };
-    (IndexPtr) => {
-        ArenaHeaderTag::IndexPtrUndefined
-            | ArenaHeaderTag::IndexPtrDynamicUndefined
-            | ArenaHeaderTag::IndexPtrDynamicIndex
-            | ArenaHeaderTag::IndexPtrIndex
-    };
     ($tag:ident) => {
         ArenaHeaderTag::$tag
     };
@@ -281,6 +276,11 @@ macro_rules! read_heap_cell_pat_body {
         #[allow(unused_braces)]
         $code
     }};
+    ($cell:ident, CodeIndex, $n:ident, $code:expr) => {{
+        let $n = cell_as_code_index!($cell);
+        #[allow(unused_braces)]
+        $code
+    }};
     ($cell:ident, Atom, ($name:ident, $arity:ident), $code:expr) => {{
         let ($name, $arity) = cell_as_atom_cell!($cell).get_name_and_arity();
         #[allow(unused_braces)]
diff --git a/src/offset_table.rs b/src/offset_table.rs
new file mode 100644 (file)
index 0000000..5afcf89
--- /dev/null
@@ -0,0 +1,428 @@
+use std::cell::UnsafeCell;
+use std::hash::{Hash, Hasher};
+use std::ops::{Deref, DerefMut};
+use std::sync::RwLock;
+use std::sync::Weak;
+use std::sync::{Arc, Mutex};
+use std::{fmt, mem, ptr};
+
+use arcu::atomic::Arcu;
+use arcu::epoch_counters::GlobalEpochCounterPool;
+use arcu::rcu_ref::RcuRef;
+use arcu::Rcu;
+
+use crate::machine::machine_indices::IndexPtr;
+use crate::raw_block::RawBlock;
+use crate::raw_block::RawBlockTraits;
+
+use ordered_float::OrderedFloat;
+
+const F64_TABLE_INIT_SIZE: usize = 1 << 16;
+const F64_TABLE_ALIGN: usize = 8;
+
+const CODE_INDEX_TABLE_INIT_SIZE: usize = 1 << 16;
+const CODE_INDEX_TABLE_ALIGN: usize = 8;
+
+#[derive(Debug)]
+pub struct OffsetTableImpl<T>
+where
+    OffsetTableImpl<T>: RawBlockTraits,
+{
+    block: Arcu<RawBlock<OffsetTableImpl<T>>, GlobalEpochCounterPool>,
+    update: Mutex<()>,
+}
+
+pub type F64Table = OffsetTableImpl<OrderedFloat<f64>>;
+pub type CodeIndexTable = OffsetTableImpl<IndexPtr>;
+
+impl RawBlockTraits for F64Table {
+    #[inline]
+    fn init_size() -> usize {
+        F64_TABLE_INIT_SIZE
+    }
+
+    #[inline]
+    fn align() -> usize {
+        F64_TABLE_ALIGN
+    }
+}
+
+impl RawBlockTraits for CodeIndexTable {
+    #[inline]
+    fn init_size() -> usize {
+        CODE_INDEX_TABLE_INIT_SIZE
+    }
+
+    #[inline]
+    fn align() -> usize {
+        CODE_INDEX_TABLE_ALIGN
+    }
+}
+
+pub trait OffsetTable: RawBlockTraits {
+    type Offset: Copy + From<usize> + Into<usize>;
+    type Stored;
+
+    fn global_table() -> &'static RwLock<Weak<Self>>;
+}
+
+impl OffsetTable for F64Table {
+    type Offset = F64Offset;
+    type Stored = OrderedFloat<f64>;
+
+    #[inline(always)]
+    fn global_table() -> &'static RwLock<Weak<Self>> {
+        static GLOBAL_ATOM_TABLE: RwLock<Weak<F64Table>> = RwLock::new(Weak::new());
+        &GLOBAL_ATOM_TABLE
+    }
+}
+
+impl OffsetTable for CodeIndexTable {
+    type Offset = CodeIndexOffset;
+    type Stored = IndexPtr;
+
+    #[inline(always)]
+    fn global_table() -> &'static RwLock<Weak<CodeIndexTable>> {
+        static GLOBAL_CODE_INDEX_TABLE: RwLock<Weak<CodeIndexTable>> = RwLock::new(Weak::new());
+        &GLOBAL_CODE_INDEX_TABLE
+    }
+}
+
+impl<T: 'static> OffsetTableImpl<T>
+where
+    OffsetTableImpl<T>: OffsetTable<Stored = T>,
+{
+    #[inline]
+    pub fn new() -> Arc<Self> {
+        let upgraded = Self::global_table().read().unwrap().upgrade();
+        // don't inline upgraded, otherwise temporary will be dropped too late in case of None
+        if let Some(atom_table) = upgraded {
+            atom_table
+        } else {
+            let mut guard = Self::global_table().write().unwrap();
+            // try to upgrade again in case we lost the race on the write lock
+            if let Some(atom_table) = guard.upgrade() {
+                atom_table
+            } else {
+                let table = Arc::new(Self {
+                    block: Arcu::new(RawBlock::new(), GlobalEpochCounterPool),
+                    update: Mutex::new(()),
+                });
+                *guard = Arc::downgrade(&table);
+                table
+            }
+        }
+    }
+
+    #[allow(clippy::missing_safety_doc)]
+    pub unsafe fn build_with(
+        &self,
+        value: <OffsetTableImpl<T> as OffsetTable>::Stored,
+    ) -> <OffsetTableImpl<T> as OffsetTable>::Offset {
+        let update_guard = self.update.lock();
+
+        // we don't have an index table for lookups as AtomTable does so
+        // just get the epoch after we take the upgrade lock
+        let mut block_epoch = self.block.read();
+
+        let mut ptr;
+
+        loop {
+            ptr = block_epoch.alloc(mem::size_of::<T>());
+
+            if ptr.is_null() {
+                let new_block = block_epoch.grow_new().unwrap();
+                self.block.replace(new_block);
+                block_epoch = self.block.read();
+            } else {
+                break;
+            }
+        }
+
+        ptr::write(ptr as *mut T, value);
+
+        let value = <OffsetTableImpl<T> as OffsetTable>::Offset::from(
+            ptr as usize - block_epoch.base as usize,
+        );
+
+        // AtomTable would have to update the index table at this point
+        // explicit drop to ensure we don't accidentally drop it early
+        drop(update_guard);
+
+        value
+    }
+
+    pub fn lookup(offset: <Self as OffsetTable>::Offset) -> RcuRef<RawBlock<Self>, UnsafeCell<T>> {
+        let table = Self::global_table()
+            .read()
+            .unwrap()
+            .upgrade()
+            .expect("We should only be looking up entries when there is a table");
+
+        RcuRef::try_map(table.block.read(), |raw_block| unsafe {
+            raw_block
+                .base
+                .add(offset.into())
+                .cast_mut()
+                .cast::<UnsafeCell<T>>()
+                .as_ref()
+        })
+        .expect("The offset should result in a non-null pointer")
+    }
+}
+
+#[derive(Debug)]
+pub struct TablePtr<T>(RcuRef<RawBlock<OffsetTableImpl<T>>, UnsafeCell<T>>)
+where
+    OffsetTableImpl<T>: RawBlockTraits;
+
+pub type CodeIndexPtr = TablePtr<IndexPtr>;
+pub type F64Ptr = TablePtr<OrderedFloat<f64>>;
+
+impl<T> Clone for TablePtr<T>
+where
+    OffsetTableImpl<T>: RawBlockTraits,
+{
+    fn clone(&self) -> Self {
+        Self(RcuRef::clone(&self.0))
+    }
+}
+
+impl<T: PartialEq> PartialEq for TablePtr<T>
+where
+    OffsetTableImpl<T>: RawBlockTraits,
+{
+    fn eq(&self, other: &TablePtr<T>) -> bool {
+        RcuRef::ptr_eq(&self.0, &other.0) || self.deref() == other.deref()
+    }
+}
+
+impl<T: Eq> Eq for TablePtr<T> where OffsetTableImpl<T>: RawBlockTraits {}
+
+impl<T: PartialOrd + Ord> PartialOrd for TablePtr<T>
+where
+    OffsetTableImpl<T>: RawBlockTraits,
+{
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl<T: Ord> Ord for TablePtr<T>
+where
+    OffsetTableImpl<T>: RawBlockTraits,
+{
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        (**self).cmp(&**other)
+    }
+}
+
+impl<T: Hash> Hash for TablePtr<T>
+where
+    OffsetTableImpl<T>: RawBlockTraits,
+{
+    #[inline(always)]
+    fn hash<H: Hasher>(&self, hasher: &mut H) {
+        (self as &T).hash(hasher)
+    }
+}
+
+impl<T: fmt::Display> fmt::Display for TablePtr<T>
+where
+    OffsetTableImpl<T>: RawBlockTraits,
+{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self as &T)
+    }
+}
+
+impl<T> Deref for TablePtr<T>
+where
+    OffsetTableImpl<T>: RawBlockTraits,
+{
+    type Target = T;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        unsafe { self.0.get().as_ref().unwrap() }
+    }
+}
+
+impl<T> DerefMut for TablePtr<T>
+where
+    OffsetTableImpl<T>: RawBlockTraits,
+{
+    #[inline]
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        unsafe { &mut *self.0.get().as_mut().unwrap() }
+    }
+}
+
+impl<T: 'static> TablePtr<T>
+where
+    OffsetTableImpl<T>: OffsetTable<Stored = T>,
+{
+    #[inline(always)]
+    pub fn from_offset(offset: <OffsetTableImpl<T> as OffsetTable>::Offset) -> Self {
+        Self(OffsetTableImpl::<T>::lookup(offset))
+    }
+
+    #[inline(always)]
+    pub fn as_offset(&self) -> <OffsetTableImpl<T> as OffsetTable>::Offset {
+        <OffsetTableImpl<T> as OffsetTable>::Offset::from(
+            self.0.get() as usize - RcuRef::get_root(&self.0).base as usize,
+        )
+    }
+}
+
+#[derive(Clone, Copy, Debug)]
+pub struct F64Offset(usize);
+
+impl From<usize> for F64Offset {
+    #[inline(always)]
+    fn from(offset: usize) -> Self {
+        Self(offset)
+    }
+}
+
+impl Into<usize> for F64Offset {
+    #[inline(always)]
+    fn into(self: Self) -> usize {
+        self.0
+    }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct CodeIndexOffset(usize);
+
+impl From<usize> for CodeIndexOffset {
+    #[inline(always)]
+    fn from(offset: usize) -> Self {
+        Self(offset)
+    }
+}
+
+impl Into<usize> for CodeIndexOffset {
+    #[inline(always)]
+    fn into(self: Self) -> usize {
+        self.0
+    }
+}
+
+impl CodeIndexOffset {
+    #[inline(always)]
+    pub fn from_ptr(ptr: CodeIndexPtr) -> Self {
+        ptr.as_offset()
+    }
+
+    #[inline(always)]
+    pub fn as_ptr(self) -> CodeIndexPtr {
+        CodeIndexPtr::from_offset(self)
+    }
+
+    #[inline(always)]
+    pub fn to_u64(self) -> u64 {
+        self.0 as u64
+    }
+}
+
+impl PartialEq for CodeIndexOffset {
+    #[inline(always)]
+    fn eq(&self, other: &CodeIndexOffset) -> bool {
+        self.as_ptr() == other.as_ptr()
+    }
+}
+
+impl Eq for CodeIndexOffset {}
+
+impl PartialOrd for CodeIndexOffset {
+    #[inline(always)]
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for CodeIndexOffset {
+    #[inline(always)]
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        self.as_ptr().cmp(&other.as_ptr())
+    }
+}
+
+impl Hash for CodeIndexOffset {
+    #[inline(always)]
+    fn hash<H: Hasher>(&self, hasher: &mut H) {
+        self.as_ptr().hash(hasher)
+    }
+}
+
+impl fmt::Display for CodeIndexOffset {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "CodeIndexOffset({})", self.0)
+    }
+}
+
+impl CodeIndexPtr {
+    #[inline]
+    pub fn set(&self, val: IndexPtr) {
+        unsafe { *self.0.get() = val };
+    }
+
+    #[inline]
+    pub fn replace(&self, val: IndexPtr) -> IndexPtr {
+        unsafe { self.0.get().replace(val) }
+    }
+}
+
+impl F64Offset {
+    #[inline(always)]
+    pub fn from_ptr(ptr: F64Ptr) -> Self {
+        ptr.as_offset()
+    }
+
+    #[inline(always)]
+    pub fn as_ptr(self) -> F64Ptr {
+        F64Ptr::from_offset(self)
+    }
+
+    #[inline(always)]
+    pub fn to_u64(self) -> u64 {
+        self.0 as u64
+    }
+}
+
+impl PartialEq for F64Offset {
+    #[inline(always)]
+    fn eq(&self, other: &F64Offset) -> bool {
+        self.as_ptr() == other.as_ptr()
+    }
+}
+
+impl Eq for F64Offset {}
+
+impl PartialOrd for F64Offset {
+    #[inline(always)]
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for F64Offset {
+    #[inline(always)]
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        self.as_ptr().cmp(&other.as_ptr())
+    }
+}
+
+impl Hash for F64Offset {
+    #[inline(always)]
+    fn hash<H: Hasher>(&self, hasher: &mut H) {
+        self.as_ptr().hash(hasher)
+    }
+}
+
+impl fmt::Display for F64Offset {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "F64Offset({})", self.0)
+    }
+}
index 346b73f46d4b96c8b00d13b88943d5a5f452f9a6..7cce7ed3a1cdb6698131c7130491c33cfdcdc5b2 100644 (file)
@@ -3,6 +3,7 @@
 use crate::arena::*;
 use crate::atom_table::*;
 use crate::machine::machine_indices::CodeIndex;
+use crate::offset_table::*;
 use crate::parser::char_reader::*;
 use crate::types::HeapCellValueTag;
 
@@ -626,8 +627,7 @@ impl fmt::Display for Literal {
             Literal::Atom(ref atom) => {
                 write!(f, "{}", atom.flat_index())
             }
-            // Literal::Char(c) => write!(f, "'{}'", *c as u32),
-            Literal::CodeIndex(i) => write!(f, "{:x}", i.as_ptr() as u64),
+            Literal::CodeIndex(i) => write!(f, "{:?}", *i.as_ptr()),
             Literal::Fixnum(n) => write!(f, "{}", n.get_num()),
             Literal::Integer(ref n) => write!(f, "{}", n),
             Literal::Rational(ref n) => write!(f, "{}", n),
index 1a6b40e67965997eae0a00360b19f927219714f6..5cf41671b2f0570aa557db049a3700e5575f37fc 100644 (file)
@@ -5,6 +5,8 @@ use crate::parser::ast::*;
 use crate::parser::char_reader::*;
 use crate::parser::dashu::Integer;
 
+use ordered_float::OrderedFloat;
+
 use std::convert::TryFrom;
 use std::fmt;
 
index dc831c3d1ad1d941c9f8e14eba30f7b0376984a3..f1d022e2ff6f14c08edc068eda1a3e0c67e8b8fd 100644 (file)
@@ -7,6 +7,8 @@ use crate::parser::ast::*;
 use crate::parser::char_reader::*;
 use crate::parser::lexer::*;
 
+use ordered_float::OrderedFloat;
+
 use std::cell::Cell;
 use std::mem;
 use std::ops::Neg;
index d04075fa1d98af620bff02779180aedadf3b1b1f..08d3c642e244f47082fb1605011416b56adc00dc 100644 (file)
@@ -6,6 +6,7 @@ use crate::forms::*;
 use crate::machine::heap::*;
 use crate::machine::machine_indices::*;
 use crate::machine::streams::*;
+use crate::offset_table::*;
 use crate::parser::ast::Fixnum;
 use crate::parser::ast::Literal;
 
@@ -31,7 +32,7 @@ pub enum HeapCellValueTag {
     Cons = 0b0,
     F64 = 0b010101,
     Fixnum = 0b011001,
-    // Char = 0b011011,
+    CodeIndex = 0b011011,
     Atom = 0b011111,
     CutPoint = 0b011101,
     // trail elements.
@@ -58,7 +59,7 @@ pub enum HeapCellValueView {
     Cons = 0b0,
     F64 = 0b010101,
     Fixnum = 0b011001,
-    Char = 0b011011,
+    CodeIndex = 0b011011,
     Atom = 0b011111,
     CutPoint = 0b011101,
     // trail elements.
@@ -315,9 +316,7 @@ impl From<Literal> for HeapCellValue {
     fn from(literal: Literal) -> Self {
         match literal {
             Literal::Atom(name) => atom_as_cell!(name),
-            Literal::CodeIndex(ptr) => {
-                untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(ptr))
-            }
+            Literal::CodeIndex(idx) => HeapCellValue::from(idx),
             Literal::Fixnum(n) => fixnum_as_cell!(n),
             Literal::Integer(bigint_ptr) => {
                 typed_arena_ptr_as_cell!(bigint_ptr)
@@ -348,6 +347,9 @@ impl TryFrom<HeapCellValue> for Literal {
             (HeapCellValueTag::F64, f) => {
                 Ok(Literal::Float(f.as_offset()))
             }
+            (HeapCellValueTag::CodeIndex, idx) => {
+                Ok(Literal::CodeIndex(idx))
+            }
             (HeapCellValueTag::Cons, cons_ptr) => {
                 match_untyped_arena_ptr!(cons_ptr,
                      (ArenaHeaderTag::Integer, n) => {
@@ -356,9 +358,6 @@ impl TryFrom<HeapCellValue> for Literal {
                      (ArenaHeaderTag::Rational, n) => {
                          Ok(Literal::Rational(n))
                      }
-                     (ArenaHeaderTag::IndexPtr, ip) => {
-                         Ok(Literal::CodeIndex(CodeIndex::from(ip)))
-                     }
                      _ => {
                          Err(())
                      }
@@ -388,6 +387,16 @@ impl From<F64Ptr> for HeapCellValue {
     }
 }
 
+impl From<CodeIndexPtr> for HeapCellValue {
+    #[inline]
+    fn from(code_index_ptr: CodeIndexPtr) -> HeapCellValue {
+        HeapCellValue::build_with(
+            HeapCellValueTag::CodeIndex,
+            code_index_ptr.as_offset().to_u64(),
+        )
+    }
+}
+
 impl From<ConsPtr> for HeapCellValue {
     #[inline(always)]
     fn from(cons_ptr: ConsPtr) -> HeapCellValue {
@@ -738,21 +747,22 @@ impl UntypedArenaPtr {
     }
 
     #[inline]
-    pub fn get_ptr(self) -> *const ArenaHeader {
-        unsafe { mem::transmute::<_, *const ArenaHeader>(self.ptr()) }
+    pub fn get_ptr(self) -> *const u8 {
+        let addr: u64 = self.ptr();
+        addr as usize as *const u8
     }
 
     #[inline]
     pub fn get_tag(self) -> ArenaHeaderTag {
         unsafe {
-            let header = *self.get_ptr();
+            let header = *(self.get_ptr() as *const ArenaHeader);
             header.get_tag()
         }
     }
 
     #[inline]
     pub fn payload_offset(self) -> *const u8 {
-        unsafe { self.get_ptr().byte_add(mem::size_of::<ArenaHeader>()) as *const _ }
+        unsafe { self.get_ptr().add(mem::size_of::<ArenaHeader>()) }
     }
 
     /// # Safety