summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2023-03-06 12:17:13 +0100
committerJean Boussier <jean.boussier@gmail.com>2023-03-06 14:43:36 +0100
commitc05fa0293f2e624cd9e78817e9d6bc4d2b039a8a (patch)
tree9b9d51babcfc8343367af0a1d7a32ad1d8e9a07c
parent99046c1852786fc3b23f3a5381b50bfe6caee798 (diff)
downloadffi-c05fa0293f2e624cd9e78817e9d6bc4d2b039a8a.tar.gz
Implement Write Barrier and dsize for FFI::DynamicLibrary
And FFI::DynamicLibrary::Symbol 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. While I was at it, I moved `Symbol.library` into the unused `Symbol.base.rbParent` which seemed appropriate and saves a pointer.
-rw-r--r--ext/ffi_c/DynamicLibrary.c26
-rw-r--r--spec/ffi/library_spec.rb17
2 files changed, 33 insertions, 10 deletions
diff --git a/ext/ffi_c/DynamicLibrary.c b/ext/ffi_c/DynamicLibrary.c
index 108394c..6e64c57 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]
@@ -356,4 +363,3 @@ rbffi_DynamicLibrary_Init(VALUE moduleFFI)
#undef DEF
}
-
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