diff options
-rw-r--r-- | ext/ffi_c/DynamicLibrary.c | 28 | ||||
-rw-r--r-- | ext/ffi_c/Function.c | 33 | ||||
-rw-r--r-- | ext/ffi_c/FunctionInfo.c | 3 | ||||
-rw-r--r-- | spec/ffi/function_spec.rb | 8 | ||||
-rw-r--r-- | spec/ffi/library_spec.rb | 17 |
5 files changed, 69 insertions, 20 deletions
diff --git a/ext/ffi_c/DynamicLibrary.c b/ext/ffi_c/DynamicLibrary.c index 108394c..c69074a 100644 --- a/ext/ffi_c/DynamicLibrary.c +++ b/ext/ffi_c/DynamicLibrary.c @@ -50,7 +50,6 @@ typedef struct LibrarySymbol_ { Pointer base; - VALUE library; VALUE name; } LibrarySymbol; @@ -62,6 +61,7 @@ static void library_free(void *); static VALUE symbol_allocate(VALUE klass); static VALUE symbol_new(VALUE library, void* address, VALUE name); static void symbol_mark(void *data); +static size_t symbol_memsize(const void *data); static const rb_data_type_t rbffi_library_data_type = { .wrap_struct_name = "FFI::DynamicLibrary", @@ -78,10 +78,12 @@ static const rb_data_type_t library_symbol_data_type = { .function = { .dmark = symbol_mark, .dfree = RUBY_TYPED_DEFAULT_FREE, - .dsize = NULL, + .dsize = symbol_memsize, }, .parent = &rbffi_pointer_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 }; static VALUE LibraryClass = Qnil, SymbolClass = Qnil; @@ -223,9 +225,8 @@ symbol_allocate(VALUE klass) { LibrarySymbol* sym; VALUE obj = TypedData_Make_Struct(klass, LibrarySymbol, &library_symbol_data_type, sym); - sym->name = Qnil; - sym->library = Qnil; - sym->base.rbParent = Qnil; + RB_OBJ_WRITE(obj, &sym->base.rbParent, Qnil); + RB_OBJ_WRITE(obj, &sym->name, Qnil); return obj; } @@ -254,8 +255,8 @@ symbol_new(VALUE library, void* address, VALUE name) sym->base.memory.size = LONG_MAX; sym->base.memory.typeSize = 1; sym->base.memory.flags = MEM_RD | MEM_WR; - sym->library = library; - sym->name = name; + RB_OBJ_WRITE(obj, &sym->base.rbParent, library); + RB_OBJ_WRITE(obj, &sym->name, name); return obj; } @@ -264,10 +265,16 @@ static void symbol_mark(void *data) { LibrarySymbol *sym = (LibrarySymbol *)data; - rb_gc_mark(sym->library); + rb_gc_mark(sym->base.rbParent); rb_gc_mark(sym->name); } +static size_t +symbol_memsize(const void *data) +{ + return sizeof(LibrarySymbol); +} + /* * call-seq: inspect * @return [String] @@ -280,7 +287,7 @@ symbol_inspect(VALUE self) char buf[256]; TypedData_Get_Struct(self, LibrarySymbol, &library_symbol_data_type, sym); - snprintf(buf, sizeof(buf), "#<FFI::Library::Symbol name=%s address=%p>", + snprintf(buf, sizeof(buf), "#<FFI::DynamicLibrary::Symbol name=%s address=%p>", StringValueCStr(sym->name), sym->base.memory.address); return rb_str_new2(buf); } @@ -356,4 +363,3 @@ rbffi_DynamicLibrary_Init(VALUE moduleFFI) #undef DEF } - diff --git a/ext/ffi_c/Function.c b/ext/ffi_c/Function.c index 20822da..b73e8b7 100644 --- a/ext/ffi_c/Function.c +++ b/ext/ffi_c/Function.c @@ -77,6 +77,7 @@ typedef struct Function_ { static void function_mark(void *data); static void function_free(void *data); +static size_t function_memsize(const void *data); static VALUE function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc); static void callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data); static bool callback_prep(void* ctx, void* code, Closure* closure, char* errmsg, size_t errmsgsize); @@ -100,10 +101,12 @@ static const rb_data_type_t function_data_type = { .function = { .dmark = function_mark, .dfree = function_free, - .dsize = NULL, + .dsize = function_memsize, }, .parent = &rbffi_pointer_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 }; VALUE rbffi_FunctionClass = Qnil; @@ -153,9 +156,9 @@ function_allocate(VALUE klass) obj = TypedData_Make_Struct(klass, Function, &function_data_type, fn); fn->base.memory.flags = MEM_RD; - fn->base.rbParent = Qnil; - fn->rbProc = Qnil; - fn->rbFunctionInfo = Qnil; + RB_OBJ_WRITE(obj, &fn->base.rbParent, Qnil); + RB_OBJ_WRITE(obj, &fn->rbProc, Qnil); + RB_OBJ_WRITE(obj, &fn->rbFunctionInfo, Qnil); fn->autorelease = true; return obj; @@ -185,6 +188,20 @@ function_free(void *data) xfree(fn); } +static size_t +function_memsize(const void *data) +{ + const Function *fn = (const Function *)data; + size_t memsize = sizeof(Function); + + // Would be nice to better account for MethodHandle and Closure too. + if (fn->closure) { + memsize += sizeof(Closure); + } + + return memsize; +} + /* * @param [Type, Symbol] return_type return type for the function * @param [Array<Type, Symbol>] param_types array of parameters types @@ -313,7 +330,7 @@ function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc) TypedData_Get_Struct(self, Function, &function_data_type, fn); - fn->rbFunctionInfo = rbFunctionInfo; + RB_OBJ_WRITE(self, &fn->rbFunctionInfo, rbFunctionInfo); TypedData_Get_Struct(fn->rbFunctionInfo, FunctionType, &rbffi_fntype_data_type, fn->info); @@ -321,7 +338,7 @@ function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc) Pointer* orig; TypedData_Get_Struct(rbProc, Pointer, &rbffi_pointer_data_type, orig); fn->base.memory = orig->memory; - fn->base.rbParent = rbProc; + RB_OBJ_WRITE(self, &fn->base.rbParent, rbProc); } else if (rb_obj_is_kind_of(rbProc, rb_cProc) || rb_respond_to(rbProc, id_call)) { if (fn->info->closurePool == NULL) { @@ -357,7 +374,7 @@ function_init(VALUE self, VALUE rbFunctionInfo, VALUE rbProc) rb_obj_classname(rbProc)); } - fn->rbProc = rbProc; + RB_OBJ_WRITE(self, &fn->rbProc, rbProc); return self; } diff --git a/ext/ffi_c/FunctionInfo.c b/ext/ffi_c/FunctionInfo.c index e3391c3..6aa93d9 100644 --- a/ext/ffi_c/FunctionInfo.c +++ b/ext/ffi_c/FunctionInfo.c @@ -183,7 +183,8 @@ fntype_initialize(int argc, VALUE* argv, VALUE self) if (rb_obj_is_kind_of(type, rbffi_FunctionTypeClass)) { REALLOC_N(fnInfo->callbackParameters, VALUE, fnInfo->callbackCount + 1); - RB_OBJ_WRITE(self, &fnInfo->callbackParameters[fnInfo->callbackCount++], type); + RB_OBJ_WRITE(self, &fnInfo->callbackParameters[fnInfo->callbackCount], type); + fnInfo->callbackCount++; } if (rb_obj_is_kind_of(type, rbffi_StructByValueClass)) { diff --git a/spec/ffi/function_spec.rb b/spec/ffi/function_spec.rb index 5bc2421..a1a50f3 100644 --- a/spec/ffi/function_spec.rb +++ b/spec/ffi/function_spec.rb @@ -103,4 +103,12 @@ describe FFI::Function do fp = FFI::Function.new(:int, [:int, :int], @libtest.find_function('testAdd')) expect { fp.free }.to raise_error RuntimeError end + + it 'has a memsize function', skip: RUBY_ENGINE != "ruby" do + base_size = ObjectSpace.memsize_of(Object.new) + + function = FFI::Function.new(:int, [:int, :int], @libtest.find_function('testAdd')) + size = ObjectSpace.memsize_of(function) + expect(size).to be > base_size + end end diff --git a/spec/ffi/library_spec.rb b/spec/ffi/library_spec.rb index 5b806bb..a17d673 100644 --- a/spec/ffi/library_spec.rb +++ b/spec/ffi/library_spec.rb @@ -322,4 +322,21 @@ describe "Library" do expect(val[:data]).to eq(i) end end + + describe "Symbol" do + before do + @libtest = FFI::DynamicLibrary.open( + TestLibrary::PATH, + FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL, + ) + end + + it "has a memsize function", skip: RUBY_ENGINE != "ruby" do + base_size = ObjectSpace.memsize_of(Object.new) + + symbol = @libtest.find_symbol("gvar_gstruct_set") + size = ObjectSpace.memsize_of(symbol) + expect(size).to be > base_size + end + end end |