fix `defined?(@ivar)` with Ractors

`defined?(@ivar)` on the non main Ractor has two issues:

1. raising an exception

```ruby
class C
  @iv1 = []
  def self.defined_iv1 = defined?(@iv1)
end

Ractor.new{
  p C.defined_iv1
  #=> can not get unshareable values from instance variables of classes/modules from non-main Ractors (Ractor::IsolationError)
}.take
```

-> Do not raise an exception but return `"instance-variable"` because
it is defined.

2. returning `"instance-variable"` if there is not defined.

```
class C
  # @iv2 is not defined
  def self.defined_iv2 = defined?(@iv2)
end

Ractor.new{
  p C.defined_iv2 #=> "instance-variable"
}.take
```

-> returns `nil`
This commit is contained in:
Koichi Sasada 2024-07-11 05:59:14 +09:00
Родитель ef563a696d
Коммит 43aee3393d
2 изменённых файлов: 21 добавлений и 1 удалений

Просмотреть файл

@ -1086,6 +1086,20 @@ assert_equal '333', %q{
a + b + c + d + e + f
}
assert_equal '["instance-variable", "instance-variable", nil]', %q{
class C
@iv1 = ""
@iv2 = 42
def self.iv1 = defined?(@iv1) # "instance-variable"
def self.iv2 = defined?(@iv2) # "instance-variable"
def self.iv3 = defined?(@iv3) # nil
end
Ractor.new{
[C.iv1, C.iv2, C.iv3]
}.take
}
# moved objects have their shape properly set to original object's shape
assert_equal '1234', %q{
class Obj

Просмотреть файл

@ -1252,7 +1252,13 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
// and modules. So we can skip locking.
// Second, other ractors need to check the shareability of the
// values returned from the class ivars.
goto general_path;
if (default_value == Qundef) { // defined?
return rb_ivar_defined(obj, id) ? Qtrue : Qundef;
}
else {
goto general_path;
}
}
ivar_list = RCLASS_IVPTR(obj);