-
-
Notifications
You must be signed in to change notification settings - Fork 925
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
Comments
Don't use 1.7.x in 2.0 mode. It's not supported. But it still fails on the master branch. |
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. |
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... |
Same problem. Metaprogramming too. |
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. |
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. |
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 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. |
@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. |
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:
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. |
JRuby only pushes the actual method name on the stack, since up until recently it was the only name needed. However the when the `__callee__` method was added, the aliased name also became necessary. Passing another argument along the dynamic call stack would take considerable work, which might happen along with making the call path flexible enough to handle allocation-free keyword arguments. For now, however this hack may be good enough. The logic here encodes the aliased name and the original name in the same string passed along the call stack. Since this name is used in very few places – making super calls, setting up the interpreter backtrace, and the `__method__` and `__callee__` methods – only those locations need to be modified to receive the encoded string. The format of the encoded string uses a leading null character, followed by the new name, another null character, and the old name. This allows an easy check for encoding using charAt(0), and the individual names can then be pulled out easily. The null character is also very unlikely to show up in any real method identifier (and may actually be illegal). Because the two name are encoded into a single string, it is necessary to allocate a new string to extract either. However, the places where these names are used already have significant overhead, this allocation may not be a big concern. This change is also hopefully temporary until we can better thread this data through the dynamic call stack. Fixes jruby#2305
JRuby only pushes the actual method name on the stack, since up until recently it was the only name needed. However the when the `__callee__` method was added, the aliased name also became necessary. Passing another argument along the dynamic call stack would take considerable work, which might happen along with making the call path flexible enough to handle allocation-free keyword arguments. For now, however this hack may be good enough. The logic here encodes the aliased name and the original name in the same string passed along the call stack. Since this name is used in very few places – making super calls, setting up the interpreter backtrace, and the `__method__` and `__callee__` methods – only those locations need to be modified to receive the encoded string. The format of the encoded string uses a leading null character, followed by the new name, another null character, and the old name. This allows an easy check for encoding using charAt(0), and the individual names can then be pulled out easily. The null character is also very unlikely to show up in any real method identifier (and may actually be illegal). Because the two name are encoded into a single string, it is necessary to allocate a new string to extract either. However, the places where these names are used already have significant overhead, this allocation may not be a big concern. This change is also hopefully temporary until we can better thread this data through the dynamic call stack. Fixes jruby#2305
JRuby only pushes the actual method name on the stack, since up until recently it was the only name needed. However the when the `__callee__` method was added, the aliased name also became necessary. Passing another argument along the dynamic call stack would take considerable work, which might happen along with making the call path flexible enough to handle allocation-free keyword arguments. For now, however this hack may be good enough. The logic here encodes the aliased name and the original name in the same string passed along the call stack. Since this name is used in very few places – making super calls, setting up the interpreter backtrace, and the `__method__` and `__callee__` methods – only those locations need to be modified to receive the encoded string. The format of the encoded string uses a leading null character, followed by the new name, another null character, and the old name. This allows an easy check for encoding using charAt(0), and the individual names can then be pulled out easily. The null character is also very unlikely to show up in any real method identifier (and may actually be illegal). Because the two name are encoded into a single string, it is necessary to allocate a new string to extract either. However, the places where these names are used already have significant overhead, this allocation may not be a big concern. This change is also hopefully temporary until we can better thread this data through the dynamic call stack. Fixes jruby#2305
JRuby only pushes the actual method name on the stack, since up until recently it was the only name needed. However the when the `__callee__` method was added, the aliased name also became necessary. Passing another argument along the dynamic call stack would take considerable work, which might happen along with making the call path flexible enough to handle allocation-free keyword arguments. For now, however this hack may be good enough. The logic here encodes the aliased name and the original name in the same string passed along the call stack. Since this name is used in very few places – making super calls, setting up the interpreter backtrace, and the `__method__` and `__callee__` methods – only those locations need to be modified to receive the encoded string. The format of the encoded string uses a leading null character, followed by the new name, another null character, and the old name. This allows an easy check for encoding using charAt(0), and the individual names can then be pulled out easily. The null character is also very unlikely to show up in any real method identifier (and may actually be illegal). Because the two name are encoded into a single string, it is necessary to allocate a new string to extract either. However, the places where these names are used already have significant overhead, this allocation may not be a big concern. This change is also hopefully temporary until we can better thread this data through the dynamic call stack. Fixes jruby#2305
I have pushed a short-term fix in #7702 that encodes both the aliased name and original name in the name passed through the call stack. Anywhere that consumes either the "super name" or the "callee name" must decode the composite name in oder to get those others out. It appears to be working properly, but will likely need more bake time before release. |
jruby 1.7.13 and 1.7.16.1 both in --2.0 mode
They must not be equal.
The text was updated successfully, but these errors were encountered: