Kotlin / kotlinx-atomicfu

The idiomatic way to use atomic operations in Kotlin
Other
918 stars 58 forks source link

Use AtomicXxxFieldUpdater and VarHandle both when compile against Android #277

Open asuka-mio opened 1 year ago

asuka-mio commented 1 year ago

VarHandle now is available on Android API 33 https://developer.android.com/reference/java/lang/invoke/VarHandle https://android.googlesource.com/platform/libcore/+/refs/heads/master/ojluni/src/main/java/java/lang/invoke/VarHandle.java

And AtomicXxx is backed by VarHandle now https://android.googlesource.com/platform/libcore/+/refs/heads/master/ojluni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java

As we all known a compatibility layer is feasible if (Build.VERSION.SDK_INT >= 33) { // VarHandle Impl } else { // AtomicXxxFieldUpdater Impl }

JakeWharton commented 1 year ago

Unfortunately runtime behavior switching like that is not as viable as you may think.

The use of method handles (or, presumably, var handles) involves generation of an invokedynamic instruction in the Java bytecode. This gets translated to an invoke-custom or invoke-polymorphic instruction in Dalvik bytecode, and that instruction is only available on API 26 and newer (Android 8.0 and newer).

Even if the codepath isn't taken at runtime, the bytecode for the alternate codepath must be compiled and thus will raise the minimum API level of the library to 26. If this were the JVM, you could use multi-release jars and put the new codepaths behind a compile-time indirection, but Android has no analagous feature.

So, unfortunately, until you can raise your minimum supported version to API 26 you can't even conditionally use these APIs if Android is to remain a target.

elizarov commented 1 year ago

Is it really the case that Android has no "multi-release jars" analogue? Can't you try to emulate it with some sort of R8 instructions?

JakeWharton commented 1 year ago

It could be emulated with a separate Dex file that is conditionally loaded similar to how one might do a jar. But it likely has performance implications because of that and may not have a JIT cache and won't participate in baseline profiles. It likely would undo any gains from using the new mechanism.