summaryrefslogtreecommitdiff
path: root/ext/ffi_c/Struct.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/ffi_c/Struct.c')
-rw-r--r--ext/ffi_c/Struct.c231
1 files changed, 151 insertions, 80 deletions
diff --git a/ext/ffi_c/Struct.c b/ext/ffi_c/Struct.c
index 92731c8..0fdba71 100644
--- a/ext/ffi_c/Struct.c
+++ b/ext/ffi_c/Struct.c
@@ -61,13 +61,29 @@ typedef struct InlineArray_ {
} InlineArray;
-static void struct_mark(Struct *);
-static void struct_free(Struct *);
+static void struct_mark(void *data);
+static void struct_compact(void *data);
+static void struct_free(void *data);
+static size_t struct_memsize(const void *);
static VALUE struct_class_layout(VALUE klass);
-static void struct_malloc(Struct* s);
-static void inline_array_mark(InlineArray *);
-static void store_reference_value(StructField* f, Struct* s, VALUE value);
-
+static void struct_malloc(VALUE self, Struct* s);
+static void inline_array_mark(void *);
+static void inline_array_compact(void *);
+static size_t inline_array_memsize(const void *);
+static void store_reference_value(VALUE self, StructField* f, Struct* s, VALUE value);
+
+const rb_data_type_t rbffi_struct_data_type = { /* extern */
+ .wrap_struct_name = "FFI::Struct",
+ .function = {
+ .dmark = struct_mark,
+ .dfree = struct_free,
+ .dsize = struct_memsize,
+ ffi_compact_callback( struct_compact )
+ },
+ // 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
+};
VALUE rbffi_StructClass = Qnil;
VALUE rbffi_StructInlineArrayClass = Qnil;
@@ -79,17 +95,19 @@ static ID id_get = 0, id_put = 0, id_to_ptr = 0, id_to_s = 0, id_layout = 0;
static inline char*
memory_address(VALUE self)
{
- return ((AbstractMemory *)DATA_PTR((self)))->address;
+ AbstractMemory *mem;
+ TypedData_Get_Struct(self, AbstractMemory, &rbffi_abstract_memory_data_type, mem);
+ return mem->address;
}
static VALUE
struct_allocate(VALUE klass)
{
Struct* s;
- VALUE obj = Data_Make_Struct(klass, Struct, struct_mark, struct_free, s);
+ VALUE obj = TypedData_Make_Struct(klass, Struct, &rbffi_struct_data_type, s);
- s->rbPointer = Qnil;
- s->rbLayout = Qnil;
+ RB_OBJ_WRITE(obj, &s->rbPointer, Qnil);
+ RB_OBJ_WRITE(obj, &s->rbLayout, Qnil);
return obj;
}
@@ -108,28 +126,29 @@ struct_initialize(int argc, VALUE* argv, VALUE self)
VALUE rbPointer = Qnil, rest = Qnil, klass = CLASS_OF(self);
int nargs;
- Data_Get_Struct(self, Struct, s);
+ TypedData_Get_Struct(self, Struct, &rbffi_struct_data_type, s);
nargs = rb_scan_args(argc, argv, "01*", &rbPointer, &rest);
/* Call up into ruby code to adjust the layout */
if (nargs > 1) {
- s->rbLayout = rb_funcall2(CLASS_OF(self), id_layout, (int) RARRAY_LEN(rest), RARRAY_PTR(rest));
+ VALUE rbLayout = rb_apply(CLASS_OF(self), id_layout, rest);
+ RB_OBJ_WRITE(self, &s->rbLayout, rbLayout);
} else {
- s->rbLayout = struct_class_layout(klass);
+ RB_OBJ_WRITE(self, &s->rbLayout, struct_class_layout(klass));
}
if (!rb_obj_is_kind_of(s->rbLayout, rbffi_StructLayoutClass)) {
rb_raise(rb_eRuntimeError, "Invalid Struct layout");
}
- Data_Get_Struct(s->rbLayout, StructLayout, s->layout);
+ TypedData_Get_Struct(s->rbLayout, StructLayout, &rbffi_struct_layout_data_type, s->layout);
if (rbPointer != Qnil) {
s->pointer = MEMORY(rbPointer);
- s->rbPointer = rbPointer;
+ RB_OBJ_WRITE(self, &s->rbPointer, rbPointer);
} else {
- struct_malloc(s);
+ struct_malloc(self, s);
}
return self;
@@ -146,13 +165,13 @@ struct_initialize_copy(VALUE self, VALUE other)
Struct* src;
Struct* dst;
- Data_Get_Struct(self, Struct, dst);
- Data_Get_Struct(other, Struct, src);
+ TypedData_Get_Struct(self, Struct, &rbffi_struct_data_type, dst);
+ TypedData_Get_Struct(other, Struct, &rbffi_struct_data_type, src);
if (dst == src) {
return self;
}
- dst->rbLayout = src->rbLayout;
+ RB_OBJ_WRITE(self, &dst->rbLayout, src->rbLayout);
dst->layout = src->layout;
/*
@@ -161,17 +180,20 @@ struct_initialize_copy(VALUE self, VALUE other)
* be longer than just this struct.
*/
if (src->pointer->address != NULL) {
- dst->rbPointer = rbffi_MemoryPointer_NewInstance(1, src->layout->size, false);
+ RB_OBJ_WRITE(self, &dst->rbPointer, rbffi_MemoryPointer_NewInstance(1, src->layout->size, false));
dst->pointer = MEMORY(dst->rbPointer);
memcpy(dst->pointer->address, src->pointer->address, src->layout->size);
} else {
- dst->rbPointer = src->rbPointer;
+ RB_OBJ_WRITE(self, &dst->rbPointer, src->rbPointer);
dst->pointer = src->pointer;
}
if (src->layout->referenceFieldCount > 0) {
dst->rbReferences = ALLOC_N(VALUE, dst->layout->referenceFieldCount);
memcpy(dst->rbReferences, src->rbReferences, dst->layout->referenceFieldCount * sizeof(VALUE));
+ for (size_t index = 0; index < dst->layout->referenceFieldCount; index++) {
+ RB_OBJ_WRITTEN(self, Qundef, &dst->rbReferences[index]);
+ }
}
return self;
@@ -196,14 +218,15 @@ struct_class_layout(VALUE klass)
static StructLayout*
struct_layout(VALUE self)
{
- Struct* s = (Struct *) DATA_PTR(self);
+ Struct* s;
+ TypedData_Get_Struct(self, Struct, &rbffi_struct_data_type, s);
if (s->layout != NULL) {
return s->layout;
}
if (s->layout == NULL) {
- s->rbLayout = struct_class_layout(CLASS_OF(self));
- Data_Get_Struct(s->rbLayout, StructLayout, s->layout);
+ RB_OBJ_WRITE(self, &s->rbLayout, struct_class_layout(CLASS_OF(self)));
+ TypedData_Get_Struct(s->rbLayout, StructLayout, &rbffi_struct_layout_data_type, s->layout);
}
return s->layout;
@@ -213,52 +236,74 @@ static Struct*
struct_validate(VALUE self)
{
Struct* s;
- Data_Get_Struct(self, Struct, s);
+ TypedData_Get_Struct(self, Struct, &rbffi_struct_data_type, s);
if (struct_layout(self) == NULL) {
rb_raise(rb_eRuntimeError, "struct layout == null");
}
if (s->pointer == NULL) {
- struct_malloc(s);
+ struct_malloc(self, s);
}
return s;
}
static void
-struct_malloc(Struct* s)
+struct_malloc(VALUE self, Struct* s)
{
if (s->rbPointer == Qnil) {
- s->rbPointer = rbffi_MemoryPointer_NewInstance(s->layout->size, 1, true);
-
+ RB_OBJ_WRITE(self, &s->rbPointer, rbffi_MemoryPointer_NewInstance(s->layout->size, 1, true));
} else if (!rb_obj_is_kind_of(s->rbPointer, rbffi_AbstractMemoryClass)) {
rb_raise(rb_eRuntimeError, "invalid pointer in struct");
}
- s->pointer = (AbstractMemory *) DATA_PTR(s->rbPointer);
+ TypedData_Get_Struct(s->rbPointer, AbstractMemory, &rbffi_abstract_memory_data_type, s->pointer);
+}
+
+static void
+struct_mark(void *data)
+{
+ Struct *s = (Struct *)data;
+ rb_gc_mark_movable(s->rbPointer);
+ rb_gc_mark_movable(s->rbLayout);
+ if (s->rbReferences != NULL) {
+ for (size_t index = 0; index < s->layout->referenceFieldCount; index++) {
+ rb_gc_mark_movable(s->rbReferences[index]);
+ }
+ }
}
static void
-struct_mark(Struct *s)
+struct_compact(void *data)
{
- rb_gc_mark(s->rbPointer);
- rb_gc_mark(s->rbLayout);
+ Struct *s = (Struct *)data;
+ ffi_gc_location(s->rbPointer);
+ ffi_gc_location(s->rbLayout);
if (s->rbReferences != NULL) {
- rb_gc_mark_locations(&s->rbReferences[0], &s->rbReferences[s->layout->referenceFieldCount]);
+ for (size_t index = 0; index < s->layout->referenceFieldCount; index++) {
+ ffi_gc_location(s->rbReferences[index]);
+ }
}
}
static void
-struct_free(Struct* s)
+struct_free(void *data)
{
+ Struct *s = (Struct *)data;
xfree(s->rbReferences);
xfree(s);
}
+static size_t
+struct_memsize(const void *data)
+{
+ const Struct *s = (const Struct *)data;
+ return sizeof(Struct) + (s->layout->referenceFieldCount * sizeof(VALUE));
+}
static void
-store_reference_value(StructField* f, Struct* s, VALUE value)
+store_reference_value(VALUE self, StructField* f, Struct* s, VALUE value)
{
if (unlikely(f->referenceIndex == -1)) {
rb_raise(rb_eRuntimeError, "put_reference_value called for non-reference type");
@@ -268,11 +313,11 @@ store_reference_value(StructField* f, Struct* s, VALUE value)
int i;
s->rbReferences = ALLOC_N(VALUE, s->layout->referenceFieldCount);
for (i = 0; i < s->layout->referenceFieldCount; ++i) {
- s->rbReferences[i] = Qnil;
+ RB_OBJ_WRITE(self, &s->rbReferences[i], Qnil);
}
}
- s->rbReferences[f->referenceIndex] = value;
+ RB_OBJ_WRITE(self, &s->rbReferences[f->referenceIndex], value);
}
@@ -290,8 +335,8 @@ struct_field(Struct* s, VALUE fieldName)
rb_raise(rb_eArgError, "No such field '%s'", StringValueCStr(str));
}
/* Write the retrieved coder to the cache */
- p_ce->fieldName = fieldName;
- p_ce->field = (StructField *) DATA_PTR(rbField);
+ RB_OBJ_WRITE(s->rbLayout, &p_ce->fieldName, fieldName);
+ TypedData_Get_Struct(rbField, StructField, &rbffi_struct_field_data_type, p_ce->field);
}
return p_ce->field;
@@ -311,10 +356,7 @@ struct_aref(VALUE self, VALUE fieldName)
s = struct_validate(self);
f = struct_field(s, fieldName);
- if (f->get != NULL) {
- return (*f->get)(f, s);
-
- } else if (f->memoryOp != NULL) {
+ if (f->memoryOp != NULL) {
return (*f->memoryOp->get)(s->pointer, f->offset);
} else {
@@ -337,13 +379,11 @@ struct_aset(VALUE self, VALUE fieldName, VALUE value)
Struct* s;
StructField* f;
+ rb_check_frozen(self);
s = struct_validate(self);
f = struct_field(s, fieldName);
- if (f->put != NULL) {
- (*f->put)(f, s, value);
-
- } else if (f->memoryOp != NULL) {
+ if (f->memoryOp != NULL) {
(*f->memoryOp->put)(s->pointer, f->offset, value);
@@ -357,7 +397,7 @@ struct_aset(VALUE self, VALUE fieldName, VALUE value)
}
if (f->referenceRequired) {
- store_reference_value(f, s, value);
+ store_reference_value(self, f, s, value);
}
return value;
@@ -376,6 +416,7 @@ struct_set_pointer(VALUE self, VALUE pointer)
StructLayout* layout;
AbstractMemory* memory;
+ rb_check_frozen(self);
if (!rb_obj_is_kind_of(pointer, rbffi_AbstractMemoryClass)) {
rb_raise(rb_eTypeError, "wrong argument type %s (expected Pointer or Buffer)",
rb_obj_classname(pointer));
@@ -383,8 +424,8 @@ struct_set_pointer(VALUE self, VALUE pointer)
}
- Data_Get_Struct(self, Struct, s);
- Data_Get_Struct(pointer, AbstractMemory, memory);
+ TypedData_Get_Struct(self, Struct, &rbffi_struct_data_type, s);
+ TypedData_Get_Struct(pointer, AbstractMemory, &rbffi_abstract_memory_data_type, memory);
layout = struct_layout(self);
if ((int) layout->base.ffiType->size > memory->size) {
@@ -393,7 +434,7 @@ struct_set_pointer(VALUE self, VALUE pointer)
}
s->pointer = MEMORY(pointer);
- s->rbPointer = pointer;
+ RB_OBJ_WRITE(self, &s->rbPointer, pointer);
rb_ivar_set(self, id_pointer_ivar, pointer);
return self;
@@ -409,7 +450,7 @@ struct_get_pointer(VALUE self)
{
Struct* s;
- Data_Get_Struct(self, Struct, s);
+ TypedData_Get_Struct(self, Struct, &rbffi_struct_data_type, s);
return s->rbPointer;
}
@@ -424,15 +465,16 @@ static VALUE
struct_set_layout(VALUE self, VALUE layout)
{
Struct* s;
- Data_Get_Struct(self, Struct, s);
+ TypedData_Get_Struct(self, Struct, &rbffi_struct_data_type, s);
+ rb_check_frozen(self);
if (!rb_obj_is_kind_of(layout, rbffi_StructLayoutClass)) {
rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)",
rb_obj_classname(layout), rb_class2name(rbffi_StructLayoutClass));
return Qnil;
}
- Data_Get_Struct(layout, StructLayout, s->layout);
+ TypedData_Get_Struct(layout, StructLayout, &rbffi_struct_layout_data_type, s->layout);
rb_ivar_set(self, id_layout_ivar, layout);
return self;
@@ -448,7 +490,7 @@ struct_get_layout(VALUE self)
{
Struct* s;
- Data_Get_Struct(self, Struct, s);
+ TypedData_Get_Struct(self, Struct, &rbffi_struct_data_type, s);
return s->rbLayout;
}
@@ -463,7 +505,7 @@ struct_null_p(VALUE self)
{
Struct* s;
- Data_Get_Struct(self, Struct, s);
+ TypedData_Get_Struct(self, Struct, &rbffi_struct_data_type, s);
return s->pointer->address == NULL ? Qtrue : Qfalse;
}
@@ -476,7 +518,7 @@ struct_order(int argc, VALUE* argv, VALUE self)
{
Struct* s;
- Data_Get_Struct(self, Struct, s);
+ TypedData_Get_Struct(self, Struct, &rbffi_struct_data_type, s);
if (argc == 0) {
return rb_funcall(s->rbPointer, rb_intern("order"), 0);
@@ -489,24 +531,52 @@ struct_order(int argc, VALUE* argv, VALUE self)
}
}
+static const rb_data_type_t inline_array_data_type = {
+ .wrap_struct_name = "FFI::Struct::InlineArray",
+ .function = {
+ .dmark = inline_array_mark,
+ .dfree = RUBY_TYPED_DEFAULT_FREE,
+ .dsize = inline_array_memsize,
+ ffi_compact_callback( inline_array_compact )
+ },
+ // 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
inline_array_allocate(VALUE klass)
{
InlineArray* array;
VALUE obj;
- obj = Data_Make_Struct(klass, InlineArray, inline_array_mark, -1, array);
- array->rbField = Qnil;
- array->rbMemory = Qnil;
+ obj = TypedData_Make_Struct(klass, InlineArray, &inline_array_data_type, array);
+ RB_OBJ_WRITE(obj, &array->rbMemory, Qnil);
+ RB_OBJ_WRITE(obj, &array->rbField, Qnil);
return obj;
}
static void
-inline_array_mark(InlineArray* array)
+inline_array_mark(void *data)
+{
+ InlineArray *array = (InlineArray *)data;
+ rb_gc_mark_movable(array->rbField);
+ rb_gc_mark_movable(array->rbMemory);
+}
+
+static void
+inline_array_compact(void *data)
+{
+ InlineArray *array = (InlineArray *)data;
+ ffi_gc_location(array->rbField);
+ ffi_gc_location(array->rbMemory);
+}
+
+static size_t
+inline_array_memsize(const void *data)
{
- rb_gc_mark(array->rbField);
- rb_gc_mark(array->rbMemory);
+ return sizeof(InlineArray);
}
/*
@@ -521,14 +591,14 @@ inline_array_initialize(VALUE self, VALUE rbMemory, VALUE rbField)
{
InlineArray* array;
- Data_Get_Struct(self, InlineArray, array);
- array->rbMemory = rbMemory;
- array->rbField = rbField;
+ TypedData_Get_Struct(self, InlineArray, &inline_array_data_type, array);
+ RB_OBJ_WRITE(self, &array->rbMemory, rbMemory);
+ RB_OBJ_WRITE(self, &array->rbField, rbField);
- Data_Get_Struct(rbMemory, AbstractMemory, array->memory);
- Data_Get_Struct(rbField, StructField, array->field);
- Data_Get_Struct(array->field->rbType, ArrayType, array->arrayType);
- Data_Get_Struct(array->arrayType->rbComponentType, Type, array->componentType);
+ TypedData_Get_Struct(rbMemory, AbstractMemory, &rbffi_abstract_memory_data_type, array->memory);
+ TypedData_Get_Struct(rbField, StructField, &rbffi_struct_field_data_type, array->field);
+ TypedData_Get_Struct(array->field->rbType, ArrayType, &rbffi_array_type_data_type, array->arrayType);
+ TypedData_Get_Struct(array->arrayType->rbComponentType, Type, &rbffi_type_data_type, array->componentType);
array->op = get_memory_op(array->componentType);
if (array->op == NULL && array->componentType->nativeType == NATIVE_MAPPED) {
@@ -550,7 +620,7 @@ inline_array_size(VALUE self)
{
InlineArray* array;
- Data_Get_Struct(self, InlineArray, array);
+ TypedData_Get_Struct(self, InlineArray, &inline_array_data_type, array);
return UINT2NUM(((ArrayType *) array->field->type)->length);
}
@@ -575,7 +645,7 @@ inline_array_aref(VALUE self, VALUE rbIndex)
{
InlineArray* array;
- Data_Get_Struct(self, InlineArray, array);
+ TypedData_Get_Struct(self, InlineArray, &inline_array_data_type, array);
if (array->op != NULL) {
VALUE rbNativeValue = array->op->get(array->memory,
@@ -611,7 +681,8 @@ inline_array_aset(VALUE self, VALUE rbIndex, VALUE rbValue)
{
InlineArray* array;
- Data_Get_Struct(self, InlineArray, array);
+ rb_check_frozen(self);
+ TypedData_Get_Struct(self, InlineArray, &inline_array_data_type, array);
if (array->op != NULL) {
if (unlikely(array->componentType->nativeType == NATIVE_MAPPED)) {
@@ -633,7 +704,7 @@ inline_array_aset(VALUE self, VALUE rbIndex, VALUE rbValue)
checkWrite(array->memory);
checkBounds(array->memory, offset, array->componentType->ffiType->size);
- Data_Get_Struct(rbValue, Struct, s);
+ TypedData_Get_Struct(rbValue, Struct, &rbffi_struct_data_type, s);
checkRead(s->pointer);
checkBounds(s->pointer, 0, array->componentType->ffiType->size);
@@ -641,7 +712,7 @@ inline_array_aset(VALUE self, VALUE rbIndex, VALUE rbValue)
} else {
ArrayType* arrayType;
- Data_Get_Struct(array->field->rbType, ArrayType, arrayType);
+ TypedData_Get_Struct(array->field->rbType, ArrayType, &rbffi_array_type_data_type, arrayType);
rb_raise(rb_eArgError, "set not supported for %s", rb_obj_classname(arrayType->rbComponentType));
return Qnil;
@@ -661,7 +732,7 @@ inline_array_each(VALUE self)
int i;
- Data_Get_Struct(self, InlineArray, array);
+ TypedData_Get_Struct(self, InlineArray, &inline_array_data_type, array);
for (i = 0; i < array->length; ++i) {
rb_yield(inline_array_aref(self, INT2FIX(i)));
@@ -682,7 +753,7 @@ inline_array_to_a(VALUE self)
VALUE obj;
int i;
- Data_Get_Struct(self, InlineArray, array);
+ TypedData_Get_Struct(self, InlineArray, &inline_array_data_type, array);
obj = rb_ary_new2(array->length);
@@ -705,7 +776,7 @@ inline_array_to_s(VALUE self)
InlineArray* array;
VALUE argv[2];
- Data_Get_Struct(self, InlineArray, array);
+ TypedData_Get_Struct(self, InlineArray, &inline_array_data_type, array);
if (array->componentType->nativeType != NATIVE_INT8 && array->componentType->nativeType != NATIVE_UINT8) {
VALUE dummy = Qnil;
@@ -728,7 +799,7 @@ inline_array_to_ptr(VALUE self)
{
InlineArray* array;
- Data_Get_Struct(self, InlineArray, array);
+ TypedData_Get_Struct(self, InlineArray, &inline_array_data_type, array);
return rb_funcall(array->rbMemory, rb_intern("slice"), 2,
UINT2NUM(array->field->offset), UINT2NUM(array->arrayType->base.ffiType->size));