Skip to content

Commit a47bfba

Browse files
authored
feat: add thin-vec Trace feature for boa_engine support (#46)
1 parent f37d70e commit a47bfba

File tree

6 files changed

+125
-9
lines changed

6 files changed

+125
-9
lines changed

.github/workflows/rust.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ jobs:
6767
- name: Set up Miri
6868
run: cargo +nightly miri setup
6969
- name: Run tests under Miri
70-
run: cargo +nightly miri test -p oscars
70+
run: cargo +nightly miri test -p oscars --all-features
7171

7272
docs:
7373
name: Documentation

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

oscars/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ allocator-api2 = { version = "0.4.0", optional = true }
88
hashbrown = "0.16.1"
99
oscars_derive = { path = "../oscars_derive", version = "0.1.0" }
1010
rustc-hash = "2.1.1"
11+
thin-vec = { version = "0.2", optional = true }
1112

1213
[dev-dependencies]
1314
criterion = { version = "0.5", features = ["html_reports"] }
@@ -32,3 +33,4 @@ default = ["mark_sweep"]
3233
std = []
3334
mark_sweep = []
3435
gc_allocator = ["dep:allocator-api2", "mark_sweep"]
36+
thin-vec = ["dep:thin-vec", "mark_sweep"]

oscars/src/collectors/mark_sweep/gc_collections.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ mod tests {
202202

203203
#[test]
204204
fn gc_alloc_vec_basic() {
205-
let collector = &MarkSweepGarbageCollector::default();
205+
let collector = &mut MarkSweepGarbageCollector::default();
206206
let vec = GcAllocVec::new_in(collector);
207207
let gc_vec = Gc::new_in(GcRefCell::new(vec), collector);
208208

@@ -214,6 +214,9 @@ mod tests {
214214
assert_eq!(gc_vec.borrow()[0], 1);
215215
assert_eq!(gc_vec.borrow()[1], 2);
216216
assert_eq!(gc_vec.borrow()[2], 3);
217+
218+
drop(gc_vec);
219+
collector.collect();
217220
}
218221

219222
#[test]
@@ -237,11 +240,14 @@ mod tests {
237240

238241
#[test]
239242
fn gc_alloc_box_basic() {
240-
let collector = &MarkSweepGarbageCollector::default();
243+
let collector = &mut MarkSweepGarbageCollector::default();
241244
let boxed = GcAllocBox::new_in(42u64, collector);
242245
let gc_box = Gc::new_in(GcRefCell::new(boxed), collector);
243246

244247
assert_eq!(**gc_box.borrow(), 42);
248+
249+
drop(gc_box);
250+
collector.collect();
245251
}
246252

247253
#[test]
@@ -255,11 +261,14 @@ mod tests {
255261

256262
assert_eq!(gc_box.borrow().len(), 5);
257263
assert_eq!(gc_box.borrow()[2], 3);
264+
265+
drop(gc_box);
266+
collector.collect();
258267
}
259268

260269
#[test]
261270
fn gc_alloc_vec_with_gc_pointers() {
262-
let collector = &MarkSweepGarbageCollector::default();
271+
let collector = &mut MarkSweepGarbageCollector::default();
263272
let vec = GcAllocVec::new_in(collector);
264273
let gc_vec = Gc::new_in(GcRefCell::new(vec), collector);
265274

@@ -278,5 +287,8 @@ mod tests {
278287
assert_eq!(gc_vec.borrow().len(), 2);
279288
assert_eq!(*gc_vec.borrow()[0].borrow(), 100);
280289
assert_eq!(*gc_vec.borrow()[1].borrow(), 200);
290+
291+
drop(gc_vec);
292+
collector.collect();
281293
}
282294
}

oscars/src/collectors/mark_sweep/tests.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,3 +642,102 @@ mod gc_edge_cases {
642642
collector.collect();
643643
}
644644
}
645+
646+
#[cfg(feature = "thin-vec")]
647+
mod thin_vec_trace {
648+
use thin_vec::ThinVec;
649+
650+
use crate::collectors::mark_sweep::MarkSweepGarbageCollector;
651+
use crate::collectors::mark_sweep::cell::GcRefCell;
652+
use crate::collectors::mark_sweep::pointers::Gc;
653+
use crate::{Finalize, Trace};
654+
655+
/// `ThinVec<Gc<T>>` keeps inner `Gc` values alive across collections.
656+
#[test]
657+
fn thin_vec_keeps_inner_gc_alive() {
658+
let collector = &mut MarkSweepGarbageCollector::default()
659+
.with_page_size(4096)
660+
.with_heap_threshold(8_192);
661+
662+
let a = Gc::new_in(GcRefCell::new(1u64), collector);
663+
let b = Gc::new_in(GcRefCell::new(2u64), collector);
664+
let c = Gc::new_in(GcRefCell::new(3u64), collector);
665+
666+
let mut vec: ThinVec<Gc<GcRefCell<u64>>> = ThinVec::new();
667+
vec.push(a.clone());
668+
vec.push(b.clone());
669+
vec.push(c.clone());
670+
671+
let container = Gc::new_in(vec, collector);
672+
673+
collector.collect();
674+
675+
assert_eq!(*a.borrow(), 1u64, "a was incorrectly swept");
676+
assert_eq!(*b.borrow(), 2u64, "b was incorrectly swept");
677+
assert_eq!(*c.borrow(), 3u64, "c was incorrectly swept");
678+
679+
drop(container);
680+
drop(a);
681+
drop(b);
682+
drop(c);
683+
collector.collect();
684+
}
685+
686+
/// An empty `ThinVec` does not cause panics during tracing.
687+
#[test]
688+
fn thin_vec_empty_trace() {
689+
let collector = &mut MarkSweepGarbageCollector::default()
690+
.with_page_size(256)
691+
.with_heap_threshold(512);
692+
693+
let empty: ThinVec<Gc<u64>> = ThinVec::new();
694+
let gc = Gc::new_in(empty, collector);
695+
696+
collector.collect();
697+
698+
drop(gc);
699+
collector.collect();
700+
}
701+
702+
/// `ThinVec` can be embedded inside a derived `Trace` struct.
703+
#[test]
704+
fn thin_vec_in_derived_trace_struct() {
705+
#[derive(Finalize, Trace)]
706+
struct AstNode {
707+
value: u64,
708+
children: ThinVec<Gc<AstNode>>,
709+
}
710+
711+
let collector = &mut MarkSweepGarbageCollector::default()
712+
.with_page_size(4096)
713+
.with_heap_threshold(8_192);
714+
715+
let leaf = Gc::new_in(
716+
AstNode {
717+
value: 42,
718+
children: ThinVec::new(),
719+
},
720+
collector,
721+
);
722+
723+
let mut root_children = ThinVec::new();
724+
root_children.push(leaf.clone());
725+
726+
let root = Gc::new_in(
727+
AstNode {
728+
value: 0,
729+
children: root_children,
730+
},
731+
collector,
732+
);
733+
734+
collector.collect();
735+
736+
assert_eq!(root.value, 0);
737+
assert_eq!(leaf.value, 42);
738+
739+
drop(root);
740+
drop(leaf);
741+
collector.collect();
742+
}
743+
}

oscars/src/collectors/mark_sweep/trace.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -311,22 +311,18 @@ unsafe impl<T: Trace, C: allocator_api2::alloc::Allocator> Trace
311311
});
312312
}
313313

314-
// TODO: Needed for boa_engine
315-
316-
/*
317314
#[cfg(feature = "thin-vec")]
318315
impl<T: Trace> Finalize for thin_vec::ThinVec<T> {}
319316

320317
#[cfg(feature = "thin-vec")]
321-
// SAFETY: All the inner elements of the `Vec` are correctly marked.
318+
// SAFETY: All the inner elements of the `ThinVec` are correctly marked.
322319
unsafe impl<T: Trace> Trace for thin_vec::ThinVec<T> {
323320
custom_trace!(this, mark, {
324321
for e in this {
325322
mark(e);
326323
}
327324
});
328325
}
329-
*/
330326

331327
impl<T: Trace> Finalize for Option<T> {}
332328
// SAFETY: The inner value of the `Option` is correctly marked.

0 commit comments

Comments
 (0)