Skip to content

Commit 01607d7

Browse files
committed
[GR-17457] Fixes for problems found in oj gem CI.
PullRequest: truffleruby/3453
2 parents 8519c94 + 6b675a6 commit 01607d7

File tree

13 files changed

+146
-11
lines changed

13 files changed

+146
-11
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ Compatibility:
2929
* Fix `Kernel#sprintf` formatting for `%c` when used non-ASCII encoding (#2369, @andrykonchin).
3030
* Fix `Kernel#sprintf` argument casting for `%c` (@andrykonchin).
3131
* Implement the `rb_enc_strlen` function for use by native extensions (@nirvdrum).
32+
* Match tag values used by `rb_protect` and `rb_jump_tag` for the `tk` gem (#2556, @aardvark179).
33+
* Implement `rb_eval_cmd_kw` to support the `tk` gem (#2556, @aardvark179).
34+
* Fix `rb_class2name` to call `inspect` on anonymous classes like in CRuby (#2701, @aardvark179).
35+
* Implement `rb_ivar_foreach` to iterate over instance and class variables like in CRuby (#2701, @aardvark179).
3236

3337
Performance:
3438

lib/cext/ABI_version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
9
1+
10

lib/truffle/truffle/cext.rb

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,34 @@ def rb_f_global_variables
484484
Kernel.global_variables
485485
end
486486

487+
def rb_ivar_foreach(object, func, arg)
488+
keys_and_vals = []
489+
if Module === object
490+
keys_and_vals << :__classpath__
491+
keys_and_vals << object.name
492+
493+
object.class_variables.each do |key|
494+
keys_and_vals << key
495+
keys_and_vals << object.class_variable_get(key)
496+
end
497+
end
498+
object.instance_variables.each do |key|
499+
keys_and_vals << key
500+
keys_and_vals << object.instance_variable_get(key)
501+
end
502+
503+
keys_and_vals.each_slice(2) do |key, val|
504+
st_result = Truffle::Interop.execute_without_conversion(
505+
func, Primitive.cext_sym2id(key), Primitive.cext_wrap(val), arg)
506+
507+
case st_result
508+
when ST_CONTINUE
509+
when ST_STOP then break
510+
else raise ArgumentError, "Unknown 'func' return value: #{st_result}"
511+
end
512+
end
513+
end
514+
487515
def rb_obj_instance_variables(object)
488516
object.instance_variables
489517
end
@@ -1610,14 +1638,17 @@ def warning?
16101638
end
16111639

16121640
def rb_time_nano_new(sec, nsec)
1613-
Time.at sec, Rational(nsec, 1000)
1641+
Time.at sec, nsec, :nanosecond
16141642
end
16151643

16161644
def rb_time_timespec_new(sec, nsec, offset, is_utc, is_local)
1617-
time = rb_time_nano_new(sec, nsec)
1618-
return time if is_local
1619-
return time.getgm if is_utc
1620-
time.getlocal(offset)
1645+
if is_local
1646+
Time.at(sec, nsec, :nanosecond)
1647+
elsif is_utc
1648+
Time.at(sec, nsec, :nanosecond, in: 0).getgm
1649+
else
1650+
Time.at(sec, nsec, :nanosecond, in: offset)
1651+
end
16211652
end
16221653

16231654
def rb_time_num_new(timev, off)
@@ -1727,7 +1758,7 @@ def rb_class_inherited_p(ruby_module, object)
17271758
def rb_get_special_vars
17281759
vars = Primitive.cext_special_variables_from_stack
17291760
unless vars
1730-
vars = Truffle::ThreadOperations.ruby_caller_special_variables([Truffle::CExt, Truffle::Interop.singleton_class])
1761+
vars = Truffle::ThreadOperations.ruby_caller_special_variables([Truffle::CExt, Truffle::CExt.singleton_class, Truffle::Interop.singleton_class])
17311762
end
17321763
vars
17331764
end
@@ -1917,4 +1948,15 @@ def rb_exception_set_message(e, mesg)
19171948
def rb_global_variable(obj)
19181949
GLOBALLY_PRESERVED_VALUES << obj
19191950
end
1951+
1952+
GC_REGISTERED_ADDRESSES = {}
1953+
def rb_gc_register_address(address, obj)
1954+
Truffle::Interop.to_native(address) unless Truffle::Interop.pointer?(address)
1955+
GC_REGISTERED_ADDRESSES[address] = obj
1956+
end
1957+
1958+
def rb_gc_unregister_address(address)
1959+
Truffle::Interop.to_native(address) unless Truffle::Interop.pointer?(address)
1960+
GC_REGISTERED_ADDRESSES.delete(address)
1961+
end
19201962
end

spec/ruby/optional/capi/class_spec.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@
204204
it "returns a string for an anonymous class" do
205205
@s.rb_class2name(Class.new).should be_kind_of(String)
206206
end
207+
208+
it "returns a string beginning with # for an anonymous class" do
209+
@s.rb_class2name(Struct.new(:x, :y).new(1, 2).class).should.start_with?('#')
210+
end
207211
end
208212

209213
describe "rb_class_path" do

spec/ruby/optional/capi/ext/object_spec.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,18 @@ static VALUE object_spec_rb_class_inherited_p(VALUE self, VALUE mod, VALUE arg)
393393
return rb_class_inherited_p(mod, arg);
394394
}
395395

396+
static int foreach_f(ID key, VALUE val, VALUE ary) {
397+
rb_ary_push(ary, ID2SYM(key));
398+
rb_ary_push(ary, val);
399+
return ST_CONTINUE;
400+
}
401+
402+
static VALUE object_spec_rb_ivar_foreach(VALUE self, VALUE obj) {
403+
VALUE ary = rb_ary_new();
404+
rb_ivar_foreach(obj, foreach_f, ary);
405+
return ary;
406+
}
407+
396408
static VALUE speced_allocator(VALUE klass) {
397409
VALUE flags = 0;
398410
VALUE instance;
@@ -508,6 +520,7 @@ void Init_object_spec(void) {
508520
rb_define_method(cls, "speced_allocator?", speced_allocator_p, 1);
509521
rb_define_method(cls, "custom_alloc_func?", custom_alloc_func_p, 1);
510522
rb_define_method(cls, "not_implemented_method", rb_f_notimplement, -1);
523+
rb_define_method(cls, "rb_ivar_foreach", object_spec_rb_ivar_foreach, 1);
511524
}
512525

513526
#ifdef __cplusplus
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
class CApiObjectSpecs
2+
class IVars
3+
def initialize
4+
@a = 3
5+
@b = 7
6+
@c = 4
7+
end
8+
9+
def self.set_class_variables
10+
@@foo = :a
11+
@@bar = :b
12+
@@baz = :c
13+
end
14+
end
15+
16+
module MVars
17+
@@mvar = :foo
18+
@@mvar2 = :bar
19+
20+
@ivar = :baz
21+
end
22+
23+
module CVars
24+
@@cvar = :foo
25+
@@cvar2 = :bar
26+
27+
@ivar = :baz
28+
end
29+
end

spec/ruby/optional/capi/object_spec.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require_relative 'spec_helper'
2+
require_relative 'fixtures/object'
23

34
load_extension("object")
45

@@ -983,5 +984,24 @@ def reach
983984
@o.speced_allocator?(parent).should == true
984985
end
985986
end
987+
988+
describe "rb_ivar_foreach" do
989+
it "calls the callback function for each instance variable on an object" do
990+
o = CApiObjectSpecs::IVars.new
991+
ary = @o.rb_ivar_foreach(o)
992+
ary.should == [:@a, 3, :@b, 7, :@c, 4]
993+
end
994+
995+
it "calls the callback function for each cvar and ivar on a class" do
996+
ary = @o.rb_ivar_foreach(CApiObjectSpecs::CVars)
997+
ary.should == [:__classpath__, 'CApiObjectSpecs::CVars', :@@cvar, :foo, :@@cvar2, :bar, :@ivar, :baz]
998+
end
999+
1000+
it "calls the callback function for each cvar and ivar on a module" do
1001+
ary = @o.rb_ivar_foreach(CApiObjectSpecs::MVars)
1002+
ary.should == [:__classpath__, 'CApiObjectSpecs::MVars', :@@mvar, :foo, :@@mvar2, :bar, :@ivar, :baz]
1003+
end
1004+
1005+
end
9861006
end
9871007
end

src/main/c/cext/class.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ VALUE rb_class_name(VALUE ruby_class) {
7171
VALUE name = RUBY_INVOKE(ruby_class, "name");
7272

7373
if (NIL_P(name)) {
74-
return rb_class_name(rb_obj_class(ruby_class));
74+
return RUBY_INVOKE(ruby_class, "inspect");
7575
} else {
7676
return name;
7777
}

src/main/c/cext/gc.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@
1313
// GC, rb_gc_*
1414

1515
void rb_gc_register_address(VALUE *address) {
16+
/* TODO: This should guard the address of the pointer, not the
17+
object pointed to, but we haven't yet found a good way to implement
18+
that, or a real world use case where it is required. */
19+
polyglot_invoke(RUBY_CEXT, "rb_gc_register_address", address, rb_tr_unwrap(*address));
1620
}
1721

1822
void rb_gc_unregister_address(VALUE *address) {
19-
// VALUE is only ever in managed memory. So, it is already garbage collected.
23+
polyglot_invoke(RUBY_CEXT, "rb_gc_unregister_address", address);
2024
}
2125

2226
void rb_gc_mark(VALUE ptr) {

src/main/c/cext/ivar.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ VALUE rb_ivar_lookup(VALUE object, const char *name, VALUE default_value) {
5050

5151
// Needed to gem install oj
5252
void rb_ivar_foreach(VALUE obj, int (*func)(ANYARGS), st_data_t arg) {
53-
rb_tr_error("rb_ivar_foreach not implemented");
53+
polyglot_invoke(RUBY_CEXT, "rb_ivar_foreach", rb_tr_unwrap(obj), func, (void*)arg);
5454
}
5555

5656
VALUE rb_attr_get(VALUE object, ID name) {

0 commit comments

Comments
 (0)