Document gc better

This commit is contained in:
nub31
2025-02-02 21:46:18 +01:00
parent 006fedba37
commit 928e9b8acb

View File

@@ -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