From 77cc80847c1d1540dcc200bfcd4265eec70f5dcf Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Mon, 11 Dec 2023 14:35:23 +0100 Subject: [PATCH 1/4] Fix rb_integer_pack() for values between 2**62 and 2**63 * Fixes https://github.com/oracle/truffleruby/issues/3352 * Add specs for it. --- lib/truffle/truffle/cext.rb | 4 ++++ spec/ruby/optional/capi/integer_spec.rb | 17 +++++++++++++++++ src/main/c/cext/integer.c | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/truffle/truffle/cext.rb b/lib/truffle/truffle/cext.rb index a7ff9db07016..5987e170d2ec 100644 --- a/lib/truffle/truffle/cext.rb +++ b/lib/truffle/truffle/cext.rb @@ -844,6 +844,10 @@ def rb_intern(str) Primitive.string_to_symbol(str, true) end + def rb_int_cmp(a, b) + a <=> b + end + def rb_int_positive_pow(a, b) a ** b end diff --git a/spec/ruby/optional/capi/integer_spec.rb b/spec/ruby/optional/capi/integer_spec.rb index e26735824e8f..089872381cbb 100644 --- a/spec/ruby/optional/capi/integer_spec.rb +++ b/spec/ruby/optional/capi/integer_spec.rb @@ -140,6 +140,23 @@ result.should == -1 @words.should == "\x11\x32\x54\x76\x98\xBA\xDC\xFE" end + + it "converts numbers near the fixnum limit successfully" do + result = @s.rb_integer_pack(0x7123_4567_89ab_cdef, @words, 1, 8, 0, + CApiIntegerSpecs::NATIVE|CApiIntegerSpecs::PACK_2COMP) + result.should == 1 + @words.should == "\xEF\xCD\xAB\x89\x67\x45\x23\x71" + + result = @s.rb_integer_pack(2**62-1, @words, 1, 8, 0, + CApiIntegerSpecs::NATIVE|CApiIntegerSpecs::PACK_2COMP) + result.should == 1 + @words.should == "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x3F" + + result = @s.rb_integer_pack(2**63-1, @words, 1, 8, 0, + CApiIntegerSpecs::NATIVE|CApiIntegerSpecs::PACK_2COMP) + result.should == 1 + @words.should == "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F" + end end end end diff --git a/src/main/c/cext/integer.c b/src/main/c/cext/integer.c index 91bb3ed6cea8..e41ffe0449b1 100644 --- a/src/main/c/cext/integer.c +++ b/src/main/c/cext/integer.c @@ -101,7 +101,7 @@ int rb_integer_pack(VALUE value, void *words, size_t numwords, size_t wordsize, long l = NUM2LONG(value); sign = (l > 0) - (l < 0); } else { - sign = polyglot_as_i32(polyglot_invoke(rb_tr_unwrap(value), "<=>", 0)); + sign = polyglot_as_i32(RUBY_CEXT_INVOKE_NO_WRAP("rb_int_cmp", value, INT2FIX(0))); } int bytes_needed = size / 8 + (size % 8 == 0 ? 0 : 1); int words_needed = bytes_needed / wordsize + (bytes_needed % wordsize == 0 ? 0 : 1); From b775214e72b1a7f36c72dd412e222aafc6986888 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Mon, 11 Dec 2023 14:50:24 +0100 Subject: [PATCH 2/4] Review and fix usages of `polyglot_invoke(rb_tr_unwrap(` and `RUBY_INVOKE(` * These only work if the unwrapped value is never a Java primitive (boolean, int, long, double). --- lib/truffle/truffle/cext.rb | 36 +++++++++++++++++++++++++++++++++++ src/main/c/cext/class.c | 2 +- src/main/c/cext/define.c | 2 +- src/main/c/cext/encoding.c | 2 +- src/main/c/cext/object.c | 8 ++++---- src/main/c/cext/rational.c | 4 ++-- src/main/c/cext/truffleruby.c | 2 +- 7 files changed, 46 insertions(+), 10 deletions(-) diff --git a/lib/truffle/truffle/cext.rb b/lib/truffle/truffle/cext.rb index 5987e170d2ec..29f460739d33 100644 --- a/lib/truffle/truffle/cext.rb +++ b/lib/truffle/truffle/cext.rb @@ -424,16 +424,44 @@ def RB_OBJ_TAINTABLE(object) end end + def rb_obj_clone(object) + object.clone + end + + def rb_obj_dup(object) + object.dup + end + + def rb_obj_encoding(object) + object.encoding + end + FREEZE_METHOD = Kernel.instance_method :freeze def rb_obj_freeze(obj) FREEZE_METHOD.bind(obj).call end + def rb_obj_frozen_p(object) + object.frozen? + end + + def rb_obj_id(object) + object.object_id + end + def rb_float_new(value) value.to_f end + def rb_flt_rationalize(value) + value.rationalize + end + + def rb_flt_rationalize_with_prec(value, prec) + value.rationalize(prec) + end + def rb_absint_singlebit_p(val) Primitive.rb_int_singlebit_p(val.abs) end @@ -556,6 +584,10 @@ def rb_class_of(object) Primitive.metaclass(object) end + def rb_singleton_class(object) + object.singleton_class + end + def rb_class_real(ruby_class) while ruby_class.singleton_class? ruby_class = ruby_class.superclass @@ -1383,6 +1415,10 @@ def rb_equal(a, b) Primitive.same_or_equal?(a, b) end + def rb_tr_obj_equal(a, b) + Primitive.equal?(a, b) + end + def rb_obj_call_init(obj, args, block) obj.__send__ :initialize, *args, &block end diff --git a/src/main/c/cext/class.c b/src/main/c/cext/class.c index f3b3a0885c88..aa066a57e123 100644 --- a/src/main/c/cext/class.c +++ b/src/main/c/cext/class.c @@ -48,7 +48,7 @@ VALUE rb_class_of(VALUE object) { } VALUE rb_singleton_class(VALUE object) { - return RUBY_INVOKE(object, "singleton_class"); + return RUBY_CEXT_INVOKE("rb_singleton_class", object); } VALUE rb_obj_alloc(VALUE ruby_class) { diff --git a/src/main/c/cext/define.c b/src/main/c/cext/define.c index d6cc8a1bdd86..0002120eacc2 100644 --- a/src/main/c/cext/define.c +++ b/src/main/c/cext/define.c @@ -74,7 +74,7 @@ void rb_define_global_function(const char *name, VALUE (*function)(ANYARGS), int #undef rb_define_singleton_method void rb_define_singleton_method(VALUE object, const char *name, VALUE (*function)(ANYARGS), int argc) { - rb_define_method(RUBY_INVOKE(object, "singleton_class"), name, function, argc); + rb_define_method(rb_singleton_class(object), name, function, argc); } void rb_define_alias(VALUE module, const char *new_name, const char *old_name) { diff --git a/src/main/c/cext/encoding.c b/src/main/c/cext/encoding.c index 1475cab0e656..2b767fc3f065 100644 --- a/src/main/c/cext/encoding.c +++ b/src/main/c/cext/encoding.c @@ -219,7 +219,7 @@ int rb_enc_to_index(rb_encoding *enc) { } VALUE rb_obj_encoding(VALUE obj) { - return RUBY_INVOKE(obj, "encoding"); + return RUBY_CEXT_INVOKE("rb_obj_encoding", obj); } int rb_to_encoding_index(VALUE enc) { diff --git a/src/main/c/cext/object.c b/src/main/c/cext/object.c index 51b792244616..97595b1cc91d 100644 --- a/src/main/c/cext/object.c +++ b/src/main/c/cext/object.c @@ -115,15 +115,15 @@ VALUE rb_obj_reveal(VALUE obj, VALUE klass) { } VALUE rb_obj_clone(VALUE obj) { - return RUBY_INVOKE(obj, "clone"); + return RUBY_CEXT_INVOKE("rb_obj_clone", obj); } VALUE rb_obj_dup(VALUE object) { - return RUBY_INVOKE(object, "dup"); + return RUBY_CEXT_INVOKE("rb_obj_dup", object); } VALUE rb_obj_id(VALUE object) { - return RUBY_INVOKE(object, "object_id"); + return RUBY_CEXT_INVOKE("rb_obj_id", object); } // The semantics of SameOrEqualNode: a.equal?(b) || a == b @@ -138,7 +138,7 @@ void rb_obj_call_init(VALUE object, int argc, const VALUE *argv) { // frozen status VALUE rb_obj_frozen_p(VALUE object) { - return RUBY_INVOKE(object, "frozen?"); + return RUBY_CEXT_INVOKE("rb_obj_frozen_p", object); } VALUE rb_obj_freeze(VALUE object) { diff --git a/src/main/c/cext/rational.c b/src/main/c/cext/rational.c index bd6a35faf555..4db99e35189c 100644 --- a/src/main/c/cext/rational.c +++ b/src/main/c/cext/rational.c @@ -33,9 +33,9 @@ VALUE rb_rational_den(VALUE rat) { } VALUE rb_flt_rationalize_with_prec(VALUE value, VALUE precision) { - return RUBY_INVOKE(value, "rationalize", precision); + return RUBY_CEXT_INVOKE("rb_flt_rationalize_with_prec", value, precision); } VALUE rb_flt_rationalize(VALUE value) { - return RUBY_INVOKE(value, "rationalize"); + return RUBY_CEXT_INVOKE("rb_flt_rationalize", value); } diff --git a/src/main/c/cext/truffleruby.c b/src/main/c/cext/truffleruby.c index 2e207d3e016b..61feb4a7d828 100644 --- a/src/main/c/cext/truffleruby.c +++ b/src/main/c/cext/truffleruby.c @@ -31,7 +31,7 @@ VALUE rb_java_to_string(VALUE obj) { // BasicObject#equal? int rb_tr_obj_equal(VALUE first, VALUE second) { - return RTEST(RUBY_INVOKE(first, "equal?", second)); + return RTEST(RUBY_CEXT_INVOKE("rb_tr_obj_equal", first, second)); } void rb_tr_warn_va_list(const char *fmt, va_list args) { From 2a46a3c636f763ad5664bd77bb8cbaefb0e2cade Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Mon, 11 Dec 2023 14:36:47 +0100 Subject: [PATCH 3/4] Bump ABI check --- lib/cext/ABI_check.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cext/ABI_check.txt b/lib/cext/ABI_check.txt index 1e8b31496214..7f8f011eb73d 100644 --- a/lib/cext/ABI_check.txt +++ b/lib/cext/ABI_check.txt @@ -1 +1 @@ -6 +7 From e4592d92a7ccd1fa433fadcb47ae2cb62405c0ee Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Mon, 11 Dec 2023 14:54:53 +0100 Subject: [PATCH 4/4] Add ChangeLog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cb2df4a0e14..5bfedc2ac6a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Bug fixes: * Fix `IO.copy_stream` with a `Tempfile` destination (#3280, @eregon). * Fix `Regexp.union` negotiating the wrong result encoding (#3287, @nirvdrum, @simonlevasseur). * Fix `Proc#parameters` and return all the numbered parameters lower than the used explicitly ones (@andrykonchin). +* Fix some C API functions which were failing when called with Ruby values represented as Java primitives (#3352, @eregon). Compatibility: