Commit f91b077
authored
[Xamarin.Android.Tools.Bytecode] Improve Kotlin metadata matching (#946)
Fixes: #945
Context: dotnet/android-libraries#436 (comment)
Consider the following Kotlin function:
fun get (index: Int) : UInt { … }
When `get` is compiled with Kotlin 1.5, `class-parse` would emit:
<method abstract="false" final="true" name="get-pVg5ArA" return="uint" jni-return="I" static="true" visibility="public" jni-signature="([II)I">
<parameter name="$this" type="int[]" jni-type="[I" />
<parameter name="index" type="int" jni-type="I" />
</method>
However, when `get` is compiled with Kotlin 1.6, `class-parse` sees:
<method abstract="false" final="true" name="get-pVg5ArA" return="int" jni-return="I" static="true" visibility="public" jni-signature="([II)I">
<parameter name="arg0" type="int[]" jni-type="[I" />
<parameter name="index" type="int" jni-type="I" />
</method>
Note that the name of the first `int[]` parameter changes from
`$this` to `arg0`, and the return type changed from `uint` to `int`.
The parameter name change is annoying; the return type change is
an ABI break, and makes many package updates impossible.
What happened?
Recall commit 71afce5: Kotlin-compiled `.class` files contain a
`kotlin.Metadata` type-level annotation blob, which contains a
Protobuf stream containing Kotlin metadata for the type.
The `kotlin.Metadata` annotation contains information about Kotlin
functions, and `class-parse` needs to associate the information about
the Kotlin functions to Java methods. This can be tricky because
there is not an explicit way to do this, and one must rely on trying
to match function names and parameter types. Previously, this was
accomplished by looping through the parameters and comparing types.
However, the `kotlin.Metadata` annotation only includes "user created"
method parameters, while the Java method may include "compiler created"
method parameters. We attempted to skip these by ignoring Java
parameters whose names begin with a dollar sign (ex `$this`).
This "worked" most of the time.
This broke in Kotlin 1.6, as the compiler generated method parameters
stopped using `$` for compiler-generated parameter names.
algorithm.
We need something better.
The `kKotlin.Metadata` annotation provides a `JvmSignature` property --
which matches the `JvmName` property which we already use -- which
sounds promising. However, `JvmSignature` is sometimes `null`, and
sometimes it doesn't actually match. But it's closer.
So now we try to match with signatures.
* If `JvmSignature` matches the Java signature we use that.
* If `JvmSignature` is `null`, calculate it from the Kotlin
parameters and try to match with that.
* Note it wants unsigned types as `Lkotlin/UInt;` and not the
primitive encoding (`I`).
* If Kotlin metadata defines a `ReceiverType`, add that as the
first parameter to the signature.
Using `kotlin-stdlib-1.5.31.jar` as a baseline, we get much better
results:
| Version | Matched Functions | Unmatched Functions |
| --------------- | ----------------: | --------------------: |
| main @ 32635fd | 946 | 154 |
| This PR | 1100 | 0 |
Now that we can match Kotlin functions to Java methods, we still have
to match up the parameters so we can apply parameter-level transforms.
Do this by removing Java method parameters from the front and back of
the list to account for cases where the compiler adds "hidden"
parameters:
* Remove Kotlin `ReceiverType` from beginning of list.
* Remove Kotlin `Lkotlin/coroutines/Continuation;` from end of list.
* Note this _could_ be a legitimate user supplied parameter so we
try to restrict it to "unnamed" parameters.
* Remove the `this` parameter added to `static` functions.
Note: the test classes `DeepRecursiveKt.class`,
`DeepRecursiveScope.class`, and `UByteArray.class` are pulled from
[`kotlin-stdlib-1.5.31.jar`][0].
[0]: https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib/1.5.311 parent 32635fd commit f91b077
File tree
11 files changed
+185
-46
lines changed- src/Xamarin.Android.Tools.Bytecode/Kotlin
- tests/Xamarin.Android.Tools.Bytecode-Tests
- kotlin-ThirdParty
- tools/generator
11 files changed
+185
-46
lines changedLines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
358 | 358 | | |
359 | 359 | | |
360 | 360 | | |
361 | | - | |
| 361 | + | |
362 | 362 | | |
363 | | - | |
| 363 | + | |
364 | 364 | | |
365 | 365 | | |
366 | 366 | | |
| |||
Lines changed: 65 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
175 | 175 | | |
176 | 176 | | |
177 | 177 | | |
178 | | - | |
| 178 | + | |
179 | 179 | | |
180 | | - | |
181 | | - | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
182 | 184 | | |
183 | 185 | | |
184 | 186 | | |
| |||
197 | 199 | | |
198 | 200 | | |
199 | 201 | | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
200 | 242 | | |
201 | 243 | | |
202 | 244 | | |
| |||
271 | 313 | | |
272 | 314 | | |
273 | 315 | | |
274 | | - | |
275 | | - | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
276 | 325 | | |
277 | | - | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
278 | 333 | | |
279 | 334 | | |
280 | 335 | | |
| |||
286 | 341 | | |
287 | 342 | | |
288 | 343 | | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
289 | 348 | | |
290 | 349 | | |
291 | 350 | | |
| |||
Lines changed: 28 additions & 12 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
| 11 | + | |
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | | - | |
| 30 | + | |
31 | 31 | | |
32 | 32 | | |
33 | | - | |
| 33 | + | |
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
38 | | - | |
| 38 | + | |
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| |||
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
48 | 51 | | |
49 | 52 | | |
50 | 53 | | |
| |||
92 | 95 | | |
93 | 96 | | |
94 | 97 | | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
95 | 106 | | |
96 | 107 | | |
97 | 108 | | |
| |||
114 | 125 | | |
115 | 126 | | |
116 | 127 | | |
| 128 | + | |
| 129 | + | |
117 | 130 | | |
118 | 131 | | |
119 | 132 | | |
120 | 133 | | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
121 | 145 | | |
122 | 146 | | |
123 | | - | |
124 | 147 | | |
125 | 148 | | |
126 | 149 | | |
127 | | - | |
128 | 150 | | |
129 | 151 | | |
130 | | - | |
131 | 152 | | |
132 | | - | |
133 | 153 | | |
134 | 154 | | |
135 | 155 | | |
136 | 156 | | |
137 | 157 | | |
138 | | - | |
139 | 158 | | |
140 | 159 | | |
141 | 160 | | |
142 | | - | |
143 | 161 | | |
144 | 162 | | |
145 | | - | |
146 | 163 | | |
147 | | - | |
148 | 164 | | |
149 | 165 | | |
150 | 166 | | |
| |||
Lines changed: 40 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
105 | 105 | | |
106 | 106 | | |
107 | 107 | | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
108 | 148 | | |
109 | 149 | | |
110 | 150 | | |
| |||
Lines changed: 48 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
310 | 310 | | |
311 | 311 | | |
312 | 312 | | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
313 | 361 | | |
314 | 362 | | |
Lines changed: 0 additions & 25 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
201 | 201 | | |
202 | 202 | | |
203 | 203 | | |
204 | | - | |
205 | | - | |
206 | | - | |
207 | | - | |
208 | | - | |
209 | | - | |
210 | | - | |
211 | | - | |
212 | | - | |
213 | | - | |
214 | | - | |
215 | | - | |
216 | | - | |
217 | | - | |
218 | | - | |
219 | | - | |
220 | | - | |
221 | | - | |
222 | | - | |
223 | | - | |
224 | | - | |
225 | | - | |
226 | | - | |
227 | | - | |
228 | | - | |
229 | 204 | | |
230 | 205 | | |
231 | 206 | | |
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
| 28 | + | |
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
| |||
Binary file not shown.
Binary file not shown.
Binary file not shown.
0 commit comments