-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Create R8 specific rules to allow for service loader optimizations #2880
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
Conversation
Hi! I didn't follow the issue closely, so please excuse me if I'm asking something obvious, but what does this accomplish? According to #1231 (comment) and the comment below, R8 already knows how to optimize the service loader calls away, even without the proposed fix. |
This PR creates r8 specific rules that gradle will use to invoke R8 with instead of the standard ones from:
The difference between the two files is the presence of the following two rules in proguard/coroutines.pro:
These are added to PG to ensure that the service loaders work - but for R8 it ends up putting a keep rule on them such that the optimization mentioned in #1270 fails to apply after updates to R8. To ensure that the optimization still works in R8 the rules have to be removed. To ensure that PG continue to work as expected I therefore separated the rules out. |
Yeah, I understand what this PR does, the question is why.
Which optimization does that issue mention? Could you link to a specific comment, for example? As far as I can see, it regards errors with which R8 fails, and doesn't at all regard service loaders. Also, do you mean that the calls to |
Ah sorry, I got confused by the hashtags and numbers. The optimization mentioned in #1231 is an R8 specific optimization that rewrites ServiceLoader.loads on a specific syntactic form to instantiations. In the optimization there is a bailout to prevent R8 from doing that optimization - and that is adding a keep rule to the configuration. If the interface is kept by a rule in any way R8 will not rewrite the serviceloader. Due to a change in the semantics of The -keepnames are not needed anyway because R8 will always regard classes mentioned in a ServiceLoader configuration file as being live if the interface becomes live. |
Can we please have this fix integrated and new version of coroutines with this fix released? |
I attempted to apply this fix. Looks like it doesn't do the trick? The bytecode of `MainDispatcherLoader` in the release APK of the reproducing project, using a version of coroutines with the fix applied
|
You are right, apparently AGP needs com.android.tools/r8 under META-INF to select the correct rules. I've updated the PR. To test that it actually works I created a test project and attached it here. Under app/libs there is: where compiling by |
I can confirm that moving the |
I am just following the same format as here: I would assume it is to pass PG specific rules to PG and R8 specific rules to R8. In kotlinx.coroutines/ui/kotlinx-coroutines-android/resources/META-INF/proguard/coroutines.pro, it says in the header:
However, I am not an AGP expert. |
We had severe performance regressions after migrating to Android Gradle Plugin 7.0. Are there plans to merge this PR? The problem is very bad and should be fixed ASAP, as AGP 7 is current stable release for at least a month. |
@nevack We were able to work around this issue by using the fast service loader implementation built into the coroutines lib. tldr; add this to your proguard-rules.pro:
ExplanationThe coroutines lib defines two implementations to get the kotlinx.coroutines/kotlinx-coroutines-core/jvm/src/internal/MainDispatchers.kt Lines 26 to 36 in 8c98180
By default, it takes the latter branch. This is slow and R8 is supposed to optimize it out. However, in AGP 7.0, this functionality broke: see https://issuetracker.google.com/issues/196302685, which is the bug that caused this issue to be filed. However, the coroutines library has an alternative implementation – the fast service loader – which is just as fast as the R8 optimized version in our experience. To activate that, you can use proguard to rewrite the boolean that defines the fast service loader here:
to true (I couldn't get the system property working). That's the tldr; up top:
Here's the PR where we implemented this change: mozilla-mobile/fenix#20844 I apologize for not documenting this sooner. |
This workaround doesn't prevent SL call for |
@mxalbert1996 You are right that the workaround I suggested doesn't optimize the |
Fixes the R8 ServiceLoader optimization that broke in the R8 bundled in the new AGP. For details, see https://issuetracker.google.com/issues/196302685
Thanks! Merged this manually in dfc4821 |
@dkhalanskyjb thanks for merging the PR. Could you please publish a bug fix release for 1.5.x which includes this fix? |
@Thomas-Vos Kotlin 1.6 will be quite soon, and we plan to publish a new release candidate shortly thereafter, which will include this fix. |
) Fixes the R8 ServiceLoader optimization that broke in the R8 bundled in the new AGP. For details, see https://issuetracker.google.com/issues/196302685
) Fixes the R8 ServiceLoader optimization that broke in the R8 bundled in the new AGP. For details, see https://issuetracker.google.com/issues/196302685
Creating R8 specific rules will allow Proguard to continue to work while allow R8 to remove the ServiceLoaders.