Skip to content

Commit

Permalink
[GR-17457] Fixes for problems found in oj gem CI.
Browse files Browse the repository at this point in the history
PullRequest: truffleruby/3453
  • Loading branch information
aardvark179 committed Sep 1, 2022
2 parents 8519c94 + 6b675a6 commit 01607d7
Show file tree
Hide file tree
Showing 13 changed files with 146 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ Compatibility:
* Fix `Kernel#sprintf` formatting for `%c` when used non-ASCII encoding (#2369, @andrykonchin).
* Fix `Kernel#sprintf` argument casting for `%c` (@andrykonchin).
* Implement the `rb_enc_strlen` function for use by native extensions (@nirvdrum).
* Match tag values used by `rb_protect` and `rb_jump_tag` for the `tk` gem (#2556, @aardvark179).
* Implement `rb_eval_cmd_kw` to support the `tk` gem (#2556, @aardvark179).
* Fix `rb_class2name` to call `inspect` on anonymous classes like in CRuby (#2701, @aardvark179).
* Implement `rb_ivar_foreach` to iterate over instance and class variables like in CRuby (#2701, @aardvark179).

Performance:

Expand Down
2 changes: 1 addition & 1 deletion lib/cext/ABI_version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
9
10
54 changes: 48 additions & 6 deletions lib/truffle/truffle/cext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,34 @@ def rb_f_global_variables
Kernel.global_variables
end

def rb_ivar_foreach(object, func, arg)
keys_and_vals = []
if Module === object
keys_and_vals << :__classpath__
keys_and_vals << object.name

object.class_variables.each do |key|
keys_and_vals << key
keys_and_vals << object.class_variable_get(key)
end
end
object.instance_variables.each do |key|
keys_and_vals << key
keys_and_vals << object.instance_variable_get(key)
end

keys_and_vals.each_slice(2) do |key, val|
st_result = Truffle::Interop.execute_without_conversion(
func, Primitive.cext_sym2id(key), Primitive.cext_wrap(val), arg)

case st_result
when ST_CONTINUE
when ST_STOP then break
else raise ArgumentError, "Unknown 'func' return value: #{st_result}"
end
end
end

def rb_obj_instance_variables(object)
object.instance_variables
end
Expand Down Expand Up @@ -1610,14 +1638,17 @@ def warning?
end

def rb_time_nano_new(sec, nsec)
Time.at sec, Rational(nsec, 1000)
Time.at sec, nsec, :nanosecond
end

def rb_time_timespec_new(sec, nsec, offset, is_utc, is_local)
time = rb_time_nano_new(sec, nsec)
return time if is_local
return time.getgm if is_utc
time.getlocal(offset)
if is_local
Time.at(sec, nsec, :nanosecond)
elsif is_utc
Time.at(sec, nsec, :nanosecond, in: 0).getgm
else
Time.at(sec, nsec, :nanosecond, in: offset)
end
end

def rb_time_num_new(timev, off)
Expand Down Expand Up @@ -1727,7 +1758,7 @@ def rb_class_inherited_p(ruby_module, object)
def rb_get_special_vars
vars = Primitive.cext_special_variables_from_stack
unless vars
vars = Truffle::ThreadOperations.ruby_caller_special_variables([Truffle::CExt, Truffle::Interop.singleton_class])
vars = Truffle::ThreadOperations.ruby_caller_special_variables([Truffle::CExt, Truffle::CExt.singleton_class, Truffle::Interop.singleton_class])
end
vars
end
Expand Down Expand Up @@ -1917,4 +1948,15 @@ def rb_exception_set_message(e, mesg)
def rb_global_variable(obj)
GLOBALLY_PRESERVED_VALUES << obj
end

GC_REGISTERED_ADDRESSES = {}
def rb_gc_register_address(address, obj)
Truffle::Interop.to_native(address) unless Truffle::Interop.pointer?(address)
GC_REGISTERED_ADDRESSES[address] = obj
end

def rb_gc_unregister_address(address)
Truffle::Interop.to_native(address) unless Truffle::Interop.pointer?(address)
GC_REGISTERED_ADDRESSES.delete(address)
end
end
4 changes: 4 additions & 0 deletions spec/ruby/optional/capi/class_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@
it "returns a string for an anonymous class" do
@s.rb_class2name(Class.new).should be_kind_of(String)
end

it "returns a string beginning with # for an anonymous class" do
@s.rb_class2name(Struct.new(:x, :y).new(1, 2).class).should.start_with?('#')
end
end

describe "rb_class_path" do
Expand Down
13 changes: 13 additions & 0 deletions spec/ruby/optional/capi/ext/object_spec.c
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,18 @@ static VALUE object_spec_rb_class_inherited_p(VALUE self, VALUE mod, VALUE arg)
return rb_class_inherited_p(mod, arg);
}

static int foreach_f(ID key, VALUE val, VALUE ary) {
rb_ary_push(ary, ID2SYM(key));
rb_ary_push(ary, val);
return ST_CONTINUE;
}

static VALUE object_spec_rb_ivar_foreach(VALUE self, VALUE obj) {
VALUE ary = rb_ary_new();
rb_ivar_foreach(obj, foreach_f, ary);
return ary;
}

static VALUE speced_allocator(VALUE klass) {
VALUE flags = 0;
VALUE instance;
Expand Down Expand Up @@ -508,6 +520,7 @@ void Init_object_spec(void) {
rb_define_method(cls, "speced_allocator?", speced_allocator_p, 1);
rb_define_method(cls, "custom_alloc_func?", custom_alloc_func_p, 1);
rb_define_method(cls, "not_implemented_method", rb_f_notimplement, -1);
rb_define_method(cls, "rb_ivar_foreach", object_spec_rb_ivar_foreach, 1);
}

#ifdef __cplusplus
Expand Down
29 changes: 29 additions & 0 deletions spec/ruby/optional/capi/fixtures/object.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class CApiObjectSpecs
class IVars
def initialize
@a = 3
@b = 7
@c = 4
end

def self.set_class_variables
@@foo = :a
@@bar = :b
@@baz = :c
end
end

module MVars
@@mvar = :foo
@@mvar2 = :bar

@ivar = :baz
end

module CVars
@@cvar = :foo
@@cvar2 = :bar

@ivar = :baz
end
end
20 changes: 20 additions & 0 deletions spec/ruby/optional/capi/object_spec.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require_relative 'spec_helper'
require_relative 'fixtures/object'

load_extension("object")

Expand Down Expand Up @@ -983,5 +984,24 @@ def reach
@o.speced_allocator?(parent).should == true
end
end

describe "rb_ivar_foreach" do
it "calls the callback function for each instance variable on an object" do
o = CApiObjectSpecs::IVars.new
ary = @o.rb_ivar_foreach(o)
ary.should == [:@a, 3, :@b, 7, :@c, 4]
end

it "calls the callback function for each cvar and ivar on a class" do
ary = @o.rb_ivar_foreach(CApiObjectSpecs::CVars)
ary.should == [:__classpath__, 'CApiObjectSpecs::CVars', :@@cvar, :foo, :@@cvar2, :bar, :@ivar, :baz]
end

it "calls the callback function for each cvar and ivar on a module" do
ary = @o.rb_ivar_foreach(CApiObjectSpecs::MVars)
ary.should == [:__classpath__, 'CApiObjectSpecs::MVars', :@@mvar, :foo, :@@mvar2, :bar, :@ivar, :baz]
end

end
end
end
2 changes: 1 addition & 1 deletion src/main/c/cext/class.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ VALUE rb_class_name(VALUE ruby_class) {
VALUE name = RUBY_INVOKE(ruby_class, "name");

if (NIL_P(name)) {
return rb_class_name(rb_obj_class(ruby_class));
return RUBY_INVOKE(ruby_class, "inspect");
} else {
return name;
}
Expand Down
6 changes: 5 additions & 1 deletion src/main/c/cext/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@
// GC, rb_gc_*

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

void rb_gc_unregister_address(VALUE *address) {
// VALUE is only ever in managed memory. So, it is already garbage collected.
polyglot_invoke(RUBY_CEXT, "rb_gc_unregister_address", address);
}

void rb_gc_mark(VALUE ptr) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/c/cext/ivar.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ VALUE rb_ivar_lookup(VALUE object, const char *name, VALUE default_value) {

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

VALUE rb_attr_get(VALUE object, ID name) {
Expand Down
8 changes: 8 additions & 0 deletions src/main/c/cext/struct.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ VALUE rb_struct_new(VALUE klass, ...) {
return RUBY_CEXT_INVOKE("rb_struct_new_no_splat", klass, ary);
}

VALUE rb_struct_s_members(VALUE klass) {
return RUBY_INVOKE(klass, "rb_struct_s_members");
}

VALUE rb_struct_members(VALUE s) {
return RUBY_INVOKE(s, "rb_struct_members");
}

VALUE rb_struct_size(VALUE s) {
return RUBY_INVOKE(s, "size");
}
11 changes: 11 additions & 0 deletions src/main/java/org/truffleruby/cext/CExtNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,17 @@ protected int rbEncMbcToCodepoint(Object string,
}
}

@Primitive(name = "cext_sym2id")
public abstract static class Sym2IDNode extends PrimitiveArrayArgumentsNode {

@Specialization
protected Object sym2id(RubySymbol symbol,
@Cached SymbolToIDNode symbolToIDNode) {
return symbolToIDNode.execute(symbol);
}

}

@Primitive(name = "cext_wrap")
public abstract static class WrapValueNode extends PrimitiveArrayArgumentsNode {

Expand Down
2 changes: 1 addition & 1 deletion src/main/ruby/truffleruby/core/range.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def initialize(first, last, exclude_end = false)
end
end

Primitive.range_initialize self, first, last, exclude_end
Primitive.range_initialize self, first, last, Primitive.as_boolean(exclude_end)
end
private :initialize

Expand Down

0 comments on commit 01607d7

Please sign in to comment.