mirror of
https://github.com/janet-lang/janet
synced 2024-12-01 04:19:55 +00:00
Add :pack and :pack-all keywords to allow for struct packing.
Syntax may need some work but covers both fully packed structs as well as packing of individual members.
This commit is contained in:
parent
33bb08d53b
commit
181f0341f5
@ -84,11 +84,17 @@ struct JanetFFIType {
|
|||||||
JanetFFIPrimType prim;
|
JanetFFIPrimType prim;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
JanetFFIType type;
|
||||||
|
size_t offset;
|
||||||
|
} JanetFFIStructMember;
|
||||||
|
|
||||||
struct JanetFFIStruct {
|
struct JanetFFIStruct {
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint32_t align;
|
uint32_t align;
|
||||||
uint32_t field_count;
|
uint32_t field_count;
|
||||||
JanetFFIType fields[];
|
uint32_t is_aligned;
|
||||||
|
JanetFFIStructMember fields[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Specifies how the registers are classified. This is used
|
/* Specifies how the registers are classified. This is used
|
||||||
@ -153,7 +159,7 @@ int struct_mark(void *p, size_t s) {
|
|||||||
(void) s;
|
(void) s;
|
||||||
JanetFFIStruct *st = p;
|
JanetFFIStruct *st = p;
|
||||||
for (uint32_t i = 0; i < st->field_count; i++) {
|
for (uint32_t i = 0; i < st->field_count; i++) {
|
||||||
JanetFFIType t = st->fields[i];
|
JanetFFIType t = st->fields[i].type;
|
||||||
if (t.prim == JANET_FFI_TYPE_STRUCT) {
|
if (t.prim == JANET_FFI_TYPE_STRUCT) {
|
||||||
janet_mark(janet_wrap_abstract(t.st));
|
janet_mark(janet_wrap_abstract(t.st));
|
||||||
}
|
}
|
||||||
@ -243,18 +249,50 @@ static JanetFFIPrimType decode_ffi_prim(const uint8_t *name) {
|
|||||||
static JanetFFIType decode_ffi_type(Janet x);
|
static JanetFFIType decode_ffi_type(Janet x);
|
||||||
|
|
||||||
static JanetFFIStruct *build_struct_type(int32_t argc, const Janet *argv) {
|
static JanetFFIStruct *build_struct_type(int32_t argc, const Janet *argv) {
|
||||||
|
/* Use :pack to indicate a single packed struct member and :pack-all
|
||||||
|
* to pack the remaining members */
|
||||||
|
int32_t member_count = argc;
|
||||||
|
int all_packed = 0;
|
||||||
|
for (int32_t i = 0; i < argc; i++) {
|
||||||
|
if (janet_keyeq(argv[i], "pack")) {
|
||||||
|
member_count--;
|
||||||
|
} else if (janet_keyeq(argv[i], "pack-all")) {
|
||||||
|
member_count--;
|
||||||
|
all_packed = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JanetFFIStruct *st = janet_abstract(&janet_struct_type,
|
JanetFFIStruct *st = janet_abstract(&janet_struct_type,
|
||||||
sizeof(JanetFFIStruct) + argc * sizeof(JanetFFIType));
|
sizeof(JanetFFIStruct) + argc * sizeof(JanetFFIStructMember));
|
||||||
st->field_count = argc;
|
st->field_count = member_count;
|
||||||
st->size = 0;
|
st->size = 0;
|
||||||
st->align = 1;
|
st->align = 1;
|
||||||
for (int32_t i = 0; i < argc; i++) {
|
if (argc == 0) {
|
||||||
st->fields[i] = decode_ffi_type(argv[i]);
|
janet_panic("invalid empty struct");
|
||||||
size_t el_align = type_align(st->fields[i]);
|
|
||||||
size_t el_size = type_size(st->fields[i]);
|
|
||||||
if (el_align > st->align) st->align = el_align;
|
|
||||||
st->size = el_size + (((st->size + el_align - 1) / el_align) * el_align);
|
|
||||||
}
|
}
|
||||||
|
uint32_t is_aligned = 1;
|
||||||
|
int32_t i = 0;
|
||||||
|
for (int32_t j = 0; j < argc; j++) {
|
||||||
|
int pack_one = 0;
|
||||||
|
if (janet_keyeq(argv[j], "pack") || janet_keyeq(argv[j], "pack-all")) {
|
||||||
|
pack_one = 1;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
st->fields[i].type = decode_ffi_type(argv[j]);
|
||||||
|
size_t el_size = type_size(st->fields[i].type);
|
||||||
|
size_t el_align = type_align(st->fields[i].type);
|
||||||
|
if (all_packed || pack_one) {
|
||||||
|
if (st->size % el_align != 0) is_aligned = 0;
|
||||||
|
st->fields[i].offset = st->size;
|
||||||
|
st->size += el_size;
|
||||||
|
} else {
|
||||||
|
if (el_align > st->align) st->align = el_align;
|
||||||
|
st->fields[i].offset = (((st->size + el_align - 1) / el_align) * el_align);
|
||||||
|
st->size = el_size + st->fields[i].offset;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
st->is_aligned = is_aligned;
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,19 +349,14 @@ static void janet_ffi_write_one(void *to, const Janet *argv, int32_t n, JanetFFI
|
|||||||
break;
|
break;
|
||||||
case JANET_FFI_TYPE_STRUCT: {
|
case JANET_FFI_TYPE_STRUCT: {
|
||||||
JanetView els = janet_getindexed(argv, n);
|
JanetView els = janet_getindexed(argv, n);
|
||||||
uint32_t cursor = 0;
|
|
||||||
JanetFFIStruct *st = type.st;
|
JanetFFIStruct *st = type.st;
|
||||||
if ((uint32_t) els.len != st->field_count) {
|
if ((uint32_t) els.len != st->field_count) {
|
||||||
janet_panicf("wrong number of fields in struct, expected %d, got %d",
|
janet_panicf("wrong number of fields in struct, expected %d, got %d",
|
||||||
(int32_t) st->field_count, els.len);
|
(int32_t) st->field_count, els.len);
|
||||||
}
|
}
|
||||||
for (int32_t i = 0; i < els.len; i++) {
|
for (int32_t i = 0; i < els.len; i++) {
|
||||||
JanetFFIType tp = st->fields[i];
|
JanetFFIType tp = st->fields[i].type;
|
||||||
size_t align = type_align(tp);
|
janet_ffi_write_one(to + st->fields[i].offset, els.items, i, tp, recur - 1);
|
||||||
size_t size = type_size(tp);
|
|
||||||
cursor = ((cursor + align - 1) / align) * align;
|
|
||||||
janet_ffi_write_one(to + cursor, els.items, i, tp, recur - 1);
|
|
||||||
cursor += size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -378,14 +411,9 @@ static Janet janet_ffi_read_one(const uint8_t *from, JanetFFIType type, int recu
|
|||||||
case JANET_FFI_TYPE_STRUCT: {
|
case JANET_FFI_TYPE_STRUCT: {
|
||||||
JanetFFIStruct *st = type.st;
|
JanetFFIStruct *st = type.st;
|
||||||
Janet *tup = janet_tuple_begin(st->field_count);
|
Janet *tup = janet_tuple_begin(st->field_count);
|
||||||
size_t cursor = 0;
|
|
||||||
for (uint32_t i = 0; i < st->field_count; i++) {
|
for (uint32_t i = 0; i < st->field_count; i++) {
|
||||||
JanetFFIType tp = st->fields[i];
|
JanetFFIType tp = st->fields[i].type;
|
||||||
size_t align = type_align(tp);
|
tup[i] = janet_ffi_read_one(from + st->fields[i].offset, tp, recur - 1);
|
||||||
size_t size = type_size(tp);
|
|
||||||
cursor = ((cursor + align - 1) / align) * align;
|
|
||||||
tup[i] = janet_ffi_read_one(from + cursor, tp, recur - 1);
|
|
||||||
cursor += size;
|
|
||||||
}
|
}
|
||||||
return janet_wrap_tuple(janet_tuple_end(tup));
|
return janet_wrap_tuple(janet_tuple_end(tup));
|
||||||
}
|
}
|
||||||
@ -452,9 +480,10 @@ static JanetFFIWordSpec sysv64_classify(JanetFFIType type) {
|
|||||||
case JANET_FFI_TYPE_STRUCT: {
|
case JANET_FFI_TYPE_STRUCT: {
|
||||||
JanetFFIStruct *st = type.st;
|
JanetFFIStruct *st = type.st;
|
||||||
if (st->size > 16) return JANET_SYSV64_MEMORY;
|
if (st->size > 16) return JANET_SYSV64_MEMORY;
|
||||||
|
if (!st->is_aligned) return JANET_SYSV64_MEMORY;
|
||||||
JanetFFIWordSpec clazz = JANET_SYSV64_NO_CLASS;
|
JanetFFIWordSpec clazz = JANET_SYSV64_NO_CLASS;
|
||||||
for (uint32_t i = 0; i < st->field_count; i++) {
|
for (uint32_t i = 0; i < st->field_count; i++) {
|
||||||
JanetFFIWordSpec next_class = sysv64_classify(st->fields[i]);
|
JanetFFIWordSpec next_class = sysv64_classify(st->fields[i].type);
|
||||||
if (next_class != clazz) {
|
if (next_class != clazz) {
|
||||||
if (clazz == JANET_SYSV64_NO_CLASS) {
|
if (clazz == JANET_SYSV64_NO_CLASS) {
|
||||||
clazz = next_class;
|
clazz = next_class;
|
||||||
|
Loading…
Reference in New Issue
Block a user