uskel/include/apply.s

188 lines
5.3 KiB
ArmAsm

.include "include/data.s"
#TODO apply1 seems obsolete by generic apply
# | fun | arg | -> cont
.thunkcode apply1
needs_alloc $050
thunkto %rsi, $apply1_fini, $3, 030(%rbp), %rbp, %rsi
enter 020(%rbp) # evaluate fun
# fun -> | arg | ret | cont |
.thunkcode apply1_fini
# we now know that fun points to a FUN with at least one arg missing.
# 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)
lea (%rdx, %r11, 010), %rbx # address behind the last arg
cmp %rdx, %rbx
jbe apply1_fini_cont
apply1_fini_copy:
sub $010, %rbx # iterate down
pushq (%rbx) # push what we have
cmp %rdx, %rbx # check if we are at the end
ja apply1_fini_copy # if not, continue
apply1_fini_cont:
add $1, %r11
pushq %r11 # new number of args of fun/thunk
pushq 010(%rsi) # thunk code pointer
# copying of all args and their thunky header is now done, let's find
# out how we need to finish it.
mov (%rsi), %rdi # infotable for the original fun
mov -010(%rdi), %r12 # amount of args required to make the thunk
cmp %r11, %r12
ja apply1_fini_feed # not enough args, just make a bigger FUN
# if there was enough args, we simply have a thunk that we want to
# continue evaluating, so let's jump to it.
mov 030(%rbp), %rdi # load the original thunk
mov %rsp, 010(%rdi) # set indirect to the new thunk
movq $IND_code, 0(%rdi)
mov 040(%rbp), %rsi # set continuation to the original continuation
enter %rsp # evaluate the new thunk
apply1_fini_feed:
# if there were not enough args, we push the function info and return
pushq (%rsi) # copy the function infoptr
mov 030(%rbp), %rdi # load the original thunk
mov %rsp, 010(%rdi) # set the indirect to the new FUN
movq $IND_code, 0(%rdi)
mov %rsp, %rsi # return the new FUN
enter 040(%rbp) # jump to the continuation
# | fun | arg[1] | arg[2] | ... | arg[args-1] | -> cont
.thunkcode apply
needs_alloc $040
thunkto %rsi, $apply_fini, $2, %rbp, %rsi
enter 020(%rbp)
# fun -> | ret (with args) | cont |
.thunkcode apply_fini
mov (%rsi), %r9 # infotable for the original function
mov 020(%rbp), %r10 # the original thunk
mov 020(%rsi), %r11 # amount of args applied in the closure
mov -010(%r9), %r12 # amount of args required to make a thunk
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)
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.
# Basically make a function or a thunk that is almost the same.
# first move thunk params
mov %r13, %rcx
cmp $0, %rcx
jz apply_fini_pt_thunk_skip
lea 030(%r10, %r13, 010), %rdx
apply_fini_pt_thunk_copy:
sub $010, %rdx
pushq (%rdx)
loop apply_fini_pt_thunk_copy
apply_fini_pt_thunk_skip:
# now move the fun params
mov %r11, %rcx
cmp $0, %rcx
jz apply_fini_pt_fun_skip
lea 030(%rsi, %r11, 010), %rdx
apply_fini_pt_fun_copy:
sub $010, %rdx
pushq (%rdx)
loop apply_fini_pt_fun_copy
apply_fini_pt_fun_skip:
# make a thunk
thunk 010(%rsi), %r14
cmp %r12, %r14 # are we precisely at the right amount of arguments for a thunk?
je apply_fini_pt_thunk # if not, wrap a closure
apply_fini_pt_closure:
thunkto %rsi, %r9
# replace the original thunk with an indirect
mov %rsi, 010(%r10)
movq $IND_code, (%r10)
# return the closure (%rsi) to the original continuation
enter 030(%rbp)
apply_fini_pt_thunk:
# it is a thunk, point to it and start evaluating it
mov %rsp, 010(%r10)
movq $IND_code, (%r10)
# tell the thunk to evaluate into the original continuation
mov 030(%rbp), %rsi
enter %rsp
apply_fini_o: #TODO needs to be tested
# too many args, we need to split off a bit
# first move just the right amount of args off the thunk
mov %r12, %rcx
sub %r11, %rcx
cmp $0, %rcx
jz apply_fini_o_tc_skip
lea 030(%r10, %rcx, 010), %rdx
apply_fini_o_tc_copy:
sub $010, %rdx
pushq (%rdx)
loop apply_fini_o_tc_copy
apply_fini_o_tc_skip:
# move all args from the closure
mov %r11, %rcx
cmp $0, %rcx
jz apply_fini_o_fun_skip
lea 030(%rsi, %r11, 010), %rdx
apply_fini_o_fun_copy:
sub $010, %rdx
pushq (%rdx)
loop apply_fini_o_fun_copy
apply_fini_o_fun_skip:
# make the thunk for the application that can be evaluated later
thunkto %r15, 010(%rsi), %r14
# now make a thunk with the rest of the stuff
mov %r14, %rcx
sub %r12, %rcx
mov %rcx, %r14 # backup leftover count for later
cmp $0, %rcx
jz apply_fini_o_tt_skip
lea 030(%r10, %r13, 010), %rdx
apply_fini_o_tt_copy:
sub $010, %rdx
pushq (%rdx)
loop apply_fini_o_tt_copy
apply_fini_o_tt_skip:
# finish the leftovers thunk
add $1, %r14 # (1 fun to apply to + args)
thunk $apply,%r14,%r15
# replace the original thunk with an indirect
mov %rsp, 010(%r10)
movq $IND_code, (%r10)
# evaluate to the original continuation
mov 030(%rbp), %rsi
enter %rsp