From 928e9b8acbce246738ed7ed63c1792d9e78f78e0 Mon Sep 17 00:00:00 2001 From: nub31 Date: Sun, 2 Feb 2025 21:46:18 +0100 Subject: [PATCH] Document gc better --- input/baseline/gc.asm | 77 ++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 48 deletions(-) diff --git a/input/baseline/gc.asm b/input/baseline/gc.asm index f1c14a9..78802f2 100644 --- a/input/baseline/gc.asm +++ b/input/baseline/gc.asm @@ -6,7 +6,7 @@ section .bss total_alloc: resq 1 section .data - gc_threshold: dq 4096 ; default of 4096 bytes, this will scale when gc_collect is ran + gc_threshold: dq 4096 ; default of 4096 bytes, this will scale when gc_collect is ran section .text gc_init: @@ -34,46 +34,14 @@ gc_alloc: add rax, 17 ; skip metadata for return value ret -; Generated by chatgpt. Rewrite this later -; TODO: refactor to unlink easier -gc_free: - mov rsi, [alloc_list] ; Load head of allocation list - test rsi, rsi ; Check if list is empty - jz .not_found ; If empty, nothing to free - cmp rsi, rdi ; Is the first item the one to free? - je .remove_head ; If so, update head directly -.loop: - mov rdx, [rsi + 9] ; Load next item in list - test rdx, rdx ; Check if end of list - jz .not_found ; If not found, return - cmp rdx, rdi ; Is this the item to remove? - je .remove_item ; If so, unlink it - mov rsi, rdx ; Move to next item - jmp .loop ; Repeat -.remove_head: - mov rdx, [rdi + 9] ; Get next item - mov [alloc_list], rdx ; Update head of list - jmp .free_memory ; Free the object -.remove_item: - mov rdx, [rdi + 9] ; Get next item - mov [rsi + 9], rdx ; Bypass rdi in the list -.free_memory: - mov rsi, [rdi + 1] ; Get object size - sub [total_alloc], rsi ; save total allocation - call sys_munmap ; Free memory - ret -.not_found: - ret ; Item not found, do nothing - gc_collect: call gc_mark_stack call gc_sweep - ; next threshold will be double of used memory or 4096, whichever is higher - mov rdi, [total_alloc] - shl rdi, 1 + mov rdi, [total_alloc] ; since we just swept, all the memory is in use + shl rdi, 1 ; double the currently used memory mov rsi, 4096 - call max - mov qword [gc_threshold], rax + call max ; get the largest of total_alloc * 2 and 4096 + mov qword [gc_threshold], rax ; update threshold to new value ret gc_mark_stack: @@ -121,20 +89,33 @@ gc_mark: gc_sweep: mov rdi, [alloc_list] + xor rsi, rsi .loop: - test rdi, rdi ; reached end of list? - jz .done ; yes? return + test rdi, rdi ; reached end of list? + jz .done ; yes? return mov al, [rdi] - test al, al ; is object marked? - jz .free ; no? free it - mov byte [rdi], 0 ; yes? clear mark for next scan - mov rdi, [rdi + 9] ; load the next object in the list - jmp .loop ; repeat + test al, al ; is object marked? + jz .free ; no? free it + mov byte [rdi], 0 ; yes? clear mark for next marking + mov rsi, rdi + mov rdi, [rdi + 9] ; load the next object in the list + jmp .loop ; repeat .free: - mov rcx, [rdi + 9] ; save address of next object in list - push rcx - call gc_free - pop rdi ; [rdi + 9] is deallocated now, and would throw a segfault unless we used the stack + mov rdx, [rdi + 9] ; save address of next object in list + test rsi, rsi + jz .remove_head + mov [rsi + 9], rdx ; unlink the current node by setting the previous node's next to the next node's address + jmp .free_memory +.remove_head: + mov [alloc_list], rdx ; update head node to be the next node +.free_memory + push rsi ; save previous node since it will also be the previous node for the next item + push rdx ; save next node + mov rsi, [rdi + 1] ; get length of the object + sub [total_alloc], rsi ; remove this allocation from total allocations + call sys_munmap ; free the memory + pop rdi ; input for next iteration + pop rsi ; prev node for next iteration jmp .loop .done: ret