8000 Actually use fast path for alias_method when checked by djudd-stripe · Pull Request #3339 · sorbet/sorbet · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Actually use fast path for alias_method when checked #3339

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

Merged
merged 2 commits into from
Aug 3, 2020

Conversation

djudd-stripe
Copy link
Contributor

When attempting to self-modify-away the initial slow wrapper for a method created via alias or alias_method, and calling into unwrap_method, pass a Signature object which has the alias as the method_name, instead of the original method name.

Before this PR, the unwrap_method call was actually just replacing the original method each time, and never affecting the alias. This worked but was unintentional.

With this PR, unwrap_method will actually do the right thing here for both checked and unchecked methods, so we can simplify.

Motivation

Followup on #3317 which had the desired effect of allowing aliases to use the fast path for unchecked, but not for checked code.

#3317 has been much more of a journey than I expected - sorry for the churn! - but I do think we're ending up in a better place.

Test plan

Added test assertions & also tested with pay-server, where I saw the expected decrease in allocations.

@djudd-stripe djudd-stripe requested a review from a team as a code owner August 3, 2020 17:06
@djudd-stripe djudd-stripe requested review from elliottt and removed request for a team August 3, 2020 17:06
original_visibility = visibility_method_name(mod, method_sig.method_name)
# Use `original_method.name` not `method_sig.method_name` to get visibility
# so that we handle aliases correctly (we want the visibility before aliasing).
original_visibility = visibility_method_name(mod, original_method.name)
Copy link
Collaborator
@elliottt elliottt Aug 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just checking my understanding: was this previously getting the visibility for the original method, instead of the visibility of the alias? So for this example:

class A
  def foo
    puts "hi"
  end

  alias :bar :foo
  private :bar

  def test
    bar
  end
end

A.new.test

Would we have used public as the visibility for the :bar alias, instead of private?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was previously getting the visibility of the original method, and continues to be getting the visibility of the original method. It probably should be getting the visibility of the alias, but we'd need to thread the aliasing module through, since that won't necessarily be the same as the mod here which is the original module.

But now that I'm looking at this I'm getting confused, I don't know how this is working at all with mod as the original module...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we already have a test case for aliases where the modules differ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do, but we weren't asserting that we got the fast path there. Now we are (and I fixed the bug, see other comment)

# Should use fast path
obj = klass.new
allocs = counting_allocations {obj.bar}
assert(allocs < 5)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a bound for the number of allocations done on the slow path? Mostly just curious to know what the difference between the two is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's 20-30 on the slow path (varies a bit by exact case), 3 on the fast path.

@@ -356,8 +349,8 @@ def self.build_sig(hook_mod, method_name, original_method, current_declaration,
end
end

def self.unwrap_method(hook_mod, signature, original_method)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: hook_mod was dead code here, it wasn't being used

@@ -304,7 +297,7 @@ def self.run_sig(hook_mod, method_name, original_method, declaration_block)
Signature.new_untyped(method: original_method)
end

unwrap_method(hook_mod, signature, original_method)
unwrap_method(signature.method.owner, signature, original_method)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ensures that in the non-alias case, we don't change behavior, since the thing we pass as mod will now actually be used

@djudd-stripe djudd-stripe merged commit d4c80e0 into master Aug 3, 2020
@djudd-stripe djudd-stripe deleted the djudd/alias-method-actual-fast-path branch August 3, 2020 21:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
0