[JVM] Force lock object in JVM synchronized implementation into local.

This fixes a performance problem in the case where the lock object
is a capture and the monitor enter/exit happens directly on
field loads. When the locking happens on field loads instead of a
local, the JVM cannot prove that locking is balanced. That has
the consequence that the code is runs very slow (always in the
interpreter).

^KT-48367 Fixed.
This commit is contained in:
Mads Ager
2021-08-24 09:46:55 +02:00
committed by Alexander Udalov
parent 9fd777cb7d
commit a12b22c04d
5 changed files with 45 additions and 2 deletions
@@ -19,13 +19,18 @@ public actual inline fun <R> synchronized(lock: Any, block: () -> R): R {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
// Force the lock object into a local and use that local for monitor enter/exit.
// This ensures that the JVM can prove that locking is balanced which is a
// prerequisite for using fast locking implementations. See KT-48367 for details.
val lockLocal = lock
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE", "INVISIBLE_MEMBER")
monitorEnter(lock)
monitorEnter(lockLocal)
try {
return block()
}
finally {
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE", "INVISIBLE_MEMBER")
monitorExit(lock)
monitorExit(lockLocal)
}
}