ObjectLowering
This commit is contained in:
committed by
Anton Bannykh
parent
ce625075f6
commit
76ff30b86e
@@ -426,14 +426,14 @@ private val staticMembersLoweringPhase = makeJsModulePhase(
|
|||||||
description = "Move static member declarations to top-level"
|
description = "Move static member declarations to top-level"
|
||||||
)
|
)
|
||||||
|
|
||||||
private val objectDeclarationLoweringPhase = makeCustomJsModulePhase(
|
private val objectDeclarationLoweringPhase = makeJsModulePhase(
|
||||||
{ context, module -> ObjectDeclarationLowering(context, context.objectToGetInstanceFunction).lower(module) },
|
::ObjectDeclarationLowering,
|
||||||
name = "ObjectDeclarationLowering",
|
name = "ObjectDeclarationLowering",
|
||||||
description = "Create lazy object instance generator functions"
|
description = "Create lazy object instance generator functions"
|
||||||
)
|
)
|
||||||
|
|
||||||
private val objectUsageLoweringPhase = makeCustomJsModulePhase(
|
private val objectUsageLoweringPhase = makeJsModulePhase(
|
||||||
{ context, module -> ObjectUsageLowering(context, context.objectToGetInstanceFunction).lower(module) },
|
::ObjectUsageLowering,
|
||||||
name = "ObjectUsageLowering",
|
name = "ObjectUsageLowering",
|
||||||
description = "Transform IrGetObjectValue into instance generator call"
|
description = "Transform IrGetObjectValue into instance generator call"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,4 +15,6 @@ class JsMapping : DefaultMapping() {
|
|||||||
val originalInnerClassPrimaryConstructorByClass = newMapping<IrClass, IrConstructor>()
|
val originalInnerClassPrimaryConstructorByClass = newMapping<IrClass, IrConstructor>()
|
||||||
val secondaryConstructorToDelegate = newMapping<IrConstructor, IrSimpleFunction>()
|
val secondaryConstructorToDelegate = newMapping<IrConstructor, IrSimpleFunction>()
|
||||||
val secondaryConstructorToFactory = newMapping<IrConstructor, IrSimpleFunction>()
|
val secondaryConstructorToFactory = newMapping<IrConstructor, IrSimpleFunction>()
|
||||||
|
val objectToGetInstanceFunction = newMapping<IrClass, IrSimpleFunction>()
|
||||||
|
val objectToInstanceField = newMapping<IrClass, IrField>()
|
||||||
}
|
}
|
||||||
+54
-45
@@ -5,94 +5,103 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
import org.jetbrains.kotlin.backend.common.getOrPut
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||||
import org.jetbrains.kotlin.backend.common.lower.irIfThen
|
import org.jetbrains.kotlin.backend.common.lower.irIfThen
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrGetObjectValue
|
import org.jetbrains.kotlin.ir.expressions.IrGetObjectValue
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
|
||||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||||
import org.jetbrains.kotlin.ir.util.defaultType
|
import org.jetbrains.kotlin.ir.util.defaultType
|
||||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||||
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
||||||
import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
class ObjectDeclarationLowering(
|
class ObjectDeclarationLowering(
|
||||||
val context: CommonBackendContext,
|
val context: JsCommonBackendContext
|
||||||
val objectToGetInstanceFunction: MutableMap<IrClassSymbol, IrSimpleFunction>
|
) : DeclarationTransformer {
|
||||||
) : DeclarationContainerLoweringPass {
|
|
||||||
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
|
||||||
irDeclarationContainer.transformDeclarationsFlat { declaration ->
|
|
||||||
if (declaration !is IrClass || declaration.kind != ClassKind.OBJECT || declaration.isEffectivelyExternal())
|
|
||||||
return@transformDeclarationsFlat null
|
|
||||||
|
|
||||||
val getInstanceFun = getOrCreateGetInstanceFunction(objectToGetInstanceFunction, declaration)
|
private var IrClass.instanceField by context.mapping.objectToInstanceField
|
||||||
|
|
||||||
val instanceField = buildField {
|
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||||
name = Name.identifier(declaration.name.asString() + "_instance")
|
if (declaration !is IrClass || declaration.kind != ClassKind.OBJECT || declaration.isEffectivelyExternal())
|
||||||
type = declaration.defaultType.makeNullable()
|
return null
|
||||||
isStatic = true
|
|
||||||
}.apply {
|
|
||||||
parent = declaration.parent
|
|
||||||
initializer = null // Initialized with 'undefined'
|
|
||||||
}
|
|
||||||
val primaryConstructor = declaration.primaryConstructor!!
|
|
||||||
val body = primaryConstructor.body as IrBlockBody
|
|
||||||
|
|
||||||
// Initialize instance field in the beginning of the constructor because it can be used inside the constructor later
|
val getInstanceFun = context.getOrCreateGetInstanceFunction(declaration)
|
||||||
val initInstanceField = context.createIrBuilder(primaryConstructor.symbol).buildStatement(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
|
||||||
irSetField(null, instanceField, irGet(declaration.thisReceiver!!))
|
|
||||||
}
|
|
||||||
body.statements.add(0, initInstanceField)
|
|
||||||
|
|
||||||
getInstanceFun.body = context.createIrBuilder(getInstanceFun.symbol).irBlockBody(getInstanceFun) {
|
val instanceField = buildField {
|
||||||
|
name = Name.identifier(declaration.name.asString() + "_instance")
|
||||||
|
type = declaration.defaultType.makeNullable()
|
||||||
|
isStatic = true
|
||||||
|
}.apply {
|
||||||
|
parent = declaration.parent
|
||||||
|
initializer = null // Initialized with 'undefined'
|
||||||
|
}
|
||||||
|
|
||||||
|
declaration.instanceField = instanceField
|
||||||
|
|
||||||
|
val primaryConstructor = declaration.primaryConstructor!! // TODO find a way to trigger this correctly
|
||||||
|
|
||||||
|
getInstanceFun.body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||||
|
statements += context.createIrBuilder(getInstanceFun.symbol).irBlockBody(getInstanceFun) {
|
||||||
+irIfThen(
|
+irIfThen(
|
||||||
irEqualsNull(irGetField(null, instanceField)),
|
irEqualsNull(irGetField(null, instanceField)),
|
||||||
// Instance field initialized inside constructor
|
// Instance field initialized inside constructor
|
||||||
irCallConstructor(primaryConstructor.symbol, emptyList())
|
irCallConstructor(primaryConstructor.symbol, emptyList())
|
||||||
)
|
)
|
||||||
+irReturn(irGetField(null, instanceField))
|
+irReturn(irGetField(null, instanceField))
|
||||||
}
|
}.statements
|
||||||
|
|
||||||
listOf(declaration, instanceField, getInstanceFun)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return listOf(declaration, instanceField, getInstanceFun)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ObjectUsageLowering(
|
class ObjectUsageLowering(
|
||||||
val context: CommonBackendContext,
|
val context: JsCommonBackendContext
|
||||||
val objectToGetInstanceFunction: MutableMap<IrClassSymbol, IrSimpleFunction>
|
) : BodyLoweringPass {
|
||||||
) : FileLoweringPass {
|
|
||||||
override fun lower(irFile: IrFile) {
|
private var IrClass.instanceField by context.mapping.objectToInstanceField
|
||||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
|
||||||
|
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||||
|
if (container is IrConstructor && container.isPrimary) {
|
||||||
|
val irClass = container.parentAsClass
|
||||||
|
irClass.instanceField?.let { instanceField ->
|
||||||
|
// Initialize instance field in the beginning of the constructor because it can be used inside the constructor later
|
||||||
|
val initInstanceField = context.createIrBuilder(container.symbol).buildStatement(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||||
|
irSetField(null, instanceField, irGet(irClass.thisReceiver!!))
|
||||||
|
}
|
||||||
|
(irBody as IrBlockBody).statements.add(0, initInstanceField)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||||
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
|
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
|
||||||
val obj: IrClass = expression.symbol.owner
|
val obj: IrClass = expression.symbol.owner
|
||||||
if (obj.isEffectivelyExternal()) return expression
|
if (obj.isEffectivelyExternal()) return expression
|
||||||
return JsIrBuilder.buildCall(getOrCreateGetInstanceFunction(objectToGetInstanceFunction, obj).symbol)
|
return JsIrBuilder.buildCall(context.getOrCreateGetInstanceFunction(obj).symbol)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getOrCreateGetInstanceFunction(objectToGetInstanceFunction: MutableMap<IrClassSymbol, IrSimpleFunction>, obj: IrClass) =
|
fun JsCommonBackendContext.getOrCreateGetInstanceFunction(obj: IrClass) =
|
||||||
objectToGetInstanceFunction.getOrPut(obj.symbol) {
|
mapping.objectToGetInstanceFunction.getOrPut(obj) {
|
||||||
JsIrBuilder.buildFunction(
|
JsIrBuilder.buildFunction(
|
||||||
obj.name.asString() + "_getInstance",
|
obj.name.asString() + "_getInstance",
|
||||||
returnType = obj.defaultType,
|
returnType = obj.defaultType,
|
||||||
|
|||||||
+4
-4
@@ -332,14 +332,14 @@ private val builtInsLoweringPhase = makeWasmModulePhase(
|
|||||||
description = "Lower IR buildins"
|
description = "Lower IR buildins"
|
||||||
)
|
)
|
||||||
|
|
||||||
private val objectDeclarationLoweringPhase = makeCustomWasmModulePhase(
|
private val objectDeclarationLoweringPhase = makeWasmModulePhase(
|
||||||
{ context, module -> ObjectUsageLowering(context, context.objectToGetInstanceFunction).lower(module) },
|
::ObjectUsageLowering,
|
||||||
name = "ObjectDeclarationLowering",
|
name = "ObjectDeclarationLowering",
|
||||||
description = "Create lazy object instance generator functions"
|
description = "Create lazy object instance generator functions"
|
||||||
)
|
)
|
||||||
|
|
||||||
private val objectUsageLoweringPhase = makeCustomWasmModulePhase(
|
private val objectUsageLoweringPhase = makeWasmModulePhase(
|
||||||
{ context, module -> ObjectUsageLowering(context, context.objectToGetInstanceFunction).lower(module) },
|
::ObjectUsageLowering,
|
||||||
name = "ObjectUsageLowering",
|
name = "ObjectUsageLowering",
|
||||||
description = "Transform IrGetObjectValue into instance generator call"
|
description = "Transform IrGetObjectValue into instance generator call"
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user