Using native 'compareAndExchange' on java if possible

This commit is contained in:
Andrew Golovashevich 2025-03-26 18:39:48 +03:00
parent 77a72a2a7c
commit fe6d2c22ef
8 changed files with 57 additions and 24 deletions

View File

@ -31,7 +31,7 @@ xomrk {
defineAllMultiplatformTargets() defineAllMultiplatformTargets()
jvmToolchain(8) jvmToolchain(11)
jvm { jvm {
withJava() withJava()

View File

@ -66,7 +66,7 @@ public class CloseableReferenceCounter {
@JvmName("close") @JvmName("close")
public fun close(errExistRefs: String) { public fun close(errExistRefs: String) {
_Platform.jvm_assertNotNull(errExistRefs, "param: errExistRefs") _Platform.jvm_assertNotNull(errExistRefs, "param: errExistRefs")
val state = _CloseableReferenceCounter_LowLevel.compareAndExchange(this._value, 0, _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE) val state = this._value.compareAndExchange(0, _Misc.CLOSED_STATE_VALUE)
when { when {
state > 0 -> throw IllegalStateException(errExistRefs) state > 0 -> throw IllegalStateException(errExistRefs)
state < 0 -> this.throwClosed() state < 0 -> this.throwClosed()

View File

@ -41,9 +41,9 @@ public class CloseableReferenceCounter_Debug {
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
private inline fun _throwErrors(valueToCheck: Long) { private inline fun _throwErrors(valueToCheck: Long) {
when { when {
valueToCheck >= 0 || valueToCheck == _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE -> {} valueToCheck >= 0 || valueToCheck == _Misc.CLOSED_STATE_VALUE -> {}
valueToCheck < _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE -> throw RuntimeException("Too many references") valueToCheck < _Misc.CLOSED_STATE_VALUE -> throw RuntimeException("Too many references")
valueToCheck > _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE -> throw RuntimeException(".decref called more times than .incref") valueToCheck > _Misc.CLOSED_STATE_VALUE -> throw RuntimeException(".decref called more times than .incref")
} }
} }
@ -118,7 +118,7 @@ public class CloseableReferenceCounter_Debug {
@JvmName("close") @JvmName("close")
public fun close(errExistRefs: String) { public fun close(errExistRefs: String) {
_Platform.jvm_assertNotNull(errExistRefs, "param: errExistRefs") _Platform.jvm_assertNotNull(errExistRefs, "param: errExistRefs")
val state = _CloseableReferenceCounter_LowLevel.compareAndExchange(this._value, 0, _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE) val state = this._value.compareAndExchange(0, _Misc.CLOSED_STATE_VALUE)
this._throwErrors(state) this._throwErrors(state)
when { when {
state > 0 -> throw IllegalStateException(errExistRefs) state > 0 -> throw IllegalStateException(errExistRefs)
@ -139,9 +139,9 @@ public class CloseableReferenceCounter_Debug {
@Suppress("LiftReturnOrAssignment") @Suppress("LiftReturnOrAssignment")
when { when {
refcntCached >= 0 -> stateRepr = refcntCached.toString() refcntCached >= 0 -> stateRepr = refcntCached.toString()
refcntCached == _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE -> stateRepr = "closed" refcntCached == _Misc.CLOSED_STATE_VALUE -> stateRepr = "closed"
refcntCached < _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE -> stateRepr = "overflow" refcntCached < _Misc.CLOSED_STATE_VALUE -> stateRepr = "overflow"
refcntCached > _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE -> stateRepr = "underflow" refcntCached > _Misc.CLOSED_STATE_VALUE -> stateRepr = "underflow"
else -> throw Error("Unreachable") else -> throw Error("Unreachable")
} }
return "<ref counter \"${this._dbgName}@${this._id}\" [${stateRepr}]>" return "<ref counter \"${this._dbgName}@${this._id}\" [${stateRepr}]>"

View File

@ -10,4 +10,6 @@ internal expect class _AtomicLong {
inline fun getAndUpdate(operator: (Long) -> Long): Long inline fun getAndUpdate(operator: (Long) -> Long): Long
fun compareAndSet(expected: Long, newValue: Long): Boolean fun compareAndSet(expected: Long, newValue: Long): Boolean
fun compareAndExchange(expected: Long, newValue: Long): Long
} }

View File

@ -1,14 +0,0 @@
package ru.landrafhomyak.utility.reference_counter
@Suppress("ClassName")
internal object _CloseableReferenceCounter_LowLevel {
internal fun compareAndExchange(atomic: _AtomicLong, expected: Long, newValue: Long): Long {
while (true) {
val old = atomic.get()
if (old != expected) return old
if (atomic.compareAndSet(old, newValue)) return old
}
}
internal const val CLOSED_STATE_VALUE = -0x4000_0000_0000_0000L
}

View File

@ -0,0 +1,17 @@
package ru.landrafhomyak.utility.reference_counter
import kotlin.jvm.JvmStatic
@Suppress("ClassName")
internal object _Misc {
@JvmStatic
internal inline fun _compareAndExchange(get: () -> Long, cas: (Long, Long) -> Boolean, expected: Long, newValue: Long): Long {
while (true) {
val old = get()
if (old != expected) return old
if (cas(old, newValue)) return old
}
}
internal const val CLOSED_STATE_VALUE = -0x4000_0000_0000_0000L
}

View File

@ -29,4 +29,25 @@ internal actual /*value*/ class _AtomicLong {
actual fun compareAndSet(expected: Long, newValue: Long): Boolean = actual fun compareAndSet(expected: Long, newValue: Long): Boolean =
this._native.compareAndSet(expected, newValue) this._native.compareAndSet(expected, newValue)
actual fun compareAndExchange(expected: Long, newValue: Long): Long =
if (_Linkage._isNativeCompareAndExchangeExists) this._native.compareAndExchange(expected, newValue)
else _Misc._compareAndExchange(
get = this._native::get,
cas = this._native::compareAndSet,
expected = expected, newValue = newValue
)
private object _Linkage {
@JvmField
val _isNativeCompareAndExchangeExists = run {
val a = AtomicLong()
try {
a.compareAndExchange(0, 0)
return@run true
} catch (_: NoSuchMethodError) {
return@run false
}
}
}
} }

View File

@ -23,4 +23,11 @@ internal actual class _AtomicLong {
actual fun compareAndSet(expected: Long, newValue: Long): Boolean = actual fun compareAndSet(expected: Long, newValue: Long): Boolean =
this._atomicfu.compareAndSet(expected, newValue) this._atomicfu.compareAndSet(expected, newValue)
actual fun compareAndExchange(expected: Long, newValue: Long): Long =
_Misc._compareAndExchange(
get = this._atomicfu::value::get,
cas = this._atomicfu::compareAndSet,
expected = expected, newValue = newValue
)
} }