[WIP] move towards lockless AtomTable

This commit is contained in:
Bennet Bleßmann
2023-08-28 23:24:27 +02:00
parent d24e6100a7
commit 01aeb7515d
17 changed files with 231 additions and 241 deletions

View File

@@ -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| {

View File

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

View File

@@ -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(),

View File

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

View File

@@ -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,

View File

@@ -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 => {

View File

@@ -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,
);

View File

@@ -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 {

View File

@@ -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![];

View File

@@ -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() {

View File

@@ -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() {

View File

@@ -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 _;
}
}
}

View File

@@ -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,

View File

@@ -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())),

View File

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

View File

@@ -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,

View File

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