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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
.include "macros.s"
.section .init
.global _start
_start:
jmp _uskel_start
.section .bss
_memory_state:
cell 0 # next free position
cell 0 # region start
cell 0 # region end
.section .text
_uskel_alloc_basic_mem:
mov $0x100000, %r15 # desired size
mov $0x9, %rax # mmap
mov $0, %rdi # addr = NULL
mov %r15, %rsi # len = %rcx
mov $0x3, %rdx # prot = PROT_READ 0x1 | PROT_WRITE 0x2
mov $0x22, %r10 # flags = MAP_PRIVATE 0x2 | MAP_ANONYMOUS 0x20
mov $-1, %r8 # fd = -1
mov $0, %r9 # off = 0
syscall
mov $_memory_state, %rdi
mov %rax, (%rdi)
mov %rax, 0x8(%rdi)
add %r15, %rax
mov %rax, 0x10(%rdi)
retq
_uskel_start:
call _uskel_alloc_basic_mem
mov _memory_state, %rdi
# push a thunk for main
mov %rdi, %r15 # backup main for later
movq $main, 0x00(%rdi)
movq $0, 0x08(%rdi)
add $0x10, %rdi
# save the memory ptr
mov %rdi, _memory_state
mov $0, %rsi # set continuation to exit
enter %r15 # run the program
# Simple values and boxed machine integers
# | ptr | value |
CON_evacuate1:
retq
CON_scavenge1:
add $0x10, %rsi
retq
INT_info_table:
cell CON_evacuate1
cell CON_scavenge1
cell 0
INT_code:
continue
# List
# | ptr | 0 |
# | ptr | 1 | a | b |
LIST_evacuate:
# [] | a : b
retq #TODO
LIST_scavenge:
mov 0x8(%rbp), %rax
shl $1, %rax
add $2, %rax
shl $3, %rax
add %rax, %rsi
retq
LIST_info_table:
cell LIST_evacuate
cell LIST_scavenge
cell 0
LIST_code:
continue
# FUN/PAP combo objects
# | ptr | thunkptr | args | arg[0] | arg[1] | ... | arg[args] |
FUN_evacuate:
retq #TODO
FUN_scavenge:
mov 0x10(%rbp), %rax
add $3, %rax
shl $3, %rax
add %rax, %rsi
retq
# Simple info for n-ary functions
# TODO continue to add as required
fun1_info_table:
cell FUN_evacuate
cell FUN_scavenge
cell 1
fun1_code:
continue
fun2_info_table:
cell FUN_evacuate
cell FUN_scavenge
cell 2
fun2_code:
continue
fun3_info_table:
cell FUN_evacuate
cell FUN_scavenge
cell 3
fun3_code:
continue
# indirection (Q: how to recognize IND and THUNK on return?)
# | ptr | indptr |
IND_evacuate:
retq #TODO
IND_scavenge:
add $0x10,%rsi
retq
IND_info:
cell IND_evacuate
cell IND_scavenge
cell 0
IND_code:
enter 0x8(%rbp)
# THU objects (gc implementation only, actual THUs are defined by functions)
# | ptr | args | arg[0] | arg[1] | ... | arg[args] |
# args wouldn't need to be here but let's keep them for gc simplicity
THU_evacuate:
retq #TODO
THU_scavenge:
mov 0x8(%rbp), %rax
add $2,%rax
shl $3,%rax
add %rax,%rsi
retq
#
# Actual code!
#
# || -> cont
.makethunk main
mov _memory_state, %r15
# push a new integer
mov %r15, %r11 # backup first arg
movq $INT_code, 0x00(%r15)
movq $100, 0x08(%r15)
add $0x10, %r15
# push another new integer
mov %r15, %r12 # backup second arg
movq $INT_code, 0x00(%r15)
movq $23, 0x08(%r15)
add $0x10, %r15
# push the plus
mov %r15, %r13 # backup plus
movq $plus, 0x00(%r15)
movq $2, 0x08(%r15)
mov %r11, 0x10(%r15)
mov %r12, 0x18(%r15)
add $0x20, %r15
# push a cont thunk for main_exit
mov %r15, %r14 # backup cont thunk
movq $main_exit, 0x00(%r15)
movq $1, 0x08(%r15)
mov %rsi, 0x10(%r15)
add $0x18, %r15
mov %r15, _memory_state
# evaluate into main_exit
mov %r14, %rsi
enter %r13
# exitcode -> | cont (unused, should be 0) |
.makethunk main_exit
mov 0x8(%rsi), %rdi
mov $0x3c, %rax
syscall # exit %rdi
# | arg1 | arg2 | -> cont
.makethunk plus
# push a thunk for finishing the plus
mov _memory_state, %r15
mov %r15, %r14 # plus_step1 origin
movq $plus_step1, 0x00(%r15)
movq $3, 0x08(%r15)
mov 0x18(%rbp), %rax
mov %rax, 0x10(%r15)
mov %rbp, 0x18(%r15)
mov %rsi, 0x20(%r15)
add $0x28, %r15
mov %r15, _memory_state
# evaluate arg0
mov %r14, %rsi
enter 0x10(%rbp)
# arg0 -> | arg1 | ret | cont |
.makethunk plus_step1
# this is guaranteed to be entered only once (it's a cont), so we can rewrite the thunk in place
mov 0x10(%rbp), %rax
movq $plus_fini, 0x00(%rbp)
mov %rsi, 0x10(%rbp)
mov %rbp, %rsi # continue on the rewritten thunk
enter %rax # evaluate arg1
# arg1 -> | arg0 | ret | cont |
.makethunk plus_fini
mov 0x8(%rsi), %rax # arg1
mov 0x10(%rbp), %rsi
add 0x8(%rsi), %rax # + arg0
mov 0x18(%rbp), %rsi # rewrite the resulting thunk
movq $INT_code, 0x00(%rsi)
mov %rax, 0x08(%rsi)
# result is in rsi already
enter 0x20(%rbp)
# Q: are there gonna be functions that have both the argument AND the cont?
# A: No, either stuff is entered as return-continuation (takes res) or as forward call (takes cont)
# (needs validation)
|