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
Support customized implementation method name #8841
base: master
Are you sure you want to change the base?
Support customized implementation method name #8841
Conversation
9317483
to
a3d77b2
Compare
@hoisie @brettchabot It's a prototype, but it's ready for reviewing now. |
a3d77b2
to
5e72a06
Compare
5e72a06
to
f8ef8d2
Compare
Friendly ping @hoisie @brettchabot, PTAL. |
if (method == null) { | ||
// Second, try to find mapped shadow method with the exact method signature except method | ||
// name. | ||
method = findMappedShadowMethodDeclaredOnClass(shadowClass, name, types); |
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.
There may be some performance implications of this, though I would like to measure it first. A rule of thumb is 90-95% of Android methods that get called do not have corresponding shadow methods. With this change, there will be extra reflection work done for 90-95% of these method calls. Maybe it's fine, since shadows typically don't contain too many methods. But I would like to quantify the impact of this change (I can get an estimate).
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.
An alternative may be to use the Processor to generate a list of shadow methods that are renamed, and store that info in shadow metadata. That may be tricky with custom shadows, though it may also be doable.
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.
I prefer the Processor. I will try it this weekend.
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 idea would be store a map in ShadowInfo that contains information about these renamed methods.
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.
@hoisie Do you think we still need ShadowInfo for renamed methods? Looks like getDeclaredMethods is not a big performance issue.
@utzcoz it looks like https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/lang/Class.java#L2905 @CallerSensitive
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
Objects.requireNonNull(name);
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
}
Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
if (method == null) {
throw new NoSuchMethodException(methodToString(name, parameterTypes));
}
return getReflectionFactory().copyMethod(method);
} This is searchMethods: // This method does not copy the returned Method object!
private static Method searchMethods(Method[] methods,
String name,
Class<?>[] parameterTypes)
{
ReflectionFactory fact = getReflectionFactory();
Method res = null;
for (Method m : methods) {
if (m.getName().equals(name)
&& arrayContentsEq(parameterTypes,
fact.getExecutableSharedParameterTypes(m))
&& (res == null
|| (res.getReturnType() != m.getReturnType()
&& res.getReturnType().isAssignableFrom(m.getReturnType()))))
res = m;
}
return res;
} |
Looks like the only difference is that calling getDeclaredMethods calls @CallerSensitive
public Method[] getDeclaredMethods() throws SecurityException {
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
}
return copyMethods(privateGetDeclaredMethods(false));
} |
@hoisie If |
…hods Previously, in ShadowWrangler, shadow method lookup was performed using ShadowClass.findDeclaredMethod. It was called once to look for an exact match of a shadow method, and sometimes called again to check for a looseSignatures match. There are plans to add new features and capabilities to the way that shadow methods are matched. For example: * looseSignatures being replaced with a more minimal @classname("internal.type") annotation. * If the signature of a method changes across SDK levels, we could introduce different method names that map to the same method name. However, to search for methods that cannot be matched using ShadowClass.findDeclaredMethod, it is required to iterate over all candidate methods using ShadowClass.findDeclaredMethods. There were some questions about the performance of using ShadowClass.findDeclaredMethods + iteration. However, after some preliminary benchmarks, this approach is surprisingly approximately 25% faster than using ShadowClass.findDeclaredMethod. It is perhaps due to the internal caching of ShadowClass.findDeclaredMethods. With this change, it will be possible to perform more advanced filtering and searching for methods. For #8841 PiperOrigin-RevId: 619288002
…hods Previously, in ShadowWrangler, shadow method lookup was performed using ShadowClass.findDeclaredMethod. It was called once to look for an exact match of a shadow method, and sometimes called again to check for a looseSignatures match. There are plans to add new features and capabilities to the way that shadow methods are matched. For example: * looseSignatures being replaced with a more minimal @classname("internal.type") annotation. * If the signature of a method changes across SDK levels, we could introduce different method names that map to the same method name. However, to search for methods that cannot be matched using ShadowClass.findDeclaredMethod, it is required to iterate over all candidate methods using ShadowClass.findDeclaredMethods. There were some questions about the performance of using ShadowClass.findDeclaredMethods + iteration. However, after some preliminary benchmarks, this approach is surprisingly approximately 25% faster than using ShadowClass.findDeclaredMethod. It is perhaps due to the internal caching of ShadowClass.findDeclaredMethods. With this change, it will be possible to perform more advanced filtering and searching for methods. For #8841 PiperOrigin-RevId: 619979740
d3d3ebe
to
57d5b24
Compare
Interesting. I keep to use From my experience, I can't use only one iteration to finish all types of finding jobs, as the exact matching has the first and highest priority than other approaches. So I reused the origin iteration with the exact method matching with highest priority and then looseSignature, and adding a new iteration for |
57d5b24
to
719bf7e
Compare
@hoisie Friendly ping for reviewing. I want to land it before other contributors start to code for GSoC. |
1. Expand Implementation with a new method called methodName for mapped method name. 2. Expand SdkStore to consider mapped shadow method for validation. 3. Expand shadow method finding logic when running to add mapped shadow method finding logic as the third priority after looseSignature. 4. Split `ShadowBluetoothAdapter#setScanMode` into two methods for different SDKs to test mapped shadow method. Signed-off-by: utzcoz <utzcoz@outlook.com>
719bf7e
to
039de38
Compare
Sometimes internal methods return different types for different SDKs. It's safe because
these methods are internal/private methods, not public methods. To support different return
types of a method for different SDKs, we often use looseSignature method, although all return
types are common types like bool and int. This field/property can be used to fix this issue by
using different real methods for different SDKs.