From 774dcfa995c8dae36c9013b947eca8a1b18afe1c Mon Sep 17 00:00:00 2001 From: nub31 Date: Tue, 4 Feb 2025 11:47:25 +0100 Subject: [PATCH] ... --- input/baseline/gc.asm | 130 ++++++++++++------ input/program.nub | 4 +- input/util.asm | 311 ++++++++++++++++++++++++++++++++++++++++++ output/build.sh | 5 +- 4 files changed, 407 insertions(+), 43 deletions(-) create mode 100644 input/util.asm diff --git a/input/baseline/gc.asm b/input/baseline/gc.asm index cc91e5f..56bf7e5 100644 --- a/input/baseline/gc.asm +++ b/input/baseline/gc.asm @@ -1,13 +1,19 @@ global gc_init, gc_alloc -extern alloc, free +extern alloc, free, printint, printstr, endl section .bss - alloc_list: resq 1 ; head of alloc list - stack_start: resq 1 ; start of stack + alloc_list_head: resq 1 + free_list_head: resq 1 + stack_start: resq 1 section .data - gc_threshold_c: dq 1024 ; default of 1024 allocations - total_alloc_c: dq 0 ; count the amount of allocations + 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_start_text: db "Running gc after ", 0 + gc_sweep_done_text: db " Sweep done. We no have ", 0 + gc_next_threshold: db " The next threshold is ", 0 + gc_allocated_bytes: db " allocated bytes", 0 + gc_mark_done_text: db " Marking done", 0 section .text gc_init: @@ -15,30 +21,65 @@ gc_init: ret gc_alloc: - add rdi, 24 ; add space for metadata - mov rdx, [total_alloc_c] ; load total allocation count - cmp rdx, [gc_threshold_c] ; has count exceeded threshold? - jb .skip_collect ; yes? run gc + add rdi, 24 + mov rdx, [gc_bytes_allocated] + cmp rdx, [gc_trigger_threshold] + jb .skip_collect ; if allocated bytes since last collect has exceeded threshold, trigger collect push rdi call gc_collect pop rdi .skip_collect: - inc qword [total_alloc_c] ; update total allocation count + add [gc_bytes_allocated], rdi push rdi - call alloc ; allocate size + metadata + call alloc ; allocate size + metadata pop rdi - mov byte [rax], 0 ; set mark to 0 - mov qword [rax + 8], rdi ; set total size of object (including metadata) - mov rsi, [alloc_list] ; load first item in allocation list - mov qword [rax + 16], rsi ; make current head of allocation list the next item in this object - mov [alloc_list], rax ; update head of allocation list so it points to this object - add rax, 24 ; skip metadata for return value + mov byte [rax], 0 ; set mark to 0 + mov qword [rax + 8], rdi ; set total size of object (including metadata) + mov rsi, [alloc_list_head] ; load first item in allocation list + mov qword [rax + 16], rsi ; make current head of allocation list the next item in this object + mov [alloc_list_head], rax ; update head of allocation list so it points to this object + add rax, 24 ; skip metadata for return value ret gc_collect: + mov rdi, gc_start_text + call printstr + mov rdi, [gc_bytes_allocated] + call printint + mov rdi, gc_allocated_bytes + call printstr + call endl + call gc_mark_stack + + mov rdi, gc_mark_done_text + call printstr + call endl + call gc_sweep - mov qword [total_alloc_c], 0 ; reset allocation count + + mov rdi, gc_sweep_done_text + call printstr + mov rdi, [gc_bytes_allocated] + call printint + mov rdi, gc_allocated_bytes + call printstr + call endl + + mov rdi, [gc_bytes_allocated] + shl rdi, 1 + mov rsi, 1024 * 1024 * 8 + call max + mov [gc_trigger_threshold], rax + mov qword [gc_bytes_allocated], 0 + + mov rdi, gc_next_threshold + call printstr + mov rdi, [gc_trigger_threshold] + call printint + mov rdi, gc_allocated_bytes + call printstr + call endl ret gc_mark_stack: @@ -57,7 +98,7 @@ gc_mark_stack: gc_mark: test rdi, rdi ; is input null? jz .done ; yes? return - mov rsi, [alloc_list] ; load start of allocation list + mov rsi, [alloc_list_head] ; load start of allocation list .loop: test rsi, rsi ; reached end of list? jz .done ; yes? return @@ -85,32 +126,43 @@ gc_mark: ret gc_sweep: - mov rdi, [alloc_list] + mov rdi, [alloc_list_head] 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 marking + test al, al ; is object marked? + jz .unmarked ; no? free it + mov byte [rdi], 0 ; yes? clear mark for next marking mov rsi, rdi - mov rdi, [rdi + 16] ; load the next object in the list - jmp .loop ; repeat -.free: - mov rdx, [rdi + 16] ; save address of next object in list + mov rdi, [rdi + 16] ; load the next object in the list + 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_memory + 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], 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 - call free ; free the memory - pop rdi ; input for next iteration - pop rsi ; prev node for next iteration + 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 .done: - ret \ No newline at end of file + ret + +max: + cmp rdi, rsi + jae .left + mov rax, rsi + ret +.left: + mov rax, rdi + ret diff --git a/input/program.nub b/input/program.nub index a851190..158635c 100644 --- a/input/program.nub +++ b/input/program.nub @@ -6,11 +6,9 @@ func main() { let x = new Human { name = "test", - age = i + age = 34958743 }; - println(x.age); - i = i + 1; } } diff --git a/input/util.asm b/input/util.asm new file mode 100644 index 0000000..fdce707 --- /dev/null +++ b/input/util.asm @@ -0,0 +1,311 @@ +;********************************************************************* +; util.asm +; Version: 1.2 +; Author: mjbrusso +; Contributors: AlessandroFonseca +; Licensed under the MIT license (see "license.txt"). +;********************************************************************* +global exit, exit0, strlen, atoi, endl, printstr, printint, readstr, readint + +SYS_READ: equ 0 +SYS_WRITE: equ 1 +SYS_EXIT: equ 60 + +STDIN: equ 0 +STDOUT: equ 1 + +LINEFEED: equ 0x0A + +section .text + +;********************************************************************* +; void exit(int64 code) +; +; Description: +; Quit program +; +; Arguments: +; rdi: int64 code: Exit code (0=Success, >0=Error) +; +; Returns: +; This function does not return +; +;********************************************************************* +exit: + mov rax, SYS_EXIT ; rax: system call number + syscall +;********************************************************************* + +;********************************************************************* +; void exit0() +; +; Description: +; Quit program with status code = 0 +; +; Arguments: +; None +; +; Returns: +; This function does not return +; +;********************************************************************* +exit0: + xor rdi, rdi ; rdi = 0 + jmp exit ; TCO: tail call optimization +;********************************************************************* + + +;********************************************************************* +; int64 strlen(char *s) +; +; Description: +; Calculates the length of string ( excluding the terminating null) +; +; Arguments: +; rdi: char *s: address of a null-terminated string (array of chars terminated by 0) +; +; Returns: +; rax: int64: string size +; +;********************************************************************* +strlen: + xor rax, rax ; rax=0; // reset counter +.loop: ; do{ + cmp byte [rdi], 0 ; if (*s==0); // If zero, skip loop + je strlen.end ; break; + inc rax ; rax++; // increment counter + inc rdi ; s++; // advance to the next char + jmp strlen.loop ; }while(true); +.end: + ret ; return rax; +;********************************************************************* + + +;********************************************************************* +; void itoa(int64 value, char *s) +; +; Description: +; Converts an integer to a null-terminated string. +; +; Arguments: +; rdi: int64 value: Integer value to convert. +; rsi: char *s: Memory address where to store the resulting string. +; +; Returns: +; rax: int64: string size +; +;********************************************************************* +itoa: + test rdi, rdi ; value = rdi + jz itoa.iszero ; value==0 has a direct solution + jns itoa.notneg ; if(value <0 ) + mov byte [rsi], '-' ; *s = '-' + neg rdi ; value = -value + inc rsi ; s++ +.notneg: + mov r9b, 1 ; bool leftzero=true + mov r10, 10 ; base = 10 + mov rcx, 1000000000000000000 ; divisor = 1000000000000000000 + mov r8, 19 ; cont = 19 // Will repeat 19 times +.loop: ; do{ + mov rax, rdi ; dividend[0..31] = value + xor rdx, rdx ; dividend[32..63] = 0 + idiv rcx ; rax=(rdx:rax)/rcx ; rdx=(rdx:rax)%rcx + test al, al ; digit = rax[0..7] + jnz itoa.notdigit0 ; if(digit!=0) + test r9b, r9b ; if(leftzero) + jnz itoa.nextdigit ; continue + jmp itoa.digit0 +.notdigit0: + xor r9b, r9b ; leftzero = false +.digit0: + add eax, 48 ; digit = '0' + digit + mov rdi, rdx ; value %= divisor + mov byte [rsi], al ; *p = digit + inc rsi ; p++ +.nextdigit: + mov rax, rcx ; dividend[0..31] = value + xor rdx, rdx ; dividend[32..63] = 0 + idiv r10 ; rax=(rdx:rax)/10 ; rdx=(rdx:rax)%10 + mov rcx, rax ; divisor /= 10 + dec r8 ; cont-- + jne itoa.loop ; }while(cont!=0) +.end: + mov byte [rsi], 0 ; *p = '\0' + ret +.iszero: + mov word [rsi], 0x0030 ; *p = "0" (x86 is little endian) + ret +;********************************************************************* + + +;********************************************************************* +; int64 atoi(char *s) +; +; Description: +; Convert string to integer. +; +; Arguments: +; rdi: char *s: Address of a null-terminated string (array of chars terminated by 0) +; +; Returns: +; rax: int64: integer value +;********************************************************************* +atoi: + push r12 ; r12 is callee saved + mov r12, rdi ; rdi is caller saved + call strlen + lea rdi, [r12+rax-1] ; char *p = &s[strlen(string)]; //scans string backward + xor rax, rax ; result value + mov rdx, 1 ; multiplier +.beginloop: + cmp rdi, r12 ; while(p>=s){ + jl atoi.end ; + xor rcx, rcx ; + mov cl, byte [rdi] ; cl = current char + cmp cl, '-' ; if(cl=='-') + jne atoi.notneg ; + neg rax ; rax=-rax + jmp atoi.end ; +.notneg: + cmp cl, '9' ; if(!isdigit(cl)) nextdigit + jg atoi.endloop ; + sub cl, '0' ; + jl atoi.endloop ; + imul rcx, rdx ; digit_value = current_char * multiplier + add rax, rcx ; result += digit_value + imul rdx, 10 ; multiplier *= 10 +.endloop: + dec rdi ; previous char //scans string backward + jmp atoi.beginloop ; } +.end: + pop r12 ; restore r12 + ret +;********************************************************************* + + +;********************************************************************* +; void endl() +; +; Description: +; Prints a newline (line break) +; +; Arguments: +; None +; +; Returns: +; Nothing +; +;********************************************************************* +endl: + lea rdi, [endl.str] ; print the string + call printstr + ret + +;********************************************************************* + + +;********************************************************************* +; void printstr(char *s) +; +; Description: +; Print a string +; +; Arguments: +; rdi: char *s: address of a null-terminated string (array of chars terminated by 0) +; +; Returns: +; Nothing +; +;********************************************************************* +printstr: + push r15 ; r15 is callee saved + mov r15, rdi ; save copy (rdi should be caller saved) + call strlen + mov rdx, rax ; string size + mov rsi, r15 ; string + mov rax, SYS_WRITE ; system call number + mov rdi, STDOUT ; file descriptor + syscall ; system call + pop r15 + ret +;********************************************************************* + + +;********************************************************************* +; void printint(int64 n) +; +; Description: +; Print integer number (decimal) +; +; Arguments: +; rdi: int64 n: Value to print +; +; Returns: +; Nothing +; +;********************************************************************* +printint: + sub rsp, 40 ; stack allocate a temp string + mov rsi, rsp ; rdi=value, rsi=&str[0] + call itoa + mov rdi, rsp ; rdi=&str[0] + call printstr ; print number + add rsp, 40 ; deallocate the string + ret +;********************************************************************* + + +;********************************************************************* +; int64 readstr(char *s, int64 maxsize) +; +; Description: +; Read up to *maxsize* chars from standard input into a string. +; +; Arguments: +; rdi: char *s: address of a string (array of chars) +; rsi: int64 maxsize: input size limit +; +; Returns: +; rax: int64: Number of characters read +; +;********************************************************************* +readstr: + mov r8, rdi ; copy of buffer address + mov rax, SYS_READ ; system call number + mov rdx, rsi ; pointer to buffer + mov rsi, rdi ; max size + mov rdi, STDIN ; file descriptor + syscall ; system call + dec rax ; removing trailing newline char + mov byte [r8+rax], 0 ; replace with '\0' + ret +;********************************************************************* + + +;********************************************************************* +; int64 readint() +; +; Description: +; Read int64 from standard input +; +; Arguments: +; None +; +; Returns: +; rax: int64: The value entered +; +;********************************************************************* +readint: + sub rsp, 40 ; char s[40] + mov rdi, rsp ; rdi = &s[0] + mov rsi, 21 ; max input size + call readstr ; read number as string + mov rdi, rsp ; + call atoi ; rax = atoi(s) + add rsp, 40 ; deallocate s from stack + ret +;********************************************************************* + +section .data +endl.str: db LINEFEED, 0 diff --git a/output/build.sh b/output/build.sh index 2de7f52..c5705fc 100755 --- a/output/build.sh +++ b/output/build.sh @@ -13,4 +13,7 @@ nasm -g -felf64 ../input/core/itoa.asm -o itoa.o # program nasm -g -felf64 out.asm -o out.o -ld -o out str_len.o arr_size.o itoa.o alloc.o gc.o str_cmp.o out.o +# tmp +nasm -g -felf64 ../input/util.asm -o util.o + +ld -o out out.o gc.o alloc.o str_cmp.o str_len.o arr_size.o itoa.o util.o