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.ir.*
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.buildValueParameter
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.IrFieldSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
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.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
@@ -165,6 +166,14 @@ class LocalDeclarationsLowering(
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(
val declaration: IrClass,
val inInlineFunctionScope: Boolean,
@@ -174,7 +183,7 @@ class LocalDeclarationsLowering(
// NOTE: This map is iterated over in `rewriteClassMembers` and we're relying on
// 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? {
// 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 }
}
val field = capturedValueToField[valueDeclaration]?.value ?: return null
val field = capturedValueToField[valueDeclaration] ?: return null
val receiver = declaration.thisReceiver!!
return IrGetFieldImpl(
startOffset, endOffset, field.symbol, field.type,
startOffset, endOffset, field.symbol, valueDeclaration.type,
receiver = IrGetValueImpl(startOffset, endOffset, receiver.type, receiver.symbol)
)
}
@@ -205,12 +213,12 @@ class LocalDeclarationsLowering(
private class LocalClassMemberContext(val member: IrDeclaration, val classContext: LocalClassContext) : LocalContext() {
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`.
val receiver = (if (member is IrFunction) member.dispatchReceiverParameter else classContext.declaration.thisReceiver)
?: error("No dispatch receiver parameter for ${member.render()}")
return IrGetFieldImpl(
startOffset, endOffset, field.symbol, field.type,
startOffset, endOffset, field.symbol, valueDeclaration.type,
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" }
val usedCaptureFields = localClassContext.capturedValueToField.values.mapNotNull { if (it.isInitialized()) it.value else null }
val usedCaptureFields = createFieldsForCapturedValues(localClassContext)
irClass.declarations += usedCaptureFields
context.mapping.capturedFields[irClass] =
@@ -515,9 +523,9 @@ class LocalDeclarationsLowering(
blockBody.statements.addAll(
0,
localClassContext.capturedValueToField.mapNotNull { (capturedValue, field) ->
if (!field.isInitialized()) return@mapNotNull null
val symbol = field.symbolIfUsed ?: return@mapNotNull null
IrSetFieldImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, field.value.symbol,
UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol,
IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irClass.thisReceiver!!.symbol),
constructorContext.irGet(UNDEFINED_OFFSET, UNDEFINED_OFFSET, capturedValue)!!,
context.irBuiltIns.unitType,
@@ -582,9 +590,10 @@ class LocalDeclarationsLowering(
}
localClasses.values.forEach {
val localClassVisibility = visibilityPolicy.forClass(it.declaration, it.inInlineFunctionScope)
it.declaration.visibility = localClassVisibility
createFieldsForCapturedValues(it)
it.declaration.visibility = visibilityPolicy.forClass(it.declaration, it.inInlineFunctionScope)
it.closure.capturedValues.associateTo(it.capturedValueToField) { capturedValue ->
capturedValue.owner to PotentiallyUnusedField()
}
}
localClassConstructors.values.forEach {
@@ -766,44 +775,26 @@ class LocalDeclarationsLowering(
context.mapping.capturedConstructors[oldDeclaration] = newDeclaration
}
private fun createFieldForCapturedValue(
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) {
private fun createFieldsForCapturedValues(localClassContext: LocalClassContext): List<IrField> {
val classDeclaration = localClassContext.declaration
val generatedNames = mutableSetOf<String>()
localClassContext.closure.capturedValues.forEach { capturedValue ->
val owner = capturedValue.owner
localClassContext.capturedValueToField[owner] = lazy(LazyThreadSafetyMode.NONE) {
createFieldForCapturedValue(
classDeclaration.startOffset,
classDeclaration.endOffset,
suggestNameForCapturedValue(owner, generatedNames),
visibilityPolicy.forCapturedField(capturedValue),
classDeclaration,
owner.type,
owner is IrValueParameter && owner.isCrossinline
)
return localClassContext.capturedValueToField.mapNotNull { (capturedValue, field) ->
val symbol = field.symbolIfUsed ?: return@mapNotNull null
val origin = if (capturedValue is IrValueParameter && capturedValue.isCrossinline)
DECLARATION_ORIGIN_FIELD_FOR_CROSSINLINE_CAPTURED_VALUE
else
DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE
context.irFactory.createField(
classDeclaration.startOffset,
classDeclaration.endOffset,
origin,
symbol,
suggestNameForCapturedValue(capturedValue, generatedNames),
capturedValue.type,
visibilityPolicy.forCapturedField(capturedValue.symbol),
isFinal = true, isExternal = false, isStatic = false,
).also {
it.parent = classDeclaration
}
}
}