1 ! Copyright (C) 2007, 2011 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: bootstrap.image.private compiler.constants
4 compiler.codegen.relocation compiler.units cpu.x86.assembler
5 cpu.x86.assembler.operands kernel kernel.private layouts
6 locals locals.backend make 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
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 : jit-signal-handler-prolog ( -- )
97 ! minus a cell each for flags, return address
98 ! use LEA so we don't dirty flags
99 stack-reg stack-reg signal-handler-stack-frame-size
100 2 bootstrap-cells - neg [+] LEA
102 signal-handler-save-regs
103 [| r i | stack-reg i bootstrap-cells [+] r MOV ] each-index
109 : jit-signal-handler-epilog ( -- )
112 signal-handler-save-regs
113 [| r i | r stack-reg i bootstrap-cells [+] MOV ] each-index
115 stack-reg stack-reg signal-handler-stack-frame-size
116 2 bootstrap-cells - [+] LEA ;
119 jit-signal-handler-prolog
121 temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
123 jit-signal-handler-epilog
125 ] \ signal-handler define-sub-primitive
128 jit-signal-handler-prolog
130 temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
132 jit-signal-handler-epilog
133 ! Pop the fake leaf frame along with our return address
134 leaf-stack-frame-size bootstrap-cell - RET
135 ] \ leaf-signal-handler define-sub-primitive
138 jit-signal-handler-prolog
139 temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
141 jit-signal-handler-epilog
143 ] \ ffi-signal-handler define-sub-primitive
146 jit-signal-handler-prolog
147 temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
149 jit-signal-handler-epilog
150 red-zone-size 16 bootstrap-cell - + RET
151 ] \ ffi-leaf-signal-handler define-sub-primitive
157 ds-reg bootstrap-cell SUB
158 ! compare boolean with f
159 temp0 \ f type-number CMP
160 ! jump to true branch if not equal
161 0 JNE f rc-relative rel-word
162 ! jump to false branch if equal
163 0 JMP f rc-relative rel-word
167 rs-reg bootstrap-cell ADD
169 ds-reg bootstrap-cell SUB
170 rs-reg [] temp0 MOV ;
173 rs-reg 2 bootstrap-cells ADD
175 temp1 ds-reg -1 bootstrap-cells [+] MOV
176 ds-reg 2 bootstrap-cells SUB
178 rs-reg -1 bootstrap-cells [+] temp1 MOV ;
181 rs-reg 3 bootstrap-cells ADD
183 temp1 ds-reg -1 bootstrap-cells [+] MOV
184 temp2 ds-reg -2 bootstrap-cells [+] MOV
185 ds-reg 3 bootstrap-cells SUB
187 rs-reg -1 bootstrap-cells [+] temp1 MOV
188 rs-reg -2 bootstrap-cells [+] temp2 MOV ;
191 ds-reg bootstrap-cell ADD
193 rs-reg bootstrap-cell SUB
194 ds-reg [] temp0 MOV ;
197 ds-reg 2 bootstrap-cells ADD
199 temp1 rs-reg -1 bootstrap-cells [+] MOV
200 rs-reg 2 bootstrap-cells SUB
202 ds-reg -1 bootstrap-cells [+] temp1 MOV ;
205 ds-reg 3 bootstrap-cells ADD
207 temp1 rs-reg -1 bootstrap-cells [+] MOV
208 temp2 rs-reg -2 bootstrap-cells [+] MOV
209 rs-reg 3 bootstrap-cells SUB
211 ds-reg -1 bootstrap-cells [+] temp1 MOV
212 ds-reg -2 bootstrap-cells [+] temp2 MOV ;
216 0 CALL f rc-relative rel-word
222 0 CALL f rc-relative rel-word
224 ] jit-2dip jit-define
228 0 CALL f rc-relative rel-word
230 ] jit-3dip jit-define
236 ds-reg bootstrap-cell SUB
238 [ temp0 word-entry-point-offset [+] CALL ]
239 [ temp0 word-entry-point-offset [+] JMP ]
240 \ (execute) define-combinator-primitive
244 ds-reg bootstrap-cell SUB
245 temp0 word-entry-point-offset [+] JMP
246 ] jit-execute jit-define
249 stack-reg stack-frame-size bootstrap-cell - SUB
250 ] jit-prolog jit-define
253 stack-reg stack-frame-size bootstrap-cell - ADD
254 ] jit-epilog jit-define
256 [ 0 RET ] jit-return jit-define
258 ! ! ! Polymorphic inline caches
260 ! The PIC stubs are not permitted to touch pic-tail-reg.
262 ! Load a value from a stack position
264 temp1 ds-reg 0x7f [+] MOV f rc-absolute-1 rel-untagged
265 ] pic-load jit-define
267 [ temp1 tag-mask get AND ] pic-tag jit-define
271 temp1 tag-mask get AND
272 temp1 tuple type-number CMP
274 [ temp1 temp0 tuple-class-offset [+] MOV ]
276 ] pic-tuple jit-define
279 temp1 0x7f CMP f rc-absolute-1 rel-untagged
280 ] pic-check-tag jit-define
282 [ 0 JE f rc-relative rel-word ] pic-hit jit-define
284 ! ! ! Megamorphic caches
289 temp1 tag-mask get AND
290 temp1 tag-bits get SHL
291 temp1 tuple type-number tag-fixnum CMP
293 [ temp1 temp0 tuple-class-offset [+] MOV ]
296 temp0 0 MOV f rc-absolute-cell rel-literal
297 ! key = hashcode(class)
299 bootstrap-cell 4 = [ temp2 1 SHR ] when
300 ! key &= cache.length - 1
301 temp2 mega-cache-size get 1 - bootstrap-cell * AND
302 ! cache += array-start-offset
303 temp0 array-start-offset ADD
306 ! if(get(cache) == class)
310 ! megamorphic_cache_hits++
311 temp1 0 MOV rc-absolute-cell rel-megamorphic-cache-hits
313 ! goto get(cache + bootstrap-cell)
314 temp0 temp0 bootstrap-cell [+] MOV
315 temp0 word-entry-point-offset [+] JMP
316 ! fall-through on miss
318 ] mega-lookup jit-define
327 temp0 tag-mask get AND
329 temp0 tag-bits get SHL
332 ] \ tag define-sub-primitive
337 ! adjust stack pointer
338 ds-reg bootstrap-cell SUB
341 ! turn slot number into offset
344 temp1 tag-bits get SHR
345 temp1 tag-bits get SHL
347 temp0 temp1 temp0 [+] MOV
350 ] \ slot define-sub-primitive
353 ! load string index from stack
354 temp0 ds-reg bootstrap-cell neg [+] MOV
355 temp0 tag-bits get SHR
356 ! load string from stack
359 temp0 8-bit-version-of temp0 temp1 string-offset [++] MOV
360 temp0 temp0 8-bit-version-of MOVZX
361 temp0 tag-bits get SHL
362 ! store character to stack
363 ds-reg bootstrap-cell SUB
365 ] \ string-nth-fast define-sub-primitive
369 ds-reg bootstrap-cell SUB
370 ] \ drop define-sub-primitive
373 ds-reg 2 bootstrap-cells SUB
374 ] \ 2drop define-sub-primitive
377 ds-reg 3 bootstrap-cells SUB
378 ] \ 3drop define-sub-primitive
382 ds-reg bootstrap-cell ADD
384 ] \ dup define-sub-primitive
388 temp1 ds-reg bootstrap-cell neg [+] MOV
389 ds-reg 2 bootstrap-cells ADD
391 ds-reg bootstrap-cell neg [+] temp1 MOV
392 ] \ 2dup define-sub-primitive
396 temp1 ds-reg -1 bootstrap-cells [+] MOV
397 temp3 ds-reg -2 bootstrap-cells [+] MOV
398 ds-reg 3 bootstrap-cells ADD
400 ds-reg -1 bootstrap-cells [+] temp1 MOV
401 ds-reg -2 bootstrap-cells [+] temp3 MOV
402 ] \ 3dup define-sub-primitive
406 ds-reg bootstrap-cell SUB
408 ] \ nip define-sub-primitive
412 ds-reg 2 bootstrap-cells SUB
414 ] \ 2nip define-sub-primitive
417 temp0 ds-reg -1 bootstrap-cells [+] MOV
418 ds-reg bootstrap-cell ADD
420 ] \ over define-sub-primitive
423 temp0 ds-reg -2 bootstrap-cells [+] MOV
424 ds-reg bootstrap-cell ADD
426 ] \ pick define-sub-primitive
430 temp1 ds-reg -1 bootstrap-cells [+] MOV
432 ds-reg bootstrap-cell ADD
434 ] \ dupd define-sub-primitive
438 temp1 ds-reg bootstrap-cell neg [+] MOV
439 ds-reg bootstrap-cell neg [+] temp0 MOV
441 ] \ swap define-sub-primitive
444 temp0 ds-reg -1 bootstrap-cells [+] MOV
445 temp1 ds-reg -2 bootstrap-cells [+] MOV
446 ds-reg -2 bootstrap-cells [+] temp0 MOV
447 ds-reg -1 bootstrap-cells [+] temp1 MOV
448 ] \ swapd define-sub-primitive
452 temp1 ds-reg -1 bootstrap-cells [+] MOV
453 temp3 ds-reg -2 bootstrap-cells [+] MOV
454 ds-reg -2 bootstrap-cells [+] temp1 MOV
455 ds-reg -1 bootstrap-cells [+] temp0 MOV
457 ] \ rot define-sub-primitive
461 temp1 ds-reg -1 bootstrap-cells [+] MOV
462 temp3 ds-reg -2 bootstrap-cells [+] MOV
463 ds-reg -2 bootstrap-cells [+] temp0 MOV
464 ds-reg -1 bootstrap-cells [+] temp3 MOV
466 ] \ -rot define-sub-primitive
468 [ jit->r ] \ load-local define-sub-primitive
471 : jit-compare ( insn -- )
473 temp3 0 MOV t rc-absolute-cell rel-literal
475 temp1 \ f type-number MOV
478 ! adjust stack pointer
479 ds-reg bootstrap-cell SUB
480 ! compare with second value
483 [ temp1 temp3 ] dip execute( dst src -- )
485 ds-reg [] temp1 MOV ;
487 : define-jit-compare ( insn word -- )
488 [ [ jit-compare ] curry ] dip define-sub-primitive ;
490 \ CMOVE \ eq? define-jit-compare
491 \ CMOVGE \ fixnum>= define-jit-compare
492 \ CMOVLE \ fixnum<= define-jit-compare
493 \ CMOVG \ fixnum> define-jit-compare
494 \ CMOVL \ fixnum< define-jit-compare
497 : jit-math ( insn -- )
501 ds-reg bootstrap-cell SUB
503 [ ds-reg [] temp0 ] dip execute( dst src -- ) ;
505 [ \ ADD jit-math ] \ fixnum+fast define-sub-primitive
507 [ \ SUB jit-math ] \ fixnum-fast define-sub-primitive
513 ds-reg bootstrap-cell SUB
517 temp0 tag-bits get SAR
522 ] \ fixnum*fast define-sub-primitive
524 [ \ AND jit-math ] \ fixnum-bitand define-sub-primitive
526 [ \ OR jit-math ] \ fixnum-bitor define-sub-primitive
528 [ \ XOR jit-math ] \ fixnum-bitxor define-sub-primitive
534 ds-reg [] tag-mask get XOR
535 ] \ fixnum-bitnot define-sub-primitive
539 shift-arg ds-reg [] MOV
541 shift-arg tag-bits get SAR
542 ! adjust stack pointer
543 ds-reg bootstrap-cell SUB
548 ! compute positive shift value in temp2
551 ! compute negative shift value in temp3
553 temp3 tag-mask get bitnot AND
555 ! if shift count was negative, move temp0 to temp2
559 ] \ fixnum-shift-fast define-sub-primitive
561 : jit-fixnum-/mod ( -- )
562 ! load second parameter
564 ! load first parameter
565 div-arg ds-reg bootstrap-cell neg [+] MOV
569 mod-arg bootstrap-cell-bits 1 - SAR
575 ! adjust stack pointer
576 ds-reg bootstrap-cell SUB
578 ds-reg [] mod-arg MOV
579 ] \ fixnum-mod define-sub-primitive
583 ! adjust stack pointer
584 ds-reg bootstrap-cell SUB
586 div-arg tag-bits get SHL
588 ds-reg [] div-arg MOV
589 ] \ fixnum/i-fast define-sub-primitive
594 div-arg tag-bits get SHL
596 ds-reg [] mod-arg MOV
597 ds-reg bootstrap-cell neg [+] div-arg MOV
598 ] \ fixnum/mod-fast define-sub-primitive
602 ds-reg bootstrap-cell SUB
604 temp0 tag-mask get TEST
605 temp0 \ f type-number MOV
606 temp1 1 tag-fixnum MOV
609 ] \ both-fixnums? define-sub-primitive
614 ! turn local number into offset
617 temp0 rs-reg temp0 [+] MOV
620 ] \ get-local define-sub-primitive
625 ! adjust stack pointer
626 ds-reg bootstrap-cell SUB
627 ! turn local number into offset
629 ! decrement retain stack pointer
631 ] \ drop-locals define-sub-primitive
633 [ "bootstrap.x86" forget-vocab ] with-compilation-unit