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.arguments_shapes.iter().flatten());
501 self.mark_shapes(&mut shapes, &mut stack);
502 self.gc.shape_stack = shapes;
503 self.cells.mark(STATIC_CELL.0);
504 stack.extend_from_slice(&self.kept);
505 stack.extend_from_slice(&self.rejections);
506 stack.extend_from_slice(&self.modules);
507 self.drain::<false>(&mut stack);
508 let mut scanned = 0;
513 loop {
514 let mut ephemerons = mem::take(&mut self.gc.ephemerons);
515 for position in scanned..self.gc.weak.len() {
516 let internal = self.payloads.internals.get(self.gc.weak[position]);
517 if internal.tag != InternalTag::WeakMap {
518 continue;
519 }
520 for entry in internal.slots.chunks(2) {
521 if entry[0].is_empty() || self.value_marked(entry[1]) {
522 continue;
523 }
524 if self.value_marked(entry[0]) {
525 stack.push(entry[1]);
526 } else {
527 ephemerons.entry(entry[0]).or_default().push(entry[1]);
528 }
529 }
530 }
531 scanned = self.gc.weak.len();
532 self.gc.ephemerons = ephemerons;
533 if stack.is_empty() {
534 break;
535 }
536 self.drain::<true>(&mut stack);
537 }
538 self.gc.ephemerons.clear();
539 for (object, info) in &self.prototypes {
541 if self.objects.is_marked(object.0)
542 && let Some(cell) = info.cell
543 {
544 self.cells.mark(cell.0);
545 }
546 }
547 stack.clear();
548 self.gc.mark_stack = stack;
549 }
550
551 fn drain<const EPHEMERONS: bool>(&mut self, stack: &mut Vec<Value>) {
555 let mut shapes = mem::take(&mut self.gc.shape_stack);
556 while let Some(value) = stack.pop() {
557 match value.kind() {
558 Kind::Object => {
559 let index = value.as_object().unwrap().0;
560 if !self.objects.mark(index) {
561 continue;
562 }
563 if EPHEMERONS
564 && !self.gc.ephemerons.is_empty()
565 && let Some(values) = self.gc.ephemerons.remove(&value)
566 {
567 stack.extend(values);
568 }
569 let header = *self.objects.get(index);
570 if !self.shapes.is_marked(header.shape.0) {
572 shapes.push(header.shape);
573 self.mark_shapes(&mut shapes, stack);
574 }
575 push_heap_values(stack, self.values.slice(header.slots()));
576 push_heap_values(stack, self.values.slice(header.elements()));
577 match header.kind {
578 ObjectKind::Scope | ObjectKind::Arguments if header.payload != NONE => {
579 stack.push(Value::object(crate::ObjectId(header.payload)));
580 }
581 kind if kind.has_internal() => {
582 if self.payloads.internals.mark(header.payload) {
583 let internal = self.payloads.internals.get(header.payload);
584 match internal.tag {
585 InternalTag::WeakMap
587 | InternalTag::WeakSet
588 | InternalTag::WeakRef => {
589 self.gc.weak.push(header.payload);
590 }
591 InternalTag::FinalizationRegistry => {
592 stack.push(internal.slots[0]);
595 for cell in internal.slots[1..].chunks(3) {
596 stack.push(cell[1]);
597 }
598 self.gc.weak.push(header.payload);
599 }
600 _ => push_heap_values(stack, &internal.slots),
601 }
602 if let super::object::InternalData::Exports(keys) = &internal.data {
604 stack.extend(keys.iter().filter_map(|key| key.heap_value()));
605 }
606 }
607 }
608 ObjectKind::Function => {
609 if self.payloads.functions.mark(header.payload) {
610 let record = *self.payloads.functions.get(header.payload);
611 for link in [record.scope, record.home_object, record.fields] {
612 if link != NONE {
613 stack.push(Value::object(crate::ObjectId(link)));
614 }
615 }
616 if record.bytecode != NONE {
617 self.mark_bytecode(record.bytecode, stack);
618 }
619 }
620 }
621 ObjectKind::RegExp if header.payload != NONE => {
622 if let Some(record) = self.regexps.mark(header.payload) {
623 stack.push(Value::string(record.source));
624 stack.push(Value::string(record.flags));
625 }
626 }
627 _ => {}
628 }
629 }
630 Kind::String => {
631 let index = value.as_string().unwrap().0;
632 if self.strings.mark(index)
633 && !self.ropes.is_empty()
634 && self.strings.get(index).flat().is_none()
635 && let Some(&(left, right)) = self.ropes.get(&index)
636 {
637 stack.push(Value::string(left));
638 stack.push(Value::string(right));
639 }
640 }
641 Kind::Symbol => {
642 let index = value.as_symbol().unwrap().0;
643 if self.symbols.mark(index) {
644 if EPHEMERONS
645 && !self.gc.ephemerons.is_empty()
646 && let Some(values) = self.gc.ephemerons.remove(&value)
647 {
648 stack.extend(values);
649 }
650 let description = self.symbols.get(index).description;
651 if description != NONE {
652 self.strings.mark(description);
653 }
654 }
655 }
656 Kind::BigInt => {
657 self.bigints.mark(value.as_bigint().unwrap().0);
658 }
659 _ => {}
660 }
661 }
662 self.gc.shape_stack = shapes;
663 }
664
665 fn mark_bytecode(&mut self, root: u32, stack: &mut Vec<Value>) {
668 let mut pending = mem::take(&mut self.gc.bytecode_stack);
669 pending.push(root);
670 while let Some(index) = pending.pop() {
671 if !self.payloads.bytecode.mark(index) {
672 continue;
673 }
674 let record = *self.payloads.bytecode.get(index);
675 let unit = crate::bytecode::CodeUnitId(record.unit);
676 if unit.is_dynamic()
677 && let Some(unit) = self.code.mark(unit)
678 {
679 stack.extend(unit.atoms.iter().map(|&atom| Value::string(atom)));
680 }
681 push_heap_values(stack, self.values.slice(record.constants));
682 let children = &self.values.slice(record.children)[..record.child_count as usize];
683 pending.extend(
684 children
685 .iter()
686 .map(|child| child.as_int32().expect("child link") as u32),
687 );
688 }
689 self.gc.bytecode_stack = pending;
690 }
691
692 fn mark_shapes(&mut self, shapes: &mut Vec<ShapeId>, stack: &mut Vec<Value>) {
695 while let Some(mut id) = shapes.pop() {
696 loop {
697 if !self.shapes.mark(id.0) {
698 break;
699 }
700 let shape = self.shapes.get(id.0);
701 if shape.count > 0
702 && let Some(key) = shape.key.heap_value()
703 {
704 stack.push(key);
705 }
706 if let Some(prototype) = shape.prototype {
707 stack.push(Value::object(prototype));
708 }
709 if shape.validity.0 != NONE {
710 self.cells.mark(shape.validity.0);
711 }
712 if let Some(dictionary) = &shape.dictionary {
713 stack.extend(
714 dictionary
715 .entries()
716 .filter_map(|entry| entry.key.heap_value()),
717 );
718 }
719 match shape.parent {
720 Some(parent) => id = parent,
721 None => break,
722 }
723 }
724 }
725 }
726
727 fn value_marked(&self, value: Value) -> bool {
731 match value.kind() {
732 Kind::Object => self.objects.is_marked(value.as_object().unwrap().0),
733 Kind::Symbol => self.symbols.is_marked(value.as_symbol().unwrap().0),
734 Kind::String => self.strings.is_marked(value.as_string().unwrap().0),
735 Kind::BigInt => self.bigints.is_marked(value.as_bigint().unwrap().0),
736 _ => true,
737 }
738 }
739
740 fn clear_weak(&mut self) {
744 let weak = mem::take(&mut self.gc.weak);
745 for &payload in &weak {
746 let tag = self.payloads.internals.get(payload).tag;
747 match tag {
748 InternalTag::WeakMap | InternalTag::WeakSet => {
749 let internal = self.payloads.internals.get(payload);
750 let width = if tag == InternalTag::WeakMap { 2 } else { 1 };
751 let dead: Vec<usize> = internal
752 .slots
753 .chunks(width)
754 .enumerate()
755 .filter(|(_, entry)| !entry[0].is_empty() && !self.value_marked(entry[0]))
756 .map(|(index, _)| index)
757 .collect();
758 let internal = self.payloads.internals.get_mut(payload);
759 for entry in dead {
760 super::table::tombstone(internal, entry);
761 }
762 }
763 InternalTag::WeakRef => {
764 let target = self.payloads.internals.get(payload).slots[0];
765 if !self.value_marked(target) {
766 self.payloads.internals.get_mut(payload).slots[0] = Value::UNDEFINED;
767 }
768 }
769 InternalTag::FinalizationRegistry => {
770 let internal = self.payloads.internals.get(payload);
771 let callback = internal.slots[0];
772 let mut jobs = Vec::new();
773 let mut dead_targets = Vec::new();
774 let mut dead_tokens = Vec::new();
775 for (index, cell) in internal.slots[1..].chunks(3).enumerate() {
776 if cell[0].is_empty() {
777 continue;
778 }
779 if !self.value_marked(cell[0]) {
780 dead_targets.push(index);
781 jobs.push(crate::vm::jobs::Job::Call {
782 function: callback,
783 this: Value::UNDEFINED,
784 args: vec![cell[1]],
785 });
786 } else if !cell[2].is_empty() && !self.value_marked(cell[2]) {
787 dead_tokens.push(index);
788 }
789 }
790 let internal = self.payloads.internals.get_mut(payload);
791 for index in dead_targets {
792 for slot in &mut internal.slots[1 + index * 3..4 + index * 3] {
793 *slot = Value::EMPTY;
794 }
795 }
796 for index in dead_tokens {
797 internal.slots[3 + index * 3] = Value::EMPTY;
798 }
799 self.jobs.extend(jobs);
800 }
801 _ => {}
802 }
803 }
804 self.gc.weak = weak;
805 self.gc.weak.clear();
806 }
807
808 fn process_weak(&mut self) {
809 self.clear_weak();
810 let strings = &self.strings;
812 self.ropes
813 .retain(|&index, _| strings.is_marked(index) && strings.get(index).flat().is_none());
814 let objects = &self.objects;
815 self.holey.retain(|&index| objects.is_marked(index));
816 if let Some((error, _)) = &self.vm.unpositioned
817 && !objects.is_marked(error.0)
818 {
819 self.vm.unpositioned = None;
820 }
821 self.prototypes.retain(|object, info| {
822 if !objects.is_marked(object.0) {
823 return false;
824 }
825 info.dependents
826 .retain(|dependent| objects.is_marked(dependent.0));
827 true
828 });
829 self.last_root = None;
830 let shapes = &mut self.shapes;
831 self.shape_roots
832 .retain(|_, shape| shapes.is_marked(shape.0));
833 let live: Vec<u32> = shapes
834 .live_indices()
835 .filter(|&index| shapes.is_marked(index))
836 .collect();
837 for index in live {
838 if shapes.get(index).transitions.is_empty() {
839 continue;
840 }
841 let mut transitions = mem::take(&mut shapes.get_mut(index).transitions);
842 transitions.retain(|child| shapes.is_marked(child.0));
843 shapes.get_mut(index).transitions = transitions;
844 }
845 }
846
847 fn prune_caches(&mut self) {
850 let (objects, shapes, cells, strings) =
851 (&self.objects, &self.shapes, &self.cells, &self.strings);
852 self.ics.prune(|record| match record {
853 Record::Shape(index) => shapes.is_marked(index),
854 Record::Object(index) => objects.is_marked(index),
855 Record::Cell(index) => cells.is_marked(index),
856 Record::Atom(index) => strings.is_marked(index),
857 });
858 }
859
860 fn sweep(&mut self) -> usize {
861 let values = &mut self.values;
862 values.begin_sweep();
863 let mut freed = self.objects.sweep(|_, header| {
864 values.release(header.slots());
865 values.release(header.elements());
866 });
867 freed += self.payloads.bytecode.sweep(|_, bytecode| {
868 values.release(bytecode.constants);
869 values.release(bytecode.children);
870 });
871 values.finish_sweep();
872 freed += self.payloads.functions.sweep(|_, _| {});
873 freed += self.payloads.internals.sweep(|_, _| {});
874 freed += self.shapes.sweep(|_, _| {});
875 let ics = &mut self.ics;
876 self.code.sweep(|unit| ics.release(unit));
877 self.regexps.sweep();
878 let (rope_bytes, atoms) = (&self.rope_bytes, &mut self.atoms);
879 freed += self.strings.sweep(|index, record| {
880 rope_bytes.set(rope_bytes.get() - record.flattened_rope_bytes());
881 if record.is_atom {
882 atoms.remove(record.repr().content_hash(), crate::value::StringId(index));
883 }
884 });
885 freed += self.symbols.sweep(|_, _| {});
886 freed += self.bigints.sweep(|_, _| {});
887 freed += self.cells.sweep(|_, _| {});
888 freed
889 }
890
891 pub fn verify(&mut self) {
896 self.mark_from_roots();
897 fn check<T: super::arena::Record>(name: &str, arena: &super::arena::Arena<T>) {
898 if let Some(index) = arena.marks_equal_live() {
899 panic!(
900 "gc verify: {name} {index} is {}",
901 if arena.is_live(index) {
902 "live but unreachable"
903 } else {
904 "reachable but freed"
905 }
906 );
907 }
908 for index in arena.free_indices() {
909 assert!(
910 !arena.is_marked(index),
911 "gc verify: free {name} {index} is marked"
912 );
913 }
914 assert!(
915 arena.free_count_matches(),
916 "gc verify: {name}'s free count or cursor disagrees with its bitmap"
917 );
918 }
919 check("object", &self.objects);
920 check("shape", &self.shapes);
921 check("string", &self.strings);
922 check("symbol", &self.symbols);
923 check("bigint", &self.bigints);
924 check("cell", &self.cells);
925 check("function", &self.payloads.functions);
926 check("bytecode", &self.payloads.bytecode);
927 check("internal", &self.payloads.internals);
928 self.code.verify();
929 self.regexps.verify();
930 self.ics.verify_free();
931 for index in self.payloads.bytecode.live_indices() {
932 let unit = crate::bytecode::CodeUnitId(self.payloads.bytecode.get(index).unit);
933 assert!(
934 !unit.is_dynamic() || self.code.lookup(unit).is_some(),
935 "gc verify: bytecode {index} names a freed dynamic unit"
936 );
937 }
938
939 let mut owner = vec![false; self.values.total_slots()];
940 let mut claim = |range: super::values::Range, what: &str| {
941 for slot in range.start..range.start + range.len {
942 assert!(
943 !owner[slot as usize],
944 "gc verify: value slot {slot} has two owners ({what})"
945 );
946 owner[slot as usize] = true;
947 }
948 };
949 for index in self.objects.live_indices() {
950 let header = self.objects.get(index);
951 claim(header.slots(), "object slots");
952 claim(header.elements(), "object elements");
953 }
954 for index in self.payloads.bytecode.live_indices() {
955 let record = self.payloads.bytecode.get(index);
956 claim(record.constants, "bytecode constants");
957 claim(record.children, "bytecode children");
958 }
959 for block in self.values.free_blocks() {
960 claim(block, "free block");
961 }
962 for (start, end) in self.values.free_runs() {
963 claim(
964 super::values::Range {
965 start,
966 len: end - start,
967 },
968 "free run",
969 );
970 }
971 if let Some(slot) = owner.iter().position(|&owned| !owned) {
973 panic!("gc verify: value slot {slot} is neither owned nor free");
974 }
975
976 for record in self.ics.named_records() {
978 let live = match record {
979 Record::Shape(index) => self.shapes.is_live(index),
980 Record::Object(index) => self.objects.is_live(index),
981 Record::Cell(index) => self.cells.is_live(index),
982 Record::Atom(index) => self.strings.is_live(index),
983 };
984 assert!(live, "gc verify: a cache entry names freed {record:?}");
985 }
986 self.clear_marks();
987 }
988}
989
990#[inline]
991fn push_heap_values(stack: &mut Vec<Value>, values: &[Value]) {
992 stack.extend(values.iter().copied().filter(|value| value.is_heap()));
993}