diff options
author | Jean Boussier <jean.boussier@gmail.com> | 2023-03-06 16:47:30 +0100 |
---|---|---|
committer | Jean Boussier <jean.boussier@gmail.com> | 2023-03-06 16:47:30 +0100 |
commit | 38e62e7d0ee149b63555c2b9a069e24968128ac7 (patch) | |
tree | 9893ef74721198d79d78d0d79cc2b5f84d43ab7f | |
parent | 683036355de9af50188fdef796b976eddbcdac6a (diff) | |
download | ffi-38e62e7d0ee149b63555c2b9a069e24968128ac7.tar.gz |
Implement Write Barrier and dsize for FFI::VariadicInvoker
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.
-rw-r--r-- | ext/ffi_c/Variadic.c | 25 |
1 files changed, 17 insertions, 8 deletions
diff --git a/ext/ffi_c/Variadic.c b/ext/ffi_c/Variadic.c index e379f4b..014fac2 100644 --- a/ext/ffi_c/Variadic.c +++ b/ext/ffi_c/Variadic.c @@ -66,6 +66,7 @@ static VALUE variadic_allocate(VALUE klass); static VALUE variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE rbReturnType, VALUE options); static void variadic_mark(void *); +static size_t variadic_memsize(const void *); static VALUE classVariadicInvoker = Qnil; @@ -74,9 +75,11 @@ static const rb_data_type_t variadic_data_type = { .function = { .dmark = variadic_mark, .dfree = RUBY_TYPED_DEFAULT_FREE, - .dsize = NULL, + .dsize = variadic_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 }; @@ -86,9 +89,9 @@ variadic_allocate(VALUE klass) VariadicInvoker *invoker; VALUE obj = TypedData_Make_Struct(klass, VariadicInvoker, &variadic_data_type, invoker); - invoker->rbAddress = Qnil; - invoker->rbEnums = Qnil; - invoker->rbReturnType = Qnil; + RB_OBJ_WRITE(obj, &invoker->rbAddress, Qnil); + RB_OBJ_WRITE(obj, &invoker->rbEnums, Qnil); + RB_OBJ_WRITE(obj, &invoker->rbReturnType, Qnil); invoker->blocking = false; return obj; @@ -103,6 +106,12 @@ variadic_mark(void *data) rb_gc_mark(invoker->rbReturnType); } +static size_t +variadic_memsize(const void *data) +{ + return sizeof(VariadicInvoker); +} + static VALUE variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE rbReturnType, VALUE options) { @@ -119,8 +128,8 @@ variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE convention = rb_hash_aref(options, ID2SYM(rb_intern("convention"))); TypedData_Get_Struct(self, VariadicInvoker, &variadic_data_type, invoker); - invoker->rbEnums = rb_hash_aref(options, ID2SYM(rb_intern("enums"))); - invoker->rbAddress = rbFunction; + RB_OBJ_WRITE(self, &invoker->rbEnums, rb_hash_aref(options, ID2SYM(rb_intern("enums")))); + RB_OBJ_WRITE(self, &invoker->rbAddress, rbFunction); invoker->function = rbffi_AbstractMemory_Cast(rbFunction, rbffi_PointerClass)->address; invoker->blocking = RTEST(rb_hash_aref(options, ID2SYM(rb_intern("blocking")))); @@ -132,7 +141,7 @@ variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE invoker->abi = FFI_DEFAULT_ABI; #endif - invoker->rbReturnType = rbffi_Type_Lookup(rbReturnType); + RB_OBJ_WRITE(self, &invoker->rbReturnType, rbffi_Type_Lookup(rbReturnType)); if (!RTEST(invoker->rbReturnType)) { VALUE typeName = rb_funcall2(rbReturnType, rb_intern("inspect"), 0, NULL); rb_raise(rb_eTypeError, "Invalid return type (%s)", RSTRING_PTR(typeName)); |