-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Optimize Struct's accessors #5131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
79657dc
to
8f33667
Compare
dfddc6e
to
a499691
Compare
Now `rb_method_optimized_t optimized` field is added to represent optimized method type.
Introduce new optimized method type `OPTIMIZED_METHOD_TYPE_STRUCT_AREF/ASET` with index information.
if (calling->kw_splat && | ||
calling->argc > 0 && | ||
RB_TYPE_P(argv[calling->argc-1], T_HASH) && | ||
RHASH_EMPTY_P(argv[calling->argc-1])) { | ||
calling->argc--; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be good to comment this to explain what this check is testing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jeremyevans may know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is testing for empty splatted keyword hashes. If an empty splatted keyword hash are passed, it should be equivalent to not passing keywords at all.
@XrXr @jhawthorn can you comment on whether this PR increases or decrease the complexity in YJIT, and how easy/hard it would be for us to support this change? |
I think it would very slightly increase complexity, since it's adding two new method types, but those method types should be pretty easy to implement. We should also be able to generate better code for these than we currently do (can now read from the memory location instead of calling the old builtin function). |
Yeah, we would need to add code to YJIT if we want to support this new method type. The actual logic is similar to getting an ivar, but a bit simpler because structs have a fixed layout. The relevant code is here: Lines 121 to 144 in ab737b1
So it's a flag test to find the buffer, and then reading at a fixed index. |
Since you guys don't seem concerned about the complexity, we can approve it. Would either of you want to implement the new struct access mechanism? |
After compiling with these changes I get a warning:
|
This PR seems to have changed the public API of Before: S = Struct.new(:foo)
S.instance_method(:foo=).parameters
#=> [[:req, :_]] After: S = Struct.new(:foo)
S.instance_method(:foo=).parameters
#=> [[:rest]] Is this intentional? I find it weird that a setter method looks like it is accepting zero or more arguments instead of a single required argument. |
You shouldn't assume bf->compiler is always non-zero. While struct aref/aset is no longer a builtin function since #5131, it seems like you could still load such an iseq binary. The refactored code fallbacks to compile_insn_default correctly when bf->compiler is zero.
Improve performance of setter/getter of Struct with optimized path.