I don't have to much experience in multi-threading. So not sure if I got right the following Java code decompiled from Kotlin.
Here is the Kotlin code:
companion object {
@Volatile private var INSTANCE: SomeDatabase? = null
fun getInstance(context: Context): SomeDatabase =
INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
}
}
Here is the decompiled code in Java:
SomeDatabase var10000 = ((SomeDatabase.Companion)this).getINSTANCE();
if (var10000 == null) {
synchronized(this){}
SomeDatabase var4;
try {
var10000 = SomeDatabase.Companion.getINSTANCE();
if (var10000 == null) {
...
var10000 = var4;
}
return var10000;
Doesn't this mean that code is actually not synchronized because of empty block in synchronized(this){}
?
If you look at the bytecode itself without decompiling it, you'll see that the synchronization happens as it should - this here is a version stripped of lots of load and store operations, line numbers, etc., but what matters is where the MONITORENTER
and MONITOREXIT
instructions are:
public final getInstance(Landroid/content/Context;)Lcom/example/SomeDatabase;
LDC "context"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
INVOKESTATIC com/example/Foo.access$getINSTANCE$cp ()Lcom/example/SomeDatabase;
MONITORENTER
INVOKESTATIC com/example/Foo.access$getINSTANCE$cp ()Lcom/example/SomeDatabase;
INVOKESTATIC com/example/FooKt.buildDatabase (Landroid/content/Context;)Lcom/example/SomeDatabase;
INVOKESTATIC com/example/Foo.access$setINSTANCE$cp (Lcom/example/SomeDatabase;)V
MONITOREXIT
MONITOREXIT
ARETURN
The issue you're seeing is not a bug in the compiler, but rather an issue with the decompiler, which isn't particularly rare. It's quite the challenge to decompile arbitrary generated bytecode back to Java.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With