diff -rN -u old-cffi/src/cffi-ecl.lisp new-cffi/src/cffi-ecl.lisp --- old-cffi/src/cffi-ecl.lisp 2007-05-14 18:01:21.000000000 +0200 +++ new-cffi/src/cffi-ecl.lisp 2007-05-14 18:01:21.000000000 +0200 @@ -62,7 +62,7 @@ (eval-when (:compile-toplevel :load-toplevel :execute) (mapc (lambda (feature) (pushnew feature *features*)) '(;; Backend mis-features. - cffi-features:no-long-long + cffi-features:emulated-long-long cffi-features:flat-namespace ;; OS/CPU features. #+:darwin cffi-features:darwin @@ -74,6 +74,28 @@ #+:powerpc7450 cffi-features:ppc32 ))) +;; This is very ugly but since not all implementations put the +;; machine endianess in *FEATURES* we need to do it ourselves +(eval-when (:compile-toplevel :load-toplevel) + (flet ((memset1 (value ptr offset) + (si:foreign-data-set-elt + (si:foreign-data-recast ptr (1+ offset) :void) + offset :unsigned-byte value)) + (memref4 (ptr) + (si:foreign-data-ref-elt + (si:foreign-data-recast ptr 4 :void) 0 :unsigned-int))) + (let ((myalien (si:allocate-foreign-data :void 4))) + (unwind-protect + (progn + (dotimes (i 4) (memset1 (1+ i) myalien i)) + (pushnew (case (memref4 myalien) + (#x01020304 :big-endian) + (#x04030201 :little-endian) + (otherwise + (error "Your machine seems to be neither little-endian nor big-endian."))) + *features*)) + (si:free-foreign-data myalien))))) + ;;; Symbol case. (defun canonicalize-symbol-name-case (name) @@ -135,21 +157,110 @@ ;;;# Dereferencing -(defun %mem-ref (ptr type &optional (offset 0)) - "Dereference an object of TYPE at OFFSET bytes from PTR." +(defun %size-of-foreign-type (type) + (case type + ((:unsigned-long-long :long-long) 8) + (t (ffi:size-of-foreign-type type)))) + +(defun %native-mem-ref (ptr type offset) (let* ((type (cffi-type->ecl-type type)) - (type-size (ffi:size-of-foreign-type type))) + (type-size (%size-of-foreign-type type))) (si:foreign-data-ref-elt (si:foreign-data-recast ptr (+ offset type-size) :void) offset type))) -(defun %mem-set (value ptr type &optional (offset 0)) +(define-compiler-macro %native-mem-ref (&whole form ptr type &optional (offset 0)) + (if (constantp type) + (let* ((type (cffi-type->ecl-type type)) + (type-size (%size-of-foreign-type type))) + (with-unique-names ($offset$) + `(let (($offset$ ,offset)) + (si:foreign-data-ref-elt + (si:foreign-data-recast ,ptr (+ ,$offset$ ,type-size) :void) ,$offset$ ,type)))) + form)) + +(defmacro %double-mem-ref-32 (ptr val offset) + `(progn + #+little-endian (setf (ldb (byte 32 0) ,val) (%native-mem-ref ,ptr :unsigned-int ,offset)) + #+little-endian (setf (ldb (byte 32 32) ,val) (%native-mem-ref ,ptr :unsigned-int (+ ,offset 4))) + #+big-endian (setf (ldb (byte 32 0) ,val) (%native-mem-ref ,ptr :unsigned-int (+ ,offset 4))) + #+big-endian (setf (ldb (byte 32 32) ,val) (%native-mem-ref ,ptr :unsigned-int ,offset)))) + +(defun %emulated-ullong-mem-ref (ptr offset) + (let ((val 0)) + (declare (type (unsigned-byte 64) val) + (optimize (speed 3))) + (%double-mem-ref-32 ptr val offset) + (values val))) + +(defun %emulated-llong-mem-ref (ptr offset) + (let ((val 0)) + (declare (type (unsigned-byte 64) val) + (optimize (speed 3))) + (%double-mem-ref-32 ptr val offset) + (if (logbitp 63 val) ; most significant bit holds the sign + ;; VAL is negative, calculating two's complement + (lognot (logxor val #xFFFFFFFFFFFFFFFF)) + ;; VAL is positive + (values val)))) + +(defun %mem-ref (ptr type &optional (offset 0)) + "Dereference an object of TYPE at OFFSET bytes from PTR." + (case (cffi::canonicalize-foreign-type type) + (:unsigned-long-long + (%emulated-ullong-mem-ref ptr offset)) + (:long-long + (%emulated-llong-mem-ref ptr offset)) + (t + (%native-mem-ref ptr type offset)))) + +(defun %native-mem-set (value ptr type offset) "Set an object of TYPE at OFFSET bytes from PTR." (let* ((type (cffi-type->ecl-type type)) - (type-size (ffi:size-of-foreign-type type))) + (type-size (%size-of-foreign-type type))) (si:foreign-data-set-elt (si:foreign-data-recast ptr (+ offset type-size) :void) offset type value))) +(define-compiler-macro %native-mem-set (&whole form value ptr type &optional (offset 0)) + (if (constantp type) + (let* ((type (cffi-type->ecl-type type)) + (type-size (%size-of-foreign-type type)) + ($offset$ (gensym "OFFSET-"))) + `(let (($offset$ ,offset)) + (si:foreign-data-set-elt + (si:foreign-data-recast ,ptr (+ ,$offset$ ,type-size) :void) + ,$offset$ ,type ,value))) + form)) + +(defmacro %double-mem-set-32 (value ptr offset) + `(progn + #+little-endian (%native-mem-set (ldb (byte 32 0) ,value) ,ptr :unsigned-int ,offset) + #+little-endian (%native-mem-set (ldb (byte 32 32) ,value) ,ptr :unsigned-int (+ ,offset 4)) + #+big-endian (%native-mem-set (ldb (byte 32 0) ,value) ,ptr :unsigned-int (+ ,offset 4)) + #+big-endian (%native-mem-set (ldb (byte 32 32) ,value) ,ptr :unsigned-int ,offset))) + +(defun %emulated-ullong-mem-set (value ptr offset) + (declare (type (unsigned-byte 64) value) + (optimize (speed 3))) + (%double-mem-set-32 value ptr offset)) + +(defun %emulated-llong-mem-set (value ptr offset) + (declare (type (signed-byte 64) value) + (optimize (speed 3))) + (%double-mem-set-32 value ptr offset)) + +(defun %mem-set (value ptr type &optional (offset 0)) + "Set an object of TYPE at OFFSET bytes from PTR." + (case (cffi::canonicalize-foreign-type type) + (:unsigned-long-long + (locally (declare (type (unsigned-byte 64) value)) + (%emulated-ullong-mem-set value ptr offset))) + (:long-long + (locally (declare (type (signed-byte 64) value)) + (%emulated-llong-mem-set value ptr offset))) + (t + (%native-mem-set value ptr type offset)))) + ;;;# Type Operations (defconstant +translation-table+ @@ -161,6 +272,8 @@ (:unsigned-int :unsigned-int "unsigned int") (:long :long "long") (:unsigned-long :unsigned-long "unsigned long") + (:long-long :long-long "long long") + (:unsigned-long-long :unsigned-long-long "unsigned long long") (:float :float "float") (:double :double "double") (:pointer :pointer-void "void*") @@ -178,12 +291,12 @@ (defun %foreign-type-size (type-keyword) "Return the size in bytes of a foreign type." - (nth-value 0 (ffi:size-of-foreign-type + (nth-value 0 (%size-of-foreign-type (cffi-type->ecl-type type-keyword)))) (defun %foreign-type-alignment (type-keyword) "Return the alignment in bytes of a foreign type." - (nth-value 1 (ffi:size-of-foreign-type + (nth-value 1 (%size-of-foreign-type (cffi-type->ecl-type type-keyword)))) ;;;# Calling Foreign Functions diff -rN -u old-cffi/src/features.lisp new-cffi/src/features.lisp --- old-cffi/src/features.lisp 2007-05-14 18:01:21.000000000 +0200 +++ new-cffi/src/features.lisp 2007-05-14 18:01:21.000000000 +0200 @@ -43,6 +43,7 @@ ;; meaning that at some point all lisps will support long-longs, ;; the foreign-funcall primitive, etc... #:no-long-long + #:emulated-long-long #:no-foreign-funcall #:no-stdcall #:flat-namespace