1use std::mem;
9use std::time::Duration;
10
11use super::hash::FxHashMap;
12use super::object::{InternalTag, NONE, ObjectKind};
13use super::{Heap, HeapError, Need};
14use crate::shape::STATIC_CELL;
15use crate::value::{Kind, ShapeId, Value};
16use crate::vm::ic::Record;
17
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub struct RootMark(usize);
21
22#[derive(Default)]
25pub struct RootStack {
26 values: Vec<Value>,
27}
28
29impl RootStack {
30 #[inline]
31 pub fn mark(&self) -> RootMark {
32 RootMark(self.values.len())
33 }
34
35 #[inline]
36 pub fn push(&mut self, value: Value) {
37 self.values.push(value);
38 }
39
40 #[inline]
41 pub fn pop_one(&mut self) {
43 self.values.pop();
44 }
45
46 pub fn truncate(&mut self, mark: RootMark) {
47 debug_assert!(mark.0 <= self.values.len(), "root mark above the stack");
48 self.values.truncate(mark.0);
49 }
50
51 #[inline]
52 pub fn get(&self, index: usize) -> Value {
53 self.values[index]
54 }
55
56 #[inline]
57 pub fn set(&mut self, index: usize, value: Value) {
58 self.values[index] = value;
59 }
60
61 pub fn len(&self) -> usize {
62 self.values.len()
63 }
64
65 pub fn is_empty(&self) -> bool {
66 self.values.is_empty()
67 }
68
69 pub fn values(&self) -> &[Value] {
70 &self.values
71 }
72}
73
74#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
76pub struct Handle(u32);
77
78#[derive(Default)]
79pub struct Handles {
80 slots: Vec<Value>,
81 free: Vec<u32>,
82}
83
84impl Handles {
85 pub fn create(&mut self, value: Value) -> Handle {
86 debug_assert!(!value.is_empty(), "EMPTY marks a released handle");
87 if let Some(index) = self.free.pop() {
88 self.slots[index as usize] = value;
89 return Handle(index);
90 }
91 self.slots.push(value);
92 Handle(self.slots.len() as u32 - 1)
93 }
94
95 #[track_caller]
96 pub fn get(&self, handle: Handle) -> Value {
97 let value = self.slots[handle.0 as usize];
98 debug_assert!(!value.is_empty(), "released handle");
99 value
100 }
101
102 pub fn set(&mut self, handle: Handle, value: Value) {
103 debug_assert!(!self.slots[handle.0 as usize].is_empty(), "released handle");
104 self.slots[handle.0 as usize] = value;
105 }
106
107 pub fn release(&mut self, handle: Handle) {
108 let slot = &mut self.slots[handle.0 as usize];
109 assert!(!slot.is_empty(), "handle released twice");
110 *slot = Value::EMPTY;
111 self.free.push(handle.0);
112 }
113
114 pub fn live_count(&self) -> usize {
115 self.slots.len() - self.free.len()
116 }
117
118 pub fn values(&self) -> impl Iterator<Item = Value> + '_ {
119 self.slots.iter().copied().filter(|value| !value.is_empty())
120 }
121}
122
123#[derive(Default)]
126pub struct Roots {
127 pub stack: RootStack,
128 pub handles: Handles,
129 pub fixed: Vec<Value>,
132}
133
134#[derive(Clone, Copy, Debug, PartialEq, Eq)]
135pub struct HeapLimits {
136 pub max_bytes: usize,
138}
139
140impl Default for HeapLimits {
141 fn default() -> Self {
142 HeapLimits {
143 max_bytes: usize::MAX,
144 }
145 }
146}
147
148#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
149pub struct GcStats {
150 pub collections: u64,
151 pub total_pause: Duration,
152 pub max_pause: Duration,
153 pub freed_records: u64,
154 pub freed_bytes: u64,
155 pub live_bytes: usize,
156}
157
158#[derive(Clone, Copy, Debug, PartialEq, Eq)]
163pub struct Room {
164 left: isize,
166 threshold: usize,
168}
169
170impl Room {
171 pub const fn unbounded() -> Room {
173 Room {
174 left: isize::MAX,
175 threshold: usize::MAX,
176 }
177 }
178
179 pub fn new(left: usize, threshold: usize) -> Room {
182 Room {
183 left: left.min(isize::MAX as usize) as isize,
184 threshold,
185 }
186 }
187
188 #[inline]
190 pub fn take(&mut self, bytes: usize) {
191 self.left = self
192 .left
193 .saturating_sub(bytes.min(isize::MAX as usize) as isize);
194 if self.left < 0 {
195 self.threshold = 0;
196 }
197 }
198
199 #[inline]
200 pub fn threshold(&self) -> usize {
201 self.threshold
202 }
203}
204
205pub fn budget_step(reserved: usize) -> usize {
208 (reserved / 4).clamp(64 << 10, 2 << 20)
209}
210
211pub struct GcState {
212 pub(crate) allocated: usize,
214 pub(crate) room: Room,
215 pub(crate) budget: usize,
219 pub min_heap: usize,
220 pub growth_factor: f64,
221 pub limits: HeapLimits,
222 pub(crate) manual: bool,
225 pub stats: GcStats,
226 pub record_pauses: bool,
228 pub pauses: Vec<Duration>,
229 mark_stack: Vec<Value>,
230 shape_stack: Vec<ShapeId>,
231 weak: Vec<u32>,
233 ephemerons: FxHashMap<Value, Vec<Value>>,
236 bytecode_stack: Vec<u32>,
237 #[cfg(feature = "gc-stress")]
238 pub stress: bool,
239 #[cfg(feature = "gc-stress")]
241 pub stress_interval: u32,
242 #[cfg(feature = "gc-stress")]
243 stress_counter: u32,
244}
245
246pub const DEFAULT_MIN_HEAP: usize = 1 << 20;
247
248impl GcState {
249 pub fn new(limits: HeapLimits) -> Self {
250 GcState {
251 allocated: 0,
252 room: Room::new(DEFAULT_MIN_HEAP, DEFAULT_MIN_HEAP),
253 budget: DEFAULT_MIN_HEAP,
254 min_heap: DEFAULT_MIN_HEAP,
255 growth_factor: 2.0,
256 limits,
257 manual: false,
258 stats: GcStats::default(),
259 record_pauses: false,
260 pauses: Vec::new(),
261 mark_stack: Vec::new(),
262 weak: Vec::new(),
263 ephemerons: FxHashMap::default(),
264 shape_stack: Vec::new(),
265 bytecode_stack: Vec::new(),
266 #[cfg(feature = "gc-stress")]
267 stress: true,
268 #[cfg(feature = "gc-stress")]
269 stress_interval: 1,
270 #[cfg(feature = "gc-stress")]
271 stress_counter: 0,
272 }
273 }
274
275 pub fn configure(&mut self, min_heap: usize, growth_factor: f64, reserved: usize) {
279 self.min_heap = min_heap;
280 self.growth_factor = growth_factor;
281 self.budget = min_heap;
282 self.room = Room::new(min_heap.saturating_sub(reserved), min_heap);
283 }
284
285 pub fn threshold(&self) -> usize {
287 self.room.threshold
288 }
289
290 pub fn budget(&self) -> usize {
292 self.budget
293 }
294
295 pub fn is_manual(&self) -> bool {
296 self.manual
297 }
298
299 #[inline]
302 fn always_slow(&self) -> bool {
303 #[cfg(feature = "gc-stress")]
304 if self.stress {
305 return true;
306 }
307 self.limits.max_bytes != usize::MAX
308 }
309
310 #[cfg(feature = "gc-stress")]
311 fn stress_tick(&mut self) -> bool {
312 if !self.stress {
313 return false;
314 }
315 self.stress_counter += 1;
316 if self.stress_counter >= self.stress_interval.max(1) {
317 self.stress_counter = 0;
318 true
319 } else {
320 false
321 }
322 }
323}
324
325impl Heap {
326 #[inline]
331 pub(crate) fn safepoint(&mut self, need: &Need, keep: &[Value]) -> Result<(), HeapError> {
332 let nominal = need.nominal_bytes();
333 if self.gc.allocated + nominal < self.gc.room.threshold && !self.gc.always_slow() {
334 self.gc.allocated += nominal;
335 return Ok(());
336 }
337 self.safepoint_slow(need, keep)
338 }
339
340 #[cold]
341 #[inline(never)]
342 fn safepoint_slow(&mut self, need: &Need, keep: &[Value]) -> Result<(), HeapError> {
343 let nominal = need.nominal_bytes();
344 #[allow(unused_mut)]
345 let mut collect = self.gc.allocated + nominal >= self.gc.room.threshold;
346 #[cfg(feature = "gc-stress")]
347 {
348 collect |= self.gc.stress_tick();
349 }
350 let capped = self.gc.limits.max_bytes != usize::MAX;
351 let over = |heap: &Heap| {
352 heap.bytes() + heap.growth_bytes(need) + need.extra > heap.gc.limits.max_bytes
353 };
354 let over_cap = capped && over(self);
355 if collect || over_cap {
356 let mark = self.roots.stack.mark();
357 for &value in keep {
358 self.roots.stack.push(value);
359 }
360 self.collect();
361 self.roots.stack.truncate(mark);
362 if capped && over(self) {
363 return Err(HeapError::OutOfMemory);
364 }
365 }
366 self.gc.allocated += nominal;
367 Ok(())
368 }
369
370 pub(crate) fn growth_bytes(&self, need: &Need) -> usize {
372 let values = self.values.growth_bytes(need.values[0] + need.values[1]);
374 self.objects.growth_bytes(need.objects)
375 + self.shapes.growth_bytes(need.shapes)
376 + self.strings.growth_bytes(need.strings)
377 + self.symbols.growth_bytes(need.symbols)
378 + self.bigints.growth_bytes(need.bigints)
379 + self.cells.growth_bytes(need.cells)
380 + self.payloads.functions.growth_bytes(need.functions)
381 + self.payloads.bytecode.growth_bytes(need.bytecodes)
382 + self.payloads.internals.growth_bytes(need.internals)
383 + values
384 }
385
386 pub fn collect(&mut self) {
388 let start = crate::clock::Stopwatch::start();
389 let before = self.used_bytes();
390 self.mark_from_roots();
391 self.process_weak();
392 self.prune_caches();
393 let freed = self.sweep();
394 let live = self.used_bytes();
395 self.set_budget(live);
396 let gc = &mut self.gc;
397 let pause = start.elapsed();
398 let stats = &mut gc.stats;
399 stats.collections += 1;
400 stats.total_pause += pause;
401 stats.max_pause = stats.max_pause.max(pause);
402 stats.freed_records += freed as u64;
403 stats.freed_bytes += before.saturating_sub(live) as u64;
404 stats.live_bytes = live;
405 if gc.record_pauses {
406 gc.pauses.push(pause);
407 }
408 #[cfg(feature = "gc-stress")]
409 self.verify();
410 }
411
412 pub fn set_gc_manual(&mut self, manual: bool) {
415 self.gc.manual = manual;
416 let allocated = self.gc.allocated;
417 self.set_budget(self.gc.stats.live_bytes);
418 self.gc.allocated = allocated;
419 }
420
421 fn set_budget(&mut self, live: usize) {
427 let reserved = self.bytes();
428 let gc = &mut self.gc;
429 gc.allocated = 0;
430 let step = budget_step(reserved);
431 let mut budget = gc
432 .min_heap
433 .max((live as f64 * (1.0 + gc.growth_factor)) as usize);
434 let threshold = budget - live.min(budget);
438 if gc.limits.max_bytes != usize::MAX {
439 budget = budget.min(gc.limits.max_bytes.saturating_sub(step));
440 }
441 gc.budget = budget.max(reserved + step);
444 gc.room = if gc.manual {
445 Room::unbounded()
446 } else {
447 Room::new(gc.budget - reserved, threshold)
448 };
449 }
450
451 fn clear_marks(&mut self) {
452 self.objects.clear_marks();
453 self.shapes.clear_marks();
454 self.strings.clear_marks();
455 self.symbols.clear_marks();
456 self.bigints.clear_marks();
457 self.cells.clear_marks();
458 self.payloads.functions.clear_marks();
459 self.payloads.bytecode.clear_marks();
460 self.payloads.internals.clear_marks();
461 self.code.clear_marks();
462 self.regexps.clear_marks();
463 }
464
465 fn mark_from_roots(&mut self) {
468 self.clear_marks();
469 let mut stack = mem::take(&mut self.gc.mark_stack);
470 stack.extend_from_slice(self.roots.stack.values());
471 stack.extend(self.roots.handles.values());
472 stack.extend_from_slice(&self.roots.fixed);
473 for job in &self.jobs {
474 job.trace(&mut stack);
475 }
476 let top = self.vm.top as usize;
479 self.vm.stale_from = self.vm.stale_from.min(self.vm.top);
480 push_heap_values(&mut stack, &self.vm.registers[..top]);
481 stack.extend(
482 self.vm
483 .frames
484 .iter()
485 .map(|frame| Value::object(frame.function)),
486 );
487 for &id in self.pinned_atoms.iter().chain(&self.held_atoms) {
488 self.strings.mark(id.0);
489 }
490 for position in 0..self.code.pinned().len() {
492 let index = self.code.pinned()[position];
493 let id = crate::bytecode::CodeUnitId(index | crate::bytecode::DYNAMIC);
494 if let Some(unit) = self.code.mark(id) {
495 stack.extend(unit.atoms.iter().map(|&atom| Value::string(atom)));
496 }
497 }
498 let mut shapes = mem::take(&mut self.gc.shape_stack);
499 shapes.extend(self.closure_shapes.iter().flatten());
500 shapes.extend(self.pending_closure_shapes.iter().flatten());
501 shapes.extend(self.arguments_shapes.iter().flatten());
502 self.mark_shapes(&mut shapes, &mut stack);
503 self.gc.shape_stack = shapes;
504 self.cells.mark(STATIC_CELL.0);
505 stack.extend_from_slice(&self.kept);
506 stack.extend_from_slice(&self.rejections);
507 stack.extend_from_slice(&self.modules);
508 self.drain::<false>(&mut stack);
509 let mut scanned = 0;
514 loop {
515 let mut ephemerons = mem::take(&mut self.gc.ephemerons);
516 for position in scanned..self.gc.weak.len() {
517 let internal = self.payloads.internals.get(self.gc.weak[position]);
518 if internal.tag != InternalTag::WeakMap {
519 continue;
520 }
521 for entry in internal.slots.chunks(2) {
522 if entry[0].is_empty() || self.value_marked(entry[1]) {
523 continue;
524 }
525 if self.value_marked(entry[0]) {
526 stack.push(entry[1]);
527 } else {
528 ephemerons.entry(entry[0]).or_default().push(entry[1]);
529 }
530 }
531 }
532 scanned = self.gc.weak.len();
533 self.gc.ephemerons = ephemerons;
534 if stack.is_empty() {
535 break;
536 }
537 self.drain::<true>(&mut stack);
538 }
539 self.gc.ephemerons.clear();
540 for (object, info) in &self.prototypes {
542 if self.objects.is_marked(object.0)
543 && let Some(cell) = info.cell
544 {
545 self.cells.mark(cell.0);
546 }
547 }
548 stack.clear();
549 self.gc.mark_stack = stack;
550 }
551
552 fn drain<const EPHEMERONS: bool>(&mut self, stack: &mut Vec<Value>) {
556 let mut shapes = mem::take(&mut self.gc.shape_stack);
557 while let Some(value) = stack.pop() {
558 match value.kind() {
559 Kind::Object => {
560 let index = value.as_object().unwrap().0;
561 if !self.objects.mark(index) {
562 continue;
563 }
564 if EPHEMERONS
565 && !self.gc.ephemerons.is_empty()
566 && let Some(values) = self.gc.ephemerons.remove(&value)
567 {
568 stack.extend(values);
569 }
570 let header = *self.objects.get(index);
571 if !self.shapes.is_marked(header.shape.0) {
573 shapes.push(header.shape);
574 self.mark_shapes(&mut shapes, stack);
575 }
576 push_heap_values(stack, self.values.slice(header.slots()));
577 push_heap_values(stack, self.values.slice(header.elements()));
578 match header.kind {
579 ObjectKind::Scope | ObjectKind::Arguments if header.payload != NONE => {
580 stack.push(Value::object(crate::ObjectId(header.payload)));
581 }
582 kind if kind.has_internal() => {
583 if self.payloads.internals.mark(header.payload) {
584 let internal = self.payloads.internals.get(header.payload);
585 match internal.tag {
586 InternalTag::WeakMap
588 | InternalTag::WeakSet
589 | InternalTag::WeakRef => {
590 self.gc.weak.push(header.payload);
591 }
592 InternalTag::FinalizationRegistry => {
593 stack.push(internal.slots[0]);
596 for cell in internal.slots[1..].chunks(3) {
597 stack.push(cell[1]);
598 }
599 self.gc.weak.push(header.payload);
600 }
601 _ => push_heap_values(stack, &internal.slots),
602 }
603 if let super::object::InternalData::Exports(keys) = &internal.data {
605 stack.extend(keys.iter().filter_map(|key| key.heap_value()));
606 }
607 }
608 }
609 ObjectKind::Function => {
610 if self.payloads.functions.mark(header.payload) {
611 let record = *self.payloads.functions.get(header.payload);
612 for link in [record.scope, record.home_object, record.fields] {
613 if link != NONE {
614 stack.push(Value::object(crate::ObjectId(link)));
615 }
616 }
617 if record.bytecode != NONE {
618 self.mark_bytecode(record.bytecode, stack);
619 }
620 }
621 }
622 ObjectKind::RegExp if header.payload != NONE => {
623 if let Some(record) = self.regexps.mark(header.payload) {
624 stack.push(Value::string(record.source));
625 stack.push(Value::string(record.flags));
626 }
627 }
628 _ => {}
629 }
630 }
631 Kind::String => {
632 let index = value.as_string().unwrap().0;
633 if self.strings.mark(index)
634 && !self.ropes.is_empty()
635 && self.strings.get(index).flat().is_none()
636 && let Some(&(left, right)) = self.ropes.get(&index)
637 {
638 stack.push(Value::string(left));
639 stack.push(Value::string(right));
640 }
641 }
642 Kind::Symbol => {
643 let index = value.as_symbol().unwrap().0;
644 if self.symbols.mark(index) {
645 if EPHEMERONS
646 && !self.gc.ephemerons.is_empty()
647 && let Some(values) = self.gc.ephemerons.remove(&value)
648 {
649 stack.extend(values);
650 }
651 let description = self.symbols.get(index).description;
652 if description != NONE {
653 self.strings.mark(description);
654 }
655 }
656 }
657 Kind::BigInt => {
658 self.bigints.mark(value.as_bigint().unwrap().0);
659 }
660 _ => {}
661 }
662 }
663 self.gc.shape_stack = shapes;
664 }
665
666 fn mark_bytecode(&mut self, root: u32, stack: &mut Vec<Value>) {
669 let mut pending = mem::take(&mut self.gc.bytecode_stack);
670 pending.push(root);
671 while let Some(index) = pending.pop() {
672 if !self.payloads.bytecode.mark(index) {
673 continue;
674 }
675 let record = *self.payloads.bytecode.get(index);
676 let unit = crate::bytecode::CodeUnitId(record.unit);
677 if unit.is_dynamic()
678 && let Some(unit) = self.code.mark(unit)
679 {
680 stack.extend(unit.atoms.iter().map(|&atom| Value::string(atom)));
681 }
682 push_heap_values(stack, self.values.slice(record.constants));
683 let children = &self.values.slice(record.children)[..record.child_count as usize];
684 pending.extend(
685 children
686 .iter()
687 .map(|child| child.as_int32().expect("child link") as u32),
688 );
689 }
690 self.gc.bytecode_stack = pending;
691 }
692
693 fn mark_shapes(&mut self, shapes: &mut Vec<ShapeId>, stack: &mut Vec<Value>) {
696 while let Some(mut id) = shapes.pop() {
697 loop {
698 if !self.shapes.mark(id.0) {
699 break;
700 }
701 let shape = self.shapes.get(id.0);
702 if shape.count > 0
703 && let Some(key) = shape.key.heap_value()
704 {
705 stack.push(key);
706 }
707 if let Some(prototype) = shape.prototype {
708 stack.push(Value::object(prototype));
709 }
710 if shape.validity.0 != NONE {
711 self.cells.mark(shape.validity.0);
712 }
713 if let Some(dictionary) = &shape.dictionary {
714 stack.extend(
715 dictionary
716 .entries()
717 .filter_map(|entry| entry.key.heap_value()),
718 );
719 }
720 match shape.parent {
721 Some(parent) => id = parent,
722 None => break,
723 }
724 }
725 }
726 }
727
728 fn value_marked(&self, value: Value) -> bool {
732 match value.kind() {
733 Kind::Object => self.objects.is_marked(value.as_object().unwrap().0),
734 Kind::Symbol => self.symbols.is_marked(value.as_symbol().unwrap().0),
735 Kind::String => self.strings.is_marked(value.as_string().unwrap().0),
736 Kind::BigInt => self.bigints.is_marked(value.as_bigint().unwrap().0),
737 _ => true,
738 }
739 }
740
741 fn clear_weak(&mut self) {
745 let weak = mem::take(&mut self.gc.weak);
746 for &payload in &weak {
747 let tag = self.payloads.internals.get(payload).tag;
748 match tag {
749 InternalTag::WeakMap | InternalTag::WeakSet => {
750 let internal = self.payloads.internals.get(payload);
751 let width = if tag == InternalTag::WeakMap { 2 } else { 1 };
752 let dead: Vec<usize> = internal
753 .slots
754 .chunks(width)
755 .enumerate()
756 .filter(|(_, entry)| !entry[0].is_empty() && !self.value_marked(entry[0]))
757 .map(|(index, _)| index)
758 .collect();
759 let internal = self.payloads.internals.get_mut(payload);
760 for entry in dead {
761 super::table::tombstone(internal, entry);
762 }
763 }
764 InternalTag::WeakRef => {
765 let target = self.payloads.internals.get(payload).slots[0];
766 if !self.value_marked(target) {
767 self.payloads.internals.get_mut(payload).slots[0] = Value::UNDEFINED;
768 }
769 }
770 InternalTag::FinalizationRegistry => {
771 let internal = self.payloads.internals.get(payload);
772 let callback = internal.slots[0];
773 let mut jobs = Vec::new();
774 let mut dead_targets = Vec::new();
775 let mut dead_tokens = Vec::new();
776 for (index, cell) in internal.slots[1..].chunks(3).enumerate() {
777 if cell[0].is_empty() {
778 continue;
779 }
780 if !self.value_marked(cell[0]) {
781 dead_targets.push(index);
782 jobs.push(crate::vm::jobs::Job::Call {
783 function: callback,
784 this: Value::UNDEFINED,
785 args: vec![cell[1]],
786 });
787 } else if !cell[2].is_empty() && !self.value_marked(cell[2]) {
788 dead_tokens.push(index);
789 }
790 }
791 let internal = self.payloads.internals.get_mut(payload);
792 for index in dead_targets {
793 for slot in &mut internal.slots[1 + index * 3..4 + index * 3] {
794 *slot = Value::EMPTY;
795 }
796 }
797 for index in dead_tokens {
798 internal.slots[3 + index * 3] = Value::EMPTY;
799 }
800 self.jobs.extend(jobs);
801 }
802 _ => {}
803 }
804 }
805 self.gc.weak = weak;
806 self.gc.weak.clear();
807 }
808
809 fn process_weak(&mut self) {
810 self.clear_weak();
811 let strings = &self.strings;
813 self.ropes
814 .retain(|&index, _| strings.is_marked(index) && strings.get(index).flat().is_none());
815 let objects = &self.objects;
816 self.holey.retain(|&index| objects.is_marked(index));
817 if let Some((error, _)) = &self.vm.unpositioned
818 && !objects.is_marked(error.0)
819 {
820 self.vm.unpositioned = None;
821 }
822 self.prototypes.retain(|object, info| {
823 if !objects.is_marked(object.0) {
824 return false;
825 }
826 info.dependents
827 .retain(|dependent| objects.is_marked(dependent.0));
828 true
829 });
830 self.last_root = None;
831 let shapes = &mut self.shapes;
832 self.shape_roots
833 .retain(|_, shape| shapes.is_marked(shape.0));
834 let live: Vec<u32> = shapes
835 .live_indices()
836 .filter(|&index| shapes.is_marked(index))
837 .collect();
838 for index in live {
839 if shapes.get(index).transitions.is_empty() {
840 continue;
841 }
842 let mut transitions = mem::take(&mut shapes.get_mut(index).transitions);
843 transitions.retain(|child| shapes.is_marked(child.0));
844 shapes.get_mut(index).transitions = transitions;
845 }
846 }
847
848 fn prune_caches(&mut self) {
851 let (objects, shapes, cells, strings) =
852 (&self.objects, &self.shapes, &self.cells, &self.strings);
853 self.ics.prune(|record| match record {
854 Record::Shape(index) => shapes.is_marked(index),
855 Record::Object(index) => objects.is_marked(index),
856 Record::Cell(index) => cells.is_marked(index),
857 Record::Atom(index) => strings.is_marked(index),
858 });
859 }
860
861 fn sweep(&mut self) -> usize {
862 let values = &mut self.values;
863 values.begin_sweep();
864 let mut freed = self.objects.sweep(|_, header| {
865 values.release(header.slots());
866 values.release(header.elements());
867 });
868 freed += self.payloads.bytecode.sweep(|_, bytecode| {
869 values.release(bytecode.constants);
870 values.release(bytecode.children);
871 });
872 values.finish_sweep();
873 freed += self.payloads.functions.sweep(|_, _| {});
874 freed += self.payloads.internals.sweep(|_, _| {});
875 freed += self.shapes.sweep(|_, _| {});
876 let ics = &mut self.ics;
877 self.code.sweep(|unit| ics.release(unit));
878 self.regexps.sweep();
879 let (rope_bytes, atoms) = (&self.rope_bytes, &mut self.atoms);
880 freed += self.strings.sweep(|index, record| {
881 rope_bytes.set(rope_bytes.get() - record.flattened_rope_bytes());
882 if record.is_atom {
883 atoms.remove(record.repr().content_hash(), crate::value::StringId(index));
884 }
885 });
886 freed += self.symbols.sweep(|_, _| {});
887 freed += self.bigints.sweep(|_, _| {});
888 freed += self.cells.sweep(|_, _| {});
889 freed
890 }
891
892 pub fn verify(&mut self) {
897 self.mark_from_roots();
898 fn check<T: super::arena::Record>(name: &str, arena: &super::arena::Arena<T>) {
899 if let Some(index) = arena.marks_equal_live() {
900 panic!(
901 "gc verify: {name} {index} is {}",
902 if arena.is_live(index) {
903 "live but unreachable"
904 } else {
905 "reachable but freed"
906 }
907 );
908 }
909 for index in arena.free_indices() {
910 assert!(
911 !arena.is_marked(index),
912 "gc verify: free {name} {index} is marked"
913 );
914 }
915 assert!(
916 arena.free_count_matches(),
917 "gc verify: {name}'s free count or cursor disagrees with its bitmap"
918 );
919 }
920 check("object", &self.objects);
921 check("shape", &self.shapes);
922 check("string", &self.strings);
923 check("symbol", &self.symbols);
924 check("bigint", &self.bigints);
925 check("cell", &self.cells);
926 check("function", &self.payloads.functions);
927 check("bytecode", &self.payloads.bytecode);
928 check("internal", &self.payloads.internals);
929 self.code.verify();
930 self.regexps.verify();
931 self.ics.verify_free();
932 for index in self.payloads.bytecode.live_indices() {
933 let unit = crate::bytecode::CodeUnitId(self.payloads.bytecode.get(index).unit);
934 assert!(
935 !unit.is_dynamic() || self.code.lookup(unit).is_some(),
936 "gc verify: bytecode {index} names a freed dynamic unit"
937 );
938 }
939
940 let mut owner = vec![false; self.values.total_slots()];
941 let mut claim = |range: super::values::Range, what: &str| {
942 for slot in range.start..range.start + range.len {
943 assert!(
944 !owner[slot as usize],
945 "gc verify: value slot {slot} has two owners ({what})"
946 );
947 owner[slot as usize] = true;
948 }
949 };
950 for index in self.objects.live_indices() {
951 let header = self.objects.get(index);
952 claim(header.slots(), "object slots");
953 claim(header.elements(), "object elements");
954 }
955 for index in self.payloads.bytecode.live_indices() {
956 let record = self.payloads.bytecode.get(index);
957 claim(record.constants, "bytecode constants");
958 claim(record.children, "bytecode children");
959 }
960 for block in self.values.free_blocks() {
961 claim(block, "free block");
962 }
963 for (start, end) in self.values.free_runs() {
964 claim(
965 super::values::Range {
966 start,
967 len: end - start,
968 },
969 "free run",
970 );
971 }
972 if let Some(slot) = owner.iter().position(|&owned| !owned) {
974 panic!("gc verify: value slot {slot} is neither owned nor free");
975 }
976
977 for record in self.ics.named_records() {
979 let live = match record {
980 Record::Shape(index) => self.shapes.is_live(index),
981 Record::Object(index) => self.objects.is_live(index),
982 Record::Cell(index) => self.cells.is_live(index),
983 Record::Atom(index) => self.strings.is_live(index),
984 };
985 assert!(live, "gc verify: a cache entry names freed {record:?}");
986 }
987 self.clear_marks();
988 }
989}
990
991#[inline]
992fn push_heap_values(stack: &mut Vec<Value>, values: &[Value]) {
993 stack.extend(values.iter().copied().filter(|value| value.is_heap()));
994}