[WIP] move towards lockless AtomTable
This commit is contained in:
@@ -70,12 +70,6 @@ pub struct F64Table {
|
||||
block: RawBlock<F64Table>,
|
||||
}
|
||||
|
||||
impl Drop for F64Table {
|
||||
fn drop(&mut self) {
|
||||
self.block.deallocate();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn set_f64_tbl_buf_base(ptr: *const u8) {
|
||||
F64_TABLE_BUF_BASE.with(|f64_table_buf_base| {
|
||||
|
||||
@@ -7,16 +7,16 @@ use std::hash::{Hash, Hasher};
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::ptr;
|
||||
use std::ptr::NonNull;
|
||||
use std::slice;
|
||||
use std::str;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::Weak;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
|
||||
use modular_bitfield::prelude::*;
|
||||
use tokio::runtime::Handle;
|
||||
use tokio::sync::OwnedRwLockReadGuard;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
@@ -46,45 +46,35 @@ impl From<bool> for Atom {
|
||||
}
|
||||
}
|
||||
|
||||
impl indexmap::Equivalent<Atom> for LookupKey<'_, '_> {
|
||||
impl indexmap::Equivalent<Atom> for str {
|
||||
fn equivalent(&self, key: &Atom) -> bool {
|
||||
&*key.as_str_with_table(self.0) == self.1
|
||||
&*key.as_str() == self
|
||||
}
|
||||
}
|
||||
|
||||
const ATOM_TABLE_INIT_SIZE: usize = 1 << 16;
|
||||
const ATOM_TABLE_ALIGN: usize = 8;
|
||||
|
||||
fn global_atom_table() -> &'static RwLock<Weak<RwLock<AtomTable>>> {
|
||||
#[inline(always)]
|
||||
fn global_atom_table() -> &'static RwLock<Weak<AtomTable>> {
|
||||
#[cfg(feature = "rust_beta_channel")]
|
||||
{
|
||||
// const Weak::new will be stabilized in 1.73 which is currently in beta,
|
||||
// till then we need a OnceLock for initialization
|
||||
static GLOBAL_ATOM_TABLE: RwLock<Weak<RwLock<AtomTable>>> = RwLock::const_new(Weak::new());
|
||||
static GLOBAL_ATOM_TABLE: RwLock<Weak<AtomTable>> = RwLock::const_new(Weak::new());
|
||||
&GLOBAL_ATOM_TABLE
|
||||
}
|
||||
#[cfg(not(feature = "rust_beta_channel"))]
|
||||
{
|
||||
use std::sync::OnceLock;
|
||||
static GLOBAL_ATOM_TABLE: OnceLock<RwLock<Weak<RwLock<AtomTable>>>> = OnceLock::new();
|
||||
static GLOBAL_ATOM_TABLE: OnceLock<RwLock<Weak<AtomTable>>> = OnceLock::new();
|
||||
GLOBAL_ATOM_TABLE.get_or_init(|| RwLock::new(Weak::new()))
|
||||
}
|
||||
}
|
||||
|
||||
fn owned_atom_table_read_guard() -> Option<OwnedRwLockReadGuard<AtomTable>> {
|
||||
let atom_table = global_atom_table().blocking_read().upgrade()?;
|
||||
|
||||
let guard = {
|
||||
// some test don't start a Runtime
|
||||
if let Ok(handle) = Handle::try_current() {
|
||||
handle.block_on(atom_table.read_owned())
|
||||
} else {
|
||||
tokio::runtime::Runtime::new()
|
||||
.unwrap()
|
||||
.block_on(atom_table.read_owned())
|
||||
}
|
||||
};
|
||||
Some(guard)
|
||||
#[inline(always)]
|
||||
fn arc_atom_table() -> Option<Arc<AtomTable>> {
|
||||
global_atom_table().blocking_read().upgrade()
|
||||
}
|
||||
|
||||
impl RawBlockTraits for AtomTable {
|
||||
@@ -132,7 +122,7 @@ macro_rules! is_char {
|
||||
|
||||
pub enum AtomString<'a> {
|
||||
Static(&'a str),
|
||||
Dynamic(OwnedRwLockReadGuard<AtomTable, str>),
|
||||
Dynamic(AtomTableRef<str>),
|
||||
}
|
||||
|
||||
impl AtomString<'_> {
|
||||
@@ -142,7 +132,7 @@ impl AtomString<'_> {
|
||||
{
|
||||
match self {
|
||||
Self::Static(reference) => Self::Static(f(reference)),
|
||||
Self::Dynamic(guard) => Self::Dynamic(OwnedRwLockReadGuard::map(guard, f)),
|
||||
Self::Dynamic(guard) => Self::Dynamic(AtomTableRef::map(guard, f)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,51 +170,28 @@ impl rustyline::completion::Candidate for AtomString<'_> {
|
||||
}
|
||||
|
||||
impl Atom {
|
||||
#[inline]
|
||||
pub fn buf(self) -> Option<OwnedRwLockReadGuard<AtomTable, u8>> {
|
||||
if let Some(guard) = self.as_ptr() {
|
||||
Some(OwnedRwLockReadGuard::map(guard, |ptr| unsafe {
|
||||
(ptr as *const u8)
|
||||
.offset(mem::size_of::<AtomHeader>() as isize)
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_static(self) -> bool {
|
||||
(self.index as usize) < STRINGS.len() << 3
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn as_ptr_with_table<'at>(&self, atom_table: &'at AtomTable) -> Option<&'at u8> {
|
||||
pub fn as_ptr(self) -> Option<AtomTableRef<u8>> {
|
||||
if self.is_static() {
|
||||
None
|
||||
} else {
|
||||
let atom_table =
|
||||
arc_atom_table().expect("We should only have an Atom while there is an AtomTable");
|
||||
unsafe {
|
||||
atom_table
|
||||
.buf()
|
||||
.offset(((self.index as usize) - (STRINGS.len() << 3)) as isize)
|
||||
.as_ref()
|
||||
AtomTableRef::try_map(atom_table.buf(), |buf| {
|
||||
(buf as *const u8)
|
||||
.offset(((self.index as usize) - (STRINGS.len() << 3)) as isize)
|
||||
.as_ref()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn as_ptr(self) -> Option<OwnedRwLockReadGuard<AtomTable, u8>> {
|
||||
if self.is_static() {
|
||||
None
|
||||
} else {
|
||||
let guard = owned_atom_table_read_guard()
|
||||
.expect("We should only have an Atom while there is an AtomTable");
|
||||
OwnedRwLockReadGuard::try_map(guard, |atom_table| self.as_ptr_with_table(atom_table))
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from(index: u64) -> Self {
|
||||
Self { index }
|
||||
@@ -260,35 +227,29 @@ impl Atom {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn as_str_with_table<'at>(&self, atom_table: &'at AtomTable) -> &'at str {
|
||||
if let Some(ptr) = self.as_ptr_with_table(atom_table) {
|
||||
let header = unsafe { ptr::read::<AtomHeader>(ptr as *const u8 as *const AtomHeader) };
|
||||
let len = header.len() as usize;
|
||||
let buf = (unsafe { (ptr as *const u8).offset(mem::size_of::<AtomHeader>() as isize) })
|
||||
as *mut u8;
|
||||
|
||||
unsafe { str::from_utf8_unchecked(slice::from_raw_parts(buf, len)) }
|
||||
} else {
|
||||
&STRINGS[(self.index >> 3) as usize]
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
#[inline]
|
||||
pub fn as_str(&self) -> AtomString<'static> {
|
||||
if self.is_static() {
|
||||
AtomString::Static(STRINGS[(self.index >> 3) as usize])
|
||||
} else {
|
||||
let guard = owned_atom_table_read_guard()
|
||||
.expect("We should only have an Atom while there is an AtomTable");
|
||||
AtomString::Dynamic(OwnedRwLockReadGuard::map(guard, |atom_table| {
|
||||
self.as_str_with_table(atom_table)
|
||||
}))
|
||||
if let Some(ptr) = self.as_ptr() {
|
||||
AtomString::Dynamic(AtomTableRef::map(ptr, |ptr| {
|
||||
let header =
|
||||
unsafe { ptr::read::<AtomHeader>(ptr as *const u8 as *const AtomHeader) };
|
||||
let len = header.len() as usize;
|
||||
let buf = (unsafe {
|
||||
(ptr as *const u8).offset(mem::size_of::<AtomHeader>() as isize)
|
||||
}) as *mut u8;
|
||||
|
||||
unsafe { str::from_utf8_unchecked(slice::from_raw_parts(buf, len)) }
|
||||
}))
|
||||
} else {
|
||||
AtomString::Static(&STRINGS[(self.index >> 3) as usize])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn defrock_brackets(&self, atom_tbl: &Arc<RwLock<AtomTable>>) -> Self {
|
||||
pub fn defrock_brackets(&self, atom_tbl: &AtomTable) -> Self {
|
||||
let s = self.as_str();
|
||||
|
||||
let sub_str = if s.starts_with('(') && s.ends_with(')') {
|
||||
@@ -297,9 +258,7 @@ impl Atom {
|
||||
return *self;
|
||||
};
|
||||
|
||||
let val = sub_str.to_string();
|
||||
drop(s); // wee need to drop s as it holds a read lock on the AtomTable and build_with may need to acquire a write lock
|
||||
AtomTable::build_with(&atom_tbl, &val)
|
||||
AtomTable::build_with(&atom_tbl, &sub_str)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,29 +282,80 @@ impl Ord for Atom {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AtomTableRef<M>
|
||||
where
|
||||
M: ?Sized,
|
||||
{
|
||||
arc: Arc<InnerAtomTable>,
|
||||
data: NonNull<M>,
|
||||
}
|
||||
|
||||
impl<M> Clone for AtomTableRef<M> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
arc: Arc::clone(&self.arc),
|
||||
data: self.data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: ?Sized> AtomTableRef<M> {
|
||||
pub fn map<N: ?Sized, F: for<'a> FnOnce(&'a M) -> &'a N>(
|
||||
referece: Self,
|
||||
f: F,
|
||||
) -> AtomTableRef<N> {
|
||||
AtomTableRef {
|
||||
arc: referece.arc,
|
||||
data: f(unsafe { referece.data.as_ref() }).into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_map<N, F: for<'a> FnOnce(&'a M) -> Option<&'a N>>(
|
||||
referece: Self,
|
||||
f: F,
|
||||
) -> Option<AtomTableRef<N>> {
|
||||
let val = f(unsafe { referece.data.as_ref() })?;
|
||||
Some(AtomTableRef {
|
||||
arc: Arc::clone(&referece.arc),
|
||||
data: val.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: ?Sized> Deref for AtomTableRef<M> {
|
||||
type Target = M;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { self.data.as_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AtomTable {
|
||||
pub struct InnerAtomTable {
|
||||
block: RawBlock<AtomTable>,
|
||||
pub table: RwLock<IndexSet<Atom>>,
|
||||
}
|
||||
|
||||
impl Drop for AtomTable {
|
||||
fn drop(&mut self) {
|
||||
self.block.deallocate();
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct AtomTable {
|
||||
inner: RwLock<Arc<InnerAtomTable>>,
|
||||
// this lock is taking during resizing
|
||||
update: Mutex<()>,
|
||||
}
|
||||
|
||||
struct LookupKey<'table, 'key>(&'table AtomTable, &'key str);
|
||||
|
||||
impl Hash for LookupKey<'_, '_> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.1.hash(state);
|
||||
impl InnerAtomTable {
|
||||
#[inline(always)]
|
||||
fn lookup_str(self: &InnerAtomTable, string: &str) -> Option<Atom> {
|
||||
STATIC_ATOMS_MAP
|
||||
.get(string)
|
||||
.cloned()
|
||||
.or_else(|| self.table.blocking_read().get(string).cloned())
|
||||
}
|
||||
}
|
||||
|
||||
impl AtomTable {
|
||||
#[inline]
|
||||
pub fn new() -> Arc<RwLock<Self>> {
|
||||
pub fn new() -> Arc<Self> {
|
||||
let upgraded = global_atom_table().blocking_read().upgrade();
|
||||
// don't inline upgraded, otherwise temporary will be dropped too late in case of None
|
||||
if let Some(atom_table) = upgraded {
|
||||
@@ -356,84 +366,89 @@ impl AtomTable {
|
||||
if let Some(atom_table) = guard.upgrade() {
|
||||
atom_table
|
||||
} else {
|
||||
let atom_table = Arc::new(RwLock::new(Self {
|
||||
block: RawBlock::new(),
|
||||
table: RwLock::new(IndexSet::new()),
|
||||
}));
|
||||
let atom_table = Arc::new(Self {
|
||||
inner: RwLock::new(Arc::new(InnerAtomTable {
|
||||
block: RawBlock::new(),
|
||||
table: RwLock::new(IndexSet::new()),
|
||||
})),
|
||||
update: Mutex::new(()),
|
||||
});
|
||||
*guard = Arc::downgrade(&atom_table);
|
||||
atom_table
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn buf(&self) -> *const u8 {
|
||||
self.block.base as *const u8
|
||||
pub fn active_epoch(&self) -> AtomTableRef<InnerAtomTable> {
|
||||
let arc = Arc::clone(&self.inner.blocking_read());
|
||||
AtomTableRef {
|
||||
data: arc.deref().into(),
|
||||
arc,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn top(&self) -> *const u8 {
|
||||
self.block.top
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn lookup_str(self: &AtomTable, string: &str) -> Option<Atom> {
|
||||
STATIC_ATOMS_MAP.get(string).cloned().or_else(|| {
|
||||
self.table
|
||||
.blocking_read()
|
||||
.get(&LookupKey(self, string))
|
||||
.cloned()
|
||||
pub fn buf(&self) -> AtomTableRef<u8> {
|
||||
AtomTableRef::<InnerAtomTable>::map(self.active_epoch(), |inner| {
|
||||
unsafe { inner.block.base.as_ref() }.unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn build_with(atom_table: &RwLock<AtomTable>, string: &str) -> Atom {
|
||||
let mut atom_table = loop {
|
||||
// we can't just use blocking_write as tokio's RwLock is fair
|
||||
// and we can't block readers here as otherwise we will deadlock, see the guard downgrade below
|
||||
if let Ok(guard) = atom_table.try_write() {
|
||||
break guard;
|
||||
pub fn build_with(atom_table: &AtomTable, string: &str) -> Atom {
|
||||
loop {
|
||||
let mut epoch = atom_table.active_epoch();
|
||||
let count = epoch.table.blocking_read().len();
|
||||
|
||||
if let Some(atom) = epoch.lookup_str(string) {
|
||||
return atom;
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(atom) = atom_table.lookup_str(string) {
|
||||
return atom;
|
||||
}
|
||||
let update_guard = atom_table.update.lock().unwrap();
|
||||
|
||||
let is_same_allocation = Arc::ptr_eq(&epoch.arc, &atom_table.active_epoch().arc);
|
||||
let is_same_atom_count = count == epoch.table.blocking_read().len();
|
||||
|
||||
if !(is_same_allocation && is_same_atom_count) {
|
||||
// some other thread raced us between our lookup and us aquring the update lock, try again
|
||||
continue;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let size = mem::size_of::<AtomHeader>() + string.len();
|
||||
let align_offset = 8 * mem::align_of::<AtomHeader>();
|
||||
let size = (size & !(align_offset - 1)) + align_offset;
|
||||
|
||||
let len_ptr = loop {
|
||||
let ptr = atom_table.block.alloc(size);
|
||||
unsafe {
|
||||
let len_ptr = loop {
|
||||
let ptr = epoch.block.alloc(size);
|
||||
|
||||
if ptr.is_null() {
|
||||
atom_table.block.grow();
|
||||
} else {
|
||||
break ptr;
|
||||
}
|
||||
};
|
||||
if ptr.is_null() {
|
||||
let new_block = epoch.block.grow_new().unwrap();
|
||||
let new_table = RwLock::new(epoch.table.blocking_read().clone());
|
||||
let new_alloc = Arc::new(InnerAtomTable {
|
||||
block: new_block,
|
||||
table: new_table,
|
||||
});
|
||||
*atom_table.inner.blocking_write() = new_alloc;
|
||||
epoch = atom_table.active_epoch();
|
||||
} else {
|
||||
break ptr;
|
||||
}
|
||||
};
|
||||
|
||||
let ptr_base = atom_table.block.base as usize;
|
||||
let ptr_base = epoch.block.base as usize;
|
||||
|
||||
write_to_ptr(string, len_ptr);
|
||||
write_to_ptr(string, len_ptr);
|
||||
|
||||
let atom = Atom {
|
||||
index: ((STRINGS.len() << 3) + len_ptr as usize - ptr_base) as u64,
|
||||
};
|
||||
let atom = Atom {
|
||||
index: ((STRINGS.len() << 3) + len_ptr as usize - ptr_base) as u64,
|
||||
};
|
||||
|
||||
// we need to downgrade to a read so that Atom::hash can read from the AtomTable,
|
||||
// so that it can calculate the hash for inserting the atom
|
||||
// we can't just drop the guard as otherwise another thread could race us with another atom insertion
|
||||
let atom_table = atom_table.downgrade();
|
||||
epoch.table.blocking_write().insert(atom);
|
||||
|
||||
// NOTE: there is no race between downgrade and blocking write as table is only accessed writable in this function
|
||||
// and only after the write lock is acquired as we have the guard and just convert it from a write to a read guard no writer can race us
|
||||
atom_table.table.blocking_write().insert(atom);
|
||||
drop(update_guard);
|
||||
|
||||
drop(atom_table); // we need to keep the guard around till after the insert
|
||||
|
||||
atom
|
||||
return atom;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ use crate::machine::machine_errors::*;
|
||||
use fxhash::FxBuildHasher;
|
||||
use indexmap::IndexSet;
|
||||
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
@@ -264,7 +262,7 @@ impl CodeGenSettings {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CodeGenerator<'a> {
|
||||
pub(crate) atom_tbl: &'a RwLock<AtomTable>,
|
||||
pub(crate) atom_tbl: &'a AtomTable,
|
||||
marker: DebrayAllocator,
|
||||
settings: CodeGenSettings,
|
||||
pub(crate) skeleton: PredicateSkeleton,
|
||||
@@ -364,7 +362,7 @@ fn structure_cell(term: &Term) -> Option<&Cell<RegType>> {
|
||||
}
|
||||
|
||||
impl<'b> CodeGenerator<'b> {
|
||||
pub(crate) fn new(atom_tbl: &'b RwLock<AtomTable>, settings: CodeGenSettings) -> Self {
|
||||
pub(crate) fn new(atom_tbl: &'b AtomTable, settings: CodeGenSettings) -> Self {
|
||||
CodeGenerator {
|
||||
atom_tbl,
|
||||
marker: DebrayAllocator::new(),
|
||||
|
||||
@@ -16,8 +16,6 @@ use fxhash::FxBuildHasher;
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use ordered_float::OrderedFloat;
|
||||
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryFrom;
|
||||
@@ -483,7 +481,7 @@ pub enum AtomOrString {
|
||||
|
||||
impl AtomOrString {
|
||||
#[inline]
|
||||
pub fn as_atom(&self, atom_tbl: &RwLock<AtomTable>) -> Atom {
|
||||
pub fn as_atom(&self, atom_tbl: &AtomTable) -> Atom {
|
||||
match self {
|
||||
&AtomOrString::Atom(atom) => atom,
|
||||
AtomOrString::String(string) => AtomTable::build_with(atom_tbl, &string),
|
||||
|
||||
@@ -24,8 +24,6 @@ use ordered_float::OrderedFloat;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::convert::TryFrom;
|
||||
use std::iter::once;
|
||||
@@ -483,7 +481,7 @@ pub fn fmt_float(mut fl: f64) -> String {
|
||||
pub struct HCPrinter<'a, Outputter> {
|
||||
outputter: Outputter,
|
||||
iter: StackfulPreOrderHeapIter<'a>,
|
||||
atom_tbl: Arc<RwLock<AtomTable>>,
|
||||
atom_tbl: Arc<AtomTable>,
|
||||
op_dir: &'a OpDir,
|
||||
state_stack: Vec<TokenOrRedirect>,
|
||||
toplevel_spec: Option<DirectedOp>,
|
||||
@@ -552,7 +550,7 @@ pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option<String>
|
||||
impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
pub fn new(
|
||||
heap: &'a mut Heap,
|
||||
atom_tbl: Arc<RwLock<AtomTable>>,
|
||||
atom_tbl: Arc<AtomTable>,
|
||||
stack: &'a mut Stack,
|
||||
op_dir: &'a OpDir,
|
||||
output: Outputter,
|
||||
|
||||
@@ -6,7 +6,6 @@ use crate::instructions::*;
|
||||
|
||||
use fxhash::FxBuildHasher;
|
||||
use indexmap::IndexMap;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::hash::Hash;
|
||||
@@ -1094,7 +1093,7 @@ fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) {
|
||||
|
||||
pub(crate) fn constant_key_alternatives(
|
||||
constant: Literal,
|
||||
atom_tbl: &RwLock<AtomTable>,
|
||||
atom_tbl: &AtomTable,
|
||||
// arena: &mut Arena,
|
||||
) -> Vec<Literal> {
|
||||
let mut constants = vec![];
|
||||
@@ -1455,7 +1454,7 @@ impl<I: Indexer> CodeOffsets<I> {
|
||||
|
||||
fn index_constant(
|
||||
&mut self,
|
||||
atom_tbl: &RwLock<AtomTable>,
|
||||
atom_tbl: &AtomTable,
|
||||
constant: Literal,
|
||||
index: usize,
|
||||
) -> Vec<Literal> {
|
||||
@@ -1512,7 +1511,7 @@ impl<I: Indexer> CodeOffsets<I> {
|
||||
optimal_arg: &Term,
|
||||
index: usize,
|
||||
clause_index_info: &mut ClauseIndexInfo,
|
||||
atom_tbl: &RwLock<AtomTable>,
|
||||
atom_tbl: &AtomTable,
|
||||
) {
|
||||
match optimal_arg {
|
||||
&Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => {
|
||||
|
||||
@@ -3000,7 +3000,7 @@ impl Machine {
|
||||
HeapCellValueTag::StackVar |
|
||||
HeapCellValueTag::Var) => {
|
||||
let target_cell = self.machine_st.push_str_to_heap(
|
||||
string.as_str(),
|
||||
&string.as_str(),
|
||||
has_tail,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
@@ -132,11 +130,7 @@ pub fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: u
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn put_complete_string(
|
||||
heap: &mut Heap,
|
||||
s: &str,
|
||||
atom_tbl: &RwLock<AtomTable>,
|
||||
) -> HeapCellValue {
|
||||
pub(crate) fn put_complete_string(heap: &mut Heap, s: &str, atom_tbl: &AtomTable) -> HeapCellValue {
|
||||
match allocate_pstr(heap, s, atom_tbl) {
|
||||
Some(h) => {
|
||||
heap.pop(); // pop the trailing variable cell from the heap planted by allocate_pstr.
|
||||
@@ -159,11 +153,7 @@ pub(crate) fn put_complete_string(
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn put_partial_string(
|
||||
heap: &mut Heap,
|
||||
s: &str,
|
||||
atom_tbl: &RwLock<AtomTable>,
|
||||
) -> HeapCellValue {
|
||||
pub(crate) fn put_partial_string(heap: &mut Heap, s: &str, atom_tbl: &AtomTable) -> HeapCellValue {
|
||||
match allocate_pstr(heap, s, atom_tbl) {
|
||||
Some(h) => {
|
||||
pstr_loc_as_cell!(h)
|
||||
@@ -175,11 +165,7 @@ pub(crate) fn put_partial_string(
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn allocate_pstr(
|
||||
heap: &mut Heap,
|
||||
mut src: &str,
|
||||
atom_tbl: &RwLock<AtomTable>,
|
||||
) -> Option<usize> {
|
||||
pub(crate) fn allocate_pstr(heap: &mut Heap, mut src: &str, atom_tbl: &AtomTable) -> Option<usize> {
|
||||
let orig_h = heap.len();
|
||||
|
||||
loop {
|
||||
|
||||
@@ -18,7 +18,6 @@ use crate::types::*;
|
||||
use crate::parser::dashu::Integer;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
@@ -59,7 +58,7 @@ pub enum OnEOF {
|
||||
}
|
||||
|
||||
pub struct MachineState {
|
||||
pub atom_tbl: Arc<RwLock<AtomTable>>,
|
||||
pub atom_tbl: Arc<AtomTable>,
|
||||
pub arena: Arena,
|
||||
pub(super) pdl: Vec<HeapCellValue>,
|
||||
pub(super) s: HeapPtr,
|
||||
@@ -205,7 +204,7 @@ pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixn
|
||||
fn push_var_eq_functors<'a>(
|
||||
heap: &mut Heap,
|
||||
iter: impl Iterator<Item = (&'a VarKey, &'a HeapCellValue)>,
|
||||
atom_tbl: &RwLock<AtomTable>,
|
||||
atom_tbl: &AtomTable,
|
||||
) -> Vec<HeapCellValue> {
|
||||
let mut list_of_var_eqs = vec![];
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::atom_table::*;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
@@ -45,7 +43,7 @@ impl Into<Atom> for PartialString {
|
||||
|
||||
impl PartialString {
|
||||
#[inline]
|
||||
pub(super) fn new<'a>(src: &'a str, atom_tbl: &RwLock<AtomTable>) -> Option<(Self, &'a str)> {
|
||||
pub(super) fn new<'a>(src: &'a str, atom_tbl: &AtomTable) -> Option<(Self, &'a str)> {
|
||||
let terminator_idx = scan_for_terminator(src.chars());
|
||||
let pstr = PartialString(AtomTable::build_with(&atom_tbl, &src[..terminator_idx]));
|
||||
Some(if terminator_idx < src.as_bytes().len() {
|
||||
|
||||
@@ -8,7 +8,6 @@ use crate::machine::machine_errors::*;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::convert::TryFrom;
|
||||
@@ -26,10 +25,7 @@ pub(crate) fn to_op_decl(prec: u16, spec: Atom, name: Atom) -> Result<OpDecl, Co
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_op_decl(
|
||||
mut terms: Vec<Term>,
|
||||
atom_tbl: &RwLock<AtomTable>,
|
||||
) -> Result<OpDecl, CompilationError> {
|
||||
fn setup_op_decl(mut terms: Vec<Term>, atom_tbl: &AtomTable) -> Result<OpDecl, CompilationError> {
|
||||
let name = match terms.pop().unwrap() {
|
||||
Term::Literal(_, Literal::Atom(name)) => name,
|
||||
Term::Literal(_, Literal::Char(c)) => AtomTable::build_with(atom_tbl, &c.to_string()),
|
||||
@@ -86,7 +82,7 @@ fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, Compilatio
|
||||
|
||||
fn setup_module_export(
|
||||
mut term: Term,
|
||||
atom_tbl: &RwLock<AtomTable>,
|
||||
atom_tbl: &AtomTable,
|
||||
) -> Result<ModuleExport, CompilationError> {
|
||||
setup_predicate_indicator(&mut term)
|
||||
.map(ModuleExport::PredicateKey)
|
||||
@@ -112,7 +108,7 @@ pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
|
||||
|
||||
pub(super) fn setup_module_export_list(
|
||||
mut export_list: Term,
|
||||
atom_tbl: &RwLock<AtomTable>,
|
||||
atom_tbl: &AtomTable,
|
||||
) -> Result<Vec<ModuleExport>, CompilationError> {
|
||||
let mut exports = vec![];
|
||||
|
||||
@@ -132,7 +128,7 @@ pub(super) fn setup_module_export_list(
|
||||
|
||||
fn setup_module_decl(
|
||||
mut terms: Vec<Term>,
|
||||
atom_tbl: &RwLock<AtomTable>,
|
||||
atom_tbl: &AtomTable,
|
||||
) -> Result<ModuleDecl, CompilationError> {
|
||||
let export_list = terms.pop().unwrap();
|
||||
let name = terms.pop().unwrap();
|
||||
@@ -165,7 +161,7 @@ type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
|
||||
|
||||
fn setup_qualified_import(
|
||||
mut terms: Vec<Term>,
|
||||
atom_tbl: &RwLock<AtomTable>,
|
||||
atom_tbl: &AtomTable,
|
||||
) -> Result<UseModuleExport, CompilationError> {
|
||||
let mut export_list = terms.pop().unwrap();
|
||||
let module_src = match terms.pop().unwrap() {
|
||||
|
||||
@@ -30,12 +30,6 @@ pub struct Stack {
|
||||
_marker: PhantomData<HeapCellValue>,
|
||||
}
|
||||
|
||||
impl Drop for Stack {
|
||||
fn drop(&mut self) {
|
||||
self.buf.deallocate();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct AndFramePrelude {
|
||||
pub(crate) num_cells: usize,
|
||||
@@ -189,7 +183,7 @@ impl Stack {
|
||||
let frame_size = AndFrame::size_of(num_cells);
|
||||
|
||||
unsafe {
|
||||
let e = self.buf.ptr as usize - self.buf.base as usize;
|
||||
let e = (*self.buf.ptr.get_mut()) as usize - self.buf.base as usize;
|
||||
let new_ptr = self.alloc(frame_size);
|
||||
let mut offset = prelude_size::<AndFramePrelude>();
|
||||
|
||||
@@ -213,7 +207,7 @@ impl Stack {
|
||||
let frame_size = OrFrame::size_of(num_cells);
|
||||
|
||||
unsafe {
|
||||
let b = self.buf.ptr as usize - self.buf.base as usize;
|
||||
let b = (*self.buf.ptr.get_mut()) as usize - self.buf.base as usize;
|
||||
let new_ptr = self.alloc(frame_size);
|
||||
let mut offset = prelude_size::<OrFramePrelude>();
|
||||
|
||||
@@ -269,8 +263,8 @@ impl Stack {
|
||||
pub(crate) fn truncate(&mut self, b: usize) {
|
||||
let base = self.buf.base as usize + b;
|
||||
|
||||
if base < self.buf.ptr as usize {
|
||||
self.buf.ptr = base as *mut _;
|
||||
if base < (*self.buf.ptr.get_mut()) as usize {
|
||||
*self.buf.ptr.get_mut() = base as *mut _;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ use fxhash::FxBuildHasher;
|
||||
use indexmap::IndexMap;
|
||||
use modular_bitfield::error::OutOfBounds;
|
||||
use modular_bitfield::prelude::*;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
pub type Specifier = u32;
|
||||
|
||||
@@ -633,7 +632,7 @@ impl fmt::Display for Literal {
|
||||
}
|
||||
|
||||
impl Literal {
|
||||
pub fn to_atom(&self, atom_tbl: &Arc<RwLock<AtomTable>>) -> Option<Atom> {
|
||||
pub fn to_atom(&self, atom_tbl: &Arc<AtomTable>) -> Option<Atom> {
|
||||
match self {
|
||||
Literal::Atom(atom) => Some(atom.defrock_brackets(atom_tbl)),
|
||||
_ => None,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use dashu::Integer;
|
||||
use dashu::Rational;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
@@ -286,14 +285,14 @@ fn read_tokens<R: CharRead>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserEr
|
||||
Ok(tokens)
|
||||
}
|
||||
|
||||
fn atomize_term(atom_tbl: &RwLock<AtomTable>, term: &Term) -> Option<Atom> {
|
||||
fn atomize_term(atom_tbl: &AtomTable, term: &Term) -> Option<Atom> {
|
||||
match term {
|
||||
Term::Literal(_, ref c) => atomize_constant(atom_tbl, *c),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn atomize_constant(atom_tbl: &RwLock<AtomTable>, c: Literal) -> Option<Atom> {
|
||||
fn atomize_constant(atom_tbl: &AtomTable, c: Literal) -> Option<Atom> {
|
||||
match c {
|
||||
Literal::Atom(ref name) => Some(*name),
|
||||
Literal::Char(c) => Some(AtomTable::build_with(atom_tbl, &c.to_string())),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use std::alloc;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::ptr;
|
||||
|
||||
pub trait RawBlockTraits {
|
||||
@@ -12,7 +13,7 @@ pub trait RawBlockTraits {
|
||||
pub struct RawBlock<T: RawBlockTraits> {
|
||||
pub base: *const u8,
|
||||
pub top: *const u8,
|
||||
pub ptr: *mut u8,
|
||||
pub ptr: UnsafeCell<*mut u8>,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
@@ -22,7 +23,7 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
||||
RawBlock {
|
||||
base: ptr::null(),
|
||||
top: ptr::null(),
|
||||
ptr: ptr::null_mut(),
|
||||
ptr: UnsafeCell::new(ptr::null_mut()),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -42,7 +43,7 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
||||
|
||||
self.base = alloc::alloc(layout) as *const _;
|
||||
self.top = (self.base as usize + cap) as *const _;
|
||||
self.ptr = self.base as *mut _;
|
||||
*self.ptr.get_mut() = self.base as *mut _;
|
||||
}
|
||||
|
||||
pub unsafe fn grow(&mut self) {
|
||||
@@ -54,7 +55,25 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
||||
|
||||
self.base = alloc::realloc(self.base as *mut _, layout, size * 2) as *const _;
|
||||
self.top = (self.base as usize + size * 2) as *const _;
|
||||
self.ptr = (self.base as usize + size) as *mut _;
|
||||
*self.ptr.get_mut() = (self.base as usize + size) as *mut _;
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn grow_new(&self) -> Option<Self> {
|
||||
if self.base.is_null() {
|
||||
Some(Self::new())
|
||||
} else {
|
||||
let mut new_block = Self::empty_block();
|
||||
new_block.init_at_size(self.size() * 2);
|
||||
if new_block.base.is_null() {
|
||||
// allocation failed
|
||||
None
|
||||
} else {
|
||||
let allocated = (*self.ptr.get()) as usize - self.base as usize;
|
||||
self.base.copy_to(new_block.base.cast_mut(), allocated);
|
||||
*new_block.ptr.get_mut() = new_block.base.offset(allocated as isize).cast_mut();
|
||||
Some(new_block)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,35 +83,39 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn free_space(&self) -> usize {
|
||||
unsafe fn free_space(&self) -> usize {
|
||||
debug_assert!(
|
||||
self.ptr as *const _ >= self.base,
|
||||
*self.ptr.get() as *const _ >= self.base,
|
||||
"self.ptr = {:?} < {:?} = self.base",
|
||||
self.ptr,
|
||||
*self.ptr.get(),
|
||||
self.base
|
||||
);
|
||||
|
||||
self.top as usize - self.ptr as usize
|
||||
self.top as usize - (*self.ptr.get()) as usize
|
||||
}
|
||||
|
||||
pub unsafe fn alloc(&mut self, size: usize) -> *mut u8 {
|
||||
pub unsafe fn alloc(&self, size: usize) -> *mut u8 {
|
||||
if self.free_space() >= size {
|
||||
let ptr = self.ptr;
|
||||
self.ptr = (self.ptr as usize + size) as *mut _;
|
||||
let ptr = *self.ptr.get();
|
||||
*self.ptr.get() = (ptr as usize + size) as *mut _;
|
||||
ptr
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deallocate(&mut self) {
|
||||
unsafe {
|
||||
let layout = alloc::Layout::from_size_align_unchecked(self.size(), T::align());
|
||||
alloc::dealloc(self.base as *mut _, layout);
|
||||
impl<T: RawBlockTraits> Drop for RawBlock<T> {
|
||||
fn drop(&mut self) {
|
||||
if !self.base.is_null() {
|
||||
unsafe {
|
||||
let layout = alloc::Layout::from_size_align_unchecked(self.size(), T::align());
|
||||
alloc::dealloc(self.base as *mut _, layout);
|
||||
}
|
||||
|
||||
self.top = ptr::null();
|
||||
self.base = ptr::null();
|
||||
self.ptr = ptr::null_mut();
|
||||
*self.ptr.get_mut() = ptr::null_mut();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
13
src/read.rs
13
src/read.rs
@@ -16,10 +16,6 @@ use crate::types::*;
|
||||
|
||||
use fxhash::FxBuildHasher;
|
||||
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(feature = "repl")]
|
||||
use rustyline::error::ReadlineError;
|
||||
#[cfg(feature = "repl")]
|
||||
@@ -29,6 +25,7 @@ use rustyline::{Config, Editor};
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::io::{Cursor, Error, ErrorKind, Read};
|
||||
use std::sync::Arc;
|
||||
|
||||
type SubtermDeque = VecDeque<(usize, usize)>;
|
||||
|
||||
@@ -148,7 +145,7 @@ impl ReadlineStream {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_atoms_for_completion(&mut self, atoms: &Arc<RwLock<AtomTable>>) {
|
||||
pub fn set_atoms_for_completion(&mut self, atoms: &Arc<AtomTable>) {
|
||||
#[cfg(feature = "repl")]
|
||||
{
|
||||
let helper = self.rl.helper_mut().unwrap();
|
||||
@@ -291,7 +288,7 @@ impl CharRead for ReadlineStream {
|
||||
pub(crate) fn write_term_to_heap<'a, 'b>(
|
||||
term: &'a Term,
|
||||
heap: &'b mut Heap,
|
||||
atom_tbl: &RwLock<AtomTable>,
|
||||
atom_tbl: &AtomTable,
|
||||
) -> Result<TermWriteResult, CompilationError> {
|
||||
let term_writer = TermWriter::new(heap, atom_tbl);
|
||||
term_writer.write_term_to_heap(term)
|
||||
@@ -300,7 +297,7 @@ pub(crate) fn write_term_to_heap<'a, 'b>(
|
||||
#[derive(Debug)]
|
||||
struct TermWriter<'a, 'b> {
|
||||
heap: &'a mut Heap,
|
||||
atom_tbl: &'b RwLock<AtomTable>,
|
||||
atom_tbl: &'b AtomTable,
|
||||
queue: SubtermDeque,
|
||||
var_dict: HeapVarDict,
|
||||
}
|
||||
@@ -313,7 +310,7 @@ pub struct TermWriteResult {
|
||||
|
||||
impl<'a, 'b> TermWriter<'a, 'b> {
|
||||
#[inline]
|
||||
fn new(heap: &'a mut Heap, atom_tbl: &'b RwLock<AtomTable>) -> Self {
|
||||
fn new(heap: &'a mut Heap, atom_tbl: &'b AtomTable) -> Self {
|
||||
TermWriter {
|
||||
heap,
|
||||
atom_tbl,
|
||||
|
||||
@@ -4,8 +4,6 @@ use rustyline::hint::Hinter;
|
||||
use rustyline::validate::Validator;
|
||||
use rustyline::{Context, Helper as RlHelper, Result};
|
||||
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use std::sync::Weak;
|
||||
|
||||
use crate::atom_table::{AtomString, AtomTable, STATIC_ATOMS_MAP};
|
||||
@@ -13,7 +11,7 @@ use crate::atom_table::{AtomString, AtomTable, STATIC_ATOMS_MAP};
|
||||
// TODO: Maybe add validation to the helper
|
||||
pub struct Helper {
|
||||
highligher: MatchingBracketHighlighter,
|
||||
pub atoms: Weak<RwLock<AtomTable>>,
|
||||
pub atoms: Weak<AtomTable>,
|
||||
}
|
||||
|
||||
impl Helper {
|
||||
@@ -71,11 +69,10 @@ impl Completer for Helper {
|
||||
let sub_str = line.get(idx..pos).unwrap();
|
||||
|
||||
let atom_table = self.atoms.upgrade().unwrap();
|
||||
let guard = atom_table.blocking_read();
|
||||
|
||||
let mut matching = guard
|
||||
.table
|
||||
.blocking_read()
|
||||
let index_set = atom_table.active_epoch().table.blocking_read().clone();
|
||||
|
||||
let mut matching = index_set
|
||||
.iter()
|
||||
.chain(STATIC_ATOMS_MAP.values())
|
||||
.map(|a| a.as_str())
|
||||
|
||||
Reference in New Issue
Block a user