///|
using @jit_ffi {
type ExecCodeHandle,
alloc_exec_managed,
stage_exec_managed,
finalize_exec_managed,
release_exec_managed,
exec_code_pointer,
}
///|
/// GC-managed executable code block wrapper.
struct ExecCode(ExecCodeHandle)
///|
/// Allocate and copy code to executable memory (GC-managed).
fn ExecCode::try_alloc(
code : Array[Int32],
reservation~ : @jit_ffi.Reservation? = None,
) -> ExecCode? {
let size = code.length()
if size == 0 {
return None
}
let bytes = FixedArray::make(size, b'\x00')
for i, b in code {
bytes[i] = b.to_byte()
}
let ec = alloc_exec_managed(bytes, size)
if exec_code_pointer(ec) != 0L {
if reservation is Some(reservation) && !ec.bind_reservation(reservation) {
return None
}
Some(ExecCode(ec))
} else {
None
}
}
///|
fn ExecCode::try_stage(
size : Int32,
reservation~ : @jit_ffi.Reservation? = None,
) -> ExecCode? {
if size <= 0 {
return None
}
let code = stage_exec_managed(size)
if exec_code_pointer(code) == 0L {
None
} else {
if reservation is Some(reservation) && !code.bind_reservation(reservation) {
return None
}
Some(ExecCode(code))
}
}
///|
fn ExecCode::finalize(self : ExecCode, code : Array[Byte]) -> Bool {
let size = code.length()
let bytes = FixedArray::make(size, b'\x00')
for index, byte in code {
bytes[index] = byte
}
finalize_exec_managed(self.0, bytes, size) == 0
}
///|
fn ExecCode::release(self : ExecCode) -> Bool {
release_exec_managed(self.0) == 0
}
///|
/// Get the function pointer from this executable code.
fn ExecCode::ptr(self : ExecCode) -> Int64 {
exec_code_pointer(self.0)
}