Skip to content
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

__callee__ behaves differently from MRI #2305

Open
guai opened this issue Dec 11, 2014 · 11 comments
Open

__callee__ behaves differently from MRI #2305

guai opened this issue Dec 11, 2014 · 11 comments

Comments

@guai
Copy link

@guai guai commented Dec 11, 2014

jruby 1.7.13 and 1.7.16.1 both in --2.0 mode

class Foo
    def foo
        {__method__ => __callee__}
    end
    alias bar foo
end
raise 'fail' if Foo.new.foo == Foo.new.bar

They must not be equal.

@BanzaiMan
Copy link
Member

@BanzaiMan BanzaiMan commented Dec 12, 2014

Don't use 1.7.x in 2.0 mode. It's not supported.

But it still fails on the master branch.

@headius
Copy link
Member

@headius headius commented Dec 12, 2014

Can I ask why you need this? In JRuby, the "callee" name used in the caller code is not tracked anywhere; the alias is just a mechanism for finding the :foo method under the :bar name. In order to support using the alias name for callee instead of the real name of the method, we would have to start storing -- on every call -- the actual name used for that call, adding significant overhead to the system and slowing down every method, regardless of whether you use callee or not.

@guai
Copy link
Author

@guai guai commented Dec 30, 2014

Metaprogramming of course. Something like this:

class Wrapper
    def initialize target
        @target = target
    end
    def __value
        @target[__callee__]
    end
end

class FoobarWrapper < Wrapper
    alias foobar __value
end

puts FoobarWrapper.new(foobar: 1).foobar

Wrap java collection for example. I thought it will be faster then method_missing. But now after I saw sources I'm not sure...

@pbl-pw
Copy link

@pbl-pw pbl-pw commented Sep 23, 2016

Same problem. Metaprogramming too.
*jruby 9.1.5.0 (2.3.1) 2016-09-23 fffffff Java HotSpot(TM) Client VM 25.101-b13 on 1.8.0_101-b13 +jit [mswin32-x86]

@headius
Copy link
Member

@headius headius commented Sep 23, 2016

There might be some way to support this in IR (if we can pass the aliased name through into all bodies as well as the actual method name) but this is a really troublesome feature to support. We don't save the actual called name, and I'm not sure I agree that we should.

@guai Your example, if it worked on JRuby, would be almost unusably slow. __method__ and __callee__ are implemented using caller logic, which is very expensive. Neither of them are particularly fast on MRI either, but they're orders of magnitude slower than that on JRuby.

@headius
Copy link
Member

@headius headius commented Sep 23, 2016

One possible way to implement this: when a method has been aliased, generate a new jitted body that has both the alias name and the original name in its signature. We can mine that out of caller backtrace then. It still will be really slow due to the need to generate a backtrace.

@headius
Copy link
Member

@headius headius commented Sep 23, 2016

Another possible way to implement this: pass the original method (AliasMethod in this case) through into the wrapped method so it always knows what method it was called as. It can report callee properly then without too much tricker. This approach will be a bit more complicated since we'd need the method to be available for evals and blocks inside a given method too.

@headius
Copy link
Member

@headius headius commented Sep 23, 2016

cc @subbuss @enebo for more ideas.

@enebo
Copy link
Member

@enebo enebo commented Sep 24, 2016

@headius I had worked on trying to pass the callsite through the call locally on a branch in one effort to make profiler easier. This would then be a trivial feature. Perhaps this is one more reason to pass callsite through call paths.

@headius
Copy link
Member

@headius headius commented Sep 26, 2016

@enebo That would indeed solve this case. And since CallSite is a pretty good place to store static call info, we might be able to use it for other purposes too.

@headius
Copy link
Member

@headius headius commented Jul 9, 2020

This is still an outstanding issue with no easy fix. The problem is largely that when we have an alias, we do not pass the called name along at all:

public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klazz, String unused) {

Because of this, it doesn't even make it as far as the interpreter/bytecode or into the frame.

Fixing this would at least require we pass through the called name along with the "super" name (the actual name of the target method) or else acquire the super name some other way that allows us to pass the called name through.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants