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
6 locals.backend math math.private namespaces sequences
7 slots.private strings.private vocabs ;
11 temp0 32-bit-version-of ;
13 temp1 32-bit-version-of ;
17 ! C to Factor entry point
19 ! Optimizing compiler's side of callback accesses
20 ! arguments that are on the stack via the frame pointer.
21 ! On x86-32 fastcall, and x86-64, some arguments are passed
22 ! in registers, and so the only registers that are safe for
23 ! use here are frame-reg, nv-reg and vm-reg.
25 frame-reg stack-reg MOV
27 ! Save all non-volatile registers
33 vm-reg 0 MOV 0 rc-absolute-cell rel-vm
36 nv-reg vm-reg vm-context-offset [+] MOV
39 ! Switch over to the spare context
40 nv-reg vm-reg vm-spare-context-offset [+] MOV
41 vm-reg vm-context-offset [+] nv-reg MOV
43 ! Save C callstack pointer
44 nv-reg context-callstack-save-offset [+] stack-reg MOV
46 ! Load Factor stack pointers
47 stack-reg nv-reg context-callstack-bottom-offset [+] MOV
51 rs-reg nv-reg context-retainstack-offset [+] MOV
52 ds-reg nv-reg context-datastack-offset [+] MOV
54 ! Call into Factor code
55 link-reg 0 MOV f rc-absolute-cell rel-word
58 ! Load VM into vm-reg; only needed on x86-32, but doesn't
60 vm-reg 0 MOV 0 rc-absolute-cell rel-vm
62 ! Load C callstack pointer
63 nv-reg vm-reg vm-context-offset [+] MOV
64 stack-reg nv-reg context-callstack-save-offset [+] MOV
68 vm-reg vm-context-offset [+] nv-reg MOV
70 ! Restore non-volatile registers
73 nv-regs <reversed> [ POP ] each
77 ! Callbacks which return structs, or use stdcall/fastcall/thiscall,
78 ! need a parameter here.
80 ! See the comment for M\ x86.32 stack-cleanup in cpu.x86.32
81 0xffff RET f rc-absolute-2 rel-untagged
82 ] CALLBACK-STUB jit-define
86 temp0 0 MOV f rc-absolute-cell rel-literal
87 ! increment datastack pointer
88 ds-reg bootstrap-cell ADD
89 ! store literal on datastack
91 ] JIT-PUSH-LITERAL jit-define
94 0 CALL f rc-relative rel-word-pic
95 ] JIT-WORD-CALL jit-define
97 ! The *-signal-handler subprimitives are special-cased in vm/quotations.cpp
98 ! not to trigger generation of a stack frame, so they can
99 ! peform their own prolog/epilog preserving registers.
101 ! It is important that the total is 192/64 and that it matches the
102 ! constants in vm/cpu-x86.*.hpp
103 : jit-signal-handler-prolog ( -- )
104 ! Return address already on stack -> 8/4 bytes.
106 ! Push all registers. 15 regs/120 bytes on 64bit, 7 regs/28 bytes
107 ! on 32bit -> 128/32 bytes.
108 signal-handler-save-regs [ PUSH ] each
110 ! Push flags -> 136/36 bytes
113 ! Register parameter area 32 bytes, unused on platforms other than
114 ! windows 64 bit, but including it doesn't hurt. Plus
115 ! alignment. LEA used so we don't dirty flags -> 192/64 bytes.
116 stack-reg stack-reg 7 bootstrap-cells neg [+] LEA
120 : jit-signal-handler-epilog ( -- )
121 stack-reg stack-reg 7 bootstrap-cells [+] LEA
123 signal-handler-save-regs reverse [ POP ] each ;
129 ds-reg bootstrap-cell SUB
130 ! compare boolean with f
131 temp0 \ f type-number CMP
132 ! jump to true branch if not equal
133 0 JNE f rc-relative rel-word
134 ! jump to false branch if equal
135 0 JMP f rc-relative rel-word
139 rs-reg bootstrap-cell ADD
141 ds-reg bootstrap-cell SUB
142 rs-reg [] temp0 MOV ;
145 rs-reg 2 bootstrap-cells ADD
147 temp1 ds-reg -1 bootstrap-cells [+] MOV
148 ds-reg 2 bootstrap-cells SUB
150 rs-reg -1 bootstrap-cells [+] temp1 MOV ;
153 rs-reg 3 bootstrap-cells ADD
155 temp1 ds-reg -1 bootstrap-cells [+] MOV
156 temp2 ds-reg -2 bootstrap-cells [+] MOV
157 ds-reg 3 bootstrap-cells SUB
159 rs-reg -1 bootstrap-cells [+] temp1 MOV
160 rs-reg -2 bootstrap-cells [+] temp2 MOV ;
163 ds-reg bootstrap-cell ADD
165 rs-reg bootstrap-cell SUB
166 ds-reg [] temp0 MOV ;
169 ds-reg 2 bootstrap-cells ADD
171 temp1 rs-reg -1 bootstrap-cells [+] MOV
172 rs-reg 2 bootstrap-cells SUB
174 ds-reg -1 bootstrap-cells [+] temp1 MOV ;
177 ds-reg 3 bootstrap-cells ADD
179 temp1 rs-reg -1 bootstrap-cells [+] MOV
180 temp2 rs-reg -2 bootstrap-cells [+] MOV
181 rs-reg 3 bootstrap-cells SUB
183 ds-reg -1 bootstrap-cells [+] temp1 MOV
184 ds-reg -2 bootstrap-cells [+] temp2 MOV ;
188 0 CALL f rc-relative rel-word
194 0 CALL f rc-relative rel-word
196 ] JIT-2DIP jit-define
200 0 CALL f rc-relative rel-word
202 ] JIT-3DIP jit-define
208 ds-reg bootstrap-cell SUB
210 [ temp0 word-entry-point-offset [+] CALL ]
211 [ temp0 word-entry-point-offset [+] JMP ]
212 \ (execute) define-combinator-primitive
216 ds-reg bootstrap-cell SUB
217 temp0 word-entry-point-offset [+] JMP
218 ] JIT-EXECUTE jit-define
221 stack-reg stack-frame-size bootstrap-cell - SUB
222 ] JIT-PROLOG jit-define
225 stack-reg stack-frame-size bootstrap-cell - ADD
226 ] JIT-EPILOG jit-define
228 [ 0 RET ] JIT-RETURN jit-define
230 ! ! ! Polymorphic inline caches
232 ! The PIC stubs are not permitted to touch pic-tail-reg.
234 ! Load a value from a stack position
236 temp1 ds-reg 0x7f [+] MOV f rc-absolute-1 rel-untagged
237 ] PIC-LOAD jit-define
239 [ temp1/32 tag-mask get AND ] PIC-TAG jit-define
243 temp1/32 tag-mask get AND
244 temp1/32 tuple type-number CMP
246 [ temp1 temp0 tuple-class-offset [+] MOV ]
248 ] PIC-TUPLE jit-define
251 temp1/32 0x7f CMP f rc-absolute-1 rel-untagged
252 ] PIC-CHECK-TAG jit-define
254 [ 0 JE f rc-relative rel-word ] PIC-HIT jit-define
256 ! ! ! Megamorphic caches
261 temp1/32 tag-mask get AND
262 temp1/32 tag-bits get SHL
263 temp1/32 tuple type-number tag-fixnum CMP
265 [ temp1 temp0 tuple-class-offset [+] MOV ]
268 temp0 0 MOV f rc-absolute-cell rel-literal
269 ! key = hashcode(class)
271 bootstrap-cell 4 = [ temp2 1 SHR ] when
272 ! key &= cache.length - 1
273 temp2 mega-cache-size get 1 - bootstrap-cell * AND
274 ! cache += array-start-offset
275 temp0 array-start-offset ADD
278 ! if(get(cache) == class)
282 ! megamorphic_cache_hits++
283 temp1 0 MOV rc-absolute-cell rel-megamorphic-cache-hits
285 ! goto get(cache + bootstrap-cell)
286 temp0 temp0 bootstrap-cell [+] MOV
287 temp0 word-entry-point-offset [+] JMP
288 ! fall-through on miss
290 ] MEGA-LOOKUP jit-define
293 : jit-compare ( insn -- )
295 temp3 0 MOV t rc-absolute-cell rel-literal
297 temp1 \ f type-number MOV
300 ! adjust stack pointer
301 ds-reg bootstrap-cell SUB
302 ! compare with second value
305 [ temp1 temp3 ] dip execute( dst src -- )
307 ds-reg [] temp1 MOV ;
310 : jit-math ( insn -- )
314 ds-reg bootstrap-cell SUB
316 [ ds-reg [] temp0 ] dip execute( dst src -- ) ;
318 : jit-fixnum-/mod ( -- )
319 ! load second parameter
321 ! load first parameter
322 div-arg ds-reg bootstrap-cell neg [+] MOV
326 mod-arg bootstrap-cell-bits 1 - SAR
330 ! # All x86 subprimitives
335 { fixnum+fast [ \ ADD jit-math ] }
338 { fixnum-bitand [ \ AND jit-math ] }
343 ds-reg [] tag-mask get XOR
345 { fixnum-bitor [ \ OR jit-math ] }
346 { fixnum-bitxor [ \ XOR jit-math ] }
347 { fixnum-shift-fast [
349 shift-arg ds-reg [] MOV
351 shift-arg tag-bits get SAR
352 ! adjust stack pointer
353 ds-reg bootstrap-cell SUB
358 ! compute positive shift value in temp2
361 ! compute negative shift value in temp3
363 temp3 tag-mask get bitnot AND
365 ! if shift count was negative, move temp0 to temp2
374 ds-reg bootstrap-cell SUB
376 temp0 tag-mask get TEST
377 temp0 \ f type-number MOV
378 temp1 1 tag-fixnum MOV
382 { eq? [ \ CMOVE jit-compare ] }
383 { fixnum> [ \ CMOVG jit-compare ] }
384 { fixnum>= [ \ CMOVGE jit-compare ] }
385 { fixnum< [ \ CMOVL jit-compare ] }
386 { fixnum<= [ \ CMOVLE jit-compare ] }
391 ! adjust stack pointer
392 ds-reg bootstrap-cell SUB
394 ds-reg [] mod-arg MOV
398 ! adjust stack pointer
399 ds-reg bootstrap-cell SUB
401 div-arg tag-bits get SHL
403 ds-reg [] div-arg MOV
408 div-arg tag-bits get SHL
410 ds-reg [] mod-arg MOV
411 ds-reg bootstrap-cell neg [+] div-arg MOV
419 ds-reg bootstrap-cell SUB
423 temp0 tag-bits get SAR
431 { fixnum-fast [ \ SUB jit-math ] }
437 ! adjust stack pointer
438 ds-reg bootstrap-cell SUB
439 ! turn local number into offset
441 ! decrement retain stack pointer
447 ! turn local number into offset
450 temp0 rs-reg temp0 [+] MOV
454 { load-local [ jit->r ] }
460 ! adjust stack pointer
461 ds-reg bootstrap-cell SUB
464 ! turn slot number into offset
467 temp1 tag-bits get SHR
468 temp1 tag-bits get SHL
470 temp0 temp1 temp0 [+] MOV
475 ! load string index from stack
476 temp0 ds-reg bootstrap-cell neg [+] MOV
477 temp0 tag-bits get SHR
478 ! load string from stack
481 temp0 8-bit-version-of temp0 temp1 string-offset [++] MOV
482 temp0 temp0 8-bit-version-of MOVZX
483 temp0 tag-bits get SHL
484 ! store character to stack
485 ds-reg bootstrap-cell SUB
492 temp0/32 tag-mask get AND
494 temp0/32 tag-bits get SHL
502 { drop [ ds-reg bootstrap-cell SUB ] }
503 { 2drop [ ds-reg 2 bootstrap-cells SUB ] }
504 { 3drop [ ds-reg 3 bootstrap-cells SUB ] }
505 { 4drop [ ds-reg 4 bootstrap-cells SUB ] }
510 ds-reg bootstrap-cell ADD
515 temp1 ds-reg bootstrap-cell neg [+] MOV
516 ds-reg 2 bootstrap-cells ADD
518 ds-reg bootstrap-cell neg [+] temp1 MOV
522 temp1 ds-reg -1 bootstrap-cells [+] MOV
523 temp3 ds-reg -2 bootstrap-cells [+] MOV
524 ds-reg 3 bootstrap-cells ADD
526 ds-reg -1 bootstrap-cells [+] temp1 MOV
527 ds-reg -2 bootstrap-cells [+] temp3 MOV
531 temp1 ds-reg -1 bootstrap-cells [+] MOV
532 temp2 ds-reg -2 bootstrap-cells [+] MOV
533 temp3 ds-reg -3 bootstrap-cells [+] MOV
534 ds-reg 4 bootstrap-cells ADD
536 ds-reg -1 bootstrap-cells [+] temp1 MOV
537 ds-reg -2 bootstrap-cells [+] temp2 MOV
538 ds-reg -3 bootstrap-cells [+] temp3 MOV
542 temp1 ds-reg -1 bootstrap-cells [+] MOV
544 ds-reg bootstrap-cell ADD
550 temp0 ds-reg -1 bootstrap-cells [+] MOV
551 ds-reg bootstrap-cell ADD
555 temp0 ds-reg -2 bootstrap-cells [+] MOV
556 ds-reg bootstrap-cell ADD
563 ds-reg bootstrap-cell SUB
568 ds-reg 2 bootstrap-cells SUB
575 temp1 ds-reg -1 bootstrap-cells [+] MOV
576 temp3 ds-reg -2 bootstrap-cells [+] MOV
577 ds-reg -2 bootstrap-cells [+] temp0 MOV
578 ds-reg -1 bootstrap-cells [+] temp3 MOV
583 temp1 ds-reg -1 bootstrap-cells [+] MOV
584 temp3 ds-reg -2 bootstrap-cells [+] MOV
585 ds-reg -2 bootstrap-cells [+] temp1 MOV
586 ds-reg -1 bootstrap-cells [+] temp0 MOV
591 temp1 ds-reg bootstrap-cell neg [+] MOV
592 ds-reg bootstrap-cell neg [+] temp0 MOV
596 temp0 ds-reg -1 bootstrap-cells [+] MOV
597 temp1 ds-reg -2 bootstrap-cells [+] MOV
598 ds-reg -2 bootstrap-cells [+] temp0 MOV
599 ds-reg -1 bootstrap-cells [+] temp1 MOV
603 { leaf-signal-handler [
604 jit-signal-handler-prolog
606 temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
608 jit-signal-handler-epilog
609 ! Pop the fake leaf frame along with our return address
610 leaf-stack-frame-size bootstrap-cell - RET
613 jit-signal-handler-prolog
615 temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
617 jit-signal-handler-epilog
620 } define-sub-primitives
622 [ "bootstrap.x86" forget-vocab ] with-compilation-unit