Skip to content

Commit

Permalink
Use repr(C) in RTS struct (#2788)
Browse files Browse the repository at this point in the history
See the node added with this commit and
#2761 (comment) for
the problem this solves.
  • Loading branch information
osa1 authored Sep 16, 2021
1 parent 9b24b7b commit a71a21b
Showing 1 changed file with 38 additions and 0 deletions.
38 changes: 38 additions & 0 deletions rts/motoko-rts/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
// Note [struct representation]
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// TLDR: Add `#[repr(C)]` in types used by both the runtime system and generated code, and add
// assertions to `static_assertions` module to check that the object size and field offsets are as
// expected.
//
// Rust compiler is free to reorder fields[1]. To avoid this in types that are used by both the
// runtime system and generated code we need a `repr` attribute like `repr(C)` or `repr(packed)`.
//
// We can't use `repr(packed)` because it potentially introduces undefined behavior as getting
// address (reference or pointer) of an unaligned field (or using the address) is an undefined
// behavior in Rust. See Motoko PR #2764.
//
// So to avoid reordering fields without introducing undefined behaviors we use `repr(C)`. See [2]
// for details on how `repr(C)` works. In short: it does not reorder fields. It can add padding,
// but in our case all fields are word-sized so that's not a problem.
//
// [1]: https://github.com/rust-lang/reference/blob/master/src/types/struct.md
// [2]: https://doc.rust-lang.org/stable/reference/type-layout.html#the-c-representation

use crate::tommath_bindings::{mp_digit, mp_int};
use core::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign};

Expand Down Expand Up @@ -309,6 +330,7 @@ pub const TAG_ONE_WORD_FILLER: Tag = 16;
pub const TAG_FREE_SPACE: Tag = 17;

// Common parts of any object. Other object pointers can be coerced into a pointer to this.
#[repr(C)] // See the note at the beginning of this module
pub struct Obj {
pub tag: Tag,
}
Expand All @@ -330,6 +352,7 @@ impl Obj {
}

#[rustfmt::skip]
#[repr(C)] // See the note at the beginning of this module
pub struct Array {
pub header: Obj,
pub len: u32, // number of elements
Expand Down Expand Up @@ -361,6 +384,7 @@ impl Array {
}
}

#[repr(C)] // See the note at the beginning of this module
pub struct Object {
pub header: Obj,
pub size: u32, // Number of elements
Expand All @@ -382,11 +406,13 @@ impl Object {
}
}

#[repr(C)] // See the note at the beginning of this module
pub struct ObjInd {
pub header: Obj,
pub field: Value,
}

#[repr(C)] // See the note at the beginning of this module
pub struct Closure {
pub header: Obj,
pub funid: u32,
Expand All @@ -404,6 +430,7 @@ impl Closure {
}
}

#[repr(C)] // See the note at the beginning of this module
pub struct Blob {
pub header: Obj,
pub len: Bytes<u32>,
Expand Down Expand Up @@ -452,11 +479,13 @@ impl Blob {
}

/// A forwarding pointer placed by the GC in place of an evacuated object.
#[repr(C)] // See the note at the beginning of this module
pub struct FwdPtr {
pub header: Obj,
pub fwd: Value,
}

#[repr(C)] // See the note at the beginning of this module
pub struct BigInt {
pub header: Obj,
/// The data following now must describe is the `mp_int` struct.
Expand Down Expand Up @@ -495,22 +524,26 @@ impl BigInt {
}
}

#[repr(C)] // See the note at the beginning of this module
pub struct MutBox {
pub header: Obj,
pub field: Value,
}

#[repr(C)] // See the note at the beginning of this module
pub struct Some {
pub header: Obj,
pub field: Value,
}

#[repr(C)] // See the note at the beginning of this module
pub struct Variant {
pub header: Obj,
pub tag: u32,
pub field: Value,
}

#[repr(C)] // See the note at the beginning of this module
pub struct Concat {
pub header: Obj,
pub n_bytes: Bytes<u32>,
Expand All @@ -528,10 +561,12 @@ impl Concat {
}
}

#[repr(C)] // See the note at the beginning of this module
pub struct Null {
pub header: Obj,
}

#[repr(C)] // See the note at the beginning of this module
pub struct Bits64 {
pub header: Obj,
// We have two 32-bit fields instead of one 64-bit to avoid aligning the fields on 64-bit
Expand All @@ -546,17 +581,20 @@ impl Bits64 {
}
}

#[repr(C)] // See the note at the beginning of this module
pub struct Bits32 {
pub header: Obj,
pub bits: u32,
}

/// Marks one word empty space in heap
#[repr(C)] // See the note at the beginning of this module
pub struct OneWordFiller {
pub header: Obj,
}

/// Marks arbitrary sized emtpy space in heap
#[repr(C)] // See the note at the beginning of this module
pub struct FreeSpace {
pub header: Obj,
pub words: Words<u32>,
Expand Down

0 comments on commit a71a21b

Please sign in to comment.