IR KT-50039 don't initialize outer 'this' in delegating constructor

This commit is contained in:
Dmitry Petrov
2021-12-03 12:06:42 +03:00
committed by teamcity
parent 0f745032af
commit 7206c06d26
11 changed files with 82 additions and 2 deletions
@@ -68,8 +68,11 @@ class InnerClassesLowering(val context: BackendContext, private val innerClasses
if (blockBody !is IrBlockBody) throw AssertionError("Unexpected constructor body: ${irConstructor.body}")
loweredConstructor.body = context.irFactory.createBlockBody(blockBody.startOffset, blockBody.endOffset) {
context.createIrBuilder(irConstructor.symbol, irConstructor.startOffset, irConstructor.endOffset).apply {
statements.add(0, irSetField(irGet(irClass.thisReceiver!!), parentThisField, irGet(outerThisParameter)))
if (irConstructor.shouldInitializeOuterThis()) {
context.createIrBuilder(irConstructor.symbol, irConstructor.startOffset, irConstructor.endOffset).apply {
statements.add(0, irSetField(irGet(irClass.thisReceiver!!), parentThisField, irGet(outerThisParameter)))
}
}
statements.addAll(blockBody.statements)
@@ -90,6 +93,15 @@ class InnerClassesLowering(val context: BackendContext, private val innerClasses
return loweredConstructor
}
private fun IrConstructor.shouldInitializeOuterThis(): Boolean {
val irBlockBody = body as? IrBlockBody ?: return false
// Constructors are either delegating to a constructor of super class (and initializing an instance of this class),
// or delegating to a constructor of this class.
// Don't initialize outer 'this' in constructor delegating to this,
// otherwise final 'this$0' field will be initialized twice (in delegating constructor and in original constructor),
// which is legal, but causes a performance regression on JVM (KT-50039).
return irBlockBody.statements.any { it is IrInstanceInitializerCall }
}
}
private fun InnerClassesSupport.primaryConstructorParameterMap(originalConstructor: IrConstructor): Map<IrValueParameter, IrValueParameter> {