[[package]]
name = "lock_api"
-version = "0.4.12"
+version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
dependencies = [
"autocfg",
"scopeguard",
[[package]]
name = "parking_lot"
-version = "0.12.3"
+version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
dependencies = [
"lock_api",
"parking_lot_core",
[[package]]
name = "parking_lot_core"
-version = "0.9.10"
+version = "0.9.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
dependencies = [
"cfg-if",
"libc",
"num-order",
"ordered-float",
"ouroboros",
+ "parking_lot",
"phf",
"pprof",
"proc-macro2",
serde_json = "1.0.122"
serde = "1.0.204"
+parking_lot = "0.12.4"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
crossterm = { version = "0.28.1", optional = true }
#[cfg(test)]
mod tests {
- use std::ops::Deref;
-
use crate::arena::*;
use crate::atom_table::*;
use crate::machine::mock_wam::*;
assert_eq!(cell.get_tag(), HeapCellValueTag::F64Offset);
assert!(!cell.get_mark_bit());
- assert_eq!(
- wam.machine_st.arena.f64_tbl.lookup(fp).deref(),
- &OrderedFloat(f)
- );
+ assert_eq!(wam.machine_st.arena.f64_tbl.get_entry(fp), OrderedFloat(f));
cell.set_mark_bit(true);
read_heap_cell!(cell,
(HeapCellValueTag::F64Offset, offset) => {
- let fp = wam.machine_st.arena.f64_tbl.lookup(offset.into());
- assert_eq!(*fp, OrderedFloat(0f64))
+ let fp = wam.machine_st.arena.f64_tbl.get_entry(offset);
+ assert_eq!(fp, OrderedFloat(0f64))
}
_ => { unreachable!() }
);
Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))),
Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))),
&Literal::F64Offset(offset) => {
- let n = *f64_tbl.lookup(offset);
+ let n = f64_tbl.get_entry(offset);
interm.push(ArithmeticTerm::Number(Number::Float(n)));
}
Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))),
)
}
(HeapCellValueTag::F64Offset, offset) => {
- let n = *f64_tbl.lookup(offset.into());
+ let n = f64_tbl.get_entry(offset);
Ok(Number::Float(n))
}
(HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint, n) => {
self.state_stack.pop();
self.state_stack.pop();
- let idx_ptr = self.arena.code_index_tbl.lookup(idx);
+ let idx_ptr = self.arena.code_index_tbl.get_entry(idx);
let offset = if idx_ptr.is_undefined() || idx_ptr.is_dynamic_undefined() {
TokenOrRedirect::Atom(atom!("undefined"))
self.print_number(max_depth, NumberFocus::Unfocused(Number::Fixnum(n)), &op);
}
(HeapCellValueTag::F64Offset, offset) => {
- let f = *self.arena.f64_tbl.lookup(offset.into());
+ let f = self.arena.f64_tbl.get_entry(offset);
self.print_number(max_depth, NumberFocus::Unfocused(Number::Float(f)), &op);
}
(HeapCellValueTag::PStrLoc) => {
self.interms.push(Number::Fixnum(n));
}
(HeapCellValueTag::F64Offset, offset) => {
- let fl = self.arena.f64_tbl.lookup(offset);
- self.interms.push(Number::Float(*fl));
+ let fl = self.arena.f64_tbl.get_entry(offset);
+ self.interms.push(Number::Float(fl));
}
(HeapCellValueTag::Cons, ptr) => {
match_untyped_arena_ptr!(ptr,
let index_ptr = LS::machine_st(&mut self.payload)
.arena
.code_index_tbl
- .lookup(code_idx.into());
+ .get_entry(code_idx.into());
print_overwrite_warning(
&predicates.compilation_target,
- *index_ptr,
+ index_ptr,
key,
settings.is_dynamic(),
);
- drop(index_ptr);
-
let index_ptr = if settings.is_dynamic() {
IndexPtr::dynamic_index(code_ptr)
} else {
if let Some(filename) = self.listing_src_file_name() {
if let Some(ref mut module) = self.wam_prelude.indices.modules.get_mut(&filename) {
- let index_ptr = *LS::machine_st(&mut self.payload)
+ let index_ptr = LS::machine_st(&mut self.payload)
.arena
.code_index_tbl
- .lookup_mut(offset.into());
+ .get_entry(offset.into());
let offset = *module.code_dir.entry(key).or_insert(offset);
// Find the boundaries of the current predicate
self.indices.code_dir.sort_by(|_, a, _, b| {
- let a = *self.machine_st.arena.code_index_tbl.lookup((*a).into());
- let b = *self.machine_st.arena.code_index_tbl.lookup((*b).into());
+ let a = self.machine_st.arena.code_index_tbl.get_entry((*a).into());
+ let b = self.machine_st.arena.code_index_tbl.get_entry((*b).into());
a.cmp(&b)
});
.indices
.code_dir
.binary_search_by_key(&p, |_, x| -> usize {
- self.machine_st.arena.code_index_tbl.lookup((*x).into()).p()
- as usize
+ self.machine_st
+ .arena
+ .code_index_tbl
+ .get_entry((*x).into())
+ .p() as usize
})
.unwrap_or_else(|x| x - 1);
self.machine_st
.arena
.code_index_tbl
- .lookup((*idx.1).into())
+ .get_entry((*idx.1).into())
.p() as usize
})
.unwrap();
self.machine_st
.arena
.code_index_tbl
- .lookup((*idx.1).into())
+ .get_entry((*idx.1).into())
.p() as usize
})
.unwrap_or(self.code.len());
}
}
&Instruction::CallNamed(arity, name, idx) => {
- let idx = *self.machine_st.arena.code_index_tbl.lookup(idx.into());
+ let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
try_or_throw!(self.machine_st, self.try_call(name, arity, idx));
}
}
&Instruction::ExecuteNamed(arity, name, idx) => {
- let idx = *self.machine_st.arena.code_index_tbl.lookup(idx.into());
+ let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
try_or_throw!(self.machine_st, self.try_execute(name, arity, idx));
}
}
&Instruction::DefaultCallNamed(arity, name, idx) => {
- let idx = *self.machine_st.arena.code_index_tbl.lookup(idx.into());
+ let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
try_or_throw!(self.machine_st, self.try_call(name, arity, idx));
}
}
&Instruction::DefaultExecuteNamed(arity, name, idx) => {
- let idx = *self.machine_st.arena.code_index_tbl.lookup(idx.into());
+ let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
try_or_throw!(self.machine_st, self.try_execute(name, arity, idx));
}
}
(HeapCellValueTag::F64Offset, offset) => {
- let f = *machine.machine_st.arena.f64_tbl.lookup(offset);
+ let f = machine.machine_st.arena.f64_tbl.get_entry(offset);
term_stack.push(Term::Float(f.into()));
}
(HeapCellValueTag::Fixnum, n) => {
self.machine_st
.arena
.code_index_tbl
- .lookup(offset.into())
+ .get_entry(offset.into())
.p() as usize
})
.expect("couldn't get code index");
code_idx: CodeIndex,
code_ptr: IndexPtr,
) {
- let mut code_idx_ptr = LS::machine_st(payload)
- .arena
- .code_index_tbl
- .lookup_mut(code_idx.into());
-
- let record = match compilation_target {
- CompilationTarget::User => {
- if IndexPtrTag::Undefined == code_idx_ptr.tag() {
- code_idx_ptr.set(code_ptr);
- RetractionRecord::AddedUserPredicate(key)
- } else {
- let replaced = code_idx_ptr.replace(code_ptr);
- RetractionRecord::ReplacedUserPredicate(key, replaced)
+ let record = LS::machine_st(payload).arena.code_index_tbl.with_entry_mut(
+ code_idx.into(),
+ |code_idx_ptr| match compilation_target {
+ CompilationTarget::User => {
+ if IndexPtrTag::Undefined == code_idx_ptr.tag() {
+ *code_idx_ptr = code_ptr;
+ RetractionRecord::AddedUserPredicate(key)
+ } else {
+ let replaced = mem::replace(code_idx_ptr, code_ptr);
+ RetractionRecord::ReplacedUserPredicate(key, replaced)
+ }
}
- }
- CompilationTarget::Module(ref module_name) => {
- if IndexPtrTag::Undefined == code_idx_ptr.tag() {
- code_idx_ptr.set(code_ptr);
- RetractionRecord::AddedModulePredicate(*module_name, key)
- } else {
- let replaced = code_idx_ptr.replace(code_ptr);
- RetractionRecord::ReplacedModulePredicate(*module_name, key, replaced)
+ CompilationTarget::Module(ref module_name) => {
+ if IndexPtrTag::Undefined == code_idx_ptr.tag() {
+ *code_idx_ptr = code_ptr;
+ RetractionRecord::AddedModulePredicate(*module_name, key)
+ } else {
+ let replaced = mem::replace(code_idx_ptr, code_ptr);
+ RetractionRecord::ReplacedModulePredicate(*module_name, key, replaced)
+ }
}
- }
- };
+ },
+ );
- drop(code_idx_ptr);
payload.retraction_info.push_record(record);
}
.entry(key)
.or_insert_with(|| CodeIndex::default(code_idx_tbl));
- let src_code_index_ptr = *code_idx_tbl.lookup(src_code_index.into());
+ let src_code_index_ptr = code_idx_tbl.get_entry(src_code_index.into());
set_code_index::<LS>(
payload,
if LS::machine_st(payload)
.arena
.code_index_tbl
- .lookup(src_code_index.into())
+ .get_entry(src_code_index.into())
.is_dynamic_undefined()
{
code_dir.insert(key, src_code_index);
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
- let src_code_ptr = *code_index_tbl.lookup(src_code_index.into());
+ let src_code_ptr = code_index_tbl.get_entry(src_code_index.into());
let target_code_index = *code_dir
.entry(key)
.or_insert_with(|| CodeIndex::default(code_index_tbl));
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
- let src_code_ptr = *code_index_tbl.lookup(src_code_index.into());
+ let src_code_ptr = code_index_tbl.get_entry(src_code_index.into());
let target_code_index =
*wam_prelude.indices.code_dir.entry(key).or_insert_with(|| {
CodeIndex::new(IndexPtr::undefined(), code_index_tbl)
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
- let src_code_ptr = *code_index_tbl.lookup(src_code_index.into());
+ let src_code_ptr = code_index_tbl.get_entry(src_code_index.into());
let target_code_index = *code_dir
.entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), code_index_tbl));
}
let code_index_tbl = &mut LS::machine_st(&mut self.payload).arena.code_index_tbl;
- let code_ptr = code_index_tbl.lookup((*code_index).into());
+ let code_ptr = code_index_tbl.get_entry((*code_index).into());
if !code_ptr.is_undefined() && !code_ptr.is_dynamic_undefined() {
- drop(code_ptr);
let old_index_ptr = code_index.replace(code_index_tbl, IndexPtr::undefined());
self.payload.retraction_info.push_record(
(Some(module_code_idx), Some(target_code_idx)) => {
let code_index_tbl =
&mut LS::machine_st(payload).arena.code_index_tbl;
- let module_code_ptr = code_index_tbl.lookup(module_code_idx.into());
- let target_code_ptr = code_index_tbl.lookup(target_code_idx.into());
+ let module_code_ptr =
+ code_index_tbl.get_entry(module_code_idx.into());
+ let target_code_ptr =
+ code_index_tbl.get_entry(target_code_idx.into());
if module_code_ptr == target_code_ptr {
- drop(module_code_ptr);
- drop(target_code_ptr);
-
let old_index_ptr = target_code_idx
.replace(code_index_tbl, IndexPtr::undefined());
payload
let code_idx_ptr = LS::machine_st(&mut self.payload)
.arena
.code_index_tbl
- .lookup_mut(offset.into());
+ .get_entry(offset.into());
if code_idx_ptr.is_undefined() {
- drop(code_idx_ptr);
-
set_code_index::<LS>(
&mut self.payload,
&compilation_target,
.machine_st
.arena
.code_index_tbl
- .lookup(offset.into())
- .tag()
+ .with_entry(offset.into(), |idx| idx.tag())
})
.unwrap_or(IndexPtrTag::DynamicUndefined);
let offset = loader.get_or_insert_code_index(key, compilation_target);
- let mut code_idx = loader
+ loader
.payload
.machine_st
.arena
.code_index_tbl
- .lookup_mut(offset.into());
-
- code_idx.set(IndexPtr::undefined());
-
- drop(code_idx);
+ .with_entry_mut(offset.into(), |code_idx| {
+ *code_idx = IndexPtr::undefined();
+ });
loader.payload.compilation_target = clause_clause_compilation_target;
#[inline(always)]
pub(crate) fn set(&self, code_index_tbl: &mut CodeIndexTable, value: IndexPtr) {
- code_index_tbl.lookup_mut(self.0).set(value);
+ code_index_tbl.with_entry_mut(self.0, |idx| *idx = value);
}
#[inline(always)]
pub(crate) fn replace(&self, code_index_tbl: &mut CodeIndexTable, value: IndexPtr) -> IndexPtr {
- code_index_tbl.lookup_mut(self.0).replace(value)
+ code_index_tbl.with_entry_mut(self.0, |idx| std::mem::replace(idx, value))
}
}
let v1 = cell_as_f64_offset!(v1);
let v2 = cell_as_f64_offset!(v2);
- let v1 = self.arena.f64_tbl.lookup(v1);
- let v2 = self.arena.f64_tbl.lookup(v2);
+ let v1 = self.arena.f64_tbl.get_entry(v1);
+ let v2 = self.arena.f64_tbl.get_entry(v2);
if v1 != v2 {
self.pdl.clear();
) -> std::process::ExitCode {
if let Some(module) = self.indices.modules.get(&module_name) {
if let Some(code_idx) = module.code_dir.get(&key) {
- let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(code_idx.into());
+ let index_ptr = self
+ .machine_st
+ .arena
+ .code_index_tbl
+ .get_entry(code_idx.into());
let p = index_ptr.local().unwrap();
// Leave a halting choice point to backtrack to in case the predicate fails or throws.
if let Some(module) = self.indices.modules.get(&atom!("$atts")) {
if let Some(code_idx) = module.code_dir.get(&(atom!("driver"), 2)) {
- let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(code_idx.into());
+ let index_ptr = self
+ .machine_st
+ .arena
+ .code_index_tbl
+ .get_entry(code_idx.into());
self.machine_st.attr_var_init.verify_attrs_loc = index_ptr.local().unwrap();
}
}
CodeIndex::new(IndexPtr::undefined(), code_index_tbl)
});
- let src_code_ptr = *code_index_tbl.lookup(src_code_index.into());
+ let src_code_ptr = code_index_tbl.get_entry(src_code_index.into());
target_code_index.set(code_index_tbl, src_code_ptr);
}
None => {
if module_name == atom!("user") {
if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
- let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(idx.into());
+ let index_ptr = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
self.try_call(name, arity, index_ptr)
} else {
Err(self.machine_st.throw_undefined_error(name, arity))
}
} else if let Some(module) = self.indices.modules.get(&module_name) {
if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() {
- let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(idx.into());
+ let index_ptr = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
self.try_call(name, arity, index_ptr)
} else {
self.undefined_procedure(name, arity)
let (name, arity) = key;
if module_name == atom!("user") {
- if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
- let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(idx.into());
+ if let Some(offset) = self.indices.code_dir.get(&(name, arity)).cloned() {
+ let index_ptr = self
+ .machine_st
+ .arena
+ .code_index_tbl
+ .get_entry(offset.into());
self.try_execute(name, arity, index_ptr)
} else {
self.undefined_procedure(name, arity)
}
} else if let Some(module) = self.indices.modules.get(&module_name) {
- if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() {
- let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(idx.into());
+ if let Some(offset) = module.code_dir.get(&(name, arity)).cloned() {
+ let index_ptr = self
+ .machine_st
+ .arena
+ .code_index_tbl
+ .get_entry(offset.into());
self.try_execute(name, arity, index_ptr)
} else {
self.undefined_procedure(name, arity)
self.machine_st
.arena
.code_index_tbl
- .lookup(code_idx.into())
+ .get_entry(code_idx.into())
.local()
})
.unwrap();
self.machine_st
.arena
.code_index_tbl
- .lookup(code_idx.into())
+ .get_entry(code_idx.into())
.local()
})
.unwrap();
self.machine_st
.arena
.code_index_tbl
- .lookup(idx.into())
+ .get_entry(idx.into())
.local()
})
.unwrap();
};
if let Some(code_idx) = index_cell_opt {
- let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(code_idx.into());
+ let index_ptr = self
+ .machine_st
+ .arena
+ .code_index_tbl
+ .get_entry(code_idx.into());
if !index_ptr.is_undefined() {
load_registers(&mut self.machine_st, goal, goal_arity);
self.machine_st
.arena
.code_index_tbl
- .lookup(idx.into())
+ .get_entry(idx.into())
.local()
.is_some()
})
arity,
module_name,
)
- .map(|idx| *self.machine_st
+ .map(|idx| self.machine_st
.arena
.code_index_tbl
- .lookup(idx.into()))
+ .get_entry(idx.into()))
.unwrap_or(IndexPtr::dynamic_undefined());
!matches!(index.tag(), IndexPtrTag::DynamicUndefined | IndexPtrTag::Undefined)
0,
module_name,
)
- .map(|idx| *self.machine_st
+ .map(|idx| self.machine_st
.arena
.code_index_tbl
- .lookup(idx.into()))
+ .get_entry(idx.into()))
.unwrap_or(IndexPtr::dynamic_undefined());
!matches!(index.tag(), IndexPtrTag::DynamicUndefined)
self.machine_st
.arena
.code_index_tbl
- .lookup(first_idx.into())
+ .get_entry(first_idx.into())
.local()
});
(HeapCellValueTag::F64Offset, f2) => {
let machine_st = self.deref_mut();
- let f1 = *machine_st.arena.f64_tbl.lookup(f1);
- let f2 = *machine_st.arena.f64_tbl.lookup(f2.into());
+ let f1 = machine_st.arena.f64_tbl.get_entry(f1);
+ let f2 = machine_st.arena.f64_tbl.get_entry(f2.into());
- self.fail = *f1 != *f2;
+ self.fail = f1 != f2;
}
_ => {
self.fail = true;
use std::cell::UnsafeCell;
-use std::hash::{Hash, Hasher};
-use std::ops::{Deref, DerefMut};
-use std::sync::{Arc, RwLock, RwLockReadGuard};
+use std::sync::Arc;
use std::{fmt, mem, ptr};
use arcu::atomic::Arcu;
use arcu::epoch_counters::GlobalEpochCounterPool;
use arcu::rcu_ref::RcuRef;
use arcu::Rcu;
+use parking_lot::RwLock;
use crate::machine::machine_indices::IndexPtr;
use crate::raw_block::RawBlock;
}
}
-impl<T: RawBlockTraits> OffsetTableImpl<T> {
+impl<T: fmt::Debug + RawBlockTraits> OffsetTableImpl<T> {
#[inline(always)]
pub fn new() -> Self {
Self(InnerOffsetTableImpl::Serial(SerialOffsetTable::new()))
};
let serial_tbl = mem::replace(serial_tbl, empty_serial_tbl);
+ let num_tbl_entries = serial_tbl.block.size() / size_of::<T>();
let block = Arcu::new(serial_tbl.block, GlobalEpochCounterPool);
- let growth_lock = RwLock::new(());
- let concurrent_tbl = Arc::new(ConcurrentOffsetTable { block, growth_lock });
+ let offset_locks: Vec<RwLock<()>> =
+ (0..num_tbl_entries).map(|_| RwLock::new(())).collect();
+
+ let concurrent_tbl = Arc::new(ConcurrentOffsetTable {
+ block,
+ growth_lock: RwLock::new(()),
+ offset_locks: RwLock::new(offset_locks),
+ });
self.0 = InnerOffsetTableImpl::Concurrent(concurrent_tbl.clone());
match &mut self.0 {
InnerOffsetTableImpl::Serial(_serial_tbl) => Ok(()),
InnerOffsetTableImpl::Concurrent(concurrent_tbl) => {
- let lock_guard = concurrent_tbl.growth_lock.write().unwrap();
- let raw_block = concurrent_tbl.block.replace(RawBlock::empty_block());
-
- match Arc::try_unwrap(raw_block) {
- Ok(block) => {
- drop(lock_guard);
- self.0 = InnerOffsetTableImpl::Serial(SerialOffsetTable { block });
+ let table_arc = std::mem::replace(
+ concurrent_tbl,
+ Arc::new(ConcurrentOffsetTable {
+ block: Arcu::new(RawBlock::empty_block(), GlobalEpochCounterPool),
+ growth_lock: RwLock::new(()),
+ offset_locks: RwLock::new(vec![]),
+ }),
+ );
+
+ match Arc::try_unwrap(table_arc) {
+ Ok(table) => {
+ // this was the only instance of the concurrent table, as such
+ // at this point no build_with/with_entry{_mut} call can be in-progress/made
+
+ // this shouldn't be able to fail
+ let raw_block =
+ Arc::try_unwrap(table.block.replace(RawBlock::empty_block())).unwrap();
+ self.0 =
+ InnerOffsetTableImpl::Serial(SerialOffsetTable { block: raw_block });
Ok(())
}
- Err(_) => Err(()),
+ Err(table_arc) => {
+ // restore the concurrent_tbl
+ *concurrent_tbl = table_arc;
+ Err(())
+ }
}
}
}
}
+
+ #[inline]
+ pub fn get_entry(&self, offset: <Self as OffsetTable<T>>::Offset) -> T
+ where
+ Self: OffsetTable<T>,
+ T: Copy,
+ {
+ self.with_entry(offset, |value| *value)
+ }
}
-impl<T: RawBlockTraits> Default for OffsetTableImpl<T> {
+impl<T: fmt::Debug + RawBlockTraits> Default for OffsetTableImpl<T> {
fn default() -> Self {
Self::new()
}
pub struct ConcurrentOffsetTable<T: RawBlockTraits> {
block: Arcu<RawBlock<T>, GlobalEpochCounterPool>,
growth_lock: RwLock<()>,
+ offset_locks: RwLock<Vec<RwLock<()>>>,
}
#[derive(Debug)]
#[inline(always)]
fn build_with(&mut self, value: T) -> usize {
match self {
- Self::Concurrent(concurrent_tbl) => unsafe { concurrent_tbl.build_with(value) },
+ Self::Concurrent(concurrent_tbl) => concurrent_tbl.build_with(value),
Self::Serial(serial_tbl) => unsafe { serial_tbl.build_with(value) },
}
}
#[inline(always)]
- fn lookup<'a>(&'a self, offset: usize) -> TablePtr<'a, T> {
+ fn with_entry<R, F: FnOnce(&T) -> R>(&self, offset: usize, f: F) -> R {
match self {
- Self::Concurrent(concurrent_tbl) => TablePtr({
- let (rcu_ref, guard_lock) = concurrent_tbl.lookup(offset);
- InnerTablePtr::Concurrent {
- rcu_ref,
- guard_lock,
- }
- }),
- Self::Serial(serial_tbl) => unsafe {
- TablePtr(InnerTablePtr::Serial(serial_tbl.lookup(offset)))
- },
+ Self::Concurrent(concurrent_tbl) => concurrent_tbl.with_entry(offset, f),
+ Self::Serial(serial_tbl) => f(unsafe { serial_tbl.lookup(offset) }),
}
}
#[inline(always)]
- fn lookup_mut<'a>(&'a mut self, offset: usize) -> TablePtrMut<'a, T> {
+ fn with_entry_mut<R, F: FnOnce(&mut T) -> R>(&mut self, offset: usize, f: F) -> R {
match self {
- InnerOffsetTableImpl::Concurrent(concurrent_tbl) => TablePtrMut({
- let (rcu_ref, guard_lock) = concurrent_tbl.lookup_mut(offset);
- InnerTablePtrMut::Concurrent {
- rcu_ref,
- guard_lock,
- }
- }),
- InnerOffsetTableImpl::Serial(serial_tbl) => {
- TablePtrMut(InnerTablePtrMut::Serial(unsafe {
- serial_tbl.lookup_mut(offset)
- }))
- }
+ Self::Concurrent(concurrent_tbl) => concurrent_tbl.with_entry_mut(offset, f),
+ Self::Serial(serial_tbl) => f(unsafe { serial_tbl.lookup_mut(offset) }),
}
}
}
type Offset: Copy + Into<usize>;
fn build_with(&mut self, value: T) -> Self::Offset;
- fn lookup<'a>(&'a self, offset: Self::Offset) -> TablePtr<'a, T>;
- fn lookup_mut<'a>(&'a mut self, offset: Self::Offset) -> TablePtrMut<'a, T>;
+
+ fn with_entry<R, F: FnOnce(&T) -> R>(&self, offset: Self::Offset, f: F) -> R;
+ fn with_entry_mut<R, F: FnOnce(&mut T) -> R>(&mut self, offset: Self::Offset, f: F) -> R;
}
impl OffsetTable<OrderedFloat<f64>> for OffsetTableImpl<OrderedFloat<f64>> {
F64Offset(self.0.build_with(value))
}
- fn lookup<'a>(&'a self, offset: F64Offset) -> TablePtr<'a, OrderedFloat<f64>> {
- self.0.lookup(offset.into())
+ #[inline]
+ fn with_entry<R, F: FnOnce(&OrderedFloat<f64>) -> R>(&self, offset: F64Offset, f: F) -> R {
+ self.0.with_entry(offset.into(), f)
}
- fn lookup_mut<'a>(&'a mut self, offset: F64Offset) -> TablePtrMut<'a, OrderedFloat<f64>> {
- self.0.lookup_mut(offset.into())
+ #[inline]
+ fn with_entry_mut<R, F: FnOnce(&mut OrderedFloat<f64>) -> R>(
+ &mut self,
+ offset: F64Offset,
+ f: F,
+ ) -> R {
+ self.0.with_entry_mut(offset.into(), f)
}
}
CodeIndexOffset(self.0.build_with(value))
}
- fn lookup<'a>(&'a self, offset: CodeIndexOffset) -> TablePtr<'a, IndexPtr> {
- self.0.lookup(offset.into())
+ #[inline]
+ fn with_entry<R, F: FnOnce(&IndexPtr) -> R>(&self, offset: CodeIndexOffset, f: F) -> R {
+ self.0.with_entry(offset.into(), f)
}
- fn lookup_mut<'a>(&'a mut self, offset: CodeIndexOffset) -> TablePtrMut<'a, IndexPtr> {
- self.0.lookup_mut(offset.into())
+ #[inline]
+ fn with_entry_mut<R, F: FnOnce(&mut IndexPtr) -> R>(
+ &mut self,
+ offset: CodeIndexOffset,
+ f: F,
+ ) -> R {
+ self.0.with_entry_mut(offset.into(), f)
}
}
impl<T: RawBlockTraits> ConcurrentOffsetTable<T> {
#[allow(clippy::missing_safety_doc)]
- unsafe fn build_with(&self, value: T) -> usize {
- let update_guard = self.growth_lock.write().unwrap();
+ fn build_with(&self, value: T) -> usize {
+ let growth_lock = self.growth_lock.write();
// 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 ptr;
loop {
- ptr = block_epoch.alloc(mem::size_of::<T>());
+ ptr = unsafe { block_epoch.alloc(mem::size_of::<T>()) };
if ptr.is_null() {
- let new_block = block_epoch.grow_new().unwrap();
+ let new_block = unsafe { block_epoch.grow_new().unwrap() };
self.block.replace(new_block);
block_epoch = self.block.read();
} else {
}
}
- ptr::write(ptr as *mut T, value);
+ let new_tbl_sz = block_epoch.size() / size_of::<T>();
+ let mut offset_locks = self.offset_locks.write();
+
+ offset_locks.resize_with(new_tbl_sz, || RwLock::new(()));
+
+ unsafe {
+ ptr::write(ptr as *mut T, value);
+ }
let value = ptr.addr() - block_epoch.base.addr();
// 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);
+ drop(offset_locks);
+ drop(growth_lock);
value
}
- #[inline]
- fn lookup<'a>(&'a self, offset: usize) -> (RcuRef<RawBlock<T>, T>, RwLockReadGuard<'a, ()>) {
- let growth_lock_guard = self.growth_lock.read().unwrap();
+ fn with_entry<R, F: FnOnce(&T) -> R>(&self, offset: usize, f: F) -> R {
+ let outer_offset_lock = self.offset_locks.read();
+ let inner_offset_lock = outer_offset_lock[offset / size_of::<T>()].read();
let rcu_ref = RcuRef::try_map(self.block.read(), |raw_block| unsafe {
raw_block.base.add(offset).cast::<T>().as_ref()
})
- .expect("The offset should result in a non-null pointer");
+ .expect("offset valid");
- (rcu_ref, growth_lock_guard)
+ let result = f(&*rcu_ref);
+
+ drop(inner_offset_lock);
+ drop(outer_offset_lock);
+
+ result
}
- #[inline]
- fn lookup_mut<'a>(
- &'a self,
- offset: usize,
- ) -> (RcuRef<RawBlock<T>, UnsafeCell<T>>, RwLockReadGuard<'a, ()>) {
- let growth_lock_guard = self.growth_lock.read().unwrap();
+ fn with_entry_mut<R, F: FnOnce(&mut T) -> R>(&self, offset: usize, f: F) -> R {
+ let growth_lock = self.growth_lock.read();
+ let outer_offset_lock = self.offset_locks.read();
+ let inner_offset_lock = outer_offset_lock[offset / size_of::<T>()].write();
let rcu_ref = RcuRef::try_map(self.block.read(), |raw_block| unsafe {
raw_block
.cast::<UnsafeCell<T>>()
.as_ref()
})
- .expect("The offset should result in a non-null pointer");
+ .expect("offset valid");
- (rcu_ref, growth_lock_guard)
+ let result = f(unsafe { &mut *rcu_ref.get().as_mut().unwrap() });
+
+ drop(inner_offset_lock);
+ drop(outer_offset_lock);
+ drop(growth_lock);
+
+ result
}
}
}
}
-#[derive(Debug)]
-pub struct TablePtr<'a, T: RawBlockTraits>(InnerTablePtr<'a, T>);
-
-#[derive(Debug)]
-enum InnerTablePtr<'a, T: RawBlockTraits> {
- Concurrent {
- rcu_ref: RcuRef<RawBlock<T>, T>,
- #[allow(dead_code)]
- guard_lock: RwLockReadGuard<'a, ()>,
- },
- Serial(&'a T),
-}
-
-impl<T: PartialEq + RawBlockTraits> PartialEq for TablePtr<'_, T> {
- fn eq(&self, other: &TablePtr<'_, T>) -> bool {
- self.deref() == other.deref()
- }
-}
-
-impl<T: Eq + RawBlockTraits> Eq for TablePtr<'_, T> {}
-
-impl<T: PartialOrd + Ord + RawBlockTraits> PartialOrd for TablePtr<'_, T> {
- fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
- Some(self.cmp(other))
- }
-}
-
-impl<T: Ord + RawBlockTraits> Ord for TablePtr<'_, T> {
- fn cmp(&self, other: &Self) -> std::cmp::Ordering {
- (**self).cmp(&**other)
- }
-}
-
-impl<T: Hash + RawBlockTraits> Hash for TablePtr<'_, T> {
- #[inline(always)]
- fn hash<H: Hasher>(&self, hasher: &mut H) {
- (self as &T).hash(hasher)
- }
-}
-
-impl<T: fmt::Display + RawBlockTraits> fmt::Display for TablePtr<'_, T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", self as &T)
- }
-}
-
-impl<T: RawBlockTraits> Deref for TablePtr<'_, T> {
- type Target = T;
-
- #[inline]
- fn deref(&self) -> &Self::Target {
- match &self.0 {
- InnerTablePtr::Concurrent { rcu_ref, .. } => rcu_ref,
- InnerTablePtr::Serial(ref_mut) => ref_mut,
- }
- }
-}
-
impl fmt::Display for CodeIndexOffset {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "CodeIndexOffset({})", self.0)
write!(f, "F64Offset({})", self.0)
}
}
-
-#[derive(Debug)]
-pub struct TablePtrMut<'a, T: RawBlockTraits>(InnerTablePtrMut<'a, T>);
-
-#[derive(Debug)]
-enum InnerTablePtrMut<'a, T: RawBlockTraits> {
- Concurrent {
- rcu_ref: RcuRef<RawBlock<T>, UnsafeCell<T>>,
- #[allow(dead_code)]
- guard_lock: RwLockReadGuard<'a, ()>,
- },
- Serial(&'a mut T),
-}
-
-impl<T: PartialEq + RawBlockTraits> PartialEq for TablePtrMut<'_, T> {
- fn eq(&self, other: &TablePtrMut<'_, T>) -> bool {
- self.deref() == other.deref()
- }
-}
-
-impl<T: Eq + RawBlockTraits> Eq for TablePtrMut<'_, T> {}
-
-impl<T: PartialOrd + Ord + RawBlockTraits> PartialOrd for TablePtrMut<'_, T> {
- fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
- Some(self.cmp(other))
- }
-}
-
-impl<T: Ord + RawBlockTraits> Ord for TablePtrMut<'_, T> {
- fn cmp(&self, other: &Self) -> std::cmp::Ordering {
- (**self).cmp(&**other)
- }
-}
-
-impl<T: Hash + RawBlockTraits> Hash for TablePtrMut<'_, T> {
- #[inline(always)]
- fn hash<H: Hasher>(&self, hasher: &mut H) {
- (self as &T).hash(hasher)
- }
-}
-
-impl<T: fmt::Display + RawBlockTraits> fmt::Display for TablePtrMut<'_, T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", self as &T)
- }
-}
-
-impl<T: RawBlockTraits> Deref for TablePtrMut<'_, T> {
- type Target = T;
-
- #[inline]
- fn deref(&self) -> &Self::Target {
- match &self.0 {
- InnerTablePtrMut::Concurrent { rcu_ref, .. } => unsafe {
- rcu_ref.get().as_ref().unwrap()
- },
- InnerTablePtrMut::Serial(ref_mut) => ref_mut,
- }
- }
-}
-
-impl<T: RawBlockTraits> DerefMut for TablePtrMut<'_, T> {
- #[inline]
- fn deref_mut(&mut self) -> &mut Self::Target {
- match &mut self.0 {
- InnerTablePtrMut::Concurrent { rcu_ref, .. } => unsafe {
- &mut *rcu_ref.get().as_mut().unwrap()
- },
- InnerTablePtrMut::Serial(ref_mut) => ref_mut,
- }
- }
-}
-
-impl TablePtrMut<'_, IndexPtr> {
- #[inline]
- pub fn set(&mut self, val: IndexPtr) {
- match &mut self.0 {
- InnerTablePtrMut::Concurrent { rcu_ref, .. } => unsafe {
- *rcu_ref.get() = val;
- },
- InnerTablePtrMut::Serial(ref_mut) => {
- **ref_mut = val;
- }
- }
- }
-
- #[inline]
- pub fn replace(&mut self, val: IndexPtr) -> IndexPtr {
- match &mut self.0 {
- InnerTablePtrMut::Concurrent { rcu_ref, .. } => unsafe { rcu_ref.get().replace(val) },
- InnerTablePtrMut::Serial(ref_mut) => mem::replace(*ref_mut, val),
- }
- }
-}
Token::Literal(Literal::Rational(n)) => {
self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r))
}
- Token::Literal(Literal::F64Offset(n)) if self.lexer.machine_st.arena.f64_tbl.lookup(n).is_infinite() => {
+ Token::Literal(Literal::F64Offset(n)) if self.lexer.machine_st.arena.f64_tbl.get_entry(n).is_infinite() => {
return Err(ParserError::InfiniteFloat(
self.lexer.line_num,
self.lexer.col_num,
));
}
Token::Literal(Literal::F64Offset(n)) => {
- let n = *self.lexer.machine_st.arena.f64_tbl.lookup(n);
+ let n = self.lexer.machine_st.arena.f64_tbl.get_entry(n);
self.negate_number(
n,