diff options
-rw-r--r-- | ffi.c | 74 | ||||
-rw-r--r-- | ffi.h | 5 | ||||
-rw-r--r-- | lisplib.c | 5 | ||||
-rw-r--r-- | share/txr/stdlib/ffi.tl | 15 | ||||
-rw-r--r-- | txr.1 | 262 |
5 files changed, 349 insertions, 12 deletions
@@ -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)); @@ -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); @@ -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)) @@ -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 |