/
comp.arc
2331 lines (1963 loc) · 63.5 KB
/
comp.arc
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
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; Copyright (c) 2008 Dissegna Stefano
; Released under the terms of the GNU LGPL
; Registers:
; eax: return values, number of arguments before function call
; esp: stack pointer (grows downwards)
; ebp: heap pointer (grows upwards)
; edi: current closure pointer
; esi: structure holding saved C registers
(set stdout* (stdout-stream))
(def emit args
(write-string (reduce str-append (map to-string args) "") stdout*)
(write-string "
" stdout*))
(set wordsize 4)
(set fxshift 2)
(set fxtag 0) ; #b00
(set fxmask 3) ; #x03
(set chshift 8)
(set chtag 15) ; #b00001111
(set chmask 255) ; #xFF
(set nil-val 47) ; #x2F
(set t-val 111) ; #x6F
(set bool-bit 6)
(set cellmask 7) ; #x7
(set celltag 1) ; #b001
(set cell-size (* 2 wordsize))
(set car-offset (- celltag))
(set cdr-offset (- wordsize celltag))
(set vecmask 7) ; #x7
(set vectag 5) ; #b101
(set closuremask 7) ; #x7
(set closuretag 2) ; #b010
(set closurelen-offset (- closuretag))
(set closureaddr-offset (- wordsize closuretag))
(set symbolmask 7) ; #x7
(set symboltag 3) ; #b011
(set symbolstring-offset (- symboltag))
(set symbolval-offset (- wordsize symboltag))
(set symbolplist-offset (+ symbolval-offset wordsize))
(set basicmask 7) ; #x7
(set extendedtag 6) ; #b110
(set strtag fxtag)
(set strchar-offset (- wordsize extendedtag))
(set floattag 207) ; #xCF
(set float-offset (- wordsize extendedtag))
(set continuation-tag 175) ; #xAF
(set unbound-val 63) ; #b111111
;; tells that the next value in the stack is a return adress
;; needed by the GC while scanning the stack
(set frame-sentinel 255) ; #xFF
(set fixnum-bits (- (* wordsize 8) fxshift))
(set fxlower -536870912);(- (expt 2 (- fixnum-bits 1))))
(set fxupper (- (- fxlower) 1))
(set let-sym '__let)
(set lambda-sym '__fn)
(set if-sym '__if)
(set setq-sym 'set)
(set call-table-lbl "__call_table")
(set call-table-err-lbl "__call_table_type_error")
(def fixnump (x)
(fxp x)); (<= fxlower x) (<= x fxupper)))
(def charp (x)
(charp x))
(def immediatep (x)
(or (fixnump x) (charp x) (is x nil) (is x t)))
(def imm-rep (x)
(if
(fixnump x) (* x 4);fxshift)
(charp x) (+ (* (char->fx x) 256) chtag)
(is x nil) nil-val
(is x t) t-val
(is x 't) t-val
(is x 'nil) nil-val
(err "Cannot find suitable representation")))
(def install-primop (name f n-args rest-args)
(plist-set name 'is-prim t)
(plist-set name 'n-args n-args)
(plist-set name 'rest-args rest-args)
(plist-set name 'emitter f))
(def make-alias (name1 name2)
(plist-set name1 'emitter (plist-get name2 'emitter))
(plist-set name1 'n-args (plist-get name2 'n-args))
(plist-set name1 'rest-args (plist-get name2 'rest-args))
(plist-set name1 'is-prim (plist-get name2 'is-prim)))
(def primitivep (x)
(and (symbolp x) (plist-get x 'is-prim)))
(def emitter (x)
(or (plist-get x 'emitter)
(err (make-string "Couldn't find an emitter for " x))))
(def primcallp (expr)
(and (consp expr) (primitivep (car expr))))
(def check-primcall-args (prim args)
(if (not (or (and (not (plist-get prim 'rest-args))
(is (len args) (plist-get prim 'n-args)))
(and (plist-get prim 'rest-args)
(>= (len args) (plist-get prim 'n-args)))))
(err (str-append "Wrong number of arguments to " (to-string prim)))))
(def emit-primcall (si env expr)
(with (prim (car expr) args (cdr expr))
(check-primcall-args prim args)
(apply (emitter prim) si env args)))
(set ax "%ax")
(set al "%al")
(set eax "%eax")
(set ebx "%ebx")
(set ecx "%ecx")
(set edx "%edx")
(set edi "%edi")
(set ebp "%ebp")
(set esp "%esp")
(set esi "%esi")
(def make-string args
(reduce str-append (map to-string args) ""))
(def globl (lbl)
(emit " .globl " lbl))
(def imm (val)
(make-string "$" val))
(def deref (offset reg)
(make-string offset "(" reg ")"))
(def unref-call (dest)
(make-string "*" dest))
(def call (label)
(emit " call " label))
(def sete (reg)
(emit " sete " reg))
(def setl (reg)
(emit " setl " reg))
(def setle (reg)
(emit " setle " reg))
(def setg (reg)
(emit " setg " reg))
(def setge (reg)
(emit " setge " reg))
(def seta (reg)
(emit " seta " reg))
(def setb (reg)
(emit " setb " reg))
(def setbe (reg)
(emit " setbe " reg))
(def setae (reg)
(emit " setae " reg))
(def movzbl (r1 r2)
(emit " movzbl " r1 ", " r2))
(def cmp (a b)
(emit " cmpl " a ", " b))
(def op-and (a b)
(emit " andl " a ", " b))
(def op-or (a b)
(emit " or " a ", " b))
(def op-orl (a b)
(emit " orl " a ", " b))
(def andl (a b)
(emit " andl " a ", " b))
(def label (lbl)
(emit lbl ":"))
(def jmp (lbl)
(emit " jmp " lbl))
(def je (lbl)
(emit " je " lbl))
(def jne (lbl)
(emit " jne " lbl))
(def jl (lbl)
(emit " jl " lbl))
(def jge (lbl)
(emit " jge " lbl))
(def unref (offset reg dest)
(emit " movl " offset "(" reg "), " dest))
(def movb (from to)
(emit " movb " from ", " to))
(def movl (from to)
(emit " movl " from ", " to))
(def lea (base dest-reg)
(emit " lea " base ", " dest-reg))
(def addl (a b)
(emit " addl " a ", " b))
(def subl (a b)
(emit " subl " a ", " b))
(def sal (a b)
(emit " sal " a ", " b))
(def sall (a b)
(emit " sall " a ", " b))
(def shll (a b)
(emit " shll " a ", " b))
(def shrl (a b)
(emit " shrl " a ", " b))
(def sarl (a b)
(emit " sarl " a ", " b))
(def xorl (a b)
(emit " xorl " a ", " b))
(def imull (a b)
(emit " imull " a ", " b))
(def idivl (a)
(emit " idivl " a))
(def cdq ()
(emit " cdq"))
(def emit-save (si reg)
; emit code for saving reg in the stack
(emit " movl " reg ", " si "(" esp ")"))
(def emit-load (si reg)
(emit " movl " si "(" esp "), " reg))
(def pushl (what)
(emit " pushl " what))
(def next-si (si)
(- si wordsize))
(def next-si-n (si n)
(- si (* n wordsize)))
(def fstpl (from)
(emit " fstpl " from))
(def fldl-plain (arg)
(emit " fldl " arg))
(def fucompp ()
(emit " fucompp"))
(def fnstsw (reg)
(emit " fnstsw " reg))
(def sahf ()
(emit " sahf"))
; the following float operations assume reg is a register containing the
; adress of a tagged float object and do automatic dereferencing
(def fldl (reg)
(emit " fldl " float-offset "(" reg ")"))
(def faddl (reg)
(emit " faddl " float-offset "(" reg ")"))
(def fsubl (reg)
(emit " fsubl " float-offset "(" reg ")"))
(def fmull (reg)
(emit " fmull " float-offset "(" reg ")"))
(def fdivl (reg)
(emit " fdivl " float-offset "(" reg ")"))
(def fildl (si)
(emit " fildl " si "(" esp ")"))
(def fistpl (si)
(emit " fistpl " si "(" esp ")"))
(def emit-call-expand-heap (si . size)
; expects number of bytes to allocate in %eax if size is nil
; address of allocated memory will be in %eax
(let size (car size)
(emit-save si edi) ; do not collect cl. pt!
(let si (next-si si)
(if size
(movl (imm size) (deref si esp))
(movl eax (deref si esp)))
(lea (deref si esp) eax)
(movl eax (deref (next-si si) esp))
;(movl ebp (deref (next-si-n si 2) esp))
(addl (imm (next-si si)) esp)
;(addl (imm (next-si-n si 2)) esp)
(call "main_expand_heap2")
(subl (imm (next-si si)) esp))
;(subl (imm (next-si-n si 2)) esp)
;(movl eax ebp))
(emit-load si edi)))
; runtime global memory area holding the base of the current stack
(set main-stack-base "main_stack_base")
;(def emit-stack-copy-rev (si)
; emit code to copy the stack up to si (exclusive) into the heap
; the stack grows downwards and the heap upwards, so it is copied in
; reverse order
; space on the heap must be allocated and memory pointer must be in %ebp
; ebx: source pointer
; ebp: target pointer
; (movl main-stack-base ebx)
; (addl (imm si) esp) ; esp: first adress not to copy
; (with (loop-start (unique-label)
; end (unique-label))
; (label loop-start)
; (cmp ebx esp)
; (je end)
; (movl (deref 0 ebx) ecx) ; copy wordsize bytes
; (movl ecx (deref 0 ebp))
; (addl (imm wordsize) ebp) ; next target adress
; (addl (imm (- wordsize)) ebx) ; next source adress
; (jmp loop-start)
; (label loop-end))
; (subl (imm si) esp)) ; restore esp
(def emit-restore-stack ()
; emit code to copy back the stack from the heap to main_stack_base
; expects closure in eax and continuation's stack pt. in esp
; ecx: current address to copy
; edx: main stack destination
; esp: destination end point
(movl (deref (+ (- extendedtag) wordsize) eax) ebx) ; stack len
(lea (deref (+ (- extendedtag) (* 5 wordsize)) eax) ecx) ; stack start addr.
(movl main-stack-base edx)
(movl edx esp)
(subl ebx esp)
(subl (imm wordsize) edx)
(with (loop-start (unique-label)
loop-end (unique-label))
(label loop-start)
(cmp edx esp) ; test
(je loop-end)
(movl (deref 0 ecx) ebx)
(movl ebx (deref 0 edx))
(addl (imm wordsize) ecx)
(addl (imm (- wordsize)) edx)
(jmp loop-start)
(label loop-end)))
; (movl (deref (+ (- extendedtag) wordsize) eax) ebx) ; stack len
; (addl ebx esp))
(def emit-call-stack-copy-rev (si)
; emit code to call the C function stack_copy_rev
; stack_copy_rev allocates heap space, so edi must be passed in the stack
; and then restored, because the GC could change the location of the closure
; it points at
(emit-save si edi)
(let si (next-si si)
(lea (deref si esp) eax) ; stack_top
(emit-save si eax)
(addl (imm si) esp)
(call "stack_copy_rev")
(subl (imm si) esp))
(emit-load si edi))
(def emit-type-pred (basic-mask basic-tag . rest)
(with (etag (car rest)
emask (cadr rest))
(movl eax ebx)
(andl (imm basic-mask) eax)
(cmp (imm basic-tag) eax)
(if etag
(let end (unique-label)
(jne end)
(unref (- extendedtag) ebx ebx)
(if emask
(op-and (imm emask) ebx))
(cmp (imm etag) ebx)
(label end)))
(sete al)
(movzbl al eax)
(sal (imm bool-bit) al)
(op-or (imm nil-val) al)))
(def emit-type-check (si env name);mask tag)
; emit code fore checking type of value in %eax
;(movl eax ebx)
;(op-and (imm mask) ebx)
;(cmp (imm tag) ebx)
;(let cont-label (unique-label)
; (je cont-label)
; (movl (imm 0) eax)
; (addl (imm si) esp)
; (jmp '__type_error)
; (label cont-label)))
(addl (imm (+ si wordsize)) esp)
(call (make-string "__check_" name))
(subl (imm (+ si wordsize)) esp))
(def emit-get-tag (src dest-reg tmp-reg)
; get the tag of the object pointed by the register src
; put tag in dest-reg
(let cont (unique-label) ; label to the end of this routine
; check if it is a character
(movl src dest-reg)
(op-and (imm chmask) dest-reg)
(cmp (imm chtag) dest-reg)
(je cont) ; yes it is
; check if it is a basic type
(movl src dest-reg)
(op-and (imm basicmask) dest-reg)
(cmp (imm extendedtag) dest-reg) ; is it an extended type?
(jne cont)
(movl (deref (- extendedtag) src) dest-reg) ; get extended type tag
; special case to handle strings' tag
(movl dest-reg tmp-reg)
(op-and (imm fxmask) tmp-reg)
(cmp (imm strtag) tmp-reg)
(jne cont)
(movl (imm extendedtag) dest-reg) ; it's a string
(label cont)))
(def emit-static-type-check-routine (name mask tag extended-p)
(decl-globl (make-string "__check_" name))
(emit-fun-header (make-string "__check_" name))
(movl eax ebx)
(op-and (imm (if extended-p basicmask mask)) ebx)
(cmp (imm (if extended-p extendedtag tag)) ebx)
(let err-label (unique-label)
(jne err-label)
(if extended-p
(do
(movl (deref (- extendedtag) eax) ebx) ; get extended object tag
(if mask
(op-and (imm mask) ebx))
(cmp (imm tag) ebx)
(jne err-label)))
(emit-fun-ret)
(label err-label)
(subl (imm wordsize) esp) ; adjust esp to be consistent with labelcall
(emit-save wordsize (imm frame-sentinel))
(emit-save 0 (imm 0)) ; won't return, no need to have a valid ret. point
(if (and extended-p mask)
(movl (imm (+ extendedtag tag)) ecx)
(movl (imm tag) ecx))
(shll (imm fxshift) ecx) ; make the tag a fixnum
(emit-save (next-si 0) ecx) ; pass expected tag
(emit-get-tag eax ebx ecx)
(shll (imm fxshift) ebx)
(emit-save (next-si-n 0 2) ebx) ; pass tag found
(movl (imm 2) eax) ; number of args passed
(jmp '__type_error)))
(def emit-extended-type-check (si env tag . mask)
(let mask (car mask)
(emit-type-check si env "extended"); basicmask extendedtag)
(movl (deref (- extendedtag) eax) ebx)
(if mask
(op-and (imm mask) ebx))
(cmp (imm tag) ebx)
(with (;error-label (unique-label)
cont-label (unique-label))
;(jne error-label)
;(jmp cont-label)
(je cont-label)
;(label error-label)
(movl (imm 0) eax)
(addl (imm si) esp)
(jmp '__type_error)
(label cont-label))))
(def emit-is-fx (si env)
(emit-type-check si env "fx"));fxmask fxtag))
(def emit-is-ch (si env)
(emit-type-check si env "ch"));chmask chtag))
(def emit-is-cell (si env)
(emit-type-check si env "cell"));cellmask celltag))
(def emit-is-vec (si env)
(emit-type-check si env "vec"));vecmask vectag))
(def emit-is-str (si env)
(emit-type-check si env "str"));strtag fxmask))
(def emit-is-float (si env)
(emit-type-check si env "float"));floattag))
(def emit-is-sym (si env)
(emit-type-check si env "sym"));symbolmask symboltag))
(def emit-is-closure (si env)
(emit-type-check si env "closure"));closuremask closuretag))
(def emit-is-continuation (si env)
(emit-type-check si env "continuation"))
(def emit-exact-arg-count-check (si env n)
(with (error-label (unique-label)
cont-label (unique-label))
(cmp (imm n) eax)
;(jne error-label)
;(jmp cont-label)
(je cont-label)
;(label error-label)
(movl (imm 0) eax)
(addl (imm si) esp)
(jmp '__arg_count_error)
(label cont-label)))
(def emit-at-least-arg-count-check (si n)
(with (error-label (unique-label)
cont-label (unique-label))
(cmp (imm n) eax)
;(jl error-label)
;(jmp cont-label)
(jge cont-label)
;(label error-label)
(movl (imm 0) eax)
(addl (imm si) esp)
(jmp '__arg_count_error)
(label cont-label)))
(def emit-unbound-check (si)
; expects value to check in eax and corresponding symbol in ebx
(with (error-label (unique-label)
cont-label (unique-label))
(cmp (imm unbound-val) eax)
(jne cont-label)
(movl (imm frame-sentinel) (deref si esp))
(movl (imm 0) (deref (next-si si) esp))
(movl ecx (deref (next-si-n si 2) esp))
(movl (imm 1) eax)
(addl (imm si) esp)
(movl '__unbound_error_fun ecx)
(call (unref-call (deref 2 ecx)))
(subl (imm si) esp)
(label cont-label)))
(def emit-bounds-check (si tag reg)
; emit error checking on vector/string access. Expects vector/string on the
; stack and the index in eax
; if reg is given the vector/string is supposed to be there
(with (error-label (unique-label)
cont-label (unique-label))
(if reg
(movl reg ebx)
(movl (deref si esp) ebx))
(movl (deref (- tag) ebx) ebx) ; get size
(cmp (imm 0) eax)
(jl error-label) ; check for negative index
(cmp ebx eax)
;(jge error-label)
;(jmp cont-label)
(jl cont-label)
(label error-label)
(movl (imm 0) eax)
(addl (imm si) esp)
(jmp '__bounds_error)
(label cont-label)))
(def fxadd1 (si env arg)
(emit-expr si env arg)
(emit-is-fx si env)
(addl (imm (imm-rep 1)) eax))
(install-primop 'fxadd1 fxadd1 1 nil)
(def fxsub1 (si env arg)
(emit-expr si env arg)
(emit-is-fx si env)
(subl (imm (imm-rep 1)) eax))
(install-primop 'fxsub1 fxsub1 1 nil)
(def fxlognot (si env arg)
(emit-expr si env arg)
(emit-is-fx si env)
(xorl (imm (imm-rep -1)) eax))
(install-primop 'fxlognot fxlognot 1 nil)
(def fx->char (si env arg)
(emit-expr si env arg)
(emit-is-fx si env)
(shll (imm (- chshift fxshift)) eax)
(op-orl (imm chtag) eax))
(install-primop 'fx->char fx->char 1 nil)
(def char->fx (si env arg)
(emit-expr si env arg)
(emit-is-ch si env)
(shrl (imm (- chshift fxshift)) eax))
(install-primop 'char->fx char->fx 1 nil)
(def fxp (si env arg)
(emit-expr si env arg)
(emit-type-pred fxmask fxtag))
(install-primop 'fxp fxp 1 nil)
(def fxzerop (si env arg)
(emit-expr si env arg)
(emit-is-fx si env)
(cmp (imm (imm-rep 0)) eax)
(sete al)
(movzbl al eax)
(sal (imm bool-bit) al)
(op-or (imm nil-val) al))
(install-primop 'fxzerop fxzerop 1 nil)
(def nullp (si env arg)
(emit-expr si env arg)
(cmp (imm nil-val) eax)
(sete al)
(movzbl al eax)
(sal (imm bool-bit) al)
(op-or (imm nil-val) al))
(install-primop 'nullp nullp 1 nil)
(make-alias 'not 'nullp)
(def op-charp (si env arg)
(emit-expr si env arg)
(emit-type-pred chmask chtag))
(install-primop 'charp op-charp 1 nil)
(def op-consp (si env arg)
(emit-expr si env arg)
(emit-type-pred cellmask celltag))
(install-primop 'consp op-consp 1 nil)
(def op-car (si env arg)
(emit-expr si env arg)
(cmp (imm (imm-rep nil)) eax)
(let end (unique-label)
(je end)
(emit-is-cell si env)
(unref car-offset eax eax)
(label end)))
(install-primop 'car op-car 1 nil)
(def op-cdr (si env arg)
(emit-expr si env arg)
(cmp (imm (imm-rep nil)) eax)
(let end (unique-label)
(je end)
(emit-is-cell si env)
(unref cdr-offset eax eax)
(label end)))
(install-primop 'cdr op-cdr 1 nil)
(def emit-build-cons ()
; saves current %ebp pointer in %eax, marks it as a cons cell and bumps %ebp
;(movl ebp eax)
;(addl (imm cell-size) ebp)
(op-orl (imm celltag) eax))
(def op-cons (si env the-car the-cdr)
(emit-expr si env the-car)
(movl eax (deref si esp))
(emit-expr (next-si si) env the-cdr)
(movl eax (deref (next-si si) esp))
(emit-call-expand-heap (next-si-n si 2) (* 2 wordsize))
(movl (deref (next-si si) esp) ebx)
(movl ebx (deref wordsize eax))
(movl (deref si esp) ebx)
(movl ebx (deref 0 eax))
(emit-build-cons))
(install-primop 'cons op-cons 2 nil)
(def op-setcar (si env the-cons value)
(emit-expr si env the-cons)
(emit-is-cell si env)
(movl eax (deref si esp))
(emit-expr (next-si si) env value)
(movl (deref si esp) ebx)
(movl eax (deref car-offset ebx)))
(install-primop 'setcar op-setcar 2 nil)
(def op-setcdr (si env the-cons value)
(emit-expr si env the-cons)
(emit-is-cell si env)
(movl eax (deref si esp))
(emit-expr (next-si si) env value)
(movl (deref si esp) ebx)
(movl eax (deref cdr-offset ebx)))
(install-primop 'setcdr op-setcdr 2 nil)
; a symbol has three values: a string, a value, a plist
(def op-mksymbol (si env string-expr)
(emit-expr si env string-expr)
(emit-is-str si env)
(emit-save si eax)
(emit-call-expand-heap (next-si si) (* 4 wordsize))
;(movl eax ebp)
(emit-load si ebx);eax)
;(emit-is-str si env)
(movl ebx (deref 0 eax))
(movl (imm unbound-val) (deref wordsize eax))
(movl (imm nil-val) (deref (* 2 wordsize) eax))
;(movl ebp eax)
;(addl (imm (* 4 wordsize)) ebp) ; round at 8 byte boundaries
(op-orl (imm symboltag) eax))
(install-primop 'mksymbol op-mksymbol 1 nil)
(def op-symbolp (si env arg)
(emit-expr si env arg)
(emit-type-pred symbolmask symboltag))
(install-primop 'symbolp op-symbolp 1 nil)
(def op-get-symbol-value (si env sym)
(emit-expr si env sym)
(emit-is-sym si env)
(movl eax ecx)
(unref symbolval-offset eax eax)
(emit-unbound-check si))
(install-primop 'get-symbol-value op-get-symbol-value 1 nil)
(def op-get-symbol-string (si env sym)
(emit-expr si env sym)
(emit-is-sym si env)
(unref symbolstring-offset eax eax))
(install-primop 'get-symbol-string op-get-symbol-string 1 nil)
(def op-set-symbol-value (si env sym arg)
(emit-expr si env sym)
(emit-is-sym si env)
(emit-save si eax)
(emit-expr (next-si si) env arg)
(emit-load si ebx)
(movl eax (deref symbolval-offset ebx)))
(install-primop 'set-symbol-value op-set-symbol-value 2 nil)
(def op-get-symbol-plist (si env sym)
(emit-expr si env sym)
(emit-is-sym si env)
(unref symbolplist-offset eax eax))
(install-primop 'get-symbol-plist op-get-symbol-plist 1 nil)
(def op-set-symbol-plist (si env sym arg)
(emit-expr si env sym)
(emit-is-sym si env)
(emit-save si eax)
(emit-expr (next-si si) env arg)
(emit-load si ebx)
(movl eax (deref symbolplist-offset ebx)))
(install-primop 'set-symbol-plist op-set-symbol-plist 2 nil)
(def op-vecp (si env arg)
(emit-expr si env arg)
(emit-type-pred vecmask vectag))
(install-primop 'vecp op-vecp 1 nil)
;; vector:
;; ---------------------------------------
;; | length | field 0 | filed 1 | ...
;; ---------------------------------------
;; | wordsize | wordsize | wordsize | ...
;; ---------------------------------------
(def op-mkvec (si env size elem)
(emit-expr si env size)
(emit-is-fx si env)
(emit-save si eax) ; save length
; !!! warning: stack position (next-si si) unknown during evaluation
; of elem (could be a problem for GC) !!!
(emit-expr (next-si-n si 2) env elem)
(emit-save (next-si-n si 2) eax) ; save elem
; round up size to be at 2*wordsize-byte boundaries
; and add space for length field
(emit-load si eax)
(addl (imm (+ wordsize (- (* 2 wordsize) 1))) eax)
(andl (imm (- (* 2 wordsize))) eax)
(emit-save (next-si si) eax) ; save size
(emit-call-expand-heap (- si (* 3 wordsize)))
(emit-load si ebx)
(movl ebx (deref 0 eax)) ; set length field
;(movl ebp eax)
(movl eax ebp)
(emit-load (next-si si) ebx) ; get back size
; loop to init all elements to the value of elem
(with (loop-label (unique-label)
end-label (unique-label))
(emit-load (next-si-n si 2) ecx)
(addl (imm wordsize) ebp)
(subl (imm wordsize) ebx)
(label loop-label)
(cmp (imm 0) ebx)
(je end-label)
(movl ecx (deref 0 ebp))
(addl (imm wordsize) ebp)
(subl (imm (imm-rep 1)) ebx)
(jmp loop-label)
(label end-label)
(op-orl (imm vectag) eax)))
(install-primop 'mkvec op-mkvec 2 nil)
(def op-vec-set (si env arg1 arg2 arg3)
(emit-expr si env arg1)
(emit-is-vec si env)
(emit-save si eax)
(emit-expr (next-si si) env arg2)
(emit-is-fx (next-si si) env)
(emit-bounds-check si vectag nil)
(emit-save (next-si si) eax)
(emit-expr (next-si-n si 2) env arg3)
(emit-load si ebx) ; get vector adress
(addl (deref (next-si si) esp) ebx) ; sum offset
(movl eax (deref (+ wordsize (- vectag)) ebx))) ; set value
(install-primop 'vec-set op-vec-set 3 nil)
(def op-vec-ref (si env arg1 arg2)
(emit-expr si env arg1)
(emit-is-vec si env)
(emit-save si eax)
(emit-expr (next-si si) env arg2)
(emit-is-fx (next-si si) env)
(emit-bounds-check si vectag nil)
(emit-load si ebx) ; get vector adress
(addl eax ebx) ; sum offset
(movl (deref (+ wordsize (- vectag)) ebx) eax)) ; get value
(install-primop 'vec-ref op-vec-ref 2 nil)
(def op-vec-len (si env arg1)
(emit-expr si env arg1)
(emit-is-vec si env)
(movl (deref (- vectag) eax) eax))
(install-primop 'vec-len op-vec-len 1 nil)
(def emit-extended-pred (tag . mask)
(with (mask (car mask)
end (unique-label)
false (unique-label))
(movl eax ebx)
(andl (imm basicmask) ebx)
(cmp (imm extendedtag) ebx)
(jne false)
(movl (deref (- extendedtag) eax) eax)
(if mask
(andl (imm mask) eax))
(cmp (imm tag) eax)
(jne false)
(movl (imm (imm-rep t)) eax)
(jmp end)
(label false)
(movl (imm (imm-rep nil)) eax)
(label end)))
(def op-strp (si env arg)
(emit-expr si env arg)
(emit-extended-pred strtag fxmask))
(install-primop 'strp op-strp 1 nil)
; allocation initializes args to 0
(install-primop 'mkstr
(fn (si env size-expr)
(emit-expr si env size-expr)
(emit-is-fx si env)
(emit-save si eax) ; save length
; round up size to be at 2*wordsize-byte boundaries
(movl eax ebx)
; strings are made of 1-byte cells
(shrl (imm fxshift) ebx)
(addl (imm (+ wordsize (- (* 2 wordsize) 1))) ebx)
(andl (imm (- (* 2 wordsize))) ebx)
;(emit-save (next-si si) ebx) ; save size
(movl ebx eax)
(emit-call-expand-heap (next-si-n si 1))
(emit-load si ebx)
(movl ebx (deref 0 eax)) ; put length in its field
;(movl ebp eax)
;(emit-load (next-si si) ebx)
;(addl ebx ebp)
(op-orl (imm extendedtag) eax))
1 nil)
(install-primop 'str-set
(fn (si env arg1 arg2 arg3)
(emit-expr si env arg1)
(emit-is-str si env)
(emit-save si eax)
(emit-expr (next-si si) env arg2)
(emit-is-fx (next-si si) env)
(emit-bounds-check si extendedtag nil)
(emit-save (next-si si) eax)
(emit-expr (next-si-n si 2) env arg3)
(emit-is-ch (next-si-n si 2) env)
(shrl (imm chshift) eax) ; remove char tag
(emit-load si ebx) ; get string adress
(shrl (imm fxshift) (deref (next-si si) esp)) ; 1-byte
(addl (deref (next-si si) esp) ebx) ; sum offset
(movb al (deref (+ wordsize (- extendedtag)) ebx)) ; set value
(shll (imm chshift) eax) ; return orginal char value
(op-orl (imm chtag) eax))
3 nil)
(install-primop 'str-ref
(fn (si env arg1 arg2)
(emit-expr si env arg1)
(emit-is-str si env)
(emit-save si eax)
(emit-expr (next-si si) env arg2)
(emit-is-fx (next-si si) env)
(emit-bounds-check si extendedtag nil)
(emit-load si ebx) ; get string adress
(shrl (imm fxshift) eax) ; 1-byte
(addl eax ebx) ; sum offset
(movb (deref (+ wordsize (- extendedtag)) ebx) al) ; get value
(movzbl al eax)
(shll (imm chshift) eax)
(op-orl (imm chtag) eax))
2 nil)
(install-primop 'str-len
(fn (si env arg1)
(emit-expr si env arg1)
(emit-is-str si env)
(movl (deref (- extendedtag) eax) eax))
1 nil)
(def op-vector-aux (si env i items)
(if items
(do
(emit-expr (next-si si) env (car items))
(emit-load si ebx)
(movl eax (deref (+ wordsize (- (* wordsize i) vectag)) ebx))
(op-vector-aux si env (+ i 1) (cdr items)))))
(install-primop 'vector