aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorMirek Kratochvil <exa.exa@gmail.com>2023-11-01 18:25:26 +0100
committerMirek Kratochvil <exa.exa@gmail.com>2023-11-01 18:25:26 +0100
commit1909e97d4615045e707710a2aaeae8bf702a8355 (patch)
treeacba7fd278ef27dbdb749f936b38a812a056176a /include
parent32d71ef9f25b4cebb2ae95b4f528bbc02f62ea31 (diff)
parent970ffb4684dbd88bd54e909820bbc5a66a87b18d (diff)
downloaduskel-1909e97d4615045e707710a2aaeae8bf702a8355.tar.gz
uskel-1909e97d4615045e707710a2aaeae8bf702a8355.tar.bz2
Merge branch 'gc-attempt-1'
Diffstat (limited to 'include')
-rw-r--r--include/apply.s19
-rw-r--r--include/data.s272
-rw-r--r--include/gc.s210
-rw-r--r--include/intops.s6
-rw-r--r--include/io.s4
-rw-r--r--include/listops.s2
-rw-r--r--include/main_exit.s7
-rw-r--r--include/primops.s2
-rw-r--r--include/uskel.s52
9 files changed, 474 insertions, 100 deletions
diff --git a/include/apply.s b/include/apply.s
index 82465bc..7c5d366 100644
--- a/include/apply.s
+++ b/include/apply.s
@@ -5,6 +5,7 @@
# | fun | arg | -> cont
.thunkcode apply1
+ needs_alloc $050
thunkto %rsi, $apply1_fini, $3, 030(%rbp), %rbp, %rsi
enter 020(%rbp) # evaluate fun
@@ -14,6 +15,10 @@
# we're certainly going to copy a lot of args.
mov 020(%rsi), %r11 # amount of args applied now
+ # prepare enough memory for the worst case alloc (make FUN from arg count + 3)
+ lea 030(,%r11,010), %r12
+ needs_alloc %r12
+
# the copying code is shared so let's do that first:
pushq 020(%rbp) #push the new arg
lea 030(%rsi), %rdx # the end (first arg)
@@ -59,6 +64,7 @@ apply1_fini_feed:
# | fun | arg[1] | arg[2] | ... | arg[args-1] | -> cont
.thunkcode apply
+ needs_alloc $040
thunkto %rsi, $apply_fini, $2, %rbp, %rsi
enter 020(%rbp)
@@ -71,13 +77,18 @@ apply1_fini_feed:
mov 010(%r10), %r13 # amount of args in the original thunk
sub $1, %r13 # amount of args we want to apply (the 1st one is the FUN)
- mov %r11, %r14
- add %r13, %r14
- cmp %r12, %r14 # do we have enough arguments?
+ lea (%r11, %r13), %r14 # total amount arguments we have
+ lea 050(%r14), %r15 # how much memory this needs in extreme
+ needs_alloc %r15
+ # worst-case memory is: we make a thunk (2 headers + some args) and a
+ # leftover closure (3 headers + rest of args)
+
+ # Now that we have enough memory, do we have enough arguments to do anything?
+ cmp %r12, %r14
ja apply_fini_o
apply_fini_pt:
- # not enough args or exactly enough args.
+ # Not enough args or exactly enough args.
# Basically make a function or a thunk that is almost the same.
# first move thunk params
diff --git a/include/data.s b/include/data.s
index 2c512d4..35c4c8d 100644
--- a/include/data.s
+++ b/include/data.s
@@ -1,14 +1,7 @@
.ifndef _data_s_file
_data_s_file:
-
-# Simple values and boxed machine integers
-# | ptr | value |
-CON_evacuate1:
- retq # TODO
-CON_scavenge1:
- add $020, %rsi
- retq
+ nop # avoid confusing gdb
# Format of the info tables:
# - code
@@ -16,27 +9,160 @@ CON_scavenge1:
# - 8B helper information for eval/apply (generally this is 0, and only gets used for FUN/PAP)
# - 8B pointer to scavenge
# - 8B pointer to evacuate
+#
+# Evacuate interface:
+# in: %rbp what to evacuate
+# out: %rbp where the thing is now
+# ret: jump to _gc_evacuate_ret
+# Notes:
+# - IND thunks skip themselves on evacuate
+# - checking if whether stuff is already in write region are managed by
+# _gc_evacuate prelude
+#
+# Scavenge interface:
+# in: %rbp what to scavenge
+# out: %rbp next thing to scavenge in memory
+# ret: jump to _gc_scavenge_ret
+#
+# Saved registers during the GC process:
+# - _uskel_gc uses %r8-%r11
+# - scavenges use %r12-%r15
+# - %rax-%rdx is scratch and evacuate use
+
+# Simple values and boxed machine integers
+# | ptr | value |
+INT_evacuate:
+ pushq 010(%rbp)
+ pushq $INT_code
+ mov %rsp,%rbp
+ jmp _gc_evacuate_ret
+INT_scavenge:
+ add $020, %rbp
+ jmp _gc_scavenge_ret
INT_info_table:
- cell CON_evacuate1
- cell CON_scavenge1
+ cell INT_evacuate
+ cell INT_scavenge
cell 0
INT_code:
continue
+# Indirection
+# | ptr | indptr |
+IND_evacuate:
+ mov 010(%rbp), %rbp
+ jmp _gc_evacuate
+IND_scavenge:
+ # this should never be triggered but let's play it safe
+ add $020, %rbp
+ jmp _gc_scavenge_ret
+
+IND_info:
+ cell IND_evacuate
+ cell IND_scavenge
+ cell 0
+IND_code:
+ enter 010(%rbp)
+
+# Blackhole (contains the original thunkptr for debugging purposes)
+# | ptr | orig_thunkptr |
+BLE_evacuate:
+ jmp _gc_evacuate_ret
+BLE_scavenge:
+ jmp _gc_scavenge_ret
+
+BLE_info_table:
+ cell BLE_evacuate
+ cell BLE_scavenge
+ cell 0
+BLE_code:
+ # if we hit this, we've got a pure loop in a program, and it is never
+ # going to actually progress. So let's just shoot it down with a
+ # helpful message or so.
+ mov 010(%rbp), %r15
+
+ mov $1, %rdi #stdout
+
+ mov $14, %rdx
+ mov $BLE_msg, %rsi
+ mov $1, %rax #write
+ syscall
+
+ mov $1, %rdx
+ BLE_loop:
+ mov %r15, %rcx
+ and $0xf, %rcx
+ mov $BLE_hex, %rsi
+ add %rcx, %rsi
+ mov $1, %rax
+ syscall
+ shr $4, %r15
+ jnz BLE_loop
+
+ mov $BLE_nl, %rsi
+ mov $1, %rax
+ syscall
+
+ # shot self down (and retry if it doesn't succeed)
+ BLE_retry_sigkill:
+ mov $39, %rax
+ syscall # getpid
+ mov %rax, %rdi
+ mov $6, %rsi # SIGABRT
+ mov $62, %rax # kill
+ syscall
+ jmp BLE_retry_sigkill
+
+BLE_msg:
+ .ascii "diverged at 0x"
+BLE_hex:
+ .ascii "0123456789abcdef"
+BLE_nl:
+ .ascii "\n"
+
# List
-# | ptr | 0 |
-# | ptr | 1 | a | b |
+# | ptr | 0 | # [] case
+# | ptr | 1 | a | b | # (a:b) case
LIST_evacuate:
- # [] | a : b
- retq #TODO
+ cmpq $0, 010(%rbp)
+ je LIST_evacuate_nil
+ pushq 030(%rbp)
+ pushq 020(%rbp)
+ pushq $1
+ pushq $LIST_code
+ mov %rsp, %rbp
+ jmp _gc_evacuate_ret
+
+ LIST_evacuate_nil:
+ pushq $0
+ pushq $LIST_code
+ mov %rsp, %rbp
+ jmp _gc_evacuate_ret
LIST_scavenge:
- mov 010(%rbp), %rax
- shl $1, %rax
- add $2, %rax
- shl $3, %rax
- add %rax, %rsi
- retq
+ cmpq $0, 010(%rbp)
+ je LIST_scavenge_nil
+ mov %rbp, %r15
+
+ mov $LIST_scavenge1, %rsi
+ mov 020(%r15), %rbp
+ jmp _gc_evacuate
+ LIST_scavenge1:
+ mov %rbp, 020(%r15)
+
+ mov $LIST_scavenge2, %rsi
+ mov 030(%r15), %rbp
+ jmp _gc_evacuate
+ LIST_scavenge2:
+ mov %rbp, 030(%r15)
+
+ mov %r15, %rbp
+ add $040, %rbp
+ jmp _gc_scavenge_ret
+
+ LIST_scavenge_nil:
+ add $020, %rbp
+ jmp _gc_scavenge_ret
+
LIST_info_table:
cell LIST_evacuate
cell LIST_scavenge
@@ -47,13 +173,42 @@ LIST_code:
# FUN objects
# | ptr | thunkptr | args | arg[0] | arg[1] | ... | arg[args] |
FUN_evacuate:
- retq #TODO
+ mov 020(%rbp), %rbx # rbx = count of arguments
+ mov %rbx, %rcx # rcx = count of arguments for later looping
+ lea 030(%rbp, %rbx, 010), %rdx # rdx = address of the arguments
+ FUN_evacuate_one:
+ sub $1, %rcx
+ jl FUN_evacuate_fini
+ sub $010, %rdx
+ pushq (%rdx)
+ jmp FUN_evacuate_one
+ FUN_evacuate_fini:
+ pushq %rbx
+ pushq 010(%rbp)
+ pushq 000(%rbp)
+ mov %rsp, %rbp
+ jmp _gc_evacuate_ret
FUN_scavenge:
- mov 020(%rbp), %rax
- add $3, %rax
- shl $3, %rax
- add %rax, %rsi
- retq
+ mov 020(%rbp), %r13 # r13 = count of arguments (for looping)
+ mov %rbp, %r15 # r15 = scavengee ptr
+ lea 030(%rbp, %r13, 010), %r14 # r14 = address of argument
+
+ FUN_scavenge_one:
+ sub $1, %r13
+ jl FUN_scavenge_fini
+ sub $010, %r14
+ mov (%r14), %rbp
+ mov $FUN_scavenge_one_cont, %rsi
+ jmp _gc_evacuate
+ FUN_scavenge_one_cont:
+ mov %rbp, (%r14)
+ jmp FUN_scavenge_one
+
+ FUN_scavenge_fini:
+ mov %r15, %rbp # restore rbp
+ mov 020(%rbp), %r14
+ lea 030(%rbp, %r14, 010), %rbp
+ jmp _gc_scavenge_ret
# Info tables for FUN objects.
FUN0_info_table:
@@ -90,39 +245,46 @@ FUN4_info_table:
cell 4
FUN4_code:
continue
+# add more funN here as needed
-# TODO: add more funN here as needed
-
-# indirection (Q: how to recognize IND and THUNK on return?)
-# | ptr | indptr |
-IND_evacuate:
- retq #TODO
-IND_scavenge:
- add $020,%rsi
- retq
-IND_info:
- cell IND_evacuate
- cell IND_scavenge
- cell 0
-IND_code:
- enter 010(%rbp)
-
-# THU objects (gc implementation only, actual THUs are defined by functions)
+# THU objects (gc implementation only, actual THU data are created by functions)
# | ptr | args | arg[0] | arg[1] | ... | arg[args] |
# args wouldn't need to be here but let's keep them for gc simplicity
THU_evacuate:
- retq #TODO
+ mov 010(%rbp), %rbx # rbx = count of arguments
+ mov %rbx, %rcx # rcx = count of arguments for later looping
+ lea 020(%rbp, %rbx, 010), %rdx # rdx = address of the argument
+ THU_evacuate_one:
+ sub $1, %rcx
+ jl THU_evacuate_fini
+ sub $010, %rdx
+ pushq (%rdx)
+ jmp THU_evacuate_one
+ THU_evacuate_fini:
+ pushq %rbx
+ pushq 000(%rbp)
+ mov %rsp, %rbp
+ jmp _gc_evacuate_ret
THU_scavenge:
- mov 010(%rbp), %rax
- add $2,%rax
- shl $3,%rax
- add %rax,%rsi
- retq
+ mov 010(%rbp), %r13 # r13 = count of arguments (for looping)
+ mov %rbp, %r15 # r15 = scavengee ptr
+ lea 020(%rbp, %r13, 010), %r14 # r14 = address of argument
-.endif # _data_s_file
+ THU_scavenge_one:
+ sub $1, %r13
+ jl THU_scavenge_fini
+ sub $010, %r14
+ mov (%r14), %rbp
+ mov $THU_scavenge_one_cont, %rsi
+ jmp _gc_evacuate
+ THU_scavenge_one_cont:
+ mov %rbp, (%r14)
+ jmp THU_scavenge_one
+
+ THU_scavenge_fini:
+ mov %r15, %rbp # restore rbp
+ mov 010(%rbp), %r14
+ lea 020(%rbp, %r14, 010), %rbp
+ jmp _gc_scavenge_ret
-# evacuate and scavenge:
-# - evacuate just copies the object
-# - scavenge evacuates all children (to the new location IF they are in the old
-# location), changes the pointer, and moves the scavenge pointer to the next
-# object (because everything needs to be scavenged)
+.endif # _data_s_file
diff --git a/include/gc.s b/include/gc.s
new file mode 100644
index 0000000..b40ac95
--- /dev/null
+++ b/include/gc.s
@@ -0,0 +1,210 @@
+
+.ifndef _gc_s_file
+_gc_s_file:
+
+.section .bss
+_write_region_start:
+ # begin of the active memory area
+ cell 0
+_write_region_end:
+ # end of the active memory area (%rsp kinda starts here and goes down
+ # towars the start)
+ cell 0
+_gc_trigger:
+ # point in memory where the gc will trigger (we don't necessarily wait for the write region to fill up!)
+ cell 0
+
+_gc_last_size:
+ # how much data we evacuated last time
+ cell 0
+_gc_min_alloc:
+ # minimum possible allocation
+ cell 0 # tunable constant
+_gc_grow_ratio:
+ # 256th's of the minimal amount of memory increment compared to the
+ # last time. New minimal amount is compared as:
+ # (ratio * last size) >> 8
+ cell 0 # tunable constant
+_gc_shrink_ratio:
+ # 256th's of the ratio of post-gc still-free to-space that should be considered for discarding
+ cell 0
+
+_gc_region_start:
+ # in GC, this region is being evacuated and will eventually disappear
+ cell 0
+_gc_region_end:
+ # end of the disappear region
+ cell 0
+
+_gc_backup_thunk:
+ # backup of %rsi so that we can use the register for other nonsense
+ cell 0
+_gc_backup_cont:
+ # backup of %rbp for same reason
+ cell 0
+
+.section .text
+
+.macro needs_alloc amount
+ mov %rsp, %rax
+ sub _write_region_start, %rax
+ cmp \amount, %rax
+ jb _uskel_gc
+.endm
+
+_uskel_alloc:
+ mov %rsi, %r15 # %rsi is the return address; back it up
+
+ # calculate the desired size to %r14
+ mov _gc_min_alloc, %r14
+ #add _gc_region_end, %r14
+ #sub _gc_region_start, %r14
+
+ # check if the desired size isn't greater because of the last gc use
+ mov _gc_last_size, %rax
+ mulq _gc_grow_ratio
+ shr $8, %rax
+ add _gc_min_alloc, %rax
+ cmp %r14, %rax
+ cmova %rax, %r14
+
+ # check if we don't need even more space because we need to evacuate stuff
+ mov _gc_region_end, %rax
+ sub %rsp, %rax # trick -- if we counted from gc region start, allocated memory could never shrink
+ cmp %r14, %rax
+ cmova %rax, %r14
+
+ and $0xfffffffffffffff8, %r14 #align
+
+ alloc_goes_mmap:
+ mov $9, %rax # mmap
+ mov $0, %rdi # addr = NULL
+ mov %r14, %rsi # len = %r14
+ mov $0b11, %rdx # prot = PROT_READ 0b1 | PROT_WRITE 0b10
+ mov $0x22, %r10 # flags = MAP_PRIVATE 0x2 | MAP_ANONYMOUS 0x20
+ mov $-1, %r8 # fd = -1
+ mov $0, %r9 # off = 0
+ syscall
+
+ # store the results
+ mov %rax, _write_region_start
+ add %r14, %rax
+ mov %rax, _write_region_end
+ mov %rax, %rsp # initialize writing into the new region
+
+ jmp *%r15
+
+_uskel_gc_init:
+ mov %rsi, %r13
+ movq $0x100000, _gc_min_alloc # must be higher than 2x the biggest thunk possible
+ movq $0x180, _gc_grow_ratio
+ movq $0x40, _gc_shrink_ratio
+ mov $0, %rsp # fake original rsp for first alloc run
+ mov $_uskel_gc_init_cont, %rsi
+ jmp _uskel_alloc
+ _uskel_gc_init_cont:
+ mov _write_region_start, %rax
+ mov %rax, _gc_trigger
+ jmp *%r13
+
+_uskel_gc:
+ # save what we did before ending up here
+ mov %rbp, _gc_backup_thunk
+ mov %rsi, _gc_backup_cont
+
+ # first we need a new memory area
+ mov _write_region_start, %rbx
+ mov _write_region_end, %rcx
+ mov %rbx, _gc_region_start
+ mov %rcx, _gc_region_end
+ mov $_uskel_gc_evacuate, %rsi
+ jmp _uskel_alloc
+ _uskel_gc_evacuate:
+
+ # point the writer to the new memory area
+ mov _write_region_end, %rsp
+ mov %rsp, %r8 # % r8 is the "last thing that was scavenged"
+
+ # start by evacuating the thunk and cont
+ mov _gc_backup_thunk, %rbp
+ mov $_uskel_gc_evacuate_cont_thunk, %rsi
+ jmp _gc_evacuate
+ _uskel_gc_evacuate_cont_thunk:
+ mov %rbp, _gc_backup_thunk
+
+ mov _gc_backup_cont, %rbp
+ mov $_uskel_gc_evacuate_cont_cont, %rsi
+ jmp _gc_evacuate
+ _uskel_gc_evacuate_cont_cont:
+ mov %rbp, _gc_backup_cont
+
+ # scavenge everything
+ _uskel_gc_scavenge:
+ # start at what we wrote last
+ mov %rsp, %rbp # rbp is the iterator (conveniently)
+ mov %rsp, %r9 # % r9 stores where we started with this evacuate round
+
+ # if the thing is already scavenged, we didn't write anything, mark done.
+ cmp %rbp, %r8
+ jbe _uskel_gc_scavenge_end
+
+ _uskel_gc_scavenge1:
+ # if all ok, scavenge one thing (moving %rbp) and recheck
+ mov (%rbp), %rax
+ jmp *-020(%rax) # scavenge position in infotable
+ _gc_scavenge_ret:
+ cmp %rbp, %r8
+ ja _uskel_gc_scavenge1
+
+ # everything above r9 is now scavenged, continue with next round
+ mov %r9, %r8 # we started at r9, so that is now "done"
+ jmp _uskel_gc_scavenge
+
+ _uskel_gc_scavenge_end:
+ # deallocate the old memory region
+ mov $11, %rax # munmap
+ mov _gc_region_end, %rsi
+ mov _gc_region_start, %rdi # addr = gc start
+ sub %rdi, %rsi # len = gc end - gc start
+ syscall
+
+ # recalculate the gc trigger point
+ mov %rsp, %rax
+ sub _write_region_start, %rax
+ mulq _gc_shrink_ratio
+ shr $8, %rax
+ add _write_region_start, %rax
+ mov %rax, _gc_trigger
+
+ # save how much data we actually had at this point
+ mov _write_region_end, %rax
+ sub %rsp, %rax
+ mov %rax, _gc_last_size
+
+ # restore what we were doing
+ mov _gc_backup_thunk, %rbp
+ mov _gc_backup_cont, %rsi
+ enter_rbp # for simplicity just restart the thunk
+
+_gc_evacuate:
+ # check if we are really out of the target region
+ cmp _write_region_start, %rbp
+ jb _gc_evacuate_go
+ cmp _write_region_end, %rbp
+ jae _gc_evacuate_go
+ _gc_evacuate_skip:
+ # if not, let's just jump to cont and leave %rbp as result
+ jmp *%rsi
+ _gc_evacuate_go:
+ # if we should evacuate, jump to the evac routine
+ mov %rbp, %r10
+ mov (%rbp), %rax
+ jmp *-030(%rax)
+ _gc_evacuate_ret:
+ # install the indirection
+ movq $IND_code, 000(%r10)
+ mov %rbp, 010(%r10)
+ jmp *%rsi
+
+
+.endif #_gc_s_file
diff --git a/include/intops.s b/include/intops.s
index dbadb37..08b3300 100644
--- a/include/intops.s
+++ b/include/intops.s
@@ -5,13 +5,13 @@ _intops_s_file:
.include "include/primops.s"
.primop2 plus
- mov 010(%rsi), %rax # arg 2
+ mov 010(%rsi), %rax # arg 2
mov 020(%rbp), %rsi # location of arg1
add 010(%rsi), %rax # arg 1
primop2_ret_int %rax
.primop2 mul
- mov 010(%rsi), %rax # arg 2
+ mov 010(%rsi), %rax # arg 2
mov 020(%rbp), %rsi # location of arg1
mulq 010(%rsi) # arg 1 (goes to %rax and %rdx)
primop2_ret_int %rax
@@ -19,7 +19,7 @@ _intops_s_file:
.primop2 sub
mov 020(%rbp), %rdi # location of arg1
mov 010(%rdx), %rax # arg 1
- sub 010(%rsi), %rax # arg 2
+ sub 010(%rsi), %rax # arg 2
primop2_ret_int %rax
.endif # _intops_s_file
diff --git a/include/io.s b/include/io.s
index 205f144..29a63c9 100644
--- a/include/io.s
+++ b/include/io.s
@@ -4,11 +4,13 @@ _io_s_file:
# | int | -> cont
.thunkcode print
+ needs_alloc $040
thunkto %rsi, $print_fini, $2, %rbp, %rsi
enter 020(%rbp)
# arg -> | ret | cont |
.thunkcode print_fini
+ needs_alloc $0110 #64 bit characters + 8 backup
mov 010(%rsi), %rax
# make a string
@@ -24,7 +26,7 @@ _io_s_file:
shr $1, %rax
jnz print_fini_loop
- mov $0, %rdi #stdin
+ mov $1, %rdi #stdout
mov %rsp, %rdx
sub %r15, %rdx #size
mov %r15, %rsi #buf
diff --git a/include/listops.s b/include/listops.s
index 447c125..0ee39ad 100644
--- a/include/listops.s
+++ b/include/listops.s
@@ -6,6 +6,8 @@ _listops_s_file:
# | n | list | -> cont
.primop2 list_int_index
+ needs_alloc $060
+
mov 010(%rsi), %rdx # the list constructor id, must be 1
cmp $1, %rdx
jne list_int_index_not_found
diff --git a/include/main_exit.s b/include/main_exit.s
index 1a38e5a..5ce6c76 100644
--- a/include/main_exit.s
+++ b/include/main_exit.s
@@ -1,13 +1,10 @@
.ifndef _main_exit_s_file
_main_exit_s_file:
-# exitcode -> | cont (unused, should be 0) |
+# exitcode -> ||
.thunkcode main_exit
- mov 010(%rsi), %rdi # result goes to syscall exitcode
+ mov 010(%rsi), %rdi # result INT goes to syscall exitcode
mov $60, %rax # exit=60
syscall # exit %rdi
-# TODO this is a "case" kind of thunk so it's quite likely that it really
-# doesn't need the continuation.
-
.endif # _main_exit_s_file
diff --git a/include/primops.s b/include/primops.s
index f532144..117bcca 100644
--- a/include/primops.s
+++ b/include/primops.s
@@ -9,6 +9,7 @@ _primops_s_file:
.macro .primop1 name
# | arg1 | -> cont
.thunkcode \name
+ needs_alloc $040
# push a thunk for collecting the first arg and set it as continuation
thunkto %rsi, $\name\()_fini, $2, %rbp, %rsi
enter 020(%rbp) # evaluate arg1
@@ -39,6 +40,7 @@ _primops_s_file:
.macro .primop2 name
# | arg1 | arg2 | -> cont
.thunkcode \name
+ needs_alloc $050
# push a thunk for collecting the first arg and set it as continuation
thunkto %rsi, $\name\()_step1, $3, 030(%rbp), %rbp, %rsi
enter 020(%rbp) # evaluate arg1
diff --git a/include/uskel.s b/include/uskel.s
index 34ee63a..0a21217 100644
--- a/include/uskel.s
+++ b/include/uskel.s
@@ -9,46 +9,34 @@ _start:
.include "include/macros.s"
.section .bss
-_memory_state:
- cell 0 # bottom of allocation (grows down)
- cell 0 # region start
- cell 0 # region end
- cell 0 # program entry rsp (aka the actual stack)
+_unix_rsp:
+ # back-up of program entry rsp (aka the actual stack given by the
+ # actual OS; we might like to use it at some point, maybe)
+ cell 0
-.section .text
+.include "include/gc.s"
-_uskel_alloc_basic_mem:
- mov $0x100000, %r15 # desired size
-
- mov $9, %rax # mmap
- mov $0, %rdi # addr = NULL
- mov %r15, %rsi # len = %rcx
- mov $0b11, %rdx # prot = PROT_READ 0b1 | PROT_WRITE 0b10
- mov $0x22, %r10 # flags = MAP_PRIVATE 0x2 | MAP_ANONYMOUS 0x20
- mov $-1, %r8 # fd = -1
- mov $0, %r9 # off = 0
- syscall
- mov $_memory_state, %rdi
- mov %rax, 010(%rdi)
- add %r15, %rax
- mov %rax, (%rdi)
- mov %rax, 020(%rdi)
- retq
+.section .text
_uskel_start:
- call _uskel_alloc_basic_mem
- # use the stack pointer for easy writing to the heap,
- # but back it up to memory state
- mov $_memory_state, %rdi
- mov %rsp, 030(%rdi)
- mov 0(%rdi), %rsp
+ # we use the stack pointer for easy writing to the heap;
+ # back it up to memory state just if we ever needed it again.
+ mov %rsp, _unix_rsp
+
+ # allocate the initial chunk of memory
+ mov $_uskel_start_main, %rsi
+ jmp _uskel_gc_init
+ _uskel_start_main:
# push a thunk for main
pushq $0
pushq $main
- mov $0, %rsi # set continuation to exit
+ # loop the continuation to itself (prevents gc trouble, should never be reached)
+ mov %rsp, %rsi
enter %rsp # run the program
# Q: are there gonna be functions that have both the argument AND the cont?
- # A: No, stuff is either entered as return-continuation (takes res, cont has to be saved) or as forward call (takes cont)
- # (needs validation)
+ # A: No, stuff is either entered as return-continuation (takes res,
+ # cont has to be saved) or as forward call (takes cont)
+ #
+ # (A needs validation)