[atomicfu-JVM]: Commonization of K/N and JVM (part 2)
The following transformations were commonized: * generation of the transformed atomic extension signature * building atomic array fields (arrays are now supported on both backends JVM and K/N) * transformation of function calls on atomic array elements * Generation and invocation of atomic extensions (the only difference is generation of synthetic value parameters) * Changed synthetic parameters passed to the generated atomic extensions See, KT-60528 Merge-request: KT-MR-11249 Merged-by: Maria Sokolova <maria.sokolova@jetbrains.com>
This commit is contained in:
+61
-16
@@ -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<IrClassSymbol>
|
||||
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) {
|
||||
"<get-value>", "getValue" -> atomicHandlerClass.getSimpleFunction("get")
|
||||
"<set-value>", "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<IrType>
|
||||
): 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<IrType>
|
||||
): IrSimpleType =
|
||||
IrSimpleTypeImpl(
|
||||
classifier = symbol,
|
||||
hasQuestionMark = false,
|
||||
arguments = typeParameters.map { makeTypeProjection(it, Variance.INVARIANT) },
|
||||
annotations = emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
+76
-2
@@ -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<IrExpression?>) =
|
||||
irCall(symbol).apply {
|
||||
this.dispatchReceiver = dispatchReceiver
|
||||
@@ -46,6 +56,13 @@ abstract class AbstractAtomicfuIrBuilder(
|
||||
}
|
||||
}
|
||||
|
||||
fun callAtomicExtension(
|
||||
symbol: IrSimpleFunctionSymbol,
|
||||
dispatchReceiver: IrExpression?,
|
||||
syntheticValueArguments: List<IrExpression?>,
|
||||
valueArguments: List<IrExpression?>
|
||||
) = 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<IrConstructorCall>,
|
||||
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<IrExpression?>,
|
||||
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<IrValueParameter>): IrBlockBody
|
||||
abstract fun atomicfuArrayLoopBody(atomicArrayClass: IrClassSymbol, valueParameters: List<IrValueParameter>): IrBlockBody
|
||||
abstract fun atomicfuUpdateBody(functionName: String, valueType: IrType, valueParameters: List<IrValueParameter>): IrBlockBody
|
||||
abstract fun atomicfuArrayUpdateBody(functionName: String, valueType: IrType, atomicArrayClass: IrClassSymbol, valueParameters: List<IrValueParameter>): IrBlockBody
|
||||
}
|
||||
|
||||
+467
-68
@@ -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<IrProperty, IrProperty>()
|
||||
protected val propertyToAtomicHandler = mutableMapOf<IrProperty, IrProperty>()
|
||||
// Maps atomicfu atomic property to the corresponding volatile property.
|
||||
protected val atomicfuPropertyToVolatile = mutableMapOf<IrProperty, IrProperty>()
|
||||
// Maps atomicfu property to the atomic handler (field updater/atomic array).
|
||||
protected val atomicfuPropertyToAtomicHandler = mutableMapOf<IrProperty, IrProperty>()
|
||||
|
||||
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<IrSetField>? =
|
||||
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<IrSetField>
|
||||
}
|
||||
|
||||
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<Int>, 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<IrFunction?> {
|
||||
@@ -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)
|
||||
* <get-intArr>()[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 <this> 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 <T> 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<Int>, 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 <this> 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<IrSimpleFunction> {
|
||||
// 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<IrSimpleFunction> {
|
||||
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<IrExpression?>
|
||||
|
||||
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<IrFunction?> {
|
||||
@@ -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<IrDeclarationContainer>().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<IrFunction>().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
|
||||
|
||||
+58
-395
@@ -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<IrClass> { 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)
|
||||
* <get-intArr>()[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 <this> 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 <T> 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<IrExpression?> {
|
||||
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 <this> 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<IrSimpleFunction> {
|
||||
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 <this> 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<IrSimpleFunction> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+43
-79
@@ -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<IrType, IrClassSymbol> = mapOf(
|
||||
irBuiltIns.intType to atomicIntArrayClass,
|
||||
irBuiltIns.booleanType to atomicIntArrayClass,
|
||||
irBuiltIns.longType to atomicLongArrayClass,
|
||||
irBuiltIns.anyNType to atomicRefArrayClass
|
||||
)
|
||||
|
||||
private val ATOMIC_ARRAY_TYPES: Set<IrClassSymbol> = setOf(
|
||||
atomicIntArrayClass,
|
||||
atomicLongArrayClass,
|
||||
atomicRefArrayClass
|
||||
)
|
||||
|
||||
private val ATOMIC_FIELD_UPDATER_TYPES: Set<IrClassSymbol> = 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) {
|
||||
"<get-value>", "getValue" -> atomicHandlerClass.getSimpleFunction("get")
|
||||
"<set-value>", "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 {
|
||||
|
||||
+54
-90
@@ -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<IrConstructorCall>,
|
||||
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<IrExpression?>,
|
||||
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<IrExpression?>,
|
||||
valueArguments: List<IrExpression?>
|
||||
) = 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 <T> atomicfu$loop(atomicfu$handler: AtomicIntegerFieldUpdater, atomicfu$action: (Int) -> Unit, dispatchReceiver: Any?) {
|
||||
inline fun <T> 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<IrValueParameter>) =
|
||||
// dispatchReceiver: IrValueParameter, atomicHandler: IrValueParameter, action: IrValueParameter
|
||||
// todo this should also be abstracted out
|
||||
override fun atomicfuLoopBody(valueType: IrType, valueParameters: List<IrValueParameter>) =
|
||||
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<IrValueParameter>) =
|
||||
override fun atomicfuArrayLoopBody(atomicArrayClass: IrClassSymbol, valueParameters: List<IrValueParameter>) =
|
||||
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<IrValueParameter>, valueType: IrType) =
|
||||
override fun atomicfuUpdateBody(functionName: String, valueType: IrType, valueParameters: List<IrValueParameter>) =
|
||||
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<IrValueParameter>) =
|
||||
override fun atomicfuArrayUpdateBody(functionName: String, valueType: IrType, atomicArrayClass: IrClassSymbol, valueParameters: List<IrValueParameter>) =
|
||||
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))
|
||||
|
||||
Vendored
+7
-7
@@ -17,19 +17,19 @@ public final class ArrayInlineExtensionTest {
|
||||
private synthetic final field refArr: java.util.concurrent.atomic.AtomicReferenceArray
|
||||
static method <clinit>(): void
|
||||
public method <init>(): 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
|
||||
|
||||
+6
-6
@@ -20,9 +20,9 @@ public final class LoopTest {
|
||||
public method <init>(): 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
|
||||
}
|
||||
|
||||
+9
-9
@@ -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 <clinit>(): void
|
||||
public method <init>(): 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
|
||||
|
||||
+4
-4
@@ -11,7 +11,7 @@ public final class ExtensionsTest {
|
||||
private synthetic volatile field s$volatile: java.lang.Object
|
||||
static method <clinit>(): void
|
||||
public method <init>(): 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
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ public final class InlineExtensionWithTypeParameterTest {
|
||||
private synthetic volatile field sref$volatile: java.lang.Object
|
||||
static method <clinit>(): void
|
||||
public method <init>(): 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
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
+2
-2
@@ -5,9 +5,9 @@ public final class ParameterizedInlineFunExtensionTest {
|
||||
private synthetic volatile field tail$volatile: java.lang.Object
|
||||
static method <clinit>(): void
|
||||
public method <init>(): 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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+3
-3
@@ -17,17 +17,17 @@ public final class LockFreeStack {
|
||||
static method <clinit>(): void
|
||||
public method <init>(): 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
|
||||
}
|
||||
|
||||
|
||||
+12
-12
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ public final class SimpleLock {
|
||||
public method <init>(): 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
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user