Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EOP: Using a Dedicated Stable Option Type in Persistent State #4601

Merged
merged 3 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions rts/motoko-rts-tests/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod gc;
mod leb128;
mod memory;
mod principal_id;
mod stable_option;
mod text;
mod utf8;

Expand All @@ -28,6 +29,7 @@ fn main() {
gc::test();
leb128::test();
principal_id::test();
stable_option::test();
text::test();
utf8::test();
}
Expand Down
24 changes: 24 additions & 0 deletions rts/motoko-rts-tests/src/stable_option.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use motoko_rts::stable_option::StableOption;

pub fn test() {
println!("Testing StableOption ...");

let mut none: StableOption<usize> = StableOption::None;
assert!(none.is_none());
assert!(!none.is_some());
assert!(none.as_ref().is_none());
assert!(!none.as_ref().is_some());
assert!(none.as_mut().is_none());
assert!(!none.as_mut().is_some());

const TEST_VALUE: usize = 123456;
let mut some = Some(TEST_VALUE);
assert!(!some.is_none());
assert!(some.is_some());
assert_eq!(some.unwrap(), TEST_VALUE);
assert_eq!(some.as_ref().unwrap(), &TEST_VALUE);
assert_eq!(*some.as_mut().unwrap(), TEST_VALUE);

*some.as_mut().unwrap() = 0;
assert_eq!(some.unwrap(), 0);
}
10 changes: 5 additions & 5 deletions rts/motoko-rts/src/gc/incremental.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

use motoko_rts_macros::ic_mem_fn;

use crate::{memory::Memory, types::*, visitor::visit_pointer_fields};
use crate::{memory::Memory, stable_option::StableOption, types::*, visitor::visit_pointer_fields};

use self::{
partitioned_heap::{PartitionedHeap, PartitionedHeapIterator},
Expand Down Expand Up @@ -162,8 +162,8 @@ pub struct State {
phase: Phase,
partitioned_heap: PartitionedHeap,
allocation_count: usize, // Number of allocations during an active GC run.
mark_state: Option<MarkState>,
iterator_state: Option<PartitionedHeapIterator>,
mark_state: StableOption<MarkState>,
iterator_state: StableOption<PartitionedHeapIterator>,
statistics: Statistics,
}

Expand Down Expand Up @@ -191,8 +191,8 @@ impl<'a, M: Memory + 'a> IncrementalGC<'a, M> {
phase: Phase::Pause,
partitioned_heap,
allocation_count: 0,
mark_state: None,
iterator_state: None,
mark_state: StableOption::None,
iterator_state: StableOption::None,
statistics,
}
}
Expand Down
11 changes: 6 additions & 5 deletions rts/motoko-rts/src/gc/incremental/partitioned_heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ use crate::{
gc::incremental::mark_bitmap::BITMAP_ITERATION_END,
memory::Memory,
rts_trap_with,
stable_option::StableOption,
types::*,
};

Expand Down Expand Up @@ -231,15 +232,15 @@ impl Partition {
#[repr(C)]
pub struct PartitionedHeapIterator {
partition_index: usize,
bitmap_iterator: Option<BitmapIterator>,
bitmap_iterator: StableOption<BitmapIterator>,
visit_large_object: bool,
}

impl PartitionedHeapIterator {
pub fn new(heap: &PartitionedHeap) -> PartitionedHeapIterator {
let mut iterator = PartitionedHeapIterator {
partition_index: 0,
bitmap_iterator: None,
bitmap_iterator: StableOption::None,
visit_large_object: false,
};
iterator.skip_empty_partitions(heap);
Expand Down Expand Up @@ -286,15 +287,15 @@ impl PartitionedHeapIterator {
fn start_object_iteration(&mut self, heap: &PartitionedHeap) {
debug_assert!(self.partition_index <= MAX_PARTITIONS);
if self.partition_index == MAX_PARTITIONS {
self.bitmap_iterator = None;
self.bitmap_iterator = StableOption::None;
self.visit_large_object = false;
} else {
let partition = heap.get_partition(self.partition_index);
if partition.has_large_content() {
self.bitmap_iterator = None;
self.bitmap_iterator = StableOption::None;
self.visit_large_object = partition.marked_size() > 0
} else {
self.bitmap_iterator = Some(partition.get_bitmap().iterate());
self.bitmap_iterator = StableOption::Some(partition.get_bitmap().iterate());
self.visit_large_object = false;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
},
mem_utils::memcpy_words,
memory::Memory,
stable_option::StableOption,
types::*,
};

Expand All @@ -20,13 +21,13 @@ impl<'a, M: Memory + 'a> EvacuationIncrement<'a, M> {
pub unsafe fn start_phase(state: &mut State) {
debug_assert!(state.iterator_state.is_none());
let heap = &mut state.partitioned_heap;
state.iterator_state = Some(PartitionedHeapIterator::new(heap));
state.iterator_state = StableOption::Some(PartitionedHeapIterator::new(heap));
heap.plan_evacuations();
}

pub unsafe fn complete_phase(state: &mut State) {
debug_assert!(Self::evacuation_completed(state));
state.iterator_state = None;
state.iterator_state = StableOption::None;
}

pub unsafe fn evacuation_completed(state: &State) -> bool {
Expand Down
5 changes: 3 additions & 2 deletions rts/motoko-rts/src/gc/incremental/phases/mark_increment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
State,
},
memory::Memory,
stable_option::StableOption,
types::*,
visitor::visit_pointer_fields,
};
Expand All @@ -32,15 +33,15 @@ impl<'a, M: Memory + 'a> MarkIncrement<'a, M> {
state.partitioned_heap.start_collection(mem, time);
debug_assert!(state.mark_state.is_none());
let mark_stack = MarkStack::new(mem);
state.mark_state = Some(MarkState {
state.mark_state = StableOption::Some(MarkState {
mark_stack,
complete: false,
});
}

pub unsafe fn complete_phase(state: &mut State) {
debug_assert!(Self::mark_completed(state));
state.mark_state = None;
state.mark_state = StableOption::None;
}

pub unsafe fn mark_completed(state: &State) -> bool {
Expand Down
5 changes: 3 additions & 2 deletions rts/motoko-rts/src/gc/incremental/phases/update_increment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
time::BoundedTime,
Roots, State,
},
stable_option::StableOption,
types::*,
visitor::visit_pointer_fields,
};
Expand All @@ -21,14 +22,14 @@ impl<'a> UpdateIncrement<'a> {
pub unsafe fn start_phase(state: &mut State) {
debug_assert!(state.iterator_state.is_none());
let heap = &mut state.partitioned_heap;
state.iterator_state = Some(PartitionedHeapIterator::new(heap));
state.iterator_state = StableOption::Some(PartitionedHeapIterator::new(heap));
heap.collect_large_objects();
heap.plan_updates();
}

pub unsafe fn complete_phase(state: &mut State) {
debug_assert!(Self::update_completed(state));
state.iterator_state = None;
state.iterator_state = StableOption::None;
state.partitioned_heap.complete_collection();
}

Expand Down
2 changes: 2 additions & 0 deletions rts/motoko-rts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ extern crate alloc;
#[cfg(feature = "ic")]
pub mod allocator;

pub mod stable_option;

#[macro_use]
mod print;

Expand Down
55 changes: 55 additions & 0 deletions rts/motoko-rts/src/stable_option.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//! Option type with a fixed C-representation.
//! This is used as a long-term option type in the persistent metata,
//! such as the garbage collector state.
//! As the native Rust type may change in future Rust releases,
//! the Motoko runtime system uses its own dedicated `Option` type
//! with a fixed long-term representation. This is used in the persistent
//! metadata, such as in the garbage collector state.
luc-blaeser marked this conversation as resolved.
Show resolved Hide resolved
//! See:
//! * `gc::incremental::State`
//! * `gc::partitioned_heap::PartitionedHeapIterator`

/// Stable option type used for orthogonal persistent state.
/// Analogous use like the Rust-native `Option`.
#[repr(C)]
pub enum StableOption<T> {
None,
Some(T),
}

impl<T> StableOption<T> {
pub const fn is_none(&self) -> bool {
match self {
Self::None => true,
Self::Some(_) => false,
}
}

pub const fn is_some(&self) -> bool {
match self {
Self::None => false,
Self::Some(_) => true,
}
}

pub fn unwrap(self) -> T {
match self {
Self::None => panic!("Unwrapping `None` on `StableOption`"),
Self::Some(x) => x,
}
}

pub fn as_mut(&mut self) -> StableOption<&mut T> {
match *self {
Self::Some(ref mut x) => StableOption::Some(x),
Self::None => StableOption::None,
}
}

pub const fn as_ref(&self) -> StableOption<&T> {
match *self {
Self::Some(ref x) => StableOption::Some(x),
Self::None => StableOption::None,
}
}
}