diff --git a/Cargo.lock b/Cargo.lock index 162bdb8d..8d1ca58a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -373,12 +373,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "bitmaps" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703642b98a00b3b90513279a8ede3fcfa479c126c5fb46e78f3051522f021403" - [[package]] name = "blake2" version = "0.9.2" @@ -1518,10 +1512,10 @@ version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" dependencies = [ - "bitmaps 2.1.0", + "bitmaps", "rand_core", "rand_xoshiro", - "sized-chunks 0.6.5", + "sized-chunks", "typenum", "version_check", ] @@ -1937,7 +1931,6 @@ dependencies = [ "rand", "serde", "serde_json", - "sized-chunks 0.7.0", "strum", "tempfile", "thiserror", @@ -1976,7 +1969,6 @@ dependencies = [ "pretty_assertions", "pwhash", "rand", - "sized-chunks 0.7.0", "strum", "tempfile", "test-case", @@ -3046,19 +3038,10 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" dependencies = [ - "bitmaps 2.1.0", + "bitmaps", "typenum", ] -[[package]] -name = "sized-chunks" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718af0c70466d1901d87da3fa23e38a955cd0dec64af16bc49cf2d901ec0e5e7" -dependencies = [ - "bitmaps 3.2.0", -] - [[package]] name = "sketches-ddsketch" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 9810f833..8b9a647b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,7 +68,6 @@ itertools = "0.12.0" lazy_static = "1.4.0" num-traits = "0.2.17" rustyline = "13.0.0" -sized-chunks = "0.7.0" strum = { version = "0.25.0", features = ["derive"] } uuid = { version = "1.6.1", features = ["v4"] } yoke = "0.7.3" diff --git a/crates/db/Cargo.toml b/crates/db/Cargo.toml index 4550b387..819db8c9 100644 --- a/crates/db/Cargo.toml +++ b/crates/db/Cargo.toml @@ -43,7 +43,6 @@ metrics-macros.workspace = true # For the DB layer. bincode.workspace = true im.workspace = true -sized-chunks.workspace = true binary-layout.workspace = true libc.workspace = true atomic-wait.workspace = true diff --git a/crates/db/src/tuplebox/tuples/slotbox.rs b/crates/db/src/tuplebox/tuples/slotbox.rs index 7c2dc832..043a6527 100644 --- a/crates/db/src/tuplebox/tuples/slotbox.rs +++ b/crates/db/src/tuplebox/tuples/slotbox.rs @@ -189,7 +189,7 @@ impl SlotBox { pub fn num_pages(&self) -> usize { let mut inner = self.inner.lock().unwrap(); - inner.available_page_space.size() + inner.available_page_space.len() } pub fn used_pages(&self) -> Vec { diff --git a/crates/kernel/Cargo.toml b/crates/kernel/Cargo.toml index 7275bf98..341d5580 100644 --- a/crates/kernel/Cargo.toml +++ b/crates/kernel/Cargo.toml @@ -35,10 +35,9 @@ async-trait.workspace = true decorum.workspace = true text_io.workspace = true bytes.workspace = true -strum.workspace = true +strum.worksspace = true uuid.workspace = true chrono.workspace = true -sized-chunks.workspace = true ## Required for MOO builtins. pwhash.workspace = true diff --git a/crates/kernel/src/vm/activation.rs b/crates/kernel/src/vm/activation.rs index 30a642d5..75eba37e 100644 --- a/crates/kernel/src/vm/activation.rs +++ b/crates/kernel/src/vm/activation.rs @@ -13,8 +13,6 @@ // use moor_values::NOTHING; -use sized_chunks::SparseChunk; -use tracing::trace; use uuid::Uuid; use moor_compiler::GlobalName; @@ -36,6 +34,7 @@ use crate::tasks::TaskId; use crate::vm::VerbExecutionRequest; use moor_compiler::labels::{Label, Name}; use moor_compiler::opcode::{Op, Program, EMPTY_PROGRAM}; +use moor_values::util::{BitArray, Bitset32}; // {this, verb-name, programmer, verb-loc, player, line-number} #[derive(Clone)] @@ -92,7 +91,7 @@ pub(crate) struct Activation { /// and caller_perms() returns the value of this in the *parent* stack frame (or #-1 if none) pub(crate) permissions: Objid, /// The values of the variables currently in scope, by their offset. - pub(crate) environment: SparseChunk, + pub(crate) environment: BitArray>, /// The value stack. pub(crate) valstack: Vec, /// A stack of active error handlers, each relative to a position in the valstack. @@ -126,7 +125,7 @@ fn set_constants(a: &mut Activation) { impl Activation { pub fn for_call(task_id: TaskId, verb_call_request: VerbExecutionRequest) -> Self { let program = verb_call_request.program; - let environment = SparseChunk::new(); + let environment = BitArray::new(); let verb_owner = verb_call_request.resolved_verb.verbdef().owner(); let mut a = Self { @@ -183,7 +182,7 @@ impl Activation { } pub fn for_eval(task_id: TaskId, permissions: Objid, player: Objid, program: Program) -> Self { - let environment = SparseChunk::new(); + let environment = BitArray::new(); let verb_info = VerbInfo::new( // Fake verbdef. Not sure how I feel about this. Similar to with BF calls. @@ -256,11 +255,10 @@ impl Activation { SliceRef::empty(), ); - trace!(bf_name, bf_index, ?args, "for_bf_call"); Self { task_id, program: EMPTY_PROGRAM.clone(), - environment: SparseChunk::new(), + environment: BitArray::new(), valstack: vec![], handler_stack: vec![], pc: 0, @@ -306,18 +304,21 @@ impl Activation { self.verb_info.verbdef().owner() } + #[inline] pub fn set_gvar(&mut self, gname: GlobalName, value: Var) { - self.environment.insert(gname as usize, value); + self.environment.set(gname as usize, value); } + #[inline] pub fn set_var_offset(&mut self, offset: Name, value: Var) -> Result<(), Error> { if offset.0 as usize >= self.environment.len() { return Err(E_VARNF); } - self.environment[offset.0 as usize] = value; + self.environment.set(offset.0 as usize, value); Ok(()) } + #[inline] pub fn next_op(&mut self) -> Option { if !self.pc < self.program.main_vector.len() { return None; @@ -327,22 +328,43 @@ impl Activation { Some(op) } + #[inline] pub fn lookahead(&self) -> Option { self.program.main_vector.get(self.pc).cloned() } + #[inline] pub fn skip(&mut self) { self.pc += 1; } + #[inline] pub fn pop(&mut self) -> Option { self.valstack.pop() } + #[inline] pub fn push(&mut self, v: Var) { self.valstack.push(v) } + #[inline] + pub fn peek_top(&self) -> Option { + self.valstack.last().cloned() + } + + #[inline] + pub fn peek(&self, width: usize) -> Vec { + let l = self.valstack.len(); + Vec::from(&self.valstack[l - width..]) + } + + #[inline] + pub fn jump(&mut self, label_id: Label) { + let label = &self.program.jump_labels[label_id.0 as usize]; + self.pc = label.position.0; + } + pub fn push_handler_label(&mut self, handler_type: HandlerType) { self.handler_stack.push(HandlerLabel { handler_type, @@ -359,19 +381,4 @@ impl Activation { } self.handler_stack.pop() } - - pub fn peek_top(&self) -> Option { - self.valstack.last().cloned() - } - - pub fn peek(&self, width: usize) -> Vec { - let l = self.valstack.len(); - Vec::from(&self.valstack[l - width..]) - } - - pub fn jump(&mut self, label_id: Label) { - let label = &self.program.jump_labels[label_id.0 as usize]; - trace!("Jump to {}", label.position.0); - self.pc = label.position.0; - } } diff --git a/crates/kernel/src/vm/exec_state.rs b/crates/kernel/src/vm/exec_state.rs index b7f27c9d..f59b3425 100644 --- a/crates/kernel/src/vm/exec_state.rs +++ b/crates/kernel/src/vm/exec_state.rs @@ -80,10 +80,12 @@ impl VMExecState { callers } + #[inline] pub(crate) fn top_mut(&mut self) -> &mut Activation { self.stack.last_mut().expect("activation stack underflow") } + #[inline] pub(crate) fn top(&self) -> &Activation { self.stack.last().expect("activation stack underflow") } @@ -132,6 +134,7 @@ impl VMExecState { } /// Pop a value off the value stack. + #[inline] pub(crate) fn pop(&mut self) -> Var { self.top_mut().pop().unwrap_or_else(|| { panic!( @@ -143,37 +146,44 @@ impl VMExecState { } /// Push a value onto the value stack + #[inline] pub(crate) fn push(&mut self, v: &Var) { self.top_mut().push(v.clone()) } /// Non-destructively peek in the value stack at the given offset. + #[inline] pub(crate) fn peek(&self, amt: usize) -> Vec { self.top().peek(amt) } /// Return the top of the value stack. + #[inline] pub(crate) fn peek_top(&self) -> Var { self.top().peek_top().expect("stack underflow") } /// Return the next opcode in the program stream. + #[inline] pub(crate) fn next_op(&mut self) -> Option { self.top_mut().next_op() } /// Jump to the given label. + #[inline] pub(crate) fn jump(&mut self, label: Label) { self.top_mut().jump(label) } /// Return the value of a local variable. + #[inline] pub(crate) fn get_env(&self, id: Name) -> Option<&Var> { self.top().environment.get(id.0 as usize) } /// Set the value of a local variable. + #[inline] pub(crate) fn set_env(&mut self, id: Name, v: &Var) { - self.top_mut().environment.insert(id.0 as usize, v.clone()); + self.top_mut().environment.set(id.0 as usize, v.clone()); } } diff --git a/crates/kernel/src/vm/vm_execute.rs b/crates/kernel/src/vm/vm_execute.rs index 1659c1ce..5aa13757 100644 --- a/crates/kernel/src/vm/vm_execute.rs +++ b/crates/kernel/src/vm/vm_execute.rs @@ -17,7 +17,6 @@ use std::time::Duration; use tokio::sync::mpsc::UnboundedSender; use moor_compiler::labels::{Name, Offset}; -use tracing::trace; use crate::tasks::command_parse::ParsedCommand; use crate::tasks::sessions::Session; @@ -192,16 +191,6 @@ impl VM { state.tick_count += 1; - trace!( - pc = state.top().pc, - ?op, - this = ?state.top().this, - player = ?state.top().player, - stack = ?state.top().valstack, - tick_count = state.tick_count, - tick_slice, - "exec" - ); match op { Op::If(label) | Op::Eif(label) | Op::IfQues(label) | Op::While(label) => { let cond = state.pop(); @@ -263,13 +252,13 @@ impl VM { } => { // Pull the range ends off the stack. // TODO LambdaMOO had optimization here where it would only peek and update. - // But I had some difficulty getting stack values right, so will do this simpler - // for now and revisit later. + // But I had some difficulty getting stack values right, so will do this simpler + // for now and revisit later. let (to, from) = (&state.pop(), &state.pop()); // TODO: LambdaMOO has special handling for MAXINT/MAXOBJ - // Given we're 64-bit this is highly unlikely to ever be a concern for us, but - // we also don't want to *crash* on obscene values, so impl that here. + // Given we're 64-bit this is highly unlikely to ever be a concern for us, but + // we also don't want to *crash* on obscene values, so impl that here. let next_val = match (to.variant(), from.variant()) { (Variant::Int(to_i), Variant::Int(from_i)) => { diff --git a/crates/values/src/util/bitarray.rs b/crates/values/src/util/bitarray.rs index 2c982dab..07c6f836 100644 --- a/crates/values/src/util/bitarray.rs +++ b/crates/values/src/util/bitarray.rs @@ -13,6 +13,7 @@ // use crate::util::BitsetTrait; +use std::fmt::{Debug, Formatter}; use std::mem::MaybeUninit; use std::ops::Index; @@ -21,7 +22,7 @@ use std::ops::Index; // Until then, don't mess up. pub struct BitArray where - BitsetType: BitsetTrait + std::default::Default, + BitsetType: BitsetTrait + Default, { pub(crate) bitset: BitsetType, storage: Box<[MaybeUninit; RANGE_WIDTH]>, @@ -29,7 +30,7 @@ where impl BitArray where - BitsetType: BitsetTrait + std::default::Default, + BitsetType: BitsetTrait + Default, { pub fn new() -> Self { Self { @@ -162,7 +163,7 @@ where self.bitset.is_empty() } - pub fn size(&mut self) -> usize { + pub fn len(&mut self) -> usize { self.bitset.size() } @@ -208,9 +209,26 @@ where } } +impl PartialEq for BitArray +where + BitsetType: BitsetTrait + Default, + X: PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + self.iter().eq(other.iter()) + } +} + +impl Eq for BitArray +where + BitsetType: BitsetTrait + Default, + X: Eq, +{ +} + impl Default for BitArray where - BitsetType: BitsetTrait + std::default::Default, + BitsetType: BitsetTrait + Default, { fn default() -> Self { Self::new() @@ -219,7 +237,7 @@ where impl Index for BitArray where - BitsetType: BitsetTrait + std::default::Default, + BitsetType: BitsetTrait + Default, { type Output = X; @@ -230,7 +248,7 @@ where impl Drop for BitArray where - BitsetType: BitsetTrait + std::default::Default, + BitsetType: BitsetTrait + Default, { fn drop(&mut self) { for i in 0..RANGE_WIDTH { @@ -242,6 +260,30 @@ where } } +impl Debug for BitArray +where + BitsetType: BitsetTrait + Default, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "BitArray({}) = {{", self.bitset.size()) + } +} + +impl Clone for BitArray +where + BitsetType: BitsetTrait + Default, + X: Clone, +{ + fn clone(&self) -> Self { + let mut new = Self::new(); + for (idx, v) in self.iter() { + let v = v.clone(); + new.set(idx, v); + } + new + } +} + #[cfg(test)] mod test { use crate::util::{BitArray, Bitset16}; @@ -263,7 +305,7 @@ mod test { vec.erase(0); assert_eq!(vec.first_empty(), Some(0)); assert_eq!(vec.last_used_pos(), Some(2)); - assert_eq!(vec.size(), 2); + assert_eq!(vec.len(), 2); vec.set(0, 126); assert_eq!(vec.get(0), Some(&126)); assert_eq!(vec.update(0, 123), Some(126));