[JS IR] Fix backend to make it possible lower partially loaded IR

This commit is contained in:
Roman Artemev
2021-09-28 18:21:49 +03:00
committed by TeamCityServer
parent 2ca74174d3
commit ebf17188cb
3 changed files with 169 additions and 149 deletions
@@ -79,58 +79,62 @@ class InlineClassLowering(val context: CommonBackendContext) {
var delegatingCtorCall: IrDelegatingConstructorCall? = null var delegatingCtorCall: IrDelegatingConstructorCall? = null
var setMemberField: IrSetField? = null var setMemberField: IrSetField? = null
initFunction.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) { initFunction.body = irConstructor.body?.let { body ->
val origParameterSymbol = irConstructor.valueParameters.single().symbol context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
statements += context.createIrBuilder(initFunction.symbol).irBlockBody(initFunction) { val origParameterSymbol = irConstructor.valueParameters.single().symbol
val builder = this statements += context.createIrBuilder(initFunction.symbol).irBlockBody(initFunction) {
fun unboxedInlineClassValue() = builder.irReinterpretCast( val builder = this
builder.irGet(initFunction.valueParameters.single()), fun unboxedInlineClassValue() = builder.irReinterpretCast(
type = klass.defaultType, builder.irGet(initFunction.valueParameters.single()),
) type = klass.defaultType,
)
(irConstructor.body as IrBlockBody).deepCopyWithSymbols(initFunction).statements.forEach { statement -> (body as IrBlockBody).deepCopyWithSymbols(initFunction).statements.forEach { statement ->
+statement.transformStatement(object : IrElementTransformerVoid() { +statement.transformStatement(object : IrElementTransformerVoid() {
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
delegatingCtorCall = expression.deepCopyWithSymbols(irConstructor) delegatingCtorCall = expression.deepCopyWithSymbols(irConstructor)
return builder.irBlock {} // Removing delegating constructor call return builder.irBlock {} // Removing delegating constructor call
}
override fun visitSetField(expression: IrSetField): IrExpression {
val isMemberFieldSet = expression.symbol.owner.parent == klass
if (isMemberFieldSet) {
setMemberField = expression.deepCopyWithSymbols(irConstructor)
} }
expression.transformChildrenVoid()
if (isMemberFieldSet) { override fun visitSetField(expression: IrSetField): IrExpression {
return expression.value val isMemberFieldSet = expression.symbol.owner.parent == klass
if (isMemberFieldSet) {
setMemberField = expression.deepCopyWithSymbols(irConstructor)
}
expression.transformChildrenVoid()
if (isMemberFieldSet) {
return expression.value
}
return expression
} }
return expression
}
override fun visitGetField(expression: IrGetField): IrExpression { override fun visitGetField(expression: IrGetField): IrExpression {
expression.transformChildrenVoid() expression.transformChildrenVoid()
if (expression.symbol.owner.parent == klass) if (expression.symbol.owner.parent == klass)
return builder.irGet(initFunction.valueParameters.single()) return builder.irGet(initFunction.valueParameters.single())
return expression return expression
} }
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid() expression.transformChildrenVoid()
if (expression.symbol.owner.parent == klass) if (expression.symbol.owner.parent == klass)
return unboxedInlineClassValue() return unboxedInlineClassValue()
if (expression.symbol == origParameterSymbol) if (expression.symbol == origParameterSymbol)
return builder.irGet(initFunction.valueParameters.single()) return builder.irGet(initFunction.valueParameters.single())
return expression return expression
} }
}) })
} }
+irReturn(unboxedInlineClassValue()) +irReturn(unboxedInlineClassValue())
}.statements }.statements
}
} }
irConstructor.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) { if (irConstructor.body != null) {
statements += delegatingCtorCall!! irConstructor.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
statements += setMemberField!! delegatingCtorCall?.let { statements += it }
setMemberField?.let { statements += it }
}
} }
return listOf(irConstructor, initFunction) return listOf(irConstructor, initFunction)
@@ -142,70 +146,72 @@ class InlineClassLowering(val context: CommonBackendContext) {
val irClass = irConstructor.parentAsClass val irClass = irConstructor.parentAsClass
// Copied and adapted from Kotlin/Native InlineClassTransformer // Copied and adapted from Kotlin/Native InlineClassTransformer
staticMethod.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) { staticMethod.body = irConstructor.body?.let { constructorBody ->
statements += context.createIrBuilder(staticMethod.symbol).irBlockBody(staticMethod) { context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
statements += context.createIrBuilder(staticMethod.symbol).irBlockBody(staticMethod) {
// Secondary ctors of inline class must delegate to some other constructors. // Secondary ctors of inline class must delegate to some other constructors.
// Use these delegating call later to initialize this variable. // Use these delegating call later to initialize this variable.
lateinit var thisVar: IrVariable lateinit var thisVar: IrVariable
val parameterMapping = staticMethod.valueParameters.associateBy { val parameterMapping = staticMethod.valueParameters.associateBy {
irConstructor.valueParameters[it.index].symbol irConstructor.valueParameters[it.index].symbol
} }
(irConstructor.body as IrBlockBody).statements.forEach { statement -> (constructorBody as IrBlockBody).statements.forEach { statement ->
+statement.transformStatement(object : IrElementTransformerVoid() { +statement.transformStatement(object : IrElementTransformerVoid() {
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
expression.transformChildrenVoid() expression.transformChildrenVoid()
// Static function for delegating constructors return unboxed instance of inline class // Static function for delegating constructors return unboxed instance of inline class
expression.type = irClass.defaultType expression.type = irClass.defaultType
return irBlock(expression) { return irBlock(expression) {
thisVar = createTmpVariable( thisVar = createTmpVariable(
expression, expression,
irType = irClass.defaultType irType = irClass.defaultType
) )
thisVar.parent = staticMethod thisVar.parent = staticMethod
} }
}
override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid()
if (expression.symbol == irClass.thisReceiver?.symbol) {
return irGet(thisVar)
} }
parameterMapping[expression.symbol]?.let { return irGet(it) } override fun visitGetValue(expression: IrGetValue): IrExpression {
return expression expression.transformChildrenVoid()
} if (expression.symbol == irClass.thisReceiver?.symbol) {
return irGet(thisVar)
}
override fun visitSetValue(expression: IrSetValue): IrExpression { parameterMapping[expression.symbol]?.let { return irGet(it) }
expression.transformChildrenVoid() return expression
parameterMapping[expression.symbol]?.let { return irSet(it.symbol, expression.value) }
return expression
}
override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement {
declaration.transformChildrenVoid(this)
if (declaration.parent == irConstructor)
declaration.parent = staticMethod
return declaration
}
override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid()
if (expression.returnTargetSymbol == irConstructor.symbol) {
return irReturn(irBlock(expression.startOffset, expression.endOffset) {
+expression.value
+irGet(thisVar)
})
} }
return expression override fun visitSetValue(expression: IrSetValue): IrExpression {
} expression.transformChildrenVoid()
parameterMapping[expression.symbol]?.let { return irSet(it.symbol, expression.value) }
return expression
}
}) override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement {
} declaration.transformChildrenVoid(this)
+irReturn(irGet(thisVar)) if (declaration.parent == irConstructor)
}.statements declaration.parent = staticMethod
return declaration
}
override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid()
if (expression.returnTargetSymbol == irConstructor.symbol) {
return irReturn(irBlock(expression.startOffset, expression.endOffset) {
+expression.value
+irGet(thisVar)
})
}
return expression
}
})
}
+irReturn(irGet(thisVar))
}.statements
}
} }
} }
@@ -213,57 +219,57 @@ class InlineClassLowering(val context: CommonBackendContext) {
// TODO: Support fake-overridden methods without boxing // TODO: Support fake-overridden methods without boxing
if (function.isStaticMethodOfClass || !function.isReal) return // TODO error() if (function.isStaticMethodOfClass || !function.isReal) return // TODO error()
val functionBody = function.body
// Move function body to static method, transforming value parameters and nested declarations // Move function body to static method, transforming value parameters and nested declarations
staticMethod.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) { staticMethod.body = function.body?.let { functionBody ->
statements.addAll((functionBody as IrBlockBody).statements) context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
statements.addAll((functionBody as IrBlockBody).statements)
transformChildrenVoid(object : IrElementTransformerVoid() { transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement { override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement {
declaration.transformChildrenVoid(this) declaration.transformChildrenVoid(this)
if (declaration.parent == function) if (declaration.parent == function)
declaration.parent = staticMethod declaration.parent = staticMethod
return declaration return declaration
} }
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
val valueDeclaration = expression.symbol.owner as? IrValueParameter ?: return super.visitGetValue(expression) val valueDeclaration = expression.symbol.owner as? IrValueParameter ?: return super.visitGetValue(expression)
return context.createIrBuilder(staticMethod.symbol).irGet( return context.createIrBuilder(staticMethod.symbol).irGet(
when (valueDeclaration) { when (valueDeclaration) {
function.dispatchReceiverParameter, function.parentAsClass.thisReceiver -> function.dispatchReceiverParameter, function.parentAsClass.thisReceiver ->
staticMethod.valueParameters[0] staticMethod.valueParameters[0]
function.extensionReceiverParameter -> function.extensionReceiverParameter ->
staticMethod.valueParameters[1] staticMethod.valueParameters[1]
in function.valueParameters -> { in function.valueParameters -> {
val offset = if (function.extensionReceiverParameter != null) 2 else 1 val offset = if (function.extensionReceiverParameter != null) 2 else 1
staticMethod.valueParameters[valueDeclaration.index + offset] staticMethod.valueParameters[valueDeclaration.index + offset]
}
else -> return expression
} }
)
}
else -> return expression override fun visitSetValue(expression: IrSetValue): IrExpression {
} val valueDeclaration = expression.symbol.owner as? IrValueParameter ?: return super.visitSetValue(expression)
) expression.transformChildrenVoid()
} return context.createIrBuilder(staticMethod.symbol).irSet(
when (valueDeclaration) {
override fun visitSetValue(expression: IrSetValue): IrExpression { in function.valueParameters -> {
val valueDeclaration = expression.symbol.owner as? IrValueParameter ?: return super.visitSetValue(expression) val offset = if (function.extensionReceiverParameter != null) 2 else 1
expression.transformChildrenVoid() staticMethod.valueParameters[valueDeclaration.index + offset].symbol
return context.createIrBuilder(staticMethod.symbol).irSet( }
when (valueDeclaration) { else -> return expression
in function.valueParameters -> { },
val offset = if (function.extensionReceiverParameter != null) 2 else 1 expression.value
staticMethod.valueParameters[valueDeclaration.index + offset].symbol )
} }
else -> return expression })
}, }
expression.value
)
}
})
} }
} }
@@ -394,7 +394,9 @@ class EnumClassCreateInitializerLowering(val context: JsCommonBackendContext) :
irClass.enumEntries.forEach { entry -> irClass.enumEntries.forEach { entry ->
entry.correspondingField?.let { instanceField -> entry.correspondingField?.let { instanceField ->
+irSetField(null, instanceField, entry.initializerExpression!!.expression.deepCopyWithSymbols(it)) entry.initializerExpression?.let { initializer ->
+irSetField(null, instanceField, initializer.expression.deepCopyWithSymbols(it))
}
} }
} }
@@ -124,14 +124,26 @@ class SecondaryConstructorLowering(val context: JsIrBackendContext) : Declaratio
private fun generateInitBody(constructor: IrConstructor, irClass: IrClass, delegate: IrSimpleFunction) { private fun generateInitBody(constructor: IrConstructor, irClass: IrClass, delegate: IrSimpleFunction) {
val thisParam = delegate.valueParameters.last() val thisParam = delegate.valueParameters.last()
val oldThisReceiver = irClass.thisReceiver!! val oldThisReceiver = irClass.thisReceiver!!
val constructorBody = constructor.body!! val constructorBody = constructor.body
val oldValueParameters = constructor.valueParameters + oldThisReceiver val oldValueParameters = constructor.valueParameters + oldThisReceiver
// TODO: replace parameters as well // TODO: replace parameters as well
delegate.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) { if (constructorBody != null) {
statements += (constructorBody.deepCopyWithSymbols(delegate) as IrStatementContainer).statements delegate.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
statements += JsIrBuilder.buildReturn(delegate.symbol, JsIrBuilder.buildGetValue(thisParam.symbol), context.irBuiltIns.nothingType) statements += (constructorBody.deepCopyWithSymbols(delegate) as IrStatementContainer).statements
transformChildrenVoid(ThisUsageReplaceTransformer(constructor.symbol, delegate.symbol, oldValueParameters.zip(delegate.valueParameters).toMap())) statements += JsIrBuilder.buildReturn(
delegate.symbol,
JsIrBuilder.buildGetValue(thisParam.symbol),
context.irBuiltIns.nothingType
)
transformChildrenVoid(
ThisUsageReplaceTransformer(
constructor.symbol,
delegate.symbol,
oldValueParameters.zip(delegate.valueParameters).toMap()
)
)
}
} }
} }