diff --git a/src/c/Makefile.in b/src/c/Makefile.in index 9c3e6781f..550e616c6 100644 --- a/src/c/Makefile.in +++ b/src/c/Makefile.in @@ -47,7 +47,7 @@ OBJS = main.o symbol.o package.o list.o\ time.o unixint.o\ mapfun.o multival.o hash.o format.o pathname.o\ structure.o load.o unixfsys.o unixsys.o \ - all_symbols.o @EXTRA_OBJS@ + all_symbols.o ffi.o @EXTRA_OBJS@ .SUFFIXES: .c .o .d diff --git a/src/c/all_symbols.d b/src/c/all_symbols.d index b10ebcddd..8df43c799 100644 --- a/src/c/all_symbols.d +++ b/src/c/all_symbols.d @@ -1,6 +1,7 @@ #include #include "ecl.h" #include "internal.h" +#include #define CL_PACKAGE 0 #define SI_PACKAGE 4 diff --git a/src/c/alloc.d b/src/c/alloc.d index 664b128ef..72229ceb8 100644 --- a/src/c/alloc.d +++ b/src/c/alloc.d @@ -382,13 +382,11 @@ ONCE_MORE: obj->cblock.data_text_size = 0; obj->cblock.links = OBJNULL; break; -#ifdef ECL_FFI case t_foreign: obj->foreign.tag = Cnil; obj->foreign.size = 0; obj->foreign.data = NUL;; break; -#endif default: printf("\ttype = %d\n", t); error("alloc botch."); @@ -696,9 +694,7 @@ init_alloc(void) #else init_tm(t_instance, "IINSTANCE", sizeof(struct ecl_instance), 32); #endif /* CLOS */ -#ifdef ECL_FFI init_tm(t_foreign, "LFOREIGN", sizeof(struct ecl_foreign), 1); -#endif #ifdef ECL_THREADS init_tm(t_process, "tPROCESS", sizeof(struct ecl_process), 2); init_tm(t_process, "tLOCK", sizeof(struct ecl_lock), 2); diff --git a/src/c/alloc_2.d b/src/c/alloc_2.d index f8bf0dc02..2f82484eb 100644 --- a/src/c/alloc_2.d +++ b/src/c/alloc_2.d @@ -186,9 +186,7 @@ init_alloc(void) #else init_tm(t_instance, "INSTANCE", sizeof(struct ecl_instance)); #endif /* CLOS */ -#ifdef ECL_FFI - init_tm(t_instance, "FOREIGN", sizeof(struct ecl_foreign)); -#endif + init_tm(t_foreign, "FOREIGN", sizeof(struct ecl_foreign)); #ifdef ECL_THREADS init_tm(t_process, "PROCESS", sizeof(struct ecl_process)); init_tm(t_lock, "LOCK", sizeof(struct ecl_lock)); diff --git a/src/c/ffi.d b/src/c/ffi.d index 30bc756ed..a81a8ff93 100644 --- a/src/c/ffi.d +++ b/src/c/ffi.d @@ -14,7 +14,41 @@ #include "ecl.h" -#ifdef ECL_FFI +cl_object +ecl_make_foreign_data(cl_object tag, cl_index size, void *data) +{ + cl_object output = cl_alloc_object(t_foreign); + output->foreign.tag = tag == Cnil ? @':void' : tag; + output->foreign.size = size; + output->foreign.data = (char*)data; + return output; +} + +cl_object +ecl_allocate_foreign_data(cl_object tag, cl_index size) +{ + cl_object output = cl_alloc_object(t_foreign); + output->foreign.tag = tag; + output->foreign.size = size; + output->foreign.data = (char*)cl_alloc_atomic(size); + return output; +} + +void * +ecl_foreign_data_pointer_safe(cl_object f) +{ + if (type_of(f) != t_foreign) + FEwrong_type_argument(@'si::foreign-data', f); + return f->foreign.data; +} + +char * +ecl_string_pointer_safe(cl_object f) +{ + if (type_of(f) != t_string) + FEwrong_type_argument(@'string', f); + return f->string.self; +} cl_object si_allocate_foreign_data(cl_object tag, cl_object size) @@ -30,40 +64,274 @@ si_allocate_foreign_data(cl_object tag, cl_object size) cl_object si_free_foreign_data(cl_object f) { - if (type_of(f) != t_foreign) + if (type_of(f) != t_foreign) { FEwrong_type_argument(@'si::foreign-data', f); - if (f->foreign.size) + } + if (f->foreign.size) { cl_dealloc(f->foreign.data, f->foreign.size); + } f->foreign.size = 0; f->foreign.data = NULL; } +cl_object +si_foreign_data_address(cl_object f) +{ + if (type_of(f) != t_foreign) { + FEwrong_type_argument(@'si::foreign-data', f); + } + @(return make_unsigned_integer((cl_index)f->foreign.data)) +} + cl_object si_foreign_data_tag(cl_object f) { - if (type_of(f) != t_foreign) + if (type_of(f) != t_foreign) { FEwrong_type_argument(@'si::foreign-data', f); + } @(return f->foreign.tag); } cl_object -ecl_make_foreign_data(cl_object tag, cl_index size, void *data) +si_foreign_data_pointer(cl_object f, cl_object andx, cl_object asize, + cl_object tag) { - cl_object output = cl_alloc_object(t_foreign); + cl_index ndx = fixnnint(andx); + cl_index size = fixnnint(asize); + cl_object output; + + if (type_of(f) != t_foreign) { + FEwrong_type_argument(@'si::foreign-data', f); + } + if (ndx >= f->foreign.size || (f->foreign.size - ndx) < size) { + FEerror("Out of bounds reference into foreign data type ~A.", 1, f); + } + output = cl_alloc_object(t_foreign); output->foreign.tag = tag; output->foreign.size = size; - output->foreign.data = (char*)data; - return output; + output->foreign.data = f->foreign.data + ndx; + @(return output) } -void * -ecl_foreign_data_pointer_safe(cl_object f, cl_object tag) +cl_object +si_foreign_data_ref(cl_object f, cl_object andx, cl_object asize, cl_object tag) +{ + cl_index ndx = fixnnint(andx); + cl_index size = fixnnint(asize); + cl_object output; + + if (type_of(f) != t_foreign) { + FEwrong_type_argument(@'si::foreign-data', f); + } + if (ndx >= f->foreign.size || (f->foreign.size - ndx) < size) { + FEerror("Out of bounds reference into foreign data type ~A.", 1, f); + } + output = ecl_allocate_foreign_data(tag, size); + memcpy(output->foreign.data, f->foreign.data + ndx, size); + @(return output) +} + +cl_object +si_foreign_data_set(cl_object f, cl_object andx, cl_object value) +{ + cl_index ndx = fixnnint(andx); + cl_index size, limit; + cl_object output; + + if (type_of(f) != t_foreign) { + FEwrong_type_argument(@'si::foreign-data', f); + } + if (type_of(value) != t_foreign) { + FEwrong_type_argument(@'si::foreign-data', value); + } + size = value->foreign.size; + limit = f->foreign.size; + if (ndx >= limit || (limit - ndx) < size) { + FEerror("Out of bounds reference into foreign data type ~A.", 1, f); + } + memcpy(f->foreign.data + ndx, value->foreign.data, size); + @(return value) +} + +cl_object +si_foreign_data_ref_elt(cl_object f, cl_object andx, cl_object tag) +{ + cl_object output; + cl_index ndx = fixnnint(andx); + cl_index limit = f->foreign.size; + void *p; + + if (type_of(f) != t_foreign) { + FEwrong_type_argument(@'si::foreign-data', f); + } + if (ndx >= limit) { + ERROR: FEerror("Out of bounds reference into foreign data type ~A.", 1, f); + } + p = (void*)(f->foreign.data + ndx); + if (tag == @':byte') { + if (ndx + sizeof(int8_t) > limit) goto ERROR; + output = MAKE_FIXNUM(*(int8_t *)p); + } else if (tag == @':unsigned-byte') { + if (ndx + sizeof(uint8_t) > limit) goto ERROR; + output = MAKE_FIXNUM(*(uint8_t *)p); + } else if (tag == @':char') { + if (ndx + sizeof(char) > limit) goto ERROR; + output = CODE_CHAR(*(char *)p); + } else if (tag == @':unsigned-char') { + if (ndx + sizeof(unsigned char) > limit) goto ERROR; + output = CODE_CHAR(*(unsigned char *)p); + } else if (tag == @':short') { + if (ndx + sizeof(short) > limit) goto ERROR; + output = MAKE_FIXNUM(*(short *)p); + } else if (tag == @':unsigned-short') { + if (ndx + sizeof(unsigned short) > limit) goto ERROR; + output = MAKE_FIXNUM(*(unsigned short *)p); + } else if (tag == @':int') { + if (ndx + sizeof(int) > limit) goto ERROR; + output = MAKE_FIXNUM(*(int *)p); + } else if (tag == @':unsigned-int') { + if (ndx + sizeof(unsigned int) > limit) goto ERROR; + output = MAKE_FIXNUM(*(unsigned int *)p); + } else if (tag == @':long') { + if (ndx + sizeof(long) > limit) goto ERROR; + output = MAKE_FIXNUM(*(long *)p); + } else if (tag == @':unsigned-long') { + if (ndx + sizeof(unsigned long) > limit) goto ERROR; + output = MAKE_FIXNUM(*(unsigned long *)p); + } else if (tag == @':pointer-void') { + if (ndx + sizeof(void *) > limit) goto ERROR; + output = ecl_make_foreign_data(@':pointer-void', 0, *(void **)p); + } else if (tag == @':object') { + if (ndx + sizeof(cl_object) > limit) goto ERROR; + output = *(cl_object *)p; + } else if (tag == @':float') { + if (ndx + sizeof(float) > limit) goto ERROR; + output = make_shortfloat(*(float *)p); + } else if (tag == @':double') { + if (ndx + sizeof(double) > limit) goto ERROR; + output = make_longfloat(*(double *)p); + } else { + FEerror("~A does not denote a foreign type.", 1, tag); + } + @(return output) +} + +cl_object +si_foreign_data_set_elt(cl_object f, cl_object andx, cl_object tag, cl_object value) +{ + cl_object output; + cl_index ndx = fixnnint(andx); + cl_index limit = f->foreign.size; + void *p; + + if (type_of(f) != t_foreign) { + FEwrong_type_argument(@'si::foreign-data', f); + } + if (ndx >= limit) { + ERROR: FEerror("Out of bounds reference into foreign data type ~A.", 1, f); + } + p = (void*)(f->foreign.data + ndx); + if (tag == @':byte') { + if (ndx + sizeof(int8_t) > limit) goto ERROR; + *(int8_t *)p = fixint(value); + } else if (tag == @':unsigned-byte') { + if (ndx + sizeof(uint8_t) > limit) goto ERROR; + *(uint8_t *)p = fixnnint(value); + } else if (tag == @':char') { + if (ndx + sizeof(char) > limit) goto ERROR; + *(char *)p = char_code(value); + } else if (tag == @':unsigned-char') { + if (ndx + sizeof(unsigned char) > limit) goto ERROR; + *(unsigned char*)p = char_code(value); + } else if (tag == @':short') { + if (ndx + sizeof(short) > limit) goto ERROR; + *(short *)p = fixint(value); + } else if (tag == @':unsigned-short') { + if (ndx + sizeof(unsigned short) > limit) goto ERROR; + *(unsigned short *)p = fixnnint(value); + } else if (tag == @':int') { + if (ndx + sizeof(int) > limit) goto ERROR; + *(int *)p = fixint(value); + } else if (tag == @':unsigned-int') { + if (ndx + sizeof(unsigned int) > limit) goto ERROR; + *(unsigned int *)p = fixnnint(value); + } else if (tag == @':long') { + if (ndx + sizeof(long) > limit) goto ERROR; + *(long *)p = fixint(value); + } else if (tag == @':unsigned-long') { + if (ndx + sizeof(unsigned long) > limit) goto ERROR; + *(unsigned long *)p = fixnnint(value); + } else if (tag == @':pointer-void') { + if (ndx + sizeof(void *) > limit) goto ERROR; + *(void **)p = ecl_foreign_data_pointer_safe(value); + } else if (tag == @':object') { + if (ndx + sizeof(cl_object) > limit) goto ERROR; + *(cl_object *)p = value; + } else if (tag == @':float') { + if (ndx + sizeof(float) > limit) goto ERROR; + *(float *)p = object_to_float(value); + } else if (tag == @':double') { + if (ndx + sizeof(double) > limit) goto ERROR; + *(double *)p = object_to_double(value); + } else { + FEerror("~A does not denote a foreign type.", 1, tag); + } + @(return output) +} + +cl_object +si_size_of_foreign_elt_type(cl_object tag) +{ + cl_fixnum size; + + if (tag == @':byte') { + size = sizeof(int8_t); + } else if (tag == @':unsigned-byte') { + size = sizeof(uint8_t); + } else if (tag == @':char') { + size = sizeof(char); + } else if (tag == @':unsigned-char') { + size = sizeof(unsigned char); + } else if (tag == @':short') { + size = sizeof(short); + } else if (tag == @':unsigned-short') { + size = sizeof(unsigned short); + } else if (tag == @':int') { + size = sizeof(int); + } else if (tag == @':unsigned-int') { + size = sizeof(unsigned int); + } else if (tag == @':long') { + size = sizeof(long); + } else if (tag == @':unsigned-long') { + size = sizeof(unsigned long); + } else if (tag == @':pointer-void') { + size = sizeof(void *); + } else if (tag == @':object') { + size = sizeof(cl_object); + } else if (tag == @':float') { + size = sizeof(float); + } else if (tag == @':double') { + size = sizeof(double); + } else { + FEerror("~A does not denote a foreign type.", 1, tag); + } + @(return MAKE_FIXNUM(size)) +} + +cl_object +si_null_pointer_p(cl_object f) { if (type_of(f) != t_foreign) FEwrong_type_argument(@'si::foreign-data', f); - if (f->foreign.tag != tag) - FEwrong_type_argument(cl_list(2, @'si::foreign-data', tag), f); - return f->foreign.data; + @(return ((f->foreign.data == NULL)? Ct : Cnil)) } -#endif /* ECL_FFI */ +cl_object +si_foreign_data_recast(cl_object f, cl_object size, cl_object tag) +{ + if (type_of(f) != t_foreign) + FEwrong_type_argument(@'si::foreign-data', f); + f->foreign.size = fixnnint(size); + f->foreign.tag = tag; + @(return f) +} diff --git a/src/c/gbc.d b/src/c/gbc.d index f30074664..4b0d66ea4 100644 --- a/src/c/gbc.d +++ b/src/c/gbc.d @@ -375,13 +375,11 @@ BEGIN: i = x->cblock.data_size; p = x->cblock.data; goto MARK_DATA; -#ifdef ECL_FFI case t_foreign: if (x->foreign.size) mark_contblock(x->foreign.data, x->foreign.size); mark_next(x->foreign.tag); break; -#endif /* ECL_FFI */ MARK_DATA: if (p) { mark_contblock(p, i * sizeof(cl_object)); diff --git a/src/c/instance.d b/src/c/instance.d index fff16bd5a..adc0a3d79 100644 --- a/src/c/instance.d +++ b/src/c/instance.d @@ -260,10 +260,8 @@ cl_class_of(cl_object x) case t_cfun: case t_cclosure: t = @'function'; break; -#ifdef ECL_FFI case t_foreign: t = @'si::foreign-data'; break; -#endif #ifdef ECL_THREADS case t_process: t = @'mp::process'; break; diff --git a/src/c/main.d b/src/c/main.d index e53fdb80b..8f7a1ff6e 100644 --- a/src/c/main.d +++ b/src/c/main.d @@ -311,7 +311,8 @@ cl_boot(int argc, char **argv) make_keyword("COMMON"), make_keyword("ANSI-CL"), make_keyword("COMMON-LISP"), - make_keyword(ECL_ARCHITECTURE)); + make_keyword(ECL_ARCHITECTURE), + make_keyword("FFI")); #define ADD_FEATURE(name) features = CONS(make_keyword(name),features) @@ -333,9 +334,6 @@ cl_boot(int argc, char **argv) #ifdef PDE ADD_FEATURE("PDE"); #endif -#ifdef ECL_FFI - ADD_FEATURE("FFI"); -#endif #ifdef unix ADD_FEATURE("UNIX"); #endif diff --git a/src/c/predicate.d b/src/c/predicate.d index 98abb0b9b..ccf421d86 100644 --- a/src/c/predicate.d +++ b/src/c/predicate.d @@ -340,6 +340,9 @@ BEGIN: equal(x->pathname.type, y->pathname.type) && equal(x->pathname.version, y->pathname.version)); + case t_foreign: + return (x->foreign.data == y->foreign.data); + default: return(eql(x,y)); } diff --git a/src/c/print.d b/src/c/print.d index 176f8fa02..35e1b13c3 100644 --- a/src/c/print.d +++ b/src/c/print.d @@ -1152,7 +1152,6 @@ _write_object(cl_object x, int level) call_print_object(x, level); break; #endif /* CLOS */ -#ifdef ECL_FFI case t_foreign: if (cl_env.print_readably) FEprint_not_readable(x); write_str("#foreign.data); write_ch('>'); break; -#endif /* ECL_FFI */ #ifdef ECL_THREADS case t_process: if (cl_env.print_readably) FEprint_not_readable(x); diff --git a/src/c/symbols_list.h b/src/c/symbols_list.h index d42a4d1b2..fb7a9a73c 100644 --- a/src/c/symbols_list.h +++ b/src/c/symbols_list.h @@ -1351,12 +1351,51 @@ cl_symbols[] = { {EXT_ "INSTANCE", EXT_ORDINARY, NULL, -1, OBJNULL}, #endif -#ifdef ECL_FFI {SYS_ "ALLOCATE-FOREIGN-DATA", SI_ORDINARY, si_allocate_foreign_data, 2, OBJNULL}, {SYS_ "FOREIGN-DATA", SI_ORDINARY, NULL, -1, OBJNULL}, +{SYS_ "FOREIGN-DATA-ADDRESS", SI_ORDINARY, si_foreign_data_address, 1, OBJNULL}, +{SYS_ "FOREIGN-DATA-POINTER", SI_ORDINARY, si_foreign_data_pointer, 4, OBJNULL}, +{SYS_ "FOREIGN-DATA-RECAST", SI_ORDINARY, si_foreign_data_recast, 3, OBJNULL}, +{SYS_ "FOREIGN-DATA-REF", SI_ORDINARY, si_foreign_data_ref, 4, OBJNULL}, +{SYS_ "FOREIGN-DATA-REF-ELT", SI_ORDINARY, si_foreign_data_ref_elt, 3, OBJNULL}, +{SYS_ "FOREIGN-DATA-SET", SI_ORDINARY, si_foreign_data_set, 3, OBJNULL}, +{SYS_ "FOREIGN-DATA-SET-ELT", SI_ORDINARY, si_foreign_data_set_elt, 4, OBJNULL}, {SYS_ "FOREIGN-DATA-TAG", SI_ORDINARY, si_foreign_data_tag, 1, OBJNULL}, {SYS_ "FREE-FOREIGN-DATA", SI_ORDINARY, si_free_foreign_data, 1, OBJNULL}, -#endif +{SYS_ "NULL-POINTER-P", SI_ORDINARY, si_null_pointer_p, 1, OBJNULL}, +{SYS_ "SIZE-OF-FOREIGN-ELT-TYPE", SI_ORDINARY, si_size_of_foreign_elt_type, 1, OBJNULL}, +{KEY_ "ARRAY", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "BYTE", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "CHAR", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "DOUBLE", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "FIXNUM", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "FLOAT", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "INT", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "LONG", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "POINTER-SELF", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "POINTER-VOID", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "SHORT", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "STRUCT", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "UNION", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "VOID", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "UNSIGNED-BYTE", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "UNSIGNED-CHAR", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "UNSIGNED-INT", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "UNSIGNED-LONG", KEYWORD, NULL, -1, OBJNULL}, +{KEY_ "UNSIGNED-SHORT", KEYWORD, NULL, -1, OBJNULL}, +{SYS_ "C-CHAR-BIT", SI_CONSTANT, NULL, -1, MAKE_FIXNUM(CHAR_BIT)}, +{SYS_ "C-CHAR-MAX", SI_CONSTANT, NULL, -1, MAKE_FIXNUM(CHAR_MAX)}, +{SYS_ "C-CHAR-MIN", SI_CONSTANT, NULL, -1, MAKE_FIXNUM(CHAR_MIN)}, +{SYS_ "C-INT-MAX", SI_CONSTANT, NULL, -1, MAKE_FIXNUM(INT_MAX)}, +{SYS_ "C-INT-MIN", SI_CONSTANT, NULL, -1, MAKE_FIXNUM(INT_MIN)}, +{SYS_ "C-SHORT-MAX", SI_CONSTANT, NULL, -1, MAKE_FIXNUM(SHRT_MAX)}, +{SYS_ "C-SHORT-MIN", SI_CONSTANT, NULL, -1, MAKE_FIXNUM(SHRT_MIN)}, +{SYS_ "C-LONG-MAX", SI_CONSTANT, NULL, -1, MAKE_FIXNUM(LONG_MAX)}, +{SYS_ "C-LONG-MIN", SI_CONSTANT, NULL, -1, MAKE_FIXNUM(LONG_MAX)}, +{SYS_ "C-UCHAR-MAX", SI_CONSTANT, NULL, -1, MAKE_FIXNUM(UCHAR_MAX)}, +{SYS_ "C-UINT-MAX", SI_CONSTANT, NULL, -1, MAKE_FIXNUM(UINT_MAX)}, +{SYS_ "C-USHORT-MAX", SI_CONSTANT, NULL, -1, MAKE_FIXNUM(USHRT_MAX)}, +{SYS_ "C-ULONG-MAX", SI_CONSTANT, NULL, -1, MAKE_FIXNUM(ULONG_MAX)}, #ifdef GBC_BOEHM {SYS_ "GC", SI_ORDINARY, si_gc, 1, OBJNULL}, diff --git a/src/c/typespec.d b/src/c/typespec.d index 48b4055f6..105611ca2 100644 --- a/src/c/typespec.d +++ b/src/c/typespec.d @@ -346,10 +346,8 @@ cl_type_of(cl_object x) case t_cclosure: t = @'function'; break; -#ifdef ECL_FFI case t_foreign: t = @'si::foreign-data'; break; -#endif #ifdef ECL_THREADS case t_process: t = @'mp::process'; break; diff --git a/src/cmp/cmpcall.lsp b/src/cmp/cmpcall.lsp index 0e9ec1d80..1cf110677 100644 --- a/src/cmp/cmpcall.lsp +++ b/src/cmp/cmpcall.lsp @@ -271,7 +271,7 @@ (defun call-loc-fixed (fname fun args narg-loc maxarg) (cond ((not (eq 'ARGS-PUSHED args)) (when (/= (length args) maxarg) - (error "Too many arguments to function ~S." fname)) + (cmperr "Wrong number of arguments to function ~S." fname)) (list 'CALL-FIX fun (coerce-locs args) fname)) ((stringp fun) (wt "if(" narg-loc "!=" maxarg ") FEwrong_num_arguments_anonym();") diff --git a/src/cmp/cmpffi.lsp b/src/cmp/cmpffi.lsp index 5e5eb9c46..5fb0e39cc 100644 --- a/src/cmp/cmpffi.lsp +++ b/src/cmp/cmpffi.lsp @@ -16,26 +16,38 @@ ;; (defconstant +representation-types+ - '(:byte ((signed-byte 8) "byte") + '(;; These types can be used by ECL to unbox data + ;; They are sorted from the most specific, to the least specific one. + :byte ((signed-byte 8) "byte") :unsigned-byte ((unsigned-byte 8) "unsigned byte") :fixnum (fixnum "cl_fixnum") - :int ((signed-byte 32) "int") - :unsigned-int ((unsigned-byte 32) "unsigned int") - :long ((signed-byte 32) "long") - :unsigned-long ((unsigned-byte 32) "unsigned long") + :int ((integer #.si:c-int-min #.si:c-int-max) "int") + :unsigned-int ((integer 0 #.si:c-uint-max) "unsigned int") + :long ((integer #.si:c-long-min #.si:c-long-max) "long") + :unsigned-long ((integer 0 #.si:c-ulong-max) "unsigned long") :cl-index ((integer 0 #.most-positive-fixnum) "cl_index") :float (short-float "float") :double (long-float "double") :char (character "char") :unsigned-char (character "char") - :void (nil "void") :object (t "cl_object") - :bool (t "bool"))) + :bool (t "bool") + ;; These types are never selected to unbox data. + ;; They are here, because we need to know how to print them. + :void (nil "void") + :pointer-void (nil "void*") + :cstring (nil "char*") + :short ((integer #.si:c-short-min #.si:c-short-max) "short") + :unsigned-short ((integer 0 #.si:c-short-max) "unsigned short") + )) (defun rep-type->lisp-type (rep-type) (let ((output (getf +representation-types+ rep-type))) - (cond (output (first output)) + (cond (output + (or (first output) + (error "Representation type ~S cannot be coerced to lisp" + rep-type))) ((lisp-type-p rep-type) rep-type) (t (error "Unknown representation type ~S" rep-type))))) @@ -49,7 +61,7 @@ (defun rep-type-name (type) (or (second (getf +representation-types+ type)) - (error "Unknown type name ~S found in compiled expression" type))) + (error "Not a valid type name ~S" type))) (defun lisp-type-p (type) (subtypep type 'T)) @@ -179,8 +191,31 @@ (wt "((" loc ")?Ct:Cnil)")) ((:char :unsigned-char) (wt "CODE_CHAR(" loc ")")) + ((:cstring) + (wt "make_string_copy(" loc ")")) + ((:pointer-void) + (wt "ecl_make_foreign_data(Cnil, 0, " loc ")")) (otherwise (coercion-error)))) + ((:pointer-void) + (case loc-rep-type + ((:object) + ;; Only foreign data types can be coerced to a pointer + (wt "ecl_foreign_data_pointer_safe(" loc ")")) + ((:cstring) + (wt "(char *)(" loc ")")) + (otherwise + (coercion-error)))) + ((:cstring) + (case loc-rep-type + ((:object) + (if (safe-compile) + (wt "ecl_string_pointer_safe(" loc ")") + (wt "(" loc ")->string.self"))) + ((:pointer-void) + (wt "(char *)(" loc ")")) + (otherwise + (coercion error)))) (t (coercion-error)))))) @@ -190,8 +225,9 @@ ;; (defun c1c-inline (args) + ;; We are on the safe side by assuming that the form has side effects (destructuring-bind (arguments arg-types output-type c-expression - &key side-effects one-liner + &key (side-effects t) one-liner &aux output-rep-type) args (if (lisp-type-p output-type) @@ -307,9 +343,8 @@ (wt (add-object object)))))) (#\# (let* ((k (char-downcase (read-char s))) - (index (- (char-code k) - (char-code (if (char<= #\0 k #\9) #\0 #\a))))) - (when (or (< index 0) (>= index (length coerced-arguments))) + (index (digit-char-p k 36))) + (unless (and index (< index (length coerced-arguments))) (cmperr "C-INLINE: Variable code exceeds number of arguments")) (wt (nth index coerced-arguments)))) (otherwise diff --git a/src/configure b/src/configure index 819ae011e..ea7d4b905 100755 --- a/src/configure +++ b/src/configure @@ -873,7 +873,6 @@ Optional Packages: --with-oldloop Use the old MIT LOOP macro. --with-cmuformat Use the FORMAT routine from CMUCL. --with-clos-streams Allow user defined stream objects. ---with-ffi Run-time foreign data manipulation. --with-cxx Build ECL using C++ compiler. --with-x use the X Window System @@ -1477,12 +1476,6 @@ if test "${with_clos_streams+set}" = set; then closstreams="yes" fi; -# Check whether --with-ffi or --without-ffi was given. -if test "${with_ffi+set}" = set; then - withval="$with_ffi" - ffi="yes" -fi; - # Check whether --with-cxx or --without-cxx was given. if test "${with_cxx+set}" = set; then withval="$with_cxx" @@ -4400,13 +4393,6 @@ if test "${closstreams}"; then #define ECL_CLOS_STREAMS 1 _ACEOF -fi -if test "${ffi}"; then - cat >>confdefs.h <<\_ACEOF -#define ECL_FFI 1 -_ACEOF - - EXTRA_OBJS="${EXTRA_OBJS} ffi.${OBJEXT}" fi if test "${locative}" ; then EXTRA_OBJS="${EXTRA_OBJS} unify.${OBJEXT}" diff --git a/src/configure.in b/src/configure.in index bff101796..f943368a0 100644 --- a/src/configure.in +++ b/src/configure.in @@ -93,9 +93,6 @@ AC_ARG_WITH(cmuformat, AC_ARG_WITH(clos-streams, [--with-clos-streams Allow user defined stream objects.], closstreams="yes") -AC_ARG_WITH(ffi, - [--with-ffi Run-time foreign data manipulation.], - ffi="yes") AC_ARG_WITH(cxx, [--with-cxx Build ECL using C++ compiler.], usecxx="${withval}",usecxx="no") @@ -241,10 +238,6 @@ fi if test "${closstreams}"; then AC_DEFINE(ECL_CLOS_STREAMS) fi -if test "${ffi}"; then - AC_DEFINE(ECL_FFI) - EXTRA_OBJS="${EXTRA_OBJS} ffi.${OBJEXT}" -fi if test "${locative}" ; then EXTRA_OBJS="${EXTRA_OBJS} unify.${OBJEXT}" AC_DEFINE(LOCATIVE) diff --git a/src/eclx/eclx.lisp b/src/eclx/eclx.lisp deleted file mode 100644 index 7f467f7e0..000000000 --- a/src/eclx/eclx.lisp +++ /dev/null @@ -1,49 +0,0 @@ -;;; -*- Mode: Lisp; Package: USER; Base: 10; Syntax: Common-Lisp -*- - -(in-package "COMMON-LISP-USER") - -(load "sys:cmp.so") - -;;; Aid function: - -(defvar *only-load* nil) - -;;; Then compile and load the true system: - -(proclaim '(optimize (safety 2) (speed 1))) - -(let* ((files (list - "split-sequence" - "package" - "depdefs" - "clx" - "dependent" - "macros" ; these are just macros - "bufmac" ; these are just macros - "buffer" - "display" - "gcontext" - "input" - "requests" - "fonts" - "graphics" - "text" - "attributes" - "translate" - "keysyms" - "manager" - "image" - "resource")) - (objects (mapcar #'(lambda (x) - (load (setq x (merge-pathnames ".lisp" x))) - (unless *only-load* - (compile-file x :system-p t))) - files))) - (unless *only-load* - #-dlopen - (c::build-static-library "eclx" :lisp-files objects) - #+dlopen - (c::build-shared-library "eclx" :lisp-files objects))) - -;(load "clx2/demo/hello.lisp") -;(xlib::hello-world "") diff --git a/src/h/external.h b/src/h/external.h index 337745c41..118b8b951 100644 --- a/src/h/external.h +++ b/src/h/external.h @@ -475,13 +475,23 @@ extern cl_object cl_safe_eval(cl_object form, cl_object env, cl_object err_value /* ffi.c */ -#ifdef ECL_FFI extern cl_object si_allocate_foreign_data(cl_object tag, cl_object size); -extern cl_object si_free_foreign_data(cl_object x); +extern cl_object si_foreign_data_address(cl_object f); +extern cl_object si_foreign_data_pointer(cl_object f, cl_object ndx, cl_object size, cl_object tag); +extern cl_object si_foreign_data_ref(cl_object f, cl_object ndx, cl_object size, cl_object tag); +extern cl_object si_foreign_data_ref_elt(cl_object f, cl_object ndx, cl_object tag); +extern cl_object si_foreign_data_set(cl_object f, cl_object ndx, cl_object value); +extern cl_object si_foreign_data_set_elt(cl_object f, cl_object ndx, cl_object tag, cl_object value); extern cl_object si_foreign_data_tag(cl_object x); +extern cl_object si_foreign_data_recast(cl_object f, cl_object size, cl_object tag); +extern cl_object si_free_foreign_data(cl_object x); +extern cl_object si_null_pointer_p(cl_object f); +extern cl_object si_size_of_foreign_elt_type(cl_object tag); + extern cl_object ecl_make_foreign_data(cl_object tag, cl_index size, void *data); -extern void *ecl_foreign_data_pointer_safe(cl_object f, cl_object tag); -#endif +extern cl_object ecl_allocate_foreign_data(cl_object tag, cl_index size); +extern void *ecl_foreign_data_pointer_safe(cl_object f); +extern char *ecl_string_pointer_safe(cl_object f); /* file.c */ diff --git a/src/h/object.h b/src/h/object.h index 73adf49d0..9b6f2ec3e 100644 --- a/src/h/object.h +++ b/src/h/object.h @@ -392,14 +392,12 @@ struct ecl_cclosure { /* compiled closure header */ cl_object block; /* descriptor of C code block for GC */ }; -#ifdef ECL_FFI struct ecl_foreign { /* user defined datatype */ HEADER; cl_object tag; /* a tag identifying the type */ cl_index size; /* the amount of memory allocated */ char *data; /* the data itself */ }; -#endif /* dummy type @@ -478,9 +476,7 @@ union cl_lispunion { struct ecl_lock lock; /* lock */ #endif struct ecl_codeblock cblock; /* codeblock */ -#ifdef ECL_FFI struct ecl_foreign foreign; /* user defined data type */ -#endif }; /* @@ -522,9 +518,7 @@ typedef enum { t_lock, #endif t_codeblock, /* 21 */ -#ifdef ECL_FFI t_foreign, /* 22 */ -#endif t_end, t_other, t_contiguous, /* contiguous block */ diff --git a/src/lsp/autoload.lsp b/src/lsp/autoload.lsp index b05cfece7..d646ddf89 100644 --- a/src/lsp/autoload.lsp +++ b/src/lsp/autoload.lsp @@ -114,7 +114,7 @@ number is zero. The optional X is simply ignored." bytecodes cfun cclosure #-clos structure #+clos instance #+clos generic-function #+threads mp::process #+threads mp::lock - #+ffi si::foreign)) + si::foreign)) (tl type-list (cdr tl)) (i 0 (+ i (if (nth 2 l) (nth 2 l) 0)))) ((null l) (setq npage i)) diff --git a/src/lsp/evalmacros.lsp b/src/lsp/evalmacros.lsp index 503d2a70e..d0f1a63f1 100644 --- a/src/lsp/evalmacros.lsp +++ b/src/lsp/evalmacros.lsp @@ -23,7 +23,11 @@ The complete syntax of a lambda-list is: The doc-string DOC, if supplied, is saved as a FUNCTION doc and can be retrieved by (documentation 'NAME 'function)." (multiple-value-setq (body doc-string) (remove-documentation body)) - (let* ((function `#'(ext::lambda-block ,name ,vl ,@body))) + (let* ((block-name (if (and (consp name) + (eq (first name) 'setf)) + (second name) + name)) + (function `#'(ext::lambda-block ,block-name ,vl ,@body))) (when *dump-defun-definitions* (print function) (setq function `(si::bc-disassemble ,function))) @@ -82,9 +86,6 @@ as a VARIABLE doc and can be retrieved by (documentation 'NAME 'variable)." `(PROGN (SYS:*MAKE-SPECIAL ',var) ,@(si::expand-set-documentation var 'variable doc-string) (SETQ ,var ,form) - (EVAL-WHEN (COMPILE) ; Beppe - (WHEN ,(CONSTANTP form) - (PROCLAIM '(TYPE ,(type-of form) ,var)))) ; (eval-when (load eval) ; Beppe ; (compiler::proclaim-var (type-of ,var) ',var)) #+PDE (SYS:RECORD-SOURCE-PATHNAME ',var 'DEFPARAMETER) diff --git a/src/lsp/ffi-objects.lsp b/src/lsp/ffi-objects.lsp deleted file mode 100644 index 8d97e511a..000000000 --- a/src/lsp/ffi-objects.lsp +++ /dev/null @@ -1,112 +0,0 @@ -;;;; Copyright (c) 2001, Juan Jose Garcia-Ripoll -;;;; -;;;; This program is free software; you can redistribute it and/or -;;;; modify it under the terms of the GNU Library General Public -;;;; License as published by the Free Software Foundation; either -;;;; version 2 of the License, or (at your option) any later version. -;;;; -;;;; See file '../Copyright' for full details. - -;;;; Routines to handle foreign objects, structures, arrays, etc. - -(in-package "FFI") - -;; ---------------------------------------------------------------------- -;; OPERATIONS WITH FOREIGN TYPES -;; - -(defmacro def-foreign-type (name type) - `(si::set-sysprop ',name 'FOREIGN-TYPE ',type)) - -(defun basic-foreign-type-size (type) - (case type - ((:unsigned-char :char :byte :unsigned-byte) 1) - ((:short :unsigned-short) 2) - ((:int :unsigned-int) 4) - ((:long :unsigned-long) 4) - ((:float) 4) - ((:double) 8) - ((:pointer-void) 4) - (:void 0) - (t (error-foreign-type type)))) - -(defun error-foreign-type (type) - (error 'simple-type-error - :format-control "~S is not a valid foreign type" - :format-args (list type) - :datum type - :expected-type 'FOREIGN-TYPE)) - -(defun compute-foreign-type-size (type &aux name args) - (if (symbolp type) - (if (setq args (si::get-sysprop type 'FOREIGN-TYPE)) - (compute-foreign-type-size type) - (basic-foreign-type-size type)) - (case (first type) - (* (basic-foreign-type-size :pointer-void)) - (:struct - (reduce #'+ (rest type) :key #'second :initial-value 0)) - (:union - (reduce #'max (rest type) :initial-value 0)) - (:enum - (basic-foreign-type-size :int)) - (:array - (let ((elt-type-size (compute-foreign-type-size (second type)))) - (unless (integerp (third type)) - (error-foreign-type type)) - (* elt-type-size (third type))))))) - -;; ---------------------------------------------------------------------- -;; ENUMERATIONS -;; - -(defmacro def-enum (enum-name &optional keys &key (separator-string "#")) - (let ((counter 0) - (output '()) - (name)) - (dolist (i keys) - (cond ((symbolp i) (setq name i)) - ((listp i) (setq name (first i) counter (second i)))) - (unless (and (symbolp name) (integerp counter)) - (error "~S is not a valid enumeration key" (list name counter))) - (setq name (intern (concatenate 'string - (symbol-name enum-name) - separator-string - (symbol-name name)))) - (push (list name counter) output) - (incf counter)) - `(progn - (def-foreign-type ,enum-name (ENUM ,@output)) - ,@(mapcar #'(lambda (x) (cons 'DEFCONSTANT x)) output)))) - -;; ---------------------------------------------------------------------- -;; ARRAYS -;; - -(defmacro def-array (name elt-type) - `(def-foreign-type ,name (:array ,elt-type))) - -;; ---------------------------------------------------------------------- -;; UTILITIES -;; - -(defun null-char-p (char) - (or (eql char 0) - (eql char (code-char 0)))) - -(defun ensure-char-character (char) - (cond ((integerp char) - (code-char char)) - ((characterp char) - char) - (t - (error 'simple-type-error :datum char :expected-type 'character)))) - -(defun ensure-char-integer (char) - (cond ((integerp char) - char) - ((characterp char) - (char-code char)) - (t - (error 'simple-type-error :datum char :expected-type 'character)))) - diff --git a/src/lsp/ffi.lsp b/src/lsp/ffi.lsp index 50889e372..41273c962 100644 --- a/src/lsp/ffi.lsp +++ b/src/lsp/ffi.lsp @@ -26,10 +26,16 @@ (in-package "FFI") +;;;---------------------------------------------------------------------- +;;; FOREIGN TYPES +;;; + +(defvar *ffi-types* (make-hash-table :size 128)) + (dolist (i '(clines defcfun defentry defla defcbody defunC)) (let ((fname i)) (si::fset i - #'(lambda (x) + #'(lambda (&rest x) (error "The special form ~S cannot be used in the interpreter" fname))))) @@ -42,3 +48,354 @@ '((,arg-types ,type t ; side-effect-p nil ,code))))) + +(defun foreign-elt-type-p (name) + (and (symbolp name) + (member name '(:byte :unsigned-byte :short :unsigned-short + :int :unsigned-int :char :unsigned-char + :long :unsigned-long :pointer-void :object + :float :double) + :test 'eq))) + +(defmacro def-foreign-type (name definition) + `(eval-when (compile load eval) + (setf (gethash ',name ffi::*ffi-types*) ',definition))) + + +(defun size-of-foreign-type (name) + (let* ((size 0) + (type (gethash name *ffi-types* name))) + (unless type + (error "Incomplete or unknown foreign type ~A" name)) + (cond ((symbolp type) + (setf size (si::size-of-foreign-elt-type type))) + ((atom type) + (error "~A is not a valid foreign type identifier" name)) + ((eq (setf name (first type)) :struct) + (setf size (slot-position type nil))) + ((eq name :array) + (when (eq (setf size (second array)) '*) + (error "Incomplete foreign type")) + (setf size (* size (size-of-foreign-type (third array))))) + ((eq name '*) + (si::size-of-foreign-elt-type :pointer-void)) + (t + (error "~A does not denote a foreign type" name))) + size)) + +(defun allocate-foreign-object (type &optional (size 0 size-flag)) + (declare (fixnum size)) + (let ((type-size (size-of-foreign-type type))) + (cond ((null size-flag) + (si::allocate-foreign-data type type-size)) + ((>= size 0) + (let ((bytes (* size type-size))) + (si::allocate-foreign-data `(array ,size ,type) bytes))) + (t + (error "~A is not a valid array dimension size" size))))) + +(defun free-foreign-object (ptr) + (si::free-foreign-data ptr)) + +;;;---------------------------------------------------------------------- +;;; ENUMERATION TYPES +;;; + +(defmacro def-enum (name values-list &key (separator-string "#")) + (let ((constants '()) + (value 0) + field) + (setf name (string name) + separator-string (string separator-string)) + (dolist (item values-list) + (cond ((symbolp item) + (setf field (string item)) + (incf value)) + ((and (consp item) + (symbolp (setf field (first item))) + (integerp (setf value (second item))) + (endp (cddr item)))) + (t + (error "Not a valid argument to DEF-ENUM~%~a" values-list))) + (setf field (concatenate 'string + (symbol-name name) + separator-string + field)) + (push `(defconstant ,(intern field (symbol-package name)) + ',value) + forms)) + `(progn + (def-foreign-type ,name :int) + ,@forms))) + + +;;;---------------------------------------------------------------------- +;;; STRUCTURE TYPES +;;; +;;; The structure type is represented by the following list: +;;; +;;; (STRUCT (SLOT-NAME1 . SLOT-TYPE1)*) +;;; +;;; FIXME! We do not care about slot alignment! +;;; + +(defmacro def-struct (name &rest slots) + (let ((struct-type (list :struct)) + field + type) + (dolist (item (subst `(* ,struct-type) :pointer-self slots)) + (if (and (consp item) + (= (length item) 2) + (symbolp (setf field (first item)))) + (setf type (second item)) + (error "Not a valid DEF-STRUCT slot ~A" item)) + (push (cons field type) struct-type)) + `(def-foreign-type ,name ,(nreverse struct-type)))) + +(defun slot-position (type field) + (setf type (gethash type *ffi-types* type)) + (let ((ndx 0) + (is-union nil)) + (cond ((atom type) + (error "~A is not a foreign STRUCT or UNION type" type)) + ((eq (first type) :struct)) + ((eq (first type) :union) + (setf is-union t)) + (t + (error "~A is not a foreign STRUCT or UNION type" type))) + (dolist (slot (rest type)) + (let* ((slot-name (car slot)) + (slot-type (cdr slot)) + (slot-size (size-of-foreign-type slot-type))) + (when (eq slot-name field) + (return-from slot-position (values ndx slot-type slot-size))) + (unless is-union + (incf ndx slot-size)))) + (values ndx nil nil))) + +(defun get-slot-value (object struct-type field) + (multiple-value-bind (slot-ndx slot-type slot-size) + (slot-position struct-type field) + (unless slot-size + (error "~A is not a field of the type ~A" field struct-type)) + (if (foreign-elt-type-p slot-type) + (si::foreign-data-ref-elt object slot-ndx slot-type) + (si::foreign-data-ref object slot-ndx slot-size slot-type)))) + +(defun (setf get-slot-value) (value object struct-type field) + (multiple-value-bind (slot-ndx slot-type slot-size) + (slot-position struct-type field) + (unless slot-size + (error "~A is not a field of the type ~A" field struct-type)) + (if (foreign-elt-type-p slot-type) + (si::foreign-data-set-elt object slot-ndx slot-type value) + (si::foreign-data-set object slot-ndx value)))) + +(defun get-slot-pointer (object struct-type field) + (multiple-value-bind (slot-ndx slot-type slot-size) + (slot-position struct-type field) + (unless slot-size + (error "~A is not a field of the type ~A" field struct-type)) + (si::foreign-data-pointer object ndx slot-size field-type))) + + +;;;---------------------------------------------------------------------- +;;; ARRAYS +;;; + +(defmacro def-array-pointer (name element-type) + `(def-foreign-type ,name (* (array * ,element-type)))) + +(defun deref-array (array array-type position) + (let* ((element-type (third array-type)) + (element-size (size-of-foreign-type array-type)) + (ndx (* position element-size)) + (length (second array-type))) + (unless (or (eq length *) + (> length position -1)) + (error "Out of bounds when accessing array ~A." array)) + (if (foreign-elt-type-p element-type) + (si::foreign-data-ref-elt array ndx element-type) + (si::foreign-data-ref array ndx element-size element-type)))) + + +;;;---------------------------------------------------------------------- +;;; UNIONS +;;; + +(defmacro def-union (name &rest slots) + (let ((struct-type (list :union)) + field + type) + (dolist (item (subst `(* ,struct-type) :pointer-self slots)) + (unless (and (consp item) + (= (length item) 2) + (symbolp (setf field (first item)))) + (error "Not a valid DEF-UNION slot ~A" item)) + (push (cons field type) struct-type)) + `(def-foreign-type ,name (nreverse struct-type)))) + +;;;---------------------------------------------------------------------- +;;; POINTERS +;;; + +(defvar +null-cstring-pointer+ (si:allocate-foreign-data :pointer-void 0)) + +(defun pointer-address (ptr) + (error "POINTER-ADDRESS not yet implemented.")) + +(defun deref-pointer (ptr type) + ;; FIXME! No checking! + (setf type (gethash type *ffi-types* type)) + (if (foreign-elt-type-p type) + (si::foreign-data-ref-elt ptr ndx type) + (error "Cannot dereference pointer to foreign data, ~A" ptr)) + +(defun (setf deref-pointer) (value ptr type) + ;; FIXME! No checking! + (setf type (gethash type *ffi-types* type)) + (if (foreign-elt-type-p type) + (si::foreign-data-set-elt ptr ndx type value) + (si::foreign-data-set ptr ndx value))) + +(defun make-null-pointer (type) + (setf type (gethash type *ffi-types* type)) + (si::allocate-foreign-data type 0)) + +(defun null-pointer-p (object) + (si::null-pointer-p object)) + + +;;;---------------------------------------------------------------------- +;;; CHARACTERS AND STRINGS +;;; +;;; ECL always returns characters when dereferencing (:array * :char) +;;; + +(defun null-char-p (char) + (eq char #.(code-char 0))) + +(defun ensure-char-character (char) + (cond ((characterp char) char) + ((integerp char) (code-char char)) + (t (error "~a cannot be coerced to type CHARACTER" char)))) + +(defun ensure-char-integer (char) + (cond ((characterp char) (char-code char)) + ((integerp char) char) + (t (error "~a cannot be coerced to type INTEGER" char)))) + +(defmacro convert-from-cstring (object) + object) + +(defmacro convert-to-cstring (object) + object) + +(defmacro free-cstring (object) + object) + +(defmacro with-cstring ((cstring string) &body body) + `(let ((,cstring ,string)) ,@body)) + +(defun foreign-string-length (foreign-string) + (c-inline (foreign-string) (t) :int + "strlen((#0)->foreign.data)" + :side-effects nil + :one-liner t)) + +(defun convert-from-foreign-string (foreign-string + &key length null-terminated-p) + (cond ((and (not length) null-terminated-p) + (setf length (foreign-string-length foreign-string))) + ((not (integerp length)) + (error "~A is not a valid string length" length))) + (c-inline (foreign-string length) (t fixnum) string + "{ + cl_index length = #1; + cl_object output = cl_alloc_simple_string(length); + @(return) = memcpy(output->string.self, (#0)->foreign.data, length); + }" + :one-liner nil + :side-effects t)) + +(defun convert-to-foreign-string (string-designator) + (let ((lisp-string (string string-designator))) + (c-inline (lisp-string) (t) t + "{ + cl_object lisp_string = #0; + cl_index size = lisp_string->string.dim; + cl_object output = ecl_allocate_foreign_data(@(* :char), size); + memcpy(output->foreign.data, lisp_string->string.self, size); + @(return) = output; + }" + :one-liner nil + :side-effects t) + )) + +(defun allocate-foreign-string (size &key unsigned) + (si::allocate-foreign-data `(* ,(if unsigned :unsigned-char :char)) + size)) + +;;;---------------------------------------------------------------------- +;;; MACROLOGY +;;; + +(defmacro with-foreign-object ((var type) &body body) + `(let ((,var (allocate-foreign-object type))) + (unwind-protect + (progn ,@body) + (free-foreign-object ,var)))) + +(defmacro with-cast-pointer (bind &body body) + (let (binding-name ptr type) + (case (length bind) + (2 (setf binding-name (first bind) + ptr binding-name + type (second bind))) + (3 (setf binding-name (first bind) + ptr (second bind) + type (third bind))) + (otherwise (error "Arguments missing in WITH-CAST-POINTER"))) + `(let ((,binding-name (si::foreign-data-pointer ,ptr 0 + (size-of-foreign-type ',type) + ',type))) + ,@body))) + +;;;---------------------------------------------------------------------- +;;; INTERFACE TO C FUNCTIONS AND VARIABLES +;;; + +(defun lisp-to-c-name (name) + (cond ((stringp name) + (values name (intern (string-upcase (substitute #\- #\_ name))))) + ((and (consp name) + (= (length name) 2)) + (values (first name) (second name))))) + +(defmacro def-function (name args &key module (returning :void)) + (multiple-value-bind (c-name lisp-name) + (lisp-to-c-name) + (let* ((arguments (mapcar #'first args)) + (arg-types (mapcar #'second args)) + (nargs (length arguments)) + (c-string (format nil "~s(~s)" c-name + (subseq 'string "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f" + :end (if arguments (1- (* nargs 2)) 0)))) + (casting-required (not (or (eq returning :cstring) + (foreign-elt-type-p returning)))) + (inline-form `(c-inline ,arguments ,arg-types + ,(if casting-required :pointer-void returning) + ,c-string + :one-liner t + :side-effects t))) + (when casting-required + (setf inline-form + `(si::foreign-data-recast ,inline-form + (size-of-foreign-type ',returning) + ',returning))) + (when (> nargs 36) + (error "FFI can only handle C functions with up to 36 arguments")) + `(defun ,lisp-name (,@arguments) + ,inline-form) + ))) + diff --git a/src/lsp/load.lsp.in b/src/lsp/load.lsp.in index a2cff64f9..5df977377 100644 --- a/src/lsp/load.lsp.in +++ b/src/lsp/load.lsp.in @@ -35,8 +35,6 @@ "src:lsp;format.lsp" "src:lsp;defpackage.lsp" "src:lsp;ffi.lsp" -#+ffi - "src:lsp;ffi-objects.lsp" #+tk "src:lsp;tk-init.lsp" "build:lsp;config.lsp" diff --git a/src/util/emacs.el b/src/util/emacs.el index 18ab2babd..b6d9ef192 100644 --- a/src/util/emacs.el +++ b/src/util/emacs.el @@ -263,6 +263,7 @@ "c/disassembler.d" "c/multival.d" "c/threads.d" +"c/ffi.d" "lsp/ansi.lsp" "lsp/arraylib.lsp" "lsp/assert.lsp"