Improved alignment of struct slots
authorespen <espen>
Thu, 8 Jun 2006 13:24:25 +0000 (13:24 +0000)
committerespen <espen>
Thu, 8 Jun 2006 13:24:25 +0000 (13:24 +0000)
gffi/basic-types.lisp
gffi/defpackage.lisp
gffi/enums.lisp
gffi/memory.lisp
gffi/proxy.lisp
gffi/vectors.lisp
glib/glib.lisp

index b355f5e..d1da957 100644 (file)
@@ -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))
index 68cf044..e0d7bec 100644 (file)
@@ -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"
index d97ef70..a1a77fd 100644 (file)
@@ -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")
   
   (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
   (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)
   (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)
          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)
index b84cb40..997a632 100644 (file)
@@ -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")
      (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)))
index 8e83f47..b7cdaed 100644 (file)
@@ -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")
 
              (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 
       (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))
   (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
            (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
index 20b987b..082c34c 100644 (file)
@@ -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")
          (* (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))
   (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
   (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))
index 6d01049..ec84bb9 100644 (file)
@@ -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")
   (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))
   (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