summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-06-02 18:57:48 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-06-02 18:57:48 -0700
commit8d52205b778c41e438192c5bc4187edd679fbdfd (patch)
tree9f082467fa66bac00206adf2fee0d04bb753b284
parentabbc0d00006c3126b9d1cf8150c21f4a8c56089a (diff)
downloadtxr-8d52205b778c41e438192c5bc4187edd679fbdfd.tar.gz
txr-8d52205b778c41e438192c5bc4187edd679fbdfd.tar.bz2
txr-8d52205b778c41e438192c5bc4187edd679fbdfd.zip
ffi: functions and macros for basic type properties.
* ffi.c (ffi_alignof, ffi_offsetof, ffi_arraysize, ffi_elemsize, ffi_elemtype): New functions. (ffi_init): Registered intrinsics ffi-alignof, ffi-offsetof, ffi-arraysize, ffi-elemsize, ffi-elemtype. * ffi.h (ffi_alignof, ffi_offsetof, ffi_arraysize, ffi_elemsize, ffi_elemtype): Declared. * lisplib.c (ffi_set_entries): New autoload entries alignof, offsetof, arraysize, elemsize, elemtype. * share/txr/stdlib/ffi.tl (alignof, offsetof, arraysize, elemsize, elemtype): New macros. * txr.1: Documented new functions and macros.
-rw-r--r--ffi.c74
-rw-r--r--ffi.h5
-rw-r--r--lisplib.c5
-rw-r--r--share/txr/stdlib/ffi.tl15
-rw-r--r--txr.1262
5 files changed, 349 insertions, 12 deletions
diff --git a/ffi.c b/ffi.c
index 255a318d..5297fc86 100644
--- a/ffi.c
+++ b/ffi.c
@@ -3037,6 +3037,75 @@ val ffi_size(val type)
return num(tft->size);
}
+val ffi_alignof(val type)
+{
+ val self = lit("ffi-alignof");
+ struct txr_ffi_type *tft = ffi_type_struct_checked(type);
+ if (tft->size == 0 && bitfield_syntax_p(tft->syntax))
+ uw_throwf(error_s, lit("~a: bitfield type ~s has no alignment"),
+ self, type, nao);
+ return num(tft->align);
+}
+
+val ffi_offsetof(val type, val memb)
+{
+ val self = lit("ffi-offsetof");
+ struct txr_ffi_type *tft = ffi_type_struct_checked(type);
+ cnum i;
+
+ if (!tft->memb)
+ uw_throwf(error_s, lit("~a: ~s isn't a struct type"), self, type, nao);
+
+ for (i = 0; i < tft->nelem; i++) {
+ struct smemb *pmemb = tft->memb + i;
+
+ if (pmemb->mname == memb) {
+ if (pmemb->mtft->mask != 0)
+ uw_throwf(error_s, lit("~a: ~s is a bitfield in ~s"), self,
+ memb, type, nao);
+ return num(tft->memb[i].offs);
+ }
+ }
+
+ uw_throwf(error_s, lit("~a: ~s has no member ~s"), self, type, memb, nao);
+}
+
+val ffi_arraysize(val type)
+{
+ val self = lit("ffi-put-into");
+ struct txr_ffi_type *tft = ffi_type_struct_checked(type);
+ if (!tft->eltype)
+ uw_throwf(error_s, lit("~a: ~s isn't an array"), self, type, nao);
+ return num(tft->nelem);
+}
+
+val ffi_elemsize(val type)
+{
+ val self = lit("ffi-elemsize");
+ struct txr_ffi_type *tft = ffi_type_struct_checked(type);
+ if (!tft->eltype) {
+ uw_throwf(error_s, lit("~a: ~s isn't an array or pointer"),
+ self, type, nao);
+ } else {
+ struct txr_ffi_type *etft = ffi_type_struct(tft->eltype);
+ return num(etft->size);
+ }
+}
+
+val ffi_elemtype(val type)
+{
+ val self = lit("ffi-elemtype");
+ struct txr_ffi_type *tft = ffi_type_struct_checked(type);
+ val eltype = tft->eltype;
+
+ if (!eltype) {
+ uw_throwf(error_s, lit("~a: ~s isn't an array or pointer"),
+ self, type, nao);
+ }
+
+ return eltype;
+}
+
val ffi_put_into(val dstbuf, val obj, val type)
{
val self = lit("ffi-put-into");
@@ -3454,6 +3523,11 @@ void ffi_init(void)
reg_fun(intern(lit("ffi-make-closure"), user_package), func_n4o(ffi_make_closure, 2));
reg_fun(intern(lit("ffi-typedef"), user_package), func_n2(ffi_typedef));
reg_fun(intern(lit("ffi-size"), user_package), func_n1(ffi_size));
+ reg_fun(intern(lit("ffi-alignof"), user_package), func_n1(ffi_alignof));
+ reg_fun(intern(lit("ffi-offsetof"), user_package), func_n2(ffi_offsetof));
+ reg_fun(intern(lit("ffi-arraysize"), user_package), func_n1(ffi_arraysize));
+ reg_fun(intern(lit("ffi-elemsize"), user_package), func_n1(ffi_elemsize));
+ reg_fun(intern(lit("ffi-elemtype"), user_package), func_n1(ffi_elemtype));
reg_fun(intern(lit("ffi-put-into"), user_package), func_n3(ffi_put_into));
reg_fun(intern(lit("ffi-put"), user_package), func_n2(ffi_put));
reg_fun(intern(lit("ffi-in"), user_package), func_n4(ffi_in));
diff --git a/ffi.h b/ffi.h
index 9f7876ef..c8f6021b 100644
--- a/ffi.h
+++ b/ffi.h
@@ -64,6 +64,11 @@ mem_t *ffi_closure_get_fptr(val closure);
val ffi_call_wrap(val fptr, val ffi_call_desc, struct args *args);
val ffi_typedef(val name, val type);
val ffi_size(val type);
+val ffi_alignof(val type);
+val ffi_offsetof(val type, val memb);
+val ffi_arraysize(val type);
+val ffi_elemsize(val type);
+val ffi_elemtype(val type);
val ffi_put_into(val dstbuf, val obj, val type);
val ffi_put(val obj, val type);
val ffi_in(val srcbuf, val obj, val type, val copy_p);
diff --git a/lisplib.c b/lisplib.c
index df5e9a93..f8ce2f47 100644
--- a/lisplib.c
+++ b/lisplib.c
@@ -524,8 +524,9 @@ static val ffi_set_entries(val dlt, val fun)
{
val name[] = {
lit("with-dyn-lib"), lit("deffi"), lit("deffi-type"), lit("deffi-cb"),
- lit("deffi-var"), lit("typedef"), lit("sizeof"), lit("ffi"),
- lit("carray-ref"),
+ lit("deffi-var"), lit("typedef"), lit("sizeof"), lit("alignof"),
+ lit("offsetof"), lit("arraysize"), lit("elemsize"), lit("elemtype"),
+ lit("ffi"), lit("carray-ref"),
nil
};
set_dlt_entries(dlt, name, fun);
diff --git a/share/txr/stdlib/ffi.tl b/share/txr/stdlib/ffi.tl
index 69a19a1e..da29c1e5 100644
--- a/share/txr/stdlib/ffi.tl
+++ b/share/txr/stdlib/ffi.tl
@@ -114,6 +114,21 @@
(defmacro sizeof (type)
(ffi-size (ffi-type-compile type)))
+(defmacro alignof (type)
+ (ffi-alignof (ffi-type-compile type)))
+
+(defmacro offsetof (struct memb)
+ (ffi-offsetof (ffi-type-compile struct) memb))
+
+(defmacro arraysize (arr)
+ (ffi-arraysize (ffi-type-compile arr)))
+
+(defmacro elemtype (type)
+ ^(ffi-elemtype (ffi-type-compile ',type)))
+
+(defmacro elemsize (type)
+ (ffi-elemsize (ffi-type-compile type)))
+
(defmacro ffi (type)
^(ffi-type-compile ',type))
diff --git a/txr.1 b/txr.1
index d758e28e..99b49a25 100644
--- a/txr.1
+++ b/txr.1
@@ -54992,6 +54992,11 @@ function returns an integer which gives the storage size of
the given FFI type: the amount of storage required for the
external representation of that type.
+Bitfield types do not have a size; it is an error to apply
+this function to a bitfield.
+
+The size is machine:specific.
+
.TP* Example:
.cblk
@@ -55001,6 +55006,169 @@ external representation of that type.
'(array 42 char))) -> 42
.cble
+.coNP Function @ ffi-alignof
+.synb
+.mets (ffi-alignof << type )
+.syne
+.desc
+The
+.code ffi-alignof
+function returns an integer which gives the alignment
+the given FFI type. When an instance of
+.meta type
+is placed into a structure as a member, it is placed after the previous member
+at the smallest available offset which is divisible by the alignment.
+The bytes skipped from the smallest available offset to the smallest
+available aligned offset are referred to as
+.IR padding .
+
+Bitfield types do not have an alignment; it is an error to apply
+this function to a bitfield. Bitfields are allocated in
+storage cells, and those cells have alignment which is the
+same as that of the type
+.codn int .
+
+The alignment is machine-specific. It may be more strict than what the
+hardware architecture requires, yet at the same time be smaller than the size
+of the type. For instance, the size of the type
+.code double
+is commonly 8, yet the alignment is often 4, and this is so
+even on processors like Intel x86 which can load and store
+a double at a misaligned address.
+
+The alignment of an array is the same as that of its element type.
+
+The alignment of a structure is that of its member which has the
+most strict (largest-valued) alignment.
+
+It is a property of arrays, derived from requirements governing the C
+language, that if the first element of an array is at a correctly aligned
+address, then all elements are. To ensure that this property holds for
+for arrays of structures, structures sometimes must include
+padding at the end. This is because the size of a structure without any
+padding might not be multiple of its alignment, which is derived from the most
+strictly aligned member. For instance, if we assume an architecture on which
+the size and alignment of
+.code int
+is 4, the size of the structure type
+.code "(struct ab (a int) (b char))"
+would be 5 if no padding were included. However,
+in an array of these structures, the second element's
+.code a
+member would be placed at offset 5, rendering it misaligned.
+To ensure that every
+.code a
+is placed at an offset which is multiple of 4, the struct type is extended
+with anonymous padding so that its size is 8.
+
+.TP* Example:
+
+.cblk
+ (ffi-alignof (ffi double)) -> 4
+.cble
+
+.coNP Function @ ffi-offsetof
+.synb
+.mets (ffi-offsetof < type << member )
+.syne
+.desc
+The
+.code ffi-alignof
+function calculates the byte offset of
+.meta member
+within the FFI type
+.metn type .
+
+If
+.meta type
+isn't a FFI struct type, or if
+.meta member
+isn't a symbol naming a member of that type,
+the function throws an exception.
+
+An exception is also thrown if
+.meta member
+is a bitfield.
+
+.TP* Example:
+
+.cblk
+ (ffi-offsetof (ffi (struct ab (a int) (b char))) 'b) -> 4
+.cble
+
+.coNP Function @ ffi-arraysize
+.synb
+.mets (ffi-arraysize << type )
+.syne
+.desc
+The
+.code ffi-arraysize
+function reports the number of elements in
+.metn type ,
+which must be an array type: an
+.codn array ,
+.code zarray
+or
+.codn carray .
+
+.TP* Example:
+
+.cblk
+ (ffi-arraysize (ffi (array 5 int))) -> 5
+.cble
+
+.coNP Function @ ffi-elemsize
+.synb
+.mets (ffi-elemsize << type )
+.syne
+.desc
+The
+.code ffi-elemsize
+function reports the size of the element type of an array,
+or of the target type of pointer.
+The
+.meta type
+argument must be an array or pointer type: an
+.codn array ,
+.codn zarray ,
+.codn carray ,
+.codn ptr ,
+.code ptr-in
+or
+.codn ptr-out .
+
+.TP* Example:
+
+.cblk
+ (ffi-elemsize (ffi (array 5 int))) -> 4 ;; (sizeof int)
+.cble
+
+.coNP Function @ ffi-elemtype
+.synb
+.mets (ffi-elemtype << type )
+.syne
+.desc
+The
+.code ffi-elemtype
+function retrieves the element type of an array type,
+or target type of a pointer type.
+The
+.meta type
+argument must be an array or pointer type: an
+.codn array ,
+.codn zarray ,
+.codn carray ,
+.codn ptr ,
+.code ptr-in
+or
+.codn ptr-out .
+
+.TP* Example:
+
+.cblk
+ (ffi-elemtype (ffi (ptr int))) -> #<ffi-type int>
+.cble
+
.coNP Macro @ with-dyn-lib
.synb
.mets (with-dyn-lib < lib-expr << body-form *)
@@ -55344,16 +55512,90 @@ as its value.
.desc
The macro
.code sizeof
-compiles the FFI type expression
-.meta type-syntax
-at macro-expansion time using
-.codn ffi-type-compile ,
-and then retrieves the type's size using
-.codn ffi-size .
-The resulting integer is the return value of the
-macro expander. That is to say, the macro expands
-to that integer, such that there is no run-time
-computation.
+calculates the size of the FFI type denoted by
+.code type-syntax
+at macro-expansion time, and produces that
+integer value as its expansion, such that there is no
+run-time computation. It uses the
+.code ffi-sizeof
+function.
+
+.coNP Macro @ alignof
+.synb
+.mets (alignof << type-syntax )
+.syne
+.desc
+The macro
+.code alignof
+calculates the alignment of the FFI type denoted by
+.code type-syntax
+at macro-expansion time, and produces that
+integer value as its expansion, such that there is no
+run-time computation. It uses the
+.code ffi-alignof
+function.
+
+.coNP Macro @ offsetof
+.synb
+.mets (offsetof < type-syntax << member-name )
+.syne
+.desc
+The macro
+.code sizeof
+calculates the offset of the structure member indicated by
+.metn member-name ,
+a symbol, inside the FFI struct type indicated by
+.metn type-syntax .
+This calculation is performed by a macro-expansion-time call to the
+.code ffi-offsetof
+function, and produces that
+integer value as its expansion, such that there is no
+run-time computation.
+
+.coNP Macro @ arraysize
+.synb
+.mets (arraysize << type-syntax )
+.syne
+.desc
+The macro
+.code arraysize
+calculates the number of elements of the array type indicated by
+.metn type-syntax .
+This calculation is performed by a macro-expansion-time call to the
+.code ffi-arraysize
+function, and produces that
+integer value as its expansion, such that there is no
+run-time computation.
+
+.coNP Macro @ elemsize
+.synb
+.mets (elemsize << type-syntax )
+.syne
+.desc
+The macro
+.code elemsize
+calculates the size of the element type of an array type, or
+the size of target type of a pointer type indicated by
+.metn type-syntax .
+This calculation is performed by a macro-expansion-time call to the
+.code ffi-elemsize
+function, and produces that
+integer value as its expansion, such that there is no
+run-time computation.
+
+.coNP Macro @ elemtype
+.synb
+.mets (elemtype << type-syntax )
+.syne
+.desc
+The macro
+.code elemtype
+produce the element type of an array type, or
+the target type of a pointer type indicated by
+.metn type-syntax ,
+using the
+.code ffi-elemsize
+function.
.coNP Macro @ ffi
.synb