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

.include "include/data.s"

# | fun | arg[1] | arg[2] | ... | arg[args-1] | -> cont
.thunkcode apply
	needs_alloc $040
	thunkto %rsi, $apply_fini, $2, %rbp, %rsi
	# TODO: this needs to be blackholed here, but we need to copy out all
	# the args because the blackhole can't hold them
	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