1use std::cell::Cell;
12use std::rc::{Rc, Weak};
13
14use super::object::InternalData;
15use super::{Heap, HeapError};
16use crate::value::{Kind, ObjectId, Value};
17
18const VACANT: u32 = 0;
20const DELETED: u32 = u32::MAX;
22
23#[derive(Debug)]
25pub struct Table {
26 width: usize,
27 index: Vec<u32>,
29 hashes: Vec<u32>,
31 live: usize,
32 cursors: Vec<Weak<Cell<u32>>>,
33}
34
35impl Table {
36 pub fn new(width: usize) -> Self {
37 Table {
38 width,
39 index: Vec::new(),
40 hashes: Vec::new(),
41 live: 0,
42 cursors: Vec::new(),
43 }
44 }
45
46 pub fn len(&self) -> usize {
47 self.live
48 }
49
50 pub fn is_empty(&self) -> bool {
51 self.live == 0
52 }
53
54 pub fn width(&self) -> usize {
55 self.width
56 }
57
58 pub fn is_zombie(&self, entry: usize) -> bool {
62 self.cursors.iter().any(|cursor| {
63 cursor
64 .upgrade()
65 .is_some_and(|cursor| cursor.get() as usize == entry + 1)
66 })
67 }
68
69 pub fn entries(&self) -> usize {
71 self.hashes.len()
72 }
73
74 pub fn owned_bytes(&self) -> usize {
75 self.index.capacity() * 4 + self.hashes.capacity() * 4 + self.cursors.capacity() * 8
76 }
77
78 fn insert_index(&mut self, hash: u32, entry: usize) {
79 let mask = self.index.len() - 1;
80 let mut bucket = hash as usize & mask;
81 while self.index[bucket] != VACANT && self.index[bucket] != DELETED {
82 bucket = (bucket + 1) & mask;
83 }
84 self.index[bucket] = entry as u32 + 1;
85 }
86
87 fn rebuild(&mut self, entries: usize, slots: &[Value]) {
89 let buckets = (entries * 2).next_power_of_two().max(8);
90 self.index.clear();
91 self.index.resize(buckets, VACANT);
92 for entry in 0..self.hashes.len() {
93 if !slots[entry * self.width].is_empty() {
94 self.insert_index(self.hashes[entry], entry);
95 }
96 }
97 }
98}
99
100pub(crate) fn tombstone(internal: &mut super::object::Internal, entry: usize) {
103 let InternalData::Table(table) = &mut internal.data else {
104 unreachable!("a collection");
105 };
106 let width = table.width;
107 let hash = table.hashes[entry];
108 let mask = table.index.len() - 1;
109 let mut bucket = hash as usize & mask;
110 while table.index[bucket] != entry as u32 + 1 {
111 bucket = (bucket + 1) & mask;
112 }
113 table.index[bucket] = DELETED;
114 table.live -= 1;
115 for slot in &mut internal.slots[entry * width..entry * width + width] {
116 *slot = Value::EMPTY;
117 }
118}
119
120impl Heap {
121 pub(crate) fn table_hash(&self, key: Value) -> u32 {
125 let bits = match key.kind() {
126 Kind::Int32 | Kind::Number => {
127 let number = key.as_f64().unwrap();
128 if number == 0.0 {
129 0
130 } else if number.is_nan() {
131 0x7FF8_0000_0000_0000
132 } else {
133 number.to_bits()
134 }
135 }
136 Kind::String => return self.string(key.as_string().unwrap()).hash(),
137 Kind::BigInt => {
138 let record = self.bigint(key.as_bigint().unwrap());
139 let mut hash = u64::from(record.negative);
140 for &limb in record.limbs.iter() {
141 hash = hash.rotate_left(5) ^ limb;
142 }
143 hash
144 }
145 _ => key.bits(),
146 };
147 let mixed = bits.wrapping_mul(0x9E37_79B9_7F4A_7C15);
148 (mixed >> 32) as u32 ^ mixed as u32
149 }
150
151 pub(crate) fn table(&self, object: ObjectId) -> &Table {
152 match &self.internal(object).data {
153 InternalData::Table(table) => table,
154 _ => unreachable!("a collection"),
155 }
156 }
157
158 fn table_mut(&mut self, object: ObjectId) -> &mut Table {
159 match &mut self.internal_mut(object).data {
160 InternalData::Table(table) => table,
161 _ => unreachable!("a collection"),
162 }
163 }
164
165 pub(crate) fn table_find(&self, object: ObjectId, key: Value) -> Option<usize> {
167 let table = self.table(object);
168 if table.live == 0 {
169 return None;
170 }
171 let hash = self.table_hash(key);
172 let slots = &self.internal(object).slots;
173 let mask = table.index.len() - 1;
174 let mut bucket = hash as usize & mask;
175 loop {
176 match table.index[bucket] {
177 VACANT => return None,
178 DELETED => {}
179 entry => {
180 let entry = entry as usize - 1;
181 if table.hashes[entry] == hash
182 && crate::vm::ops::same_value_zero_heap(
183 self,
184 slots[entry * table.width],
185 key,
186 )
187 {
188 return Some(entry);
189 }
190 }
191 }
192 bucket = (bucket + 1) & mask;
193 }
194 }
195
196 pub(crate) fn table_get(&self, object: ObjectId, key: Value) -> Option<Value> {
198 let entry = self.table_find(object, key)?;
199 let width = self.table(object).width;
200 Some(self.internal(object).slots[entry * width + width - 1])
201 }
202
203 pub(crate) fn table_set(
206 &mut self,
207 object: ObjectId,
208 key: Value,
209 value: Value,
210 ) -> Result<(), HeapError> {
211 let key = if key.as_f64() == Some(0.0) {
212 Value::int32(0)
213 } else {
214 key
215 };
216 let width = self.table(object).width;
217 if let Some(entry) = self.table_find(object, key) {
218 if width == 2 {
219 self.internal_mut(object).slots[entry * 2 + 1] = value;
220 }
221 return Ok(());
222 }
223 let hash = self.table_hash(key);
224 self.reserve_internal_slots(object, width, &[key, value])?;
225 let internal = self.internal_mut(object);
226 internal.slots.push(key);
227 if width == 2 {
228 internal.slots.push(value);
229 }
230 let InternalData::Table(table) = &mut internal.data else {
231 unreachable!("a collection");
232 };
233 let entry = table.hashes.len();
234 table.hashes.push(hash);
235 table.live += 1;
236 if (entry + 1) * 2 > table.index.len() {
238 let entries = table.live.max(entry + 1);
239 table.rebuild(entries, &internal.slots);
240 } else {
241 table.insert_index(hash, entry);
242 }
243 Ok(())
244 }
245
246 pub(crate) fn table_delete(&mut self, object: ObjectId, key: Value) -> bool {
248 let Some(entry) = self.table_find(object, key) else {
249 return false;
250 };
251 self.table_delete_entry(object, entry);
252 true
253 }
254
255 pub(crate) fn table_delete_entry(&mut self, object: ObjectId, entry: usize) {
257 let internal = self.internal_mut(object);
258 let InternalData::Table(table) = &mut internal.data else {
259 unreachable!("a collection");
260 };
261 let width = table.width;
262 let hash = table.hashes[entry];
263 let mask = table.index.len() - 1;
264 let mut bucket = hash as usize & mask;
265 while table.index[bucket] != entry as u32 + 1 {
266 bucket = (bucket + 1) & mask;
267 }
268 table.index[bucket] = DELETED;
269 table.live -= 1;
270 for slot in &mut internal.slots[entry * width..entry * width + width] {
271 *slot = Value::EMPTY;
272 }
273 if table.hashes.len() >= 16 && table.live * 2 < table.hashes.len() {
274 self.table_compact(object);
275 }
276 }
277
278 pub(crate) fn table_clear(&mut self, object: ObjectId) {
280 let internal = self.internal_mut(object);
281 internal.slots.fill(Value::EMPTY);
282 self.table_compact(object);
283 }
284
285 fn table_compact(&mut self, object: ObjectId) {
288 let internal = self.internal_mut(object);
289 let InternalData::Table(table) = &mut internal.data else {
290 unreachable!("a collection");
291 };
292 let width = table.width;
293 let entries = table.hashes.len();
294 let mut before = Vec::with_capacity(entries + 1);
296 let mut kept = 0u32;
297 let mut write = 0;
298 for entry in 0..entries {
299 before.push(kept);
300 if !internal.slots[entry * width].is_empty() {
301 for offset in 0..width {
302 internal.slots[write * width + offset] = internal.slots[entry * width + offset];
303 }
304 table.hashes[write] = table.hashes[entry];
305 write += 1;
306 kept += 1;
307 }
308 }
309 before.push(kept);
310 internal.slots.truncate(write * width);
311 table.hashes.truncate(write);
312 table.cursors.retain(|cursor| match cursor.upgrade() {
313 Some(cursor) => {
314 let at = (cursor.get() as usize).min(entries);
315 cursor.set(before[at]);
316 true
317 }
318 None => false,
319 });
320 table.live = write;
321 table.rebuild(write, &internal.slots);
322 }
323
324 pub(crate) fn table_cursor(&mut self, object: ObjectId) -> Rc<Cell<u32>> {
326 let cursor = Rc::new(Cell::new(0));
327 let table = self.table_mut(object);
328 table.cursors.retain(|cursor| cursor.strong_count() > 0);
329 table.cursors.push(Rc::downgrade(&cursor));
330 cursor
331 }
332
333 pub(crate) fn table_next(
336 &self,
337 object: ObjectId,
338 cursor: &Cell<u32>,
339 ) -> Option<(Value, Value)> {
340 let table = self.table(object);
341 let slots = &self.internal(object).slots;
342 let width = table.width;
343 let mut entry = cursor.get() as usize;
344 while entry < table.hashes.len() {
345 let key = slots[entry * width];
346 entry += 1;
347 if !key.is_empty() {
348 cursor.set(entry as u32);
349 return Some((key, slots[entry * width - 1]));
350 }
351 }
352 cursor.set(entry as u32);
353 None
354 }
355
356 pub(crate) fn reserve_internal_slots(
359 &mut self,
360 object: ObjectId,
361 additional: usize,
362 keep: &[Value],
363 ) -> Result<(), HeapError> {
364 let internal = self.internal(object);
365 if internal.slots.capacity() - internal.slots.len() >= additional {
366 return Ok(());
367 }
368 let extra = internal.slots.capacity().max(4) * 8;
369 let mut kept = Vec::with_capacity(keep.len() + 1);
370 kept.push(Value::object(object));
371 kept.extend_from_slice(keep);
372 self.safepoint(
373 &super::Need {
374 extra,
375 ..Default::default()
376 },
377 &kept,
378 )?;
379 let internal = self.internal_mut(object);
380 let grow = internal.slots.capacity().max(4).max(additional);
381 internal.slots.reserve(grow);
382 Ok(())
383 }
384}