[K/N]: Allow invocation of volatile intrinsics on inline function constant arguments.
Invocation of atomic intrinsics is only allowed on property references that are known at compile time. This commit makes it possible to also invoke intrinsics on a constant property reference getter passed as an argument. See KT-58359 Co-authored-by: Pavel Kunyavskiy <Pavel.Kunyavskiy@jetbrains.com> Merge-request: KT-MR-10413 Merged-by: Maria Sokolova <maria.sokolova@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
d77af3c43d
commit
488d24296a
@@ -0,0 +1,43 @@
|
||||
// TARGET_BACKEND: NATIVE
|
||||
|
||||
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
|
||||
import kotlin.concurrent.*
|
||||
import kotlin.reflect.*
|
||||
|
||||
class Box(@Volatile var value1: Int, @Volatile var value2: Int)
|
||||
|
||||
inline fun wrapCas(crossinline refGetter: () -> KMutableProperty0<Int>, expected: Int, new: Int) = refGetter().compareAndExchangeField(expected, new)
|
||||
inline fun wrapCasTwice(crossinline refGetter: () -> KMutableProperty0<Int>, expected: Int, new: Int) = wrapCas(refGetter, expected, new)
|
||||
|
||||
class A(@Volatile var x: String) {
|
||||
fun add(str: String) {
|
||||
update({ -> (this::x)}) { x + str }
|
||||
}
|
||||
}
|
||||
|
||||
inline fun update(crossinline refGetter: () -> KMutableProperty0<String>, action: (String) -> String) {
|
||||
while (true) {
|
||||
val cur = refGetter().get()
|
||||
val upd = action(cur)
|
||||
if (refGetter().compareAndSetField(cur, upd)) return
|
||||
}
|
||||
}
|
||||
|
||||
fun box() : String {
|
||||
val box = Box(1, 2)
|
||||
wrapCas({ -> (box::value1)}, 1, 3)
|
||||
wrapCas({ -> (box::value2)}, 2, 4)
|
||||
if (box.value1 != 3) return "FAIL 1"
|
||||
if (box.value2 != 4) return "FAIL 2"
|
||||
wrapCasTwice({ -> (box::value1)}, 3, 5)
|
||||
wrapCasTwice( { -> (box::value2)}, 4, 6)
|
||||
if (box.value1 != 5) return "FAIL 3"
|
||||
if (box.value2 != 6) return "FAIL 4"
|
||||
|
||||
val a = A("a")
|
||||
a.add("b")
|
||||
if (a.x != "ab") return "FAIL 5"
|
||||
return "OK"
|
||||
}
|
||||
|
||||
+15
-1
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.util.irCall
|
||||
@@ -203,11 +204,24 @@ internal class VolatileFieldsLowering(val context: Context) : FileLoweringPass {
|
||||
IntrinsicType.GET_AND_ADD_FIELD to ::getAndAddFunction,
|
||||
)
|
||||
|
||||
private val IrBlock.singleExpressionOrNull get() = statements.singleOrNull() as? IrExpression
|
||||
|
||||
private tailrec fun getConstPropertyReference(expression: IrExpression?, expectedReturn: IrReturnableBlockSymbol?) : IrPropertyReference? {
|
||||
return when {
|
||||
expression == null -> null
|
||||
expectedReturn == null && expression is IrPropertyReference -> expression
|
||||
expectedReturn == null && expression is IrReturnableBlock -> getConstPropertyReference(expression.singleExpressionOrNull, expression.symbol)
|
||||
expression is IrReturn && expression.returnTargetSymbol == expectedReturn -> getConstPropertyReference(expression.value, null)
|
||||
expression is IrBlock -> getConstPropertyReference(expression.singleExpressionOrNull, expectedReturn)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
val intrinsicType = tryGetIntrinsicType(expression).takeIf { it in intrinsicMap } ?: return expression
|
||||
builder.at(expression)
|
||||
val reference = expression.extensionReceiver as? IrPropertyReference
|
||||
val reference = getConstPropertyReference(expression.extensionReceiver, null)
|
||||
?: return unsupported("Only compile-time known IrProperties supported for $intrinsicType")
|
||||
val property = reference.symbol.owner
|
||||
val backingField = property.backingField
|
||||
|
||||
+6
@@ -40151,6 +40151,12 @@ public class FirNativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTe
|
||||
runTest("compiler/testData/codegen/box/volatile/crossModuleIntrinsic.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intrinsicWithInlineFunction.kt")
|
||||
public void testIntrinsicWithInlineFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/volatile/intrinsicWithInlineFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intrinsics.kt")
|
||||
public void testIntrinsics() throws Exception {
|
||||
|
||||
+6
@@ -41185,6 +41185,12 @@ public class FirNativeCodegenBoxTestNoPLGenerated extends AbstractNativeCodegenB
|
||||
runTest("compiler/testData/codegen/box/volatile/crossModuleIntrinsic.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intrinsicWithInlineFunction.kt")
|
||||
public void testIntrinsicWithInlineFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/volatile/intrinsicWithInlineFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intrinsics.kt")
|
||||
public void testIntrinsics() throws Exception {
|
||||
|
||||
+6
@@ -39635,6 +39635,12 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest
|
||||
runTest("compiler/testData/codegen/box/volatile/crossModuleIntrinsic.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intrinsicWithInlineFunction.kt")
|
||||
public void testIntrinsicWithInlineFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/volatile/intrinsicWithInlineFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intrinsics.kt")
|
||||
public void testIntrinsics() throws Exception {
|
||||
|
||||
+6
@@ -40152,6 +40152,12 @@ public class NativeCodegenBoxTestNoPLGenerated extends AbstractNativeCodegenBoxT
|
||||
runTest("compiler/testData/codegen/box/volatile/crossModuleIntrinsic.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intrinsicWithInlineFunction.kt")
|
||||
public void testIntrinsicWithInlineFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/volatile/intrinsicWithInlineFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intrinsics.kt")
|
||||
public void testIntrinsics() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user