-
Notifications
You must be signed in to change notification settings - Fork 185
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
Ruby 2.7: Refinements take place at Object#method and Module#instance_method #2177
Ruby 2.7: Refinements take place at Object#method and Module#instance_method #2177
Conversation
@@ -1352,6 +1354,15 @@ protected RubyMethod method(VirtualFrame frame, Object self, Object name, | |||
@Cached ConditionProfile notFoundProfile, | |||
@Cached ConditionProfile respondToMissingProfile, | |||
@Cached LogicalClassNode logicalClassNode) { | |||
final Frame callerFrame = getContext() | |||
.getCallStack() | |||
.getCallerFrameIgnoringSend(FrameInstance.FrameAccess.READ_ONLY); |
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.
Kernel#method should be fast and basically just be an inline cache on the instance class + name.
This causes to iterate the stack every time.
Let's use the same approach as in RespondToNode.
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.
Hm, but ReadCallerFrameNode
(used in RespondToNode
) also iterate the stack, isn't?
truffleruby/src/main/java/org/truffleruby/language/arguments/ReadCallerDataNode.java
Lines 31 to 39 in 9da7552
public Object execute(VirtualFrame frame) { | |
final Object data = getData(frame); | |
if (callerDataProfile.profile(data != null)) { | |
return data; | |
} else { | |
return getCallerData(); | |
} | |
} |
It just has a condition profiler to "skip" an iteration sometimes (not sure how often)
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.
The first branch is basically always taken after the first call for a given call site, so it only iterates once per call site, and then all later calls just read the caller frame from the arguments of the current frame (except edge cases like a non-Ruby caller, but we can detect those by being passed a null
frame or so).
Here is a quick summary of the work & progress of this issue. The whole idea of supporting refinements for
We need to tweek
Then we had a conversation in Slack about the solution and the final thought is:
As a result, I would be happy to get a review of the last solution and a hint of what I am doing wrong 🙏 |
My apologies for the super late reply. The error is from Regarding type casting, I think we can exploit the fact that MaterializedFrame subclasses VirtualFrame, but we might not even need it. |
286ad8d
to
237d2a5
Compare
8aea66c
to
783c3cc
Compare
@eregon we are ready for another review-round 🧑🍳 |
src/main/java/org/truffleruby/language/methods/GetMethodObjectNode.java
Outdated
Show resolved
Hide resolved
src/main/java/org/truffleruby/language/methods/LookupMethodOnSelfNode.java
Outdated
Show resolved
Hide resolved
849d51a
to
01ef61a
Compare
01ef61a
to
2d95cfe
Compare
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.
Great PR, thank you for your work and persistence on this, it was much harder than expected!
* Now that we found out that having a public execute(Frame, ...) is fine.
} | ||
final RubyMethod instance = new RubyMethod( | ||
context.getCoreLibrary().methodClass, | ||
RubyLanguage.getCurrentLanguage().methodShape, |
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.
RubyLanguage.getCurrentLanguage()
is slow, it's essentially a ThreadLocal lookup.
So I switched to @CachedLanguage
instead.
…sed a reason * neverPartOfCompilation() is much safer to use now that it is checked statically when building a Native Image.
…erPartOfCompilation * neverPartOfCompilation() is much safer to use now that it is checked statically when building a Native Image.
I added a check that RubyLanguage.getCurrentLanguage/getCurrentContext are never used in PE code, so the gate would nicely catch issues like #2177 (comment). |
It looks like TCK tests fail, I'll take a look:
|
…mbol name from Kernel#method
…_to_missing? and #method_missing
Related to #2004
A few notes:
#method
is similar to#respond_to?
(see: https://github.com/oracle/truffleruby/pull/2120/files) where we usedReadCallerFrameNode
. In this PR I don't useReadCallerFrameNode
, but instead directly call:to avoid frame materialization. However, we discussed the possible optimization of
ReadCallerFrameNode
so maybe we should repeat theRespondToNode
approach (with@Child private ReadCallerFrameNode readCallerFrame
) to be more consistent.I didn't find
#method
or#instance_method
uses via Primitive (so there are no needs in : d84da65).There were also options with AST-inlining, but we haven't done that yet.
How do you think this is expected?