///|
/// Metadata for regular objects with pointer and non-pointer fields.
///
/// Regular objects have a fixed layout with a specific number of pointer fields
/// and non-pointer fields. The `ptr_field_offset` indicates where pointer
/// fields start, `n_ptr_fields` indicates how many pointer fields there are,
/// and `tag` is an 8-bit tag for enum type.
pub struct Regular {
ptr_field_offset : UInt
n_ptr_fields : UInt
tag : UInt
} derive(Show, ToJson)
///|
/// Metadata for reference arrays (arrays of pointers).
///
/// Reference arrays store pointers to other objects.
pub struct RefArray {
/// - `1` for array of value type with reference fields
/// - `2`/`3` for array of references. Whether it's 2 or 3 depends on the
/// size of pointer on that platform.
object_size_shift : UInt
/// The number of elements in the array.
len : UInt
} derive(Show, ToJson)
///|
/// Metadata for value arrays (arrays of non-pointer values).
///
/// Value arrays store primitive values or values of value types.
pub struct ValArray {
/// The size of each element in the array, encoded as a shift value.
/// The size of each element can be calculated as `1 << object_size_shift`.
/// Note that this field is not precise when the array elements are value
/// types
object_size_shift : UInt
/// The number of elements in the array.
len : UInt
} derive(Show, ToJson)
///|
/// Metadata for external objects with custom finalizers.
///
/// External objects are used for managing resources that require custom
/// finalization logic.
pub struct External {
/// Size of the object's data portion in bytes
size : UInt
} derive(Show, ToJson)
///|
/// Abstract type representing a finalizer function for an external object.
#external
type Finalizer
///|
/// Convert a Finalizer to a function reference.
///
/// This function converts a Finalizer object into a function reference that can
/// be called to clean up resources associated with an external object.
pub fn Finalizer::to_funcref(
self : Finalizer,
) -> FuncRef[(@c.Pointer[Unit]) -> Unit] = "%identity"
///|
/// Metadata descriptor for MoonBit objects.
pub(all) enum Meta {
/// Objects with fixed layouts containing pointer and non-pointer fields
Regular(Regular)
/// Arrays of references/pointers
RefArray(RefArray)
/// Arrays of primitive values or values of value types
ValArray(ValArray)
/// Objects with custom finalizers for resource management
External(External)
} derive(Show, ToJson)
///|
/// Get the finalizer associated with an external object.
///
/// Retrieves the finalizer function pointer stored at the end of the external
/// object's data. The finalizer is located at offset `size` from the object
/// pointer.
///
/// Parameters
///
/// - `object`: Pointer to the external object
///
/// Returns the finalizer function for this object.
pub fn External::finalizer(
self : External,
object : @c.Pointer[Unit],
) -> Finalizer {
let byte_ptr : @c.Pointer[Byte] = object.cast()
let drop_ptr : @c.Pointer[@c.Pointer[Unit]] = byte_ptr
.add(self.size.to_uint64())
.cast()
drop_ptr.load().unsafe_into()
}
///|
/// Set the finalizer for an external object.
///
/// Stores a finalizer function pointer at the end of the external object's data
/// (at offset `size` from the object pointer). This finalizer will be called
/// when the object is garbage collected.
///
/// Parameters
///
/// - `object`: Pointer to the external object
/// - `finalizer`: Function to be called when the object is finalized
pub fn External::set_finalizer(
self : External,
object : @c.Pointer[Unit],
finalizer : FuncRef[(@c.Pointer[Unit]) -> Unit],
) -> Unit {
let byte_ptr : @c.Pointer[Byte] = object.cast()
let drop_ptr : @c.Pointer[@c.Pointer[Unit]] = byte_ptr
.add(self.size.to_uint64())
.cast()
drop_ptr.store(@c.Pointer::unsafe_from(finalizer))
}
///|
/// Decode metadata from a UInt value.
///
/// Parses a 32-bit unsigned integer to extract object metadata. The top 2 bits
/// determine the object kind (Regular, RefArray, ValArray, or External), and
/// the remaining bits encode kind-specific information.
///
/// Parameters
///
/// - `meta`: The encoded metadata as a UInt
///
/// Returns the decoded Meta enum value.
pub fn Meta::of_uint(meta : UInt) -> Meta {
let kind = meta >> 30
match kind {
0 => {
// Regular
// 11 bits
let ptr_field_offset = (meta >> 19) & 0x7FF
// 11 bits
let n_ptr_fields = (meta >> 8) & 0x7FF
// 8 bits
let tag = meta & 0xFF
Regular({ ptr_field_offset, n_ptr_fields, tag })
}
1 => {
// RefArray
// 2 bits
let object_size_shift = (meta >> 28) & 0x3
// 28 bits
let len = meta & 0x0FFFFFFF
RefArray({ object_size_shift, len })
}
2 => {
// ValArray
// 2 bits
let object_size_shift = (meta >> 28) & 0x3
// 28 bits
let len = meta & 0x0FFFFFFF
ValArray({ object_size_shift, len })
}
3 => {
// External
// 30 bits
let size = meta & 0x3FFFFFFF
External({ size, })
}
_ => abort("invalid kind: \{kind}")
}
}
///|
/// Encode metadata to a UInt value.
///
/// Converts a Meta enum value into a 32-bit unsigned integer encoding. The top
/// 2 bits indicate the object kind, and the remaining bits encode kind-specific
/// information such as field offsets, array lengths, or object sizes.
///
/// Returns the encoded metadata as a UInt.
pub fn Meta::to_uint(self : Meta) -> UInt {
match self {
Regular(r) =>
(0 << 30) |
((r.ptr_field_offset & 0x7FF) << 19) |
((r.n_ptr_fields & 0x7FF) << 8) |
(r.tag & 0xFF)
RefArray(ra) =>
(1 << 30) | ((ra.object_size_shift & 0x3) << 28) | (ra.len & 0x0FFFFFFF)
ValArray(va) => (2 << 30) | (va.len & 0x0FFFFFFF)
External(e) => (3 << 30) | (e.size & 0x3FFFFFFF)
}
}
///|
/// Wrapper type around `@c.Pointer` for easier access to object header fields.
struct Object(@c.Pointer[Int])
///|
/// Convert an Object to a generic pointer.
///
/// Returns a pointer to the beginning of the object's data (excluding the
/// header).
///
/// Returns a pointer to the object's data.
pub fn Object::to_pointer(self : Object) -> @c.Pointer[Unit] {
self.0.cast()
}
///|
/// Get the reference count of an object.
///
/// Returns the current reference count stored in the object's header.
///
/// Returns the reference count as an Int.
pub fn Object::rc(self : Object) -> Int {
self.0[0]
}
///|
/// Set the reference count of an object.
///
/// Updates the reference count stored in the object's header.
///
/// Parameters
/// - `rc`: The new reference count value
pub fn Object::set_rc(self : Object, rc : Int) -> Unit {
self.0[0] = rc
}
///|
/// Get the metadata of an object.
///
/// Retrieves and decodes the metadata stored in the object's header.
///
/// Returns the decoded Meta enum describing the object's type and layout.
pub fn Object::meta(self : Object) -> Meta {
Meta::of_uint(self.0[1].reinterpret_as_uint())
}
///|
/// Set the metadata of an object.
///
/// Encodes and stores metadata in the object's header.
///
/// Parameters
///
/// - `meta`: The Meta enum value to encode and store
pub fn Object::set_meta(self : Object, meta : Meta) -> Unit {
self.0[1] = meta.to_uint().reinterpret_as_int()
}
///|
/// Get the object header from a data pointer.
///
/// Given a pointer to an object's data, returns an Object handle that provides
/// access to the object's header (containing reference count and metadata).
///
/// Parameters
///
/// - `object`: Pointer to the object's data
///
/// Returns an Object handle for accessing the header.
pub fn object_header(object : @c.Pointer[Unit]) -> Object {
Object(object.cast().sub(2))
}
///|
/// Create a new external object with a custom finalizer.
///
/// Allocates memory for an external object and associates it with a finalizer
/// function that will be called when the object is garbage collected.
///
/// Parameters
///
/// - `drop`: The finalizer function to call when the object is collected
/// - `size`: The size of the object's data in bytes
///
/// Returns a pointer to the newly allocated external object.
pub extern "c" fn make_external_object(
drop : FuncRef[(@c.Pointer[Unit]) -> Unit],
size : UInt64,
) -> @c.Pointer[Unit] = "moonbit_tonyfettes_insomnia_make_external_object"
///|
/// Increment the reference count of an object.
///
/// Increases the reference count by one. This should be called when creating
/// a new reference to an existing object.
///
/// Parameters
///
/// - `object`: Pointer to the object whose reference count should be incremented
pub extern "c" fn incref(object : @c.Pointer[Unit]) -> Unit = "moonbit_tonyfettes_insomnia_incref"
///|
/// Decrement the reference count of an object.
///
/// Decreases the reference count by one. When the reference count reaches zero,
/// the object will be deallocated. If the object has a finalizer, it will be
/// called before deallocation.
///
/// Parameters
///
/// - `object`: Pointer to the object whose reference count should be decremented
pub extern "c" fn decref(object : @c.Pointer[Unit]) -> Unit = "moonbit_tonyfettes_insomnia_decref"