From 488d24296a325c2c17350b2a74f99472443d3c24 Mon Sep 17 00:00:00 2001 From: Pavel Kunyavskiy Date: Mon, 24 Jul 2023 17:45:16 +0000 Subject: [PATCH] [K/N]: Allow invocation of volatile intrinsics on inline function constant arguments. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Merge-request: KT-MR-10413 Merged-by: Maria Sokolova --- .../volatile/intrinsicWithInlineFunction.kt | 43 +++++++++++++++++++ .../konan/lower/VolatileFieldsLowering.kt | 16 ++++++- .../FirNativeCodegenBoxTestGenerated.java | 6 +++ .../FirNativeCodegenBoxTestNoPLGenerated.java | 6 +++ .../NativeCodegenBoxTestGenerated.java | 6 +++ .../NativeCodegenBoxTestNoPLGenerated.java | 6 +++ 6 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/codegen/box/volatile/intrinsicWithInlineFunction.kt diff --git a/compiler/testData/codegen/box/volatile/intrinsicWithInlineFunction.kt b/compiler/testData/codegen/box/volatile/intrinsicWithInlineFunction.kt new file mode 100644 index 00000000000..315036086b0 --- /dev/null +++ b/compiler/testData/codegen/box/volatile/intrinsicWithInlineFunction.kt @@ -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, expected: Int, new: Int) = refGetter().compareAndExchangeField(expected, new) +inline fun wrapCasTwice(crossinline refGetter: () -> KMutableProperty0, 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, 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" +} + diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/VolatileFieldsLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/VolatileFieldsLowering.kt index e7438e1b8ec..8afdab85d95 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/VolatileFieldsLowering.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/VolatileFieldsLowering.kt @@ -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 diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeCodegenBoxTestGenerated.java index 92b0dba236b..32dea00c172 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeCodegenBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeCodegenBoxTestGenerated.java @@ -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 { diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeCodegenBoxTestNoPLGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeCodegenBoxTestNoPLGenerated.java index 75f3dae2292..e73d91be404 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeCodegenBoxTestNoPLGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeCodegenBoxTestNoPLGenerated.java @@ -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 { diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java index b2627332f23..c222c3116e6 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java @@ -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 { diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestNoPLGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestNoPLGenerated.java index 2d4922b570f..8751d00f2a0 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestNoPLGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestNoPLGenerated.java @@ -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 {