]> gitweb.factorcode.org Git - factor.git/blobdiff - basis/cpu/x86/bootstrap.factor
use radix literals
[factor.git] / basis / cpu / x86 / bootstrap.factor
index eb4da296dc9d85601a76d3a0bf44c178262b80b3..3c6d7ae8de60449f3cefe90b72e4eaaae5eafa89 100644 (file)
-! Copyright (C) 2007, 2009 Slava Pestov.
+! Copyright (C) 2007, 2011 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: bootstrap.image.private kernel kernel.private namespaces system
-layouts compiler.units math math.private compiler.constants vocabs
-slots.private words locals.backend make sequences combinators arrays
- cpu.x86.assembler cpu.x86.assembler.operands ;
+USING: bootstrap.image.private compiler.constants
+compiler.codegen.relocation compiler.units cpu.x86.assembler
+cpu.x86.assembler.operands kernel kernel.private layouts
+locals locals.backend make math math.private namespaces sequences
+slots.private strings.private vocabs ;
 IN: bootstrap.x86
 
 big-endian off
 
+! C to Factor entry point
 [
-    ! Load word
-    temp0 0 MOV rc-absolute-cell rt-immediate jit-rel
-    ! Bump profiling counter
-    temp0 profile-count-offset [+] 1 tag-fixnum ADD
-    ! Load word->code
-    temp0 temp0 word-code-offset [+] MOV
-    ! Compute word XT
-    temp0 compiled-header-size ADD
-    ! Jump to XT
-    temp0 JMP
-] jit-profiling jit-define
+    ! Optimizing compiler's side of callback accesses
+    ! arguments that are on the stack via the frame pointer.
+    ! On x86-32 fastcall, and x86-64, some arguments are passed
+    ! in registers, and so the only registers that are safe for
+    ! use here are frame-reg, nv-reg and vm-reg.
+    frame-reg PUSH
+    frame-reg stack-reg MOV
 
-[
-    ! load XT
-    temp0 0 MOV rc-absolute-cell rt-this jit-rel
-    ! save stack frame size
-    stack-frame-size PUSH
-    ! push XT
-    temp0 PUSH
-    ! alignment
-    stack-reg stack-frame-size 3 bootstrap-cells - SUB
-] jit-prolog jit-define
+    ! Save all non-volatile registers
+    nv-regs [ PUSH ] each
+
+    jit-save-tib
+
+    ! Load VM into vm-reg
+    vm-reg 0 MOV 0 rc-absolute-cell rel-vm
+
+    ! Save old context
+    nv-reg vm-reg vm-context-offset [+] MOV
+    nv-reg PUSH
+
+    ! Switch over to the spare context
+    nv-reg vm-reg vm-spare-context-offset [+] MOV
+    vm-reg vm-context-offset [+] nv-reg MOV
+
+    ! Save C callstack pointer
+    nv-reg context-callstack-save-offset [+] stack-reg MOV
+
+    ! Load Factor stack pointers
+    stack-reg nv-reg context-callstack-bottom-offset [+] MOV
+    nv-reg jit-update-tib
+    jit-install-seh
+
+    rs-reg nv-reg context-retainstack-offset [+] MOV
+    ds-reg nv-reg context-datastack-offset [+] MOV
+
+    ! Call into Factor code
+    link-reg 0 MOV f rc-absolute-cell rel-word
+    link-reg CALL
+
+    ! Load VM into vm-reg; only needed on x86-32, but doesn't
+    ! hurt on x86-64
+    vm-reg 0 MOV 0 rc-absolute-cell rel-vm
+
+    ! Load C callstack pointer
+    nv-reg vm-reg vm-context-offset [+] MOV
+    stack-reg nv-reg context-callstack-save-offset [+] MOV
+
+    ! Load old context
+    nv-reg POP
+    vm-reg vm-context-offset [+] nv-reg MOV
+
+    ! Restore non-volatile registers
+    jit-restore-tib
+
+    nv-regs <reversed> [ POP ] each
+
+    frame-reg POP
+
+    ! Callbacks which return structs, or use stdcall/fastcall/thiscall,
+    ! need a parameter here.
+
+    ! See the comment for M\ x86.32 stack-cleanup in cpu.x86.32
+    0xffff RET f rc-absolute-2 rel-untagged
+] callback-stub jit-define
 
 [
     ! load literal
-    temp0 0 MOV rc-absolute-cell rt-immediate jit-rel
+    temp0 0 MOV f rc-absolute-cell rel-literal
     ! increment datastack pointer
     ds-reg bootstrap-cell ADD
     ! store literal on datastack
     ds-reg [] temp0 MOV
-] jit-push-immediate jit-define
+] jit-push jit-define
 
 [
-    temp3 0 MOV rc-absolute-cell rt-here jit-rel
-    0 JMP rc-relative rt-xt-pic-tail jit-rel
-] jit-word-jump jit-define
-
-[
-    0 CALL rc-relative rt-xt-pic jit-rel
+    0 CALL f rc-relative rel-word-pic
 ] jit-word-call jit-define
 
-[
-    0 JMP rc-relative rt-xt jit-rel
-] jit-word-special jit-define
+! The *-signal-handler subprimitives are special-cased in vm/quotations.cpp
+! not to trigger generation of a stack frame, so they can
+! peform their own prolog/epilog preserving registers.
+
+[| |
+    jit-signal-handler-prolog :> frame-size
+    jit-save-context
+    temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
+    temp0 CALL
+    frame-size jit-signal-handler-epilog
+    0 RET
+] \ signal-handler define-sub-primitive
+
+: leaf-frame-size ( -- n ) 4 bootstrap-cells ;
+
+[| |
+    jit-signal-handler-prolog :> frame-size
+    jit-save-context
+    temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
+    temp0 CALL
+    frame-size jit-signal-handler-epilog
+    ! Pop the fake leaf frame along with our return address
+    leaf-frame-size bootstrap-cell - RET
+] \ leaf-signal-handler define-sub-primitive
+
+[| |
+    jit-signal-handler-prolog :> frame-size
+    temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
+    temp0 CALL
+    frame-size jit-signal-handler-epilog
+    red-zone-size RET
+] \ ffi-signal-handler define-sub-primitive
+
+[| |
+    jit-signal-handler-prolog :> frame-size
+    temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
+    temp0 CALL
+    frame-size jit-signal-handler-epilog
+    red-zone-size 16 bootstrap-cell - + RET
+] \ ffi-leaf-signal-handler define-sub-primitive
 
 [
     ! load boolean
@@ -60,11 +136,11 @@ big-endian off
     ! pop boolean
     ds-reg bootstrap-cell SUB
     ! compare boolean with f
-    temp0 \ f tag-number CMP
+    temp0 \ f type-number CMP
     ! jump to true branch if not equal
-    0 JNE rc-relative rt-xt jit-rel
+    0 JNE f rc-relative rel-word
     ! jump to false branch if equal
-    0 JMP rc-relative rt-xt jit-rel
+    0 JMP f rc-relative rel-word
 ] jit-if jit-define
 
 : jit->r ( -- )
@@ -117,36 +193,39 @@ big-endian off
 
 [
     jit->r
-    0 CALL rc-relative rt-xt jit-rel
+    0 CALL f rc-relative rel-word
     jit-r>
 ] jit-dip jit-define
 
 [
     jit-2>r
-    0 CALL rc-relative rt-xt jit-rel
+    0 CALL f rc-relative rel-word
     jit-2r>
 ] jit-2dip jit-define
 
 [
     jit-3>r
-    0 CALL rc-relative rt-xt jit-rel
+    0 CALL f rc-relative rel-word
     jit-3r>
 ] jit-3dip jit-define
 
-: prepare-(execute) ( -- operand )
+[
     ! load from stack
     temp0 ds-reg [] MOV
     ! pop stack
     ds-reg bootstrap-cell SUB
-    ! execute word
-    temp0 word-xt-offset [+] ;
+]
+[ temp0 word-entry-point-offset [+] CALL ]
+[ temp0 word-entry-point-offset [+] JMP ]
+\ (execute) define-combinator-primitive
 
-[ prepare-(execute) JMP ] jit-execute-jump jit-define
-
-[ prepare-(execute) CALL ] jit-execute-call jit-define
+[
+    temp0 ds-reg [] MOV
+    ds-reg bootstrap-cell SUB
+    temp0 word-entry-point-offset [+] JMP
+] jit-execute jit-define
 
 [
-    ! unwind stack frame
     stack-reg stack-frame-size bootstrap-cell - ADD
 ] jit-epilog jit-define
 
@@ -154,77 +233,46 @@ big-endian off
 
 ! ! ! Polymorphic inline caches
 
-! The PIC and megamorphic code stubs are not permitted to touch temp3.
+! The PIC stubs are not permitted to touch pic-tail-reg.
 
 ! Load a value from a stack position
 [
-    temp1 ds-reg HEX: ffffffff [+] MOV rc-absolute rt-untagged jit-rel
+    temp1 ds-reg 0x7f [+] MOV f rc-absolute-1 rel-untagged
 ] pic-load jit-define
 
-! Tag
-: load-tag ( -- )
-    temp1 tag-mask get AND
-    temp1 tag-bits get SHL ;
-
-[ load-tag ] pic-tag jit-define
-
-! The 'make' trick lets us compute the jump distance for the
-! conditional branches there
-
-! Hi-tag
-[
-    temp0 temp1 MOV
-    load-tag
-    temp1 object tag-number tag-fixnum CMP
-    [ temp1 temp0 object tag-number neg [+] MOV ] { } make
-    [ length JNE ] [ % ] bi
-] pic-hi-tag jit-define
+[ temp1 tag-mask get AND ] pic-tag jit-define
 
-! Tuple
 [
     temp0 temp1 MOV
-    load-tag
-    temp1 tuple tag-number tag-fixnum CMP
-    [ temp1 temp0 tuple tag-number neg bootstrap-cell + [+] MOV ] { } make
-    [ length JNE ] [ % ] bi
+    temp1 tag-mask get AND
+    temp1 tuple type-number CMP
+    [ JNE ]
+    [ temp1 temp0 tuple-class-offset [+] MOV ]
+    jit-conditional
 ] pic-tuple jit-define
 
-! Hi-tag and tuple
 [
-    temp0 temp1 MOV
-    load-tag
-    ! If bits 2 and 3 are set, the tag is either 6 (object) or 7 (tuple)
-    temp1 BIN: 110 tag-fixnum CMP
-    [
-        ! Untag temp0
-        temp0 tag-mask get bitnot AND
-        ! Set temp1 to 0 for objects, and bootstrap-cell for tuples
-        temp1 1 tag-fixnum AND
-        bootstrap-cell 4 = [ temp1 1 SHR ] when
-        ! Load header cell or tuple layout cell
-        temp1 temp0 temp1 [+] MOV
-    ] [ ] make [ length JL ] [ % ] bi
-] pic-hi-tag-tuple jit-define
-
-[
-    temp1 HEX: ffffffff CMP rc-absolute rt-immediate jit-rel
+    temp1 0x7f CMP f rc-absolute-1 rel-untagged
 ] pic-check-tag jit-define
 
-[
-    temp2 HEX: ffffffff MOV rc-absolute-cell rt-immediate jit-rel
-    temp1 temp2 CMP
-] pic-check jit-define
-
-[ 0 JE rc-relative rt-xt jit-rel ] pic-hit jit-define
+[ 0 JE f rc-relative rel-word ] pic-hit jit-define
 
 ! ! ! Megamorphic caches
 
 [
+    ! class = ...
+    temp0 temp1 MOV
+    temp1 tag-mask get AND
+    temp1 tag-bits get SHL
+    temp1 tuple type-number tag-fixnum CMP
+    [ JNE ]
+    [ temp1 temp0 tuple-class-offset [+] MOV ]
+    jit-conditional
     ! cache = ...
-    temp0 0 MOV rc-absolute-cell rt-immediate jit-rel
-    ! key = class
+    temp0 0 MOV f rc-absolute-cell rel-literal
+    ! key = hashcode(class)
     temp2 temp1 MOV
-    bootstrap-cell 8 = [ temp2 1 SHL ] when
+    bootstrap-cell 4 = [ temp2 1 SHR ] when
     ! key &= cache.length - 1
     temp2 mega-cache-size get 1 - bootstrap-cell * AND
     ! cache += array-start-offset
@@ -233,30 +281,20 @@ big-endian off
     temp0 temp2 ADD
     ! if(get(cache) == class)
     temp0 [] temp1 CMP
-    bootstrap-cell 4 = 14 22 ? JNE ! Yuck!
-    ! megamorphic_cache_hits++
-    temp1 0 MOV rc-absolute-cell rt-megamorphic-cache-hits jit-rel
-    temp1 [] 1 ADD
-    ! goto get(cache + bootstrap-cell)
-    temp0 temp0 bootstrap-cell [+] MOV
-    temp0 word-xt-offset [+] JMP
-    ! fall-through on miss
+    [ JNE ]
+    [
+        ! megamorphic_cache_hits++
+        temp1 0 MOV rc-absolute-cell rel-megamorphic-cache-hits
+        temp1 [] 1 ADD
+        ! goto get(cache + bootstrap-cell)
+        temp0 temp0 bootstrap-cell [+] MOV
+        temp0 word-entry-point-offset [+] JMP
+        ! fall-through on miss
+    ] jit-conditional
 ] mega-lookup jit-define
 
 ! ! ! Sub-primitives
 
-! Quotations and words
-[
-    ! load from stack
-    arg1 ds-reg [] MOV
-    ! pop stack
-    ds-reg bootstrap-cell SUB
-    ! pass vm pointer
-    arg2 0 MOV 0 jit-literal rc-absolute-cell rt-vm jit-rel
-    ! call quotation
-    arg1 quot-xt-offset [+] JMP
-] \ (call) define-sub-primitive
-
 ! Objects
 [
     ! load from stack
@@ -287,6 +325,21 @@ big-endian off
     ds-reg [] temp0 MOV
 ] \ slot define-sub-primitive
 
+[
+    ! load string index from stack
+    temp0 ds-reg bootstrap-cell neg [+] MOV
+    temp0 tag-bits get SHR
+    ! load string from stack
+    temp1 ds-reg [] MOV
+    ! load character
+    temp0 8-bit-version-of temp0 temp1 string-offset [++] MOV
+    temp0 temp0 8-bit-version-of MOVZX
+    temp0 tag-bits get SHL
+    ! store character to stack
+    ds-reg bootstrap-cell SUB
+    ds-reg [] temp0 MOV
+] \ string-nth-fast define-sub-primitive
+
 ! Shufflers
 [
     ds-reg bootstrap-cell SUB
@@ -356,15 +409,6 @@ big-endian off
     ds-reg [] temp0 MOV
 ] \ dupd define-sub-primitive
 
-[
-    temp0 ds-reg [] MOV
-    temp1 ds-reg -1 bootstrap-cells [+] MOV
-    ds-reg bootstrap-cell ADD
-    ds-reg [] temp0 MOV
-    ds-reg -1 bootstrap-cells [+] temp1 MOV
-    ds-reg -2 bootstrap-cells [+] temp0 MOV
-] \ tuck define-sub-primitive
-
 [
     temp0 ds-reg [] MOV
     temp1 ds-reg bootstrap-cell neg [+] MOV
@@ -402,10 +446,9 @@ big-endian off
 ! Comparisons
 : jit-compare ( insn -- )
     ! load t
-    t jit-literal
-    temp3 0 MOV rc-absolute-cell rt-immediate jit-rel
+    temp3 0 MOV t rc-absolute-cell rel-literal
     ! load f
-    temp1 \ f tag-number MOV
+    temp1 \ f type-number MOV
     ! load first value
     temp0 ds-reg [] MOV
     ! adjust stack pointer
@@ -451,7 +494,7 @@ big-endian off
     ! multiply
     temp0 temp1 IMUL2
     ! push result
-    ds-reg [] temp1 MOV
+    ds-reg [] temp0 MOV
 ] \ fixnum*fast define-sub-primitive
 
 [ \ AND jit-math ] \ fixnum-bitand define-sub-primitive
@@ -477,23 +520,23 @@ big-endian off
     ! load value
     temp3 ds-reg [] MOV
     ! make a copy
-    temp1 temp3 MOV
-    ! compute positive shift value in temp1
-    temp1 CL SHL
+    temp2 temp3 MOV
+    ! compute positive shift value in temp2
+    temp2 CL SHL
     shift-arg NEG
     ! compute negative shift value in temp3
     temp3 CL SAR
     temp3 tag-mask get bitnot AND
     shift-arg 0 CMP
-    ! if shift count was negative, move temp0 to temp1
-    temp1 temp3 CMOVGE
+    ! if shift count was negative, move temp0 to temp2
+    temp2 temp3 CMOVGE
     ! push to stack
-    ds-reg [] temp1 MOV
+    ds-reg [] temp2 MOV
 ] \ fixnum-shift-fast define-sub-primitive
 
 : jit-fixnum-/mod ( -- )
     ! load second parameter
-    temp3 ds-reg [] MOV
+    temp1 ds-reg [] MOV
     ! load first parameter
     div-arg ds-reg bootstrap-cell neg [+] MOV
     ! make a copy
@@ -501,7 +544,7 @@ big-endian off
     ! sign-extend
     mod-arg bootstrap-cell-bits 1 - SAR
     ! divide
-    temp3 IDIV ;
+    temp1 IDIV ;
 
 [
     jit-fixnum-/mod
@@ -534,8 +577,8 @@ big-endian off
     temp0 ds-reg [] MOV
     ds-reg bootstrap-cell SUB
     temp0 ds-reg [] OR
-    temp0 tag-mask get AND
-    temp0 \ f tag-number MOV
+    temp0 tag-mask get TEST
+    temp0 \ f type-number MOV
     temp1 1 tag-fixnum MOV
     temp0 temp1 CMOVE
     ds-reg [] temp0 MOV