IR: remove the use of lazy from LocalDeclarationsLowering

This commit is contained in:
pyos
2021-09-22 11:17:30 +02:00
committed by Alexander Udalov
parent 255e94e961
commit be53fc3467
@@ -17,14 +17,15 @@ import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.DescriptorVisibility import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.ir.* import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
import org.jetbrains.kotlin.ir.builders.declarations.buildField
import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.builders.declarations.buildFun
import org.jetbrains.kotlin.ir.builders.declarations.buildValueParameter import org.jetbrains.kotlin.ir.builders.declarations.buildValueParameter
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
@@ -165,6 +166,14 @@ class LocalDeclarationsLowering(
override lateinit var transformedDeclaration: IrConstructor override lateinit var transformedDeclaration: IrConstructor
} }
private class PotentiallyUnusedField {
var symbolIfUsed: IrFieldSymbol? = null
private set
val symbol: IrFieldSymbol
get() = symbolIfUsed ?: IrFieldSymbolImpl().also { symbolIfUsed = it }
}
private inner class LocalClassContext( private inner class LocalClassContext(
val declaration: IrClass, val declaration: IrClass,
val inInlineFunctionScope: Boolean, val inInlineFunctionScope: Boolean,
@@ -174,7 +183,7 @@ class LocalDeclarationsLowering(
// NOTE: This map is iterated over in `rewriteClassMembers` and we're relying on // NOTE: This map is iterated over in `rewriteClassMembers` and we're relying on
// the deterministic iteration order that `mutableMapOf` provides. // the deterministic iteration order that `mutableMapOf` provides.
val capturedValueToField: MutableMap<IrValueDeclaration, Lazy<IrField>> = mutableMapOf() val capturedValueToField: MutableMap<IrValueDeclaration, PotentiallyUnusedField> = mutableMapOf()
override fun irGet(startOffset: Int, endOffset: Int, valueDeclaration: IrValueDeclaration): IrExpression? { override fun irGet(startOffset: Int, endOffset: Int, valueDeclaration: IrValueDeclaration): IrExpression? {
// On the JVM backend, `AnonymousObjectTransformer` in the bytecode inliner uses field assignment // On the JVM backend, `AnonymousObjectTransformer` in the bytecode inliner uses field assignment
@@ -190,11 +199,10 @@ class LocalDeclarationsLowering(
constructorContext?.irGet(startOffset, endOffset, valueDeclaration)?.let { return it } constructorContext?.irGet(startOffset, endOffset, valueDeclaration)?.let { return it }
} }
val field = capturedValueToField[valueDeclaration]?.value ?: return null val field = capturedValueToField[valueDeclaration] ?: return null
val receiver = declaration.thisReceiver!! val receiver = declaration.thisReceiver!!
return IrGetFieldImpl( return IrGetFieldImpl(
startOffset, endOffset, field.symbol, field.type, startOffset, endOffset, field.symbol, valueDeclaration.type,
receiver = IrGetValueImpl(startOffset, endOffset, receiver.type, receiver.symbol) receiver = IrGetValueImpl(startOffset, endOffset, receiver.type, receiver.symbol)
) )
} }
@@ -205,12 +213,12 @@ class LocalDeclarationsLowering(
private class LocalClassMemberContext(val member: IrDeclaration, val classContext: LocalClassContext) : LocalContext() { private class LocalClassMemberContext(val member: IrDeclaration, val classContext: LocalClassContext) : LocalContext() {
override fun irGet(startOffset: Int, endOffset: Int, valueDeclaration: IrValueDeclaration): IrExpression? { override fun irGet(startOffset: Int, endOffset: Int, valueDeclaration: IrValueDeclaration): IrExpression? {
val field = classContext.capturedValueToField[valueDeclaration]?.value ?: return null val field = classContext.capturedValueToField[valueDeclaration] ?: return null
// This lowering does not process accesses to outer `this`. // This lowering does not process accesses to outer `this`.
val receiver = (if (member is IrFunction) member.dispatchReceiverParameter else classContext.declaration.thisReceiver) val receiver = (if (member is IrFunction) member.dispatchReceiverParameter else classContext.declaration.thisReceiver)
?: error("No dispatch receiver parameter for ${member.render()}") ?: error("No dispatch receiver parameter for ${member.render()}")
return IrGetFieldImpl( return IrGetFieldImpl(
startOffset, endOffset, field.symbol, field.type, startOffset, endOffset, field.symbol, valueDeclaration.type,
receiver = IrGetValueImpl(startOffset, endOffset, receiver.type, receiver.symbol) receiver = IrGetValueImpl(startOffset, endOffset, receiver.type, receiver.symbol)
) )
} }
@@ -500,7 +508,7 @@ class LocalDeclarationsLowering(
assert(constructorsCallingSuper.any()) { "Expected at least one constructor calling super; class: $irClass" } assert(constructorsCallingSuper.any()) { "Expected at least one constructor calling super; class: $irClass" }
val usedCaptureFields = localClassContext.capturedValueToField.values.mapNotNull { if (it.isInitialized()) it.value else null } val usedCaptureFields = createFieldsForCapturedValues(localClassContext)
irClass.declarations += usedCaptureFields irClass.declarations += usedCaptureFields
context.mapping.capturedFields[irClass] = context.mapping.capturedFields[irClass] =
@@ -515,9 +523,9 @@ class LocalDeclarationsLowering(
blockBody.statements.addAll( blockBody.statements.addAll(
0, 0,
localClassContext.capturedValueToField.mapNotNull { (capturedValue, field) -> localClassContext.capturedValueToField.mapNotNull { (capturedValue, field) ->
if (!field.isInitialized()) return@mapNotNull null val symbol = field.symbolIfUsed ?: return@mapNotNull null
IrSetFieldImpl( IrSetFieldImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, field.value.symbol, UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol,
IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irClass.thisReceiver!!.symbol), IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irClass.thisReceiver!!.symbol),
constructorContext.irGet(UNDEFINED_OFFSET, UNDEFINED_OFFSET, capturedValue)!!, constructorContext.irGet(UNDEFINED_OFFSET, UNDEFINED_OFFSET, capturedValue)!!,
context.irBuiltIns.unitType, context.irBuiltIns.unitType,
@@ -582,9 +590,10 @@ class LocalDeclarationsLowering(
} }
localClasses.values.forEach { localClasses.values.forEach {
val localClassVisibility = visibilityPolicy.forClass(it.declaration, it.inInlineFunctionScope) it.declaration.visibility = visibilityPolicy.forClass(it.declaration, it.inInlineFunctionScope)
it.declaration.visibility = localClassVisibility it.closure.capturedValues.associateTo(it.capturedValueToField) { capturedValue ->
createFieldsForCapturedValues(it) capturedValue.owner to PotentiallyUnusedField()
}
} }
localClassConstructors.values.forEach { localClassConstructors.values.forEach {
@@ -766,44 +775,26 @@ class LocalDeclarationsLowering(
context.mapping.capturedConstructors[oldDeclaration] = newDeclaration context.mapping.capturedConstructors[oldDeclaration] = newDeclaration
} }
private fun createFieldForCapturedValue( private fun createFieldsForCapturedValues(localClassContext: LocalClassContext): List<IrField> {
startOffset: Int,
endOffset: Int,
name: Name,
visibility: DescriptorVisibility,
parent: IrClass,
fieldType: IrType,
isCrossinline: Boolean
): IrField =
context.irFactory.buildField {
this.startOffset = startOffset
this.endOffset = endOffset
this.origin =
if (isCrossinline) DECLARATION_ORIGIN_FIELD_FOR_CROSSINLINE_CAPTURED_VALUE
else DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE
this.name = name
this.type = fieldType
this.visibility = visibility
this.isFinal = true
}.also {
it.parent = parent
}
private fun createFieldsForCapturedValues(localClassContext: LocalClassContext) {
val classDeclaration = localClassContext.declaration val classDeclaration = localClassContext.declaration
val generatedNames = mutableSetOf<String>() val generatedNames = mutableSetOf<String>()
localClassContext.closure.capturedValues.forEach { capturedValue -> return localClassContext.capturedValueToField.mapNotNull { (capturedValue, field) ->
val owner = capturedValue.owner val symbol = field.symbolIfUsed ?: return@mapNotNull null
localClassContext.capturedValueToField[owner] = lazy(LazyThreadSafetyMode.NONE) { val origin = if (capturedValue is IrValueParameter && capturedValue.isCrossinline)
createFieldForCapturedValue( DECLARATION_ORIGIN_FIELD_FOR_CROSSINLINE_CAPTURED_VALUE
classDeclaration.startOffset, else
classDeclaration.endOffset, DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE
suggestNameForCapturedValue(owner, generatedNames), context.irFactory.createField(
visibilityPolicy.forCapturedField(capturedValue), classDeclaration.startOffset,
classDeclaration, classDeclaration.endOffset,
owner.type, origin,
owner is IrValueParameter && owner.isCrossinline symbol,
) suggestNameForCapturedValue(capturedValue, generatedNames),
capturedValue.type,
visibilityPolicy.forCapturedField(capturedValue.symbol),
isFinal = true, isExternal = false, isStatic = false,
).also {
it.parent = classDeclaration
} }
} }
} }