...
This commit is contained in:
@@ -1,14 +1,14 @@
|
|||||||
global gc_init, gc_alloc
|
global gc_init, gc_alloc
|
||||||
extern alloc, free, printint, printstr, endl
|
extern printint, printstr, endl
|
||||||
|
|
||||||
section .bss
|
section .bss
|
||||||
alloc_list_head: resq 1
|
alloc_list_head: resq 1 ; metadata size: 24
|
||||||
free_list_head: resq 1
|
free_list_head: resq 1 ; metadata size: 16
|
||||||
stack_start: resq 1
|
stack_start: resq 1
|
||||||
|
|
||||||
section .data
|
section .data
|
||||||
gc_bytes_allocated: dq 0 ; bytes allocated since the last gc cycle
|
gc_bytes_allocated: dq 0 ; bytes allocated since the last gc cycle
|
||||||
gc_trigger_threshold: dq 1024 * 1024 * 8 ; initial gc trigger threshold in bytes (adjusts dynamically)
|
gc_trigger_threshold: dq 1024 * 1024 * 8 ; initial gc trigger threshold in bytes (adjusts dynamically)
|
||||||
gc_start_text: db "Running gc after ", 0
|
gc_start_text: db "Running gc after ", 0
|
||||||
gc_sweep_done_text: db " Sweep done. We no have ", 0
|
gc_sweep_done_text: db " Sweep done. We no have ", 0
|
||||||
gc_next_threshold: db " The next threshold is ", 0
|
gc_next_threshold: db " The next threshold is ", 0
|
||||||
@@ -21,24 +21,66 @@ gc_init:
|
|||||||
ret
|
ret
|
||||||
|
|
||||||
gc_alloc:
|
gc_alloc:
|
||||||
add rdi, 24
|
add rdi, 24 ; adjust for metadata size
|
||||||
mov rdx, [gc_bytes_allocated]
|
mov rdx, [gc_bytes_allocated]
|
||||||
cmp rdx, [gc_trigger_threshold]
|
cmp rdx, [gc_trigger_threshold]
|
||||||
jb .skip_collect ; if allocated bytes since last collect has exceeded threshold, trigger collect
|
jbe .alloc ; if allocated bytes since last collect has exceeded threshold, trigger collect
|
||||||
push rdi
|
push rdi
|
||||||
call gc_collect
|
call gc_collect
|
||||||
pop rdi
|
pop rdi
|
||||||
.skip_collect:
|
.alloc:
|
||||||
add [gc_bytes_allocated], rdi
|
add [gc_bytes_allocated], rdi ; adjust allocated bytes list
|
||||||
|
mov rsi, [free_list_head]
|
||||||
|
xor r8, r8
|
||||||
|
.loop:
|
||||||
|
test rsi, rsi
|
||||||
|
jz .new_block ; allocate new block if at end of list
|
||||||
|
mov rdx, [rsi]
|
||||||
|
cmp rdi, rdx
|
||||||
|
jbe .use_block ; use block if object fits within block
|
||||||
|
mov r8, rsi ; load r8 with current node
|
||||||
|
mov rsi, [rsi + 8] ; load next node
|
||||||
|
jmp .loop
|
||||||
|
.new_block:
|
||||||
push rdi
|
push rdi
|
||||||
call alloc ; allocate size + metadata
|
push r8
|
||||||
|
mov rsi, 4096
|
||||||
|
call max ; calculate size of allocation (max(input, 4096))
|
||||||
|
mov rdi, rax
|
||||||
|
push rdi
|
||||||
|
call sys_mmap
|
||||||
|
pop rsi
|
||||||
|
sub rsi, 16
|
||||||
|
mov qword [rax], rsi ; update metadata to page size - metadata
|
||||||
|
push rax
|
||||||
|
mov rdi, rax
|
||||||
|
call insert_into_free
|
||||||
|
pop rsi
|
||||||
|
pop r8
|
||||||
pop rdi
|
pop rdi
|
||||||
mov byte [rax], 0 ; set mark to 0
|
.use_block:
|
||||||
mov qword [rax + 8], rdi ; set total size of object (including metadata)
|
cmp [rsi], rdi ; check if the block will be empty after allocation
|
||||||
mov rsi, [alloc_list_head] ; load first item in allocation list
|
ja .unlink_done ; if not, do not unlink
|
||||||
mov qword [rax + 16], rsi ; make current head of allocation list the next item in this object
|
test r8, r8 ; r8 is null if node is also head
|
||||||
mov [alloc_list_head], rax ; update head of allocation list so it points to this object
|
jz .unlink_head
|
||||||
add rax, 24 ; skip metadata for return value
|
mov rdx, [rsi + 8] ; load next node
|
||||||
|
mov [r8 + 8], rdx ; link next node to last node's next
|
||||||
|
jmp .unlink_done
|
||||||
|
.unlink_head:
|
||||||
|
mov rdx, [free_list_head] ; load head
|
||||||
|
mov rdx, [rdx + 8] ; load head.next
|
||||||
|
mov [free_list_head], rdx ; mov head.next into head
|
||||||
|
.unlink_done:
|
||||||
|
sub [rsi], rdi ; reduce available space of block by the allocated space
|
||||||
|
mov rdx, [rsi] ; load the available space excluding the newly allocated space
|
||||||
|
lea rax, [rsi + rdx + 16] ; load the address of the newly allocated space
|
||||||
|
mov byte [rax], 0 ; update mark to 0
|
||||||
|
sub rdi, 24
|
||||||
|
mov [rax + 8], rdi ; update metadata size to allocation size - metadata
|
||||||
|
mov rdx, [alloc_list_head]
|
||||||
|
mov [rax + 16], rdx
|
||||||
|
mov [alloc_list_head], rax ; append this allocation to the head of allocation list
|
||||||
|
lea rax, [rax + 24] ; skip past metadata for return value
|
||||||
ret
|
ret
|
||||||
|
|
||||||
gc_collect:
|
gc_collect:
|
||||||
@@ -82,7 +124,7 @@ gc_collect:
|
|||||||
call endl
|
call endl
|
||||||
ret
|
ret
|
||||||
|
|
||||||
gc_mark_stack:
|
gc_mark_stack:
|
||||||
mov r8, rsp ; load current stack pointer
|
mov r8, rsp ; load current stack pointer
|
||||||
mov r9, [stack_start] ; load start of stack
|
mov r9, [stack_start] ; load start of stack
|
||||||
.loop:
|
.loop:
|
||||||
@@ -96,68 +138,124 @@ gc_mark_stack:
|
|||||||
ret
|
ret
|
||||||
|
|
||||||
gc_mark:
|
gc_mark:
|
||||||
test rdi, rdi ; is input null?
|
test rdi, rdi ; is input null?
|
||||||
jz .done ; yes? return
|
jz .done ; yes? return
|
||||||
mov rsi, [alloc_list_head] ; load start of allocation list
|
mov rsi, [alloc_list_head] ; load start of allocation list
|
||||||
.loop:
|
.loop:
|
||||||
test rsi, rsi ; reached end of list?
|
test rsi, rsi ; reached end of list?
|
||||||
jz .done ; yes? return
|
jz .done ; yes? return
|
||||||
lea rdx, [rsi + 24]
|
lea rdx, [rsi + 24]
|
||||||
cmp rdx, rdi ; no? is this the input object?
|
cmp rdx, rdi ; no? is this the input object?
|
||||||
je .mark_object ; yes? mark it
|
je .mark_object ; yes? mark it
|
||||||
mov rsi, [rsi + 16] ; no? next item
|
mov rsi, [rsi + 16] ; no? next item
|
||||||
jmp .loop
|
jmp .loop
|
||||||
.mark_object:
|
.mark_object:
|
||||||
mov al, [rdi] ; load mark
|
mov al, [rdi] ; load mark
|
||||||
test al, al ; already marked?
|
test al, al ; already marked?
|
||||||
jnz .done ; yes? return
|
jnz .done ; yes? return
|
||||||
mov byte [rdi - 24], 1 ; mark object
|
mov byte [rdi - 24], 1 ; mark object
|
||||||
mov rcx, [rdi + 8] ; load object size
|
mov rcx, [rdi + 8] ; load object size
|
||||||
mov rdx, rdi ; start of data
|
mov rdx, rdi ; start of data
|
||||||
add rcx, rdx ; end of data
|
add rcx, rdx ; end of data
|
||||||
.scan_object:
|
.scan_object:
|
||||||
cmp rdx, rcx ; done scanning?
|
cmp rdx, rcx ; done scanning?
|
||||||
jae .done ; yes? return
|
jae .done ; yes? return
|
||||||
mov rdi, [rdx] ; load value
|
mov rdi, [rdx] ; load value
|
||||||
call gc_mark
|
call gc_mark
|
||||||
add rdx, 8 ; next object
|
add rdx, 8 ; next object
|
||||||
jmp .scan_object
|
jmp .scan_object
|
||||||
.done:
|
.done:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
gc_sweep:
|
gc_sweep:
|
||||||
mov rdi, [alloc_list_head]
|
mov rdi, [alloc_list_head]
|
||||||
xor rsi, rsi
|
xor r8, r8
|
||||||
.loop:
|
.loop:
|
||||||
test rdi, rdi ; reached end of list?
|
test rdi, rdi ; reached end of list?
|
||||||
jz .done ; yes? return
|
jz .done ; yes? return
|
||||||
mov al, [rdi]
|
mov al, [rdi]
|
||||||
test al, al ; is object marked?
|
test al, al
|
||||||
jz .unmarked ; no? free it
|
jz .unmarked ; if unmarked, free object
|
||||||
mov byte [rdi], 0 ; yes? clear mark for next marking
|
mov byte [rdi], 0 ; unmark object
|
||||||
mov rsi, rdi
|
mov r8, rdi
|
||||||
mov rdi, [rdi + 16] ; load the next object in the list
|
mov rdi, [rdi + 16] ; next item
|
||||||
jmp .loop ; repeat
|
|
||||||
.unmarked:
|
|
||||||
mov rdx, [rdi + 16] ; save address of next object in list
|
|
||||||
test rsi, rsi
|
|
||||||
jz .remove_head
|
|
||||||
mov [rsi + 16], rdx ; unlink the current node by setting the previous node's next to the next node's address
|
|
||||||
jmp .free
|
|
||||||
.remove_head:
|
|
||||||
mov [alloc_list_head], rdx ; update head node to be the next node
|
|
||||||
.free:
|
|
||||||
push rsi ; save previous node since it will also be the previous node for the next item
|
|
||||||
push rdx ; save next node
|
|
||||||
mov rdx, [rdi + 8] ; load the size of the object
|
|
||||||
sub [gc_bytes_allocated], rdx ; adjust allocated bytes
|
|
||||||
call free ; free the memory
|
|
||||||
pop rdi ; input for next iteration
|
|
||||||
pop rsi ; prev node for next iteration
|
|
||||||
jmp .loop
|
jmp .loop
|
||||||
.done:
|
.done:
|
||||||
ret
|
ret
|
||||||
|
.unmarked:
|
||||||
|
mov r9, [rdi + 16] ; save address of next object in list
|
||||||
|
test r8, r8
|
||||||
|
jz .unlink_head ; if current is head, unlink head
|
||||||
|
mov [r8 + 16], r9 ; unlink the current node by setting the previous node's next to the next node's address
|
||||||
|
jmp .unlink_done
|
||||||
|
.unlink_head:
|
||||||
|
mov [alloc_list_head], r9 ; update head node to be the next node
|
||||||
|
.unlink_done:
|
||||||
|
push r8 ; save previous node since it will also be the previous node for the next item
|
||||||
|
push r9 ; save next node
|
||||||
|
mov rdx, [rdi + 8] ; load the size of the object
|
||||||
|
add rdx, 24 ; adjust for metadata size
|
||||||
|
sub [gc_bytes_allocated], rdx ; adjust allocated bytes
|
||||||
|
call insert_into_free
|
||||||
|
pop rdi ; input for next iteration
|
||||||
|
pop r8 ; prev node for next iteration
|
||||||
|
jmp .loop
|
||||||
|
|
||||||
|
insert_into_free:
|
||||||
|
mov rsi, [free_list_head] ; rsi will track the current node
|
||||||
|
test rsi, rsi
|
||||||
|
jz .insert_head ; if list is empty, insert at head
|
||||||
|
cmp rdi, rsi
|
||||||
|
jb .insert_head ; is input is smaller than head, insert at head
|
||||||
|
.loop:
|
||||||
|
mov r9, [rsi + 8] ; load next node
|
||||||
|
test r9, r9
|
||||||
|
jz .insert_tail ; if at end of the list, insert at tail
|
||||||
|
cmp rdi, r9
|
||||||
|
ja .next ; if input > next continue
|
||||||
|
mov [rdi + 8], r9
|
||||||
|
mov [rsi + 8], rdi ; insert node between current and next
|
||||||
|
ret
|
||||||
|
.insert_head:
|
||||||
|
mov [rdi + 8], rsi ; set old head to input.next
|
||||||
|
mov [free_list_head], rdi ; set head to input
|
||||||
|
ret
|
||||||
|
.insert_tail:
|
||||||
|
mov qword [rdi + 8], 0 ; set input.tail to null
|
||||||
|
mov [rsi + 8], rdi ; add input to current.next
|
||||||
|
ret
|
||||||
|
.next:
|
||||||
|
mov rsi, r9
|
||||||
|
jmp .loop
|
||||||
|
|
||||||
|
sys_mmap:
|
||||||
|
mov rax, 9
|
||||||
|
mov rsi, rdi
|
||||||
|
mov rdi, 0
|
||||||
|
mov rdx, 3
|
||||||
|
mov r10, 34
|
||||||
|
mov r8, -1
|
||||||
|
mov r9, 0
|
||||||
|
syscall
|
||||||
|
cmp rax, -1
|
||||||
|
je .error
|
||||||
|
ret
|
||||||
|
.error:
|
||||||
|
mov rax, 60
|
||||||
|
mov rdi, 1
|
||||||
|
syscall
|
||||||
|
|
||||||
|
sys_munmap:
|
||||||
|
mov rax, 11
|
||||||
|
syscall
|
||||||
|
cmp rax, -1
|
||||||
|
je .error
|
||||||
|
ret
|
||||||
|
.error:
|
||||||
|
mov rax, 60
|
||||||
|
mov rdi, 1
|
||||||
|
syscall
|
||||||
|
|
||||||
max:
|
max:
|
||||||
cmp rdi, rsi
|
cmp rdi, rsi
|
||||||
jae .left
|
jae .left
|
||||||
|
|||||||
Reference in New Issue
Block a user