aboutsummaryrefslogtreecommitdiff
path: root/include/apply.s
blob: 638aac27ac991e76795c8b7f1f0d08bbf5c68a55 (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

.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