-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathobject.s
367 lines (354 loc) · 9.4 KB
/
object.s
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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
.attribute arch, "rv64im"
.include "object.h.s"
# make cons from a0 (head), a1 (tail)
.global cons
cons:
mv a3, zero
mv a2, a1
mv a1, a0
li a0, LISP_OBJECT_TYPE_CONS
j make_obj
# destructure cons in a0
# return a0 = 1 on success, a1 = head, a2 = tail
# maintains refcount on head and tail, but releases the cons
.global uncons
uncons:
addi sp, sp, -0x28
sd ra, 0x00(sp)
sd a0, 0x08(sp)
sd zero, 0x10(sp)
sd zero, 0x18(sp)
sd zero, 0x20(sp)
beqz a0, .Luncons_ret # nil
li t1, LISP_OBJECT_TYPE_CONS
lw t2, LISP_OBJECT_TYPE(a0)
bne t2, t1, .Luncons_ret # not cons
# success - get value
li t1, 1
ld t2, LISP_CONS_HEAD(a0)
ld t3, LISP_CONS_TAIL(a0)
sd t1, 0x10(sp)
sd t2, 0x18(sp)
sd t3, 0x20(sp)
# acquire HEAD
mv a0, t2
call acquire_object
# acquire TAIL
ld a0, 0x20(sp)
call acquire_object
.Luncons_ret:
# always release
ld a0, 0x08(sp)
call release_object
ld ra, 0x00(sp)
ld a0, 0x10(sp)
ld a1, 0x18(sp)
ld a2, 0x20(sp)
addi sp, sp, 0x28
ret
# make integer object from int in a0
.global box_integer
box_integer:
mv a3, zero
mv a2, zero
mv a1, a0
li a0, LISP_OBJECT_TYPE_INTEGER
j make_obj
# make string from buf (a0), len (a1)
# object takes ownership of the buf and will deallocate it on drop
.global box_string
box_string:
mv a3, zero
mv a2, a1
mv a1, a0
li a0, LISP_OBJECT_TYPE_STRING
j make_obj
# Return only head from cons in a0
# Takes ownership of reference, so make sure to acquire first if you don't want to lose the cons
# Returns nil if not cons
.global car
car:
add sp, sp, -0x10
sd ra, 0x00(sp)
sd zero, 0x08(sp) # head
call uncons
beqz a0, .Lcar_ret # not cons
# save head
sd a1, 0x08(sp)
# release tail
mv a0, a2
call release_object
.Lcar_ret:
ld ra, 0x00(sp)
ld a0, 0x08(sp)
addi sp, sp, 0x10
ret
# Return only tail from cons in a0
# Takes ownership of reference, so make sure to acquire first if you don't want to lose the cons
# Returns nil if not cons
.global cdr
cdr:
add sp, sp, -0x10
sd ra, 0x00(sp)
sd zero, 0x08(sp) # tail
call uncons
beqz a0, .Lcdr_ret # not cons
# save tail
sd a2, 0x08(sp)
# release head
mv a0, a1
call release_object
.Lcdr_ret:
ld ra, 0x00(sp)
ld a0, 0x08(sp)
addi sp, sp, 0x10
ret
# load integer from boxed int (a0) and release it
# return 1 on success in a0, int value in a1
.global unbox_integer
unbox_integer:
addi sp, sp, -0x18
sd ra, 0x00(sp)
sd zero, 0x08(sp)
sd zero, 0x10(sp)
beqz a0, .Lunbox_integer_ret # nil
li t1, LISP_OBJECT_TYPE_INTEGER
lw t2, LISP_OBJECT_TYPE(a0)
bne t2, t1, .Lunbox_integer_ret # not integer
# success - get value
li t1, 1
ld t2, LISP_INTEGER_VALUE(a0)
sd t1, 0x08(sp)
sd t2, 0x10(sp)
.Lunbox_integer_ret:
# always release
call release_object
ld ra, 0x00(sp)
ld a0, 0x08(sp)
ld a1, 0x10(sp)
addi sp, sp, 0x18
ret
# make procedure object from a0 (ptr), a1 (data)
# set data to zero (nil) if not used
.global box_procedure
box_procedure:
mv a3, zero
mv a2, a1
mv a1, a0
li a0, LISP_OBJECT_TYPE_PROCEDURE
j make_obj
# unbox and release procedure object (a0), incrementing data refcount first
# a0 = 1 if success
# a1 = ptr
# a2 = data
.global unbox_procedure
unbox_procedure:
addi sp, sp, -0x28
sd ra, 0x00(sp)
sd zero, 0x08(sp)
sd zero, 0x10(sp)
sd zero, 0x18(sp)
sd a0, 0x20(sp)
beqz a0, .Lunbox_procedure_ret # nil
li t1, LISP_OBJECT_TYPE_PROCEDURE
lw t2, LISP_OBJECT_TYPE(a0)
bne t2, t1, .Lunbox_procedure_ret # not procedure
# success - get value
li t1, 1
ld t2, LISP_PROCEDURE_PTR(a0)
ld t3, LISP_PROCEDURE_DATA(a1)
sd t1, 0x08(sp)
sd t2, 0x10(sp)
sd t3, 0x18(sp)
# acquire DATA
mv a0, t3
call acquire_object
.Lunbox_procedure_ret:
# always release
ld a0, 0x20(sp)
call release_object
ld ra, 0x00(sp)
ld a0, 0x08(sp)
ld a1, 0x10(sp)
ld a2, 0x18(sp)
addi sp, sp, 0x28
ret
# sets up a new object and initializes refcount ONLY.
# returns a0=zero on allocation error, otherwise a0=object.
.global new_obj
new_obj:
# keep sp so we can do allocate
addi sp, sp, -8
sd ra, 0(sp)
# allocate lisp object
li a0, LISP_OBJECT_SIZE
li a1, LISP_OBJECT_ALIGN
call allocate
beqz a0, .Lnew_obj_ret # allocation error
# initialize to all zero
sd zero, 0x00(a0)
sd zero, 0x08(a0)
sd zero, 0x10(a0)
sd zero, 0x18(a0)
# set refcount = 1
li t1, 1
sw t1, LISP_OBJECT_REFCOUNT(a0)
.Lnew_obj_ret:
# clean up stack
ld ra, 0(sp)
addi sp, sp, 8
ret
# make an object from type (a0), field0 (a1), field2 (a2), field3 (a3)
# objects are 32 bytes but this assumes that the remainder after type and refcount
# are all double-words
.global make_obj
make_obj:
addi sp, sp, -0x28
sd ra, 0x00(sp)
sd a0, 0x08(sp)
sd a1, 0x10(sp)
sd a2, 0x18(sp)
sd a3, 0x20(sp)
call new_obj
beqz a0, .Lmake_obj_ret
ld t1, 0x08(sp)
sw t1, LISP_OBJECT_TYPE(a0)
ld t2, 0x10(sp) # original a1
ld t3, 0x18(sp) # original a2
ld t4, 0x20(sp) # original a3
sd t2, 0x08(a0) # field0
sd t3, 0x10(a0) # field1
sd t4, 0x18(a0) # field2
.Lmake_obj_ret:
ld ra, 0x00(sp)
addi sp, sp, 0x28
ret
# object to print in a0
# preserves a0, does not touch refcount
.global print_obj
print_obj:
# reserve stack and save arg in s1
addi sp, sp, -0x18
sd ra, 0x00(sp)
sd s1, 0x08(sp)
sd a0, 0x10(sp) # so we can preserve it
mv s1, a0
beqz s1, .Lprint_obj_cons # since nil = (), handle with cons
# check object type
lw t0, LISP_OBJECT_TYPE(s1)
li t1, LISP_OBJECT_TYPE_CONS
beq t0, t1, .Lprint_obj_cons
li t1, LISP_OBJECT_TYPE_INTEGER
beq t0, t1, .Lprint_obj_integer
li t1, LISP_OBJECT_TYPE_SYMBOL
beq t0, t1, .Lprint_obj_symbol
li t1, LISP_OBJECT_TYPE_STRING
beq t0, t1, .Lprint_obj_string
# for anything else, print the raw fields
li a0, '<'
call putc
ld a0, 0x00(s1)
li a1, 16
call put_hex
li a0, ' '
call putc
ld a0, 0x08(s1)
li a1, 16
call put_hex
li a0, ' '
call putc
ld a0, 0x10(s1)
li a1, 16
call put_hex
li a0, ' '
call putc
ld a0, 0x18(s1)
li a1, 16
call put_hex
li a0, '>'
call putc
j .Lprint_obj_ret
.Lprint_obj_cons:
li a0, '('
call putc
beqz s1, .Lprint_obj_cons_end # handle nil case here
.Lprint_obj_cons_loop:
# print head
ld a0, LISP_CONS_HEAD(s1)
call print_obj
# prepare to loop on tail
ld s1, LISP_CONS_TAIL(s1)
# if it's nil, just end
beqz s1, .Lprint_obj_cons_end
# print a space since we need it in either case
li a0, ' '
call putc
# check if the type is CONS and loop if so
lw t0, LISP_OBJECT_TYPE(s1)
li t1, LISP_OBJECT_TYPE_CONS
beq t0, t1, .Lprint_obj_cons_loop
# this is an assoc so put the dot and space
li a0, '.'
call putc
li a0, ' '
call putc
# then print the object and end without looping
mv a0, s1
call print_obj
.Lprint_obj_cons_end:
li a0, ')'
call putc
j .Lprint_obj_ret
.Lprint_obj_integer:
# TODO: it would be nice to flag integers that should be presented as hex?
ld a0, LISP_INTEGER_VALUE(s1)
call put_dec
j .Lprint_obj_ret
.Lprint_obj_symbol:
# just print the string
ld a0, LISP_SYMBOL_BUF(s1)
ld a1, LISP_SYMBOL_LEN(s1)
call put_buf
j .Lprint_obj_ret
.Lprint_obj_string:
# get string buf, len
addi sp, sp, -0x10
sd s2, 0x00(sp)
sd s3, 0x08(sp)
ld s2, LISP_STRING_BUF(s1)
ld s3, LISP_STRING_LEN(s1)
# put quote
li a0, 0x22
call putc
# loop through chars, print double quote if quote
1:
beqz s3, 2f
lb a0, (s2)
call putc
lb a0, (s2)
li t0, 0x22
addi s2, s2, 1
addi s3, s3, -1
bne a0, t0, 1b # not a quote
call putc # print extra quote
j 1b
2:
# closing quote
li a0, 0x22
call putc
ld s2, 0x00(sp)
ld s3, 0x08(sp)
addi sp, sp, 0x10
j .Lprint_obj_ret
.Lprint_obj_zero_x:
li a0, '0'
call putc
li a0, 'x'
call putc
jr t0
.Lprint_obj_ret:
ld ra, 0x00(sp)
ld s1, 0x08(sp)
ld a0, 0x10(sp)
addi sp, sp, 0x18
ret