(** The compiler's own dlopen, and raw memory to lay a [Form] out in. Every function here is a stub in [dynload_stubs.c]; the comment at the top of that file is the design. Addresses are [nativeint] because that is the only OCaml type that is exactly a machine word and carries no tag bit. *) type handle = nativeint type addr = nativeint external dl_open : string -> handle = "flan_dl_open" external dl_sym : handle -> string -> addr = "flan_dl_sym" external dl_close : handle -> unit = "flan_dl_close" (** [call fn args n out] runs one macro: [args] is an array of [n] [Form]s, [out] is room for the one it answers. *) external call : addr -> addr -> int64 -> addr -> unit = "flan_macro_call" external alloc : int -> addr = "flan_mem_alloc" external free : addr -> unit = "flan_mem_free" external poke_i32 : addr -> int -> int32 -> unit = "flan_poke_i32" external poke_i64 : addr -> int -> int64 -> unit = "flan_poke_i64" external poke_f64 : addr -> int -> float -> unit = "flan_poke_f64" external poke_ptr : addr -> int -> addr -> unit = "flan_poke_ptr" external poke_bytes : addr -> int -> string -> unit = "flan_poke_bytes" external peek_i32 : addr -> int -> int32 = "flan_peek_i32" external peek_i64 : addr -> int -> int64 = "flan_peek_i64" external peek_f64 : addr -> int -> float = "flan_peek_f64" external peek_ptr : addr -> int -> addr = "flan_peek_ptr" external peek_bytes : addr -> int -> int -> string = "flan_peek_bytes" (* Every allocation a macro call makes on this side, kept so the whole lot can be released at once. A macro's *own* allocations are the macro process's -- which is this process -- and are leaked on purpose: a returned Form points into them, and the compiler reads it after the call returns. An expansion is bounded by the size of the program being compiled, so leaking it costs what holding the program costs. *) let owned : addr list ref = ref [] let take n = let p = alloc n in owned := p :: !owned; p let release () = List.iter free !owned; owned := []