Skip to content

Commit

Permalink
Use passive data segments
Browse files Browse the repository at this point in the history
  • Loading branch information
luc-blaeser committed Feb 20, 2024
1 parent be54eca commit 76e6ff7
Show file tree
Hide file tree
Showing 9 changed files with 324 additions and 166 deletions.
18 changes: 12 additions & 6 deletions rts/motoko-rts/src/idl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use crate::buf::{read_byte, read_word, skip_leb128, Buf};
use crate::idl_trap_with;
use crate::leb128::{leb128_decode, sleb128_decode};
use crate::memory::{alloc_blob, Memory};
use crate::types::Words;
use crate::persistence::compatibility::TypeDescriptor;
use crate::types::{Value, Words};
use crate::utf8::utf8_validate;

use core::cmp::min;
Expand Down Expand Up @@ -1180,20 +1181,25 @@ unsafe extern "C" fn idl_sub_buf_init(rel_buf: *mut u32, typtbl_size1: u32, typt
rel.init();
}

#[no_mangle]
unsafe extern "C" fn idl_sub(
#[ic_mem_fn]
unsafe fn idl_sub<M: Memory>(
mem: &mut M,
rel_buf: *mut u32, // a buffer with at least 2 * typtbl_size1 * typtbl_size2 bits
typtbl1: *mut *mut u8,
typtbl2: *mut *mut u8,
typtbl_end1: *mut u8,
typtbl_end2: *mut u8,
typtbl_size1: u32,
typtbl_size2: u32,
candid_data2: Value,
type_offsets2: Value,
t1: i32,
t2: i32,
) -> bool {
debug_assert!(rel_buf != (0 as *mut u32));

let mut type_descriptor2 = TypeDescriptor::new(candid_data2, type_offsets2);
let typtbl2 = type_descriptor2.build_type_table(mem);
let typtbl_end2 = type_descriptor2.type_table_end();
let typtbl_size2 = type_descriptor2.type_count() as u32;

let rel = BitRel {
ptr: rel_buf,
end: rel_buf.add(idl_sub_buf_words(typtbl_size1, typtbl_size2) as usize),
Expand Down
3 changes: 1 addition & 2 deletions rts/motoko-rts/src/persistence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,9 @@ pub unsafe fn register_stable_type<M: Memory>(
mem: &mut M,
new_candid_data: Value,
new_type_offsets: Value,
new_actor_index: i32,
) {
assert_eq!(new_candid_data.tag(), TAG_BLOB);
let mut new_type = TypeDescriptor::new(new_candid_data, new_type_offsets, new_actor_index);
let mut new_type = TypeDescriptor::new(new_candid_data, new_type_offsets);
let metadata = PersistentMetadata::get();
let old_type = &mut (*metadata).stable_type;
if !old_type.is_default() && !memory_compatible(mem, old_type, &mut new_type) {
Expand Down
48 changes: 25 additions & 23 deletions rts/motoko-rts/src/persistence/compatibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,46 @@ use crate::{

const DEFAULT_VALUE: Value = Value::from_scalar(0);

/// Relocatable static type descriptor used for Candid subtypes and program upgrade compatibility checks.
/// The descriptor consists of two blobs, one for the Candid type data and one denoting a vector of types.
/// The vector only stores relative offsets in the Candid data and does not hold any absolute addresses.
/// A type descriptor is used for two cases:
/// * To store the types of the previous program version in the persistent dynamic heap, with the GC
/// potentially moving the blobs.
/// * To load the types of the current program version from passive data segments, without that absolute
/// addresses are known at compile-time.
/// The static type table is only created when calling the Candid subtype or memory compatibility check.
/// As the static table contains absolute addresses, it can only temporarily used until the next GC increment.
pub struct TypeDescriptor {
// Blob with candid-encoded type definitions.
candid_data: Value,
// Blob with a list of `u32` offsets referring to the `candid_data`.
type_offsets: Value,
// Type index of the main actor to the compared for memory compatibility.
main_actor_index: i32,
}

impl TypeDescriptor {
pub fn default() -> Self {
Self {
candid_data: DEFAULT_VALUE,
type_offsets: DEFAULT_VALUE,
main_actor_index: 0,
}
}

pub unsafe fn new(
candid_data: Value,
type_offsets: Value,
main_actor_index: i32,
) -> TypeDescriptor {
pub unsafe fn new(candid_data: Value, type_offsets: Value) -> Self {
Self {
candid_data: candid_data.forward_if_possible(),
type_offsets: type_offsets.forward_if_possible(),
main_actor_index,
}
}

pub fn is_default(&self) -> bool {
self.candid_data == DEFAULT_VALUE && self.type_offsets == DEFAULT_VALUE
}

pub fn assert_initialized(&self) {
assert!(self.candid_data != DEFAULT_VALUE && self.type_offsets != DEFAULT_VALUE);
}

// GC root if part of the persistent stable type
pub fn candid_data_location(&mut self) -> *mut Value {
&mut self.candid_data as *mut Value
Expand All @@ -53,22 +63,11 @@ impl TypeDescriptor {
&mut self.type_offsets as *mut Value
}

pub fn is_default(&self) -> bool {
self.candid_data == DEFAULT_VALUE
&& self.type_offsets == DEFAULT_VALUE
&& self.main_actor_index == 0
}

pub fn assert_initialized(&self) {
assert!(self.candid_data != DEFAULT_VALUE && self.type_offsets != DEFAULT_VALUE);
}

pub unsafe fn assign<M: Memory>(&mut self, mem: &mut M, other: &TypeDescriptor) {
pub unsafe fn assign<M: Memory>(&mut self, mem: &mut M, other: &Self) {
let candid_data_location = &mut self.candid_data as *mut Value;
write_with_barrier(mem, candid_data_location, other.candid_data);
let type_offsets_location = &mut self.type_offsets as *mut Value;
write_with_barrier(mem, type_offsets_location, other.type_offsets);
self.main_actor_index = other.main_actor_index;
}

pub unsafe fn type_count(&self) -> usize {
Expand Down Expand Up @@ -131,6 +130,9 @@ unsafe fn create_type_check_cache<M: Memory>(
cache
}

// Fix main actor type index, see `compile.ml`.
const MAIN_ACTOR_TYPE_INDEX: i32 = 0;

/// Test whether the new stable type complies with the existing old stable type.
/// This uses the existing IDL subtype test.
pub unsafe fn memory_compatible<M: Memory>(
Expand All @@ -153,8 +155,8 @@ pub unsafe fn memory_compatible<M: Memory>(
new_type_table,
old_table_end,
new_table_end,
old_type.main_actor_index,
new_type.main_actor_index,
MAIN_ACTOR_TYPE_INDEX,
MAIN_ACTOR_TYPE_INDEX,
true,
)
}
Loading

0 comments on commit 76e6ff7

Please sign in to comment.