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 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
use settings::AllocSettings; use std::alloc::{GlobalAlloc, Layout, AllocInit}; pub mod settings { use crate::mem::*; pub trait AllocSettings { fn allocator_addr<T: Sized>() -> usize; fn allocation_start_address<T: Sized>() -> isize; } pub struct Logic; pub struct Graphics; impl AllocSettings for Logic { fn allocator_addr<T: Sized>() -> usize { ALLOCATOR } fn allocation_start_address<T: Sized>() -> isize { LOGIC_HEAP as isize } } impl AllocSettings for Graphics { fn allocator_addr<T: Sized>() -> usize { ALLOCATOR + std::mem::size_of::<T>() } fn allocation_start_address<T: Sized>() -> isize { GRAPHICS_HEAP as isize } } } pub trait MutableAlloc { unsafe fn alloc(&mut self, layout: Layout, init: AllocInit) -> *mut u8; unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); } pub struct SimpleAllocator { pos: usize, } impl SimpleAllocator { fn layout_to_size(layout: Layout) -> usize { let (size, align) = (layout.size(), layout.align()); let overhead = size % align; size + (if overhead == 0 { 0 } else { align - overhead }) } pub fn new(pos: usize) -> Self { Self { pos } } } impl MutableAlloc for SimpleAllocator { unsafe fn alloc(&mut self, layout: Layout, init: AllocInit) -> *mut u8 { let size = Self::layout_to_size(layout); let pos = self.pos; self.pos += size; pos as *mut u8 } #[allow(unused_variables)] unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {} } pub trait Initial<T> { unsafe fn init() -> T { std::mem::zeroed() } } pub struct ZeroedInitial; impl<T> Initial<T> for ZeroedInitial {} pub struct Allocator<M, S: AllocSettings, I: Initial<M>>( pub std::marker::PhantomData<M>, pub std::marker::PhantomData<S>, pub std::marker::PhantomData<I>, ); impl<M: Sized + 'static, S: AllocSettings, I: Initial<M>> Allocator<M, S, I> { fn allocator() -> &'static mut M { unsafe { &mut *(S::allocator_addr::<M>() as *mut M) } } pub unsafe fn reset(&self) { *Self::allocator() = I::init(); } } use wasm_bindgen::prelude::*; #[wasm_bindgen] extern "C" { #[wasm_bindgen(js_namespace = console, js_name = debug)] fn console_debug_u32(il: bool, a: u32, b: u32, s: u32, e: u32, f: u32); #[wasm_bindgen(js_namespace = console, js_name = error)] fn console_error_u32(a: u32, b: u32, s: u32, e: u32); } unsafe impl<M: MutableAlloc + Sized + 'static, S: AllocSettings, I: Initial<M>> GlobalAlloc for Allocator<M, S, I> { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { let out = Self::allocator().alloc(layout, AllocInit::Uninitialized); let tout = out as usize as u32; let size = SimpleAllocator::layout_to_size(layout) as u32; let start = S::allocation_start_address::<M>() as usize as u32; let heaplen: u32 = env!("WEE_ALLOC_STATIC_ARRAY_BACKEND_BYTES") .parse() .unwrap(); if tout + size > start + heaplen || tout < start { console_error_u32(size, start, start + heaplen, tout); } out } unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { Self::allocator().dealloc(ptr, layout) } } impl<A: GlobalAlloc> MutableAlloc for A { unsafe fn alloc(&mut self, layout: Layout, init: AllocInit) -> *mut u8 { <Self as GlobalAlloc>::alloc(self, layout) } unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { <Self as GlobalAlloc>::dealloc(self, ptr, layout) } } #[macro_export] macro_rules! create_allocator { ($name:ident,$method:ty,$setting:ty,$v:expr) => { struct __Initial; impl Initial<$method> for __Initial { unsafe fn init() -> $method { $v } } #[global_allocator] static $name: Allocator<$method, $setting, __Initial> = Allocator( std::marker::PhantomData, std::marker::PhantomData, std::marker::PhantomData, ); }; ($name:ident,$method:ty,$setting:ty) => { #[global_allocator] static $name: Allocator<$method, $setting, NaiveInitial> = Allocator( std::marker::PhantomData, std::marker::PhantomData, std::marker::PhantomData, ); }; } use crate::wasm_log::WasmLog; pub unsafe fn reset_heap<M: Sized + 'static, S: AllocSettings, I: Initial<M>>( alloc: &Allocator<M, S, I>, log_level_filter: log::LevelFilter, ) { alloc.reset(); log::set_boxed_logger(Box::new(WasmLog::new())) .map(|()| log::set_max_level(log_level_filter)) .unwrap(); }