From 90e8bbf63d6ab5647f284af1cbab30ae37c5ae1c Mon Sep 17 00:00:00 2001 From: espen Date: Thu, 8 Jun 2006 13:24:25 +0000 Subject: [PATCH] Improved alignment of struct slots --- gffi/basic-types.lisp | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++- gffi/defpackage.lisp | 8 ++--- gffi/enums.lisp | 76 ++++++++++++++++++++++++++-------------------- gffi/memory.lisp | 9 ++++-- gffi/proxy.lisp | 65 ++++++++++++++++++++++------------------ gffi/vectors.lisp | 19 +++++++++++- glib/glib.lisp | 9 +++++- 7 files changed, 198 insertions(+), 71 deletions(-) diff --git a/gffi/basic-types.lisp b/gffi/basic-types.lisp index b355f5e..d1da957 100644 --- a/gffi/basic-types.lisp +++ b/gffi/basic-types.lisp @@ -20,7 +20,7 @@ ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -;; $Id: basic-types.lisp,v 1.1 2006-04-25 20:36:05 espen Exp $ +;; $Id: basic-types.lisp,v 1.2 2006-06-08 13:24:25 espen Exp $ (in-package "GFFI") @@ -67,6 +67,9 @@ (define-type-generic size-of (type &key inlined) "Returns the foreign size of TYPE. The default value of INLINED is T for basic C types and NIL for other types.") +(define-type-generic type-alignment (type &key inlined) + "Returns the alignment of TYPE. The default value of INLINED is +T for basic C types and NIL for other types.") (define-type-generic alien-arg-wrapper (type var arg style form &optional copy-p) "Creates a wrapper around FORM which binds the alien translation of ARG to VAR in a way which makes it possible to pass the location of @@ -202,6 +205,10 @@ have been written as temporal.") (declare (ignore type)) (size-of 'signed-byte :inlined inlined)) +(define-type-method type-alignment ((type integer) &key (inlined t)) + (declare (ignore type)) + (type-alignment 'signed-byte :inlined inlined)) + (define-type-method writer-function ((type integer) &key temp (inlined t)) (declare (ignore temp)) (assert-inlined type inlined) @@ -253,6 +260,21 @@ have been written as temporal.") (32 4) (64 8))))) +(define-type-method type-alignment ((type signed-byte) &key (inlined t)) + (assert-inlined type inlined) + (destructuring-bind (&optional (size '*)) + (rest (mklist (type-expand-to 'signed-byte type))) + (let ((size (if (eq size '*) + (second (type-expand-to 'signed-byte 'int)) + size))) + #+sbcl(sb-alignment `(sb-alien:signed ,size)) + #+clisp(ecase size + ( 8 (nth-value 1 (ffi:sizeof 'ffi:sint8))) + (16 (nth-value 1 (ffi:sizeof 'ffi:sint16))) + (32 (nth-value 1 (ffi:sizeof 'ffi:sint32))) + (64 (nth-value 1 (ffi:sizeof 'ffi:sint64)))) + #-(or sbcl clisp) 4))) + (define-type-method writer-function ((type signed-byte) &key temp (inlined t)) (declare (ignore temp)) (assert-inlined type inlined) @@ -340,6 +362,12 @@ have been written as temporal.") (rest (mklist (type-expand-to 'unsigned-byte type))) (size-of `(signed ,size)))) +(define-type-method type-alignment ((type unsigned-byte) &key (inlined t)) + (assert-inlined type inlined) + (destructuring-bind (&optional (size '*)) + (rest (mklist (type-expand-to 'unsigned-byte type))) + (type-alignment `(signed ,size)))) + (define-type-method writer-function ((type unsigned-byte) &key temp (inlined t)) (declare (ignore temp)) (assert-inlined type inlined) @@ -408,6 +436,12 @@ have been written as temporal.") #+clisp (ffi:sizeof 'single-float) #-(or sbcl clisp) 4) +(define-type-method type-alignment ((type single-float) &key (inlined t)) + (assert-inlined type inlined) + #+sbcl (sb-alignment 'single-float) + #+clisp (nth-value 1 (ffi:sizeof 'single-float)) + #-(or sbcl clisp) 4) + (define-type-method to-alien-form ((type single-float) form &optional copy-p) (declare (ignore type copy-p)) `(coerce ,form 'single-float)) @@ -449,6 +483,12 @@ have been written as temporal.") #+clisp (ffi:sizeof 'double-float) #-(or sbcl clisp) 8) +(define-type-method type-alignment ((type double-float) &key (inlined t)) + (assert-inlined type inlined) + #+sbcl (sb-alignment 'double-float) + #+clisp (nth-value 1 (ffi:sizeof 'double-float)) + #-(or sbcl clisp) 4) + (define-type-method to-alien-form ((type double-float) form &optional copy-p) (declare (ignore type copy-p)) `(coerce ,form 'double-float)) @@ -487,6 +527,12 @@ have been written as temporal.") (define-type-method size-of ((type base-char) &key (inlined t)) (assert-inlined type inlined) 1) + +(define-type-method type-alignment ((type base-char) &key (inlined t)) + (assert-inlined type inlined) + #+sbcl (sb-alignment 'sb-alien:char) + #+clisp (nth-value 1 (ffi:sizeof 'ffi:character)) + #-(or sbcl clisp) 4) (define-type-method to-alien-form ((type base-char) form &optional copy-p) (declare (ignore type copy-p)) @@ -607,6 +653,10 @@ have been written as temporal.") (assert-not-inlined type inlined) (size-of 'pointer)) +(define-type-method type-alignment ((type string) &key inlined) + (assert-not-inlined type inlined) + (type-alignment 'pointer)) + (define-type-method to-alien-form ((type string) string &optional copy-p) (declare (ignore type copy-p)) `(encode-utf8-string ,string)) @@ -697,6 +747,10 @@ have been written as temporal.") (assert-not-inlined type inlined) (size-of 'string)) +(define-type-method type-alignment ((type pathname) &key inlined) + (assert-not-inlined type inlined) + (type-alignment 'string)) + (define-type-method alien-arg-wrapper ((type pathname) var pathname style form &optional copy-in-p) (declare (ignore type)) (alien-arg-wrapper 'string var `(namestring (translate-logical-pathname ,pathname)) style form copy-in-p)) @@ -765,6 +819,12 @@ have been written as temporal.") (rest (mklist (type-expand-to 'bool type))) (size-of `(signed-byte ,size)))) +(define-type-method type-alignment ((type bool) &key (inlined t)) + (assert-inlined type inlined) + (destructuring-bind (&optional (size '*)) + (rest (mklist (type-expand-to 'bool type))) + (type-alignment `(signed-byte ,size)))) + (define-type-method to-alien-form ((type bool) bool &optional copy-p) (declare (ignore type copy-p)) `(if ,bool 1 0)) @@ -813,6 +873,10 @@ have been written as temporal.") (assert-inlined type inlined) (size-of 'bool)) +(define-type-method type-alignment ((type boolean) &key (inlined t)) + (assert-inlined type inlined) + (type-alignment 'bool)) + (define-type-method to-alien-form ((type boolean) boolean &optional copy-p) (declare (ignore type copy-p)) (to-alien-form 'bool boolean)) @@ -858,6 +922,13 @@ have been written as temporal.") (size-of subtype inlined) (size-of subtype)))) +(define-type-method type-alignment ((type or) &key (inlined nil inlined-p)) + (loop + for subtype in (type-expand-to 'or type) + maximize (if inlined-p + (type-alignment subtype inlined) + (type-alignment subtype)))) + (define-type-method alien-arg-wrapper ((type or) var value style form &optional copy-in-p) (cond ((and (in-arg-p style) (out-arg-p style)) @@ -919,6 +990,12 @@ have been written as temporal.") #+clisp (ffi:sizeof 'ffi:c-pointer) #-(or sbcl clisp) 4) +(define-type-method type-alignment ((type pointer) &key (inlined t)) + (assert-inlined type inlined) + #+sbcl (sb-alignment 'system-area-pointer) + #+clisp (ffi:sizeof 'ffi:c-pointer) + #-(or sbcl clisp) (size-of 'pointer)) + (define-type-method to-alien-form ((type pointer) form &optional copy-p) (declare (ignore type copy-p)) form) @@ -1094,6 +1171,10 @@ have been written as temporal.") (assert-inlined type inlined) (size-of (second (type-expand-to 'inlined type)) :inlined t)) +(define-type-method type-alignment ((type inlined) &key (inlined t)) + (assert-inlined type inlined) + (type-alignment (second (type-expand-to 'inlined type)) :inlined t)) + (define-type-method reader-function ((type inlined) &key (ref :read) (inlined t)) (assert-inlined type inlined) (reader-function (second (type-expand-to 'inlined type)) :ref ref :inlined t)) diff --git a/gffi/defpackage.lisp b/gffi/defpackage.lisp index 68cf044..e0d7bec 100644 --- a/gffi/defpackage.lisp +++ b/gffi/defpackage.lisp @@ -20,7 +20,7 @@ ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -;; $Id: defpackage.lisp,v 1.1 2006-04-25 20:29:14 espen Exp $ +;; $Id: defpackage.lisp,v 1.2 2006-06-08 13:24:25 espen Exp $ (defpackage "GFFI" (:use "COMMON-LISP" "AUTOEXPORT" "PKG-CONFIG" "CLG-UTILS") @@ -56,9 +56,9 @@ "DEFAULT-ALIEN-TYPE-NAME" "DEFAULT-TYPE-NAME" "TYPE-EXPAND" "TYPE-EXPAND-1" "TYPE-EXPAND-TO") ;; Symbols from basic-types.lisp - (:export "LONG" "UNSIGNED-LONG" "INT" "UNSIGNED-INT" "SHORT" - "UNSIGNED-SHORT" "SIGNED" "UNSIGNED" "CHAR" "POINTER" - "BOOL" "COPY-OF" "STATIC" "SIZE-OF" "ALIEN-TYPE" "UNBOUND-VALUE" + (:export "LONG" "UNSIGNED-LONG" "INT" "UNSIGNED-INT" "SHORT" "UNSIGNED-SHORT" + "SIGNED" "UNSIGNED" "CHAR" "POINTER" "BOOL" "COPY-OF" "STATIC" + "SIZE-OF" "TYPE-ALIGNMENT" "ALIEN-TYPE" "UNBOUND-VALUE" "ALIEN-ARG-WRAPPER" "TO-ALIEN-FORM" "FROM-ALIEN-FORM" "CALLBACK-WRAPPER" "TO-ALIEN-FUNCTION" "FROM-ALIEN-FUNCTION" "READER-FUNCTION" "WRITER-FUNCTION" "GETTER-FUNCTION" diff --git a/gffi/enums.lisp b/gffi/enums.lisp index d97ef70..a1a77fd 100644 --- a/gffi/enums.lisp +++ b/gffi/enums.lisp @@ -20,7 +20,7 @@ ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -;; $Id: enums.lisp,v 1.1 2006-04-25 20:37:49 espen Exp $ +;; $Id: enums.lisp,v 1.2 2006-06-08 13:24:25 espen Exp $ (in-package "GFFI") @@ -56,6 +56,10 @@ (assert-inlined type inlined) (size-of 'signed)) +(define-type-method type-alignment ((type enum) &key (inlined t)) + (assert-inlined type inlined) + (type-alignment 'signed)) + (define-type-method to-alien-form ((type enum) form &optional copy-p) (declare (ignore copy-p)) `(case ,form @@ -174,6 +178,10 @@ (assert-inlined type inlined) (size-of 'unsigned)) +(define-type-method type-alignment ((type flags) &key (inlined t)) + (assert-inlined type inlined) + (type-alignment 'unsigned)) + (define-type-method to-alien-form ((type flags) flags &optional copy-p) (declare (ignore copy-p)) `(reduce #'logior (mklist ,flags) @@ -231,7 +239,7 @@ (let ((flags-int (intern (format nil "~A-TO-INT" name))) (int-flags (intern (format nil "INT-TO-~A" name))) (satisfies (intern (format nil "~A-P" name)))) - `(progn + `(eval-when (:compile-toplevel :load-toplevel :execute) (deftype ,name () '(satisfies ,satisfies)) (defun ,satisfies (object) (flet ((valid-p (ob) @@ -250,37 +258,39 @@ for (int symbol) in ',(%map-flags args :int-symbol) when(= (logand value int) int) collect symbol)) - (eval-when (:compile-toplevel :load-toplevel :execute) - (define-type-method alien-type ((type ,name)) - (declare (ignore type)) - (alien-type 'flags)) - (define-type-method size-of ((type ,name) &key (inlined t)) - (assert-inlined type inlined) - (size-of 'flags)) - (define-type-method to-alien-form ((type ,name) form &optional copy-p) - (declare (ignore type copy-p)) - (list ',flags-int form)) - (define-type-method from-alien-form ((type ,name) form &key ref) - (declare (ignore type ref)) - (list ',int-flags form)) - (define-type-method to-alien-function ((type ,name) &optional copy-p) - (declare (ignore type copy-p)) - #',flags-int) - (define-type-method from-alien-function ((type ,name) &key ref) - (declare (ignore type ref)) - #',int-flags) - (define-type-method writer-function ((type ,name) &key temp (inlined t)) - (declare (ignore temp)) - (assert-inlined type inlined) - (let ((writer (writer-function 'signed))) - #'(lambda (flags location &optional (offset 0)) - (funcall writer (,flags-int flags) location offset)))) - (define-type-method reader-function ((type ,name) &key ref (inlined t)) - (declare (ignore ref)) - (assert-inlined type inlined) - (let ((reader (reader-function 'signed))) - #'(lambda (location &optional (offset 0)) - (,int-flags (funcall reader location offset))))))))) + (define-type-method alien-type ((type ,name)) + (declare (ignore type)) + (alien-type 'flags)) + (define-type-method size-of ((type ,name) &key (inlined t)) + (assert-inlined type inlined) + (size-of 'flags)) + (define-type-method type-alignment ((type ,name) &key (inlined t)) + (assert-inlined type inlined) + (type-alignment 'flags)) + (define-type-method to-alien-form ((type ,name) form &optional copy-p) + (declare (ignore type copy-p)) + (list ',flags-int form)) + (define-type-method from-alien-form ((type ,name) form &key ref) + (declare (ignore type ref)) + (list ',int-flags form)) + (define-type-method to-alien-function ((type ,name) &optional copy-p) + (declare (ignore type copy-p)) + #',flags-int) + (define-type-method from-alien-function ((type ,name) &key ref) + (declare (ignore type ref)) + #',int-flags) + (define-type-method writer-function ((type ,name) &key temp (inlined t)) + (declare (ignore temp)) + (assert-inlined type inlined) + (let ((writer (writer-function 'signed))) + #'(lambda (flags location &optional (offset 0)) + (funcall writer (,flags-int flags) location offset)))) + (define-type-method reader-function ((type ,name) &key ref (inlined t)) + (declare (ignore ref)) + (assert-inlined type inlined) + (let ((reader (reader-function 'signed))) + #'(lambda (location &optional (offset 0)) + (,int-flags (funcall reader location offset)))))))) (defexport define-enum-type (name &rest args) diff --git a/gffi/memory.lisp b/gffi/memory.lisp index b84cb40..997a632 100644 --- a/gffi/memory.lisp +++ b/gffi/memory.lisp @@ -20,7 +20,7 @@ ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -;; $Id: memory.lisp,v 1.1 2006-04-25 20:31:35 espen Exp $ +;; $Id: memory.lisp,v 1.2 2006-06-08 13:24:25 espen Exp $ (in-package "GFFI") @@ -141,4 +141,9 @@ (sb-alien-internals:parse-alien-type type nil))) (defun sb-sizeof (type) - (/ (sb-sizeof-bits type) 8))) + (/ (sb-sizeof-bits type) 8)) + + (defun sb-alignment (type) + (/ (sb-alien-internals:alien-type-alignment + (sb-alien-internals:parse-alien-type type nil)) + 8))) diff --git a/gffi/proxy.lisp b/gffi/proxy.lisp index 8e83f47..b7cdaed 100644 --- a/gffi/proxy.lisp +++ b/gffi/proxy.lisp @@ -20,7 +20,7 @@ ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -;; $Id: proxy.lisp,v 1.1 2006-04-25 20:49:16 espen Exp $ +;; $Id: proxy.lisp,v 1.2 2006-06-08 13:25:09 espen Exp $ (in-package "GFFI") @@ -282,12 +282,11 @@ (funcall writer (foreign-location object) value))) (call-next-method))) - (defconstant +struct-alignmen+ (size-of 'pointer)) - - (defun align-offset (size &optional packed-p) - (if (or packed-p (zerop (mod size +struct-alignmen+))) - size - (+ size (- +struct-alignmen+ (mod size +struct-alignmen+))))) + (defun adjust-offset (offset type &optional packed-p) + (let ((alignment (type-alignment type))) + (if (or packed-p (zerop (mod offset alignment))) + offset + (+ offset (- alignment (mod offset alignment)))))) (defmethod compute-slots ((class proxy-class)) (let ((alien-slots (remove-if-not @@ -297,17 +296,16 @@ (when alien-slots (loop with packed-p = (foreign-slots-packed-p class) - as offset = (align-offset + for slotd in alien-slots + as offset = (adjust-offset (foreign-size (most-specific-proxy-superclass class)) + (slot-definition-type slotd) packed-p) - then (align-offset - (+ - (slot-definition-offset slotd) - (size-of (slot-definition-type slotd))) - packed-p) - for slotd in alien-slots - unless (slot-boundp slotd 'offset) - do (setf (slot-value slotd 'offset) offset)))) + then (adjust-offset offset (slot-definition-type slotd) packed-p) + do (if (slot-boundp slotd 'offset) + (setf offset (slot-value slotd 'offset)) + (setf (slot-value slotd 'offset) offset)) + (incf offset (size-of (slot-definition-type slotd)))))) (call-next-method)) (defmethod validate-superclass ((class proxy-class) (super standard-class)) @@ -327,6 +325,10 @@ (assert-not-inlined type inlined) (size-of 'pointer)) +(define-type-method type-alignment ((type proxy) &key inlined) + (assert-not-inlined type inlined) + (type-alignment 'pointer)) + (define-type-method from-alien-form ((type proxy) form &key (ref :free)) (let ((class (type-expand type))) (ecase ref @@ -365,10 +367,6 @@ (funcall ref (foreign-location instance)))) #'foreign-location)) -(define-type-method size-of ((type proxy) &key inlined) - (assert-not-inlined type inlined) - (size-of 'pointer)) - (define-type-method writer-function ((type proxy) &key temp inlined) (assert-not-inlined type inlined) (if temp @@ -549,15 +547,15 @@ object at the give location.")) (when (and #?-(or (sbcl>= 0 9 8) (featurep :clisp))(class-finalized-p class) (not (slot-boundp class 'size))) - (let ((size (or - (loop - for slotd in slots - when (eq (slot-definition-allocation slotd) :alien) - maximize (+ - (slot-definition-offset slotd) - (size-of (slot-definition-type slotd)))) - 0))) - (setf (slot-value class 'size) (+ size (mod size +struct-alignmen+))))) + (setf (slot-value class 'size) + (or + (loop + for slotd in slots + when (eq (slot-definition-allocation slotd) :alien) + maximize (+ + (slot-definition-offset slotd) + (size-of (slot-definition-type slotd)))) + 0))) slots)) (define-type-method callback-wrapper ((type struct) var arg form) @@ -572,6 +570,15 @@ object at the give location.")) (foreign-size type) (size-of 'pointer))) +(define-type-method type-alignment ((type struct) &key inlined) + (if inlined + (let ((slot1 (find-if + #'(lambda (slotd) + (eq (slot-definition-allocation slotd) :alien)) + (class-slots (find-class type))))) + (type-alignment (slot-definition-type slot1))) + (type-alignment 'pointer))) + (define-type-method writer-function ((type struct) &key temp inlined) (if inlined (if temp diff --git a/gffi/vectors.lisp b/gffi/vectors.lisp index 20b987b..082c34c 100644 --- a/gffi/vectors.lisp +++ b/gffi/vectors.lisp @@ -20,7 +20,7 @@ ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -;; $Id: vectors.lisp,v 1.1 2006-04-25 20:40:57 espen Exp $ +;; $Id: vectors.lisp,v 1.2 2006-06-08 13:24:25 espen Exp $ (in-package "GFFI") @@ -110,6 +110,15 @@ (* (size-of element-type) length))) (size-of 'pointer))) +(define-type-method type-alignment ((type vector) &key inlined) + (if inlined + (destructuring-bind (element-type &optional (length '*)) + (rest (type-expand-to 'vector type)) + (if (eq length '*) + (error "Can't inline vector with variable size: ~A" type) + (* (type-alignment element-type) length))) + (type-alignment 'pointer))) + (define-type-method alien-arg-wrapper ((type vector) var vector style form &optional copy-in-p) (destructuring-bind (element-type &optional (length '*)) (rest (type-expand-to 'vector type)) @@ -308,6 +317,10 @@ (assert-not-inlined type inlined) (size-of 'pointer)) +(define-type-method type-alignment ((type vector0) &key inlined) + (assert-not-inlined type inlined) + (type-alignment 'pointer)) + (define-type-method alien-arg-wrapper ((type vector0) var vector style form &optional copy-in-p) (destructuring-bind (element-type) (rest (type-expand-to 'vector0 type)) (cond @@ -453,6 +466,10 @@ (assert-not-inlined type inlined) (size-of 'pointer)) +(define-type-method type-alignment ((type counted-vector) &key inlined) + (assert-not-inlined type inlined) + (type-alignment 'pointer)) + (define-type-method alien-arg-wrapper ((type counted-vector) var vector style form &optional copy-in-p) (destructuring-bind (element-type &optional (counter-type 'unsigned-int)) (rest (type-expand-to 'counted-vector type)) diff --git a/glib/glib.lisp b/glib/glib.lisp index 6d01049..ec84bb9 100644 --- a/glib/glib.lisp +++ b/glib/glib.lisp @@ -20,7 +20,7 @@ ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -;; $Id: glib.lisp,v 1.37 2006-04-25 21:51:32 espen Exp $ +;; $Id: glib.lisp,v 1.38 2006-06-08 13:24:25 espen Exp $ (in-package "GLIB") @@ -167,6 +167,9 @@ (assert-not-inlined type inlined) (size-of 'pointer)) +(define-type-method type-alignment ((type glist) &key inlined) + (assert-not-inlined type inlined) + (type-alignment 'pointer)) (define-type-method alien-arg-wrapper ((type glist) var list style form &optional copy-in-p) (destructuring-bind (element-type) (rest (type-expand-to 'glist type)) @@ -317,6 +320,10 @@ (assert-not-inlined type inlined) (size-of 'pointer)) +(define-type-method type-alignment ((type gslist) &key inlined) + (assert-not-inlined type inlined) + (type-alignment 'pointer)) + (define-type-method alien-arg-wrapper ((type gslist) var list style form &optional copy-in-p) (destructuring-bind (element-type) (rest (type-expand-to 'gslist type)) (cond -- 2.11.0