move CodeIndex to F64Table-like table

This commit is contained in:
Mark Thom
2025-04-06 12:11:57 -07:00
committed by Mark Thom
parent 9e1e99f961
commit 22080f3787
21 changed files with 584 additions and 501 deletions

View File

@@ -136,6 +136,7 @@ opt-level = 3
[profile.release] [profile.release]
lto = true lto = true
opt-level = 3 opt-level = 3
debug = 2
[profile.wasm-dev] [profile.wasm-dev]
inherits = "dev" inherits = "dev"

View File

@@ -3,20 +3,14 @@
#[cfg(feature = "http")] #[cfg(feature = "http")]
use crate::http::{HttpListener, HttpResponse}; use crate::http::{HttpListener, HttpResponse};
use crate::machine::loader::LiveLoadState; use crate::machine::loader::LiveLoadState;
use crate::machine::machine_indices::*;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::raw_block::*; use crate::offset_table::*;
use crate::read::*; use crate::read::*;
use crate::types::UntypedArenaPtr; use crate::types::UntypedArenaPtr;
use crate::parser::dashu::{Integer, Rational}; 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 ordered_float::OrderedFloat;
use std::cell::UnsafeCell;
use std::fmt; use std::fmt;
use std::fmt::Debug; use std::fmt::Debug;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
@@ -27,7 +21,7 @@ use std::ops::{Deref, DerefMut};
use std::ptr; use std::ptr;
use std::ptr::addr_of_mut; use std::ptr::addr_of_mut;
use std::ptr::NonNull; use std::ptr::NonNull;
use std::sync::RwLock; use std::sync::Arc;
macro_rules! arena_alloc { macro_rules! arena_alloc {
($e:expr, $arena:expr) => {{ ($e:expr, $arena:expr) => {{
@@ -39,7 +33,7 @@ macro_rules! arena_alloc {
macro_rules! float_alloc { macro_rules! float_alloc {
($e:expr, $arena:expr) => {{ ($e:expr, $arena:expr) => {{
let result = $e; let result = $e;
unsafe { $arena.f64_tbl.build_with(result).as_ptr() } unsafe { $arena.f64_tbl.build_with(OrderedFloat(result)).as_ptr() }
}}; }};
} }
@@ -55,120 +49,6 @@ where
payload_offset - header_offset 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<()>,
}
// TODO: Actually prove this, as it's probably unsound right now
unsafe impl Send for F64Table {}
unsafe impl Sync for F64Table {}
#[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)] #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)]
#[bits = 7] #[bits = 7]
pub enum ArenaHeaderTag { pub enum ArenaHeaderTag {
@@ -194,10 +74,6 @@ pub enum ArenaHeaderTag {
HttpListener = 0b1000001, HttpListener = 0b1000001,
HttpResponse = 0b1000010, HttpResponse = 0b1000010,
Dropped = 0b1000100, Dropped = 0b1000100,
IndexPtrDynamicUndefined = 0b1000101,
IndexPtrDynamicIndex = 0b1000110,
IndexPtrIndex = 0b1000111,
IndexPtrUndefined = 0b1001000,
} }
#[bitfield] #[bitfield]
@@ -436,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 { impl ArenaAllocated for Integer {
type Payload = Self; type Payload = Self;
#[inline] #[inline]
@@ -644,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)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]
pub struct AllocSlab { pub struct AllocSlab {
@@ -691,13 +396,6 @@ pub struct AllocSlab {
header: ArenaHeader, header: ArenaHeader,
} }
#[repr(C)]
#[derive(Debug)]
pub struct IndexPtrSlab {
next: Option<UntypedArenaSlab>,
index_ptr: IndexPtr,
}
const _: () = { const _: () = {
if std::mem::align_of::<AllocSlab>() < std::mem::align_of::<*const ()>() { if std::mem::align_of::<AllocSlab>() < std::mem::align_of::<*const ()>() {
panic!("alignment of AllocSlab is too low"); panic!("alignment of AllocSlab is too low");
@@ -706,34 +404,8 @@ const _: () = {
if std::mem::offset_of!(AllocSlab, header) % std::mem::align_of::<*const ()>() != 0 { if std::mem::offset_of!(AllocSlab, header) % std::mem::align_of::<*const ()>() != 0 {
panic!("alignment of header not a multiple of pointers alignment"); 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)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]
pub struct TypedAllocSlab<T: ?Sized + ArenaAllocated> { pub struct TypedAllocSlab<T: ?Sized + ArenaAllocated> {
@@ -787,6 +459,7 @@ impl Drop for UntypedArenaSlab {
pub struct Arena { pub struct Arena {
base: Option<UntypedArenaSlab>, base: Option<UntypedArenaSlab>,
pub f64_tbl: Arc<F64Table>, pub f64_tbl: Arc<F64Table>,
pub code_index_tbl: Arc<CodeIndexTable>,
} }
unsafe impl Send for Arena {} unsafe impl Send for Arena {}
@@ -799,6 +472,7 @@ impl Arena {
Arena { Arena {
base: None, base: None,
f64_tbl: F64Table::new(), f64_tbl: F64Table::new(),
code_index_tbl: CodeIndexTable::new(),
} }
} }
} }
@@ -874,12 +548,6 @@ unsafe fn drop_slab_in_place(value: NonNull<AllocSlab>, tag: ArenaHeaderTag) {
ArenaHeaderTag::StandardErrorStream => { ArenaHeaderTag::StandardErrorStream => {
drop_typed_slab_in_place!(StandardErrorStream, value); drop_typed_slab_in_place!(StandardErrorStream, value);
} }
ArenaHeaderTag::IndexPtrUndefined
| ArenaHeaderTag::IndexPtrDynamicUndefined
| ArenaHeaderTag::IndexPtrDynamicIndex
| ArenaHeaderTag::IndexPtrIndex => {
drop_typed_slab_in_place!(IndexPtr, value);
}
ArenaHeaderTag::NullStream => { ArenaHeaderTag::NullStream => {
unreachable!("NullStream is never arena allocated!"); unreachable!("NullStream is never arena allocated!");
} }

View File

@@ -7,6 +7,7 @@ use crate::debray_allocator::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::iterators::*; use crate::iterators::*;
use crate::offset_table::*;
use crate::targets::QueryInstruction; use crate::targets::QueryInstruction;
use crate::types::*; use crate::types::*;

View File

@@ -12,6 +12,7 @@ use crate::machine::machine_indices::*;
use crate::machine::partial_string::*; use crate::machine::partial_string::*;
use crate::machine::stack::*; use crate::machine::stack::*;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::offset_table::*;
use crate::types::*; use crate::types::*;
use dashu::base::Signed; 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")) { if self.format_struct(max_depth, 1, atom!("$index_ptr")) {
let atom = self.state_stack.pop().unwrap(); let atom = self.state_stack.pop().unwrap();
self.state_stack.pop(); self.state_stack.pop();
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")) TokenOrRedirect::Atom(atom!("undefined"))
} else { } else {
let idx = index_ptr.p() as i64; let idx_ptr_p = idx_ptr.p() as i64;
TokenOrRedirect::NumberFocus( TokenOrRedirect::NumberFocus(
max_depth, max_depth,
NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(idx))), NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(idx_ptr_p))),
None, 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) => { (HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint, n) => {
self.print_number(max_depth, NumberFocus::Unfocused(Number::Fixnum(n)), &op); 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) => { (ArenaHeaderTag::Dropped, _value) => {
self.print_impromptu_atom(atom!("$dropped_value")); self.print_impromptu_atom(atom!("$dropped_value"));
} }
(ArenaHeaderTag::IndexPtr, index_ptr) => {
self.print_index_ptr(*index_ptr, max_depth);
}
_ => { _ => {
} }
); );

View File

@@ -11,6 +11,7 @@ pub(crate) mod macros;
pub(crate) mod atom_table; pub(crate) mod atom_table;
#[macro_use] #[macro_use]
pub(crate) mod arena; pub(crate) mod arena;
pub(crate) mod offset_table;
#[macro_use] #[macro_use]
pub(crate) mod parser; pub(crate) mod parser;
#[macro_use] #[macro_use]

View File

@@ -11,6 +11,7 @@ use crate::forms::*;
use crate::heap_iter::*; use crate::heap_iter::*;
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
use crate::machine::machine_state::*; use crate::machine::machine_state::*;
use crate::offset_table::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::parser::dashu::{Integer, Rational}; use crate::parser::dashu::{Integer, Rational};
use crate::types::*; use crate::types::*;

View File

@@ -610,7 +610,7 @@ impl Machine {
.indices .indices
.code_dir .code_dir
.get_index(predicate_idx) .get_index(predicate_idx)
.map(|x| x.1.p() as usize) .map(|x| x.1.as_ptr().p() as usize)
.unwrap(); .unwrap();
debug_assert!(current_pred_start <= p); debug_assert!(current_pred_start <= p);
@@ -619,7 +619,7 @@ impl Machine {
.indices .indices
.code_dir .code_dir
.get_index(predicate_idx + 1) .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()); .unwrap_or(self.code.len());
debug_assert!(current_pred_end >= p); debug_assert!(current_pred_end >= p);

View File

@@ -7,9 +7,9 @@ use crate::heap_iter::{stackful_post_order_iter, NonListElider};
use crate::machine::machine_indices::VarKey; use crate::machine::machine_indices::VarKey;
use crate::machine::mock_wam::CompositeOpDir; use crate::machine::mock_wam::CompositeOpDir;
use crate::machine::{ use crate::machine::{
ArenaHeaderTag, F64Offset, F64Ptr, Fixnum, Number, BREAK_FROM_DISPATCH_LOOP_LOC, ArenaHeaderTag, Fixnum, Number, BREAK_FROM_DISPATCH_LOOP_LOC, LIB_QUERY_SUCCESS,
LIB_QUERY_SUCCESS,
}; };
use crate::offset_table::*;
use crate::parser::ast::{Var, VarPtr}; use crate::parser::ast::{Var, VarPtr};
use crate::parser::parser::{Parser, Tokens}; use crate::parser::parser::{Parser, Tokens};
use crate::read::{write_term_to_heap, TermWriteResult}; use crate::read::{write_term_to_heap, TermWriteResult};

View File

@@ -147,7 +147,7 @@ pub(super) fn import_module_exports<'a, LS: LoadState<'a>>(
src_code_index.get(), 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); code_dir.insert(key, src_code_index);
} }
} else { } else {
@@ -486,7 +486,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
continue; 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()); let old_index_ptr = code_index.replace(IndexPtr::undefined());
self.payload.retraction_info.push_record( self.payload.retraction_info.push_record(

View 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); 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( set_code_index(
&mut self.payload.retraction_info, &mut self.payload.retraction_info,
&compilation_target, &compilation_target,
@@ -1378,73 +1378,72 @@ impl MachineState {
while let Some(addr) = iter.next() { while let Some(addr) = iter.next() {
let addr = unmark_cell_bits!(addr); let addr = unmark_cell_bits!(addr);
if let Ok(literal) = Literal::try_from(addr) { read_heap_cell!(addr,
term_stack.push(Term::Literal(Cell::default(), literal)); (HeapCellValueTag::Lis) => {
} else { 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 tail = term_stack.pop().unwrap();
let head = term_stack.pop().unwrap(); let head = term_stack.pop().unwrap();
match as_partial_string(head, tail) { match as_partial_string(head, tail) {
Ok((string, Some(tail))) => { Ok((string, Some(tail))) => {
term_stack.push(Term::PartialString(Cell::default(), Rc::new(string), 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),
} }
} Ok((string, None)) => {
(HeapCellValueTag::StackVar, h) => { term_stack.push(Term::CompleteString(Cell::default(), Rc::new(string)));
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;
}
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));
} }
Err(cons_term) => term_stack.push(cons_term),
} }
(HeapCellValueTag::PStrLoc, h) => { }
let HeapStringScan { string, .. } = iter.heap.scan_slice_to_str(h); (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | HeapCellValueTag::F64) => {
let tail = term_stack.pop().unwrap(); 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)];
term_stack.push(if matches!(tail, Term::Literal(_, Literal::Atom(atom!("[]")))) { if let Some(idx) = get_structure_index(value) {
Term::CompleteString( term_stack.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx)));
Cell::default(), arity += 1;
Rc::new(string.to_owned()),
)
} else {
Term::PartialString(
Cell::default(),
Rc::new(string.to_owned()),
Box::new(tail),
)
});
} }
_ => {
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),
)
});
}
_ => {
}
);
} }
debug_assert!(term_stack.len() == 1); debug_assert!(term_stack.len() == 1);

View File

@@ -10,6 +10,7 @@ use crate::machine::machine_state::*;
use crate::machine::streams::{Stream, StreamOptions}; use crate::machine::streams::{Stream, StreamOptions};
use crate::machine::ClauseType; use crate::machine::ClauseType;
use crate::machine::MachineStubGen; use crate::machine::MachineStubGen;
use crate::offset_table::*;
use fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
use indexmap::{IndexMap, IndexSet}; use indexmap::{IndexMap, IndexSet};
@@ -18,7 +19,7 @@ use scryer_modular_bitfield::{bitfield, BitfieldSpecifier};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::ops::{Deref, DerefMut}; use std::ops::Deref;
use crate::types::*; use crate::types::*;
@@ -129,7 +130,7 @@ impl IndexPtr {
} }
#[derive(Debug, Clone, Copy, Ord, Hash, PartialOrd, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Ord, Hash, PartialOrd, Eq, PartialEq)]
pub struct CodeIndex(TypedArenaPtr<IndexPtr>); pub struct CodeIndex(CodeIndexOffset);
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
const_assert!(std::mem::align_of::<CodeIndex>() == 4); 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")] #[cfg(target_pointer_width = "64")]
const_assert!(std::mem::align_of::<CodeIndex>() == 8); 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 {
#[inline(always)]
fn from(ptr: TypedArenaPtr<IndexPtr>) -> CodeIndex {
CodeIndex(ptr)
}
}
impl From<CodeIndex> for HeapCellValue { impl From<CodeIndex> for HeapCellValue {
#[inline(always)] #[inline(always)]
fn from(idx: CodeIndex) -> HeapCellValue { fn from(idx: CodeIndex) -> HeapCellValue {
untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx)) HeapCellValue::from(idx.as_ptr())
}
}
impl From<CodeIndexOffset> for CodeIndex {
#[inline(always)]
fn from(offset: CodeIndexOffset) -> CodeIndex {
CodeIndex(offset)
} }
} }
impl CodeIndex { impl CodeIndex {
#[inline] #[inline]
pub(crate) fn new(ptr: IndexPtr, arena: &mut Arena) -> Self { 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)] #[inline(always)]
@@ -186,39 +164,37 @@ impl CodeIndex {
} }
pub(crate) fn local(&self) -> Option<usize> { pub(crate) fn local(&self) -> Option<usize> {
match self.0.tag() { match self.0.as_ptr().tag() {
IndexPtrTag::Index => Some(self.0.p() as usize), IndexPtrTag::Index => Some(self.get().p() as usize),
IndexPtrTag::DynamicIndex => Some(self.0.p() as usize), IndexPtrTag::DynamicIndex => Some(self.get().p() as usize),
_ => None, _ => None,
} }
} }
#[inline(always)] #[inline(always)]
pub(crate) fn get(&self) -> IndexPtr { pub(crate) fn get(&self) -> IndexPtr {
*self.0.deref() *self.as_ptr().deref()
} }
#[inline(always)] #[inline(always)]
pub(crate) fn set(&mut self, value: IndexPtr) { pub(crate) fn set(&mut self, value: IndexPtr) {
*self.0.deref_mut() = value; self.as_ptr().set(value);
} }
#[inline(always)] #[inline(always)]
pub(crate) fn get_tag(self) -> IndexPtrTag { pub(crate) fn get_tag(self) -> IndexPtrTag {
self.0.tag() self.get().tag()
} }
#[inline(always)] #[inline(always)]
pub(crate) fn replace(&mut self, value: IndexPtr) -> IndexPtr { pub(crate) fn replace(&mut self, value: IndexPtr) -> IndexPtr {
std::mem::replace(self.0.deref_mut(), value) self.as_ptr().replace(value)
} }
/*
#[inline(always)] #[inline(always)]
pub(crate) fn as_ptr(&self) -> *const IndexPtr { pub(crate) fn as_ptr(&self) -> CodeIndexPtr {
self.0.as_ptr() self.0.as_ptr()
} }
*/
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]

View File

@@ -11,6 +11,7 @@ use crate::machine::machine_state::*;
use crate::machine::partial_string::*; use crate::machine::partial_string::*;
use crate::machine::stack::*; use crate::machine::stack::*;
use crate::machine::unify::*; use crate::machine::unify::*;
use crate::offset_table::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::parser::dashu::{Integer, Rational}; use crate::parser::dashu::{Integer, Rational};
use crate::types::*; use crate::types::*;

View File

@@ -45,6 +45,7 @@ use crate::machine::machine_indices::*;
use crate::machine::machine_state::*; use crate::machine::machine_state::*;
use crate::machine::stack::*; use crate::machine::stack::*;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::offset_table::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::parser::dashu::{Integer, Rational}; use crate::parser::dashu::{Integer, Rational};
use crate::types::*; use crate::types::*;
@@ -207,13 +208,8 @@ pub(crate) fn import_builtin_impls(code_dir: &CodeDir, builtins: &mut Module) {
#[inline] #[inline]
pub(crate) fn get_structure_index(value: HeapCellValue) -> Option<CodeIndex> { pub(crate) fn get_structure_index(value: HeapCellValue) -> Option<CodeIndex> {
read_heap_cell!(value, read_heap_cell!(value,
(HeapCellValueTag::Cons, cons_ptr) => { (HeapCellValueTag::CodeIndex, ip) => {
match_untyped_arena_ptr!(cons_ptr, return Some(ip);
(ArenaHeaderTag::IndexPtr, ip) => {
return Some(CodeIndex::from(ip));
}
_ => {}
);
} }
_ => { _ => {
} }

View File

@@ -1454,7 +1454,7 @@ impl Machine {
}; };
if let Some(code_index) = index_cell { 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); load_registers(&mut self.machine_st, goal, goal_arity);
self.machine_st.neck_cut(); self.machine_st.neck_cut();
return call_at_index(self, name, arity, code_index.get()); return call_at_index(self, name, arity, code_index.get());
@@ -1603,8 +1603,7 @@ impl Machine {
let expanded_term = if result.is_simple_goal { let expanded_term = if result.is_simple_goal {
let idx = self.get_or_insert_qualified_code_index(module_name, result.key); let idx = self.get_or_insert_qualified_code_index(module_name, result.key);
self.machine_st.heap[result.index_ptr_loc] = self.machine_st.heap[result.index_ptr_loc] = HeapCellValue::from(idx);
untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx));
result.goal result.goal
} else { } else {
let mut unexpanded_vars = IndexSet::with_hasher(FxBuildHasher::default()); let mut unexpanded_vars = IndexSet::with_hasher(FxBuildHasher::default());
@@ -1642,7 +1641,7 @@ impl Machine {
); );
writer.write_with(|section| { 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)); section.push_cell(atom_as_cell!(atom!("$aux"), 0));
for value in unexpanded_vars.difference(&result.supp_vars).cloned() { for value in unexpanded_vars.difference(&result.supp_vars).cloned() {
@@ -1679,14 +1678,8 @@ impl Machine {
let idx_cell = self.machine_st.heap[s.saturating_sub(1)]; let idx_cell = self.machine_st.heap[s.saturating_sub(1)];
if HeapCellValueTag::Cons == idx_cell.get_tag() { if HeapCellValueTag::CodeIndex == idx_cell.get_tag() {
match_untyped_arena_ptr!(cell_as_untyped_arena_ptr!(idx_cell), return true;
(ArenaHeaderTag::IndexPtr, _ip) => {
return true;
}
_ => {
}
);
} }
} }

View File

@@ -3,6 +3,7 @@ use crate::forms::*;
use crate::heap_iter::{stackful_preorder_iter, NonListElider}; use crate::heap_iter::{stackful_preorder_iter, NonListElider};
use crate::machine::machine_state::*; use crate::machine::machine_state::*;
use crate::machine::*; use crate::machine::*;
use crate::offset_table::*;
use crate::types::*; use crate::types::*;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};

View File

@@ -62,7 +62,14 @@ macro_rules! cell_as_atom_cell {
macro_rules! cell_as_f64_ptr { macro_rules! cell_as_f64_ptr {
($cell:expr) => {{ ($cell:expr) => {{
let offset = $cell.get_value() as usize; 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) => {{ ($ptr:expr) => {{
// Cell is 64-bit, but raw ptr is 32-bit in 32-bit systems // 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 // 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; let ptr : *const _ = $ptr;
debug_assert!(!$ptr.is_null()); debug_assert!(!$ptr.is_null());
HeapCellValue::from_ptr_addr(ptr as usize) HeapCellValue::from_ptr_addr(ptr as usize)
@@ -217,12 +224,6 @@ macro_rules! match_untyped_arena_ptr_pat_body {
#[allow(unused_braces)] #[allow(unused_braces)]
$code $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) => {{ ($ptr:ident, $($tags:tt)|+, $s:ident, $code:expr) => {{
let $s = Stream::from_tag($ptr.get_tag(), $ptr); let $s = Stream::from_tag($ptr.get_tag(), $ptr);
#[allow(unused_braces)] #[allow(unused_braces)]
@@ -246,12 +247,6 @@ macro_rules! match_untyped_arena_ptr_pat {
| ArenaHeaderTag::StandardOutputStream | ArenaHeaderTag::StandardOutputStream
| ArenaHeaderTag::StandardErrorStream | ArenaHeaderTag::StandardErrorStream
}; };
(IndexPtr) => {
ArenaHeaderTag::IndexPtrUndefined
| ArenaHeaderTag::IndexPtrDynamicUndefined
| ArenaHeaderTag::IndexPtrDynamicIndex
| ArenaHeaderTag::IndexPtrIndex
};
($tag:ident) => { ($tag:ident) => {
ArenaHeaderTag::$tag ArenaHeaderTag::$tag
}; };
@@ -282,6 +277,11 @@ macro_rules! read_heap_cell_pat_body {
#[allow(unused_braces)] #[allow(unused_braces)]
$code $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) => {{ ($cell:ident, Atom, ($name:ident, $arity:ident), $code:expr) => {{
let ($name, $arity) = cell_as_atom_cell!($cell).get_name_and_arity(); let ($name, $arity) = cell_as_atom_cell!($cell).get_name_and_arity();
#[allow(unused_braces)] #[allow(unused_braces)]

428
src/offset_table.rs Normal file
View File

@@ -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)
}
}

View File

@@ -3,6 +3,7 @@
use crate::arena::*; use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::machine::machine_indices::CodeIndex; use crate::machine::machine_indices::CodeIndex;
use crate::offset_table::*;
use crate::parser::char_reader::*; use crate::parser::char_reader::*;
use crate::types::HeapCellValueTag; use crate::types::HeapCellValueTag;
@@ -631,8 +632,7 @@ impl fmt::Display for Literal {
Literal::Atom(ref atom) => { Literal::Atom(ref atom) => {
write!(f, "{}", atom.flat_index()) write!(f, "{}", atom.flat_index())
} }
// Literal::Char(c) => write!(f, "'{}'", *c as u32), Literal::CodeIndex(i) => write!(f, "{:?}", *i.as_ptr()),
Literal::CodeIndex(i) => write!(f, "{:x}", i.as_ptr() as u64),
Literal::Fixnum(n) => write!(f, "{}", n.get_num()), Literal::Fixnum(n) => write!(f, "{}", n.get_num()),
Literal::Integer(ref n) => write!(f, "{}", n), Literal::Integer(ref n) => write!(f, "{}", n),
Literal::Rational(ref n) => write!(f, "{}", n), Literal::Rational(ref n) => write!(f, "{}", n),

View File

@@ -8,6 +8,8 @@ use crate::parser::ast::*;
use crate::parser::char_reader::*; use crate::parser::char_reader::*;
use crate::parser::dashu::Integer; use crate::parser::dashu::Integer;
use ordered_float::OrderedFloat;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt; use std::fmt;

View File

@@ -7,6 +7,8 @@ use crate::parser::ast::*;
use crate::parser::char_reader::*; use crate::parser::char_reader::*;
use crate::parser::lexer::*; use crate::parser::lexer::*;
use ordered_float::OrderedFloat;
use std::cell::Cell; use std::cell::Cell;
use std::mem; use std::mem;
use std::ops::Neg; use std::ops::Neg;

View File

@@ -6,6 +6,7 @@ use crate::forms::*;
use crate::machine::heap::*; use crate::machine::heap::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::offset_table::*;
use crate::parser::ast::Fixnum; use crate::parser::ast::Fixnum;
use crate::parser::ast::Literal; use crate::parser::ast::Literal;
@@ -31,7 +32,7 @@ pub enum HeapCellValueTag {
Cons = 0b0, Cons = 0b0,
F64 = 0b010101, F64 = 0b010101,
Fixnum = 0b011001, Fixnum = 0b011001,
// Char = 0b011011, CodeIndex = 0b011011,
Atom = 0b011111, Atom = 0b011111,
CutPoint = 0b011101, CutPoint = 0b011101,
// trail elements. // trail elements.
@@ -58,7 +59,7 @@ pub enum HeapCellValueView {
Cons = 0b0, Cons = 0b0,
F64 = 0b010101, F64 = 0b010101,
Fixnum = 0b011001, Fixnum = 0b011001,
Char = 0b011011, CodeIndex = 0b011011,
Atom = 0b011111, Atom = 0b011111,
CutPoint = 0b011101, CutPoint = 0b011101,
// trail elements. // trail elements.
@@ -315,9 +316,7 @@ impl From<Literal> for HeapCellValue {
fn from(literal: Literal) -> Self { fn from(literal: Literal) -> Self {
match literal { match literal {
Literal::Atom(name) => atom_as_cell!(name), Literal::Atom(name) => atom_as_cell!(name),
Literal::CodeIndex(ptr) => { Literal::CodeIndex(idx) => HeapCellValue::from(idx),
untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(ptr))
}
Literal::Fixnum(n) => fixnum_as_cell!(n), Literal::Fixnum(n) => fixnum_as_cell!(n),
Literal::Integer(bigint_ptr) => { Literal::Integer(bigint_ptr) => {
typed_arena_ptr_as_cell!(bigint_ptr) typed_arena_ptr_as_cell!(bigint_ptr)
@@ -348,6 +347,9 @@ impl TryFrom<HeapCellValue> for Literal {
(HeapCellValueTag::F64, f) => { (HeapCellValueTag::F64, f) => {
Ok(Literal::Float(f.as_offset())) Ok(Literal::Float(f.as_offset()))
} }
(HeapCellValueTag::CodeIndex, idx) => {
Ok(Literal::CodeIndex(idx))
}
(HeapCellValueTag::Cons, cons_ptr) => { (HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr, match_untyped_arena_ptr!(cons_ptr,
(ArenaHeaderTag::Integer, n) => { (ArenaHeaderTag::Integer, n) => {
@@ -356,9 +358,6 @@ impl TryFrom<HeapCellValue> for Literal {
(ArenaHeaderTag::Rational, n) => { (ArenaHeaderTag::Rational, n) => {
Ok(Literal::Rational(n)) Ok(Literal::Rational(n))
} }
(ArenaHeaderTag::IndexPtr, ip) => {
Ok(Literal::CodeIndex(CodeIndex::from(ip)))
}
_ => { _ => {
Err(()) 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 { impl From<ConsPtr> for HeapCellValue {
#[inline(always)] #[inline(always)]
fn from(cons_ptr: ConsPtr) -> HeapCellValue { fn from(cons_ptr: ConsPtr) -> HeapCellValue {
@@ -739,22 +748,23 @@ impl UntypedArenaPtr {
} }
#[inline] #[inline]
pub fn get_ptr(self) -> *const ArenaHeader { pub fn get_ptr(self) -> *const u8 {
unsafe { mem::transmute::<_, *const ArenaHeader>(self.ptr()) } let addr: u64 = self.ptr();
addr as usize as *const u8
} }
#[inline] #[inline]
pub fn get_tag(self) -> ArenaHeaderTag { pub fn get_tag(self) -> ArenaHeaderTag {
unsafe { unsafe {
debug_assert!(!self.get_ptr().is_null()); debug_assert!(!self.get_ptr().is_null());
let header = *self.get_ptr(); let header = *(self.get_ptr() as *const ArenaHeader);
header.get_tag() header.get_tag()
} }
} }
#[inline] #[inline]
pub fn payload_offset(self) -> *const u8 { 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 /// # Safety