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 ;
12 ! C to Factor entry point
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.
20 frame-reg stack-reg MOV
22 ! Save all non-volatile registers
28 vm-reg 0 MOV 0 rc-absolute-cell rel-vm
31 nv-reg vm-reg vm-context-offset [+] MOV
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
38 ! Save C callstack pointer
39 nv-reg context-callstack-save-offset [+] stack-reg MOV
41 ! Load Factor stack pointers
42 stack-reg nv-reg context-callstack-bottom-offset [+] MOV
46 rs-reg nv-reg context-retainstack-offset [+] MOV
47 ds-reg nv-reg context-datastack-offset [+] MOV
49 ! Call into Factor code
50 link-reg 0 MOV f rc-absolute-cell rel-word
53 ! Load VM into vm-reg; only needed on x86-32, but doesn't
55 vm-reg 0 MOV 0 rc-absolute-cell rel-vm
57 ! Load C callstack pointer
58 nv-reg vm-reg vm-context-offset [+] MOV
59 stack-reg nv-reg context-callstack-save-offset [+] MOV
63 vm-reg vm-context-offset [+] nv-reg MOV
65 ! Restore non-volatile registers
68 nv-regs <reversed> [ POP ] each
72 ! Callbacks which return structs, or use stdcall/fastcall/thiscall,
73 ! need a parameter here.
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
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
86 ] JIT-PUSH-IMMEDIATE jit-define
89 0 CALL f rc-relative rel-word-pic
90 ] JIT-WORD-CALL jit-define
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.
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.
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
105 ! Push flags -> 136/36 bytes
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
115 : jit-signal-handler-epilog ( -- )
116 stack-reg stack-reg 7 bootstrap-cells [+] LEA
118 signal-handler-save-regs reverse [ POP ] each ;
121 jit-signal-handler-prolog
123 temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
125 jit-signal-handler-epilog
127 ] \ signal-handler define-sub-primitive
130 jit-signal-handler-prolog
132 temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
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
140 jit-signal-handler-prolog
141 temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
143 jit-signal-handler-epilog
145 ] \ ffi-signal-handler define-sub-primitive
148 jit-signal-handler-prolog
149 temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
151 jit-signal-handler-epilog
152 red-zone-size 16 bootstrap-cell - + RET
153 ] \ ffi-leaf-signal-handler define-sub-primitive
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
169 rs-reg bootstrap-cell ADD
171 ds-reg bootstrap-cell SUB
172 rs-reg [] temp0 MOV ;
175 rs-reg 2 bootstrap-cells ADD
177 temp1 ds-reg -1 bootstrap-cells [+] MOV
178 ds-reg 2 bootstrap-cells SUB
180 rs-reg -1 bootstrap-cells [+] temp1 MOV ;
183 rs-reg 3 bootstrap-cells ADD
185 temp1 ds-reg -1 bootstrap-cells [+] MOV
186 temp2 ds-reg -2 bootstrap-cells [+] MOV
187 ds-reg 3 bootstrap-cells SUB
189 rs-reg -1 bootstrap-cells [+] temp1 MOV
190 rs-reg -2 bootstrap-cells [+] temp2 MOV ;
193 ds-reg bootstrap-cell ADD
195 rs-reg bootstrap-cell SUB
196 ds-reg [] temp0 MOV ;
199 ds-reg 2 bootstrap-cells ADD
201 temp1 rs-reg -1 bootstrap-cells [+] MOV
202 rs-reg 2 bootstrap-cells SUB
204 ds-reg -1 bootstrap-cells [+] temp1 MOV ;
207 ds-reg 3 bootstrap-cells ADD
209 temp1 rs-reg -1 bootstrap-cells [+] MOV
210 temp2 rs-reg -2 bootstrap-cells [+] MOV
211 rs-reg 3 bootstrap-cells SUB
213 ds-reg -1 bootstrap-cells [+] temp1 MOV
214 ds-reg -2 bootstrap-cells [+] temp2 MOV ;
218 0 CALL f rc-relative rel-word
224 0 CALL f rc-relative rel-word
226 ] JIT-2DIP jit-define
230 0 CALL f rc-relative rel-word
232 ] JIT-3DIP jit-define
238 ds-reg bootstrap-cell SUB
240 [ temp0 word-entry-point-offset [+] CALL ]
241 [ temp0 word-entry-point-offset [+] JMP ]
242 \ (execute) define-combinator-primitive
246 ds-reg bootstrap-cell SUB
247 temp0 word-entry-point-offset [+] JMP
248 ] JIT-EXECUTE jit-define
251 stack-reg stack-frame-size bootstrap-cell - SUB
252 ] JIT-PROLOG jit-define
255 stack-reg stack-frame-size bootstrap-cell - ADD
256 ] JIT-EPILOG jit-define
258 [ 0 RET ] JIT-RETURN jit-define
260 ! ! ! Polymorphic inline caches
262 ! The PIC stubs are not permitted to touch pic-tail-reg.
264 ! Load a value from a stack position
266 temp1 ds-reg 0x7f [+] MOV f rc-absolute-1 rel-untagged
267 ] PIC-LOAD jit-define
269 [ temp1 tag-mask get AND ] PIC-TAG jit-define
273 temp1 tag-mask get AND
274 temp1 tuple type-number CMP
276 [ temp1 temp0 tuple-class-offset [+] MOV ]
278 ] PIC-TUPLE jit-define
281 temp1 0x7f CMP f rc-absolute-1 rel-untagged
282 ] PIC-CHECK-TAG jit-define
284 [ 0 JE f rc-relative rel-word ] PIC-HIT jit-define
286 ! ! ! Megamorphic caches
291 temp1 tag-mask get AND
292 temp1 tag-bits get SHL
293 temp1 tuple type-number tag-fixnum CMP
295 [ temp1 temp0 tuple-class-offset [+] MOV ]
298 temp0 0 MOV f rc-absolute-cell rel-literal
299 ! key = hashcode(class)
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
308 ! if(get(cache) == class)
312 ! megamorphic_cache_hits++
313 temp1 0 MOV rc-absolute-cell rel-megamorphic-cache-hits
315 ! goto get(cache + bootstrap-cell)
316 temp0 temp0 bootstrap-cell [+] MOV
317 temp0 word-entry-point-offset [+] JMP
318 ! fall-through on miss
320 ] MEGA-LOOKUP jit-define
329 temp0 tag-mask get AND
331 temp0 tag-bits get SHL
334 ] \ tag define-sub-primitive
339 ! adjust stack pointer
340 ds-reg bootstrap-cell SUB
343 ! turn slot number into offset
346 temp1 tag-bits get SHR
347 temp1 tag-bits get SHL
349 temp0 temp1 temp0 [+] MOV
352 ] \ slot define-sub-primitive
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
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
367 ] \ string-nth-fast define-sub-primitive
371 ds-reg bootstrap-cell SUB
372 ] \ drop define-sub-primitive
375 ds-reg 2 bootstrap-cells SUB
376 ] \ 2drop define-sub-primitive
379 ds-reg 3 bootstrap-cells SUB
380 ] \ 3drop define-sub-primitive
383 ds-reg 4 bootstrap-cells SUB
384 ] \ 4drop define-sub-primitive
388 ds-reg bootstrap-cell ADD
390 ] \ dup define-sub-primitive
394 temp1 ds-reg bootstrap-cell neg [+] MOV
395 ds-reg 2 bootstrap-cells ADD
397 ds-reg bootstrap-cell neg [+] temp1 MOV
398 ] \ 2dup define-sub-primitive
402 temp1 ds-reg -1 bootstrap-cells [+] MOV
403 temp3 ds-reg -2 bootstrap-cells [+] MOV
404 ds-reg 3 bootstrap-cells ADD
406 ds-reg -1 bootstrap-cells [+] temp1 MOV
407 ds-reg -2 bootstrap-cells [+] temp3 MOV
408 ] \ 3dup define-sub-primitive
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
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
424 ds-reg bootstrap-cell SUB
426 ] \ nip define-sub-primitive
430 ds-reg 2 bootstrap-cells SUB
432 ] \ 2nip define-sub-primitive
435 temp0 ds-reg -1 bootstrap-cells [+] MOV
436 ds-reg bootstrap-cell ADD
438 ] \ over define-sub-primitive
441 temp0 ds-reg -2 bootstrap-cells [+] MOV
442 ds-reg bootstrap-cell ADD
444 ] \ pick define-sub-primitive
448 temp1 ds-reg -1 bootstrap-cells [+] MOV
450 ds-reg bootstrap-cell ADD
452 ] \ dupd define-sub-primitive
456 temp1 ds-reg bootstrap-cell neg [+] MOV
457 ds-reg bootstrap-cell neg [+] temp0 MOV
459 ] \ swap define-sub-primitive
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
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
475 ] \ rot define-sub-primitive
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
484 ] \ -rot define-sub-primitive
486 [ jit->r ] \ load-local define-sub-primitive
489 : jit-compare ( insn -- )
491 temp3 0 MOV t rc-absolute-cell rel-literal
493 temp1 \ f type-number MOV
496 ! adjust stack pointer
497 ds-reg bootstrap-cell SUB
498 ! compare with second value
501 [ temp1 temp3 ] dip execute( dst src -- )
503 ds-reg [] temp1 MOV ;
505 : define-jit-compare ( insn word -- )
506 [ [ jit-compare ] curry ] dip define-sub-primitive ;
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
515 : jit-math ( insn -- )
519 ds-reg bootstrap-cell SUB
521 [ ds-reg [] temp0 ] dip execute( dst src -- ) ;
523 [ \ ADD jit-math ] \ fixnum+fast define-sub-primitive
525 [ \ SUB jit-math ] \ fixnum-fast define-sub-primitive
531 ds-reg bootstrap-cell SUB
535 temp0 tag-bits get SAR
540 ] \ fixnum*fast define-sub-primitive
542 [ \ AND jit-math ] \ fixnum-bitand define-sub-primitive
544 [ \ OR jit-math ] \ fixnum-bitor define-sub-primitive
546 [ \ XOR jit-math ] \ fixnum-bitxor define-sub-primitive
552 ds-reg [] tag-mask get XOR
553 ] \ fixnum-bitnot define-sub-primitive
557 shift-arg ds-reg [] MOV
559 shift-arg tag-bits get SAR
560 ! adjust stack pointer
561 ds-reg bootstrap-cell SUB
566 ! compute positive shift value in temp2
569 ! compute negative shift value in temp3
571 temp3 tag-mask get bitnot AND
573 ! if shift count was negative, move temp0 to temp2
577 ] \ fixnum-shift-fast define-sub-primitive
579 : jit-fixnum-/mod ( -- )
580 ! load second parameter
582 ! load first parameter
583 div-arg ds-reg bootstrap-cell neg [+] MOV
587 mod-arg bootstrap-cell-bits 1 - SAR
593 ! adjust stack pointer
594 ds-reg bootstrap-cell SUB
596 ds-reg [] mod-arg MOV
597 ] \ fixnum-mod define-sub-primitive
601 ! adjust stack pointer
602 ds-reg bootstrap-cell SUB
604 div-arg tag-bits get SHL
606 ds-reg [] div-arg MOV
607 ] \ fixnum/i-fast define-sub-primitive
612 div-arg tag-bits get SHL
614 ds-reg [] mod-arg MOV
615 ds-reg bootstrap-cell neg [+] div-arg MOV
616 ] \ fixnum/mod-fast define-sub-primitive
620 ds-reg bootstrap-cell SUB
622 temp0 tag-mask get TEST
623 temp0 \ f type-number MOV
624 temp1 1 tag-fixnum MOV
627 ] \ both-fixnums? define-sub-primitive
632 ! turn local number into offset
635 temp0 rs-reg temp0 [+] MOV
638 ] \ get-local define-sub-primitive
643 ! adjust stack pointer
644 ds-reg bootstrap-cell SUB
645 ! turn local number into offset
647 ! decrement retain stack pointer
649 ] \ drop-locals define-sub-primitive
651 [ "bootstrap.x86" forget-vocab ] with-compilation-unit