compiler, cpu.x86.32: clean up FFI implementation, in particular 32-bit x86-specific backend

db4
Slava Pestov 2009-10-20 04:15:10 -05:00
parent 08b683de61
commit 560b6f45cc
4 changed files with 95 additions and 147 deletions

View File

@ -1,18 +1,19 @@
! Copyright (C) 2007, 2008 Slava Pestov. ! Copyright (C) 2007, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien alien.data alien.strings parser USING: accessors alien alien.c-types alien.data alien.strings
threads words kernel.private kernel io.encodings.utf8 eval ; parser threads words kernel.private kernel io.encodings.utf8
eval ;
IN: alien.remote-control IN: alien.remote-control
: eval-callback ( -- callback ) : eval-callback ( -- callback )
"void*" { "char*" } "cdecl" void* { char* } "cdecl"
[ eval>string utf8 malloc-string ] alien-callback ; [ eval>string utf8 malloc-string ] alien-callback ;
: yield-callback ( -- callback ) : yield-callback ( -- callback )
"void" { } "cdecl" [ yield ] alien-callback ; void { } "cdecl" [ yield ] alien-callback ;
: sleep-callback ( -- callback ) : sleep-callback ( -- callback )
"void" { "long" } "cdecl" [ sleep ] alien-callback ; void { long } "cdecl" [ sleep ] alien-callback ;
: ?callback ( word -- alien ) : ?callback ( word -- alien )
dup optimized? [ execute ] [ drop f ] if ; inline dup optimized? [ execute ] [ drop f ] if ; inline

View File

@ -9,10 +9,10 @@ IN: compiler.alien
: alien-parameters ( params -- seq ) : alien-parameters ( params -- seq )
dup parameters>> dup parameters>>
swap return>> large-struct? [ "void*" prefix ] when ; swap return>> large-struct? [ void* prefix ] when ;
: alien-return ( params -- ctype ) : alien-return ( params -- ctype )
return>> dup large-struct? [ drop "void" ] when ; return>> dup large-struct? [ drop void ] when ;
: c-type-stack-align ( type -- align ) : c-type-stack-align ( type -- align )
dup c-type-stack-align? [ c-type-align ] [ drop cell ] if ; dup c-type-stack-align? [ c-type-align ] [ drop cell ] if ;

View File

@ -333,25 +333,22 @@ M: reg-class reg-class-full?
[ alloc-stack-param ] [ alloc-fastcall-param ] if [ alloc-stack-param ] [ alloc-fastcall-param ] if
[ param-reg ] dip ; [ param-reg ] dip ;
: (flatten-int-type) ( size -- seq ) : (flatten-int-type) ( type -- seq )
cell /i "void*" c-type <repetition> ; stack-size cell align cell /i void* c-type <repetition> ;
GENERIC: flatten-value-type ( type -- types ) GENERIC: flatten-value-type ( type -- types )
M: object flatten-value-type 1array ; M: object flatten-value-type 1array ;
M: struct-c-type flatten-value-type (flatten-int-type) ;
M: struct-c-type flatten-value-type ( type -- types ) M: long-long-type flatten-value-type (flatten-int-type) ;
stack-size cell align (flatten-int-type) ; M: c-type-name flatten-value-type c-type flatten-value-type ;
M: long-long-type flatten-value-type ( type -- types )
stack-size cell align (flatten-int-type) ;
: flatten-value-types ( params -- params ) : flatten-value-types ( params -- params )
#! Convert value type structs to consecutive void*s. #! Convert value type structs to consecutive void*s.
[ [
0 [ 0 [
c-type c-type
[ parameter-align (flatten-int-type) % ] keep [ parameter-align cell /i void* c-type <repetition> % ] keep
[ stack-size cell align + ] keep [ stack-size cell align + ] keep
flatten-value-type % flatten-value-type %
] reduce drop ] reduce drop

View File

@ -57,12 +57,12 @@ M:: x86.32 %dispatch ( src temp -- )
M: x86.32 pic-tail-reg EBX ; M: x86.32 pic-tail-reg EBX ;
M: x86.32 reserved-area-size 0 ; M: x86.32 reserved-area-size 4 cells ;
M: x86.32 %alien-invoke 0 CALL rc-relative rel-dlsym ; M: x86.32 %alien-invoke 0 CALL rc-relative rel-dlsym ;
: push-vm-ptr ( -- ) : save-vm-ptr ( n -- )
0 PUSH 0 rc-absolute-cell rel-vm ; ! push the vm ptr as an argument stack@ 0 MOV 0 rc-absolute-cell rel-vm ;
M: x86.32 return-struct-in-registers? ( c-type -- ? ) M: x86.32 return-struct-in-registers? ( c-type -- ? )
c-type c-type
@ -72,44 +72,34 @@ M: x86.32 return-struct-in-registers? ( c-type -- ? )
and or ; and or ;
: struct-return@ ( n -- operand ) : struct-return@ ( n -- operand )
[ next-stack@ ] [ stack-frame get params>> stack@ ] if* ; [ next-stack@ ] [ stack-frame get params>> param@ ] if* ;
! On x86, parameters are never passed in registers. ! On x86, parameters are never passed in registers.
M: int-regs return-reg drop EAX ; M: int-regs return-reg drop EAX ;
M: int-regs param-regs drop { } ; M: int-regs param-regs drop { } ;
M: float-regs param-regs drop { } ; M: float-regs param-regs drop { } ;
GENERIC: push-return-reg ( rep -- ) GENERIC: load-return-reg ( src rep -- )
GENERIC: load-return-reg ( n rep -- ) GENERIC: store-return-reg ( dst rep -- )
GENERIC: store-return-reg ( n rep -- )
M: int-rep push-return-reg drop EAX PUSH ; M: int-rep load-return-reg drop EAX swap MOV ;
M: int-rep load-return-reg drop EAX swap next-stack@ MOV ; M: int-rep store-return-reg drop EAX MOV ;
M: int-rep store-return-reg drop stack@ EAX MOV ;
M: float-rep push-return-reg drop ESP 4 SUB ESP [] FSTPS ; M: float-rep load-return-reg drop FLDS ;
M: float-rep load-return-reg drop next-stack@ FLDS ; M: float-rep store-return-reg drop FSTPS ;
M: float-rep store-return-reg drop stack@ FSTPS ;
M: double-rep push-return-reg drop ESP 8 SUB ESP [] FSTPL ; M: double-rep load-return-reg drop FLDL ;
M: double-rep load-return-reg drop next-stack@ FLDL ; M: double-rep store-return-reg drop FSTPL ;
M: double-rep store-return-reg drop stack@ FSTPL ;
: align-sub ( n -- )
[ align-stack ] keep - decr-stack-reg ;
: align-add ( n -- )
align-stack incr-stack-reg ;
: with-aligned-stack ( n quot -- )
'[ align-sub @ ] [ align-add ] bi ; inline
M: x86.32 %prologue ( n -- ) M: x86.32 %prologue ( n -- )
dup PUSH dup PUSH
0 PUSH rc-absolute-cell rel-this 0 PUSH rc-absolute-cell rel-this
3 cells - decr-stack-reg ; 3 cells - decr-stack-reg ;
M: x86.32 %load-param-reg 3drop ; M: x86.32 %load-param-reg
stack-params assert=
[ [ EAX ] dip param@ MOV ] dip
stack@ EAX MOV ;
M: x86.32 %save-param-reg 3drop ; M: x86.32 %save-param-reg 3drop ;
@ -118,15 +108,13 @@ M: x86.32 %save-param-reg 3drop ;
#! are boxing a return value of a C function. If n is an #! are boxing a return value of a C function. If n is an
#! integer, push [ESP+n] on the stack; we are boxing a #! integer, push [ESP+n] on the stack; we are boxing a
#! parameter being passed to a callback from C. #! parameter being passed to a callback from C.
over [ load-return-reg ] [ 2drop ] if ; over [ [ next-stack@ ] dip load-return-reg ] [ 2drop ] if ;
M:: x86.32 %box ( n rep func -- ) M:: x86.32 %box ( n rep func -- )
n rep (%box) n rep (%box)
rep rep-size cell + [ rep rep-size save-vm-ptr
push-vm-ptr 0 stack@ rep store-return-reg
rep push-return-reg func f %alien-invoke ;
func f %alien-invoke
] with-aligned-stack ;
: (%box-long-long) ( n -- ) : (%box-long-long) ( n -- )
[ [
@ -136,41 +124,31 @@ M:: x86.32 %box ( n rep func -- )
M: x86.32 %box-long-long ( n func -- ) M: x86.32 %box-long-long ( n func -- )
[ (%box-long-long) ] dip [ (%box-long-long) ] dip
12 [ 8 save-vm-ptr
push-vm-ptr 4 stack@ EDX MOV
EDX PUSH 0 stack@ EAX MOV
EAX PUSH f %alien-invoke ;
f %alien-invoke
] with-aligned-stack ;
M:: x86.32 %box-large-struct ( n c-type -- ) M:: x86.32 %box-large-struct ( n c-type -- )
! Compute destination address
EDX n struct-return@ LEA EDX n struct-return@ LEA
12 [ 8 save-vm-ptr
push-vm-ptr 4 stack@ c-type heap-size MOV
! Push struct size 0 stack@ EDX MOV
c-type heap-size PUSH "box_value_struct" f %alien-invoke ;
! Push destination address
EDX PUSH
! Copy the struct from the C stack
"box_value_struct" f %alien-invoke
] with-aligned-stack ;
M: x86.32 %prepare-box-struct ( -- ) M: x86.32 %prepare-box-struct ( -- )
! Compute target address for value struct return ! Compute target address for value struct return
EAX f struct-return@ LEA EAX f struct-return@ LEA
! Store it as the first parameter ! Store it as the first parameter
0 stack@ EAX MOV ; 0 param@ EAX MOV ;
M: x86.32 %box-small-struct ( c-type -- ) M: x86.32 %box-small-struct ( c-type -- )
#! Box a <= 8-byte struct returned in EAX:EDX. OS X only. #! Box a <= 8-byte struct returned in EAX:EDX. OS X only.
16 [ 12 save-vm-ptr
push-vm-ptr 8 stack@ swap heap-size MOV
heap-size PUSH 4 stack@ EDX MOV
EDX PUSH 0 stack@ EAX MOV
EAX PUSH "box_small_struct" f %alien-invoke ;
"box_small_struct" f %alien-invoke
] with-aligned-stack ;
M: x86.32 %prepare-unbox ( -- ) M: x86.32 %prepare-unbox ( -- )
#! Move top of data stack to EAX. #! Move top of data stack to EAX.
@ -178,14 +156,9 @@ M: x86.32 %prepare-unbox ( -- )
ESI 4 SUB ; ESI 4 SUB ;
: call-unbox-func ( func -- ) : call-unbox-func ( func -- )
8 [ 4 save-vm-ptr
! push the vm ptr as an argument 0 stack@ EAX MOV
push-vm-ptr f %alien-invoke ;
! Push parameter
EAX PUSH
! Call the unboxer
f %alien-invoke
] with-aligned-stack ;
M: x86.32 %unbox ( n rep func -- ) M: x86.32 %unbox ( n rep func -- )
#! The value being unboxed must already be in EAX. #! The value being unboxed must already be in EAX.
@ -194,37 +167,33 @@ M: x86.32 %unbox ( n rep func -- )
#! a parameter to a C function about to be called. #! a parameter to a C function about to be called.
call-unbox-func call-unbox-func
! Store the return value on the C stack ! Store the return value on the C stack
over [ store-return-reg ] [ 2drop ] if ; over [ [ param@ ] dip store-return-reg ] [ 2drop ] if ;
M: x86.32 %unbox-long-long ( n func -- ) M: x86.32 %unbox-long-long ( n func -- )
call-unbox-func call-unbox-func
! Store the return value on the C stack ! Store the return value on the C stack
[ [
dup stack@ EAX MOV dup param@ EAX MOV
cell + stack@ EDX MOV 4 + param@ EDX MOV
] when* ; ] when* ;
: %unbox-struct-1 ( -- ) : %unbox-struct-1 ( -- )
#! Alien must be in EAX. #! Alien must be in EAX.
8 [ 4 save-vm-ptr
push-vm-ptr 0 stack@ EAX MOV
EAX PUSH
"alien_offset" f %alien-invoke "alien_offset" f %alien-invoke
! Load first cell ! Load first cell
EAX EAX [] MOV EAX EAX [] MOV ;
] with-aligned-stack ;
: %unbox-struct-2 ( -- ) : %unbox-struct-2 ( -- )
#! Alien must be in EAX. #! Alien must be in EAX.
8 [ 4 save-vm-ptr
push-vm-ptr 0 stack@ EAX MOV
EAX PUSH
"alien_offset" f %alien-invoke "alien_offset" f %alien-invoke
! Load second cell ! Load second cell
EDX EAX 4 [+] MOV EDX EAX 4 [+] MOV
! Load first cell ! Load first cell
EAX EAX [] MOV EAX EAX [] MOV ;
] with-aligned-stack ;
M: x86 %unbox-small-struct ( size -- ) M: x86 %unbox-small-struct ( size -- )
#! Alien must be in EAX. #! Alien must be in EAX.
@ -236,63 +205,47 @@ M: x86 %unbox-small-struct ( size -- )
M:: x86.32 %unbox-large-struct ( n c-type -- ) M:: x86.32 %unbox-large-struct ( n c-type -- )
! Alien must be in EAX. ! Alien must be in EAX.
! Compute destination address ! Compute destination address
EDX n stack@ LEA EDX n param@ LEA
16 [ 12 save-vm-ptr
push-vm-ptr 8 stack@ c-type heap-size MOV
! Push struct size 4 stack@ EDX MOV
c-type heap-size PUSH 0 stack@ EAX MOV
! Push destination address "to_value_struct" f %alien-invoke ;
EDX PUSH
! Push source address
EAX PUSH
! Copy the struct to the stack
"to_value_struct" f %alien-invoke
] with-aligned-stack ;
M: x86.32 %nest-stacks ( -- ) M: x86.32 %nest-stacks ( -- )
! Save current frame. See comment in vm/contexts.hpp ! Save current frame. See comment in vm/contexts.hpp
EAX stack-reg stack-frame get total-size>> 3 cells - [+] LEA EAX stack-reg stack-frame get total-size>> 3 cells - [+] LEA
8 [ 4 save-vm-ptr
push-vm-ptr 0 stack@ EAX MOV
EAX PUSH "nest_stacks" f %alien-invoke ;
"nest_stacks" f %alien-invoke
] with-aligned-stack ;
M: x86.32 %unnest-stacks ( -- ) M: x86.32 %unnest-stacks ( -- )
4 [ 0 save-vm-ptr
push-vm-ptr "unnest_stacks" f %alien-invoke ;
"unnest_stacks" f %alien-invoke
] with-aligned-stack ;
M: x86.32 %prepare-alien-indirect ( -- ) M: x86.32 %prepare-alien-indirect ( -- )
4 [ 0 save-vm-ptr
push-vm-ptr
"unbox_alien" f %alien-invoke "unbox_alien" f %alien-invoke
] with-aligned-stack
EBP EAX MOV ; EBP EAX MOV ;
M: x86.32 %alien-indirect ( -- ) M: x86.32 %alien-indirect ( -- )
EBP CALL ; EBP CALL ;
M: x86.32 %alien-callback ( quot -- ) M: x86.32 %alien-callback ( quot -- )
! Fastcall
param-reg-1 swap %load-reference param-reg-1 swap %load-reference
param-reg-2 %mov-vm-ptr param-reg-2 %mov-vm-ptr
"c_to_factor" f %alien-invoke ; "c_to_factor" f %alien-invoke ;
M: x86.32 %callback-value ( ctype -- ) M: x86.32 %callback-value ( ctype -- )
! Align C stack
ESP 12 SUB
! Save top of data stack in non-volatile register ! Save top of data stack in non-volatile register
%prepare-unbox %prepare-unbox
EAX PUSH 4 stack@ EAX MOV
push-vm-ptr 0 save-vm-ptr
! Restore data/call/retain stacks ! Restore data/call/retain stacks
"unnest_stacks" f %alien-invoke "unnest_stacks" f %alien-invoke
! Place top of data stack in EAX ! Place former top of data stack back in EAX
temp-reg POP EAX 4 stack@ MOV
EAX POP
! Restore C stack
ESP 12 ADD
! Unbox EAX ! Unbox EAX
unbox-return ; unbox-return ;
@ -358,16 +311,10 @@ M: x86.32 %callback-return ( n -- )
M:: x86.32 %call-gc ( gc-root-count temp -- ) M:: x86.32 %call-gc ( gc-root-count temp -- )
temp gc-root-base param@ LEA temp gc-root-base param@ LEA
12 [ 8 save-vm-ptr
! Pass the VM ptr as the third parameter 4 stack@ gc-root-count MOV
push-vm-ptr 0 stack@ temp MOV
! Pass number of roots as second parameter "inline_gc" f %alien-invoke ;
gc-root-count PUSH
! Pass pointer to start of GC roots as first parameter
temp PUSH
! Call GC
"inline_gc" f %alien-invoke
] with-aligned-stack ;
M: x86.32 dummy-stack-params? f ; M: x86.32 dummy-stack-params? f ;
@ -375,10 +322,13 @@ M: x86.32 dummy-int-params? f ;
M: x86.32 dummy-fp-params? f ; M: x86.32 dummy-fp-params? f ;
! Dreadful
M: object flatten-value-type (flatten-int-type) ;
os windows? [ os windows? [
cell "longlong" c-type (>>align) cell longlong c-type (>>align)
cell "ulonglong" c-type (>>align) cell ulonglong c-type (>>align)
4 "double" c-type (>>align) 4 double c-type (>>align)
] unless ] unless
check-sse check-sse