gaia-jit 0.1.1

JIT execution primitives for Gaia project
Documentation
use std::{io, ptr::NonNull};
use windows_sys::Win32::System::{
    Diagnostics::Debug::FlushInstructionCache,
    Memory::*,
    SystemInformation::{GetSystemInfo, SYSTEM_INFO},
    Threading::GetCurrentProcess,
};

pub fn get_page_size() -> usize {
    unsafe {
        let mut system_info: SYSTEM_INFO = std::mem::zeroed();
        GetSystemInfo(&mut system_info);
        system_info.dwPageSize as usize
    }
}

pub fn alloc_rw(size: usize) -> io::Result<NonNull<u8>> {
    unsafe {
        let ptr = VirtualAlloc(std::ptr::null(), size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
        if ptr.is_null() {
            return Err(io::Error::last_os_error());
        }
        Ok(NonNull::new_unchecked(ptr as *mut u8))
    }
}

pub unsafe fn dealloc(ptr: *mut u8, _size: usize) {
    unsafe {
        let _ = VirtualFree(ptr as *mut _, 0, MEM_RELEASE);
    }
}

pub unsafe fn make_executable(ptr: *mut u8, size: usize) -> io::Result<()> {
    unsafe {
        let mut old_prot = 0;
        if VirtualProtect(ptr as _, size, PAGE_EXECUTE_READ, &mut old_prot) == 0 {
            return Err(io::Error::last_os_error());
        }
        FlushInstructionCache(GetCurrentProcess(), ptr as _, size);
    }
    Ok(())
}

pub unsafe fn make_writable(ptr: *mut u8, size: usize) -> io::Result<()> {
    unsafe {
        let mut old_prot = 0;
        if VirtualProtect(ptr as _, size, PAGE_READWRITE, &mut old_prot) == 0 {
            return Err(io::Error::last_os_error());
        }
    }
    Ok(())
}

pub unsafe fn write_protect_scoped<F, R>(ptr: *mut u8, size: usize, f: F) -> io::Result<R>
where
    F: FnOnce() -> R,
{
    let mut old_prot = 0;
    unsafe {
        if VirtualProtect(ptr as _, size, PAGE_READWRITE, &mut old_prot) == 0 {
            return Err(io::Error::last_os_error());
        }
    }

    let result = f();

    unsafe {
        let mut _dummy = 0;
        if VirtualProtect(ptr as _, size, old_prot, &mut _dummy) == 0 {
            return Err(io::Error::last_os_error());
        }
    }

    Ok(result)
}