diff --git a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/common/AbstractAtomicSymbols.kt b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/common/AbstractAtomicSymbols.kt index 497ac25a2c8..cd40f404b28 100644 --- a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/common/AbstractAtomicSymbols.kt +++ b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/common/AbstractAtomicSymbols.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlinx.atomicfu.compiler.backend.common import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isPrimitiveType import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.IrBuiltIns @@ -17,15 +18,13 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl -import org.jetbrains.kotlin.ir.symbols.IrClassSymbol -import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol -import org.jetbrains.kotlin.ir.symbols.IrSymbol -import org.jetbrains.kotlin.ir.types.IrSimpleType -import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.util.createImplicitParameterDeclarationWithWrappedDescriptor import org.jetbrains.kotlin.ir.util.getSimpleFunction +import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.Variance @@ -44,19 +43,76 @@ abstract class AbstractAtomicSymbols( return IrConstructorCallImpl.fromSymbolOwner(volatileAnnotationConstructor.returnType, volatileAnnotationConstructor.symbol) } + abstract val atomicIntArrayClassSymbol: IrClassSymbol + abstract val atomicLongArrayClassSymbol: IrClassSymbol + abstract val atomicRefArrayClassSymbol: IrClassSymbol + + protected val ATOMIC_ARRAY_TYPES: Set + get() = setOf( + atomicIntArrayClassSymbol, + atomicLongArrayClassSymbol, + atomicRefArrayClassSymbol + ) + + fun isAtomicArrayHandlerType(valueType: IrType) = valueType.classOrNull in ATOMIC_ARRAY_TYPES + + abstract fun getAtomicArrayConstructor(atomicArrayClassSymbol: IrClassSymbol): IrFunctionSymbol + + fun getAtomicArrayClassByAtomicfuArrayType(atomicfuArrayType: IrType): IrClassSymbol = + when (atomicfuArrayType.classFqName?.shortName()?.asString()) { + "AtomicIntArray" -> atomicIntArrayClassSymbol + "AtomicLongArray" -> atomicLongArrayClassSymbol + "AtomicBooleanArray" -> atomicIntArrayClassSymbol + "AtomicArray" -> atomicRefArrayClassSymbol + else -> error("Unexpected atomicfu array type ${atomicfuArrayType.render()}.") + } + + fun getAtomicArrayClassByValueType(valueType: IrType): IrClassSymbol = + when { + valueType == irBuiltIns.intType -> atomicIntArrayClassSymbol + valueType == irBuiltIns.booleanType -> atomicIntArrayClassSymbol + valueType == irBuiltIns.longType -> atomicLongArrayClassSymbol + !valueType.isPrimitiveType() -> atomicRefArrayClassSymbol + else -> error("No corresponding atomic array class found for the given value type ${valueType.render()}.") + } + + fun getAtomicHandlerFunctionSymbol(atomicHandlerClass: IrClassSymbol, name: String): IrSimpleFunctionSymbol = + when (name) { + "", "getValue" -> atomicHandlerClass.getSimpleFunction("get") + "", "setValue", "lazySet" -> atomicHandlerClass.getSimpleFunction("set") + else -> atomicHandlerClass.getSimpleFunction(name) + } ?: error("No $name function found in ${atomicHandlerClass.owner.render()}") + abstract fun createBuilder( symbol: IrSymbol, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET ): AbstractAtomicfuIrBuilder + val invoke0Symbol = irBuiltIns.functionN(0).getSimpleFunction("invoke")!! val invoke1Symbol = irBuiltIns.functionN(1).getSimpleFunction("invoke")!! + fun function0Type(returnType: IrType) = buildSimpleType( + irBuiltIns.functionN(0).symbol, + listOf(returnType) + ) + fun function1Type(argType: IrType, returnType: IrType) = buildSimpleType( irBuiltIns.functionN(1).symbol, listOf(argType, returnType) ) + fun buildSimpleType( + symbol: IrClassifierSymbol, + typeParameters: List + ): IrSimpleType = + IrSimpleTypeImpl( + classifier = symbol, + hasQuestionMark = false, + arguments = typeParameters.map { makeTypeProjection(it, Variance.INVARIANT) }, + annotations = emptyList() + ) + object ATOMICFU_GENERATED_CLASS : IrDeclarationOriginImpl("ATOMICFU_GENERATED_CLASS", isSynthetic = true) object ATOMICFU_GENERATED_FUNCTION : IrDeclarationOriginImpl("ATOMICFU_GENERATED_FUNCTION", isSynthetic = true) object ATOMICFU_GENERATED_FIELD : IrDeclarationOriginImpl("ATOMICFU_GENERATED_FIELD", isSynthetic = true) @@ -87,15 +143,4 @@ abstract class AbstractAtomicSymbols( private fun buildAnnotationConstructor(annotationClass: IrClass): IrConstructor = annotationClass.addConstructor { isPrimary = true } - - private fun buildSimpleType( - symbol: IrClassifierSymbol, - typeParameters: List - ): IrSimpleType = - IrSimpleTypeImpl( - classifier = symbol, - hasQuestionMark = false, - arguments = typeParameters.map { makeTypeProjection(it, Variance.INVARIANT) }, - annotations = emptyList() - ) } diff --git a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/common/AbstractAtomicfuIrBuilder.kt b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/common/AbstractAtomicfuIrBuilder.kt index f1a8e4eff69..8798f7a4753 100644 --- a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/common/AbstractAtomicfuIrBuilder.kt +++ b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/common/AbstractAtomicfuIrBuilder.kt @@ -15,10 +15,13 @@ import org.jetbrains.kotlin.ir.builders.declarations.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.defaultType import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl +import org.jetbrains.kotlin.ir.types.isInt import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeAsciiOnly @@ -37,6 +40,13 @@ abstract class AbstractAtomicfuIrBuilder( this.dispatchReceiver = dispatchReceiver?.deepCopyWithSymbols() } + // atomicArr.get(index) + fun atomicGetArrayElement(atomicArrayClass: IrClassSymbol, receiver: IrExpression, index: IrExpression) = + irCall(atomicSymbols.getAtomicHandlerFunctionSymbol(atomicArrayClass, "get")).apply { + dispatchReceiver = receiver + putValueArgument(0, index) + } + fun irCallWithArgs(symbol: IrSimpleFunctionSymbol, dispatchReceiver: IrExpression?, extensionReceiver: IrExpression?, valueArguments: List) = irCall(symbol).apply { this.dispatchReceiver = dispatchReceiver @@ -46,6 +56,13 @@ abstract class AbstractAtomicfuIrBuilder( } } + fun callAtomicExtension( + symbol: IrSimpleFunctionSymbol, + dispatchReceiver: IrExpression?, + syntheticValueArguments: List, + valueArguments: List + ) = irCallWithArgs(symbol, dispatchReceiver, null, syntheticValueArguments + valueArguments) + fun irVolatileField( name: String, type: IrType, @@ -66,6 +83,57 @@ abstract class AbstractAtomicfuIrBuilder( this.parent = parentContainer } + fun irAtomicArrayField( + name: Name, + arrayClass: IrClassSymbol, + isStatic: Boolean, + annotations: List, + size: IrExpression, + dispatchReceiver: IrExpression?, + parentContainer: IrDeclarationContainer + ): IrField = + context.irFactory.buildField { + this.name = name + type = arrayClass.defaultType + this.isFinal = true + this.isStatic = isStatic + visibility = DescriptorVisibilities.PRIVATE + origin = AbstractAtomicSymbols.ATOMICFU_GENERATED_FIELD + }.apply { + this.initializer = IrExpressionBodyImpl( + newAtomicArray(arrayClass, size, dispatchReceiver) + ) + this.annotations = annotations + this.parent = parentContainer + } + + abstract fun newAtomicArray( + atomicArrayClass: IrClassSymbol, + size: IrExpression, + dispatchReceiver: IrExpression? + ): IrFunctionAccessExpression + + // atomicArr.compareAndSet(index, expect, update) + fun callAtomicArray( + arrayClassSymbol: IrClassSymbol, + functionName: String, + dispatchReceiver: IrExpression?, + index: IrExpression, + valueArguments: List, + isBooleanReceiver: Boolean + ): IrCall { + val irCall = irCall(atomicSymbols.getAtomicHandlerFunctionSymbol(arrayClassSymbol, functionName)).apply { + this.dispatchReceiver = dispatchReceiver + putValueArgument(0, index) // array element index + valueArguments.forEachIndexed { index, arg -> + // as AtomicBooleanArray is represented with AtomicIntArray, + // boolean arguments should be cast to int + putValueArgument(index + 1, if (isBooleanReceiver) arg?.toInt() else arg) + } + } + return if (isBooleanReceiver && irCall.type.isInt()) irCall.toBoolean() else irCall + } + fun buildClassInstance( irClass: IrClass, parentContainer: IrDeclarationContainer, @@ -89,6 +157,7 @@ abstract class AbstractAtomicfuIrBuilder( } fun IrExpression.toBoolean() = irNotEquals(this, irInt(0)) as IrCall + fun IrExpression.toInt() = irIfThenElse(irBuiltIns.intType, irEquals(this, irBoolean(true)), irInt(1), irInt(0)) fun irClassWithPrivateConstructor( name: String, @@ -156,7 +225,7 @@ abstract class AbstractAtomicfuIrBuilder( private fun IrProperty.addGetter(isStatic: Boolean, parentContainer: IrDeclarationContainer, irBuiltIns: IrBuiltIns) { val property = this - val field = requireNotNull(backingField) { "BackingField of the property $property should not be null"} + val field = requireNotNull(backingField) { "The backing field of the property $property should not be null."} addGetter { visibility = property.visibility returnType = field.type @@ -189,7 +258,7 @@ abstract class AbstractAtomicfuIrBuilder( private fun IrProperty.addSetter(isStatic: Boolean, parentClass: IrDeclarationContainer, irBuiltIns: IrBuiltIns) { val property = this - val field = requireNotNull(property.backingField) { "BackingField of the property $property should not be null"} + val field = requireNotNull(property.backingField) { "The backing field of the property $property should not be null."} this@addSetter.addSetter { visibility = property.visibility returnType = irBuiltIns.unitType @@ -222,4 +291,9 @@ abstract class AbstractAtomicfuIrBuilder( ) } } + + abstract fun atomicfuLoopBody(valueType: IrType, valueParameters: List): IrBlockBody + abstract fun atomicfuArrayLoopBody(atomicArrayClass: IrClassSymbol, valueParameters: List): IrBlockBody + abstract fun atomicfuUpdateBody(functionName: String, valueType: IrType, valueParameters: List): IrBlockBody + abstract fun atomicfuArrayUpdateBody(functionName: String, valueType: IrType, atomicArrayClass: IrClassSymbol, valueParameters: List): IrBlockBody } diff --git a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/common/AbstractAtomicfuTransformer.kt b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/common/AbstractAtomicfuTransformer.kt index bccc68dcd92..1ff382da7f0 100644 --- a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/common/AbstractAtomicfuTransformer.kt +++ b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/common/AbstractAtomicfuTransformer.kt @@ -12,9 +12,13 @@ import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibility import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement -import org.jetbrains.kotlin.ir.builders.irExprBody +import org.jetbrains.kotlin.ir.backend.js.utils.valueArguments +import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter +import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.builders.irGetField import org.jetbrains.kotlin.ir.builders.irSetField +import org.jetbrains.kotlin.ir.builders.irBlockBody +import org.jetbrains.kotlin.ir.builders.irReturn import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.expressions.* @@ -25,6 +29,7 @@ import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.* +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance private const val ATOMICFU = "atomicfu" @@ -37,6 +42,10 @@ private const val APPEND = "append" private const val GET = "get" private const val VOLATILE = "\$volatile" private const val VOLATILE_WRAPPER_SUFFIX = "\$VolatileWrapper\$$ATOMICFU" +private const val LOOP = "loop" +private const val ACTION = "action\$$ATOMICFU" +private const val INDEX = "index\$$ATOMICFU" +private const val UPDATE = "update" abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { @@ -77,8 +86,10 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { private val ATOMIC_VALUE_TYPES = setOf("AtomicInt", "AtomicLong", "AtomicBoolean", "AtomicRef") private val ATOMIC_ARRAY_TYPES = setOf("AtomicIntArray", "AtomicLongArray", "AtomicBooleanArray", "AtomicArray") - protected val atomicPropertyToVolatile = mutableMapOf() - protected val propertyToAtomicHandler = mutableMapOf() + // Maps atomicfu atomic property to the corresponding volatile property. + protected val atomicfuPropertyToVolatile = mutableMapOf() + // Maps atomicfu property to the atomic handler (field updater/atomic array). + protected val atomicfuPropertyToAtomicHandler = mutableMapOf() fun transform(moduleFragment: IrModuleFragment) { transformAtomicProperties(moduleFragment) @@ -91,7 +102,6 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { } protected abstract val atomicPropertiesTransformer: AtomicPropertiesTransformer - protected abstract val atomicExtensionsTransformer: AtomicExtensionTransformer protected abstract val atomicFunctionsTransformer: AtomicFunctionCallTransformer private fun transformAtomicProperties(moduleFragment: IrModuleFragment) { @@ -102,7 +112,7 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { private fun transformAtomicExtensions(moduleFragment: IrModuleFragment) { for (irFile in moduleFragment.files) { - irFile.transform(atomicExtensionsTransformer, null) + irFile.transform(AtomicExtensionTransformer(), null) } } @@ -156,7 +166,7 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { } atomicProperty.isAtomicArray() -> { atomicProperty.checkVisibility() - parentContainer.addTransformedAtomicArray(atomicProperty, index)?.also { + parentContainer.addTransformedAtomicArray(atomicProperty, index).also { declarationsToBeRemoved.add(atomicProperty) } } @@ -167,26 +177,45 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { } /** - * Generates a volatile property that can be atomically updated instead of the given atomic property - * and adds it to the parent class. - * Returns the volatile property. + * Builds a volatile property that can be atomically updated instead of the given atomicfu property, + * and replaces the original declaration in the parent class. + * Returns the new volatile property. */ abstract fun IrClass.addTransformedInClassAtomic(atomicProperty: IrProperty, index: Int): IrProperty /** - * Generates a volatile property that can be atomically updated instead of the given static atomic property - * and adds it to the parent container. - * Returns the voaltile property. + * Builds a volatile property that can be atomically updated instead of the given static atomicfu property + * and replaces the original declaration in the parent container. + * Returns the new volatile property. */ abstract fun IrDeclarationContainer.addTransformedStaticAtomic(atomicProperty: IrProperty, index: Int): IrProperty /** - * Generates an array that can be atomically updated instead of the given atomic array - * and adds it to the parent class. - * Returns the new property or null if transformation was skipped. - * NOTE: skipping transformation is supported for K/N backend, because arrays are currently not supported there. + * Builds an array that can be atomically updated instead of the given atomicfu atomic array + * and replaces the original declaration in the parent class. + * Returns the generated array. + * For JVM: atomic arrays are replaced with the corresponding java.util.concurrent.Atomic*Array + * For Native: atomic arrays are replaced with the corresponding kotlin.concurrent.Atomic*Array + * (In the future atomic arrays will be commonized in Kotlin stdlib) + * + * val intArr = kotlinx.atomicfu.AtomicIntArray(45) --> val intArr = java.util.concurrent.AtomicIntegerArray(45) // JVM + * val intArr = kotlinx.atomicfu.AtomicIntArray(45) --> val intArr = kotlin.concurrent.AtomicIntArray(45) // Native */ - abstract fun IrDeclarationContainer.addTransformedAtomicArray(atomicProperty: IrProperty, index: Int): IrProperty? + private fun IrDeclarationContainer.addTransformedAtomicArray(atomicProperty: IrProperty, index: Int): IrProperty { + val parentContainer = this + with(atomicSymbols.createBuilder(atomicProperty.symbol)) { + val javaAtomicArrayField = buildAtomicArrayField(atomicProperty, parentContainer) + return parentContainer.replacePropertyAtIndex( + javaAtomicArrayField, + atomicProperty.visibility, + isVar = false, + isStatic = parentContainer is IrFile, + index + ).also { + atomicfuPropertyToAtomicHandler[atomicProperty] = it + } + } + } /** * Transforms the given property that was delegated to the atomic property: @@ -194,7 +223,8 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { */ private fun IrDeclarationContainer.transformDelegatedAtomic(atomicProperty: IrProperty) { val getDelegate = atomicProperty.backingField?.initializer?.expression - require(getDelegate is IrCall) { "Expected initializer of the delegated property ${this.render()} is IrCall but found ${getDelegate?.render()}" } + require(getDelegate is IrCall) { "Unexpected initializer of the delegated property ${atomicProperty.render()}: " + + "expected invocation of the delegate atomic property getter, but found ${getDelegate?.render()}." + CONSTRAINTS_MESSAGE } val delegateVolatileField = when { getDelegate.isAtomicFactoryCall() -> { /** @@ -223,11 +253,13 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { val delegate = getDelegate.getCorrespondingProperty() check(delegate.parent == atomicProperty.parent) { "The delegated property [${atomicProperty.render()}] declared in [${atomicProperty.parent.render()}] should be declared in the same scope " + - "as the corresponding atomic property [${delegate.render()}] declared in [${delegate.parent.render()}]." + CONSTRAINTS_MESSAGE} - val volatileProperty = atomicPropertyToVolatile[delegate] ?: error("The delegate property was not transformed: ${delegate.render()}.") - volatileProperty.backingField ?: error("Transformed atomic field should have a non-null backingField.") + "as the corresponding atomic property [${delegate.render()}] declared in [${delegate.parent.render()}]" + CONSTRAINTS_MESSAGE} + val volatileProperty = atomicfuPropertyToVolatile[delegate] + ?: error("No generated volatile property was found for the delegate atomic property ${delegate.render()}") + volatileProperty.backingField + ?: error("Volatile property ${volatileProperty.render()} corresponding to the atomic property ${delegate.render()} should have a non-null backingField") } - else -> error("Unexpected initializer of the delegated property ${this.render()}") + else -> error("Unexpected initializer of the delegated property ${getDelegate.render()}" + CONSTRAINTS_MESSAGE) } atomicProperty.getter?.transformAccessor(delegateVolatileField) atomicProperty.setter?.transformAccessor(delegateVolatileField) @@ -242,18 +274,20 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { dispatchReceiverParameter?.capture() } with(atomicSymbols.createBuilder(symbol)) { - body = irExprBody( - if (this@transformAccessor.isGetter) { - irGetField(dispatchReceiver, delegateVolatileField) - } else { - irSetField(dispatchReceiver, delegateVolatileField, this@transformAccessor.valueParameters[0].capture()) - } - ) + body = irBlockBody { + +irReturn( + if (this@transformAccessor.isGetter) { + irGetField(dispatchReceiver, delegateVolatileField) + } else { + irSetField(dispatchReceiver, delegateVolatileField, this@transformAccessor.valueParameters[0].capture()) + } + ) + } } } /** - * Generates a private volatile field initialized with the initial value of the given atomic property: + * Builds a private volatile field initialized with the initial value of the given atomic property: * private val a = atomic(0) --> private @Volatile a: Int = 0 */ protected fun AbstractAtomicfuIrBuilder.buildVolatileBackingField( @@ -261,13 +295,13 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { parentContainer: IrDeclarationContainer, tweakBooleanToInt: Boolean ): IrField { - val atomicField = requireNotNull(atomicProperty.backingField) { "BackingField of atomic property $atomicProperty should not be null." } - val fieldType = atomicField.type.atomicToPrimitiveType() + val atomicField = requireNotNull(atomicProperty.backingField) { "The backing field of the atomic property ${atomicProperty.render()} declared in ${parentContainer.render()} should not be null." + CONSTRAINTS_MESSAGE } + val fieldType = (atomicField.type as IrSimpleType).atomicToPrimitiveType() val initializer = atomicField.initializer?.expression if (initializer == null) { val initBlock = atomicField.getInitBlockForField(parentContainer) val initExprWithIndex = initBlock.getInitExprWithIndexFromInitBlock(atomicField.symbol) - ?: error("Expected property ${atomicProperty.render()} initialization in init block ${initBlock.render()}.") + ?: error("The atomic property ${atomicProperty.render()} was not initialized neither at the declaration, nor in the init block." + CONSTRAINTS_MESSAGE) val atomicFactoryCall = initExprWithIndex.value.value val initExprIndex = initExprWithIndex.index val initValue = atomicFactoryCall.getAtomicFactoryValueArgument() @@ -296,6 +330,56 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { } } + /** + * Builds an atomic array field initialized with the initial size of the given atomic array, + * the generated field has the same visibility as the original atomic array: + * internal val intArr = kotlinx.atomicfu.AtomicIntArray --> internal val intArr = j.u.c.a.AtomicIntegerArray // JVM + * internal val intArr = kotlin.concurrent.AtomicIntArray // Native + */ + private fun AbstractAtomicfuIrBuilder.buildAtomicArrayField( + atomicProperty: IrProperty, + parentContainer: IrDeclarationContainer + ): IrField { + val atomicArrayField = + requireNotNull(atomicProperty.backingField) { "The backing field of the atomic array ${atomicProperty.render()} should not be null." + CONSTRAINTS_MESSAGE } + val initializer = atomicArrayField.initializer?.expression + if (initializer == null) { + // replace field initialization in the init block + val initBlock = atomicArrayField.getInitBlockForField(parentContainer) + // property initialization order in the init block matters -> transformed initializer should be placed at the same position + val initExprWithIndex = initBlock.getInitExprWithIndexFromInitBlock(atomicArrayField.symbol) + ?: error("The atomic array ${atomicProperty.render()} was not initialized neither at the declaration, nor in the init block." + CONSTRAINTS_MESSAGE) + val atomicFactoryCall = initExprWithIndex.value.value + val initExprIndex = initExprWithIndex.index + val arraySize = atomicFactoryCall.getArraySizeArgument() + return irAtomicArrayField( + atomicArrayField.name, + atomicSymbols.getAtomicArrayClassByAtomicfuArrayType(atomicArrayField.type), + atomicArrayField.isStatic, + atomicArrayField.annotations, + arraySize, + (atomicFactoryCall as IrFunctionAccessExpression).dispatchReceiver, + parentContainer + ).also { + val initExpr = it.initializer?.expression + ?: error("The generated atomic array field ${it.render()} should've already be initialized." + CONSTRAINTS_MESSAGE) + it.initializer = null + initBlock.updateFieldInitialization(atomicArrayField.symbol, it.symbol, initExpr, initExprIndex) + } + } else { + val arraySize = initializer.getArraySizeArgument() + return irAtomicArrayField( + atomicArrayField.name, + atomicSymbols.getAtomicArrayClassByAtomicfuArrayType(atomicArrayField.type), + atomicArrayField.isStatic, + atomicArrayField.annotations, + arraySize, + (initializer as IrFunctionAccessExpression).dispatchReceiver, + parentContainer + ) + } + } + /** * In case if atomic property is initialized in init block it's declaration is replaced with the volatile property * and initialization of the backing field is also performed in the init block: @@ -306,7 +390,7 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { * _a = atomic(0) _a = 0 * } } */ - protected fun IrAnonymousInitializer.getInitExprWithIndexFromInitBlock( + private fun IrAnonymousInitializer.getInitExprWithIndexFromInitBlock( oldFieldSymbol: IrFieldSymbol ): IndexedValue? = body.statements.withIndex().singleOrNull { it.value is IrSetField && (it.value as IrSetField).symbol == oldFieldSymbol }?.let { @@ -314,7 +398,7 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { it as IndexedValue } - protected fun IrAnonymousInitializer.updateFieldInitialization( + private fun IrAnonymousInitializer.updateFieldInitialization( oldFieldSymbol: IrFieldSymbol, volatileFieldSymbol: IrFieldSymbol, initExpr: IrExpression, @@ -331,7 +415,7 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { } } - protected fun IrField.getInitBlockForField(parentContainer: IrDeclarationContainer): IrAnonymousInitializer { + private fun IrField.getInitBlockForField(parentContainer: IrDeclarationContainer): IrAnonymousInitializer { for (declaration in parentContainer.declarations) { if (declaration is IrAnonymousInitializer) { if (declaration.body.statements.any { it is IrSetField && it.symbol == this.symbol }) { @@ -362,22 +446,6 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { ) } - // atomic(value = 0) -> 0 - private fun IrExpression.getAtomicFactoryValueArgument(): IrExpression { - require(this is IrCall) { "Expected atomic factory invocation but found: ${this.render()}." } - return getValueArgument(0)?.deepCopyWithSymbols() - ?: error("Atomic factory should take at least one argument: ${this.render()}.") - } - - // AtomicIntArray(size = 10) -> 10 - protected fun IrExpression.getArraySizeArgument(): IrExpression { - require(this is IrFunctionAccessExpression) { - "Expected atomic array factory invocation, but found: ${this.render()}." - } - return getValueArgument(0)?.deepCopyWithSymbols() - ?: error("Atomic array factory should take at least one argument: ${this.render()}.") - } - private fun IrProperty.checkVisibility() = check((visibility == DescriptorVisibilities.PRIVATE || visibility == DescriptorVisibilities.INTERNAL) || (parent is IrClass && @@ -402,7 +470,7 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { } } - protected abstract inner class AtomicExtensionTransformer : IrElementTransformerVoid() { + private inner class AtomicExtensionTransformer : IrElementTransformerVoid() { override fun visitFile(declaration: IrFile): IrFile { declaration.transformAllAtomicExtensions() return super.visitFile(declaration) @@ -413,7 +481,57 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { return super.visitClass(declaration) } - abstract fun IrDeclarationContainer.transformAllAtomicExtensions() + private fun IrDeclarationContainer.transformAllAtomicExtensions() { + declarations.filter { it is IrFunction && it.isAtomicExtension() }.forEach { atomicExtension -> + atomicExtension as IrFunction + declarations.add(transformAtomicExtension(atomicExtension, this, false)) + declarations.add(transformAtomicExtension(atomicExtension, this, true)) + // the original atomic extension is removed + declarations.remove(atomicExtension) + } + } + + private fun transformAtomicExtension( + atomicExtension: IrFunction, + parent: IrDeclarationContainer, + isArrayReceiver: Boolean + ): IrFunction { + /** + * At this step, only signature of the atomic extension is changed, + * the body is just copied and will be transformed at the next step by AtomicFunctionCallTransformer. + * + * Two different signatures are generated for the case of atomic property receiver + * and for the case of atomic array element receiver, due to different atomic updaters. + * + * Generated signatures for JVM: + * inline fun AtomicInt.foo(arg: Int) --> inline fun foo$atomicfu(dispatchReceiver: Any?, atomicHandler: AtomicIntegerFieldUpdater, arg': Int) + * inline fun foo$atomicfu$array(dispatchReceiver: Any?, atomicHandler: AtomicIntegerArray, index: Int, arg': Int) + * + * Generated signatures for Native: + * inline fun AtomicInt.foo(arg: Int) --> inline fun foo$atomicfu(refGetter: () -> KMutableProperty0, arg': Int) + * * inline fun foo$atomicfu$array(atomicArray: AtomicIntegerArray, index: Int, arg': Int) + */ + return buildTransformedAtomicExtensionSignature(atomicExtension, isArrayReceiver).apply { + body = atomicExtension.body?.deepCopyWithSymbols(this) + body?.transform( + object : IrElementTransformerVoid() { + override fun visitReturn(expression: IrReturn): IrExpression = super.visitReturn( + if (expression.returnTargetSymbol == atomicExtension.symbol) { + with(atomicSymbols.createBuilder(this@apply.symbol)) { + irReturn(expression.value) + } + } else { + expression + } + ) + }, null + ) + this.parent = parent + // all usages of the old type parameters should be remapped to the new type parameters. + val typeRemapper = IrTypeParameterRemapper(atomicExtension.typeParameters.associateWith { this.typeParameters[it.index] }) + remapTypes(typeRemapper) + } + } } protected abstract inner class AtomicFunctionCallTransformer : IrElementTransformer { @@ -431,9 +549,13 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { // then valueType is the type argument of Atomic* class `String` (it.type as IrSimpleType).arguments[0] as IrSimpleType } else { - propertyGetterCall.type.atomicToPrimitiveType() + (propertyGetterCall.type as IrSimpleType).atomicToPrimitiveType() + } + val isArrayReceiver = when { + propertyGetterCall is IrCall -> propertyGetterCall.isArrayElementReceiver(data) + propertyGetterCall.isThisReceiver() -> data != null && data.name.asString().isMangledAtomicArrayExtension() + else -> error("Unsupported atomic array receiver ${propertyGetterCall.render()}" + CONSTRAINTS_MESSAGE) } - val isArrayReceiver = propertyGetterCall.isArrayElementReceiver(data) if (expression.symbol.owner.isFromKotlinxAtomicfuPackage()) { /** * Transform invocations of functions from kotlinx.atomicfu on atomics properties or atomic array elements: @@ -506,35 +628,215 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { parentFunction: IrFunction? ): IrExpression - abstract fun transformAtomicUpdateCallOnArrayElement( + private fun transformAtomicUpdateCallOnArrayElement( expression: IrCall, functionName: String, valueType: IrType, getPropertyReceiver: IrExpression, parentFunction: IrFunction? - ): IrExpression + ): IrExpression { + with(atomicSymbols.createBuilder(expression.symbol)) { + /** + * Atomic update call on the atomic array element is replaced + * with the call to the j.u.c.a.Atomic*Array (for JVM) or kotlin.concurrent.AtomicIntArray (for Native). + * The API of these classes is consistent -> this transformation is commonized. + * + * 1. Function call receiver is atomic property getter call. + * + * The call is delegated to the corresponding atomic array: + * + * val intArr = kotlinx.atomicfu.AtomicIntArray(10) val intArr = AtomicIntArray(10) + * ()[5].compareAndSet(0, 5) ---> intArr.compareAndSet(5, 0, 5) + * + * + * 2. Function is called in the body of the transformed atomic extension, + * the call receiver is receiver of the original atomic extension: + * + * inline fun AtomicInt.foo(new: Int) { inline fun foo$atomicfu$array(atomicArray: AtomicIntArray, index: Int, arg': Int) + * this.getAndSet(value, new) ---> atomicArray.getAndSet(index, new) + * } } + */ + val getAtomicArray = getAtomicHandler(getPropertyReceiver, parentFunction) + return callAtomicArray( + arrayClassSymbol = getAtomicArray.type.classOrNull!!, + functionName = functionName, + dispatchReceiver = getAtomicArray, + index = getPropertyReceiver.getArrayElementIndex(parentFunction), + valueArguments = expression.valueArguments, + isBooleanReceiver = valueType.isBoolean() + ) + } + } - abstract fun transformedAtomicfuInlineFunctionCall( + private fun transformedAtomicfuInlineFunctionCall( expression: IrCall, functionName: String, valueType: IrType, getPropertyReceiver: IrExpression, isArrayReceiver: Boolean, parentFunction: IrFunction? - ): IrCall + ): IrCall { + with(atomicSymbols.createBuilder(expression.symbol)) { + /** + * a.loop { value -> a.compareAndSet(value, 777) } --> + * + * inline fun atomicfu$loop(dispatchReceiver: Any?, fu: AtomicIntegerFieldUpdater, action: (Int) -> Unit) { + * while (true) { + * val cur = fu.get() + * action(cur) + * } + * } + * + * a.atomicfu$loop(dispatchReceiver, fu) { ... } + */ + requireNotNull(parentFunction) { "Expected containing function of the call ${expression.render()}, but found null." + CONSTRAINTS_MESSAGE } + val loopFunc = parentFunction.parentDeclarationContainer.getOrBuildInlineLoopFunction( + functionName = functionName, + valueType = if (valueType.isBoolean()) irBuiltIns.intType else valueType, + isArrayReceiver = isArrayReceiver + ) + // We have to copy this lambda, because it is passed to both foo$atomicfu and foo$atomicfu$array transformations, + // and otherwise causes "lambda is already bound" error in K/N. + val action = (expression.getValueArgument(0) as IrFunctionExpression).apply { + function.body?.transform(this@AtomicFunctionCallTransformer, parentFunction) + if (function.valueParameters[0].type.isBoolean()) { + function.valueParameters[0].type = irBuiltIns.intType + function.returnType = irBuiltIns.intType + } + }.deepCopyWithSymbols(parentFunction) + val syntheticArguments = buildSyntheticValueArgsForTransformedAtomicExtensionCall(expression, getPropertyReceiver, isArrayReceiver, parentFunction) + return irCallWithArgs( + symbol = loopFunc.symbol, + dispatchReceiver = parentFunction.containingFunction.dispatchReceiverParameter?.capture(), + extensionReceiver = null, + valueArguments = syntheticArguments + action + ) + } + } - abstract fun transformAtomicExtensionCall( + private fun transformAtomicExtensionCall( expression: IrCall, originalAtomicExtension: IrSimpleFunction, getPropertyReceiver: IrExpression, isArrayReceiver: Boolean, parentFunction: IrFunction? - ): IrCall + ): IrCall { + with(atomicSymbols.createBuilder(expression.symbol)) { + /** + * Atomic extension call is replaced with the call to transformed atomic extension: + * + * 1. Function call receiver is atomic property getter call. + * Transformation variant of the atomic extension is chosen according to the type of receiver + * (atomic property -> foo$atomicfu, atomic array element -> foo$atomicfu$array) + * + * For JVM: + * + * inline fun AtomicInt.foo(arg: Int) {..} inline fun foo$atomicfu(dispatchReceiver: Any?, fu: j.u.c.a.AtomicIntegerFieldUpdater, arg: Int) + * aClass._a.foo(arg) --> foo$atomicfu(aClass, _a$volatile$FU, arg) + * + * For Native: + * inline fun AtomicInt.foo(arg: Int) {..} inline foo$atomicfu(refGetter: () -> KMutableProperty0, arg: Int) + * aClass._a.foo(arg) --> foo$atomicfu({_ -> aClass::_a}, arg) + * + * 2. Function is called in the body of the transformed atomic extension, + * the call receiver is the old receiver of the extension. + * In this case value parameters captured from the parent function are passed as arguments. + * + * For JVM: + * + * inline fun AtomicInt.bar(new: Int) inline fun bar$atomicfu(dispatchReceiver: Any?, handler: j.u.c.a.AtomicIntegerFieldUpdater, arg': Int) + * inline fun AtomicInt.foo(new: Int) { inline fun foo$atomicfu(dispatchReceiver: Any?, handler: j.u.c.a.AtomicIntegerFieldUpdater, arg': Int) + * bar(new) ---> bar$atomicfu(dispatchReceiver, handler, new) + * } + */ + requireNotNull(parentFunction) { "Expected containing function of the call ${expression.render()}, but found null." } + val parent = originalAtomicExtension.parent as IrDeclarationContainer + val transformedAtomicExtension = parent.getOrBuildTransformedAtomicExtension(originalAtomicExtension, isArrayReceiver) + val syntheticValueArguments = buildSyntheticValueArgsForTransformedAtomicExtensionCall(expression, getPropertyReceiver, isArrayReceiver, parentFunction) + return callAtomicExtension( + symbol = transformedAtomicExtension.symbol, + dispatchReceiver = expression.dispatchReceiver, + syntheticValueArguments = syntheticValueArguments, + valueArguments = expression.valueArguments + ) + } + } - abstract fun IrDeclarationContainer.getTransformedAtomicExtension( + private fun IrDeclarationContainer.getOrBuildInlineLoopFunction( + functionName: String, + valueType: IrType, + isArrayReceiver: Boolean + ): IrSimpleFunction { + val parent = this + val mangledName = mangleAtomicExtensionName(functionName, isArrayReceiver) + findDeclaration { + // check the type of the receiver here + it.name.asString() == mangledName && it.checkSyntheticParameterTypes(isArrayReceiver, valueType) + }?.let { return it } + return pluginContext.irFactory.buildFun { + name = Name.identifier(mangledName) + isInline = true + visibility = DescriptorVisibilities.PRIVATE + origin = AbstractAtomicSymbols.ATOMICFU_GENERATED_FUNCTION + }.apply { + dispatchReceiverParameter = (parent as? IrClass)?.thisReceiver?.deepCopyWithSymbols(this) + if (functionName == LOOP) { + if (isArrayReceiver) generateAtomicfuArrayLoop(valueType) else generateAtomicfuLoop(valueType) + } else { + if (isArrayReceiver) generateAtomicfuArrayUpdate(functionName, valueType) else generateAtomicfuUpdate(functionName, valueType) + } + this.parent = parent + parent.declarations.add(this) + } + } + + private fun IrDeclarationContainer.getOrBuildTransformedAtomicExtension( declaration: IrSimpleFunction, isArrayReceiver: Boolean - ): IrSimpleFunction + ): IrSimpleFunction { + // Try find the transformed atomic extension in the parent container + findDeclaration { + it.name.asString() == mangleAtomicExtensionName(declaration.name.asString(), isArrayReceiver) && + it.isTransformedAtomicExtension() + }?.let { return it } + /** + * NOTE: this comment is applicable to the JVM backend incremental compialtion: + * If the transformed declaration is not found then the call may be performed from another module + * which depends on the module where declarations are generated from untransformed metadata (real transformed declarations are not there). + * This happens if the call is performed from the test module or in case of incremental compilation. + * + * We build a fake declaration here: it's signature equals the one of the real transformed declaration, + * it doesn't have body and won't be generated. It is placed in the call site and + * during compilation this fake declaration will be resolved to the real transformed declaration. + */ + return buildTransformedAtomicExtensionSignature(declaration, isArrayReceiver) + } + + protected fun getAtomicHandler(atomicCallReceiver: IrExpression, parentFunction: IrFunction?): IrExpression = + when { + atomicCallReceiver is IrCall -> { + val isArrayReceiver = atomicCallReceiver.isArrayElementGetter() + val getAtomicProperty = if (isArrayReceiver) atomicCallReceiver.dispatchReceiver as IrCall else atomicCallReceiver + val atomicProperty = getAtomicProperty.getCorrespondingProperty() + val atomicHandlerProperty = atomicfuPropertyToAtomicHandler[atomicProperty] + ?: error("No atomic handler found for the atomic property ${atomicProperty.render()}, \n" + + "these properties were registered: ${ + atomicfuPropertyToAtomicHandler.keys.toList().joinToString("\n") { it.render() } + }" + CONSTRAINTS_MESSAGE) + with(atomicSymbols.createBuilder(atomicCallReceiver.symbol)) { + // dispatchReceiver for get-a$FU() is null, because a$FU is a static property + // dispatchReceiver for get-arr'() is equal to the dispatchReceiver of the original getter + irGetProperty(atomicHandlerProperty, if (isArrayReceiver) getAtomicProperty.dispatchReceiver else null) + } + } + atomicCallReceiver.isThisReceiver() -> { + requireNotNull(parentFunction) { "Expected containing function of the call with receiver ${atomicCallReceiver.render()}, but found null." + CONSTRAINTS_MESSAGE} + require(parentFunction.isTransformedAtomicExtension()) + val isArrayReceiver = parentFunction.name.asString().isMangledAtomicArrayExtension() + if (isArrayReceiver) parentFunction.valueParameters[0].capture() else parentFunction.valueParameters[1].capture() + } + else -> error("Unexpected type of atomic function call receiver: ${atomicCallReceiver.render()} \n" + CONSTRAINTS_MESSAGE) + } override fun visitGetValue(expression: IrGetValue, data: IrFunction?): IrExpression { /** @@ -561,9 +863,26 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { return super.visitGetValue(expression, data) } + // Generates value arguments for the transformed atomic extension invocation. + abstract fun buildSyntheticValueArgsForTransformedAtomicExtensionCall( + expression: IrCall, + getPropertyReceiver: IrExpression, + isArrayReceiver: Boolean, + parentFunction: IrFunction + ): List + abstract fun IrValueParameter.remapValueParameter(transformedExtension: IrFunction): IrValueParameter? - abstract fun IrFunction.isTransformedAtomicExtension(): Boolean + protected fun IrFunction.isTransformedAtomicExtension(): Boolean { + val isArrayReceiver = name.asString().isMangledAtomicArrayExtension() + return if (isArrayReceiver) checkSyntheticArrayElementExtensionParameter() else checkSyntheticAtomicExtensionParameters() + } + + abstract fun IrFunction.checkSyntheticAtomicExtensionParameters(): Boolean + + abstract fun IrFunction.checkSyntheticArrayElementExtensionParameter(): Boolean + + abstract fun IrFunction.checkSyntheticParameterTypes(isArrayReceiver: Boolean, receiverValueType: IrType): Boolean abstract fun IrExpression.isArrayElementReceiver( parentFunction: IrFunction? @@ -589,6 +908,53 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { } return super.visitContainerExpression(expression, data) } + + private fun IrSimpleFunction.generateAtomicfuLoop(valueType: IrType) { + addSyntheticValueParametersToTransformedAtomicExtension(false, valueType) + addValueParameter(ACTION, atomicSymbols.function1Type(valueType, irBuiltIns.unitType)) + body = with(atomicSymbols.createBuilder(symbol)) { + atomicfuLoopBody(valueType, valueParameters) + } + returnType = irBuiltIns.unitType + } + + private fun IrSimpleFunction.generateAtomicfuArrayLoop(valueType: IrType) { + val atomicfuArrayClass = atomicSymbols.getAtomicArrayClassByValueType(valueType) + addSyntheticValueParametersToTransformedAtomicExtension(true, valueType) + addValueParameter(ACTION, atomicSymbols.function1Type(valueType, irBuiltIns.unitType)) + body = with(atomicSymbols.createBuilder(symbol)) { + atomicfuArrayLoopBody(atomicfuArrayClass, valueParameters) + } + returnType = irBuiltIns.unitType + } + + private fun IrSimpleFunction.generateAtomicfuUpdate(functionName: String, valueType: IrType) { + addSyntheticValueParametersToTransformedAtomicExtension(false, valueType) + addValueParameter(ACTION, atomicSymbols.function1Type(valueType, valueType)) + body = with(atomicSymbols.createBuilder(symbol)) { + atomicfuUpdateBody( + functionName, + valueType, + valueParameters + ) + } + returnType = if (functionName == UPDATE) irBuiltIns.unitType else valueType + } + + private fun IrSimpleFunction.generateAtomicfuArrayUpdate(functionName: String, valueType: IrType) { + val atomicfuArrayClass = atomicSymbols.getAtomicArrayClassByValueType(valueType) + addSyntheticValueParametersToTransformedAtomicExtension(true, valueType) + addValueParameter(ACTION, atomicSymbols.function1Type(valueType, valueType)) + body = with(atomicSymbols.createBuilder(symbol)) { + atomicfuArrayUpdateBody( + functionName, + valueType, + atomicfuArrayClass, + valueParameters + ) + } + returnType = if (functionName == UPDATE) irBuiltIns.unitType else valueType + } } private inner class FinalTransformationChecker: IrElementTransformer { @@ -611,6 +977,11 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { } } + // Builds the signature of the transformed atomic extension. + abstract fun buildTransformedAtomicExtensionSignature(atomicExtension: IrFunction, isArrayReceiver: Boolean): IrSimpleFunction + // Adds value parameters for transformed inline extension functions. + abstract fun IrFunction.addSyntheticValueParametersToTransformedAtomicExtension(isArrayReceiver: Boolean, valueType: IrType) + // Util transformer functions protected fun getStaticVolatileWrapperInstance(volatileWrapperClass: IrClass): IrExpression { @@ -671,7 +1042,7 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { it.type.isAtomicArrayType() && symbol.owner.name.asString() == GET } ?: false - protected fun IrType.atomicToPrimitiveType(): IrType = + protected fun IrSimpleType.atomicToPrimitiveType(): IrType = when(classFqName?.shortName()?.asString()) { "AtomicInt" -> irBuiltIns.intType "AtomicLong" -> irBuiltIns.longType @@ -704,14 +1075,42 @@ abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) { protected val IrDeclaration.parentDeclarationContainer: IrDeclarationContainer get() = parents.filterIsInstance().firstOrNull() - ?: error("In the sequence of parents for ${this.render()} no IrDeclarationContainer was found") + ?: error("In the sequence of parents for ${this.render()} no IrDeclarationContainer was found" + CONSTRAINTS_MESSAGE) protected val IrFunction.containingFunction: IrFunction get() { if (this.origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA) return this return parents.filterIsInstance().firstOrNull { it.origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA - } ?: error("In the sequence of parents for the local function ${this.render()} no containing function was found") + } ?: error("In the sequence of parents for the local function ${this.render()} no containing function was found" + CONSTRAINTS_MESSAGE) + } + + // atomic(value = 0) -> 0 + protected fun IrExpression.getAtomicFactoryValueArgument(): IrExpression { + require(this is IrCall) { "Expected atomic factory invocation but found: ${this.render()}" } + return getValueArgument(0)?.deepCopyWithSymbols() + ?: error("Atomic factory should take at least one argument: ${this.render()}" + CONSTRAINTS_MESSAGE) + } + + // AtomicIntArray(size = 10) -> 10 + protected fun IrExpression.getArraySizeArgument(): IrExpression { + require(this is IrFunctionAccessExpression) { + "Expected atomic array factory invocation, but found: ${this.render()}." + } + return getValueArgument(0)?.deepCopyWithSymbols() + ?: error("Atomic array factory should take at least one argument: ${this.render()}" + CONSTRAINTS_MESSAGE) + } + + protected fun IrExpression.getArrayElementIndex(parentFunction: IrFunction?): IrExpression = + when { + this is IrCall -> getValueArgument(0)!! + this.isThisReceiver() -> { + require(parentFunction != null) + val index = parentFunction.valueParameters[1] + require(index.name.asString() == INDEX && index.type == irBuiltIns.intType) + index.capture() + } + else -> error("Unexpected type of atomic receiver expression: ${this.render()} \n" + CONSTRAINTS_MESSAGE) } // A.kt -> A$VolatileWrapper$atomicfu diff --git a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/jvm/AtomicfuJvmIrTransformer.kt b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/jvm/AtomicfuJvmIrTransformer.kt index 2dfe9973a91..8d10abc0087 100644 --- a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/jvm/AtomicfuJvmIrTransformer.kt +++ b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/jvm/AtomicfuJvmIrTransformer.kt @@ -6,15 +6,14 @@ package org.jetbrains.kotlinx.atomicfu.compiler.backend.jvm import org.jetbrains.kotlin.backend.common.extensions.* +import org.jetbrains.kotlin.backend.jvm.ir.representativeUpperBound import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.ir.backend.js.utils.valueArguments import org.jetbrains.kotlin.ir.builders.declarations.* -import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.name.* import org.jetbrains.kotlinx.atomicfu.compiler.backend.common.AbstractAtomicSymbols import org.jetbrains.kotlinx.atomicfu.compiler.backend.common.AbstractAtomicfuTransformer @@ -23,10 +22,7 @@ import kotlin.collections.set private const val ATOMICFU = "atomicfu" private const val DISPATCH_RECEIVER = "dispatchReceiver\$$ATOMICFU" private const val ATOMIC_HANDLER = "handler\$$ATOMICFU" -private const val ACTION = "action\$$ATOMICFU" private const val INDEX = "index\$$ATOMICFU" -private const val LOOP = "loop" -private const val UPDATE = "update" class AtomicfuJvmIrTransformer( pluginContext: IrPluginContext, @@ -36,9 +32,6 @@ class AtomicfuJvmIrTransformer( override val atomicPropertiesTransformer: AtomicPropertiesTransformer get() = JvmAtomicPropertiesTransformer() - override val atomicExtensionsTransformer: AtomicExtensionTransformer - get() = JvmAtomicExtensionTransformer() - override val atomicFunctionsTransformer: AtomicFunctionCallTransformer get() = JvmAtomicFunctionCallTransformer() @@ -80,27 +73,6 @@ class AtomicfuJvmIrTransformer( return wrapperClass.addVolatilePropertyWithAtomicUpdater(atomicProperty, index) } - override fun IrDeclarationContainer.addTransformedAtomicArray(atomicProperty: IrProperty, index: Int): IrProperty { - /** - * Atomic arrays are replaced with corresponding java.util.concurrent.Atomic*Array: - * - * val intArr = kotlinx.atomicfu.AtomicIntArray(45) --> val intArr = java.util.concurrent.AtomicIntegerArray(45) - */ - val parentContainer = this - with(atomicSymbols.createBuilder(atomicProperty.symbol)) { - val javaAtomicArrayField = buildJavaAtomicArrayField(atomicProperty, parentContainer) - return parentContainer.replacePropertyAtIndex( - javaAtomicArrayField, - atomicProperty.visibility, - isVar = false, - isStatic = parentContainer is IrFile, - index - ).also { - propertyToAtomicHandler[atomicProperty] = it - } - } - } - private fun IrClass.addVolatilePropertyWithAtomicUpdater(from: IrProperty, index: Int): IrProperty { /** * Generates a volatile property and an atomic updater for this property, @@ -133,58 +105,15 @@ class AtomicfuJvmIrTransformer( } else { parentClass.addProperty(volatileField, DescriptorVisibilities.PRIVATE, isVar = true, isStatic = false) } - atomicPropertyToVolatile[from] = volatileProperty + atomicfuPropertyToVolatile[from] = volatileProperty val atomicUpdaterField = irJavaAtomicFieldUpdater(volatileField, parentClass) parentClass.addProperty(atomicUpdaterField, from.getMinVisibility(), isVar = false, isStatic = true).also { - propertyToAtomicHandler[from] = it + atomicfuPropertyToAtomicHandler[from] = it } return volatileProperty } } - private fun JvmAtomicfuIrBuilder.buildJavaAtomicArrayField( - atomicProperty: IrProperty, - parentContainer: IrDeclarationContainer - ): IrField { - val atomicArrayField = - requireNotNull(atomicProperty.backingField) { "BackingField of atomic array $atomicProperty should not be null" } - val initializer = atomicArrayField.initializer?.expression - if (initializer == null) { - // replace field initialization in the init block - val initBlock = atomicArrayField.getInitBlockForField(parentContainer) - // property initialization order in the init block matters -> transformed initializer should be placed at the same position - val initExprWithIndex = initBlock.getInitExprWithIndexFromInitBlock(atomicArrayField.symbol) - ?: error("Expected atomic array ${atomicProperty.render()} initialization in init block ${initBlock.render()}" + CONSTRAINTS_MESSAGE) - val atomicFactoryCall = initExprWithIndex.value.value - val initExprIndex = initExprWithIndex.index - val arraySize = atomicFactoryCall.getArraySizeArgument() - return irJavaAtomicArrayField( - atomicArrayField.name, - atomicSymbols.getAtomicArrayClassByAtomicfuArrayType(atomicArrayField.type), - atomicArrayField.isStatic, - atomicArrayField.annotations, - arraySize, - (atomicFactoryCall as IrFunctionAccessExpression).dispatchReceiver, - parentContainer - ).also { - val initExpr = it.initializer?.expression ?: error("Initializer of the generated field ${it.render()} can not be null" + CONSTRAINTS_MESSAGE) - it.initializer = null - initBlock.updateFieldInitialization(atomicArrayField.symbol, it.symbol, initExpr, initExprIndex) - } - } else { - val arraySize = initializer.getArraySizeArgument() - return irJavaAtomicArrayField( - atomicArrayField.name, - atomicSymbols.getAtomicArrayClassByAtomicfuArrayType(atomicArrayField.type), - atomicArrayField.isStatic, - atomicArrayField.annotations, - arraySize, - (initializer as IrFunctionAccessExpression).dispatchReceiver, - parentContainer - ) - } - } - private fun IrDeclarationContainer.getOrBuildVolatileWrapper(atomicProperty: IrProperty): IrClass { val visibility = atomicProperty.getMinVisibility() findDeclaration { it.isVolatileWrapper(visibility) && it.visibility == visibility }?.let { return it } @@ -202,50 +131,6 @@ class AtomicfuJvmIrTransformer( } } - private inner class JvmAtomicExtensionTransformer : AtomicExtensionTransformer() { - - override fun IrDeclarationContainer.transformAllAtomicExtensions() { - declarations.filter { it is IrFunction && it.isAtomicExtension() }.forEach { atomicExtension -> - atomicExtension as IrFunction - declarations.add(transformAtomicExtension(atomicExtension, this, false)) - declarations.add(transformAtomicExtension(atomicExtension, this, true)) - // the original atomic extension is removed - declarations.remove(atomicExtension) - } - } - - private fun transformAtomicExtension(atomicExtension: IrFunction, parent: IrDeclarationContainer, isArrayReceiver: Boolean): IrFunction { - /** - * At this step, only signature of the atomic extension is changed, - * the body is just copied and will be transformed at the next step by JvmAtomicFunctionCallTransformer. - * - * Two different signatures are generated for the case of atomic property receiver - * and for the case of atomic array element receiver, due to different atomic updaters. - * - * inline fun AtomicInt.foo(arg: Int) --> inline fun foo$atomicfu(dispatchReceiver: Any?, atomicHandler: AtomicIntegerFieldUpdater, arg': Int) - * inline fun foo$atomicfu$array(dispatchReceiver: Any?, atomicHandler: AtomicIntegerArray, index: Int, arg': Int) - */ - return buildTransformedAtomicExtensionDeclaration(atomicExtension, isArrayReceiver).apply { - // the body will be transformed later by `AtomicFUTransformer` - body = atomicExtension.body?.deepCopyWithSymbols(this) - body?.transform( - object : IrElementTransformerVoid() { - override fun visitReturn(expression: IrReturn): IrExpression = super.visitReturn( - if (expression.returnTargetSymbol == atomicExtension.symbol) { - with(atomicSymbols.createBuilder(this@apply.symbol)) { - irReturn(expression.value) - } - } else { - expression - } - ) - }, null - ) - this.parent = parent - } - } - } - private inner class JvmAtomicFunctionCallTransformer : AtomicFunctionCallTransformer() { override fun transformAtomicUpdateCallOnProperty( @@ -288,174 +173,32 @@ class AtomicfuJvmIrTransformer( } } - override fun transformAtomicUpdateCallOnArrayElement( + override fun buildSyntheticValueArgsForTransformedAtomicExtensionCall( expression: IrCall, - functionName: String, - valueType: IrType, - getPropertyReceiver: IrExpression, - parentFunction: IrFunction? - ): IrCall { - with(atomicSymbols.createBuilder(expression.symbol)) { - /** - * Atomic update call on the atomic array element is replaced - * with the call on the j.u.c.a.Atomic*Array field: - * - * 1. Function call receiver is atomic property getter call. - * - * The call is replaced with the call on the corresponding field updater: - * - * val intArr = AtomicIntArray(10) val intArr = AtomicIntegerArray(10) - * ()[5].compareAndSet(0, 5) ---> intArr.compareAndSet(5, 0, 5) - * - * - * 2. Function is called in the body of the transformed atomic extension, - * the call receiver is the old receiver of the extension: - * - * inline fun AtomicInt.foo(new: Int) { inline fun foo$atomicfu$array(dispatchReceiver: Any?, atomicHandler: AtomicIntegerArray, index: Int, arg': Int) - * this.getAndSet(value, new) ---> atomicHandler.getAndSet(index, new) - * } } - */ - val getJavaAtomicArray = getAtomicHandler(getPropertyReceiver, parentFunction) - return callAtomicArray( - arrayClassSymbol = getJavaAtomicArray.type.classOrNull!!, - functionName = functionName, - dispatchReceiver = getJavaAtomicArray, - index = getPropertyReceiver.getArrayElementIndex(parentFunction), - valueArguments = expression.valueArguments, - isBooleanReceiver = valueType.isBoolean() - ) - } - } - - override fun transformedAtomicfuInlineFunctionCall( - expression: IrCall, - functionName: String, - valueType: IrType, getPropertyReceiver: IrExpression, isArrayReceiver: Boolean, - parentFunction: IrFunction? - ): IrCall { - with(atomicSymbols.createBuilder(expression.symbol)) { - val dispatchReceiver = getDispatchReceiver(getPropertyReceiver, parentFunction) - val getAtomicHandler = getAtomicHandler(getPropertyReceiver, parentFunction) - /** - * a.loop { value -> a.compareAndSet(value, 777) } --> - * - * inline fun atomicfu$loop(atomicfu$handler: AtomicIntegerFieldUpdater, atomicfu$action: (Int) -> Unit, dispatchReceiver: Any?) { - * while (true) { - * val cur = atomicfu$handler.get() - * atomicfu$action(cur) - * } - * } - * - * a.atomicfu$loop(dispatchReceiver, atomicHandler) { ... } - */ - requireNotNull(parentFunction) { "Parent function of this call ${expression.render()} is null" + CONSTRAINTS_MESSAGE } - val loopFunc = parentFunction.parentDeclarationContainer.getOrBuildInlineLoopFunction( - functionName = functionName, - valueType = if (valueType.isBoolean()) irBuiltIns.intType else valueType, - isArrayReceiver = isArrayReceiver - ) - val action = (expression.getValueArgument(0) as IrFunctionExpression).apply { - function.body?.transform(this@JvmAtomicFunctionCallTransformer, parentFunction) - if (function.valueParameters[0].type.isBoolean()) { - function.valueParameters[0].type = irBuiltIns.intType - function.returnType = irBuiltIns.intType - } - } - return irCallWithArgs( - symbol = loopFunc.symbol, - dispatchReceiver = parentFunction.containingFunction.dispatchReceiverParameter?.capture(), - extensionReceiver = null, - valueArguments = if (isArrayReceiver) { - val index = getPropertyReceiver.getArrayElementIndex(parentFunction) - listOf(getAtomicHandler, index, action) - } else { - listOf(getAtomicHandler, action, dispatchReceiver) - } - ) + parentFunction: IrFunction + ): List { + val dispatchReceiver = getDispatchReceiver(getPropertyReceiver, parentFunction) + val getAtomicHandler = getAtomicHandler(getPropertyReceiver, parentFunction) + return if (isArrayReceiver) { + val index = getPropertyReceiver.getArrayElementIndex(parentFunction) + listOf(getAtomicHandler, index) + } else { + listOf(dispatchReceiver, getAtomicHandler) } } - override fun transformAtomicExtensionCall( - expression: IrCall, - originalAtomicExtension: IrSimpleFunction, - getPropertyReceiver: IrExpression, - isArrayReceiver: Boolean, - parentFunction: IrFunction? - ): IrCall { - with(atomicSymbols.createBuilder(expression.symbol)) { - /** - * Atomic extension call is replaced with the call to transformed atomic extension: - * - * 1. Function call receiver is atomic property getter call. - * Transformation variant of the atomic extension is chosen accorfin to the type of receiver - * (atomic property -> foo$atomicfu, atomic array element -> foo$atomicfu$array) - * - * inline fun AtomicInt.foo(atg: Int) {..} - * aClass._a.foo(arg) --> foo$atomicfu(aClass, _a$volatile$FU, arg) - * - * - * 2. Function is called in the body of the transformed atomic extension, - * the call receiver is the old receiver of the extension. - * In this case value parameters captured from the parent function are passed as arguments. - * - * inline fun AtomicInt.bar(new: Int) inline fun bar$atomicfu(dispatchReceiver: Any?, handler: j.u.c.a.AtomicIntegerFieldUpdater, arg': Int) - * inline fun AtomicInt.foo(new: Int) { inline fun foo$atomicfu(dispatchReceiver: Any?, handler: j.u.c.a.AtomicIntegerFieldUpdater, arg': Int) - * bar(new) ---> bar$atomicfu(dispatchReceiver, handler, new) - * } } - */ - val parent = originalAtomicExtension.parent as IrDeclarationContainer - val transformedAtomicExtension = parent.getTransformedAtomicExtension(originalAtomicExtension, isArrayReceiver) - val dispatchReceiver = getDispatchReceiver(getPropertyReceiver, parentFunction) - val getAtomicHandler = getAtomicHandler(getPropertyReceiver, parentFunction) - return callAtomicExtension( - symbol = transformedAtomicExtension.symbol, - dispatchReceiver = expression.dispatchReceiver, - syntheticValueArguments = if (isArrayReceiver) { - listOf(dispatchReceiver, getAtomicHandler, getPropertyReceiver.getArrayElementIndex(parentFunction)) - } else { - listOf(dispatchReceiver, getAtomicHandler) - }, - valueArguments = expression.valueArguments - ) - } - } - - override fun IrDeclarationContainer.getTransformedAtomicExtension( - declaration: IrSimpleFunction, - isArrayReceiver: Boolean - ): IrSimpleFunction { - // Try find the transformed atomic extension in the parent container - findDeclaration { - it.name.asString() == mangleAtomicExtensionName(declaration.name.asString(), isArrayReceiver) && - it.isTransformedAtomicExtension() - }?.let { return it } - /** - * If the transformed declaration is not found then the call may be performed from another module - * which depends on the module where declarations are generated from untransformed metadata (real transformed declarations are not there). - * This happens if the call is performed from the test module or in case of incremental compilation. - * - * We build a fake declaration here: it's signature equals the one of the real transformed declaration, - * it doesn't have body and won't be generated. It is placed in the call site and - * during compilation this fake declaration will be resolved to the real transformed declaration. - */ - return buildTransformedAtomicExtensionDeclaration(declaration, isArrayReceiver) - } - - override fun IrFunction.isTransformedAtomicExtension(): Boolean { - val isArrayReceiver = name.asString().isMangledAtomicArrayExtension() - return if (isArrayReceiver) checkSyntheticArrayElementExtensionParameter() else checkSyntheticAtomicExtensionParameters() - } - override fun IrValueParameter.remapValueParameter(transformedExtension: IrFunction): IrValueParameter? { if (index < 0 && !type.isAtomicValueType()) { // data is a transformed function // index == -1 for `this` parameter - return transformedExtension.dispatchReceiverParameter ?: error("Dispatch receiver of ${transformedExtension.render()} is null" + CONSTRAINTS_MESSAGE) + return transformedExtension.dispatchReceiverParameter + ?: error("During remapping of value parameters from the original atomic extension ${this.parent.render()} to the transformed one ${transformedExtension}:" + + "dispatchReceiver parameter (index == -1) was not found at the transformed extension." + CONSTRAINTS_MESSAGE) } if (index >= 0) { - val shift = if (transformedExtension.name.asString().isMangledAtomicArrayExtension()) 3 else 2 + val shift = 2 // 2 synthetic value parameters return transformedExtension.valueParameters[index + shift] } return null @@ -485,32 +228,7 @@ class AtomicfuJvmIrTransformer( parentFunction.valueParameters[0].capture() } else null } - else -> error("Unexpected type of atomic function call receiver: ${atomicCallReceiver.render()}" + CONSTRAINTS_MESSAGE) - } - - private fun getAtomicHandler(atomicCallReceiver: IrExpression, parentFunction: IrFunction?): IrExpression = - when { - atomicCallReceiver is IrCall -> { - val isArrayReceiver = atomicCallReceiver.isArrayElementGetter() - val getAtomicProperty = if (isArrayReceiver) atomicCallReceiver.dispatchReceiver as IrCall else atomicCallReceiver - val atomicProperty = getAtomicProperty.getCorrespondingProperty() - val atomicHandlerProperty = propertyToAtomicHandler[atomicProperty] - ?: error("No atomic handler found for the atomic property ${atomicProperty.render()}, \n" + - "these properties were registered: ${ - propertyToAtomicHandler.keys.toList().joinToString("\n") { it.render() } - }" + CONSTRAINTS_MESSAGE) - with(atomicSymbols.createBuilder(atomicCallReceiver.symbol)) { - // dispatchReceiver for get-a$FU() is null, because a$FU is a static property - // dispatchReceiver for get-arr'() is equal to the dispatchReceiver of the original getter - irGetProperty(atomicHandlerProperty, if (isArrayReceiver) getAtomicProperty.dispatchReceiver else null) - } - } - atomicCallReceiver.isThisReceiver() -> { - requireNotNull(parentFunction) { "Containing function of the atomic call with receiver should not be null" + CONSTRAINTS_MESSAGE} - require(parentFunction.isTransformedAtomicExtension()) - parentFunction.valueParameters[1].capture() - } - else -> error("Unexpected type of atomic function call receiver: ${atomicCallReceiver.render()} \n" + CONSTRAINTS_MESSAGE) + else -> error("Unexpected type of atomic function call receiver: ${atomicCallReceiver.render()}." + CONSTRAINTS_MESSAGE) } private fun IrCall.getDispatchReceiver(): IrExpression? { @@ -520,110 +238,48 @@ class AtomicfuJvmIrTransformer( val dispatchReceiver = getAtomicProperty.dispatchReceiver // top-level atomics if (!isArrayReceiver && (dispatchReceiver == null || dispatchReceiver.type.isObject())) { - val volatileProperty = atomicPropertyToVolatile[atomicProperty]!! + val volatileProperty = atomicfuPropertyToVolatile[atomicProperty]!! return getStaticVolatileWrapperInstance(volatileProperty.parentAsClass) } return dispatchReceiver } - private fun IrExpression.getArrayElementIndex(parentFunction: IrFunction?): IrExpression = - when { - this is IrCall -> getValueArgument(0)!! - this.isThisReceiver() -> { - require(parentFunction != null) - parentFunction.valueParameters[2].capture() - } - else -> error("Unexpected type of atomic receiver expression: ${this.render()} \n" + CONSTRAINTS_MESSAGE) - } - - private fun IrFunction.checkSyntheticArrayElementExtensionParameter(): Boolean { - if (valueParameters.size < 3) return false - return valueParameters[0].name.asString() == DISPATCH_RECEIVER && valueParameters[0].type == irBuiltIns.anyNType && - valueParameters[1].name.asString() == ATOMIC_HANDLER && atomicSymbols.isAtomicArrayHandlerType(valueParameters[1].type) && - valueParameters[2].name.asString() == INDEX && valueParameters[2].type == irBuiltIns.intType + override fun IrFunction.checkSyntheticArrayElementExtensionParameter(): Boolean { + if (valueParameters.size < 2) return false + return valueParameters[0].name.asString() == ATOMIC_HANDLER && atomicSymbols.isAtomicArrayHandlerType(valueParameters[0].type) && + valueParameters[1].name.asString() == INDEX && valueParameters[1].type == irBuiltIns.intType } - private fun IrFunction.checkSyntheticAtomicExtensionParameters(): Boolean { + override fun IrFunction.checkSyntheticAtomicExtensionParameters(): Boolean { if (valueParameters.size < 2) return false return valueParameters[0].name.asString() == DISPATCH_RECEIVER && valueParameters[0].type == irBuiltIns.anyNType && valueParameters[1].name.asString() == ATOMIC_HANDLER && atomicSymbols.isAtomicFieldUpdaterType(valueParameters[1].type) } - private fun IrDeclarationContainer.getOrBuildInlineLoopFunction( - functionName: String, - valueType: IrType, - isArrayReceiver: Boolean - ): IrSimpleFunction { - val parent = this - val mangledName = mangleAtomicExtensionName(functionName, isArrayReceiver) - val updaterType = - if (isArrayReceiver) atomicSymbols.getAtomicArrayType(valueType) else atomicSymbols.getFieldUpdaterType(valueType) - findDeclaration { - it.name.asString() == mangledName && it.valueParameters[0].type == updaterType - }?.let { return it } - return pluginContext.irFactory.buildFun { - name = Name.identifier(mangledName) - isInline = true - visibility = DescriptorVisibilities.PRIVATE - origin = AbstractAtomicSymbols.ATOMICFU_GENERATED_FUNCTION - }.apply { - dispatchReceiverParameter = (parent as? IrClass)?.thisReceiver?.deepCopyWithSymbols(this) - if (functionName == LOOP) { - if (isArrayReceiver) generateAtomicfuArrayLoop(valueType) else generateAtomicfuLoop(valueType) - } else { - if (isArrayReceiver) generateAtomicfuArrayUpdate(functionName, valueType) else generateAtomicfuUpdate(functionName, valueType) - } - this.parent = parent - parent.declarations.add(this) + override fun IrFunction.checkSyntheticParameterTypes(isArrayReceiver: Boolean, receiverValueType: IrType): Boolean { + if (isArrayReceiver) { + if (valueParameters.size < 2) return false + val atomicArrayType = atomicSymbols.getAtomicArrayClassByValueType(receiverValueType).defaultType + return valueParameters[0].name.asString() == ATOMIC_HANDLER && valueParameters[0].type == atomicArrayType && + valueParameters[1].name.asString() == INDEX && valueParameters[1].type == irBuiltIns.intType + } else { + if (valueParameters.size < 2) return false + val atomicUpdaterType = atomicSymbols.getFieldUpdaterType(receiverValueType) + return valueParameters[0].name.asString() == DISPATCH_RECEIVER && valueParameters[0].type == irBuiltIns.anyNType && + valueParameters[1].name.asString() == ATOMIC_HANDLER && valueParameters[1].type == atomicUpdaterType } } - - private fun IrSimpleFunction.generateAtomicfuLoop(valueType: IrType) { - addValueParameter(ATOMIC_HANDLER, atomicSymbols.getFieldUpdaterType(valueType)) - addValueParameter(ACTION, atomicSymbols.function1Type(valueType, irBuiltIns.unitType)) - addValueParameter(DISPATCH_RECEIVER, irBuiltIns.anyNType) - body = with(atomicSymbols.createBuilder(symbol)) { - atomicfuLoopBody(valueType, valueParameters) - } - returnType = irBuiltIns.unitType - } - - private fun IrSimpleFunction.generateAtomicfuArrayLoop(valueType: IrType) { - val atomicfuArrayClass = atomicSymbols.getAtomicArrayClassByValueType(valueType) - addValueParameter(ATOMIC_HANDLER, atomicfuArrayClass.defaultType) - addValueParameter(INDEX, irBuiltIns.intType) - addValueParameter(ACTION, atomicSymbols.function1Type(valueType, irBuiltIns.unitType)) - body = with(atomicSymbols.createBuilder(symbol)) { - atomicfuArrayLoopBody(atomicfuArrayClass, valueParameters) - } - returnType = irBuiltIns.unitType - } - - private fun IrSimpleFunction.generateAtomicfuUpdate(functionName: String, valueType: IrType) { - addValueParameter(ATOMIC_HANDLER, atomicSymbols.getFieldUpdaterType(valueType)) - addValueParameter(ACTION, atomicSymbols.function1Type(valueType, valueType)) - addValueParameter(DISPATCH_RECEIVER, irBuiltIns.anyNType) - body = with(atomicSymbols.createBuilder(symbol)) { - atomicfuUpdateBody(functionName, valueParameters, valueType) - } - returnType = if (functionName == UPDATE) irBuiltIns.unitType else valueType - } - - private fun IrSimpleFunction.generateAtomicfuArrayUpdate(functionName: String, valueType: IrType) { - val atomicfuArrayClass = atomicSymbols.getAtomicArrayClassByValueType(valueType) - addValueParameter(ATOMIC_HANDLER, atomicfuArrayClass.defaultType) - addValueParameter(INDEX, irBuiltIns.intType) - addValueParameter(ACTION, atomicSymbols.function1Type(valueType, valueType)) - body = with(atomicSymbols.createBuilder(symbol)) { - atomicfuArrayUpdateBody(functionName, atomicfuArrayClass, valueParameters) - } - returnType = if (functionName == UPDATE) irBuiltIns.unitType else valueType - } } - private fun buildTransformedAtomicExtensionDeclaration(atomicExtension: IrFunction, isArrayReceiver: Boolean): IrSimpleFunction { + /** + * Builds the signature of the transformed atomic extension: + * + * inline fun AtomicInt.foo(arg: Int) --> inline fun foo$atomicfu(dispatchReceiver: Any?, atomicHandler: AtomicIntegerFieldUpdater, arg': Int) + * inline fun foo$atomicfu$array(atomicArray: AtomicIntegerArray, index: Int, arg': Int) + */ + override fun buildTransformedAtomicExtensionSignature(atomicExtension: IrFunction, isArrayReceiver: Boolean): IrSimpleFunction { val mangledName = mangleAtomicExtensionName(atomicExtension.name.asString(), isArrayReceiver) - val valueType = atomicExtension.extensionReceiverParameter!!.type.atomicToPrimitiveType() + val valueType = (atomicExtension.extensionReceiverParameter!!.type as IrSimpleType).atomicToPrimitiveType() return pluginContext.irFactory.buildFun { name = Name.identifier(mangledName) isInline = true @@ -632,17 +288,24 @@ class AtomicfuJvmIrTransformer( }.apply { extensionReceiverParameter = null dispatchReceiverParameter = atomicExtension.dispatchReceiverParameter?.deepCopyWithSymbols(this) - if (isArrayReceiver) { - addValueParameter(DISPATCH_RECEIVER, irBuiltIns.anyNType) - addValueParameter(ATOMIC_HANDLER, atomicSymbols.getAtomicArrayClassByValueType(valueType).defaultType) - addValueParameter(INDEX, irBuiltIns.intType) - } else { - addValueParameter(DISPATCH_RECEIVER, irBuiltIns.anyNType) - addValueParameter(ATOMIC_HANDLER, atomicSymbols.getFieldUpdaterType(valueType)) - } + atomicExtension.typeParameters.forEach { addTypeParameter(it.name.asString(), it.representativeUpperBound) } + addSyntheticValueParametersToTransformedAtomicExtension(isArrayReceiver, valueType) atomicExtension.valueParameters.forEach { addValueParameter(it.name, it.type) } returnType = atomicExtension.returnType this.parent = atomicExtension.parent } } + + /** + * Adds synthetic value parameters to the transformed atomic extension (custom atomic extension or atomicfu inline update functions). + */ + override fun IrFunction.addSyntheticValueParametersToTransformedAtomicExtension(isArrayReceiver: Boolean, valueType: IrType) { + if (isArrayReceiver) { + addValueParameter(ATOMIC_HANDLER, atomicSymbols.getAtomicArrayClassByValueType(valueType).defaultType) + addValueParameter(INDEX, irBuiltIns.intType) + } else { + addValueParameter(DISPATCH_RECEIVER, irBuiltIns.anyNType) + addValueParameter(ATOMIC_HANDLER, atomicSymbols.getFieldUpdaterType(valueType)) + } + } } diff --git a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/jvm/JvmAtomicSymbols.kt b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/jvm/JvmAtomicSymbols.kt index 7a92cf2ccda..b6724ba776a 100644 --- a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/jvm/JvmAtomicSymbols.kt +++ b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/jvm/JvmAtomicSymbols.kt @@ -28,7 +28,7 @@ class JvmAtomicSymbols( private val kotlinJvm: IrPackageFragment = createPackage("kotlin.jvm") private val javaLangClass: IrClassSymbol = createClass(javaLang, "Class", ClassKind.CLASS, Modality.FINAL) - // AtomicIntegerFieldUpdater + // java.util.concurrent.AtomicIntegerFieldUpdater val atomicIntFieldUpdaterClass: IrClassSymbol = createClass(javaUtilConcurrent, "AtomicIntegerFieldUpdater", ClassKind.CLASS, Modality.FINAL) @@ -104,7 +104,7 @@ class JvmAtomicSymbols( addValueParameter("newValue", irBuiltIns.intType) }.symbol - // AtomicLongFieldUpdater + // java.util.concurrent.AtomicLongFieldUpdater val atomicLongFieldUpdaterClass: IrClassSymbol = createClass(javaUtilConcurrent, "AtomicLongFieldUpdater", ClassKind.CLASS, Modality.FINAL) @@ -180,7 +180,7 @@ class JvmAtomicSymbols( addValueParameter("newValue", irBuiltIns.longType) }.symbol - // AtomicReferenceFieldUpdater + // java.util.concurrent.AtomicReferenceFieldUpdater val atomicRefFieldUpdaterClass: IrClassSymbol = createClass(javaUtilConcurrent, "AtomicReferenceFieldUpdater", ClassKind.CLASS, Modality.FINAL) @@ -232,170 +232,170 @@ class JvmAtomicSymbols( returnType = valueType.defaultType }.symbol - // AtomicIntegerArray - val atomicIntArrayClass: IrClassSymbol = + // java.util.concurrent.AtomicIntegerArray + override val atomicIntArrayClassSymbol: IrClassSymbol = createClass(javaUtilConcurrent, "AtomicIntegerArray", ClassKind.CLASS, Modality.FINAL) - val atomicIntArrayConstructor: IrConstructorSymbol = atomicIntArrayClass.owner.addConstructor().apply { + val atomicIntArrayConstructor: IrConstructorSymbol = atomicIntArrayClassSymbol.owner.addConstructor().apply { addValueParameter("length", irBuiltIns.intType) }.symbol val atomicIntArrayGet: IrSimpleFunctionSymbol = - atomicIntArrayClass.owner.addFunction(name = "get", returnType = irBuiltIns.intType).apply { + atomicIntArrayClassSymbol.owner.addFunction(name = "get", returnType = irBuiltIns.intType).apply { addValueParameter("i", irBuiltIns.intType) }.symbol val atomicIntArraySet: IrSimpleFunctionSymbol = - atomicIntArrayClass.owner.addFunction(name = "set", returnType = irBuiltIns.unitType).apply { + atomicIntArrayClassSymbol.owner.addFunction(name = "set", returnType = irBuiltIns.unitType).apply { addValueParameter("i", irBuiltIns.intType) addValueParameter("newValue", irBuiltIns.intType) }.symbol val atomicIntArrayCompareAndSet: IrSimpleFunctionSymbol = - atomicIntArrayClass.owner.addFunction(name = "compareAndSet", returnType = irBuiltIns.booleanType).apply { + atomicIntArrayClassSymbol.owner.addFunction(name = "compareAndSet", returnType = irBuiltIns.booleanType).apply { addValueParameter("i", irBuiltIns.intType) addValueParameter("expect", irBuiltIns.intType) addValueParameter("update", irBuiltIns.intType) }.symbol val atomicIntArrayAddAndGet: IrSimpleFunctionSymbol = - atomicIntArrayClass.owner.addFunction(name = "addAndGet", returnType = irBuiltIns.intType).apply { + atomicIntArrayClassSymbol.owner.addFunction(name = "addAndGet", returnType = irBuiltIns.intType).apply { addValueParameter("i", irBuiltIns.intType) addValueParameter("delta", irBuiltIns.intType) }.symbol val atomicIntArrayGetAndAdd: IrSimpleFunctionSymbol = - atomicIntArrayClass.owner.addFunction(name = "getAndAdd", returnType = irBuiltIns.intType).apply { + atomicIntArrayClassSymbol.owner.addFunction(name = "getAndAdd", returnType = irBuiltIns.intType).apply { addValueParameter("i", irBuiltIns.intType) addValueParameter("delta", irBuiltIns.intType) }.symbol val atomicIntArrayIncrementAndGet: IrSimpleFunctionSymbol = - atomicIntArrayClass.owner.addFunction(name = "incrementAndGet", returnType = irBuiltIns.intType).apply { + atomicIntArrayClassSymbol.owner.addFunction(name = "incrementAndGet", returnType = irBuiltIns.intType).apply { addValueParameter("i", irBuiltIns.intType) }.symbol val atomicIntArrayGetAndIncrement: IrSimpleFunctionSymbol = - atomicIntArrayClass.owner.addFunction(name = "getAndIncrement", returnType = irBuiltIns.intType).apply { + atomicIntArrayClassSymbol.owner.addFunction(name = "getAndIncrement", returnType = irBuiltIns.intType).apply { addValueParameter("i", irBuiltIns.intType) }.symbol val atomicIntArrayDecrementAndGet: IrSimpleFunctionSymbol = - atomicIntArrayClass.owner.addFunction(name = "decrementAndGet", returnType = irBuiltIns.intType).apply { + atomicIntArrayClassSymbol.owner.addFunction(name = "decrementAndGet", returnType = irBuiltIns.intType).apply { addValueParameter("i", irBuiltIns.intType) }.symbol val atomicIntArrayGetAndDecrement: IrSimpleFunctionSymbol = - atomicIntArrayClass.owner.addFunction(name = "getAndDecrement", returnType = irBuiltIns.intType).apply { + atomicIntArrayClassSymbol.owner.addFunction(name = "getAndDecrement", returnType = irBuiltIns.intType).apply { addValueParameter("i", irBuiltIns.intType) }.symbol val atomicIntArrayLazySet: IrSimpleFunctionSymbol = - atomicIntArrayClass.owner.addFunction(name = "lazySet", returnType = irBuiltIns.unitType).apply { + atomicIntArrayClassSymbol.owner.addFunction(name = "lazySet", returnType = irBuiltIns.unitType).apply { addValueParameter("i", irBuiltIns.intType) addValueParameter("newValue", irBuiltIns.intType) }.symbol val atomicIntArrayGetAndSet: IrSimpleFunctionSymbol = - atomicIntArrayClass.owner.addFunction(name = "getAndSet", returnType = irBuiltIns.intType).apply { + atomicIntArrayClassSymbol.owner.addFunction(name = "getAndSet", returnType = irBuiltIns.intType).apply { addValueParameter("i", irBuiltIns.intType) addValueParameter("newValue", irBuiltIns.intType) }.symbol - // AtomicLongArray - val atomicLongArrayClass: IrClassSymbol = + // java.util.concurrent.AtomicLongArray + override val atomicLongArrayClassSymbol: IrClassSymbol = createClass(javaUtilConcurrent, "AtomicLongArray", ClassKind.CLASS, Modality.FINAL) - val atomicLongArrayConstructor: IrConstructorSymbol = atomicLongArrayClass.owner.addConstructor().apply { + val atomicLongArrayConstructor: IrConstructorSymbol = atomicLongArrayClassSymbol.owner.addConstructor().apply { addValueParameter("length", irBuiltIns.intType) }.symbol val atomicLongArrayGet: IrSimpleFunctionSymbol = - atomicLongArrayClass.owner.addFunction(name = "get", returnType = irBuiltIns.longType).apply { + atomicLongArrayClassSymbol.owner.addFunction(name = "get", returnType = irBuiltIns.longType).apply { addValueParameter("i", irBuiltIns.intType) }.symbol val atomicLongArraySet: IrSimpleFunctionSymbol = - atomicLongArrayClass.owner.addFunction(name = "set", returnType = irBuiltIns.unitType).apply { + atomicLongArrayClassSymbol.owner.addFunction(name = "set", returnType = irBuiltIns.unitType).apply { addValueParameter("i", irBuiltIns.intType) addValueParameter("newValue", irBuiltIns.longType) }.symbol val atomicLongArrayCompareAndSet: IrSimpleFunctionSymbol = - atomicLongArrayClass.owner.addFunction(name = "compareAndSet", returnType = irBuiltIns.booleanType).apply { + atomicLongArrayClassSymbol.owner.addFunction(name = "compareAndSet", returnType = irBuiltIns.booleanType).apply { addValueParameter("i", irBuiltIns.intType) addValueParameter("expect", irBuiltIns.longType) addValueParameter("update", irBuiltIns.longType) }.symbol val atomicLongArrayAddAndGet: IrSimpleFunctionSymbol = - atomicLongArrayClass.owner.addFunction(name = "addAndGet", returnType = irBuiltIns.longType).apply { + atomicLongArrayClassSymbol.owner.addFunction(name = "addAndGet", returnType = irBuiltIns.longType).apply { addValueParameter("i", irBuiltIns.intType) addValueParameter("delta", irBuiltIns.longType) }.symbol val atomicLongArrayGetAndAdd: IrSimpleFunctionSymbol = - atomicLongArrayClass.owner.addFunction(name = "getAndAdd", returnType = irBuiltIns.longType).apply { + atomicLongArrayClassSymbol.owner.addFunction(name = "getAndAdd", returnType = irBuiltIns.longType).apply { addValueParameter("i", irBuiltIns.intType) addValueParameter("delta", irBuiltIns.longType) }.symbol val atomicLongArrayIncrementAndGet: IrSimpleFunctionSymbol = - atomicLongArrayClass.owner.addFunction(name = "incrementAndGet", returnType = irBuiltIns.longType).apply { + atomicLongArrayClassSymbol.owner.addFunction(name = "incrementAndGet", returnType = irBuiltIns.longType).apply { addValueParameter("i", irBuiltIns.intType) }.symbol val atomicLongArrayGetAndIncrement: IrSimpleFunctionSymbol = - atomicLongArrayClass.owner.addFunction(name = "getAndIncrement", returnType = irBuiltIns.longType).apply { + atomicLongArrayClassSymbol.owner.addFunction(name = "getAndIncrement", returnType = irBuiltIns.longType).apply { addValueParameter("i", irBuiltIns.intType) }.symbol val atomicLongArrayDecrementAndGet: IrSimpleFunctionSymbol = - atomicLongArrayClass.owner.addFunction(name = "decrementAndGet", returnType = irBuiltIns.longType).apply { + atomicLongArrayClassSymbol.owner.addFunction(name = "decrementAndGet", returnType = irBuiltIns.longType).apply { addValueParameter("i", irBuiltIns.intType) }.symbol val atomicLongArrayGetAndDecrement: IrSimpleFunctionSymbol = - atomicLongArrayClass.owner.addFunction(name = "getAndDecrement", returnType = irBuiltIns.longType).apply { + atomicLongArrayClassSymbol.owner.addFunction(name = "getAndDecrement", returnType = irBuiltIns.longType).apply { addValueParameter("i", irBuiltIns.intType) }.symbol val atomicLongArrayLazySet: IrSimpleFunctionSymbol = - atomicLongArrayClass.owner.addFunction(name = "lazySet", returnType = irBuiltIns.unitType).apply { + atomicLongArrayClassSymbol.owner.addFunction(name = "lazySet", returnType = irBuiltIns.unitType).apply { addValueParameter("i", irBuiltIns.intType) addValueParameter("newValue", irBuiltIns.longType) }.symbol val atomicLongArrayGetAndSet: IrSimpleFunctionSymbol = - atomicLongArrayClass.owner.addFunction(name = "getAndSet", returnType = irBuiltIns.longType).apply { + atomicLongArrayClassSymbol.owner.addFunction(name = "getAndSet", returnType = irBuiltIns.longType).apply { addValueParameter("i", irBuiltIns.intType) addValueParameter("newValue", irBuiltIns.longType) }.symbol - // AtomicReferenceArray - val atomicRefArrayClass: IrClassSymbol = + // java.util.concurrent.AtomicReferenceArray + override val atomicRefArrayClassSymbol: IrClassSymbol = createClass(javaUtilConcurrent, "AtomicReferenceArray", ClassKind.CLASS, Modality.FINAL) - val atomicRefArrayConstructor: IrConstructorSymbol = atomicRefArrayClass.owner.addConstructor().apply { + val atomicRefArrayConstructor: IrConstructorSymbol = atomicRefArrayClassSymbol.owner.addConstructor().apply { addValueParameter("length", irBuiltIns.intType) }.symbol val atomicRefArrayGet: IrSimpleFunctionSymbol = - atomicRefArrayClass.owner.addFunction(name = "get", returnType = irBuiltIns.anyNType).apply { + atomicRefArrayClassSymbol.owner.addFunction(name = "get", returnType = irBuiltIns.anyNType).apply { val valueType = addTypeParameter("T", irBuiltIns.anyNType) addValueParameter("i", irBuiltIns.intType) returnType = valueType.defaultType }.symbol val atomicRefArraySet: IrSimpleFunctionSymbol = - atomicRefArrayClass.owner.addFunction(name = "set", returnType = irBuiltIns.unitType).apply { + atomicRefArrayClassSymbol.owner.addFunction(name = "set", returnType = irBuiltIns.unitType).apply { val valueType = addTypeParameter("T", irBuiltIns.anyNType) addValueParameter("i", irBuiltIns.intType) addValueParameter("newValue", valueType.defaultType) }.symbol val atomicRefArrayCompareAndSet: IrSimpleFunctionSymbol = - atomicRefArrayClass.owner.addFunction(name = "compareAndSet", returnType = irBuiltIns.booleanType).apply { + atomicRefArrayClassSymbol.owner.addFunction(name = "compareAndSet", returnType = irBuiltIns.booleanType).apply { val valueType = addTypeParameter("T", irBuiltIns.anyNType) addValueParameter("i", irBuiltIns.intType) addValueParameter("expect", valueType.defaultType) @@ -403,39 +403,30 @@ class JvmAtomicSymbols( }.symbol val atomicRefArrayLazySet: IrSimpleFunctionSymbol = - atomicRefArrayClass.owner.addFunction(name = "lazySet", returnType = irBuiltIns.unitType).apply { + atomicRefArrayClassSymbol.owner.addFunction(name = "lazySet", returnType = irBuiltIns.unitType).apply { val valueType = addTypeParameter("T", irBuiltIns.anyNType) addValueParameter("i", irBuiltIns.intType) addValueParameter("newValue", valueType.defaultType) }.symbol val atomicRefArrayGetAndSet: IrSimpleFunctionSymbol = - atomicRefArrayClass.owner.addFunction(name = "getAndSet", returnType = irBuiltIns.anyNType).apply { + atomicRefArrayClassSymbol.owner.addFunction(name = "getAndSet", returnType = irBuiltIns.anyNType).apply { val valueType = addTypeParameter("T", irBuiltIns.anyNType) addValueParameter("i", irBuiltIns.intType) addValueParameter("newValue", valueType.defaultType) returnType = valueType.defaultType }.symbol - private val VALUE_TYPE_TO_ATOMIC_ARRAY_CLASS: Map = mapOf( - irBuiltIns.intType to atomicIntArrayClass, - irBuiltIns.booleanType to atomicIntArrayClass, - irBuiltIns.longType to atomicLongArrayClass, - irBuiltIns.anyNType to atomicRefArrayClass - ) - - private val ATOMIC_ARRAY_TYPES: Set = setOf( - atomicIntArrayClass, - atomicLongArrayClass, - atomicRefArrayClass - ) - private val ATOMIC_FIELD_UPDATER_TYPES: Set = setOf( atomicIntFieldUpdaterClass, atomicLongFieldUpdaterClass, atomicRefFieldUpdaterClass ) + // only one constructor is imported for java array types (see values atomicIntArrayConstructor, atomicRefArrayConstructor) + override fun getAtomicArrayConstructor(atomicArrayClassSymbol: IrClassSymbol): IrFunctionSymbol = + atomicArrayClassSymbol.constructors.firstOrNull() ?: error("No constructors found for ${atomicArrayClassSymbol.owner.render()}") + override fun createBuilder(symbol: IrSymbol, startOffset: Int, endOffset: Int) = JvmAtomicfuIrBuilder(this, symbol, startOffset, endOffset) @@ -449,38 +440,11 @@ class JvmAtomicSymbols( fun getFieldUpdaterType(valueType: IrType) = getJucaAFUClass(valueType).defaultType - fun getAtomicArrayClassByAtomicfuArrayType(atomicfuArrayType: IrType): IrClassSymbol = - when (atomicfuArrayType.classFqName?.shortName()?.asString()) { - "AtomicIntArray" -> atomicIntArrayClass - "AtomicLongArray" -> atomicLongArrayClass - "AtomicBooleanArray" -> atomicIntArrayClass - "AtomicArray" -> atomicRefArrayClass - else -> error("Unexpected atomicfu array type ${atomicfuArrayType.render()}") - } - - fun getAtomicArrayClassByValueType(valueType: IrType): IrClassSymbol = - VALUE_TYPE_TO_ATOMIC_ARRAY_CLASS[valueType] - ?: error("No corresponding atomic array class found for this value type ${valueType.render()} ") - - fun getAtomicArrayType(valueType: IrType) = getAtomicArrayClassByValueType(valueType).defaultType - - fun isAtomicArrayHandlerType(valueType: IrType) = valueType.classOrNull in ATOMIC_ARRAY_TYPES - fun isAtomicFieldUpdaterType(valueType: IrType) = valueType.classOrNull in ATOMIC_FIELD_UPDATER_TYPES fun getNewUpdater(atomicUpdaterClassSymbol: IrClassSymbol): IrSimpleFunctionSymbol = atomicUpdaterClassSymbol.getSimpleFunction("newUpdater") ?: error("No newUpdater function was found for ${atomicUpdaterClassSymbol.owner.render()} ") - fun getAtomicArrayConstructor(atomicArrayClassSymbol: IrClassSymbol): IrConstructorSymbol = - atomicArrayClassSymbol.constructors.firstOrNull() ?: error("No constructors declared for ${atomicArrayClassSymbol.owner.render()} ") - - fun getAtomicHandlerFunctionSymbol(atomicHandlerClass: IrClassSymbol, name: String): IrSimpleFunctionSymbol = - when (name) { - "", "getValue" -> atomicHandlerClass.getSimpleFunction("get") - "", "setValue" -> atomicHandlerClass.getSimpleFunction("set") - else -> atomicHandlerClass.getSimpleFunction(name) - } ?: error("No $name function found in $name") - val kotlinKClassJava: IrPropertySymbol = irFactory.buildProperty { name = Name.identifier("java") }.apply { diff --git a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/jvm/JvmAtomicfuIrBuilder.kt b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/jvm/JvmAtomicfuIrBuilder.kt index 9076d9858f3..a0f59a2f0bc 100644 --- a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/jvm/JvmAtomicfuIrBuilder.kt +++ b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/jvm/JvmAtomicfuIrBuilder.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlinx.atomicfu.compiler.backend.common.AbstractAtomicSymbols import org.jetbrains.kotlinx.atomicfu.compiler.backend.common.AbstractAtomicfuIrBuilder @@ -32,37 +33,6 @@ class JvmAtomicfuIrBuilder internal constructor( putValueArgument(0, obj) } - // atomicArr.get(index) - fun atomicGetArrayElement(atomicArrayClass: IrClassSymbol, receiver: IrExpression, index: IrExpression) = - irCall(atomicSymbols.getAtomicHandlerFunctionSymbol(atomicArrayClass, "get")).apply { - dispatchReceiver = receiver - putValueArgument(0, index) - } - - fun irJavaAtomicArrayField( - name: Name, - arrayClass: IrClassSymbol, - isStatic: Boolean, - annotations: List, - size: IrExpression, - dispatchReceiver: IrExpression?, - parentContainer: IrDeclarationContainer - ): IrField = - context.irFactory.buildField { - this.name = name - type = arrayClass.defaultType - this.isFinal = true - this.isStatic = isStatic - visibility = DescriptorVisibilities.PRIVATE - origin = AbstractAtomicSymbols.ATOMICFU_GENERATED_FIELD - }.apply { - this.initializer = IrExpressionBodyImpl( - newJavaAtomicArray(arrayClass, size, dispatchReceiver) - ) - this.annotations = annotations - this.parent = parentContainer - } - fun irJavaAtomicFieldUpdater(volatileField: IrField, parentClass: IrClass): IrField { // Generate an atomic field updater for the volatile backing field of the given property: // val a = atomic(0) @@ -83,23 +53,13 @@ class JvmAtomicfuIrBuilder internal constructor( } } - // atomicArr.compareAndSet(index, expect, update) - fun callAtomicArray( - arrayClassSymbol: IrClassSymbol, - functionName: String, - dispatchReceiver: IrExpression?, - index: IrExpression, - valueArguments: List, - isBooleanReceiver: Boolean - ): IrCall { - val irCall = irCall(atomicSymbols.getAtomicHandlerFunctionSymbol(arrayClassSymbol, functionName)).apply { - this.dispatchReceiver = dispatchReceiver - putValueArgument(0, index) // array element index - valueArguments.forEachIndexed { index, arg -> - putValueArgument(index + 1, arg) // function arguments - } - } - return if (isBooleanReceiver && irCall.type.isInt()) irCall.toBoolean() else irCall + override fun newAtomicArray( + atomicArrayClass: IrClassSymbol, + size: IrExpression, + dispatchReceiver: IrExpression? + ): IrFunctionAccessExpression = irCall(atomicSymbols.getAtomicArrayConstructor(atomicArrayClass)).apply { + putValueArgument(0, size) // size + this.dispatchReceiver = dispatchReceiver } // a$FU.compareAndSet(obj, expect, update) @@ -127,13 +87,6 @@ class JvmAtomicfuIrBuilder internal constructor( return if (isBooleanReceiver && irCall.type.isInt()) irCall.toBoolean() else irCall } - fun callAtomicExtension( - symbol: IrSimpleFunctionSymbol, - dispatchReceiver: IrExpression?, - syntheticValueArguments: List, - valueArguments: List - ) = irCallWithArgs(symbol, dispatchReceiver, null, syntheticValueArguments + valueArguments) - // val a$FU = j.u.c.a.AtomicIntegerFieldUpdater.newUpdater(A::class, "a") private fun newJavaAtomicFieldUpdater( fieldUpdaterClass: IrClassSymbol, @@ -150,35 +103,30 @@ class JvmAtomicfuIrBuilder internal constructor( } } - // val atomicArr = j.u.c.a.AtomicIntegerArray(size) - fun newJavaAtomicArray( - atomicArrayClass: IrClassSymbol, - size: IrExpression, - dispatchReceiver: IrExpression? - ) = irCall(atomicSymbols.getAtomicArrayConstructor(atomicArrayClass)).apply { - putValueArgument(0, size) // size - this.dispatchReceiver = dispatchReceiver - } - /* - inline fun atomicfu$loop(atomicfu$handler: AtomicIntegerFieldUpdater, atomicfu$action: (Int) -> Unit, dispatchReceiver: Any?) { + inline fun atomicfu$loop(dispatchReceiver: Any?, atomicfu$handler: AtomicIntegerFieldUpdater, atomicfu$action: (Int) -> Unit) { while (true) { val cur = atomicfu$handler.get() atomicfu$action(cur) } } */ - fun atomicfuLoopBody(valueType: IrType, valueParameters: List) = + // dispatchReceiver: IrValueParameter, atomicHandler: IrValueParameter, action: IrValueParameter + // todo this should also be abstracted out + override fun atomicfuLoopBody(valueType: IrType, valueParameters: List) = irBlockBody { + val dispatchReceiver = valueParameters[0] + val atomicHandler = valueParameters[1] + val action = valueParameters[2] +irWhile().apply { condition = irTrue() body = irBlock { val cur = createTmpVariable( - atomicGetValue(valueType, irGet(valueParameters[0]), irGet(valueParameters[2])), + atomicGetValue(valueType, irGet(atomicHandler), irGet(dispatchReceiver)), "atomicfu\$cur", false ) +irCall(atomicSymbols.invoke1Symbol).apply { - dispatchReceiver = irGet(valueParameters[1]) + this.dispatchReceiver = irGet(action) putValueArgument(0, irGet(cur)) } } @@ -193,17 +141,20 @@ class JvmAtomicfuIrBuilder internal constructor( } } */ - fun atomicfuArrayLoopBody(atomicArrayClass: IrClassSymbol, valueParameters: List) = + override fun atomicfuArrayLoopBody(atomicArrayClass: IrClassSymbol, valueParameters: List) = irBlockBody { + val atomicHandler = valueParameters[0] + val index = valueParameters[1] + val action = valueParameters[2] +irWhile().apply { condition = irTrue() body = irBlock { val cur = createTmpVariable( - atomicGetArrayElement(atomicArrayClass, irGet(valueParameters[0]), irGet(valueParameters[1])), + atomicGetArrayElement(atomicArrayClass, irGet(atomicHandler), irGet(index)), "atomicfu\$cur", false ) +irCall(atomicSymbols.invoke1Symbol).apply { - dispatchReceiver = irGet(valueParameters[2]) + dispatchReceiver = irGet(action) putValueArgument(0, irGet(cur)) } } @@ -239,29 +190,35 @@ class JvmAtomicfuIrBuilder internal constructor( } } */ - fun atomicfuUpdateBody(functionName: String, valueParameters: List, valueType: IrType) = + override fun atomicfuUpdateBody(functionName: String, valueType: IrType, valueParameters: List) = irBlockBody { + val dispatchReceiver = valueParameters[0] + val atomicHandler = valueParameters[1] + val action = valueParameters[2] +irWhile().apply { condition = irTrue() body = irBlock { val cur = createTmpVariable( - atomicGetValue(valueType, irGet(valueParameters[0]), irGet(valueParameters[2])), + atomicGetValue(valueType, irGet(atomicHandler), irGet(dispatchReceiver)), "atomicfu\$cur", false ) val upd = createTmpVariable( irCall(atomicSymbols.invoke1Symbol).apply { - dispatchReceiver = irGet(valueParameters[1]) + this.dispatchReceiver = irGet(action) putValueArgument(0, irGet(cur)) }, "atomicfu\$upd", false ) +irIfThen( type = atomicSymbols.irBuiltIns.unitType, - condition = irCall(atomicSymbols.getAtomicHandlerFunctionSymbol(atomicSymbols.getJucaAFUClass(valueType), "compareAndSet")).apply { - putValueArgument(0, irGet(valueParameters[2])) - putValueArgument(1, irGet(cur)) - putValueArgument(2, irGet(upd)) - dispatchReceiver = irGet(valueParameters[0]) - }, + condition = callFieldUpdater( + fieldUpdaterSymbol = atomicSymbols.getJucaAFUClass(valueType), + functionName = "compareAndSet", + getAtomicHandler = irGet(atomicHandler), + classInstanceContainingField = irGet(dispatchReceiver), + valueArguments = listOf(irGet(cur), irGet(upd)), + castType = null, + isBooleanReceiver = valueType.isBoolean() + ), thenPart = when (functionName) { "update" -> irReturnUnit() "getAndUpdate" -> irReturn(irGet(cur)) @@ -302,29 +259,36 @@ class JvmAtomicfuIrBuilder internal constructor( } } */ - fun atomicfuArrayUpdateBody(functionName: String, atomicArrayClass: IrClassSymbol, valueParameters: List) = + override fun atomicfuArrayUpdateBody(functionName: String, valueType: IrType, atomicArrayClass: IrClassSymbol, valueParameters: List) = irBlockBody { + val atomicHandler = valueParameters[0] + val index = valueParameters[1] + val action = valueParameters[2] +irWhile().apply { + val atomicArrayClassSymbol = (atomicHandler.type as IrSimpleType).classOrNull + ?: error("Failed to obtain the class corresponding to the array type ${atomicHandler.render()}.") condition = irTrue() body = irBlock { val cur = createTmpVariable( - atomicGetArrayElement(atomicArrayClass, irGet(valueParameters[0]), irGet(valueParameters[1])), + atomicGetArrayElement(atomicArrayClass, irGet(atomicHandler), irGet(index)), "atomicfu\$cur", false ) val upd = createTmpVariable( irCall(atomicSymbols.invoke1Symbol).apply { - dispatchReceiver = irGet(valueParameters[2]) + dispatchReceiver = irGet(action) putValueArgument(0, irGet(cur)) }, "atomicfu\$upd", false ) +irIfThen( type = atomicSymbols.irBuiltIns.unitType, - condition = irCall(atomicSymbols.getAtomicHandlerFunctionSymbol(atomicArrayClass, "compareAndSet")).apply { - putValueArgument(0, irGet(valueParameters[1])) // index - putValueArgument(1, irGet(cur)) - putValueArgument(2, irGet(upd)) - dispatchReceiver = irGet(valueParameters[0]) - }, + condition = callAtomicArray( + arrayClassSymbol = atomicArrayClassSymbol, + functionName = "compareAndSet", + dispatchReceiver = irGet(atomicHandler), + index = irGet(index), + valueArguments = listOf(irGet(cur), irGet(upd)), + isBooleanReceiver = valueType.isBoolean() + ), thenPart = when (functionName) { "update" -> irReturnUnit() "getAndUpdate" -> irReturn(irGet(cur)) diff --git a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ArrayInlineExtensionTest.txt b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ArrayInlineExtensionTest.txt index f581317b733..3a8e2492985 100644 --- a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ArrayInlineExtensionTest.txt +++ b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ArrayInlineExtensionTest.txt @@ -17,19 +17,19 @@ public final class ArrayInlineExtensionTest { private synthetic final field refArr: java.util.concurrent.atomic.AtomicReferenceArray static method (): void public method (): void - private synthetic final method bar$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerArray, p2: int, p3: int): int + private synthetic final method bar$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: int): int private synthetic final method bar$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: int): int private final method casLoop(p0: int): int private final method casLoopExpression(p0: long): long - private synthetic final method extensionLoop$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerArray, p2: int, p3: int): int + private synthetic final method extensionLoop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: int): int private synthetic final method extensionLoop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: int): int - private synthetic final method extensionLoopExpression$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerArray, p2: int, p3: int): int + private synthetic final method extensionLoopExpression$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: int): int private synthetic final method extensionLoopExpression$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: int): int - private synthetic final method extensionLoopMixedReceivers$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerArray, p2: int, p3: int, p4: int, p5: int): int + private synthetic final method extensionLoopMixedReceivers$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: int, p3: int, p4: int): int private synthetic final method extensionLoopMixedReceivers$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: int, p3: int, p4: int): int - private synthetic final method extensionLoopRecursive$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerArray, p2: int, p3: int): int + private synthetic final method extensionLoopRecursive$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: int): int private synthetic final method extensionLoopRecursive$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: int): int - private synthetic final method foo$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerArray, p2: int, p3: int): int + private synthetic final method foo$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: int): int private synthetic final method foo$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: int): int private synthetic final static method getA$volatile$FU(): java.util.concurrent.atomic.AtomicIntegerFieldUpdater private synthetic final method getA$volatile(): int @@ -38,7 +38,7 @@ public final class ArrayInlineExtensionTest { private synthetic final method getRefArr(): java.util.concurrent.atomic.AtomicReferenceArray private synthetic final method loop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: kotlin.jvm.functions.Function1): void private synthetic final method loop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicLongArray, p1: int, p2: kotlin.jvm.functions.Function1): void - private synthetic final method loop$atomicfu(p0: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void + private synthetic final method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: kotlin.jvm.functions.Function1): void private synthetic final method setA$volatile(p0: int): void public final method testIntExtensionLoops(): void public final inner class ArrayInlineExtensionTest$A diff --git a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ComplexLoopTest.txt b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ComplexLoopTest.txt index 0690a5ab88f..34e464f4333 100644 --- a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ComplexLoopTest.txt +++ b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ComplexLoopTest.txt @@ -20,9 +20,9 @@ public final class LoopTest { public method (): void private final method embeddedLoops(p0: int): int private final method embeddedUpdate(p0: int): int - private synthetic final method extensionEmbeddedLoops$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerArray, p2: int, p3: int): int + private synthetic final method extensionEmbeddedLoops$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: int): int private synthetic final method extensionEmbeddedLoops$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: int): int - private synthetic final method extesntionEmbeddedRefUpdate$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceArray, p2: int, p3: java.lang.String): java.lang.String + private synthetic final method extesntionEmbeddedRefUpdate$atomicfu$array(p0: java.util.concurrent.atomic.AtomicReferenceArray, p1: int, p2: java.lang.String): java.lang.String private synthetic final method extesntionEmbeddedRefUpdate$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: java.lang.String): java.lang.String private synthetic final static method getA$volatile$FU(): java.util.concurrent.atomic.AtomicIntegerFieldUpdater private synthetic final method getA$volatile(): int @@ -35,14 +35,14 @@ public final class LoopTest { private synthetic final method getR$volatile(): java.lang.Object private synthetic final method loop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: kotlin.jvm.functions.Function1): void private synthetic final method loop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicReferenceArray, p1: int, p2: kotlin.jvm.functions.Function1): void - private synthetic final method loop$atomicfu(p0: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void - private synthetic final method loop$atomicfu(p0: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void + private synthetic final method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: kotlin.jvm.functions.Function1): void + private synthetic final method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: kotlin.jvm.functions.Function1): void private synthetic final method setA$volatile(p0: int): void private synthetic final method setB$volatile(p0: int): void private synthetic final method setC$volatile(p0: int): void private synthetic final method setR$volatile(p0: java.lang.Object): void public final method test(): void private synthetic final method updateAndGet$atomicfu$array(p0: java.util.concurrent.atomic.AtomicReferenceArray, p1: int, p2: kotlin.jvm.functions.Function1): java.lang.Object - private synthetic final method updateAndGet$atomicfu(p0: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): int - private synthetic final method updateAndGet$atomicfu(p0: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): java.lang.Object + private synthetic final method updateAndGet$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: kotlin.jvm.functions.Function1): int + private synthetic final method updateAndGet$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: kotlin.jvm.functions.Function1): java.lang.Object } diff --git a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ExtensionLoopTest.txt b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ExtensionLoopTest.txt index fa31979f898..85e560c8095 100644 --- a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ExtensionLoopTest.txt +++ b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ExtensionLoopTest.txt @@ -20,9 +20,9 @@ public final class ExtensionLoopTestKt { public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String private synthetic final static method getExtensionLoopTest$VolatileWrapper$atomicfu$private(): ExtensionLoopTest$VolatileWrapper$atomicfu$private private synthetic final static method loop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicReferenceArray, p1: int, p2: kotlin.jvm.functions.Function1): void - private synthetic final static method loop$atomicfu(p0: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void + private synthetic final static method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: kotlin.jvm.functions.Function1): void public final static method testTopLevelExtensionLoop(): void - private synthetic final static method topLevelExtensionLoop$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceArray, p2: int, p3: java.lang.String): java.lang.String + private synthetic final static method topLevelExtensionLoop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicReferenceArray, p1: int, p2: java.lang.String): java.lang.String private synthetic final static method topLevelExtensionLoop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: java.lang.String): java.lang.String } @@ -52,19 +52,19 @@ public final class LoopTest { private synthetic volatile field rs$volatile: java.lang.Object static method (): void public method (): void - private synthetic final method bar$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerArray, p2: int, p3: int): int + private synthetic final method bar$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: int): int private synthetic final method bar$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: int): int private final method casLoop(p0: int): int private final method casLoopExpression(p0: int): int - private synthetic final method extensionLoop$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerArray, p2: int, p3: int): int + private synthetic final method extensionLoop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: int): int private synthetic final method extensionLoop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: int): int - private synthetic final method extensionLoopExpression$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerArray, p2: int, p3: int): int + private synthetic final method extensionLoopExpression$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: int): int private synthetic final method extensionLoopExpression$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: int): int - private synthetic final method extensionLoopMixedReceivers$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerArray, p2: int, p3: int, p4: int): int + private synthetic final method extensionLoopMixedReceivers$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: int, p3: int): int private synthetic final method extensionLoopMixedReceivers$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: int, p3: int): int - private synthetic final method extensionLoopRecursive$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerArray, p2: int, p3: int): int + private synthetic final method extensionLoopRecursive$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: int): int private synthetic final method extensionLoopRecursive$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: int): int - private synthetic final method foo$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerArray, p2: int, p3: int): int + private synthetic final method foo$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: int): int private synthetic final method foo$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: int): int private synthetic final static method getA$volatile$FU(): java.util.concurrent.atomic.AtomicIntegerFieldUpdater private synthetic final method getA$volatile(): int @@ -79,7 +79,7 @@ public final class LoopTest { private synthetic final static method getRs$volatile$FU(): java.util.concurrent.atomic.AtomicReferenceFieldUpdater private synthetic final method getRs$volatile(): java.lang.Object private synthetic final method loop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: kotlin.jvm.functions.Function1): void - private synthetic final method loop$atomicfu(p0: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void + private synthetic final method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: kotlin.jvm.functions.Function1): void private synthetic final method setA$volatile(p0: int): void private synthetic final method setA1$volatile(p0: int): void private synthetic final method setB$volatile(p0: int): void diff --git a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ExtensionsTest.txt b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ExtensionsTest.txt index d2648cd715a..e0584b5131c 100644 --- a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ExtensionsTest.txt +++ b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ExtensionsTest.txt @@ -11,7 +11,7 @@ public final class ExtensionsTest { private synthetic volatile field s$volatile: java.lang.Object static method (): void public method (): void - private synthetic final method booleanExtensionArithmetic$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerArray, p2: int): void + private synthetic final method booleanExtensionArithmetic$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int): void private synthetic final method booleanExtensionArithmetic$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater): void private synthetic final static method getA$volatile$FU(): java.util.concurrent.atomic.AtomicIntegerFieldUpdater private synthetic final method getA$volatile(): int @@ -21,11 +21,11 @@ public final class ExtensionsTest { private synthetic final method getL$volatile(): long private synthetic final static method getS$volatile$FU(): java.util.concurrent.atomic.AtomicReferenceFieldUpdater private synthetic final method getS$volatile(): java.lang.Object - private synthetic final method intExtensionArithmetic$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerArray, p2: int): void + private synthetic final method intExtensionArithmetic$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int): void private synthetic final method intExtensionArithmetic$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater): void - private synthetic final method longExtensionArithmetic$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicLongArray, p2: int): void + private synthetic final method longExtensionArithmetic$atomicfu$array(p0: java.util.concurrent.atomic.AtomicLongArray, p1: int): void private synthetic final method longExtensionArithmetic$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicLongFieldUpdater): void - private synthetic final method refExtension$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceArray, p2: int): void + private synthetic final method refExtension$atomicfu$array(p0: java.util.concurrent.atomic.AtomicReferenceArray, p1: int): void private synthetic final method refExtension$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater): void private synthetic final method setA$volatile(p0: int): void private synthetic final method setB$volatile(p0: int): void diff --git a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/InlineExtensionWithTypeParameterTest.txt b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/InlineExtensionWithTypeParameterTest.txt index 94a82de93a4..9a1703f4264 100644 --- a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/InlineExtensionWithTypeParameterTest.txt +++ b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/InlineExtensionWithTypeParameterTest.txt @@ -22,7 +22,7 @@ public final class InlineExtensionWithTypeParameterTest { private synthetic volatile field sref$volatile: java.lang.Object static method (): void public method (): void - private synthetic final method foo$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceArray, p2: int, p3: int, p4: InlineExtensionWithTypeParameterTest$Segment): int + private synthetic final method foo$atomicfu$array(p0: java.util.concurrent.atomic.AtomicReferenceArray, p1: int, p2: int, p3: InlineExtensionWithTypeParameterTest$Segment): int private synthetic final method foo$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: int, p3: InlineExtensionWithTypeParameterTest$Segment): int private final method getSegmentId(p0: InlineExtensionWithTypeParameterTest$Segment): int private synthetic final static method getSref$volatile$FU(): java.util.concurrent.atomic.AtomicReferenceFieldUpdater diff --git a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/LambdaTest.txt b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/LambdaTest.txt index b61e4dc0540..028290c0543 100644 --- a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/LambdaTest.txt +++ b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/LambdaTest.txt @@ -14,8 +14,8 @@ public final class LambdaTest { private synthetic final static method getRs$volatile$FU(): java.util.concurrent.atomic.AtomicReferenceFieldUpdater private synthetic final method getRs$volatile(): java.lang.Object private final method inlineLambda(p0: java.lang.Object, p1: kotlin.jvm.functions.Function1): void - private synthetic final method loop$atomicfu(p0: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void - private synthetic final method loop$atomicfu(p0: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void + private synthetic final method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: kotlin.jvm.functions.Function1): void + private synthetic final method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: kotlin.jvm.functions.Function1): void public final method loopInLambda1(p0: int): void public final method loopInLambda2(p0: int): void public final method loopInLambda2Ref(@org.jetbrains.annotations.NotNull p0: java.lang.String): void diff --git a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/LockFreeIntBitsTest.txt b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/LockFreeIntBitsTest.txt index 09965886ab4..75b1e189f70 100644 --- a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/LockFreeIntBitsTest.txt +++ b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/LockFreeIntBitsTest.txt @@ -13,7 +13,7 @@ public final class LockFreeIntBits { private synthetic final method getBits$volatile(): int private final method mask(p0: int): int private synthetic final method setBits$volatile(p0: int): void - private synthetic final method update$atomicfu(p0: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void + private synthetic final method update$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: kotlin.jvm.functions.Function1): void } @kotlin.Metadata diff --git a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/LockTest.txt b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/LockTest.txt index f8bbbe09d17..302aeeb9acc 100644 --- a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/LockTest.txt +++ b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/LockTest.txt @@ -16,6 +16,6 @@ public final class LockTestKt { // source: 'LockTest.kt' public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String public final static @org.jetbrains.annotations.NotNull method reflectionTest(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: java.util.Map): java.util.List - private synthetic final static method tryAcquire$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerArray, p2: int): boolean + private synthetic final static method tryAcquire$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int): boolean private synthetic final static method tryAcquire$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater): boolean } diff --git a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ParameterizedInlineFunExtensionTest.txt b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ParameterizedInlineFunExtensionTest.txt index 21a6583aa3e..d6d7646f4c9 100644 --- a/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ParameterizedInlineFunExtensionTest.txt +++ b/plugins/atomicfu/atomicfu-compiler/testData/box/atomic_extensions/ParameterizedInlineFunExtensionTest.txt @@ -5,9 +5,9 @@ public final class ParameterizedInlineFunExtensionTest { private synthetic volatile field tail$volatile: java.lang.Object static method (): void public method (): void - private synthetic final method bar$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceArray, p2: int, p3: java.lang.Object, p4: java.lang.Object): java.lang.Object + private synthetic final method bar$atomicfu$array(p0: java.util.concurrent.atomic.AtomicReferenceArray, p1: int, p2: java.lang.Object, p3: java.lang.Object): java.lang.Object private synthetic final method bar$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: java.lang.Object, p3: java.lang.Object): java.lang.Object - private synthetic final method foo$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceArray, p2: int, p3: java.lang.Object, p4: java.lang.Object, p5: kotlin.jvm.functions.Function1): java.lang.Object + private synthetic final method foo$atomicfu$array(p0: java.util.concurrent.atomic.AtomicReferenceArray, p1: int, p2: java.lang.Object, p3: java.lang.Object, p4: kotlin.jvm.functions.Function1): java.lang.Object private synthetic final method foo$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: java.lang.Object, p3: java.lang.Object, p4: kotlin.jvm.functions.Function1): java.lang.Object private synthetic final static method getTail$volatile$FU(): java.util.concurrent.atomic.AtomicReferenceFieldUpdater private synthetic final method getTail$volatile(): java.lang.Object diff --git a/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/LockFreeQueueTest.txt b/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/LockFreeQueueTest.txt index 3d2004f5de7..5558d10fdd3 100644 --- a/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/LockFreeQueueTest.txt +++ b/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/LockFreeQueueTest.txt @@ -29,7 +29,7 @@ public final class LockFreeQueue { private synthetic final method getHead$volatile(): java.lang.Object private synthetic final static method getTail$volatile$FU(): java.util.concurrent.atomic.AtomicReferenceFieldUpdater private synthetic final method getTail$volatile(): java.lang.Object - private synthetic final method loop$atomicfu(p0: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void + private synthetic final method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: kotlin.jvm.functions.Function1): void private synthetic final method setHead$volatile(p0: java.lang.Object): void private synthetic final method setTail$volatile(p0: java.lang.Object): void private final inner class LockFreeQueue$Node diff --git a/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/LockFreeStackTest.txt b/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/LockFreeStackTest.txt index bb8914f2b39..1468e146f5c 100644 --- a/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/LockFreeStackTest.txt +++ b/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/LockFreeStackTest.txt @@ -17,17 +17,17 @@ public final class LockFreeStack { static method (): void public method (): void public final method clear(): void - private synthetic final method getAndUpdate$atomicfu(p0: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): java.lang.Object + private synthetic final method getAndUpdate$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: kotlin.jvm.functions.Function1): java.lang.Object private synthetic final static method getTop$volatile$FU(): java.util.concurrent.atomic.AtomicReferenceFieldUpdater private synthetic final method getTop$volatile(): java.lang.Object public final method isEmpty(): boolean - private synthetic final method loop$atomicfu(p0: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void + private synthetic final method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: kotlin.jvm.functions.Function1): void public final @org.jetbrains.annotations.Nullable method popLoop(): java.lang.Object public final @org.jetbrains.annotations.Nullable method popUpdate(): java.lang.Object public final method pushLoop(p0: java.lang.Object): void public final method pushUpdate(p0: java.lang.Object): void private synthetic final method setTop$volatile(p0: java.lang.Object): void - private synthetic final method update$atomicfu(p0: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void + private synthetic final method update$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: kotlin.jvm.functions.Function1): void private final inner class LockFreeStack$Node } diff --git a/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/LoopTest.txt b/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/LoopTest.txt index 7e5a09a3f54..cac77d4614b 100644 --- a/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/LoopTest.txt +++ b/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/LoopTest.txt @@ -36,9 +36,9 @@ public final class LoopTest { private synthetic final method getA$volatile(): int private synthetic final static method getA1$volatile$FU(): java.util.concurrent.atomic.AtomicIntegerFieldUpdater private synthetic final method getA1$volatile(): int - private synthetic final method getAndUpdate$atomicfu(p0: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): int - private synthetic final method getAndUpdate$atomicfu(p0: java.util.concurrent.atomic.AtomicLongFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): long - private synthetic final method getAndUpdate$atomicfu(p0: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): java.lang.Object + private synthetic final method getAndUpdate$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: kotlin.jvm.functions.Function1): int + private synthetic final method getAndUpdate$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicLongFieldUpdater, p2: kotlin.jvm.functions.Function1): long + private synthetic final method getAndUpdate$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: kotlin.jvm.functions.Function1): java.lang.Object private synthetic final static method getB$volatile$FU(): java.util.concurrent.atomic.AtomicIntegerFieldUpdater private synthetic final method getB$volatile(): int private synthetic final static method getL$volatile$FU(): java.util.concurrent.atomic.AtomicLongFieldUpdater @@ -47,21 +47,21 @@ public final class LoopTest { private synthetic final method getR$volatile(): java.lang.Object private synthetic final static method getRs$volatile$FU(): java.util.concurrent.atomic.AtomicReferenceFieldUpdater private synthetic final method getRs$volatile(): java.lang.Object - private synthetic final method loop$atomicfu(p0: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void - private synthetic final method loop$atomicfu(p0: java.util.concurrent.atomic.AtomicLongFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void - private synthetic final method loop$atomicfu(p0: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void + private synthetic final method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: kotlin.jvm.functions.Function1): void + private synthetic final method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicLongFieldUpdater, p2: kotlin.jvm.functions.Function1): void + private synthetic final method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: kotlin.jvm.functions.Function1): void private synthetic final method setA$volatile(p0: int): void private synthetic final method setA1$volatile(p0: int): void private synthetic final method setB$volatile(p0: int): void private synthetic final method setL$volatile(p0: long): void private synthetic final method setR$volatile(p0: java.lang.Object): void private synthetic final method setRs$volatile(p0: java.lang.Object): void - private synthetic final method update$atomicfu(p0: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void - private synthetic final method update$atomicfu(p0: java.util.concurrent.atomic.AtomicLongFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void - private synthetic final method update$atomicfu(p0: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void - private synthetic final method updateAndGet$atomicfu(p0: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): int - private synthetic final method updateAndGet$atomicfu(p0: java.util.concurrent.atomic.AtomicLongFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): long - private synthetic final method updateAndGet$atomicfu(p0: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): java.lang.Object + private synthetic final method update$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: kotlin.jvm.functions.Function1): void + private synthetic final method update$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicLongFieldUpdater, p2: kotlin.jvm.functions.Function1): void + private synthetic final method update$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: kotlin.jvm.functions.Function1): void + private synthetic final method updateAndGet$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: kotlin.jvm.functions.Function1): int + private synthetic final method updateAndGet$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicLongFieldUpdater, p2: kotlin.jvm.functions.Function1): long + private synthetic final method updateAndGet$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: kotlin.jvm.functions.Function1): java.lang.Object public final inner class LoopTest$A } diff --git a/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/SimpleLockTest.txt b/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/SimpleLockTest.txt index be529ab8f1f..4fa28839187 100644 --- a/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/SimpleLockTest.txt +++ b/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/SimpleLockTest.txt @@ -7,7 +7,7 @@ public final class SimpleLock { public method (): void private synthetic final static method get_locked$volatile$FU(): java.util.concurrent.atomic.AtomicIntegerFieldUpdater private synthetic final method get_locked$volatile(): int - private synthetic final method loop$atomicfu(p0: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p1: kotlin.jvm.functions.Function1, p2: java.lang.Object): void + private synthetic final method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: kotlin.jvm.functions.Function1): void private synthetic final method set_locked$volatile(p0: int): void public final method withLock(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.Object } diff --git a/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/UncheckedCastTest.txt b/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/UncheckedCastTest.txt index 55d4b5499c6..7cb2d6b421f 100644 --- a/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/UncheckedCastTest.txt +++ b/plugins/atomicfu/atomicfu-compiler/testData/box/atomics_basic/UncheckedCastTest.txt @@ -42,7 +42,7 @@ public final class UncheckedCastTest { private synthetic final method getBs$volatile(): java.lang.Object private synthetic final static method getS$volatile$FU(): java.util.concurrent.atomic.AtomicReferenceFieldUpdater private synthetic final method getS$volatile(): java.lang.Object - private synthetic final method getString$atomicfu$array(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceArray, p2: int): java.lang.String + private synthetic final method getString$atomicfu$array(p0: java.util.concurrent.atomic.AtomicReferenceArray, p1: int): java.lang.String private synthetic final method getString$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater): java.lang.String private synthetic final method setBs$volatile(p0: java.lang.Object): void private synthetic final method setS$volatile(p0: java.lang.Object): void