Implement Object Shapes - #6386
Conversation
985c6d8 to
6422f8d
Compare
| } | ||
| } | ||
| RUBY_SYMBOL_EXPORT_BEGIN | ||
| void rb_obj_freeze_inline(VALUE obj); |
There was a problem hiding this comment.
inline function is used for performance but is it hard to keep inline?
There was a problem hiding this comment.
It seems like the idea is to avoid exporting rb_shape_transition_shape_frozen as C API.
I think it's okay to make it a non-inline function for C API users even while the _inline name becomes a lie, but as Koichi said, it's worth checking if it impacts the interpreter's performance. If it does, you could define it as an inline function in an internal header, and use it as the implementation of (non-inline) rb_obj_freeze_inline.
There was a problem hiding this comment.
Thanks for flagging this. Yes, we removed the inline because we didn't want to export the shape transition function.
I added a new benchmark for measuring freezing objects.
Running this benchmark, it looks like there's no performance change on freezing objects:
compare-ruby: ruby 3.2.0dev (2022-09-20T13:25:05Z master b3d8dddee7) [arm64-darwin21]
built-ruby: ruby 3.2.0dev (2022-09-21T21:33:46Z object-shapes-prot.. d3003b71e3) [arm64-darwin21]
# Iteration per second (i/s)
| |compare-ruby|built-ruby|
|:--------------|-----------:|---------:|
|vm_freeze_obj | 364.956| 364.985|
| | -| 1.00x|
|
|
||
| AC_SUBST(MJIT_SUPPORT) | ||
|
|
||
| AC_ARG_ENABLE(compile-commands, |
There was a problem hiding this comment.
It'd be nice to remove the diff of #6352 from this PR.
| src << "#undef GET_SELF\n" | ||
| src << "#define GET_SELF() cfp_self\n" | ||
|
|
||
| # Generate merged ivar guards first if needed |
There was a problem hiding this comment.
I think you shouldn't have deleted the merge_ivar_guards_p optimization because checking RB_TYPE_P(obj, T_OBJECT) for self multiple times remains to be redundant. Now this place should check only RB_TYPE_P(GET_SELF(), T_OBJECT) and then the check should be removed from the following places when merge_ivar_guards_p.
There was a problem hiding this comment.
Sorry, didn't mean to remove this. Should be fixed now!
|
Great job. My comment about MJIT #6386 (comment) is not a blocker because I can easily fix it as long as I'm aware that it was removed. However, I do want you to check #6386 (comment) because it's performance-related. #6386 (comment) is fairly trivial, but it's obvious that it should be removed. I have zero experience of using imemo even today, so I'll leave it for other committers to review how it's used for shapes. P.S. I misclicked the close button while cleaning up dust on my trackpad. I'm sorry 🙇 |
6422f8d to
fe77e03
Compare
8e2fa28 to
ecd2b50
Compare
Object Shapes is used for accessing instance variables and representing the
"frozenness" of objects. Object instances have a "shape" and the shape
represents some attributes of the object (currently which instance variables are
set and the "frozenness"). Shapes form a tree data structure, and when a new
instance variable is set on an object, that object "transitions" to a new shape
in the shape tree. Each shape has an ID that is used for caching. The shape
structure is independent of class, so objects of different types can have the
same shape.
For example:
```ruby
class Foo
def initialize
# Starts with shape id 0
@A = 1 # transitions to shape id 1
@b = 1 # transitions to shape id 2
end
end
class Bar
def initialize
# Starts with shape id 0
@A = 1 # transitions to shape id 1
@b = 1 # transitions to shape id 2
end
end
foo = Foo.new # `foo` has shape id 2
bar = Bar.new # `bar` has shape id 2
```
Both `foo` and `bar` instances have the same shape because they both set
instance variables of the same name in the same order.
This technique can help to improve inline cache hits as well as generate more
efficient machine code in JIT compilers.
This commit also adds some methods for debugging shapes on objects. See
`RubyVM::Shape` for more details.
For more context on Object Shapes, see [Feature: #18776]
Co-Authored-By: Aaron Patterson <[email protected]>
Co-Authored-By: Eileen M. Uchitelle <[email protected]>
Co-Authored-By: John Hawthorn <[email protected]>
ecd2b50 to
3fae3b1
Compare
|
This is amazing, congrats for getting this merged in! :) |
|
I think it got reverted at 06abfa5 |
|
The revert was reverted in ad63b66 |
This commit implements the Object Shapes technique in CRuby. Object Shapes is used for accessing instance variables and representing the "frozenness" of objects. Object instances have a "shape" and the shape represents some attributes of the object (currently which instance variables are set and the "frozenness"). Shapes form a tree data structure, and when a new instance variable is set on an object, that object "transitions" to a new shape in the shape tree. Each shape has an ID that is used for caching. The shape structure is independent of class, so objects of different types can have the same shape.
For example:
Both
fooandbarinstances have the same shape because they both set instance variables of the same name in the same order.This technique can help to improve inline cache hits as well as generate more efficient machine code in JIT compilers.
This commit also adds some methods for debugging shapes on objects. See
RubyVM::Shapefor more details.For more context on Object Shapes, see [Feature: #18776]
Co-Authored-By: Aaron Patterson [email protected]
Co-Authored-By: Eileen M. Uchitelle [email protected]