Previously it would bypass the `FL_ABLE` check, but
since shapes introduction, it started having a different
behavior than `OBJ_FREEZE`, as it would onyl set the `FL_FREEZE`
flag, but not update the shape.
I have no indication of this causing a bug yet, but it seems
like a trap waiting to happen.
This `st_table` is used to both mark and pin classes
defined from the C API. But `vm->mark_object_ary` already
does both much more efficiently.
Currently a Ruby process starts with 252 rooted classes,
which uses `7224B` in an `st_table` or `2016B` in an `RArray`.
So a baseline of 5kB saved, but since `mark_object_ary` is
preallocated with `1024` slots but only use `405` of them,
it's a net `7kB` save.
`vm->mark_object_ary` is also being refactored.
Prior to this changes, `mark_object_ary` was a regular `RArray`, but
since this allows for references to be moved, it was marked a second
time from `rb_vm_mark()` to pin these objects.
This has the detrimental effect of marking these references on every
minors even though it's a mostly append only list.
But using a custom TypedData we can save from having to mark
all the references on minor GC runs.
Addtionally, immediate values are now ignored and not appended
to `vm->mark_object_ary` as it's just wasted space.
[Bug #20311]
`rb_define_class_under` assumes it's called from C and that the
reference might be held in a C global variable, so it adds the
class to the VM root.
In the case of `Struct.new('Name')` it's wasteful and make
the struct immortal.
Implements [Feature #19000]
This commit adds copy with changes functionality for `Data` objects
using a new method `Data#with`.
Since Data objects are immutable, the only way to change them is by
creating a copy. This PR adds a `with` method for `Data` class instances
that optionally takes keyword arguments.
If the `with` method is called with no arguments, the behaviour is the
same as the `Kernel#dup` method, i.e. a new shallow copy is created
with no field values changed.
However, if keyword arguments are supplied to the `with` method, then
the copy is created with the specified field values changed. For
example:
```ruby
Point = Data.define(:x, :y)
point = Point.new(x: 1, y: 2)
point.with(x: 3) # => #<data Point x: 3, y: 2>
```
Passing positional arguments to `with` or passing keyword arguments to
it that do not correspond to any of the members of the Data class will
raise an `ArgumentError`.
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
struct_ivar_get recently started using rb_class_superclass to
resolve super instead of RCLASS_SUPER. This change made
Qnil a possible case we need to return from within the
struct_ivar_get for loop.
rb_ary_tmp_new suggests that the array is temporary in some way, but
that's not true, it just creates an array that's hidden and not on the
transient heap. This commit renames it to rb_ary_hidden_new.
I used this regex:
([A-Za-z]+)\.html#(?:class|module)-[A-Za-z]+-label-([A-Za-z0-9\-\+]+)
And performed a global find & replace for this:
rdoc-ref:$1@$2