bump allocator

This commit is contained in:
janis 2025-10-28 20:40:25 +01:00
parent 5f63d4303e
commit 6a6af53667
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
4 changed files with 225 additions and 3 deletions

View file

@ -1,7 +1,7 @@
# Makefile: Compile and link main.asm using nasm and mold, intermediate files in target/
TARGET_DIR := target
SRC := src/lib.asm src/int_to_str.asm src/vec.asm src/tokeniser.asm src/file.asm
SRC := src/lib.asm src/int_to_str.asm src/vec.asm src/tokeniser.asm src/file.asm src/alloc.asm
OBJ := $(patsubst src/%.asm,$(TARGET_DIR)/%.o,$(SRC))
BIN_SRC := src/main.asm src/panic.asm

153
lang/src/alloc.asm Normal file
View file

@ -0,0 +1,153 @@
default rel
section .bss
align 8
free_list: resb 40
section .text
extern memcpy
extern memswap
extern oom
extern panic
extern eprint_error
extern allocate
extern vec_init
extern vec_push
extern vec_get
global bump_init
global bump_alloc
;; rdi: number of bytes to allocate
;; fn mmap(length: usize) -> *mut u8 {
mmap_alloc:
push rbp
mov rbp, rsp
call allocate
pop rbp
ret
bump_init:
push rbp
mov rbp, rsp
lea rdi, [rel free_list]
mov rsi, 16
mov rdx, 0
call vec_init
pop rbp
ret
;; rdi: min_size
bump_new_block:
push rbp
mov rbp, rsp
cmp rdi, 4096
ja .mmap
mov rdi, 4096
.mmap:
; next power of 2
lea rax, [rdi - 1]
lzcnt rax, rax
mov rdx, -1
shrx rdx, rdx, rax
inc rdx
mov rdi, rdx
push rdi
call mmap_alloc
pop rdi
; Add to free list
sub rsp, 0x10
mov [rsp], rax
mov [rsp + 8], rdi
lea rdi, [rel free_list]
mov rsi, rsp
mov rdx, 0x10
call vec_push
add rsp, 0x10
pop rbp
ret
;; rdi: number of bytes to allocate
;; rsi: alignment
bump_alloc:
push rbp
mov rbp, rsp
push r12
push r13
sub rsp, 0x28
mov [rsp], rdi ; size
mov [rsp + 8], rsi ; alignment
lea rdi, [rel free_list]
mov r12, [rdi + 8]
xor r13, r13
.alloc_loop:
cmp r13, r12
jae .no_block
lea rdi, [rel free_list]
mov rsi, r13
call vec_get
mov [rsp + 32], rax ; block entry ptr
mov rdx, [rax]
mov [rsp + 16], rdx ; block_ptr
mov rax, [rax + 8] ; block_size
mov [rsp + 24], rax
; check for space
; block_ptr.next_multiple_of(alignment) + size <= block_ptr + block_size
mov rcx, [rsp + 8] ; alignment
; let ptr = block_ptr | alignment
or rax, rcx ; align up
xor rdx, rdx ; clear high qword
; let rem = ptr % alignment
div rcx
; let diff = alignment - rem
sub rcx, rdx
mov rax, [rsp + 16] ; block+ptr
; let aligned_ptr = block_ptr + diff
add rax, rcx
; let aligned_end = aligned_ptr + size
add rax, [rsp] ; size
; let block_end = block_ptr + block_size
mov rdx, [rsp + 16] ; block_ptr
add rdx, [rsp + 24] ; block_ptr + block_size
; if aligned_end <= block_end
cmp rax, rdx
jle .found_space
; else try next block
inc r13
jmp .alloc_loop
.no_block:
; allocate new block
mov rdi, [rsp] ; size
call bump_new_block
lea r13, [rel free_list]
mov r13, [r13 + 8] ; new block index
mov r12, r13
dec r13
jmp .alloc_loop
.found_space:
sub rdx, rax ; remaining size in block
mov r13, [rsp + 32] ; block entry ptr
mov [r13], rax
mov rax, [rsp + 24] ; block_size
sub rax, rdx
mov [r13 + 8], rax
mov rax, [r13]
add rsp, 0x28
pop r13
pop r12
pop rbp
ret

69
lang/tests/bump.rs Normal file
View file

@ -0,0 +1,69 @@
#![feature(allocator_api, box_as_ptr)]
#[unsafe(no_mangle)]
extern "C" fn panic() -> ! {
panic!("Called panic from external code.");
}
unsafe extern "C" {
unsafe fn bump_init();
unsafe fn bump_alloc(size: usize, align: usize) -> *mut u8;
}
struct BumpAllocator;
unsafe impl std::alloc::Allocator for BumpAllocator {
fn allocate(
&self,
layout: std::alloc::Layout,
) -> Result<std::ptr::NonNull<[u8]>, std::alloc::AllocError> {
unsafe {
let ptr = bump_alloc(layout.size(), layout.align());
if ptr.is_null() {
Err(std::alloc::AllocError)
} else {
Ok(std::ptr::NonNull::slice_from_raw_parts(
std::ptr::NonNull::new_unchecked(ptr),
layout.size(),
))
}
}
}
unsafe fn deallocate(&self, _ptr: std::ptr::NonNull<u8>, _layout: std::alloc::Layout) {
// Bump allocator does not deallocate individual allocations
}
}
fn main() {
unsafe {
bump_init();
}
let a = Box::new_in(42u32, BumpAllocator);
let b = Box::new_in(42u32, BumpAllocator);
let c = Box::new_in(52u32, BumpAllocator);
eprintln!("a: {a}, b: {b}, c: {c}");
assert_ne!(Box::as_ptr(&a), Box::as_ptr(&b));
assert_eq!(*a, *b);
struct BigType {
data: [u8; 0x1010],
}
let mut big = Box::new_in(BigType { data: [0; 0x1010] }, BumpAllocator);
assert_ne!(Box::as_ptr(&big) as *const (), Box::as_ptr(&a) as *const ());
big.data[47] = 123;
assert_eq!(big.data[47], 123);
#[repr(align(256))]
struct AlignedType {
data: [u8; 512],
}
let aligned = Box::new_in(AlignedType { data: [0; 512] }, BumpAllocator);
assert_eq!(
(Box::as_ptr(&aligned) as usize) % 256,
0,
"Aligned allocation should be aligned to 256 bytes"
);
}

View file

@ -215,13 +215,13 @@ fn main() {
assert_eq!(
&collect_tokens()[..],
&[[
&[
Lexeme(32, "\"this is a string\""),
Lexeme(32, "\"another\nstring\nspanning multiple\n lines\""),
Lexeme(32, "\"string with a \\\"quoted\\\" word\""),
Lexeme(32, "\"a\""),
Lexeme(32, "\"\"")
],]
],
);
eprintln!("Finished tokenising.");