From 65f30148770099bd53a840017a87a5b8e109b491 Mon Sep 17 00:00:00 2001 From: Sutou Kouhei Date: Sun, 29 Sep 2024 18:10:54 +0900 Subject: [PATCH 1/2] Import TruffleRuby implementation Fix GH-145 lib/fiddle/truffleruby.rb is based on https://github.com/oracle/truffleruby/blob/master/lib/truffle/truffle/fiddle_backend.rb . Here are changes for it: * Add `Fiddle::Types::VARIADIC` * Add `Fiddle::Types::CONST_STRING` * Add `Fiddle::Types::BOOL` * Add `Fiddle::ALIGN_BOOL` * Add `Fiddle::SIZEOF_BOOL` * Add `Fiddle::SIZEOF_CONST_STRING` * Add support for specifying type as not only `Fiddle::Types::*` but also `Symbol` like `:int` * Add `Fiddle::Error` as base the error class * Add support for `Fiddle::Pointer.malloc {}` `Fiddle::Pointer` * Add support for `Fiddle.free(#to_int)` * Accept `Fiddle::Function(need_gvl:)` but it's just ignored * `Fiddle::Function#initialize`: Add an argument validation * `Fiddle::Function#initialize`: Keep arguments as instance variables for getters * Add support for `Fiddle::Handle.sym` * Add support for `Fiddle::Handle.[]` * Add support for `Fiddle::Handle.sym_defined?` * Add support for `Fiddle::Handle#sym` * Add support for `Fiddle::Handle#[]` * Add support for `Fiddle::Handle#sym_defined?` * Add support for `Fiddle::Pointer.malloc` * Add support for `Fiddle::Pointer.to_ptr(#to_ptr)` * Add support for `Fiddle::Pointer#free=` * Add `Fiddle::Pointer#freed?` * Add support for `Fiddle::Pointer#call_free` * Add support for `Fiddle::Pointer#to_i` * Add support for `Fiddle::Pointer#to_int` * Add support for `Fiddle::Pointer#ptr` * Add support for `Fiddle::Pointer#+@` * Add support for `Fiddle::Pointer#ref` * Add support for `Fiddle::Pointer#-@` * Add support for `Fiddle::Pointer#null?` * Add support for `Fiddle::Pointer#to_s` * Add support for `Fiddle::Pointer#to_str` * Add support for `Fiddle::Pointer#inspect` * Add support for `Fiddle::Pointer#<=>` * Add support for `Fiddle::Pointer#==` * Add support for `Fiddle::Pointer#eql?` * Add support for `Fiddle::Pointer#+` * Add support for `Fiddle::Pointer#-` * Add support for `Fiddle::Pointer#[]=` * Add support for `Fiddle::Pointer#size` * Add support for `Fiddle::Pointer#size=` * Add `Fiddle::ClearedReferenceError` * Add no-op `Fiddle::Pinned` * Add `Fiddle::NULL` Some features are still "not implemented". So there are some "omit"s for TruffleRuby in tests. --- .github/workflows/ci.yml | 2 + ext/fiddle/extconf.rb | 2 +- fiddle.gemspec | 1 + lib/fiddle/truffleruby.rb | 623 +++++++++++++++++++++++++++++++++++ test/fiddle/test_closure.rb | 6 + test/fiddle/test_fiddle.rb | 11 + test/fiddle/test_func.rb | 8 + test/fiddle/test_function.rb | 13 + test/fiddle/test_handle.rb | 32 ++ test/fiddle/test_import.rb | 3 + test/fiddle/test_pointer.rb | 15 + 11 files changed, 715 insertions(+), 1 deletion(-) create mode 100644 lib/fiddle/truffleruby.rb diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe0d68bf..972bcce5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,7 @@ jobs: - '3.2' - debug - jruby + - truffleruby include: - { os: windows-latest , ruby: mingw } - { os: windows-latest , ruby: mswin } @@ -33,6 +34,7 @@ jobs: - { os: macos-14 , ruby: '2.5' } - { os: windows-latest , ruby: '3.0' } - { os: windows-latest , ruby: debug } + - { os: windows-latest , ruby: truffleruby } steps: - uses: actions/checkout@v4 diff --git a/ext/fiddle/extconf.rb b/ext/fiddle/extconf.rb index 6b0ea753..a4a7e7e1 100644 --- a/ext/fiddle/extconf.rb +++ b/ext/fiddle/extconf.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'mkmf' -if RUBY_ENGINE == "jruby" +unless RUBY_ENGINE == "ruby" File.write('Makefile', dummy_makefile("").join) return end diff --git a/fiddle.gemspec b/fiddle.gemspec index 65de7a30..89c2c851 100644 --- a/fiddle.gemspec +++ b/fiddle.gemspec @@ -44,6 +44,7 @@ Gem::Specification.new do |spec| "lib/fiddle/pack.rb", "lib/fiddle/ruby.rb", "lib/fiddle/struct.rb", + "lib/fiddle/truffleruby.rb", "lib/fiddle/types.rb", "lib/fiddle/value.rb", "lib/fiddle/version.rb", diff --git a/lib/fiddle/truffleruby.rb b/lib/fiddle/truffleruby.rb new file mode 100644 index 00000000..f1c34c75 --- /dev/null +++ b/lib/fiddle/truffleruby.rb @@ -0,0 +1,623 @@ +# frozen_string_literal: true +# truffleruby_primitives: true + +# Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved. This +# code is released under a tri EPL/GPL/LGPL license. You can use it, +# redistribute it and/or modify it under the terms of the: +# +# Eclipse Public License version 2.0, or +# GNU General Public License version 2, or +# GNU Lesser General Public License version 2.1. + +module Truffle::FiddleBackend + + SIZEOF_CHAR = Primitive.pointer_find_type_size(:char) + SIZEOF_SHORT = Primitive.pointer_find_type_size(:short) + SIZEOF_INT = Primitive.pointer_find_type_size(:int) + SIZEOF_LONG = Primitive.pointer_find_type_size(:long) + + CHAR_NFI_TYPE = "SINT#{SIZEOF_CHAR * 8}" + UCHAR_NFI_TYPE = "UINT#{SIZEOF_CHAR * 8}" + SHORT_NFI_TYPE = "SINT#{SIZEOF_SHORT * 8}" + USHORT_NFI_TYPE = "UINT#{SIZEOF_SHORT * 8}" + INT_NFI_TYPE = "SINT#{SIZEOF_INT * 8}" + UINT_NFI_TYPE = "UINT#{SIZEOF_INT * 8}" + LONG_NFI_TYPE = "SINT#{SIZEOF_LONG * 8}" + ULONG_NFI_TYPE = "UINT#{SIZEOF_LONG * 8}" + + SIZE_T_TYPEDEF = Truffle::Config.lookup('platform.typedef.size_t') + + case SIZE_T_TYPEDEF + when 'ulong' + SIGNEDNESS_OF_SIZE_T = 1 + else + raise NotImplementedError, "#{SIZE_T_TYPEDEF} not recognised" + end + + def self.type_to_nfi(type) + if type.is_a?(Symbol) + type = Fiddle::Types.const_get(type.to_s.upcase) + end + if !type.is_a?(Integer) and type.respond_to?(:to_int) + type = type.to_int + end + case type + when Fiddle::TYPE_VOID + 'VOID' + when Fiddle::TYPE_VOIDP, Fiddle::TYPE_CONST_STRING + 'POINTER' + when Fiddle::TYPE_CHAR + CHAR_NFI_TYPE + when -Fiddle::TYPE_CHAR + UCHAR_NFI_TYPE + when Fiddle::TYPE_SHORT + SHORT_NFI_TYPE + when -Fiddle::TYPE_SHORT + USHORT_NFI_TYPE + when Fiddle::TYPE_INT + INT_NFI_TYPE + when -Fiddle::TYPE_INT + UINT_NFI_TYPE + when Fiddle::TYPE_LONG, Fiddle::TYPE_LONG_LONG + LONG_NFI_TYPE + when -Fiddle::TYPE_LONG, -Fiddle::TYPE_LONG_LONG + ULONG_NFI_TYPE + when Fiddle::TYPE_FLOAT + 'FLOAT' + when Fiddle::TYPE_DOUBLE + 'DOUBLE' + when Fiddle::TYPE_BOOL + 'BOOL' + else + raise TypeError, "#{type} not implemented" + end + end + + def self.type_from_config(type) + case type + when 'long' + Fiddle::Types::LONG + else + raise NotImplementedError, "integer #{type} not known" + end + end + + def self.convert_ruby_to_native(type, val) + case type + when Fiddle::TYPE_CHAR + Integer(val) + when Fiddle::TYPE_VOIDP + get_pointer_value(val) + when Fiddle::TYPE_INT + Integer(val) + when -Fiddle::TYPE_LONG + Integer(val) + when Fiddle::TYPE_FLOAT, Fiddle::TYPE_DOUBLE + Float(val) + else + raise NotImplementedError, "#{val.inspect} to type #{type}" + end + end + + def self.get_pointer_value(val) + if Primitive.is_a?(val, String) + # NOTE: Fiddle::TYPE_CONST_STRING wouldn't need inplace, but not defined yet by this file + Truffle::CExt.string_to_ffi_pointer_inplace(val) + elsif Primitive.is_a?(val, Fiddle::Pointer) + val.to_i + elsif val.respond_to?(:to_ptr) + val.to_ptr.to_i + elsif Primitive.nil?(val) + 0 + elsif Primitive.is_a?(val, Integer) + val + else + raise NotImplementedError, "#{val.inspect} to pointer" + end + end + + def self.convert_native_to_ruby(type, val) + case type + when Fiddle::TYPE_VOID + nil + when Fiddle::TYPE_VOIDP + Fiddle::Pointer.new(Truffle::Interop.as_pointer(val)) + when Fiddle::TYPE_INT, + Fiddle::TYPE_ULONG, + Fiddle::TYPE_FLOAT, + Fiddle::TYPE_DOUBLE + val + else + raise NotImplementedError, "#{val.inspect} from type #{type}" + end + end + + RTLD_NEXT = Truffle::Config['platform.dlopen.RTLD_NEXT'] + RTLD_DEFAULT = Truffle::Config['platform.dlopen.RTLD_DEFAULT'] + +end + +module Fiddle + + class Error < StandardError + end + class DLError < Error + end + class ClearedReferenceError < Error + end + + module Types + VOID = 0 + VOIDP = 1 + CHAR = 2 + SHORT = 3 + INT = 4 + LONG = 5 + LONG_LONG = 6 + FLOAT = 7 + DOUBLE = 8 + VARIADIC = 9 + CONST_STRING = 10 + BOOL = 11 + + UCHAR = -CHAR + USHORT = -SHORT + UINT = -INT + ULONG = -LONG + ULONG_LONG = -LONG_LONG + + INT8_T = CHAR + INT16_T = SHORT + INT32_T = INT + INT64_T = LONG + + UINT8_T = -INT8_T + UINT16_T = -INT16_T + UINT32_T = -INT32_T + UINT64_T = -INT64_T + + SSIZE_T = Truffle::FiddleBackend.type_from_config(Truffle::Config.lookup('platform.typedef.ssize_t')) + SIZE_T = -1 * Truffle::FiddleBackend::SIGNEDNESS_OF_SIZE_T * SSIZE_T + PTRDIFF_T = Truffle::FiddleBackend.type_from_config(Truffle::Config.lookup('platform.typedef.ptrdiff_t')) + INTPTR_T = Truffle::FiddleBackend.type_from_config(Truffle::Config.lookup('platform.typedef.intptr_t')) + UINTPTR_T = -INTPTR_T + end + + SIZEOF_VOIDP = Primitive.pointer_find_type_size(:pointer) + SIZEOF_CHAR = Primitive.pointer_find_type_size(:char) + SIZEOF_SHORT = Primitive.pointer_find_type_size(:short) + SIZEOF_INT = Truffle::FiddleBackend::SIZEOF_INT + SIZEOF_LONG = Truffle::FiddleBackend::SIZEOF_LONG + SIZEOF_LONG_LONG = Primitive.pointer_find_type_size(:long_long) + SIZEOF_FLOAT = Primitive.pointer_find_type_size(:float) + SIZEOF_DOUBLE = Primitive.pointer_find_type_size(:double) + SIZEOF_BOOL = SIZEOF_CHAR # TODO: Use sizeof(bool) + SIZEOF_CONST_STRING = SIZEOF_VOIDP + + SIZEOF_UCHAR = SIZEOF_CHAR + SIZEOF_USHORT = SIZEOF_SHORT + SIZEOF_UINT = SIZEOF_INT + SIZEOF_ULONG = SIZEOF_LONG + SIZEOF_ULONG_LONG = SIZEOF_LONG_LONG + + SIZEOF_INT8_T = 1 + SIZEOF_INT16_T = 2 + SIZEOF_INT32_T = 4 + SIZEOF_INT64_T = 8 + + SIZEOF_UINT8_T = 1 + SIZEOF_UINT16_T = 2 + SIZEOF_UINT32_T = 4 + SIZEOF_UINT64_T = 8 + + SIZEOF_SSIZE_T = Primitive.pointer_find_type_size(:ssize_t) + SIZEOF_SIZE_T = Primitive.pointer_find_type_size(:size_t) + SIZEOF_PTRDIFF_T = Primitive.pointer_find_type_size(:ptrdiff_t) + SIZEOF_INTPTR_T = Primitive.pointer_find_type_size(:intptr_t) + SIZEOF_UINTPTR_T = Primitive.pointer_find_type_size(:uintptr_t) + + # Alignment assumed to be the same as size + + ALIGN_VOIDP = SIZEOF_VOIDP + ALIGN_CHAR = SIZEOF_CHAR + ALIGN_SHORT = SIZEOF_SHORT + ALIGN_INT = SIZEOF_INT + ALIGN_LONG = SIZEOF_LONG + ALIGN_LONG_LONG = SIZEOF_LONG_LONG + ALIGN_FLOAT = SIZEOF_FLOAT + ALIGN_DOUBLE = SIZEOF_DOUBLE + ALIGN_BOOL = SIZEOF_BOOL + + ALIGN_INT8_T = SIZEOF_INT8_T + ALIGN_INT16_T = SIZEOF_INT16_T + ALIGN_INT32_T = SIZEOF_INT32_T + ALIGN_INT64_T = SIZEOF_INT64_T + + ALIGN_SIZE_T = SIZEOF_SIZE_T + ALIGN_SSIZE_T = SIZEOF_SSIZE_T + ALIGN_PTRDIFF_T = SIZEOF_PTRDIFF_T + ALIGN_INTPTR_T = SIZEOF_INTPTR_T + ALIGN_UINTPTR_T = SIZEOF_UINTPTR_T + + WINDOWS = Truffle::Platform.windows? + BUILD_RUBY_PLATFORM = RUBY_PLATFORM + + def self.dlwrap(*args) + raise NotImplementedError + end + + def self.dlunwrap(*args) + raise NotImplementedError + end + + def self.malloc(size) + Primitive.pointer_raw_malloc size + end + + def self.realloc(address, size) + Primitive.pointer_raw_realloc address, size + end + + def self.free(address) + if !address.is_a?(Integer) and address.respond_to?(:to_int) + address = address.to_int + end + Primitive.pointer_raw_free address + end + + class Function + + DEFAULT = :default_abi + + def initialize(ptr, args, ret_type, abi = DEFAULT, name: nil, need_gvl: false) + raise TypeError.new "invalid argument types" unless args.is_a?(Array) + + @ptr = ptr + @arg_types = args + @ret_type = ret_type + @abi = abi + @name = name + @need_gvl = need_gvl + args = args.map { |arg| Truffle::FiddleBackend.type_to_nfi(arg) } + ret_type = Truffle::FiddleBackend.type_to_nfi(ret_type) + signature = "(#{args.join(',')}):#{ret_type}" + + if Primitive.is_a?(ptr, Closure) + @function = ptr.method(:call) + else + ptr = Truffle::FFI::Pointer.new(ptr) + @function = Primitive.interop_eval_nfi(signature).bind(ptr) + end + end + + def call(*args) + args = args.zip(@arg_types).map { |arg, type| Truffle::FiddleBackend.convert_ruby_to_native(type, arg) } + ret = @function.call(*args) + Truffle::FiddleBackend.convert_native_to_ruby(@ret_type, ret) + end + + end + + class Closure + + def initialize(ret, args, abi = Function::DEFAULT) + # does nothing - 'not implemented' when used + end + + def to_i(*args) + raise NotImplementedError + end + + end + + class Handle + + def self.sym(name) + DEFAULT.sym(name) + end + + def self.[](name) + sym(name) + end + + def self.sym_defined?(name) + DEFAULT.sym_defined?(name) + end + + RTLD_LAZY = Truffle::Config['platform.dlopen.RTLD_LAZY'] + RTLD_NOW = Truffle::Config['platform.dlopen.RTLD_NOW'] + RTLD_GLOBAL = Truffle::Config['platform.dlopen.RTLD_GLOBAL'] + + def initialize(library = nil, flags = RTLD_LAZY | RTLD_GLOBAL) + raise DLError, 'unsupported dlopen flags' if flags != (RTLD_LAZY | RTLD_GLOBAL) + + if library == Truffle::FiddleBackend::RTLD_NEXT + @handle = :rtld_next + else + library = nil if library == Truffle::FiddleBackend::RTLD_DEFAULT + begin + @handle = Primitive.interop_eval_nfi(library ? "load '#{library}'" : 'default') + rescue Polyglot::ForeignException => e + raise DLError, "#{e.message}" + end + end + end + + def to_i(*args) + raise NotImplementedError + end + + def close(*args) + raise NotImplementedError + end + + def sym(name) + if :rtld_next == @handle + raise DLError, 'RTLD_NEXT is not supported' + else + begin + sym = @handle[name] + rescue NameError + raise DLError, "unknown symbol \"#{name}\"" + else + Truffle::Interop.as_pointer(sym) + end + end + end + + alias_method :[], :sym + + def sym_defined?(name) + if :rtld_next == @handle + raise DLError, 'RTLD_NEXT is not supported' + else + begin + @handle[name] + rescue NameError + false + else + true + end + end + end + + def disable_close(*args) + raise NotImplementedError + end + + def enable_close(*args) + raise NotImplementedError + end + + def close_enabled?(*args) + raise NotImplementedError + end + + DEFAULT = Handle.new(Truffle::FiddleBackend::RTLD_DEFAULT) + NEXT = Handle.new(Truffle::FiddleBackend::RTLD_NEXT) + + end + + class Pointer + + def self.malloc(size, free=nil) + if block_given? and free.nil? + message = "a free function must be supplied to #{self}.malloc " + + "when it is called with a block" + raise ArgumentError, message + end + + pointer = new(Fiddle.malloc(size), size, free) + if block_given? + begin + yield(pointer) + ensure + pointer.call_free + end + else + pointer + end + end + + def self.to_ptr(val) + if Primitive.is_a?(val, IO) + raise NotImplementedError + elsif Primitive.is_a?(val, String) + ptr = Pointer.new(Primitive.string_pointer_to_native(val), val.bytesize) + elsif val.respond_to?(:to_ptr) + ptr = val.to_ptr + case ptr + when Pointer + ptr + else + raise DLError.new("to_ptr should return a Fiddle::Pointer object, was #{ptr.class}") + end + else + ptr = Pointer.new(Integer(val)) + end + ptr + end + + class << self + alias_method :[], :to_ptr + end + + def initialize(address, size = 0, free = nil) + @size = size + @free = free + if address.is_a?(Pointer) + @pointer = Truffle::FFI::Pointer.new(address.to_i) + else + @pointer = Truffle::FFI::Pointer.new(address) + end + @freed = false + end + + def free=(free) + @free = free + end + + def free + @free + end + + def call_free + return if @free.nil? + return if @freed + if @free == RUBY_FREE + Fiddle.free(@pointer.address) + else + @free.call(@pointer.address) + end + @freed = true + end + + def freed? + @freed + end + + def to_i + @pointer.address + end + alias_method :to_int, :to_i + + def to_value(*args) + raise NotImplementedError + end + + def ptr + Pointer.new(@pointer.read_pointer) + end + + def +@ + ptr + end + + def ref + reference = Pointer.malloc(SIZEOF_VOIDP, RUBY_FREE) + reference.instance_variable_get(:@pointer).put_pointer(0, to_i) + reference + end + + def -@ + ref + end + + def null? + @pointer.null? + end + + def to_s(len=nil) + if len + @pointer.get_string(0, len) + else + @pointer.get_string(0) + end + end + + def to_str(len=nil) + if len + @pointer.get_bytes(0, len) + else + @pointer.get_bytes(0, @size) + end + end + + def inspect + "#<#{self.class.name} ptr=#{to_i.to_s(16)} size=#{@size} free=#{@free.inspect}>" + end + + def <=>(other) + return nil unless other.is_a?(Pointer) + diff = to_i - other.to_i + return 0 if diff == 0 + diff > 0 ? 1 : -1 + end + + def ==(other) + eql?(other) + end + + def eql?(other) + return unless other.is_a?(Pointer) + to_i == other.to_i + end + + def +(delta) + self.class.new(to_i + delta, @size - delta) + end + + def -(delta) + self.class.new(to_i - delta, @size + delta) + end + + def [](start, length = nil) + if length + (@pointer + start).read_string(length) + else + (@pointer + start).read_int8 + end + rescue Truffle::FFI::NullPointerError + raise DLError.new("NULL pointer access") + end + + def []=(*args, value) + if args.size == 2 + if value.is_a?(Integer) + value = self.class.new(value) + end + if value.is_a?(Pointer) + value = value.to_str(args[1]) + end + + @pointer.put_bytes(args[0], value, 0, args[1]) + elsif args.size == 1 + if value.is_a?(Pointer) + value = value.to_str(args[0] + 1) + else + value = value.chr + end + + @pointer.put_bytes(args[0], value, 0, 1) + end + rescue Truffle::FFI::NullPointerError + raise DLError.new("NULL pointer access") + end + + def size + @size + end + + def size=(size) + @size = size + end + + NULL = Pointer.new(0) + + end + + class Pinned + def initialize(object) + @object = object + end + + def ref + if @object.nil? + raise ClearedReferenceError, "`ref` called on a cleared object" + end + @object + end + + def clear + @object = nil + end + + def cleared? + @object.nil? + end + end + + RUBY_FREE = Handle.sym('free') + NULL = Pointer.new(0) + +end diff --git a/test/fiddle/test_closure.rb b/test/fiddle/test_closure.rb index 787a9b63..b0b9b2e5 100644 --- a/test/fiddle/test_closure.rb +++ b/test/fiddle/test_closure.rb @@ -6,6 +6,12 @@ module Fiddle class TestClosure < Fiddle::TestCase + def setup + if RUBY_ENGINE == "truffleruby" + omit("TruffleRuby doesn't support Fiddle::Closure") + end + end + def teardown super # We can't use ObjectSpace with JRuby. diff --git a/test/fiddle/test_fiddle.rb b/test/fiddle/test_fiddle.rb index b247ae15..305f39bd 100644 --- a/test/fiddle/test_fiddle.rb +++ b/test/fiddle/test_fiddle.rb @@ -9,6 +9,9 @@ def test_nil_true_etc if RUBY_ENGINE == "jruby" omit("Fiddle::Q* aren't supported with JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Q* aren't supported with TruffleRuby") + end assert_equal Fiddle::Qtrue, Fiddle.dlwrap(true) assert_equal Fiddle::Qfalse, Fiddle.dlwrap(false) @@ -27,6 +30,10 @@ def test_windows_constant def test_dlopen_linker_script_input_linux omit("This is only for Linux") unless RUBY_PLATFORM.match?("linux") + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Handle#close is unavailable with TruffleRuby") + end + if Dir.glob("/usr/lib/*/libncurses.so").empty? omit("libncurses.so is needed") end @@ -44,6 +51,10 @@ def test_dlopen_linker_script_input_linux def test_dlopen_linker_script_group_linux omit("This is only for Linux") unless RUBY_PLATFORM.match?("linux") + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Handle#close is unavailable with TruffleRuby") + end + # libc.so uses GROUP() on Debian GNU/Linux # $ cat /usr/lib/x86_64-linux-gnu/libc.so # /* GNU ld script diff --git a/test/fiddle/test_func.rb b/test/fiddle/test_func.rb index 5d69cc5f..23559071 100644 --- a/test/fiddle/test_func.rb +++ b/test/fiddle/test_func.rb @@ -64,6 +64,10 @@ def test_strtod end def test_qsort1 + if RUBY_ENGINE == "truffleruby" + omit("TruffleRuby doesn't support Fiddle::Closure") + end + closure_class = Class.new(Closure) do def call(x, y) Pointer.new(x)[0] <=> Pointer.new(y)[0] @@ -98,9 +102,13 @@ def call(x, y) end def test_snprintf + if RUBY_ENGINE == "truffleruby" + omit("TruffleRuby doesn't support variadic arguments") + end unless Fiddle.const_defined?("TYPE_VARIADIC") omit "libffi doesn't support variadic arguments" end + if Fiddle::WINDOWS snprintf_name = "_snprintf" else diff --git a/test/fiddle/test_function.rb b/test/fiddle/test_function.rb index b6ae8c14..4073b70e 100644 --- a/test/fiddle/test_function.rb +++ b/test/fiddle/test_function.rb @@ -41,6 +41,9 @@ def test_need_gvl? if RUBY_ENGINE == "jruby" omit("rb_str_dup() doesn't exist in JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle.dl{,un}wrap don't work in TruffleRuby") + end libruby = Fiddle.dlopen(nil) rb_str_dup = Function.new(libruby['rb_str_dup'], @@ -91,6 +94,10 @@ def test_call end def test_argument_count + if RUBY_ENGINE == "truffleruby" + omit("TruffleRuby doesn't support Fiddle::Closure") + end + closure_class = Class.new(Closure) do def call one 10 + one @@ -112,6 +119,9 @@ def test_last_error if RUBY_ENGINE == "jruby" omit("Fiddle.last_error doesn't work with JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle.last_error doesn't work with TruffleRuby") + end func = Function.new(@libc['strcpy'], [TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP) @@ -219,6 +229,9 @@ def test_no_memory_leak if RUBY_ENGINE == "jruby" omit("rb_obj_frozen_p() doesn't exist in JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("rb_obj_frozen_p() doesn't exit in TruffleRuby") + end if respond_to?(:assert_nothing_leaked_memory) rb_obj_frozen_p_symbol = Fiddle.dlopen(nil)["rb_obj_frozen_p"] diff --git a/test/fiddle/test_handle.rb b/test/fiddle/test_handle.rb index c952a7ef..6feca747 100644 --- a/test/fiddle/test_handle.rb +++ b/test/fiddle/test_handle.rb @@ -12,6 +12,9 @@ def test_to_i if RUBY_ENGINE == "jruby" omit("Fiddle::Handle#to_i is unavailable with JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Handle#to_i is unavailable with TruffleRuby") + end handle = Fiddle::Handle.new(LIBC_SO) assert_kind_of Integer, handle.to_i @@ -21,6 +24,9 @@ def test_to_ptr if RUBY_ENGINE == "jruby" omit("Fiddle::Handle#to_i is unavailable with JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Handle#to_i is unavailable with TruffleRuby") + end handle = Fiddle::Handle.new(LIBC_SO) ptr = handle.to_ptr @@ -58,6 +64,10 @@ def test_static_sym end unless /mswin|mingw/ =~ RUBY_PLATFORM def test_sym_closed_handle + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Handle#close is unavailable with TruffleRuby") + end + handle = Fiddle::Handle.new(LIBC_SO) handle.close assert_raise(DLError) { handle.sym("calloc") } @@ -85,11 +95,19 @@ def test_sym end def test_handle_close + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Handle#close is unavailable with TruffleRuby") + end + handle = Handle.new(LIBC_SO) assert_equal 0, handle.close end def test_handle_close_twice + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Handle#close is unavailable with TruffleRuby") + end + handle = Handle.new(LIBC_SO) handle.close assert_raise(DLError) do @@ -116,6 +134,10 @@ def test_initialize_flags end def test_enable_close + if RUBY_ENGINE == "truffleruby" + omit("Close on free is unavailable with TruffleRuby") + end + handle = Handle.new(LIBC_SO) assert !handle.close_enabled?, 'close is enabled' @@ -124,6 +146,10 @@ def test_enable_close end def test_disable_close + if RUBY_ENGINE == "truffleruby" + omit("Close on free is unavailable with TruffleRuby") + end + handle = Handle.new(LIBC_SO) handle.enable_close @@ -136,6 +162,9 @@ def test_file_name if RUBY_ENGINE == "jruby" omit("Fiddle::Handle#file_name doesn't exist in JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Handle#file_name is unavailable with TruffleRuby") + end file_name = Handle.new(LIBC_SO).file_name if file_name @@ -174,6 +203,9 @@ def test_NEXT rescue end + if RUBY_ENGINE == "truffleruby" + omit("-test-/dln/empty is unavailable with TruffleRuby") + end begin # BSD # diff --git a/test/fiddle/test_import.rb b/test/fiddle/test_import.rb index 26190325..afba8656 100644 --- a/test/fiddle/test_import.rb +++ b/test/fiddle/test_import.rb @@ -157,6 +157,9 @@ def test_io() if RUBY_ENGINE == "jruby" omit("BUILD_RUBY_PLATFORM doesn't exist in JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("IO as argument is unavailable with TruffleRuby") + end if( RUBY_PLATFORM != BUILD_RUBY_PLATFORM ) || !defined?(LIBC.fprintf) return diff --git a/test/fiddle/test_pointer.rb b/test/fiddle/test_pointer.rb index f17c8338..56c2f4ea 100644 --- a/test/fiddle/test_pointer.rb +++ b/test/fiddle/test_pointer.rb @@ -14,6 +14,9 @@ def test_can_read_write_memory if RUBY_ENGINE == "jruby" omit("Fiddle::Pointer.{read,write} don't exist in JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Pointer.{read,write} don't exist in TruffleRuby") + end # Allocate some memory Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP, Fiddle::RUBY_FREE) do |pointer| @@ -116,6 +119,9 @@ def test_inspect if RUBY_ENGINE == "jruby" omit("Fiddle::Pointer#inspect is incompatible on JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Pointer#inspect is incompatible on TruffleRuby") + end ptr = Pointer.new(0) inspect = ptr.inspect @@ -135,6 +141,9 @@ def test_to_ptr_io if RUBY_ENGINE == "jruby" omit("Fiddle::Pointer.to_ptr(IO) isn't supported with JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Pointer.to_ptr(IO) isn't supported with TruffleRuby") + end Pointer.malloc(10, Fiddle::RUBY_FREE) do |buf| File.open(__FILE__, 'r') do |f| @@ -186,6 +195,9 @@ def test_ref_ptr if RUBY_ENGINE == "jruby" omit("Fiddle.dlwrap([]) isn't supported with JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle.dlwrap([]) isn't supported with TruffleRuby") + end ary = [0,1,2,4,5] addr = Pointer.new(dlwrap(ary)) @@ -198,6 +210,9 @@ def test_to_value if RUBY_ENGINE == "jruby" omit("Fiddle.dlwrap([]) isn't supported with JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle.dlwrap([]) isn't supported with TruffleRuby") + end ary = [0,1,2,4,5] addr = Pointer.new(dlwrap(ary)) From e3b5d07453c4633c90195f22a1e2786970ca84a0 Mon Sep 17 00:00:00 2001 From: Sutou Kouhei Date: Wed, 2 Oct 2024 13:44:30 +0900 Subject: [PATCH 2/2] Add TruffleRuby 23.1 and 24.0 --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 972bcce5..54b51ce0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,8 @@ jobs: - '3.2' - debug - jruby + - truffleruby-23.1 + - truffleruby-24.0 - truffleruby include: - { os: windows-latest , ruby: mingw } @@ -34,6 +36,8 @@ jobs: - { os: macos-14 , ruby: '2.5' } - { os: windows-latest , ruby: '3.0' } - { os: windows-latest , ruby: debug } + - { os: windows-latest , ruby: truffleruby-23.1 } + - { os: windows-latest , ruby: truffleruby-24.0 } - { os: windows-latest , ruby: truffleruby } steps: