From b448759f390bb50eceb9b48a307efeba68c3581c Mon Sep 17 00:00:00 2001 From: Lars Kanis Date: Mon, 8 May 2023 08:57:10 +0200 Subject: Register functions in Ruby code For consistency and to ease proting to JRuby and Truffleruby. --- ext/ffi_c/Function.c | 12 ------------ lib/ffi/function.rb | 17 +++++++++++++++++ lib/ffi/library.rb | 1 + lib/ffi/variadic.rb | 3 ++- spec/ffi/library_spec.rb | 2 +- spec/ffi/variadic_spec.rb | 2 +- 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/ext/ffi_c/Function.c b/ext/ffi_c/Function.c index d0b65fb..7810056 100644 --- a/ext/ffi_c/Function.c +++ b/ext/ffi_c/Function.c @@ -492,7 +492,6 @@ static VALUE function_attach(VALUE self, VALUE module, VALUE name) { Function* fn; - VALUE funcs; StringValue(name); TypedData_Get_Struct(self, Function, &function_data_type, fn); @@ -511,17 +510,6 @@ function_attach(VALUE self, VALUE module, VALUE name) fn->methodHandle = rbffi_MethodHandle_Alloc(fn->info, fn->base.memory.address); } - /* - * Stash the Function in a module variable so it does not get garbage collected and can be inspected by attached_functions - */ - - funcs = rb_iv_get(module, "@ffi_functions"); - if (RB_NIL_P(funcs)) { - funcs = rb_hash_new(); - rb_iv_set(module, "@ffi_functions", funcs); - } - rb_hash_aset(funcs, rb_str_intern(name), self); - rb_define_singleton_method(module, StringValueCStr(name), rbffi_MethodHandle_CodeAddress(fn->methodHandle), -1); diff --git a/lib/ffi/function.rb b/lib/ffi/function.rb index b4469be..ac4daf0 100644 --- a/lib/ffi/function.rb +++ b/lib/ffi/function.rb @@ -50,5 +50,22 @@ module FFI type.param_types end end + + # Stash the Function in a module variable so it can be inspected by attached_functions. + # On CRuby it also ensures that it does not get garbage collected. + module RegisterAttach + def attach(mod, name) + funcs = mod.instance_variable_get("@ffi_functions") + unless funcs + funcs = {} + mod.instance_variable_set("@ffi_functions", funcs) + end + funcs[name.to_sym] = self + # Jump to the native attach method of CRuby, JRuby or Tuffleruby + super + end + end + private_constant :RegisterAttach + prepend RegisterAttach end end diff --git a/lib/ffi/library.rb b/lib/ffi/library.rb index 9394902..c23112b 100644 --- a/lib/ffi/library.rb +++ b/lib/ffi/library.rb @@ -281,6 +281,7 @@ module FFI # Attach C variable +cname+ to this module. def attach_variable(mname, a1, a2 = nil) cname, type = a2 ? [ a1, a2 ] : [ mname.to_s, a1 ] + mname = mname.to_sym address = nil ffi_libraries.each do |lib| begin diff --git a/lib/ffi/variadic.rb b/lib/ffi/variadic.rb index 389c53c..ee33409 100644 --- a/lib/ffi/variadic.rb +++ b/lib/ffi/variadic.rb @@ -54,6 +54,7 @@ module FFI invoker = self params = "*args" call = "call" + mname = mname.to_sym mod.module_eval <<-code, __FILE__, __LINE__ @ffi_functions = {} unless defined?(@ffi_functions) @ffi_functions[#{mname.inspect}] = invoker @@ -62,7 +63,7 @@ module FFI @ffi_functions[#{mname.inspect}].#{call}(#{params}) end - define_method(#{mname.inspect}, &method(:#{mname})) + define_method(#{mname.inspect}, &method(#{mname.inspect})) code invoker end diff --git a/spec/ffi/library_spec.rb b/spec/ffi/library_spec.rb index 1b8e8c1..9bbbd6c 100644 --- a/spec/ffi/library_spec.rb +++ b/spec/ffi/library_spec.rb @@ -381,7 +381,7 @@ describe "Library" do lib = Module.new do |m| m.extend FFI::Library ffi_lib TestLibrary::PATH - attach_variable :gvaro, "gvar_u32", :uint32 + attach_variable "gvaro", "gvar_u32", :uint32 end expect(lib.attached_variables).to eq({ gvaro: FFI::Type::UINT32 }) end diff --git a/spec/ffi/variadic_spec.rb b/spec/ffi/variadic_spec.rb index 21a803f..4d3f1c2 100644 --- a/spec/ffi/variadic_spec.rb +++ b/spec/ffi/variadic_spec.rb @@ -40,7 +40,7 @@ describe "Function with variadic arguments" do end it "can reveal its return and parameters" do - fun = LibTest.attached_functions["testBlockingWRva"] + fun = LibTest.attached_functions[:testBlockingWRva] expect(fun.param_types).to eq([FFI::Type::POINTER, FFI::Type::CHAR, FFI::Type::VARARGS]) expect(fun.return_type).to eq(FFI::Type::INT8) end -- cgit v1.2.1