1pub mod arena;
10pub mod atom;
11pub mod bigint;
12pub mod buffer;
13pub mod code;
14pub mod gc;
15pub(crate) mod hash;
16pub mod object;
17pub mod report;
18pub mod string;
19pub mod symbol;
20pub mod table;
21pub mod values;
22
23use std::fmt;
24
25use self::arena::Arena;
26use self::atom::{AtomTable, KEY_INDEX_LIMIT, PropertyKey};
27use self::bigint::BigIntRecord;
28use self::gc::{GcState, Handles, HeapLimits, RootStack, Roots};
29use self::hash::FxHashMap;
30use self::object::{
31 FunctionBytecode, FunctionRecord, Internal, InternalData, InternalTag, NONE, ObjectHeader,
32 ObjectKind, PayloadArenas, flags,
33};
34use self::string::{AtomKeep, StringRecord, StringRepr};
35use self::symbol::SymbolRecord;
36use self::values::{Range, ValueHeap};
37use crate::bytecode::CodeUnitId;
38use crate::shape::{Dictionary, PrototypeInfo, STATIC_CELL, Shape, ValidityCell};
39use crate::value::{BigIntId, BytecodeId, ObjectId, ScopeId, ShapeId, StringId, SymbolId, Value};
40use crate::vm::VmStack;
41use crate::vm::ic::IcStore;
42
43#[derive(Clone, Copy, Debug, PartialEq, Eq)]
44pub enum HeapError {
45 OutOfMemory,
48 DuplicateKey,
50 PrototypeCycle,
52}
53
54impl fmt::Display for HeapError {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 f.write_str(match self {
57 HeapError::OutOfMemory => "out of memory",
58 HeapError::DuplicateKey => "duplicate property key",
59 HeapError::PrototypeCycle => "cyclic prototype chain",
60 })
61 }
62}
63
64impl std::error::Error for HeapError {}
65
66#[derive(Clone, Copy, Debug)]
68pub struct BytecodeTemplate<'a> {
69 pub unit: CodeUnitId,
70 pub constants: &'a [Value],
71 pub children: &'a [u32],
73}
74
75#[derive(Clone, Copy, Debug, Default)]
77pub(crate) struct Need {
78 pub objects: usize,
79 pub shapes: usize,
80 pub strings: usize,
81 pub symbols: usize,
82 pub bigints: usize,
83 pub cells: usize,
84 pub functions: usize,
85 pub bytecodes: usize,
86 pub internals: usize,
87 pub values: [u32; 2],
89 pub extra: usize,
91}
92
93impl Need {
94 pub fn nominal_bytes(&self) -> usize {
99 self.objects * size_of::<ObjectHeader>()
100 + self.strings * size_of::<StringRecord>()
101 + self.symbols * size_of::<SymbolRecord>()
102 + self.bigints * size_of::<BigIntRecord>()
103 + self.functions * size_of::<FunctionRecord>()
104 + self.bytecodes * size_of::<FunctionBytecode>()
105 + self.internals * size_of::<Internal>()
106 + (values::class_len(self.values[0]) + values::class_len(self.values[1])) as usize * 8
107 + self.extra
108 }
109}
110
111pub struct Heap {
112 pub(crate) objects: Arena<ObjectHeader>,
113 pub(crate) shapes: Arena<Shape>,
114 pub(crate) strings: Arena<StringRecord>,
115 pub(crate) kept: Vec<Value>,
117 pub(crate) rejections: Vec<Value>,
120 pub(crate) holey: crate::heap::hash::FxHashSet<u32>,
123 pub(crate) modules: Vec<Value>,
125 pub(crate) rope_bytes: std::cell::Cell<usize>,
127 pub(crate) ropes: FxHashMap<u32, (StringId, StringId)>,
130 pub(crate) html_dda: bool,
133 pub(crate) symbols: Arena<SymbolRecord>,
134 pub(crate) bigints: Arena<BigIntRecord>,
135 pub(crate) cells: Arena<ValidityCell>,
136 pub(crate) values: ValueHeap,
137 pub(crate) payloads: PayloadArenas,
138 pub(crate) atoms: AtomTable,
139 pub(crate) atom_mode: AtomMode,
141 pub(crate) pinned_atoms: Vec<StringId>,
144 pub(crate) held_atoms: Vec<StringId>,
147 pub(crate) code: code::DynamicUnits,
149 pub(crate) regexps: crate::vm::regexp::RegExpStore,
151 pub(crate) shape_roots: FxHashMap<(u32, ObjectKind), ShapeId>,
153 pub(crate) last_root: Option<((u32, ObjectKind), ShapeId)>,
155 pub(crate) prototypes: FxHashMap<ObjectId, PrototypeInfo>,
157 pub(crate) roots: Roots,
158 pub(crate) gc: GcState,
159 pub(crate) vm: VmStack,
162 pub(crate) ics: IcStore,
165 pub(crate) global_generation: u32,
169 pub(crate) holes_writable: bool,
174 pub(crate) closure_shapes: [Option<ShapeId>; CLOSURE_SHAPES],
178 pub(crate) arguments_shapes: [Option<ShapeId>; 2],
182 pub(crate) jobs: std::collections::VecDeque<crate::vm::jobs::Job>,
184}
185
186#[derive(Clone, Copy, Debug, PartialEq, Eq)]
190pub enum AtomMode {
191 Pin,
195 Hold,
199 Weak,
201}
202
203pub(crate) const CLOSURE_SHAPES: usize = 5;
206
207impl Default for Heap {
208 fn default() -> Self {
209 Self::new(HeapLimits::default())
210 }
211}
212
213impl Heap {
214 pub fn new(limits: HeapLimits) -> Self {
215 let mut heap = Heap {
216 objects: Arena::new(),
217 shapes: Arena::new(),
218 strings: Arena::new(),
219 kept: Vec::new(),
220 rejections: Vec::new(),
221 holey: Default::default(),
222 modules: Vec::new(),
223 rope_bytes: std::cell::Cell::new(0),
224 ropes: FxHashMap::default(),
225 html_dda: false,
226 symbols: Arena::new(),
227 bigints: Arena::new(),
228 cells: Arena::new(),
229 values: ValueHeap::new(),
230 payloads: PayloadArenas::default(),
231 atoms: AtomTable::default(),
232 atom_mode: AtomMode::Pin,
233 pinned_atoms: Vec::new(),
234 held_atoms: Vec::new(),
235 code: code::DynamicUnits::default(),
236 regexps: Default::default(),
237 shape_roots: FxHashMap::default(),
238 last_root: None,
239 prototypes: FxHashMap::default(),
240 roots: Roots::default(),
241 gc: GcState::new(limits),
242 vm: VmStack::default(),
243 ics: IcStore::default(),
244 global_generation: 0,
245 holes_writable: true,
246 closure_shapes: [None; CLOSURE_SHAPES],
247 arguments_shapes: [None; 2],
248 jobs: std::collections::VecDeque::new(),
249 };
250 let cell = heap
251 .cells
252 .alloc(ValidityCell { valid: true }, &mut heap.gc.room);
253 debug_assert_eq!(cell, STATIC_CELL.0);
254 heap
255 }
256
257 pub fn roots(&mut self) -> &mut RootStack {
260 &mut self.roots.stack
261 }
262
263 pub fn handles(&mut self) -> &mut Handles {
264 &mut self.roots.handles
265 }
266
267 pub fn handles_ref(&self) -> &Handles {
268 &self.roots.handles
269 }
270
271 pub fn add_fixed_root(&mut self, value: Value) -> usize {
273 self.roots.fixed.push(value);
274 self.roots.fixed.len() - 1
275 }
276
277 pub fn set_fixed_root(&mut self, slot: usize, value: Value) {
278 self.roots.fixed[slot] = value;
279 }
280
281 pub fn fixed_root(&self, slot: usize) -> Value {
282 self.roots.fixed[slot]
283 }
284
285 pub fn gc(&self) -> &GcState {
288 &self.gc
289 }
290
291 pub fn gc_mut(&mut self) -> &mut GcState {
292 &mut self.gc
293 }
294
295 pub fn bytes(&self) -> usize {
299 self.objects.bytes()
300 + self.shapes.bytes()
301 + self.strings.bytes()
302 + self.rope_bytes.get()
303 + self.symbols.bytes()
304 + self.bigints.bytes()
305 + self.cells.bytes()
306 + self.payloads.functions.bytes()
307 + self.payloads.bytecode.bytes()
308 + self.payloads.internals.bytes()
309 + self.values.bytes()
310 + self.code.live_bytes()
311 + self.regexps.bytes()
312 + self.table_bytes()
313 }
314
315 pub fn table_bytes(&self) -> usize {
318 self.ropes.capacity() * (size_of::<(u32, (StringId, StringId))>() + 1)
319 + self.atoms.bytes()
320 + self.ics.bytes()
321 }
322
323 pub fn used_bytes(&self) -> usize {
325 self.objects.used_bytes()
326 + self.shapes.used_bytes()
327 + self.strings.used_bytes()
328 + self.rope_bytes.get()
329 + self.symbols.used_bytes()
330 + self.bigints.used_bytes()
331 + self.cells.used_bytes()
332 + self.payloads.functions.used_bytes()
333 + self.payloads.bytecode.used_bytes()
334 + self.payloads.internals.used_bytes()
335 + self.values.used_slots() * 8
336 + self.code.live_bytes()
337 + self.regexps.bytes()
338 }
339
340 pub fn ics(&self) -> &IcStore {
341 &self.ics
342 }
343
344 pub fn ics_mut(&mut self) -> &mut IcStore {
345 &mut self.ics
346 }
347
348 pub fn global_generation(&self) -> u32 {
349 self.global_generation
350 }
351
352 pub(crate) fn bump_global_generation(&mut self) {
356 self.global_generation = self.global_generation.wrapping_add(1);
357 if self.global_generation == crate::vm::ic::EMPTY_TAG {
358 self.global_generation = 0;
359 self.ics.clear_kind(crate::vm::ic::IcKind::Global);
360 }
361 }
362
363 pub fn value_heap(&self) -> &ValueHeap {
364 &self.values
365 }
366
367 pub fn regexps(&self) -> &crate::vm::regexp::RegExpStore {
369 &self.regexps
370 }
371
372 pub fn atom_table(&self) -> &AtomTable {
373 &self.atoms
374 }
375
376 pub fn live_objects(&self) -> usize {
377 self.objects.live_count()
378 }
379
380 pub fn live_shapes(&self) -> usize {
381 self.shapes.live_count()
382 }
383
384 pub fn live_strings(&self) -> usize {
385 self.strings.live_count()
386 }
387
388 pub fn live_cells(&self) -> usize {
389 self.cells.live_count()
390 }
391
392 pub fn is_live(&self, value: Value) -> bool {
393 if let Some(id) = value.as_object() {
394 self.objects.is_live(id.0)
395 } else if let Some(id) = value.as_string() {
396 self.strings.is_live(id.0)
397 } else if let Some(id) = value.as_symbol() {
398 self.symbols.is_live(id.0)
399 } else if let Some(id) = value.as_bigint() {
400 self.bigints.is_live(id.0)
401 } else {
402 true
403 }
404 }
405
406 pub fn alloc_object(
412 &mut self,
413 kind: ObjectKind,
414 prototype: Option<ObjectId>,
415 slot_capacity: u32,
416 ) -> Result<ObjectId, HeapError> {
417 match kind {
418 ObjectKind::Ordinary
419 | ObjectKind::Array
420 | ObjectKind::Native
421 | ObjectKind::Arguments
422 | ObjectKind::ForInIterator => self.alloc_plain(kind, prototype, slot_capacity, 0),
423 ObjectKind::RegExp => {
425 self.alloc_object_with(kind, prototype, slot_capacity, 0, NONE, Need::default())
426 }
427 ObjectKind::Scope | ObjectKind::GlobalObject => {
428 self.alloc_object_with(kind, prototype, slot_capacity, 0, NONE, Need::default())
429 }
430 ObjectKind::Function => panic!("function objects are created by alloc_function"),
431 ObjectKind::Free => panic!("ObjectKind::Free is the poison value"),
432 _ => panic!("{kind:?} objects are created by alloc_internal"),
433 }
434 }
435
436 #[allow(clippy::too_many_arguments)]
441 pub fn alloc_internal(
442 &mut self,
443 kind: ObjectKind,
444 tag: InternalTag,
445 prototype: Option<ObjectId>,
446 slot_capacity: u32,
447 slots: &[Value],
448 data: InternalData,
449 extra_flags: u8,
450 ) -> Result<ObjectId, HeapError> {
451 debug_assert!(kind.has_internal());
452 let mut keep = Vec::with_capacity(slots.len() + 1);
453 keep.push(prototype.map_or(Value::UNDEFINED, Value::object));
454 keep.extend_from_slice(slots);
455 let need = Need {
456 objects: 1,
457 shapes: 1,
458 internals: 1,
459 values: [slot_capacity, 0],
460 extra: slots.len() * 8,
461 ..Need::default()
462 };
463 self.safepoint(&need, &keep)?;
464 let shape = self.root_shape(prototype, kind);
465 let range = self.values.alloc_slots(slot_capacity, &mut self.gc.room);
466 let payload = self.payloads.internals.alloc(
467 Internal {
468 tag,
469 slots: slots.to_vec(),
470 data,
471 },
472 &mut self.gc.room,
473 );
474 let header = ObjectHeader::new(
475 kind,
476 shape,
477 range,
478 Range::EMPTY,
479 payload,
480 flags::EXTENSIBLE | extra_flags,
481 );
482 Ok(ObjectId(self.objects.alloc(header, &mut self.gc.room)))
483 }
484
485 #[inline]
487 pub fn internal(&self, object: ObjectId) -> &Internal {
488 let header = self.objects.get(object.0);
489 debug_assert!(header.kind.has_internal(), "{:?}", header.kind);
490 self.payloads.internals.get(header.payload)
491 }
492
493 #[inline]
494 pub fn internal_mut(&mut self, object: ObjectId) -> &mut Internal {
495 let header = self.objects.get(object.0);
496 debug_assert!(header.kind.has_internal(), "{:?}", header.kind);
497 self.payloads.internals.get_mut(header.payload)
498 }
499
500 #[inline]
502 pub fn internal_tag(&self, object: ObjectId) -> InternalTag {
503 let header = self.objects.get(object.0);
504 if header.kind.has_internal() {
505 self.payloads.internals.get(header.payload).tag
506 } else {
507 InternalTag::None
508 }
509 }
510
511 #[inline]
512 pub fn internal_slot(&self, object: ObjectId, slot: usize) -> Value {
513 self.internal(object).slots[slot]
514 }
515
516 #[inline]
517 pub fn set_internal_slot(&mut self, object: ObjectId, slot: usize, value: Value) {
518 self.internal_mut(object).slots[slot] = value;
519 }
520
521 pub fn push_internal_slot(&mut self, object: ObjectId, value: Value) -> Result<(), HeapError> {
524 let internal = self.internal(object);
525 if internal.slots.len() == internal.slots.capacity() {
526 let extra = internal.slots.capacity().max(4) * 8;
527 self.safepoint(
528 &Need {
529 extra,
530 ..Need::default()
531 },
532 &[Value::object(object), value],
533 )?;
534 }
535 self.internal_mut(object).slots.push(value);
536 Ok(())
537 }
538
539 #[inline]
541 fn alloc_plain(
542 &mut self,
543 kind: ObjectKind,
544 prototype: Option<ObjectId>,
545 slot_capacity: u32,
546 element_capacity: u32,
547 ) -> Result<ObjectId, HeapError> {
548 let need = Need {
549 objects: 1,
550 shapes: 1,
551 values: [slot_capacity, element_capacity],
552 ..Need::default()
553 };
554 self.safepoint(&need, &[prototype.map_or(Value::UNDEFINED, Value::object)])?;
555 let shape = self.root_shape(prototype, kind);
556 let slots = self.values.alloc_slots(slot_capacity, &mut self.gc.room);
557 let elements = self.values.alloc(element_capacity, &mut self.gc.room);
558 let header = ObjectHeader::new(kind, shape, slots, elements, 0, flags::EXTENSIBLE);
559 Ok(ObjectId(self.objects.alloc(header, &mut self.gc.room)))
560 }
561
562 #[inline]
563 fn alloc_object_with(
564 &mut self,
565 kind: ObjectKind,
566 prototype: Option<ObjectId>,
567 slot_capacity: u32,
568 element_capacity: u32,
569 payload: u32,
570 extra: Need,
571 ) -> Result<ObjectId, HeapError> {
572 debug_assert!(kind != ObjectKind::Free);
573 let need = Need {
574 objects: 1,
575 shapes: 1,
576 values: [slot_capacity, element_capacity],
577 ..extra
578 };
579 let proto_value = prototype.map_or(Value::UNDEFINED, Value::object);
580 let payload_value = if kind == ObjectKind::Scope && payload != NONE {
581 Value::object(ObjectId(payload))
582 } else {
583 Value::UNDEFINED
584 };
585 self.safepoint(&need, &[proto_value, payload_value])?;
586 let mut object_flags = flags::EXTENSIBLE;
587 let shape = if kind == ObjectKind::GlobalObject {
588 object_flags |= flags::DICTIONARY;
589 self.dictionary_shape(prototype, kind, Dictionary::default())
590 } else {
591 self.root_shape(prototype, kind)
592 };
593 let slots = self.values.alloc_slots(slot_capacity, &mut self.gc.room);
594 let elements = self.values.alloc(element_capacity, &mut self.gc.room);
595 if kind == ObjectKind::Function {
596 object_flags |= flags::CALLABLE;
597 }
598 let header = ObjectHeader::new(kind, shape, slots, elements, payload, object_flags);
599 Ok(ObjectId(self.objects.alloc(header, &mut self.gc.room)))
600 }
601
602 pub fn object_kind(&self, object: ObjectId) -> ObjectKind {
603 self.objects.get(object.0).kind
604 }
605
606 pub fn header(&self, object: ObjectId) -> &ObjectHeader {
607 self.objects.get(object.0)
608 }
609
610 pub fn alloc_object_with_elements(
613 &mut self,
614 kind: ObjectKind,
615 prototype: Option<ObjectId>,
616 slot_capacity: u32,
617 element_capacity: u32,
618 ) -> Result<ObjectId, HeapError> {
619 debug_assert!(matches!(
620 kind,
621 ObjectKind::Ordinary | ObjectKind::Arguments | ObjectKind::ForInIterator
622 ));
623 self.alloc_plain(kind, prototype, slot_capacity, element_capacity)
624 }
625
626 pub(crate) fn set_payload(&mut self, object: ObjectId, payload: u32) {
630 self.objects.get_mut(object.0).payload = payload;
631 }
632
633 pub(crate) fn set_raw_slot(&mut self, object: ObjectId, slot: u32, value: Value) {
636 let slots = self.objects.get(object.0).slots();
637 self.values.set(slots, slot, value);
638 }
639
640 pub(crate) fn raw_slot(&self, object: ObjectId, slot: u32) -> Value {
641 self.values.get(self.objects.get(object.0).slots(), slot)
642 }
643
644 pub fn alloc_array(
648 &mut self,
649 prototype: Option<ObjectId>,
650 capacity: u32,
651 ) -> Result<ObjectId, HeapError> {
652 self.alloc_object_with(
653 ObjectKind::Array,
654 prototype,
655 0,
656 capacity,
657 0,
658 Need::default(),
659 )
660 }
661
662 pub fn array_length(&self, array: ObjectId) -> u32 {
663 let header = self.objects.get(array.0);
664 debug_assert_eq!(header.kind, ObjectKind::Array);
665 header.payload
666 }
667
668 #[inline]
670 pub fn get_element(&self, object: ObjectId, index: u32) -> Value {
671 let header = self.objects.get(object.0);
672 let elements = header.elements();
673 if index < elements.len && (header.kind != ObjectKind::Array || index < header.payload) {
674 self.values.get(elements, index)
675 } else {
676 Value::EMPTY
677 }
678 }
679
680 pub fn set_element(
685 &mut self,
686 object: ObjectId,
687 index: u32,
688 value: Value,
689 ) -> Result<(), HeapError> {
690 let header = *self.objects.get(object.0);
691 let mut elements = header.elements();
692 if index >= elements.len {
693 let grown = if elements.len < 1024 {
696 elements.len * 2
697 } else {
698 values::next_class_len(elements.len)
699 };
700 let new_len = grown.max(index + 1).max(4);
701 self.safepoint(
702 &Need {
703 values: [new_len, 0],
704 ..Need::default()
705 },
706 &[Value::object(object), value],
707 )?;
708 elements = self.values.grow(elements, new_len, &mut self.gc.room);
709 self.objects.get_mut(object.0).set_elements(elements);
710 }
711 if header.kind == ObjectKind::Array
714 && (value.is_empty()
715 || index > header.payload
716 || (index > 0 && self.values.get(elements, index - 1).is_empty()))
717 {
718 self.holey.insert(object.0);
719 }
720 self.values.set(elements, index, value);
721 let header = self.objects.get_mut(object.0);
722 if header.kind == ObjectKind::Array && index >= header.payload {
723 header.payload = index + 1;
724 }
725 if header.has(flags::USED_AS_PROTOTYPE) {
726 self.holes_writable = false;
727 }
728 Ok(())
729 }
730
731 pub fn make_sparse(&mut self, object: ObjectId) -> Result<(), HeapError> {
735 let header = *self.objects.get(object.0);
736 if header.has(flags::SPARSE) {
737 return Ok(());
738 }
739 let elements = header.elements();
740 let count = if header.kind == ObjectKind::Array {
741 header.payload.min(elements.len)
742 } else {
743 elements.len
744 };
745 let mut index = 0;
746 while index < count {
747 let value = self
748 .values
749 .get(self.objects.get(object.0).elements(), index);
750 if !value.is_empty() {
751 let key = PropertyKey::index(index).ok_or(HeapError::OutOfMemory)?;
752 self.add_property(object, key, crate::shape::PropertyFlags::DEFAULT, value)?;
755 }
756 index += 1;
757 }
758 let header = self.objects.get_mut(object.0);
759 let elements = header.elements();
760 header.set_elements(Range::EMPTY);
761 header.flags |= flags::SPARSE;
762 self.values.free(elements);
763 Ok(())
764 }
765
766 #[inline]
769 pub(crate) fn note_prototype_index(&mut self, object: ObjectId) {
770 if self.holes_writable && self.objects.get(object.0).has(flags::USED_AS_PROTOTYPE) {
771 self.holes_writable = false;
772 }
773 }
774
775 #[inline]
777 pub fn holes_writable(&self) -> bool {
778 self.holes_writable
779 }
780
781 pub fn push_element(&mut self, array: ObjectId, value: Value) -> Result<(), HeapError> {
782 let length = self.array_length(array);
783 self.set_element(array, length, value)
784 }
785
786 pub fn set_array_length(&mut self, array: ObjectId, length: u32) {
789 let header = *self.objects.get(array.0);
790 debug_assert_eq!(header.kind, ObjectKind::Array);
791 let elements = header.elements();
792 let cut = length.min(elements.len)..header.payload.min(elements.len);
793 if !cut.is_empty() {
794 self.values.slice_mut(elements)[cut.start as usize..cut.end as usize]
795 .fill(Value::EMPTY);
796 }
797 self.objects.get_mut(array.0).payload = length;
798 }
799
800 pub fn alloc_scope(
805 &mut self,
806 parent: Option<ScopeId>,
807 slots: u32,
808 ) -> Result<ScopeId, HeapError> {
809 let payload = parent.map_or(NONE, |scope| scope.0);
810 let object =
811 self.alloc_object_with(ObjectKind::Scope, None, slots, 0, payload, Need::default())?;
812 Ok(ScopeId(object.0))
813 }
814
815 pub fn scope_parent(&self, scope: ScopeId) -> Option<ScopeId> {
816 let header = self.objects.get(scope.0);
817 debug_assert_eq!(header.kind, ObjectKind::Scope);
818 (header.payload != NONE).then_some(ScopeId(header.payload))
819 }
820
821 #[inline]
822 fn scope_at(&self, mut scope: ScopeId, depth: u32) -> &ObjectHeader {
823 for _ in 0..depth {
824 scope = ScopeId(self.objects.get(scope.0).payload);
825 }
826 self.objects.get(scope.0)
827 }
828
829 #[inline]
831 pub fn scope_get(&self, scope: ScopeId, depth: u32, index: u32) -> Value {
832 self.values.get(self.scope_at(scope, depth).slots(), index)
833 }
834
835 #[inline]
836 pub fn scope_set(&mut self, scope: ScopeId, depth: u32, index: u32, value: Value) {
837 let slots = self.scope_at(scope, depth).slots();
838 self.values.set(slots, index, value);
839 }
840
841 pub fn alloc_function(
843 &mut self,
844 prototype: Option<ObjectId>,
845 scope: Option<ScopeId>,
846 ) -> Result<ObjectId, HeapError> {
847 self.alloc_function_with(prototype, scope, 2)
848 }
849
850 pub fn alloc_function_with(
853 &mut self,
854 prototype: Option<ObjectId>,
855 scope: Option<ScopeId>,
856 slot_capacity: u32,
857 ) -> Result<ObjectId, HeapError> {
858 let scope_value = scope.map_or(Value::UNDEFINED, |scope| Value::object(scope.object()));
859 let mark = self.roots.stack.mark();
860 self.roots.stack.push(scope_value);
861 let need = Need {
862 functions: 1,
863 ..Need::default()
864 };
865 let result = self.alloc_object_with(
866 ObjectKind::Function,
867 prototype,
868 slot_capacity,
869 0,
870 NONE,
871 need,
872 );
873 self.roots.stack.truncate(mark);
874 let object = result?;
875 let record = FunctionRecord {
876 scope: scope.map_or(NONE, |scope| scope.0),
877 bytecode: NONE,
878 native: NONE,
879 home_object: NONE,
880 fields: NONE,
881 };
882 let payload = self.payloads.functions.alloc(record, &mut self.gc.room);
883 self.objects.get_mut(object.0).payload = payload;
884 Ok(object)
885 }
886
887 pub(crate) fn function_record_mut(&mut self, function: ObjectId) -> &mut FunctionRecord {
888 let header = self.objects.get(function.0);
889 debug_assert_eq!(header.kind, ObjectKind::Function);
890 self.payloads.functions.get_mut(header.payload)
891 }
892
893 pub(crate) fn set_function_scope(&mut self, function: ObjectId, scope: ScopeId) {
896 let header = self.objects.get(function.0);
897 debug_assert_eq!(header.kind, ObjectKind::Function);
898 let payload = header.payload;
899 self.payloads.functions.get_mut(payload).scope = scope.0;
900 }
901
902 pub fn function_scope(&self, function: ObjectId) -> Option<ScopeId> {
903 let header = self.objects.get(function.0);
904 debug_assert_eq!(header.kind, ObjectKind::Function);
905 let scope = self.payloads.functions.get(header.payload).scope;
906 (scope != NONE).then_some(ScopeId(scope))
907 }
908
909 pub fn alloc_bytecode_function(
914 &mut self,
915 prototype: Option<ObjectId>,
916 scope: Option<ScopeId>,
917 tree: &[BytecodeTemplate<'_>],
918 ) -> Result<ObjectId, HeapError> {
919 assert!(!tree.is_empty(), "a bytecode tree has a root");
920 let mark = self.roots.stack.mark();
921 for template in tree {
922 for &constant in template.constants {
923 self.roots.stack.push(constant);
924 }
925 }
926 let result = self.alloc_bytecode_function_rooted(prototype, scope, tree);
927 self.roots.stack.truncate(mark);
928 result
929 }
930
931 fn alloc_bytecode_function_rooted(
932 &mut self,
933 prototype: Option<ObjectId>,
934 scope: Option<ScopeId>,
935 tree: &[BytecodeTemplate<'_>],
936 ) -> Result<ObjectId, HeapError> {
937 let function = self.alloc_function(prototype, scope)?;
938 let count = |len: usize| u32::try_from(len).map_err(|_| HeapError::OutOfMemory);
939 let mut constant_slots = 0u32;
940 let mut child_slots = 0u32;
941 for template in tree {
942 let constants = values::class_len(count(template.constants.len())?);
943 let children = values::class_len(count(template.children.len())?);
944 constant_slots = constant_slots
945 .checked_add(constants)
946 .ok_or(HeapError::OutOfMemory)?;
947 child_slots = child_slots
948 .checked_add(children)
949 .ok_or(HeapError::OutOfMemory)?;
950 }
951 self.safepoint(
954 &Need {
955 bytecodes: tree.len(),
956 values: [constant_slots, child_slots],
957 ..Need::default()
958 },
959 &[Value::object(function)],
960 )?;
961 let mut ids = Vec::with_capacity(tree.len());
962 for template in tree {
963 let constant_count = template.constants.len() as u32;
964 let constants = self.values.alloc(constant_count, &mut self.gc.room);
965 self.values.slice_mut(constants)[..template.constants.len()]
966 .copy_from_slice(template.constants);
967 let record = FunctionBytecode {
968 unit: template.unit.0,
969 constants,
970 constant_count,
971 children: Range::EMPTY,
972 child_count: 0,
973 };
974 ids.push(self.payloads.bytecode.alloc(record, &mut self.gc.room));
975 }
976 for (template, &id) in tree.iter().zip(&ids) {
977 let child_count = template.children.len() as u32;
978 let children = self.values.alloc(child_count, &mut self.gc.room);
979 for (slot, &child) in template.children.iter().enumerate() {
980 let child = Value::int32(ids[child as usize] as i32);
981 self.values.set(children, slot as u32, child);
982 }
983 let record = self.payloads.bytecode.get_mut(id);
984 record.children = children;
985 record.child_count = child_count;
986 }
987 let payload = self.objects.get(function.0).payload;
988 self.payloads.functions.get_mut(payload).bytecode = ids[0];
989 Ok(function)
990 }
991
992 pub fn alloc_closure(
997 &mut self,
998 prototype: Option<ObjectId>,
999 scope: Option<ScopeId>,
1000 bytecode: BytecodeId,
1001 ) -> Result<ObjectId, HeapError> {
1002 let function = self.alloc_function_with(prototype, scope, 3)?;
1003 debug_assert!(self.payloads.bytecode.is_live(bytecode.0));
1004 let payload = self.objects.get(function.0).payload;
1005 self.payloads.functions.get_mut(payload).bytecode = bytecode.0;
1006 Ok(function)
1007 }
1008
1009 pub fn alloc_native_function(
1011 &mut self,
1012 prototype: Option<ObjectId>,
1013 native: u32,
1014 ) -> Result<ObjectId, HeapError> {
1015 self.alloc_native_closure(prototype, native, None)
1016 }
1017
1018 pub fn alloc_native_closure(
1022 &mut self,
1023 prototype: Option<ObjectId>,
1024 native: u32,
1025 data: Option<ObjectId>,
1026 ) -> Result<ObjectId, HeapError> {
1027 let function = self.alloc_function(prototype, data.map(|data| ScopeId(data.0)))?;
1028 let payload = self.objects.get(function.0).payload;
1029 self.payloads.functions.get_mut(payload).native = native;
1030 Ok(function)
1031 }
1032
1033 pub(crate) fn apply_closure_shape(
1036 &mut self,
1037 function: ObjectId,
1038 shape: ShapeId,
1039 values: &[Value],
1040 ) {
1041 let header = self.objects.get_mut(function.0);
1042 debug_assert_eq!(self.shapes.get(shape.0).width as usize, values.len());
1043 debug_assert!(header.slots().len as usize >= values.len());
1044 header.shape = shape;
1045 let slots = header.slots();
1046 for (slot, &value) in values.iter().enumerate() {
1047 self.values.set(slots, slot as u32, value);
1048 }
1049 }
1050
1051 #[inline]
1053 pub fn function_record(&self, function: ObjectId) -> FunctionRecord {
1054 let header = self.objects.get(function.0);
1055 debug_assert_eq!(header.kind, ObjectKind::Function);
1056 *self.payloads.functions.get(header.payload)
1057 }
1058
1059 pub fn function_bytecode(&self, function: ObjectId) -> Option<BytecodeId> {
1060 let header = self.objects.get(function.0);
1061 debug_assert_eq!(header.kind, ObjectKind::Function);
1062 let bytecode = self.payloads.functions.get(header.payload).bytecode;
1063 (bytecode != NONE).then_some(BytecodeId(bytecode))
1064 }
1065
1066 #[inline]
1067 pub fn bytecode_unit(&self, bytecode: BytecodeId) -> CodeUnitId {
1068 CodeUnitId(self.payloads.bytecode.get(bytecode.0).unit)
1069 }
1070
1071 pub fn bytecode_constants(&self, bytecode: BytecodeId) -> &[Value] {
1072 let record = self.payloads.bytecode.get(bytecode.0);
1073 &self.values.slice(record.constants)[..record.constant_count as usize]
1074 }
1075
1076 #[inline]
1077 pub fn bytecode_constant(&self, bytecode: BytecodeId, index: u32) -> Value {
1078 let record = self.payloads.bytecode.get(bytecode.0);
1079 debug_assert!(index < record.constant_count);
1080 self.values.get(record.constants, index)
1081 }
1082
1083 #[inline]
1085 pub fn bytecode_child(&self, bytecode: BytecodeId, index: u32) -> BytecodeId {
1086 let record = self.payloads.bytecode.get(bytecode.0);
1087 debug_assert!(index < record.child_count);
1088 let child = self.values.get(record.children, index);
1089 BytecodeId(child.as_int32().expect("child link") as u32)
1090 }
1091
1092 pub fn live_bytecodes(&self) -> usize {
1093 self.payloads.bytecode.live_count()
1094 }
1095
1096 fn alloc_string_record(&mut self, record: StringRecord) -> Result<StringId, HeapError> {
1099 let need = Need {
1100 strings: 1,
1101 extra: record.flat().map_or(0, StringRepr::content_bytes),
1102 ..Need::default()
1103 };
1104 self.safepoint(&need, &[])?;
1105 Ok(StringId(self.strings.alloc(record, &mut self.gc.room)))
1106 }
1107
1108 pub fn alloc_string_repr(&mut self, repr: StringRepr) -> Result<StringId, HeapError> {
1110 self.alloc_string_record(StringRecord::new(repr))
1111 }
1112
1113 pub(crate) fn set_object_flag(&mut self, object: ObjectId, flag: u8) {
1115 self.objects.get_mut(object.0).flags |= flag;
1116 }
1117
1118 pub(crate) fn clear_object_flag(&mut self, object: ObjectId, flag: u8) {
1120 self.objects.get_mut(object.0).flags &= !flag;
1121 }
1122
1123 pub fn alloc_string(&mut self, text: &str) -> Result<StringId, HeapError> {
1125 self.alloc_string_record(StringRecord::new(StringRepr::from_text(text)))
1126 }
1127
1128 pub fn alloc_string_units(&mut self, units: &[u16]) -> Result<StringId, HeapError> {
1129 self.alloc_string_record(StringRecord::new(StringRepr::from_units(units)))
1130 }
1131
1132 #[inline]
1134 pub fn string(&self, id: StringId) -> &StringRecord {
1135 let record = self.strings.get(id.0);
1136 if record.flat().is_none() {
1137 self.flatten(id, record);
1138 }
1139 record
1140 }
1141
1142 #[inline]
1144 pub fn string_len(&self, id: StringId) -> usize {
1145 self.strings.get(id.0).len()
1146 }
1147
1148 #[inline]
1150 pub fn string_is_one_byte(&self, id: StringId) -> bool {
1151 self.strings.get(id.0).is_one_byte()
1152 }
1153
1154 #[cold]
1157 #[inline(never)]
1158 fn flatten(&self, id: StringId, record: &StringRecord) {
1159 let halves = |id: StringId| self.ropes.get(&id.0).copied();
1160 let (left, right) = halves(id).expect("a rope");
1161 let mut stack = vec![right, left];
1162 let repr = if record.is_one_byte() {
1163 let mut bytes = Vec::with_capacity(record.len());
1164 while let Some(id) = stack.pop() {
1165 let part = self.strings.get(id.0);
1166 match (part.flat(), halves(id)) {
1167 (Some(StringRepr::OneByte(flat)), _) => bytes.extend_from_slice(flat),
1168 (Some(StringRepr::TwoByte(_)), _) => unreachable!("a one-byte rope"),
1169 (None, Some((left, right))) => {
1170 stack.push(right);
1171 stack.push(left);
1172 }
1173 (None, None) => unreachable!("a string with neither units nor halves"),
1174 }
1175 }
1176 StringRepr::OneByte(bytes.into())
1177 } else {
1178 let mut units = Vec::with_capacity(record.len());
1179 while let Some(id) = stack.pop() {
1180 let part = self.strings.get(id.0);
1181 match (part.flat(), halves(id)) {
1182 (Some(flat), _) => units.extend(flat.units()),
1183 (None, Some((left, right))) => {
1184 stack.push(right);
1185 stack.push(left);
1186 }
1187 (None, None) => unreachable!("a string with neither units nor halves"),
1188 }
1189 }
1190 StringRepr::TwoByte(units.into())
1191 };
1192 self.rope_bytes
1193 .set(self.rope_bytes.get() + repr.content_bytes());
1194 record.set_flat(repr);
1195 }
1196
1197 pub fn alloc_rope(&mut self, left: StringId, right: StringId) -> Result<StringId, HeapError> {
1199 let len = self.string_len(left) + self.string_len(right);
1200 let one_byte = self.string_is_one_byte(left) && self.string_is_one_byte(right);
1201 let need = Need {
1202 strings: 1,
1203 ..Need::default()
1204 };
1205 self.safepoint(&need, &[Value::string(left), Value::string(right)])?;
1206 let record = StringRecord::rope(len as u32, one_byte);
1207 let id = self.strings.alloc(record, &mut self.gc.room);
1208 self.ropes.insert(id, (left, right));
1209 Ok(StringId(id))
1210 }
1211
1212 pub fn string_text(&self, id: StringId) -> String {
1213 self.string(id).repr().to_rust_string()
1214 }
1215
1216 fn intern_repr(&mut self, repr: StringRepr) -> Result<StringId, HeapError> {
1217 let hash = repr.content_hash();
1218 if let Some(id) = self.atoms.find(&self.strings, &repr, hash) {
1219 self.retain_atom(id);
1220 return Ok(id);
1221 }
1222 self.insert_atom(repr, hash)
1223 }
1224
1225 fn insert_atom(&mut self, repr: StringRepr, hash: u32) -> Result<StringId, HeapError> {
1227 let array_index = repr.array_index().unwrap_or(NONE);
1228 let mut record = StringRecord::new(repr);
1229 record.is_atom = true;
1230 record.array_index = array_index;
1231 let id = self.alloc_string_record(record)?;
1232 if id.0 >= KEY_INDEX_LIMIT {
1233 self.strings.free(id.0);
1234 return Err(HeapError::OutOfMemory);
1235 }
1236 self.atoms.insert(hash, id);
1237 self.retain_atom(id);
1238 Ok(id)
1239 }
1240
1241 #[inline]
1243 fn retain_atom(&mut self, id: StringId) {
1244 match self.atom_mode {
1245 AtomMode::Weak => {}
1246 AtomMode::Hold => self.hold_atom(id),
1247 AtomMode::Pin => self.pin_atom(id),
1248 }
1249 }
1250
1251 fn hold_atom(&mut self, id: StringId) {
1254 let record = self.strings.get_mut(id.0);
1255 if record.keep == AtomKeep::Weak {
1256 record.keep = AtomKeep::Held;
1257 self.held_atoms.push(id);
1258 }
1259 }
1260
1261 pub fn pin_atom(&mut self, id: StringId) {
1263 let record = self.strings.get_mut(id.0);
1264 debug_assert!(record.is_atom, "pinning a string that is not an atom");
1265 if record.keep != AtomKeep::Pinned {
1266 record.keep = AtomKeep::Pinned;
1267 self.pinned_atoms.push(id);
1268 }
1269 }
1270
1271 pub fn set_atom_mode(&mut self, mode: AtomMode) -> AtomMode {
1273 std::mem::replace(&mut self.atom_mode, mode)
1274 }
1275
1276 pub fn atom_mode(&self) -> AtomMode {
1277 self.atom_mode
1278 }
1279
1280 pub fn intern_pinned(&mut self, text: &str) -> Result<StringId, HeapError> {
1283 let mode = self.set_atom_mode(AtomMode::Pin);
1284 let result = self.intern(text);
1285 self.atom_mode = mode;
1286 result
1287 }
1288
1289 pub fn property_key_pinned(&mut self, text: &str) -> Result<PropertyKey, HeapError> {
1292 let mode = self.set_atom_mode(AtomMode::Pin);
1293 let result = self.property_key(text);
1294 self.atom_mode = mode;
1295 result
1296 }
1297
1298 pub(crate) fn held_atoms_mark(&self) -> usize {
1300 self.held_atoms.len()
1301 }
1302
1303 pub(crate) fn release_held_atoms(&mut self, mark: usize) {
1304 for position in mark..self.held_atoms.len() {
1305 let id = self.held_atoms[position];
1306 let record = self.strings.get_mut(id.0);
1307 if record.keep == AtomKeep::Held {
1308 record.keep = AtomKeep::Weak;
1309 }
1310 }
1311 self.held_atoms.truncate(mark);
1312 }
1313
1314 pub fn intern(&mut self, text: &str) -> Result<StringId, HeapError> {
1316 self.intern_repr(StringRepr::from_text(text))
1317 }
1318
1319 pub fn intern_units(&mut self, units: &[u16]) -> Result<StringId, HeapError> {
1320 self.intern_repr(StringRepr::from_units(units))
1321 }
1322
1323 pub fn intern_latin1(&mut self, bytes: &[u8]) -> Result<StringId, HeapError> {
1326 let hash = string::content_hash(bytes.iter().map(|&byte| u16::from(byte)));
1327 if let Some(id) = self.atoms.find_one_byte(&self.strings, bytes, hash) {
1328 self.retain_atom(id);
1329 return Ok(id);
1330 }
1331 self.insert_atom(StringRepr::OneByte(bytes.into()), hash)
1332 }
1333
1334 pub fn intern_string(&mut self, string: StringId) -> Result<StringId, HeapError> {
1336 let record = self.string(string);
1337 if record.is_atom {
1338 self.retain_atom(string);
1339 return Ok(string);
1340 }
1341 let repr = record.repr().clone();
1342 self.intern_repr(repr)
1343 }
1344
1345 fn key_for_repr(&mut self, repr: StringRepr) -> Result<PropertyKey, HeapError> {
1346 if let Some(key) = repr.array_index().and_then(PropertyKey::index) {
1347 return Ok(key);
1348 }
1349 Ok(PropertyKey::atom(self.intern_repr(repr)?))
1350 }
1351
1352 pub fn property_key(&mut self, text: &str) -> Result<PropertyKey, HeapError> {
1356 self.key_for_repr(StringRepr::from_text(text))
1357 }
1358
1359 pub fn property_key_units(&mut self, units: &[u16]) -> Result<PropertyKey, HeapError> {
1360 self.key_for_repr(StringRepr::from_units(units))
1361 }
1362
1363 pub fn property_key_latin1(&mut self, bytes: &[u8]) -> Result<PropertyKey, HeapError> {
1365 let units = || bytes.iter().map(|&byte| u16::from(byte));
1366 if let Some(key) = string::array_index(bytes.len(), units()).and_then(PropertyKey::index) {
1367 return Ok(key);
1368 }
1369 Ok(PropertyKey::atom(self.intern_latin1(bytes)?))
1370 }
1371
1372 pub fn alloc_symbol(
1373 &mut self,
1374 description: Option<StringId>,
1375 private: bool,
1376 ) -> Result<SymbolId, HeapError> {
1377 let keep = description.map_or(Value::UNDEFINED, Value::string);
1378 self.safepoint(
1379 &Need {
1380 symbols: 1,
1381 ..Need::default()
1382 },
1383 &[keep],
1384 )?;
1385 let record = SymbolRecord {
1386 description: description.map_or(NONE, |id| id.0),
1387 private,
1388 };
1389 let id = self.symbols.alloc(record, &mut self.gc.room);
1390 if id >= KEY_INDEX_LIMIT {
1391 self.symbols.free(id);
1392 return Err(HeapError::OutOfMemory);
1393 }
1394 Ok(SymbolId(id))
1395 }
1396
1397 pub fn symbol(&self, id: SymbolId) -> &SymbolRecord {
1398 self.symbols.get(id.0)
1399 }
1400
1401 pub fn symbol_description(&self, id: SymbolId) -> Option<StringId> {
1402 let description = self.symbols.get(id.0).description;
1403 (description != NONE).then_some(StringId(description))
1404 }
1405
1406 pub fn alloc_bigint(&mut self, negative: bool, limbs: &[u64]) -> Result<BigIntId, HeapError> {
1407 let used = limbs.len() - limbs.iter().rev().take_while(|&&limb| limb == 0).count();
1408 let limbs: Box<[u64]> = limbs[..used].into();
1409 let need = Need {
1410 bigints: 1,
1411 extra: limbs.len() * 8,
1412 ..Need::default()
1413 };
1414 self.safepoint(&need, &[])?;
1415 let record = BigIntRecord {
1416 negative: negative && !limbs.is_empty(),
1417 limbs,
1418 };
1419 Ok(BigIntId(self.bigints.alloc(record, &mut self.gc.room)))
1420 }
1421
1422 pub fn bigint(&self, id: BigIntId) -> &BigIntRecord {
1423 self.bigints.get(id.0)
1424 }
1425}