1 USING: accessors alien alien.c-types alien.libraries
2 alien.syntax arrays classes.struct combinators
3 compiler continuations effects io io.backend io.pathnames
4 io.streams.string kernel math memory namespaces
5 namespaces.private parser quotations sequences
6 specialized-arrays stack-checker stack-checker.errors
7 system threads tools.test words alien.complex concurrency.promises ;
8 FROM: alien.c-types => float short ;
9 FROM: alien.private => fastcall ;
10 SPECIALIZED-ARRAY: float
11 SPECIALIZED-ARRAY: char
12 IN: compiler.tests.alien
15 : libfactor-ffi-tests-path ( -- string )
16 "resource:" absolute-path
18 { [ os winnt? ] [ "libfactor-ffi-test.dll" ] }
19 { [ os macosx? ] [ "libfactor-ffi-test.dylib" ] }
20 { [ os unix? ] [ "libfactor-ffi-test.so" ] }
23 "f-cdecl" libfactor-ffi-tests-path cdecl add-library
25 "f-stdcall" libfactor-ffi-tests-path stdcall add-library
27 "f-fastcall" libfactor-ffi-tests-path fastcall add-library
32 FUNCTION: void ffi_test_0 ;
33 [ ] [ ffi_test_0 ] unit-test
35 FUNCTION: int ffi_test_1 ;
36 [ 3 ] [ ffi_test_1 ] unit-test
38 FUNCTION: int ffi_test_2 int x int y ;
39 [ 5 ] [ 2 3 ffi_test_2 ] unit-test
40 [ "hi" 3 ffi_test_2 ] must-fail
42 FUNCTION: int ffi_test_3 int x int y int z int t ;
43 [ 25 ] [ 2 3 4 5 ffi_test_3 ] unit-test
45 FUNCTION: float ffi_test_4 ;
46 [ 1.5 ] [ ffi_test_4 ] unit-test
48 FUNCTION: double ffi_test_5 ;
49 [ 1.5 ] [ ffi_test_5 ] unit-test
51 FUNCTION: int ffi_test_9 int a int b int c int d int e int f int g ;
52 [ 28 ] [ 1 2 3 4 5 6 7 ffi_test_9 ] unit-test
53 [ "a" 2 3 4 5 6 7 ffi_test_9 ] must-fail
54 [ 1 2 3 4 5 6 "a" ffi_test_9 ] must-fail
56 STRUCT: FOO { x int } { y int } ;
58 : make-FOO ( x y -- FOO )
59 FOO <struct> swap >>y swap >>x ;
61 FUNCTION: int ffi_test_11 int a FOO b int c ;
63 [ 14 ] [ 1 2 3 make-FOO 4 ffi_test_11 ] unit-test
65 FUNCTION: int ffi_test_13 int a int b int c int d int e int f int g int h int i int j int k ;
67 [ 66 ] [ 1 2 3 4 5 6 7 8 9 10 11 ffi_test_13 ] unit-test
69 FUNCTION: FOO ffi_test_14 int x int y ;
71 [ 11 6 ] [ 11 6 ffi_test_14 [ x>> ] [ y>> ] bi ] unit-test
73 FUNCTION: c-string ffi_test_15 c-string x c-string y ;
75 [ "foo" ] [ "xy" "zt" ffi_test_15 ] unit-test
76 [ "bar" ] [ "xy" "xy" ffi_test_15 ] unit-test
77 [ 1 2 ffi_test_15 ] must-fail
79 STRUCT: BAR { x long } { y long } { z long } ;
81 FUNCTION: BAR ffi_test_16 long x long y long z ;
84 11 6 -7 ffi_test_16 [ x>> ] [ y>> ] [ z>> ] tri
87 STRUCT: TINY { x int } ;
89 FUNCTION: TINY ffi_test_17 int x ;
91 [ 11 ] [ 11 ffi_test_17 x>> ] unit-test
93 [ [ alien-indirect ] infer ] [ inference-error? ] must-fail-with
95 : indirect-test-1 ( ptr -- result )
96 int { } cdecl alien-indirect ;
98 { 1 1 } [ indirect-test-1 ] must-infer-as
100 [ B{ } indirect-test-1 ] [ { "kernel-error" 3 6 B{ } } = ] must-fail-with
102 [ 3 ] [ &: ffi_test_1 indirect-test-1 ] unit-test
104 : indirect-test-1' ( ptr -- )
105 int { } cdecl alien-indirect drop ;
107 { 1 0 } [ indirect-test-1' ] must-infer-as
109 [ ] [ &: ffi_test_1 indirect-test-1' ] unit-test
111 [ -1 indirect-test-1 ] must-fail
113 : indirect-test-2 ( x y ptr -- result )
114 int { int int } cdecl alien-indirect gc ;
116 { 3 1 } [ indirect-test-2 ] must-infer-as
119 [ 2 3 &: ffi_test_2 indirect-test-2 ]
122 : indirect-test-3 ( a b c d ptr -- result )
123 int { int int int int } stdcall alien-indirect
126 [ f ] [ "f-stdcall" load-library f = ] unit-test
127 [ stdcall ] [ "f-stdcall" library abi>> ] unit-test
129 : ffi_test_18 ( w x y z -- int )
130 int "f-stdcall" "ffi_test_18" { int int int int }
133 [ 25 ] [ 2 3 4 5 ffi_test_18 ] unit-test
135 : ffi_test_19 ( x y z -- BAR )
136 BAR "f-stdcall" "ffi_test_19" { long long long }
140 11 6 -7 ffi_test_19 [ x>> ] [ y>> ] [ z>> ] tri
143 FUNCTION: double ffi_test_6 float x float y ;
144 [ 6.0 ] [ 3.0 2.0 ffi_test_6 ] unit-test
145 [ "a" "b" ffi_test_6 ] must-fail
147 FUNCTION: double ffi_test_7 double x double y ;
148 [ 6.0 ] [ 3.0 2.0 ffi_test_7 ] unit-test
150 FUNCTION: double ffi_test_8 double x float y double z float t int w ;
151 [ 19.0 ] [ 3.0 2.0 1.0 6.0 7 ffi_test_8 ] unit-test
153 FUNCTION: int ffi_test_10 int a int b double c int d float e int f int g int h ;
154 [ -34 ] [ 1 2 3.0 4 5.0 6 7 8 ffi_test_10 ] unit-test
156 FUNCTION: void ffi_test_20 double x1, double x2, double x3,
157 double y1, double y2, double y3,
158 double z1, double z2, double z3 ;
160 [ ] [ 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 ffi_test_20 ] unit-test
162 ! Make sure XT doesn't get clobbered in stack frame
164 : ffi_test_31 ( a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a -- result y )
166 "f-cdecl" "ffi_test_31"
167 { int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int int }
170 [ 861 3 ] [ 42 [ ] each-integer ffi_test_31 ] unit-test
172 : ffi_test_31_point_5 ( a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a -- result )
174 "f-cdecl" "ffi_test_31_point_5"
175 { float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float float }
178 [ 861.0 ] [ 42 [ >float ] each-integer ffi_test_31_point_5 ] unit-test
180 FUNCTION: longlong ffi_test_21 long x long y ;
182 [ 121932631112635269 ]
183 [ 123456789 987654321 ffi_test_21 ] unit-test
185 FUNCTION: long ffi_test_22 long x longlong y longlong z ;
188 [ 1111 121932631112635269 123456789 ffi_test_22 ] unit-test
190 [ 1111 f 123456789 ffi_test_22 ] must-fail
193 { x float } { y float }
194 { w float } { h float } ;
196 : <RECT> ( x y w h -- rect )
203 FUNCTION: int ffi_test_12 int a int b RECT c int d int e int f ;
205 [ 45 ] [ 1 2 3.0 4.0 5.0 6.0 <RECT> 7 8 9 ffi_test_12 ] unit-test
207 [ 1 2 { 1 2 3 } 7 8 9 ffi_test_12 ] must-fail
209 FUNCTION: float ffi_test_23 ( float[3] x, float[3] y ) ;
212 { 1.0 2.0 3.0 } >float-array
213 { 4.0 5.0 6.0 } >float-array
217 ! Test odd-size structs
218 STRUCT: test-struct-1 { x char[1] } ;
220 FUNCTION: test-struct-1 ffi_test_24 ;
222 [ S{ test-struct-1 { x char-array{ 1 } } } ] [ ffi_test_24 ] unit-test
224 STRUCT: test-struct-2 { x char[2] } ;
226 FUNCTION: test-struct-2 ffi_test_25 ;
228 [ S{ test-struct-2 { x char-array{ 1 2 } } } ] [ ffi_test_25 ] unit-test
230 STRUCT: test-struct-3 { x char[3] } ;
232 FUNCTION: test-struct-3 ffi_test_26 ;
234 [ S{ test-struct-3 { x char-array{ 1 2 3 } } } ] [ ffi_test_26 ] unit-test
236 STRUCT: test-struct-4 { x char[4] } ;
238 FUNCTION: test-struct-4 ffi_test_27 ;
240 [ S{ test-struct-4 { x char-array{ 1 2 3 4 } } } ] [ ffi_test_27 ] unit-test
242 STRUCT: test-struct-5 { x char[5] } ;
244 FUNCTION: test-struct-5 ffi_test_28 ;
246 [ S{ test-struct-5 { x char-array{ 1 2 3 4 5 } } } ] [ ffi_test_28 ] unit-test
248 STRUCT: test-struct-6 { x char[6] } ;
250 FUNCTION: test-struct-6 ffi_test_29 ;
252 [ S{ test-struct-6 { x char-array{ 1 2 3 4 5 6 } } } ] [ ffi_test_29 ] unit-test
254 STRUCT: test-struct-7 { x char[7] } ;
256 FUNCTION: test-struct-7 ffi_test_30 ;
258 [ S{ test-struct-7 { x char-array{ 1 2 3 4 5 6 7 } } } ] [ ffi_test_30 ] unit-test
260 STRUCT: test-struct-8 { x double } { y double } ;
262 FUNCTION: double ffi_test_32 test-struct-8 x int y ;
265 test-struct-8 <struct>
271 STRUCT: test-struct-9 { x float } { y float } ;
273 FUNCTION: double ffi_test_33 test-struct-9 x int y ;
276 test-struct-9 <struct>
282 STRUCT: test-struct-10 { x float } { y int } ;
284 FUNCTION: double ffi_test_34 test-struct-10 x int y ;
287 test-struct-10 <struct>
293 STRUCT: test-struct-11 { x int } { y int } ;
295 FUNCTION: double ffi_test_35 test-struct-11 x int y ;
298 test-struct-11 <struct>
304 STRUCT: test-struct-12 { a int } { x double } ;
306 : make-struct-12 ( x -- alien )
307 test-struct-12 <struct>
310 FUNCTION: double ffi_test_36 ( test-struct-12 x ) ;
312 [ 1.23456 ] [ 1.23456 make-struct-12 ffi_test_36 ] unit-test
314 FUNCTION: ulonglong ffi_test_38 ( ulonglong x, ulonglong y ) ;
316 [ t ] [ 31 2^ 32 2^ ffi_test_38 63 2^ = ] unit-test
320 : callback-1 ( -- callback ) void { } cdecl [ ] alien-callback ;
322 [ 0 1 ] [ [ callback-1 ] infer [ in>> length ] [ out>> length ] bi ] unit-test
324 [ t ] [ callback-1 alien? ] unit-test
326 : callback_test_1 ( ptr -- ) void { } cdecl alien-indirect ;
328 [ ] [ callback-1 callback_test_1 ] unit-test
330 : callback-2 ( -- callback ) void { } cdecl [ [ 5 throw ] ignore-errors ] alien-callback ;
332 [ ] [ callback-2 callback_test_1 ] unit-test
334 : callback-3 ( -- callback ) void { } cdecl [ 5 "x" set ] alien-callback ;
339 3 "x" set callback-3 callback_test_1
341 "x" get "x" get-global
345 : callback-5 ( -- callback )
346 void { } cdecl [ gc ] alien-callback ;
349 "testing" callback-5 callback_test_1
352 : callback-5b ( -- callback )
353 void { } cdecl [ compact-gc ] alien-callback ;
356 "testing" callback-5b callback_test_1
359 : callback-6 ( -- callback )
360 void { } cdecl [ [ continue ] callcc0 ] alien-callback ;
362 [ 1 2 3 ] [ callback-6 callback_test_1 1 2 3 ] unit-test
364 : callback-7 ( -- callback )
365 void { } cdecl [ 1000000 sleep ] alien-callback ;
367 [ 1 2 3 ] [ callback-7 callback_test_1 1 2 3 ] unit-test
369 [ f ] [ namespace global eq? ] unit-test
371 : callback-8 ( -- callback )
372 void { } cdecl [ [ ] in-thread yield ] alien-callback ;
374 [ ] [ callback-8 callback_test_1 ] unit-test
376 : callback-9 ( -- callback )
377 int { int int int } cdecl [
381 FUNCTION: void ffi_test_36_point_5 ( ) ;
383 [ ] [ ffi_test_36_point_5 ] unit-test
385 FUNCTION: int ffi_test_37 ( void* func ) ;
387 [ 1 ] [ callback-9 ffi_test_37 ] unit-test
389 [ 7 ] [ callback-9 ffi_test_37 ] unit-test
391 STRUCT: test_struct_13
399 : make-test-struct-13 ( -- alien )
400 test_struct_13 <struct>
408 FUNCTION: int ffi_test_39 ( long a, long b, test_struct_13 s ) ;
410 [ 21 ] [ 12347 12347 make-test-struct-13 ffi_test_39 ] unit-test
412 ! Joe Groff found this problem
419 : <double-rect> ( a b c d -- foo )
426 : >double-rect< ( foo -- a b c d )
434 : double-rect-callback ( -- alien )
435 void { void* void* double-rect } cdecl
436 [ "example" set-global 2drop ] alien-callback ;
438 : double-rect-test ( arg -- arg' )
441 void { void* void* double-rect } cdecl alien-indirect
442 "example" get-global ;
445 [ 1.0 2.0 3.0 4.0 <double-rect> double-rect-test >double-rect< ] unit-test
447 STRUCT: test_struct_14
451 FUNCTION: test_struct_14 ffi_test_40 ( double x1, double x2 ) ;
454 1.0 2.0 ffi_test_40 [ x1>> ] [ x2>> ] bi
457 : callback-10 ( -- callback )
458 test_struct_14 { double double } cdecl
460 test_struct_14 <struct>
465 : callback-10-test ( x1 x2 callback -- result )
466 test_struct_14 { double double } cdecl alien-indirect ;
469 1.0 2.0 callback-10 callback-10-test
473 FUNCTION: test-struct-12 ffi_test_41 ( int a, double x ) ;
480 : callback-11 ( -- callback )
481 test-struct-12 { int double } cdecl
483 test-struct-12 <struct>
488 : callback-11-test ( x1 x2 callback -- result )
489 test-struct-12 { int double } cdecl alien-indirect ;
492 1 2.0 callback-11 callback-11-test
496 STRUCT: test_struct_15
500 FUNCTION: test_struct_15 ffi_test_42 ( float x, float y ) ;
502 [ 1.0 2.0 ] [ 1.0 2.0 ffi_test_42 [ x>> ] [ y>> ] bi ] unit-test
504 : callback-12 ( -- callback )
505 test_struct_15 { float float } cdecl
507 test_struct_15 <struct>
512 : callback-12-test ( x1 x2 callback -- result )
513 test_struct_15 { float float } cdecl alien-indirect ;
516 1.0 2.0 callback-12 callback-12-test [ x>> ] [ y>> ] bi
519 STRUCT: test_struct_16
523 FUNCTION: test_struct_16 ffi_test_43 ( float x, int a ) ;
525 [ 1.0 2 ] [ 1.0 2 ffi_test_43 [ x>> ] [ a>> ] bi ] unit-test
527 : callback-13 ( -- callback )
528 test_struct_16 { float int } cdecl
530 test_struct_16 <struct>
535 : callback-13-test ( x1 x2 callback -- result )
536 test_struct_16 { float int } cdecl alien-indirect ;
539 1.0 2 callback-13 callback-13-test
543 FUNCTION: test_struct_14 ffi_test_44 ( ) ; inline
545 [ 1.0 2.0 ] [ ffi_test_44 [ x1>> ] [ x2>> ] bi ] unit-test
547 : stack-frame-bustage ( -- a b ) ffi_test_44 gc 3 ;
549 [ ] [ stack-frame-bustage 2drop ] unit-test
554 FUNCTION: complex-float ffi_test_45 ( int x ) ;
556 [ C{ 3.0 0.0 } ] [ 3 ffi_test_45 ] unit-test
558 FUNCTION: complex-double ffi_test_46 ( int x ) ;
560 [ C{ 3.0 0.0 } ] [ 3 ffi_test_46 ] unit-test
562 FUNCTION: complex-float ffi_test_47 ( complex-float x, complex-double y ) ;
566 C{ 1.5 1.0 } ffi_test_47
570 STRUCT: bool-field-test
575 FUNCTION: short ffi_test_48 ( bool-field-test x ) ;
578 bool-field-test <struct>
585 ! Test interaction between threads and callbacks
586 : thread-callback-1 ( -- callback )
587 int { } cdecl [ yield 100 ] alien-callback ;
589 : thread-callback-2 ( -- callback )
590 int { } cdecl [ yield 200 ] alien-callback ;
592 : thread-callback-invoker ( callback -- n )
593 int { } cdecl alien-indirect ;
596 [ thread-callback-1 thread-callback-invoker "p" get fulfill ] in-thread
597 [ 200 ] [ thread-callback-2 thread-callback-invoker ] unit-test
598 [ 100 ] [ "p" get ?promise ] unit-test
600 ! Regression: calling an undefined function would raise a protection fault
601 FUNCTION: void this_does_not_exist ( ) ;
603 [ this_does_not_exist ] [ { "kernel-error" 9 f f } = ] must-fail-with
605 ! More alien-assembly tests are in cpu.* vocabs
606 : assembly-test-1 ( -- ) void { } cdecl [ ] alien-assembly ;
608 [ ] [ assembly-test-1 ] unit-test
610 [ f ] [ "f-fastcall" load-library f = ] unit-test
611 [ fastcall ] [ "f-fastcall" library abi>> ] unit-test
613 : ffi_test_49 ( x -- int )
614 int "f-fastcall" "ffi_test_49" { int }
616 : ffi_test_50 ( x y -- int )
617 int "f-fastcall" "ffi_test_50" { int int }
619 : ffi_test_51 ( x y z -- int )
620 int "f-fastcall" "ffi_test_51" { int int int }
623 [ 4 ] [ 3 ffi_test_49 ] unit-test
624 [ 8 ] [ 3 4 ffi_test_50 ] unit-test
625 [ 13 ] [ 3 4 5 ffi_test_51 ] unit-test