aboutsummaryrefslogtreecommitdiff
path: root/include/apply.s
blob: 0a0457d4b45bdbb5dbd93161f2e9ae7fd68e3011 (plain)
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

.include "include/data.s"

#TODO apply1 seems obsolete by generic apply

# | fun | arg | -> cont
.thunkcode apply1
	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

	# 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
	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)

	mov %r11, %r14
	add %r13, %r14
	cmp %r12, %r14 # do we have enough arguments?
	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
	lea 030(%r10, %rcx, 010), %rdx
	apply_fini_o_tc_copy:
	sub $010, %rdx
	pushq (%rdx)
	loop apply_fini_o_tc_copy

	# move all args from the closure
	mov %r11, %rcx
	lea 030(%rsi, %r11, 010), %rdx
	apply_fini_o_fun_copy:
	sub $010, %rdx
	pushq (%rdx)
	loop apply_fini_o_fun_copy

	# 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
	lea 030(%r10, %r13, 010), %rdx
	apply_fini_o_tt_copy:
	sub $010, %rdx
	pushq (%rdx)
	loop apply_fini_o_tt_copy

	# 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