1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
.include "include/data.s"
# | fun | arg[1] | arg[2] | ... | arg[args-1] | -> cont
.thunkcode apply
#determine how much stuff we need
mov 010(%rbp), %rcx
dec %rcx # we don't move the FUN
lea 040(,%rcx,010), %rbx # all args (in rcx) + rbp+rsi + 2qw thunk header
needs_alloc %rbx
# push all closure args
mov %rcx, %rbx # backup arg count
lea 030(%rbp, %rcx, 010), %rdx #point behind the thunk (this re-adds the FUN qw!)
apply_copy:
sub $010, %rdx
pushq (%rdx)
loop apply_copy
# push thunk header (+2 args for rbp/rsi) and continue evaluating the FUN
add $2, %rbx
thunkto %rsi, $apply_fini, %rbx, %rbp, %rsi
blackhole
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(%rbp), %r13 # amount of args in the original thunk
sub $2, %r13 # amount of args we want to apply (the extra ones are the backup rbp, rsi, and the FUN)
lea (%r11, %r13), %r14 # total amount arguments we have
lea 050(%r14), %r15 # how much memory this needs in extreme #TODO: check this
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 040(%rbp, %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 # thunk code (from FUN code) + amount of args
cmp %r12, %r14 # are we precisely at the right amount of arguments for a thunk?
jb apply_fini_pt_closure # if not, wrap a closure
apply_fini_pt_thunk:
# we've made the exact thunk we want. Replace the original with an indirect
mov %rsp, 010(%r10)
movq $IND_code, (%r10)
# and tell the new thunk to evaluate into the original continuation
mov 030(%rbp), %rsi
enter %rsp
apply_fini_pt_closure:
# if we still have an incomplete closure, rewrap it in the original FUN wrappage
thunkto %rsi, %r9
# replace the original thunk with an indirect
mov %rsp, 010(%r10)
movq $IND_code, (%r10)
# and return the closure (%rsi) to the original continuation as a result
enter 030(%rbp)
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 040(%rbp, %rcx, 010), %rdx
apply_fini_o_tc_copy:
sub $010, %rdx
pushq (%rdx)
loop apply_fini_o_tc_copy
apply_fini_o_tc_skip:
# now add all the 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 a thunk out of the successfully finished closure; it will 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 the leftover-args count for later
cmp $0, %rcx
jz apply_fini_o_tt_skip
lea 040(%rbp, %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 + lefrover args)
thunk $apply, %r14, %r15 # push the 1st arg (FUN) + argcount
# replace the original thunk with an indirect
mov %rsp, 010(%r10)
movq $IND_code, (%r10)
# return the applied function to the original continuation
mov 030(%rbp), %rsi
enter %rsp
|