From 5f1cbba44319d66d71eba6753c3e3e950c6f8efa Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Mon, 6 Mar 2023 19:44:45 +0100 Subject: Implement the last missing Write Barriers and dsize Ref: https://github.com/ffi/ffi/pull/991 Write barrier protected objects are allowed to be promoted to the old generation, which means they only get marked on major GC. The downside is that the RB_BJ_WRITE macro MUST be used to set references, otherwise the referenced object may be garbaged collected. This commit also implement a `dsize` function so that these instance report a more relevant size in various memory profilers. It's not counting everything because some types are opaque right now, so a larger refactoring would be needed. --- ext/ffi_c/ArrayType.c | 20 ++++++++++++++++---- ext/ffi_c/DynamicLibrary.c | 14 +++++++++++--- ext/ffi_c/LastError.c | 11 +++++++++-- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/ext/ffi_c/ArrayType.c b/ext/ffi_c/ArrayType.c index f6e6fc4..1d766a4 100644 --- a/ext/ffi_c/ArrayType.c +++ b/ext/ffi_c/ArrayType.c @@ -35,16 +35,19 @@ static VALUE array_type_s_allocate(VALUE klass); static VALUE array_type_initialize(VALUE self, VALUE rbComponentType, VALUE rbLength); static void array_type_mark(void *); static void array_type_free(void *); +static size_t array_type_memsize(const void *); const rb_data_type_t rbffi_array_type_data_type = { /* extern */ .wrap_struct_name = "FFI::ArrayType", .function = { .dmark = array_type_mark, .dfree = array_type_free, - .dsize = NULL, + .dsize = array_type_memsize, }, .parent = &rbffi_type_data_type, - .flags = RUBY_TYPED_FREE_IMMEDIATELY + // 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 }; @@ -63,7 +66,7 @@ array_type_s_allocate(VALUE klass) array->base.ffiType->type = FFI_TYPE_STRUCT; array->base.ffiType->size = 0; array->base.ffiType->alignment = 0; - array->rbComponentType = Qnil; + RB_OBJ_WRITE(obj, &array->rbComponentType, Qnil); return obj; } @@ -84,6 +87,15 @@ array_type_free(void *data) xfree(array); } +static size_t +array_type_memsize(const void *data) +{ + const ArrayType *array = (const ArrayType *)data; + size_t memsize = sizeof(ArrayType); + memsize += array->length * sizeof(*array->ffiTypes); + memsize += sizeof(*array->base.ffiType); + return memsize; +} /* * call-seq: initialize(component_type, length) @@ -101,7 +113,7 @@ array_type_initialize(VALUE self, VALUE rbComponentType, VALUE rbLength) TypedData_Get_Struct(self, ArrayType, &rbffi_array_type_data_type, array); array->length = NUM2UINT(rbLength); - array->rbComponentType = rbComponentType; + RB_OBJ_WRITE(self, &array->rbComponentType, rbComponentType); TypedData_Get_Struct(rbComponentType, Type, &rbffi_type_data_type, array->componentType); array->ffiTypes = xcalloc(array->length + 1, sizeof(*array->ffiTypes)); diff --git a/ext/ffi_c/DynamicLibrary.c b/ext/ffi_c/DynamicLibrary.c index c69074a..2e0bf4b 100644 --- a/ext/ffi_c/DynamicLibrary.c +++ b/ext/ffi_c/DynamicLibrary.c @@ -56,7 +56,7 @@ typedef struct LibrarySymbol_ { static VALUE library_initialize(VALUE self, VALUE libname, VALUE libflags); static void library_free(void *); - +static size_t library_memsize(const void *); static VALUE symbol_allocate(VALUE klass); static VALUE symbol_new(VALUE library, void* address, VALUE name); @@ -68,9 +68,11 @@ static const rb_data_type_t rbffi_library_data_type = { .function = { .dmark = NULL, .dfree = library_free, - .dsize = NULL, + .dsize = library_memsize, }, - .flags = RUBY_TYPED_FREE_IMMEDIATELY + // 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 }; static const rb_data_type_t library_symbol_data_type = { @@ -200,6 +202,12 @@ library_free(void *data) xfree(library); } +static size_t +library_memsize(const void *data) +{ + return sizeof(Library); +} + #if (defined(_WIN32) || defined(__WIN32__)) && !defined(__CYGWIN__) static void* dl_open(const char* name, int flags) diff --git a/ext/ffi_c/LastError.c b/ext/ffi_c/LastError.c index 4cef93b..d5ef132 100644 --- a/ext/ffi_c/LastError.c +++ b/ext/ffi_c/LastError.c @@ -91,14 +91,21 @@ thread_data_free(void *ptr) } #else +static size_t +thread_data_memsize(const void *data) { + return sizeof(ThreadData); +} + static const rb_data_type_t thread_data_data_type = { .wrap_struct_name = "FFI::ThreadData", .function = { .dmark = NULL, .dfree = RUBY_TYPED_DEFAULT_FREE, - .dsize = NULL, + .dsize = thread_data_memsize, }, - .flags = RUBY_TYPED_FREE_IMMEDIATELY + // 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 }; static ID id_thread_data; -- cgit v1.2.1