working kinda
This commit is contained in:
@@ -42,6 +42,8 @@ public class Generator
|
||||
{
|
||||
_builder.AppendLine("global _start");
|
||||
|
||||
_builder.AppendLine("extern gc_alloc");
|
||||
_builder.AppendLine("extern str_cmp");
|
||||
foreach (var externFuncDefinition in _definitions.OfType<ExternFuncDefinitionNode>())
|
||||
{
|
||||
_builder.AppendLine($"extern {externFuncDefinition.Name}");
|
||||
@@ -70,41 +72,6 @@ public class Generator
|
||||
|
||||
_builder.AppendLine("""
|
||||
|
||||
eb6e_alloc:
|
||||
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
|
||||
|
||||
eb6e_str_cmp:
|
||||
xor rdx, rdx
|
||||
.loop:
|
||||
mov al, [rsi + rdx]
|
||||
mov bl, [rdi + rdx]
|
||||
inc rdx
|
||||
cmp al, bl
|
||||
jne .not_equal
|
||||
cmp al, 0
|
||||
je .equal
|
||||
jmp .loop
|
||||
.not_equal:
|
||||
mov rax, 0
|
||||
ret
|
||||
.equal:
|
||||
mov rax, 1
|
||||
ret
|
||||
|
||||
eb6e_oob_error:
|
||||
mov rax, 60
|
||||
mov rdi, 139
|
||||
@@ -429,8 +396,8 @@ public class Generator
|
||||
private void GenerateArrayInitializer(ArrayInitializerNode arrayInitializer)
|
||||
{
|
||||
_builder.AppendLine($" mov rdi, {8 + arrayInitializer.Length * 8}");
|
||||
_builder.AppendLine(" call eb6e_alloc");
|
||||
_builder.AppendLine($" mov QWORD [rax], {arrayInitializer.Length}");
|
||||
_builder.AppendLine(" call gc_alloc");
|
||||
_builder.AppendLine($" mov qword [rax], {arrayInitializer.Length}");
|
||||
}
|
||||
|
||||
private void GenerateBinaryExpression(BinaryExpressionNode binaryExpression, LocalFunc func)
|
||||
@@ -506,7 +473,7 @@ public class Generator
|
||||
case StringType:
|
||||
_builder.AppendLine(" mov rdi, rax");
|
||||
_builder.AppendLine(" mov rsi, rcx");
|
||||
_builder.AppendLine(" call eb6e_str_cmp");
|
||||
_builder.AppendLine(" call str_cmp");
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(type));
|
||||
@@ -660,7 +627,7 @@ public class Generator
|
||||
}
|
||||
|
||||
_builder.AppendLine($" mov rdi, {structDefinition.Members.Count * 8}");
|
||||
_builder.AppendLine(" call eb6e_alloc");
|
||||
_builder.AppendLine(" call gc_alloc");
|
||||
_builder.AppendLine(" mov rcx, rax");
|
||||
|
||||
foreach (var initializer in structInitializer.Initializers)
|
||||
|
||||
@@ -91,20 +91,20 @@ public class SymbolTable
|
||||
{
|
||||
case IfNode ifStatement:
|
||||
{
|
||||
offset += ResolveBlockVariables(ifStatement.Body, variables, offset);
|
||||
offset = ResolveBlockVariables(ifStatement.Body, variables, offset);
|
||||
if (ifStatement.Else.HasValue)
|
||||
{
|
||||
ifStatement.Else.Value.Match
|
||||
(
|
||||
elseIfStatement => offset += ResolveBlockVariables(elseIfStatement.Body, variables, offset),
|
||||
elseStatement => offset += ResolveBlockVariables(elseStatement, variables, offset)
|
||||
elseIfStatement => offset = ResolveBlockVariables(elseIfStatement.Body, variables, offset),
|
||||
elseStatement => offset = ResolveBlockVariables(elseStatement, variables, offset)
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WhileNode whileStatement:
|
||||
{
|
||||
offset += ResolveBlockVariables(whileStatement.Body, variables, offset);
|
||||
offset = ResolveBlockVariables(whileStatement.Body, variables, offset);
|
||||
break;
|
||||
}
|
||||
case VariableAssignmentNode variableAssignment:
|
||||
|
||||
208
input/baseline/gc.asm
Normal file
208
input/baseline/gc.asm
Normal file
@@ -0,0 +1,208 @@
|
||||
global gc_init, gc_alloc, gc_free, gc_collect
|
||||
extern itoa
|
||||
extern str_len
|
||||
|
||||
section .bss
|
||||
alloc_list: resq 1
|
||||
stack_start: resq 1
|
||||
|
||||
; TMP
|
||||
|
||||
section .data
|
||||
newline: db 10, 0
|
||||
start_mark: db "Starting to mark", 0
|
||||
marked: db "Marked object", 0
|
||||
|
||||
; /TMP
|
||||
|
||||
section .text
|
||||
|
||||
; TMP
|
||||
|
||||
print_int:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
sub rsp, 8
|
||||
mov [rbp - 8], rdi
|
||||
mov rax, [rbp - 8]
|
||||
push rax
|
||||
pop rdi
|
||||
call itoa
|
||||
push rax
|
||||
pop rdi
|
||||
call print
|
||||
mov rdi, newline
|
||||
call print
|
||||
mov rsp, rbp
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
print:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
sub rsp, 8
|
||||
mov [rbp - 8], rdi
|
||||
mov rax, 1
|
||||
push rax
|
||||
mov rax, 1
|
||||
push rax
|
||||
mov rax, [rbp - 8]
|
||||
push rax
|
||||
mov rax, [rbp - 8]
|
||||
push rax
|
||||
pop rdi
|
||||
call str_len
|
||||
push rax
|
||||
pop rdx
|
||||
pop rsi
|
||||
pop rdi
|
||||
pop rax
|
||||
syscall
|
||||
mov rsp, rbp
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
; /TMP
|
||||
|
||||
gc_init:
|
||||
mov [stack_start], rsp
|
||||
ret
|
||||
|
||||
gc_alloc:
|
||||
add rdi, 17 ; add space for metadata
|
||||
push rdi
|
||||
call sys_mmap ; allocate size + metadata
|
||||
pop rdi
|
||||
mov byte [rax], 0 ; set mark to 0
|
||||
mov qword [rax + 1], rdi ; set total size of object (including metadata)
|
||||
mov rsi, [alloc_list] ; load first item in allocation list
|
||||
mov qword [rax + 9], 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, 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
|
||||
call sys_munmap ; Free memory
|
||||
ret
|
||||
.not_found:
|
||||
ret ; Item not found, do nothing
|
||||
|
||||
gc_collect:
|
||||
call gc_mark_stack
|
||||
call gc_sweep
|
||||
ret
|
||||
|
||||
gc_mark_stack:
|
||||
mov r8, rsp ; load current stack pointer
|
||||
mov r9, [stack_start] ; load start of stack
|
||||
.loop:
|
||||
cmp r8, r9 ; have we reached end of stack?
|
||||
ja .done ; yes? return
|
||||
mov rdi, [r8] ; no? load the value
|
||||
call gc_mark ; this might be an allocation, check
|
||||
add r8, 8 ; next item in stack
|
||||
jmp .loop
|
||||
.done:
|
||||
ret
|
||||
|
||||
gc_mark:
|
||||
test rdi, rdi ; is input null?
|
||||
jz .done ; yes? return
|
||||
mov rsi, [alloc_list] ; load start of allocation list
|
||||
.loop:
|
||||
test rsi, rsi ; reached end of list?
|
||||
jz .done ; yes? return
|
||||
lea rdx, [rsi + 17]
|
||||
cmp rdx, rdi ; no? is this the input object?
|
||||
je .mark_object ; yes? mark it
|
||||
mov rsi, [rsi + 9] ; no? next item
|
||||
jmp .loop
|
||||
.mark_object:
|
||||
mov al, [rdi] ; load mark
|
||||
test al, al ; already marked?
|
||||
jnz .done ; yes? return
|
||||
mov byte [rdi - 17], 1 ; mark object
|
||||
mov rcx, [rdi + 1] ; load object size
|
||||
lea rdx, [rdi + 17] ; start of data
|
||||
add rcx, rdx ; end of data
|
||||
.scan_object:
|
||||
cmp rdx, rcx ; done scanning?
|
||||
jae .done ; yes? return
|
||||
mov rdi, [rbx] ; load value
|
||||
call gc_mark
|
||||
add rdx, 8 ; next object
|
||||
jmp .scan_object
|
||||
.done:
|
||||
ret
|
||||
|
||||
gc_sweep:
|
||||
mov rdi, [alloc_list]
|
||||
.loop:
|
||||
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]
|
||||
jmp .loop
|
||||
.free:
|
||||
mov rcx, [rdi + 9]
|
||||
push rcx
|
||||
call gc_free
|
||||
pop rdi
|
||||
jmp .loop
|
||||
.done:
|
||||
ret
|
||||
|
||||
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
|
||||
20
input/baseline/str_cmp.asm
Normal file
20
input/baseline/str_cmp.asm
Normal file
@@ -0,0 +1,20 @@
|
||||
global str_cmp
|
||||
|
||||
section .text
|
||||
str_cmp:
|
||||
xor rdx, rdx
|
||||
.loop:
|
||||
mov al, [rsi + rdx]
|
||||
mov bl, [rdi + rdx]
|
||||
inc rdx
|
||||
cmp al, bl
|
||||
jne .not_equal
|
||||
cmp al, 0
|
||||
je .equal
|
||||
jmp .loop
|
||||
.not_equal:
|
||||
mov rax, 0
|
||||
ret
|
||||
.equal:
|
||||
mov rax, 1
|
||||
ret
|
||||
@@ -1,6 +1,6 @@
|
||||
global arr_size
|
||||
section .text
|
||||
|
||||
section .text
|
||||
arr_size:
|
||||
mov rax, [rdi]
|
||||
ret
|
||||
@@ -1,6 +1,6 @@
|
||||
global str_len
|
||||
section .text
|
||||
|
||||
section .text
|
||||
str_len:
|
||||
xor rax, rax
|
||||
.loop:
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
#!/bin/sh
|
||||
nasm -g -felf64 out.asm -o out.o
|
||||
|
||||
# baseline
|
||||
nasm -g -felf64 ../input/baseline/gc.asm -o gc.o
|
||||
nasm -g -felf64 ../input/baseline/str_cmp.asm -o str_cmp.o
|
||||
|
||||
# core
|
||||
nasm -g -felf64 ../input/core/str_len.asm -o str_len.o
|
||||
nasm -g -felf64 ../input/core/arr_size.asm -o arr_size.o
|
||||
nasm -g -felf64 ../input/core/itoa.asm -o itoa.o
|
||||
|
||||
ld -o out str_len.o arr_size.o itoa.o out.o
|
||||
# program
|
||||
nasm -g -felf64 out.asm -o out.o
|
||||
|
||||
ld -o out str_len.o arr_size.o itoa.o gc.o str_cmp.o out.o
|
||||
|
||||
Reference in New Issue
Block a user