forked from AbleOS/holey-bytes
163 lines
4.5 KiB
Rust
163 lines
4.5 KiB
Rust
#![feature(alloc_error_handler)]
|
|
#![feature(pointer_is_aligned_to)]
|
|
#![feature(slice_take)]
|
|
#![no_std]
|
|
|
|
use core::{
|
|
alloc::{GlobalAlloc, Layout},
|
|
cell::UnsafeCell,
|
|
};
|
|
|
|
extern crate alloc;
|
|
|
|
#[macro_export]
|
|
macro_rules! decl_buffer {
|
|
($cap:expr, $export_cap:ident, $export_base:ident, $export_len:ident) => {
|
|
#[no_mangle]
|
|
static $export_cap: usize = $cap;
|
|
#[no_mangle]
|
|
static mut $export_base: [u8; $cap] = [0; $cap];
|
|
#[no_mangle]
|
|
static mut $export_len: usize = 0;
|
|
};
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! decl_runtime {
|
|
($memory_size:expr, $max_panic_size:expr) => {
|
|
#[cfg(debug_assertions)]
|
|
#[no_mangle]
|
|
static mut PANIC_MESSAGE: [u8; $max_panic_size] = [0; $max_panic_size];
|
|
#[cfg(debug_assertions)]
|
|
#[no_mangle]
|
|
static mut PANIC_MESSAGE_LEN: usize = 0;
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
#[panic_handler]
|
|
pub fn handle_panic(_info: &core::panic::PanicInfo) -> ! {
|
|
#[cfg(debug_assertions)]
|
|
{
|
|
unsafe {
|
|
use core::fmt::Write;
|
|
let mut f = $crate::Write(&mut PANIC_MESSAGE[..]);
|
|
_ = writeln!(f, "{}", _info);
|
|
PANIC_MESSAGE_LEN = $max_panic_size - f.0.len();
|
|
}
|
|
}
|
|
|
|
core::arch::wasm32::unreachable();
|
|
}
|
|
|
|
#[global_allocator]
|
|
static ALLOCATOR: $crate::ArenaAllocator<{ $memory_size }> = $crate::ArenaAllocator::new();
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
#[alloc_error_handler]
|
|
fn alloc_error(_: core::alloc::Layout) -> ! {
|
|
#[cfg(debug_assertions)]
|
|
{
|
|
unsafe {
|
|
use core::fmt::Write;
|
|
let mut f = $crate::Write(&mut PANIC_MESSAGE[..]);
|
|
_ = writeln!(f, "out of memory");
|
|
PANIC_MESSAGE_LEN = $max_panic_size - f.0.len();
|
|
}
|
|
}
|
|
|
|
core::arch::wasm32::unreachable()
|
|
}
|
|
};
|
|
}
|
|
|
|
#[cfg(feature = "log")]
|
|
pub struct Logger;
|
|
|
|
#[cfg(feature = "log")]
|
|
impl log::Log for Logger {
|
|
fn enabled(&self, _: &log::Metadata) -> bool {
|
|
true
|
|
}
|
|
|
|
fn log(&self, record: &log::Record) {
|
|
if self.enabled(record.metadata()) {
|
|
const MAX_LOG_MESSAGE: usize = 1024 * 8;
|
|
#[no_mangle]
|
|
static mut LOG_MESSAGES: [u8; MAX_LOG_MESSAGE] = [0; MAX_LOG_MESSAGE];
|
|
#[no_mangle]
|
|
static mut LOG_MESSAGES_LEN: usize = 0;
|
|
|
|
unsafe {
|
|
use core::fmt::Write;
|
|
let mut f = Write(&mut LOG_MESSAGES[LOG_MESSAGES_LEN..]);
|
|
_ = writeln!(f, "{}", record.args());
|
|
LOG_MESSAGES_LEN = MAX_LOG_MESSAGE - f.0.len();
|
|
}
|
|
}
|
|
}
|
|
|
|
fn flush(&self) {}
|
|
}
|
|
|
|
pub struct ArenaAllocator<const SIZE: usize> {
|
|
arena: UnsafeCell<[u8; SIZE]>,
|
|
head: UnsafeCell<*mut u8>,
|
|
}
|
|
|
|
impl<const SIZE: usize> ArenaAllocator<SIZE> {
|
|
#[expect(clippy::new_without_default)]
|
|
pub const fn new() -> Self {
|
|
ArenaAllocator {
|
|
arena: UnsafeCell::new([0; SIZE]),
|
|
head: UnsafeCell::new(core::ptr::null_mut()),
|
|
}
|
|
}
|
|
|
|
#[expect(clippy::missing_safety_doc)]
|
|
pub unsafe fn reset(&self) {
|
|
(*self.head.get()) = self.arena.get().cast::<u8>().add(SIZE);
|
|
}
|
|
|
|
pub fn used(&self) -> usize {
|
|
unsafe { self.arena.get() as usize + SIZE - (*self.head.get()) as usize }
|
|
}
|
|
}
|
|
|
|
unsafe impl<const SIZE: usize> Sync for ArenaAllocator<SIZE> {}
|
|
|
|
unsafe impl<const SIZE: usize> GlobalAlloc for ArenaAllocator<SIZE> {
|
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
|
let size = layout.size();
|
|
let align = layout.align();
|
|
|
|
let until = self.arena.get() as *mut u8;
|
|
|
|
let new_head = (*self.head.get()).sub(size);
|
|
let aligned_head = (new_head as usize & !(align - 1)) as *mut u8;
|
|
debug_assert!(aligned_head.is_aligned_to(align));
|
|
|
|
if until > aligned_head {
|
|
return core::ptr::null_mut();
|
|
}
|
|
|
|
*self.head.get() = aligned_head;
|
|
aligned_head
|
|
}
|
|
|
|
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
|
|
/* lol */
|
|
}
|
|
}
|
|
|
|
pub struct Write<'a>(pub &'a mut [u8]);
|
|
|
|
impl core::fmt::Write for Write<'_> {
|
|
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
|
if let Some(m) = self.0.take_mut(..s.len()) {
|
|
m.copy_from_slice(s.as_bytes());
|
|
Ok(())
|
|
} else {
|
|
Err(core::fmt::Error)
|
|
}
|
|
}
|
|
}
|