1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
//! Defines types and macros primarily for interacting with the OCaml GC.
//!
//! # `CAMLParam` Macros
//! The following macros are used to declare C local variables and
//! function parameters of type `value`.
//!
//! The function body must start with one of the `CAMLparam` macros.
//! If the function has no parameter of type `value], use [CAMLparam0`.
//! If the function has 1 to 5 `value` parameters, use the corresponding
//!
//! `CAMLparam` with the parameters as arguments.
//! If the function has more than 5 `value] parameters, use [CAMLparam5`
//! for the first 5 parameters, and one or more calls to the `CAMLxparam`
//! macros for the others.
//!
//! If the function takes an array of `value`s as argument, use
//! `CAMLparamN] to declare it (or [CAMLxparamN` if you already have a
//! call to `CAMLparam` for some other arguments).
//!
//! If you need local variables of type `value`, declare them with one
//! or more calls to the `CAMLlocal` macros at the beginning of the
//! function, after the call to CAMLparam.  Use `CAMLlocalN` (at the
//! beginning of the function) to declare an array of `value`s.
//!
//! Your function may raise an exception or return a `value` with the
//! `CAMLreturn] macro.  Its argument is simply the [value` returned by
//! your function.  Do NOT directly return a `value] with the [return`
//! keyword.  If your function returns void, use `CAMLreturn0`.
//!
//! All the identifiers beginning with "caml__" are reserved by OCaml.
//! Do not use them for anything (local or global variables, struct or
//! union tags, macros, etc.)
//!

use core::default::Default;
use core::ptr;

use crate::mlvalues::{field, Size, Value};

#[repr(C)]
#[derive(Debug, Clone)]
/// The GC root struct. **WARNING**: You should seriously not mess with this...
///
/// The fields need to be public because the macros need to access them, which means they're out of the module; in a future version, perhaps we will add methods on the struct, and avoid any `pub` exposure of the fields.
pub struct CamlRootsBlock {
    pub next: *mut CamlRootsBlock,
    pub ntables: usize,
    pub nitems: usize,
    pub tables: [*mut Value; 5],
}

impl Default for CamlRootsBlock {
    fn default() -> CamlRootsBlock {
        CamlRootsBlock {
            next: ptr::null_mut(),
            ntables: 0,
            nitems: 0,
            tables: [ptr::null_mut(); 5],
        }
    }
}

extern "C" {
    pub fn caml_modify(addr: *mut Value, value: Value);
    pub fn caml_initialize(addr: *mut Value, value: Value);
}

/// Stores the `$val` at `$offset` in the `$block`.
///
/// # Original C code
///
/// ```c
/// Store_field(block, offset, val) do{ \
///   mlsize_t caml__temp_offset = (offset); \
///   value caml__temp_val = (val); \
///   caml_modify (&Field ((block), caml__temp_offset), caml__temp_val); \
/// }while(0)
/// ```
///
/// # Example
/// ```norun
/// // stores some_value in the first field in the given block
/// store_field!(some_block, 1, some_value)
/// ```
macro_rules! store_field {
    ($block:expr, $offset:expr, $val:expr) => {
        let offset = $offset;
        let val = $val;
        let block = $block;
        $crate::memory::caml_modify(field(block, offset), val);
    };
}

/// Stores the `value` in the `block` at `offset`.
///
/// # Safety
///
/// No bounds checking or validation of the OCaml values is done in this function
pub unsafe fn store_field(block: Value, offset: Size, value: Value) {
    store_field!(block, offset, value);
}

extern "C" {
    pub fn caml_enter_blocking_section();
    pub fn caml_leave_blocking_section();
    pub fn caml_register_global_root(value: *mut Value);
    pub fn caml_remove_global_root(value: *mut Value);
}