]> gitweb.factorcode.org Git - factor.git/blob - basis/bootstrap/assembler/x86.factor
VM: fix jit-signal-handler-prolog/epilog to account for the home space
[factor.git] / basis / bootstrap / assembler / x86.factor
1 ! Copyright (C) 2007, 2011 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: bootstrap.image.private compiler.codegen.relocation
4 compiler.constants compiler.units cpu.x86.assembler
5 cpu.x86.assembler.operands kernel kernel.private layouts locals
6 locals.backend math math.private namespaces sequences
7 slots.private strings.private vocabs ;
8 IN: bootstrap.x86
9
10 big-endian off
11
12 ! C to Factor entry point
13 [
14     ! Optimizing compiler's side of callback accesses
15     ! arguments that are on the stack via the frame pointer.
16     ! On x86-32 fastcall, and x86-64, some arguments are passed
17     ! in registers, and so the only registers that are safe for
18     ! use here are frame-reg, nv-reg and vm-reg.
19     frame-reg PUSH
20     frame-reg stack-reg MOV
21
22     ! Save all non-volatile registers
23     nv-regs [ PUSH ] each
24
25     jit-save-tib
26
27     ! Load VM into vm-reg
28     vm-reg 0 MOV 0 rc-absolute-cell rel-vm
29
30     ! Save old context
31     nv-reg vm-reg vm-context-offset [+] MOV
32     nv-reg PUSH
33
34     ! Switch over to the spare context
35     nv-reg vm-reg vm-spare-context-offset [+] MOV
36     vm-reg vm-context-offset [+] nv-reg MOV
37
38     ! Save C callstack pointer
39     nv-reg context-callstack-save-offset [+] stack-reg MOV
40
41     ! Load Factor stack pointers
42     stack-reg nv-reg context-callstack-bottom-offset [+] MOV
43     nv-reg jit-update-tib
44     jit-install-seh
45
46     rs-reg nv-reg context-retainstack-offset [+] MOV
47     ds-reg nv-reg context-datastack-offset [+] MOV
48
49     ! Call into Factor code
50     link-reg 0 MOV f rc-absolute-cell rel-word
51     link-reg CALL
52
53     ! Load VM into vm-reg; only needed on x86-32, but doesn't
54     ! hurt on x86-64
55     vm-reg 0 MOV 0 rc-absolute-cell rel-vm
56
57     ! Load C callstack pointer
58     nv-reg vm-reg vm-context-offset [+] MOV
59     stack-reg nv-reg context-callstack-save-offset [+] MOV
60
61     ! Load old context
62     nv-reg POP
63     vm-reg vm-context-offset [+] nv-reg MOV
64
65     ! Restore non-volatile registers
66     jit-restore-tib
67
68     nv-regs <reversed> [ POP ] each
69
70     frame-reg POP
71
72     ! Callbacks which return structs, or use stdcall/fastcall/thiscall,
73     ! need a parameter here.
74
75     ! See the comment for M\ x86.32 stack-cleanup in cpu.x86.32
76     0xffff RET f rc-absolute-2 rel-untagged
77 ] CALLBACK-STUB jit-define
78
79 [
80     ! load literal
81     temp0 0 MOV f rc-absolute-cell rel-literal
82     ! increment datastack pointer
83     ds-reg bootstrap-cell ADD
84     ! store literal on datastack
85     ds-reg [] temp0 MOV
86 ] JIT-PUSH-IMMEDIATE jit-define
87
88 [
89     0 CALL f rc-relative rel-word-pic
90 ] JIT-WORD-CALL jit-define
91
92 ! The *-signal-handler subprimitives are special-cased in vm/quotations.cpp
93 ! not to trigger generation of a stack frame, so they can
94 ! peform their own prolog/epilog preserving registers.
95 !
96 ! It is important that the total is 192/64 and that it matches the
97 ! constants in vm/cpu-x86.*.hpp
98 : jit-signal-handler-prolog ( -- )
99     ! Return address already on stack -> 8/4 bytes.
100
101     ! Push all registers. 15 regs/120 bytes on 64bit, 7 regs/28 bytes
102     ! on 32bit -> 128/32 bytes.
103     signal-handler-save-regs [ PUSH ] each
104
105     ! Push flags -> 136/36 bytes
106     PUSHF
107
108     ! Register parameter area 32 bytes, unused on platforms other than
109     ! windows 64 bit, but including it doesn't hurt. Plus
110     ! alignment. LEA used so we don't dirty flags -> 192/64 bytes.
111     stack-reg stack-reg 7 bootstrap-cells neg [+] LEA
112
113     jit-load-vm ;
114
115 : jit-signal-handler-epilog ( -- )
116     stack-reg stack-reg 7 bootstrap-cells [+] LEA
117     POPF
118     signal-handler-save-regs reverse [ POP ] each ;
119
120 [| |
121     jit-signal-handler-prolog
122     jit-save-context
123     temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
124     temp0 CALL
125     jit-signal-handler-epilog
126     0 RET
127 ] \ signal-handler define-sub-primitive
128
129 [| |
130     jit-signal-handler-prolog
131     jit-save-context
132     temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
133     temp0 CALL
134     jit-signal-handler-epilog
135     ! Pop the fake leaf frame along with our return address
136     leaf-stack-frame-size bootstrap-cell - RET
137 ] \ leaf-signal-handler define-sub-primitive
138
139 [| |
140     jit-signal-handler-prolog
141     temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
142     temp0 CALL
143     jit-signal-handler-epilog
144     red-zone-size RET
145 ] \ ffi-signal-handler define-sub-primitive
146
147 [| |
148     jit-signal-handler-prolog
149     temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
150     temp0 CALL
151     jit-signal-handler-epilog
152     red-zone-size 16 bootstrap-cell - + RET
153 ] \ ffi-leaf-signal-handler define-sub-primitive
154
155 [
156     ! load boolean
157     temp0 ds-reg [] MOV
158     ! pop boolean
159     ds-reg bootstrap-cell SUB
160     ! compare boolean with f
161     temp0 \ f type-number CMP
162     ! jump to true branch if not equal
163     0 JNE f rc-relative rel-word
164     ! jump to false branch if equal
165     0 JMP f rc-relative rel-word
166 ] JIT-IF jit-define
167
168 : jit->r ( -- )
169     rs-reg bootstrap-cell ADD
170     temp0 ds-reg [] MOV
171     ds-reg bootstrap-cell SUB
172     rs-reg [] temp0 MOV ;
173
174 : jit-2>r ( -- )
175     rs-reg 2 bootstrap-cells ADD
176     temp0 ds-reg [] MOV
177     temp1 ds-reg -1 bootstrap-cells [+] MOV
178     ds-reg 2 bootstrap-cells SUB
179     rs-reg [] temp0 MOV
180     rs-reg -1 bootstrap-cells [+] temp1 MOV ;
181
182 : jit-3>r ( -- )
183     rs-reg 3 bootstrap-cells ADD
184     temp0 ds-reg [] MOV
185     temp1 ds-reg -1 bootstrap-cells [+] MOV
186     temp2 ds-reg -2 bootstrap-cells [+] MOV
187     ds-reg 3 bootstrap-cells SUB
188     rs-reg [] temp0 MOV
189     rs-reg -1 bootstrap-cells [+] temp1 MOV
190     rs-reg -2 bootstrap-cells [+] temp2 MOV ;
191
192 : jit-r> ( -- )
193     ds-reg bootstrap-cell ADD
194     temp0 rs-reg [] MOV
195     rs-reg bootstrap-cell SUB
196     ds-reg [] temp0 MOV ;
197
198 : jit-2r> ( -- )
199     ds-reg 2 bootstrap-cells ADD
200     temp0 rs-reg [] MOV
201     temp1 rs-reg -1 bootstrap-cells [+] MOV
202     rs-reg 2 bootstrap-cells SUB
203     ds-reg [] temp0 MOV
204     ds-reg -1 bootstrap-cells [+] temp1 MOV ;
205
206 : jit-3r> ( -- )
207     ds-reg 3 bootstrap-cells ADD
208     temp0 rs-reg [] MOV
209     temp1 rs-reg -1 bootstrap-cells [+] MOV
210     temp2 rs-reg -2 bootstrap-cells [+] MOV
211     rs-reg 3 bootstrap-cells SUB
212     ds-reg [] temp0 MOV
213     ds-reg -1 bootstrap-cells [+] temp1 MOV
214     ds-reg -2 bootstrap-cells [+] temp2 MOV ;
215
216 [
217     jit->r
218     0 CALL f rc-relative rel-word
219     jit-r>
220 ] JIT-DIP jit-define
221
222 [
223     jit-2>r
224     0 CALL f rc-relative rel-word
225     jit-2r>
226 ] JIT-2DIP jit-define
227
228 [
229     jit-3>r
230     0 CALL f rc-relative rel-word
231     jit-3r>
232 ] JIT-3DIP jit-define
233
234 [
235     ! load from stack
236     temp0 ds-reg [] MOV
237     ! pop stack
238     ds-reg bootstrap-cell SUB
239 ]
240 [ temp0 word-entry-point-offset [+] CALL ]
241 [ temp0 word-entry-point-offset [+] JMP ]
242 \ (execute) define-combinator-primitive
243
244 [
245     temp0 ds-reg [] MOV
246     ds-reg bootstrap-cell SUB
247     temp0 word-entry-point-offset [+] JMP
248 ] JIT-EXECUTE jit-define
249
250 [
251     stack-reg stack-frame-size bootstrap-cell - SUB
252 ] JIT-PROLOG jit-define
253
254 [
255     stack-reg stack-frame-size bootstrap-cell - ADD
256 ] JIT-EPILOG jit-define
257
258 [ 0 RET ] JIT-RETURN jit-define
259
260 ! ! ! Polymorphic inline caches
261
262 ! The PIC stubs are not permitted to touch pic-tail-reg.
263
264 ! Load a value from a stack position
265 [
266     temp1 ds-reg 0x7f [+] MOV f rc-absolute-1 rel-untagged
267 ] PIC-LOAD jit-define
268
269 [ temp1 tag-mask get AND ] PIC-TAG jit-define
270
271 [
272     temp0 temp1 MOV
273     temp1 tag-mask get AND
274     temp1 tuple type-number CMP
275     [ JNE ]
276     [ temp1 temp0 tuple-class-offset [+] MOV ]
277     jit-conditional
278 ] PIC-TUPLE jit-define
279
280 [
281     temp1 0x7f CMP f rc-absolute-1 rel-untagged
282 ] PIC-CHECK-TAG jit-define
283
284 [ 0 JE f rc-relative rel-word ] PIC-HIT jit-define
285
286 ! ! ! Megamorphic caches
287
288 [
289     ! class = ...
290     temp0 temp1 MOV
291     temp1 tag-mask get AND
292     temp1 tag-bits get SHL
293     temp1 tuple type-number tag-fixnum CMP
294     [ JNE ]
295     [ temp1 temp0 tuple-class-offset [+] MOV ]
296     jit-conditional
297     ! cache = ...
298     temp0 0 MOV f rc-absolute-cell rel-literal
299     ! key = hashcode(class)
300     temp2 temp1 MOV
301     bootstrap-cell 4 = [ temp2 1 SHR ] when
302     ! key &= cache.length - 1
303     temp2 mega-cache-size get 1 - bootstrap-cell * AND
304     ! cache += array-start-offset
305     temp0 array-start-offset ADD
306     ! cache += key
307     temp0 temp2 ADD
308     ! if(get(cache) == class)
309     temp0 [] temp1 CMP
310     [ JNE ]
311     [
312         ! megamorphic_cache_hits++
313         temp1 0 MOV rc-absolute-cell rel-megamorphic-cache-hits
314         temp1 [] 1 ADD
315         ! goto get(cache + bootstrap-cell)
316         temp0 temp0 bootstrap-cell [+] MOV
317         temp0 word-entry-point-offset [+] JMP
318         ! fall-through on miss
319     ] jit-conditional
320 ] MEGA-LOOKUP jit-define
321
322 ! ! ! Sub-primitives
323
324 ! Objects
325 [
326     ! load from stack
327     temp0 ds-reg [] MOV
328     ! compute tag
329     temp0 tag-mask get AND
330     ! tag the tag
331     temp0 tag-bits get SHL
332     ! push to stack
333     ds-reg [] temp0 MOV
334 ] \ tag define-sub-primitive
335
336 [
337     ! load slot number
338     temp0 ds-reg [] MOV
339     ! adjust stack pointer
340     ds-reg bootstrap-cell SUB
341     ! load object
342     temp1 ds-reg [] MOV
343     ! turn slot number into offset
344     fixnum>slot@
345     ! mask off tag
346     temp1 tag-bits get SHR
347     temp1 tag-bits get SHL
348     ! load slot value
349     temp0 temp1 temp0 [+] MOV
350     ! push to stack
351     ds-reg [] temp0 MOV
352 ] \ slot define-sub-primitive
353
354 [
355     ! load string index from stack
356     temp0 ds-reg bootstrap-cell neg [+] MOV
357     temp0 tag-bits get SHR
358     ! load string from stack
359     temp1 ds-reg [] MOV
360     ! load character
361     temp0 8-bit-version-of temp0 temp1 string-offset [++] MOV
362     temp0 temp0 8-bit-version-of MOVZX
363     temp0 tag-bits get SHL
364     ! store character to stack
365     ds-reg bootstrap-cell SUB
366     ds-reg [] temp0 MOV
367 ] \ string-nth-fast define-sub-primitive
368
369 ! Shufflers
370 [
371     ds-reg bootstrap-cell SUB
372 ] \ drop define-sub-primitive
373
374 [
375     ds-reg 2 bootstrap-cells SUB
376 ] \ 2drop define-sub-primitive
377
378 [
379     ds-reg 3 bootstrap-cells SUB
380 ] \ 3drop define-sub-primitive
381
382 [
383     ds-reg 4 bootstrap-cells SUB
384 ] \ 4drop define-sub-primitive
385
386 [
387     temp0 ds-reg [] MOV
388     ds-reg bootstrap-cell ADD
389     ds-reg [] temp0 MOV
390 ] \ dup define-sub-primitive
391
392 [
393     temp0 ds-reg [] MOV
394     temp1 ds-reg bootstrap-cell neg [+] MOV
395     ds-reg 2 bootstrap-cells ADD
396     ds-reg [] temp0 MOV
397     ds-reg bootstrap-cell neg [+] temp1 MOV
398 ] \ 2dup define-sub-primitive
399
400 [
401     temp0 ds-reg [] MOV
402     temp1 ds-reg -1 bootstrap-cells [+] MOV
403     temp3 ds-reg -2 bootstrap-cells [+] MOV
404     ds-reg 3 bootstrap-cells ADD
405     ds-reg [] temp0 MOV
406     ds-reg -1 bootstrap-cells [+] temp1 MOV
407     ds-reg -2 bootstrap-cells [+] temp3 MOV
408 ] \ 3dup define-sub-primitive
409
410 [
411     temp0 ds-reg [] MOV
412     temp1 ds-reg -1 bootstrap-cells [+] MOV
413     temp2 ds-reg -2 bootstrap-cells [+] MOV
414     temp3 ds-reg -3 bootstrap-cells [+] MOV
415     ds-reg 4 bootstrap-cells ADD
416     ds-reg [] temp0 MOV
417     ds-reg -1 bootstrap-cells [+] temp1 MOV
418     ds-reg -2 bootstrap-cells [+] temp2 MOV
419     ds-reg -3 bootstrap-cells [+] temp3 MOV
420 ] \ 4dup define-sub-primitive
421
422 [
423     temp0 ds-reg [] MOV
424     ds-reg bootstrap-cell SUB
425     ds-reg [] temp0 MOV
426 ] \ nip define-sub-primitive
427
428 [
429     temp0 ds-reg [] MOV
430     ds-reg 2 bootstrap-cells SUB
431     ds-reg [] temp0 MOV
432 ] \ 2nip define-sub-primitive
433
434 [
435     temp0 ds-reg -1 bootstrap-cells [+] MOV
436     ds-reg bootstrap-cell ADD
437     ds-reg [] temp0 MOV
438 ] \ over define-sub-primitive
439
440 [
441     temp0 ds-reg -2 bootstrap-cells [+] MOV
442     ds-reg bootstrap-cell ADD
443     ds-reg [] temp0 MOV
444 ] \ pick define-sub-primitive
445
446 [
447     temp0 ds-reg [] MOV
448     temp1 ds-reg -1 bootstrap-cells [+] MOV
449     ds-reg [] temp1 MOV
450     ds-reg bootstrap-cell ADD
451     ds-reg [] temp0 MOV
452 ] \ dupd define-sub-primitive
453
454 [
455     temp0 ds-reg [] MOV
456     temp1 ds-reg bootstrap-cell neg [+] MOV
457     ds-reg bootstrap-cell neg [+] temp0 MOV
458     ds-reg [] temp1 MOV
459 ] \ swap define-sub-primitive
460
461 [
462     temp0 ds-reg -1 bootstrap-cells [+] MOV
463     temp1 ds-reg -2 bootstrap-cells [+] MOV
464     ds-reg -2 bootstrap-cells [+] temp0 MOV
465     ds-reg -1 bootstrap-cells [+] temp1 MOV
466 ] \ swapd define-sub-primitive
467
468 [
469     temp0 ds-reg [] MOV
470     temp1 ds-reg -1 bootstrap-cells [+] MOV
471     temp3 ds-reg -2 bootstrap-cells [+] MOV
472     ds-reg -2 bootstrap-cells [+] temp1 MOV
473     ds-reg -1 bootstrap-cells [+] temp0 MOV
474     ds-reg [] temp3 MOV
475 ] \ rot define-sub-primitive
476
477 [
478     temp0 ds-reg [] MOV
479     temp1 ds-reg -1 bootstrap-cells [+] MOV
480     temp3 ds-reg -2 bootstrap-cells [+] MOV
481     ds-reg -2 bootstrap-cells [+] temp0 MOV
482     ds-reg -1 bootstrap-cells [+] temp3 MOV
483     ds-reg [] temp1 MOV
484 ] \ -rot define-sub-primitive
485
486 [ jit->r ] \ load-local define-sub-primitive
487
488 ! Comparisons
489 : jit-compare ( insn -- )
490     ! load t
491     temp3 0 MOV t rc-absolute-cell rel-literal
492     ! load f
493     temp1 \ f type-number MOV
494     ! load first value
495     temp0 ds-reg [] MOV
496     ! adjust stack pointer
497     ds-reg bootstrap-cell SUB
498     ! compare with second value
499     ds-reg [] temp0 CMP
500     ! move t if true
501     [ temp1 temp3 ] dip execute( dst src -- )
502     ! store
503     ds-reg [] temp1 MOV ;
504
505 : define-jit-compare ( insn word -- )
506     [ [ jit-compare ] curry ] dip define-sub-primitive ;
507
508 \ CMOVE \ eq? define-jit-compare
509 \ CMOVGE \ fixnum>= define-jit-compare
510 \ CMOVLE \ fixnum<= define-jit-compare
511 \ CMOVG \ fixnum> define-jit-compare
512 \ CMOVL \ fixnum< define-jit-compare
513
514 ! Math
515 : jit-math ( insn -- )
516     ! load second input
517     temp0 ds-reg [] MOV
518     ! pop stack
519     ds-reg bootstrap-cell SUB
520     ! compute result
521     [ ds-reg [] temp0 ] dip execute( dst src -- ) ;
522
523 [ \ ADD jit-math ] \ fixnum+fast define-sub-primitive
524
525 [ \ SUB jit-math ] \ fixnum-fast define-sub-primitive
526
527 [
528     ! load second input
529     temp0 ds-reg [] MOV
530     ! pop stack
531     ds-reg bootstrap-cell SUB
532     ! load first input
533     temp1 ds-reg [] MOV
534     ! untag second input
535     temp0 tag-bits get SAR
536     ! multiply
537     temp0 temp1 IMUL2
538     ! push result
539     ds-reg [] temp0 MOV
540 ] \ fixnum*fast define-sub-primitive
541
542 [ \ AND jit-math ] \ fixnum-bitand define-sub-primitive
543
544 [ \ OR jit-math ] \ fixnum-bitor define-sub-primitive
545
546 [ \ XOR jit-math ] \ fixnum-bitxor define-sub-primitive
547
548 [
549     ! complement
550     ds-reg [] NOT
551     ! clear tag bits
552     ds-reg [] tag-mask get XOR
553 ] \ fixnum-bitnot define-sub-primitive
554
555 [
556     ! load shift count
557     shift-arg ds-reg [] MOV
558     ! untag shift count
559     shift-arg tag-bits get SAR
560     ! adjust stack pointer
561     ds-reg bootstrap-cell SUB
562     ! load value
563     temp3 ds-reg [] MOV
564     ! make a copy
565     temp2 temp3 MOV
566     ! compute positive shift value in temp2
567     temp2 CL SHL
568     shift-arg NEG
569     ! compute negative shift value in temp3
570     temp3 CL SAR
571     temp3 tag-mask get bitnot AND
572     shift-arg 0 CMP
573     ! if shift count was negative, move temp0 to temp2
574     temp2 temp3 CMOVGE
575     ! push to stack
576     ds-reg [] temp2 MOV
577 ] \ fixnum-shift-fast define-sub-primitive
578
579 : jit-fixnum-/mod ( -- )
580     ! load second parameter
581     temp1 ds-reg [] MOV
582     ! load first parameter
583     div-arg ds-reg bootstrap-cell neg [+] MOV
584     ! make a copy
585     mod-arg div-arg MOV
586     ! sign-extend
587     mod-arg bootstrap-cell-bits 1 - SAR
588     ! divide
589     temp1 IDIV ;
590
591 [
592     jit-fixnum-/mod
593     ! adjust stack pointer
594     ds-reg bootstrap-cell SUB
595     ! push to stack
596     ds-reg [] mod-arg MOV
597 ] \ fixnum-mod define-sub-primitive
598
599 [
600     jit-fixnum-/mod
601     ! adjust stack pointer
602     ds-reg bootstrap-cell SUB
603     ! tag it
604     div-arg tag-bits get SHL
605     ! push to stack
606     ds-reg [] div-arg MOV
607 ] \ fixnum/i-fast define-sub-primitive
608
609 [
610     jit-fixnum-/mod
611     ! tag it
612     div-arg tag-bits get SHL
613     ! push to stack
614     ds-reg [] mod-arg MOV
615     ds-reg bootstrap-cell neg [+] div-arg MOV
616 ] \ fixnum/mod-fast define-sub-primitive
617
618 [
619     temp0 ds-reg [] MOV
620     ds-reg bootstrap-cell SUB
621     temp0 ds-reg [] OR
622     temp0 tag-mask get TEST
623     temp0 \ f type-number MOV
624     temp1 1 tag-fixnum MOV
625     temp0 temp1 CMOVE
626     ds-reg [] temp0 MOV
627 ] \ both-fixnums? define-sub-primitive
628
629 [
630     ! load local number
631     temp0 ds-reg [] MOV
632     ! turn local number into offset
633     fixnum>slot@
634     ! load local value
635     temp0 rs-reg temp0 [+] MOV
636     ! push to stack
637     ds-reg [] temp0 MOV
638 ] \ get-local define-sub-primitive
639
640 [
641     ! load local count
642     temp0 ds-reg [] MOV
643     ! adjust stack pointer
644     ds-reg bootstrap-cell SUB
645     ! turn local number into offset
646     fixnum>slot@
647     ! decrement retain stack pointer
648     rs-reg temp0 SUB
649 ] \ drop-locals define-sub-primitive
650
651 [ "bootstrap.x86" forget-vocab ] with-compilation-unit