summaryrefslogtreecommitdiff
path: root/ext/ffi_c/StructLayout.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/ffi_c/StructLayout.c')
-rw-r--r--ext/ffi_c/StructLayout.c165
1 files changed, 117 insertions, 48 deletions
diff --git a/ext/ffi_c/StructLayout.c b/ext/ffi_c/StructLayout.c
index d318b8c..a56d48f 100644
--- a/ext/ffi_c/StructLayout.c
+++ b/ext/ffi_c/StructLayout.c
@@ -51,9 +51,13 @@
#define FFI_ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1)
-static void struct_layout_mark(StructLayout *);
-static void struct_layout_free(StructLayout *);
-static void struct_field_mark(StructField* );
+static void struct_layout_mark(void *);
+static void struct_layout_compact(void *);
+static void struct_layout_free(void *);
+static size_t struct_layout_memsize(const void *);
+static void struct_field_mark(void *);
+static void struct_field_compact(void *);
+static size_t struct_field_memsize(const void *);
VALUE rbffi_StructLayoutFieldClass = Qnil;
VALUE rbffi_StructLayoutNumberFieldClass = Qnil, rbffi_StructLayoutPointerFieldClass = Qnil;
@@ -62,6 +66,33 @@ VALUE rbffi_StructLayoutFunctionFieldClass = Qnil, rbffi_StructLayoutArrayFieldC
VALUE rbffi_StructLayoutClass = Qnil;
+const rb_data_type_t rbffi_struct_layout_data_type = { /* extern */
+ .wrap_struct_name = "FFI::StructLayout",
+ .function = {
+ .dmark = struct_layout_mark,
+ .dfree = struct_layout_free,
+ .dsize = struct_layout_memsize,
+ ffi_compact_callback( struct_layout_compact )
+ },
+ .parent = &rbffi_type_data_type,
+ // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
+ // macro to update VALUE references, as to trigger write barriers.
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | FFI_RUBY_TYPED_FROZEN_SHAREABLE
+};
+
+const rb_data_type_t rbffi_struct_field_data_type = { /* extern */
+ .wrap_struct_name = "FFI::StructField",
+ .function = {
+ .dmark = struct_field_mark,
+ .dfree = RUBY_TYPED_DEFAULT_FREE,
+ .dsize = struct_field_memsize,
+ ffi_compact_callback( struct_field_compact )
+ },
+ .parent = &rbffi_type_data_type,
+ // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
+ // macro to update VALUE references, as to trigger write barriers.
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | FFI_RUBY_TYPED_FROZEN_SHAREABLE
+};
static VALUE
struct_field_allocate(VALUE klass)
@@ -69,18 +100,33 @@ struct_field_allocate(VALUE klass)
StructField* field;
VALUE obj;
- obj = Data_Make_Struct(klass, StructField, struct_field_mark, -1, field);
- field->rbType = Qnil;
- field->rbName = Qnil;
+ obj = TypedData_Make_Struct(klass, StructField, &rbffi_struct_field_data_type, field);
+ RB_OBJ_WRITE(obj, &field->rbType, Qnil);
+ RB_OBJ_WRITE(obj, &field->rbName, Qnil);
return obj;
}
static void
-struct_field_mark(StructField* f)
+struct_field_mark(void *data)
{
- rb_gc_mark(f->rbType);
- rb_gc_mark(f->rbName);
+ StructField *f = (StructField *)data;
+ rb_gc_mark_movable(f->rbType);
+ rb_gc_mark_movable(f->rbName);
+}
+
+static void
+struct_field_compact(void *data)
+{
+ StructField *f = (StructField *)data;
+ ffi_gc_location(f->rbType);
+ ffi_gc_location(f->rbName);
+}
+
+static size_t
+struct_field_memsize(const void *data)
+{
+ return sizeof(StructField);
}
/*
@@ -98,7 +144,7 @@ struct_field_initialize(int argc, VALUE* argv, VALUE self)
StructField* field;
int nargs;
- Data_Get_Struct(self, StructField, field);
+ TypedData_Get_Struct(self, StructField, &rbffi_struct_field_data_type, field);
nargs = rb_scan_args(argc, argv, "3", &rbName, &rbOffset, &rbType);
@@ -115,9 +161,9 @@ struct_field_initialize(int argc, VALUE* argv, VALUE self)
}
field->offset = NUM2UINT(rbOffset);
- field->rbName = (TYPE(rbName) == T_SYMBOL) ? rbName : rb_str_intern(rbName);
- field->rbType = rbType;
- Data_Get_Struct(field->rbType, Type, field->type);
+ RB_OBJ_WRITE(self, &field->rbName, (TYPE(rbName) == T_SYMBOL) ? rbName : rb_str_intern(rbName));
+ RB_OBJ_WRITE(self, &field->rbType, rbType);
+ TypedData_Get_Struct(field->rbType, Type, &rbffi_type_data_type, field->type);
field->memoryOp = get_memory_op(field->type);
field->referenceIndex = -1;
@@ -135,6 +181,8 @@ struct_field_initialize(int argc, VALUE* argv, VALUE self)
break;
}
+ rb_obj_freeze(self);
+
return self;
}
@@ -147,7 +195,7 @@ static VALUE
struct_field_offset(VALUE self)
{
StructField* field;
- Data_Get_Struct(self, StructField, field);
+ TypedData_Get_Struct(self, StructField, &rbffi_struct_field_data_type, field);
return UINT2NUM(field->offset);
}
@@ -160,7 +208,7 @@ static VALUE
struct_field_size(VALUE self)
{
StructField* field;
- Data_Get_Struct(self, StructField, field);
+ TypedData_Get_Struct(self, StructField, &rbffi_struct_field_data_type, field);
return UINT2NUM(field->type->ffiType->size);
}
@@ -173,7 +221,7 @@ static VALUE
struct_field_alignment(VALUE self)
{
StructField* field;
- Data_Get_Struct(self, StructField, field);
+ TypedData_Get_Struct(self, StructField, &rbffi_struct_field_data_type, field);
return UINT2NUM(field->type->ffiType->alignment);
}
@@ -186,7 +234,7 @@ static VALUE
struct_field_type(VALUE self)
{
StructField* field;
- Data_Get_Struct(self, StructField, field);
+ TypedData_Get_Struct(self, StructField, &rbffi_struct_field_data_type, field);
return field->rbType;
}
@@ -200,7 +248,7 @@ static VALUE
struct_field_name(VALUE self)
{
StructField* field;
- Data_Get_Struct(self, StructField, field);
+ TypedData_Get_Struct(self, StructField, &rbffi_struct_field_data_type, field);
return field->rbName;
}
@@ -215,7 +263,7 @@ struct_field_get(VALUE self, VALUE pointer)
{
StructField* f;
- Data_Get_Struct(self, StructField, f);
+ TypedData_Get_Struct(self, StructField, &rbffi_struct_field_data_type, f);
if (f->memoryOp == NULL) {
rb_raise(rb_eArgError, "get not supported for %s", rb_obj_classname(f->rbType));
return Qnil;
@@ -236,7 +284,7 @@ struct_field_put(VALUE self, VALUE pointer, VALUE value)
{
StructField* f;
- Data_Get_Struct(self, StructField, f);
+ TypedData_Get_Struct(self, StructField, &rbffi_struct_field_data_type, f);
if (f->memoryOp == NULL) {
rb_raise(rb_eArgError, "put not supported for %s", rb_obj_classname(f->rbType));
return self;
@@ -258,7 +306,7 @@ function_field_get(VALUE self, VALUE pointer)
{
StructField* f;
- Data_Get_Struct(self, StructField, f);
+ TypedData_Get_Struct(self, StructField, &rbffi_struct_field_data_type, f);
return rbffi_Function_NewInstance(f->rbType, (*rbffi_AbstractMemoryOps.pointer->get)(MEMORY(pointer), f->offset));
}
@@ -278,7 +326,7 @@ function_field_put(VALUE self, VALUE pointer, VALUE proc)
StructField* f;
VALUE value = Qnil;
- Data_Get_Struct(self, StructField, f);
+ TypedData_Get_Struct(self, StructField, &rbffi_struct_field_data_type, f);
if (NIL_P(proc) || rb_obj_is_kind_of(proc, rbffi_FunctionClass)) {
value = proc;
@@ -313,8 +361,8 @@ array_field_get(VALUE self, VALUE pointer)
ArrayType* array;
VALUE argv[2];
- Data_Get_Struct(self, StructField, f);
- Data_Get_Struct(f->rbType, ArrayType, array);
+ TypedData_Get_Struct(self, StructField, &rbffi_struct_field_data_type, f);
+ TypedData_Get_Struct(f->rbType, ArrayType, &rbffi_array_type_data_type, array);
argv[0] = pointer;
argv[1] = self;
@@ -336,9 +384,8 @@ array_field_put(VALUE self, VALUE pointer, VALUE value)
StructField* f;
ArrayType* array;
-
- Data_Get_Struct(self, StructField, f);
- Data_Get_Struct(f->rbType, ArrayType, array);
+ TypedData_Get_Struct(self, StructField, &rbffi_struct_field_data_type, f);
+ TypedData_Get_Struct(f->rbType, ArrayType, &rbffi_array_type_data_type, array);
if (isCharArray(array) && rb_obj_is_instance_of(value, rb_cString)) {
VALUE argv[2];
@@ -385,12 +432,8 @@ array_field_put(VALUE self, VALUE pointer, VALUE value)
VALUE entry = rb_ary_entry(value, i);
Struct* s;
- if (!rb_obj_is_kind_of(entry, rbffi_StructClass)) {
- rb_raise(rb_eTypeError, "array element not an instance of FFI::Struct");
- break;
- }
+ TypedData_Get_Struct(entry, Struct, &rbffi_struct_data_type, s);
- Data_Get_Struct(entry, Struct, s);
checkRead(s->pointer);
checkBounds(s->pointer, 0, array->componentType->ffiType->size);
@@ -416,7 +459,7 @@ struct_layout_allocate(VALUE klass)
StructLayout* layout;
VALUE obj;
- obj = Data_Make_Struct(klass, StructLayout, struct_layout_mark, struct_layout_free, layout);
+ obj = TypedData_Make_Struct(klass, StructLayout, &rbffi_struct_layout_data_type, layout);
layout->rbFieldMap = Qnil;
layout->rbFieldNames = Qnil;
layout->rbFields = Qnil;
@@ -443,7 +486,7 @@ struct_layout_initialize(VALUE self, VALUE fields, VALUE size, VALUE align)
ffi_type* ltype;
int i;
- Data_Get_Struct(self, StructLayout, layout);
+ TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout);
layout->fieldCount = (int) RARRAY_LEN(fields);
layout->rbFieldMap = rb_hash_new();
layout->rbFieldNames = rb_ary_new2(layout->fieldCount);
@@ -470,7 +513,7 @@ struct_layout_initialize(VALUE self, VALUE fields, VALUE size, VALUE align)
}
rbName = rb_funcall2(rbField, rb_intern("name"), 0, NULL);
- Data_Get_Struct(rbField, StructField, field);
+ TypedData_Get_Struct(rbField, StructField, &rbffi_struct_field_data_type, field);
layout->fields[i] = field;
if (field->type == NULL || field->type->ffiType == NULL) {
@@ -497,6 +540,11 @@ struct_layout_initialize(VALUE self, VALUE fields, VALUE size, VALUE align)
rb_raise(rb_eRuntimeError, "Struct size is zero");
}
+ rb_obj_freeze(layout->rbFieldMap);
+ rb_obj_freeze(layout->rbFields);
+ rb_obj_freeze(layout->rbFieldNames);
+ rb_obj_freeze(self);
+
return self;
}
@@ -515,7 +563,7 @@ struct_layout_union_bang(VALUE self)
ffi_type *t = NULL;
int count, i;
- Data_Get_Struct(self, StructLayout, layout);
+ TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout);
for (i = 0; alignment_types[i] != NULL; ++i) {
if (alignment_types[i]->alignment == layout->align) {
@@ -545,7 +593,7 @@ struct_layout_aref(VALUE self, VALUE field)
{
StructLayout* layout;
- Data_Get_Struct(self, StructLayout, layout);
+ TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout);
return rb_hash_aref(layout->rbFieldMap, field);
}
@@ -560,7 +608,7 @@ struct_layout_fields(VALUE self)
{
StructLayout* layout;
- Data_Get_Struct(self, StructLayout, layout);
+ TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout);
return rb_ary_dup(layout->rbFields);
}
@@ -575,7 +623,7 @@ struct_layout_members(VALUE self)
{
StructLayout* layout;
- Data_Get_Struct(self, StructLayout, layout);
+ TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout);
return rb_ary_dup(layout->rbFieldNames);
}
@@ -590,26 +638,37 @@ struct_layout_to_a(VALUE self)
{
StructLayout* layout;
- Data_Get_Struct(self, StructLayout, layout);
+ TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout);
return rb_ary_dup(layout->rbFields);
}
static void
-struct_layout_mark(StructLayout *layout)
+struct_layout_mark(void *data)
{
- rb_gc_mark(layout->rbFieldMap);
- rb_gc_mark(layout->rbFieldNames);
- rb_gc_mark(layout->rbFields);
- /* Clear the cache, to be safe from changes of fieldName VALUE by GC.compact.
- * TODO: Move cache clearing to compactation callback provided by Ruby-2.7+.
- */
+ StructLayout *layout = (StructLayout *)data;
+ rb_gc_mark_movable(layout->rbFieldMap);
+ rb_gc_mark_movable(layout->rbFieldNames);
+ rb_gc_mark_movable(layout->rbFields);
+ /* The values stored in layout->cache_row.fieldName are primary stored in layout->rbFieldMap and are marked there */
+}
+
+static void
+struct_layout_compact(void *data)
+{
+ StructLayout *layout = (StructLayout *)data;
+ ffi_gc_location(layout->rbFieldMap);
+ ffi_gc_location(layout->rbFieldNames);
+ ffi_gc_location(layout->rbFields);
+
+ /* Clear the cache, to be safe from changes of fieldName VALUE by GC.compact */
memset(&layout->cache_row, 0, sizeof(layout->cache_row));
}
static void
-struct_layout_free(StructLayout *layout)
+struct_layout_free(void *data)
{
+ StructLayout *layout = (StructLayout *)data;
xfree(layout->ffiTypes);
xfree(layout->base.ffiType);
xfree(layout->fields);
@@ -617,6 +676,16 @@ struct_layout_free(StructLayout *layout)
}
+static size_t
+struct_layout_memsize(const void * data)
+{
+ const StructLayout *layout = (const StructLayout *)data;
+ size_t memsize = sizeof(StructLayout);
+ memsize += layout->fieldCount * (sizeof(StructField *) + sizeof(ffi_type *));
+ memsize += sizeof(*layout->base.ffiType);
+ return memsize;
+}
+
void
rbffi_StructLayout_Init(VALUE moduleFFI)
{