diff --git a/dora-runtime/src/gc.rs b/dora-runtime/src/gc.rs index 749ac4490..1b7dedbef 100644 --- a/dora-runtime/src/gc.rs +++ b/dora-runtime/src/gc.rs @@ -9,7 +9,7 @@ use crate::gc::allocator::GenerationAllocator; use crate::gc::code::CodeSpace; use crate::gc::compact::MarkCompactCollector; use crate::gc::copy::CopyCollector; -use crate::gc::space::{Space, SpaceConfig}; +use crate::gc::space::{default_readonly_space_config, Space}; use crate::gc::sweep::SweepCollector; use crate::gc::swiper::{Swiper, CARD_SIZE}; use crate::gc::tlab::MAX_TLAB_OBJECT_SIZE; @@ -45,14 +45,13 @@ pub const M: usize = K * K; const CHUNK_SIZE: usize = 8 * K; pub const DEFAULT_CODE_SPACE_LIMIT: usize = 2 * M; -pub const DEFAULT_READONLY_SPACE_LIMIT: usize = PAGE_SIZE; +pub const DEFAULT_READONLY_SPACE_LIMIT: usize = PAGE_SIZE * 4; pub struct Gc { collector: Box, supports_tlab: bool, code_space: CodeSpace, - readonly_space: Space, epoch: AtomicUsize, finalizers: Mutex)>>, @@ -60,13 +59,6 @@ pub struct Gc { impl Gc { pub fn new(args: &Flags) -> Gc { - let readonly_config = SpaceConfig { - executable: false, - chunk: PAGE_SIZE, - limit: args.readonly_size(), - object_alignment: mem::ptr_width_usize(), - }; - let collector_name = args.gc.unwrap_or(CollectorName::Swiper); let collector: Box = match collector_name { @@ -86,7 +78,6 @@ impl Gc { supports_tlab, code_space: CodeSpace::new(code_size), - readonly_space: Space::new(readonly_config, "perm"), epoch: AtomicUsize::new(0), finalizers: Mutex::new(Vec::new()), @@ -114,8 +105,8 @@ impl Gc { self.code_space.alloc(size) } - pub fn alloc_readonly(&self, size: usize) -> Address { - self.readonly_space.alloc(size) + pub fn alloc_readonly(&self, vm: &VM, size: usize) -> Address { + self.collector.alloc_readonly(vm, size) } pub fn alloc(&self, vm: &VM, size: usize) -> Address { @@ -189,6 +180,7 @@ trait Collector { // allocate object of given size fn alloc_tlab_area(&self, vm: &VM, size: usize) -> Option; fn alloc(&self, vm: &VM, size: usize) -> Address; + fn alloc_readonly(&self, vm: &VM, size: usize) -> Address; // collect garbage fn collect(&self, vm: &VM, reason: GcReason); diff --git a/dora-runtime/src/gc/compact.rs b/dora-runtime/src/gc/compact.rs index c52dbab27..7e83f5848 100644 --- a/dora-runtime/src/gc/compact.rs +++ b/dora-runtime/src/gc/compact.rs @@ -3,10 +3,10 @@ use parking_lot::Mutex; use crate::gc::bump::BumpAllocator; use crate::gc::marking; use crate::gc::root::{determine_strong_roots, Slot}; -use crate::gc::space::Space; use crate::gc::tlab; use crate::gc::{ - formatted_size, iterate_weak_roots, Address, CollectionStats, Collector, GcReason, Region, + default_readonly_space_config, iterate_weak_roots, Address, CollectionStats, Collector, + GcReason, Region, Space, }; use crate::object::Obj; use crate::os; @@ -18,6 +18,7 @@ pub struct MarkCompactCollector { heap: Region, alloc: BumpAllocator, stats: Mutex, + readonly: Space, } impl MarkCompactCollector { @@ -32,14 +33,13 @@ impl MarkCompactCollector { let heap_end = heap_start.offset(heap_size); let heap = Region::new(heap_start, heap_end); - if args.gc_verbose { - println!("GC: {} {}", heap, formatted_size(heap_size)); - } + let readonly_space = Space::new(default_readonly_space_config(args), "perm"); MarkCompactCollector { heap, alloc: BumpAllocator::new(heap_start, heap_end), stats: Mutex::new(CollectionStats::new()), + readonly: readonly_space, } } } @@ -78,6 +78,10 @@ impl Collector for MarkCompactCollector { self.alloc.bump_alloc(size) } + fn alloc_readonly(&self, _vm: &VM, size: usize) -> Address { + self.readonly.alloc(size) + } + fn collect(&self, vm: &VM, reason: GcReason) { let mut timer = Timer::new(vm.flags.gc_stats); @@ -133,7 +137,7 @@ impl MarkCompactCollector { let mut mark_compact = MarkCompact { vm, heap: self.heap, - readonly_space: &vm.gc.readonly_space, + readonly_space: &self.readonly, init_top: self.alloc.top(), top: self.heap.start, diff --git a/dora-runtime/src/gc/copy.rs b/dora-runtime/src/gc/copy.rs index 31b559a9d..c15d78544 100644 --- a/dora-runtime/src/gc/copy.rs +++ b/dora-runtime/src/gc/copy.rs @@ -5,8 +5,8 @@ use std::sync::Arc; use crate::gc::bump::BumpAllocator; use crate::gc::tlab; use crate::gc::{ - formatted_size, iterate_strong_roots, iterate_weak_roots, Address, CollectionStats, Collector, - GcReason, Region, + default_readonly_space_config, formatted_size, iterate_strong_roots, iterate_weak_roots, + Address, CollectionStats, Collector, GcReason, Region, Space, }; use crate::mem; use crate::object::{Obj, VtblptrWordKind}; @@ -22,6 +22,7 @@ pub struct CopyCollector { alloc: BumpAllocator, stats: Mutex, + readonly: Space, } impl CopyCollector { @@ -39,15 +40,14 @@ impl CopyCollector { let semi_size = heap_size / 2; let separator = heap_start.offset(semi_size); - if args.gc_verbose { - println!("GC: {}; semi size: {}", heap, formatted_size(semi_size),); - } + let readonly_space = Space::new(default_readonly_space_config(args), "perm"); CopyCollector { total: heap, separator, alloc: BumpAllocator::new(heap_start, separator), stats: Mutex::new(CollectionStats::new()), + readonly: readonly_space, } } } @@ -86,6 +86,10 @@ impl Collector for CopyCollector { self.alloc.bump_alloc(size) } + fn alloc_readonly(&self, _vm: &VM, size: usize) -> Address { + self.readonly.alloc(size) + } + fn collect(&self, vm: &VM, reason: GcReason) { let mut timer = Timer::new(vm.flags.gc_stats); diff --git a/dora-runtime/src/gc/space.rs b/dora-runtime/src/gc/space.rs index 6f91d5cf9..edf3f77b6 100644 --- a/dora-runtime/src/gc/space.rs +++ b/dora-runtime/src/gc/space.rs @@ -1,9 +1,10 @@ use parking_lot::Mutex; use std::sync::atomic::{AtomicUsize, Ordering}; -use crate::gc::{Address, Region}; +use crate::gc::{Address, Region, PAGE_SIZE}; use crate::mem; use crate::os::{self, MemoryPermission, Reservation}; +use crate::vm::Flags; /// Configuration for a space. /// This makes it possible to use `Space` both for the @@ -15,6 +16,15 @@ pub struct SpaceConfig { pub object_alignment: usize, } +pub fn default_readonly_space_config(flags: &Flags) -> SpaceConfig { + SpaceConfig { + executable: false, + chunk: PAGE_SIZE, + limit: flags.readonly_size(), + object_alignment: mem::ptr_width_usize(), + } +} + fn adapt_to_page_size(config: SpaceConfig) -> SpaceConfig { SpaceConfig { executable: config.executable, diff --git a/dora-runtime/src/gc/sweep.rs b/dora-runtime/src/gc/sweep.rs index 1355d96dc..bc65b8fec 100644 --- a/dora-runtime/src/gc/sweep.rs +++ b/dora-runtime/src/gc/sweep.rs @@ -3,11 +3,10 @@ use parking_lot::Mutex; use crate::gc::freelist::FreeList; use crate::gc::marking; use crate::gc::root::{determine_strong_roots, Slot}; -use crate::gc::space::Space; use crate::gc::tlab; use crate::gc::{ - fill_region_with_free, formatted_size, iterate_weak_roots, Address, CollectionStats, Collector, - GcReason, Region, + default_readonly_space_config, fill_region_with_free, formatted_size, iterate_weak_roots, + Address, CollectionStats, Collector, GcReason, Region, Space, }; use crate::os; use crate::safepoint; @@ -18,6 +17,7 @@ pub struct SweepCollector { heap: Region, alloc: Mutex, stats: Mutex, + readonly: Space, } impl SweepCollector { @@ -36,10 +36,13 @@ impl SweepCollector { println!("GC: {} {}", heap, formatted_size(heap_size)); } + let readonly_space = Space::new(default_readonly_space_config(args), "perm"); + SweepCollector { heap, alloc: Mutex::new(SweepAllocator::new(heap)), stats: Mutex::new(CollectionStats::new()), + readonly: readonly_space, } } } @@ -78,6 +81,10 @@ impl Collector for SweepCollector { self.inner_alloc(vm, size) } + fn alloc_readonly(&self, _vm: &VM, size: usize) -> Address { + self.readonly.alloc(size) + } + fn collect(&self, vm: &VM, reason: GcReason) { let mut timer = Timer::new(vm.flags.gc_stats); @@ -141,7 +148,7 @@ impl SweepCollector { let mut collector = MarkSweep { vm, heap: Region::new(start, top), - readonly_space: &vm.gc.readonly_space, + readonly_space: &self.readonly, rootset, reason, diff --git a/dora-runtime/src/gc/swiper.rs b/dora-runtime/src/gc/swiper.rs index 911c9c3fc..99f3e433f 100644 --- a/dora-runtime/src/gc/swiper.rs +++ b/dora-runtime/src/gc/swiper.rs @@ -18,10 +18,10 @@ use crate::gc::swiper::minor::MinorCollector; use crate::gc::swiper::old::OldGen; use crate::gc::swiper::verify::{Verifier, VerifierPhase}; use crate::gc::swiper::young::YoungGen; -use crate::gc::tlab; -use crate::gc::Collector; -use crate::gc::GcReason; -use crate::gc::{align_page_up, Address, Region, K}; +use crate::gc::{ + align_page_up, default_readonly_space_config, tlab, Address, Collector, GcReason, Region, + Space, K, +}; use crate::mem; use crate::object::{Obj, OLD_BIT, REMEMBERED_BIT}; use crate::os::{self, MemoryPermission, Reservation}; @@ -69,6 +69,7 @@ pub struct Swiper { young: YoungGen, old: OldGen, large: LargeSpace, + readonly: Space, card_table: CardTable, crossing_map: CrossingMap, @@ -168,6 +169,8 @@ impl Swiper { let threadpool = Mutex::new(Pool::new(nworkers as u32)); + let readonly = Space::new(default_readonly_space_config(args), "perm"); + Swiper { heap: Region::new(heap_start, heap_end), reserved_area, @@ -176,6 +179,7 @@ impl Swiper { young, old, large, + readonly, card_table, crossing_map, @@ -296,7 +300,7 @@ impl Swiper { &self.large, &self.card_table, &self.crossing_map, - &vm.gc.readonly_space, + &self.readonly, rootset, threads, reason, @@ -316,8 +320,6 @@ impl Swiper { fn verify(&self, vm: &VM, phase: VerifierPhase, _kind: CollectionKind, rootset: &[Slot]) { if vm.flags.gc_verify { - let readonly_space = &vm.gc.readonly_space; - let mut verifier = Verifier::new( vm, self.heap, @@ -327,7 +329,7 @@ impl Swiper { &self.crossing_map, rootset, &self.large, - &*readonly_space, + &self.readonly, phase, ); verifier.verify(); @@ -391,6 +393,10 @@ impl Collector for Swiper { } } + fn alloc_readonly(&self, _vm: &VM, size: usize) -> Address { + self.readonly.alloc(size) + } + fn collect(&self, vm: &VM, reason: GcReason) { self.perform_collection(vm, CollectionKind::Full, reason); } @@ -658,6 +664,10 @@ impl RegularPage { self.base_page_header().is_large() } + pub fn is_survivor(&self) -> bool { + self.base_page_header().is_large() + } + fn raw_flags(&self) -> usize { self.base_page_header().raw_flags() } @@ -669,7 +679,7 @@ impl RegularPage { const YOUNG_BIT: usize = 1; const LARGE_BIT: usize = 1 << 1; -const SURVIVED_BIT: usize = 1 << 2; +const SURVIVOR_BIT: usize = 1 << 2; #[repr(C)] struct BasePageHeader { @@ -685,8 +695,8 @@ impl BasePageHeader { (self.raw_flags() & LARGE_BIT) != 0 } - fn is_survived(&self) -> bool { - (self.raw_flags() & SURVIVED_BIT) != 0 + fn is_survivor(&self) -> bool { + (self.raw_flags() & SURVIVOR_BIT) != 0 } fn add_flag(&self, flag: usize) { diff --git a/dora-runtime/src/gc/swiper/verify.rs b/dora-runtime/src/gc/swiper/verify.rs index 8593806d1..00565efd8 100644 --- a/dora-runtime/src/gc/swiper/verify.rs +++ b/dora-runtime/src/gc/swiper/verify.rs @@ -128,6 +128,14 @@ impl<'a> Verifier<'a> { fn verify_heap(&mut self) { assert!(!self.in_old); + self.young.unprotect_from(); + for page in self.young.from_pages() { + assert!(page.is_young()); + assert!(!page.is_large()); + assert!(!page.is_survivor()); + } + self.young.protect_from(); + for page in self.young.to_pages() { self.verify_page(page); } diff --git a/dora-runtime/src/gc/zero.rs b/dora-runtime/src/gc/zero.rs index 2dc433b83..d274b82af 100644 --- a/dora-runtime/src/gc/zero.rs +++ b/dora-runtime/src/gc/zero.rs @@ -1,5 +1,5 @@ use crate::gc::bump::BumpAllocator; -use crate::gc::{Address, Collector, GcReason, Region}; +use crate::gc::{default_readonly_space_config, Address, Collector, GcReason, Region, Space}; use crate::os::{self, MemoryPermission, Reservation}; use crate::vm::{Flags, VM}; @@ -8,6 +8,7 @@ pub struct ZeroCollector { end: Address, alloc: BumpAllocator, reservation: Reservation, + readonly: Space, } impl ZeroCollector { @@ -20,11 +21,14 @@ impl ZeroCollector { os::commit_at(start, heap_size, MemoryPermission::ReadWrite); + let readonly_space = Space::new(default_readonly_space_config(args), "perm"); + ZeroCollector { start, end, alloc: BumpAllocator::new(start, end), reservation, + readonly: readonly_space, } } } @@ -48,6 +52,10 @@ impl Collector for ZeroCollector { self.alloc.bump_alloc(size) } + fn alloc_readonly(&self, _vm: &VM, size: usize) -> Address { + self.readonly.alloc(size) + } + fn collect(&self, _: &VM, _: GcReason) { // do nothing } diff --git a/dora-runtime/src/object.rs b/dora-runtime/src/object.rs index 469e7070b..252ecb2bb 100644 --- a/dora-runtime/src/object.rs +++ b/dora-runtime/src/object.rs @@ -654,7 +654,7 @@ fn str_alloc_heap(vm: &VM, len: usize) -> Ref { } fn str_alloc_perm(vm: &VM, len: usize) -> Ref { - str_alloc(vm, len, |vm, size| vm.gc.alloc_readonly(size)) + str_alloc(vm, len, |vm, size| vm.gc.alloc_readonly(vm, size)) } fn str_alloc(vm: &VM, len: usize, alloc: F) -> Ref