[JS IR BE] Reorder phases in order to extract a common prefix

This commit is contained in:
Anton Bannykh
2019-02-20 20:19:05 +03:00
parent 017cd3a0f6
commit 9a56b0e6d6
13 changed files with 345 additions and 278 deletions
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.Name
@@ -42,25 +43,26 @@ class PropertiesLowering(
override fun visitClass(declaration: IrClass): IrStatement {
declaration.transformChildrenVoid(this)
declaration.transformDeclarationsFlat { lowerProperty(it, declaration.kind) }
declaration.declarations.removeAll { it is IrProperty }
return declaration
}
private fun lowerProperty(declaration: IrDeclaration, kind: ClassKind): List<IrDeclaration>? =
if (declaration is IrProperty)
ArrayList<IrDeclaration>(4).apply {
// JvmFields in a companion object refer to companion's owners and should not be generated within companion.
if (kind != ClassKind.ANNOTATION_CLASS && declaration.backingField?.parent == declaration.parent) {
addIfNotNull(declaration.backingField)
}
addIfNotNull(declaration.getter)
addIfNotNull(declaration.setter)
if (declaration.isEffectivelyExternal()) listOf(declaration) else {
ArrayList<IrDeclaration>(4).apply {
// JvmFields in a companion object refer to companion's owners and should not be generated within companion.
if (kind != ClassKind.ANNOTATION_CLASS && declaration.backingField?.parent == declaration.parent) {
addIfNotNull(declaration.backingField)
}
addIfNotNull(declaration.getter)
addIfNotNull(declaration.setter)
if (declaration.annotations.isNotEmpty() && originOfSyntheticMethodForAnnotations != null
&& computeSyntheticMethodName != null
) {
val methodName = computeSyntheticMethodName.invoke(declaration.name) // Workaround KT-4113
add(createSyntheticMethodForAnnotations(declaration, originOfSyntheticMethodForAnnotations, methodName))
if (declaration.annotations.isNotEmpty() && originOfSyntheticMethodForAnnotations != null
&& computeSyntheticMethodName != null
) {
val methodName = computeSyntheticMethodName.invoke(declaration.name) // Workaround KT-4113
add(createSyntheticMethodForAnnotations(declaration, originOfSyntheticMethodForAnnotations, methodName))
}
}
}
else
@@ -18,20 +18,24 @@ package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.name.Name
fun IrClassSymbol.getPropertyDeclaration(name: String) =
this.owner.declarations.filterIsInstance<IrProperty>()
.atMostOne { it.descriptor.name == Name.identifier(name) }
fun IrClassSymbol.getPropertyGetter(name: String): IrFunctionSymbol? =
this.getPropertyDeclaration(name)?.getter?.symbol
fun IrClassSymbol.getSimpleFunction(name: String): IrSimpleFunctionSymbol? =
owner.findDeclaration<IrSimpleFunction> { it.name.asString() == name }?.symbol
fun IrClassSymbol.getPropertySetter(name: String): IrFunctionSymbol? =
this.getPropertyDeclaration(name)?.setter?.symbol
fun IrClassSymbol.getPropertyGetter(name: String): IrSimpleFunctionSymbol? =
this.getPropertyDeclaration(name)?.getter?.symbol ?: this.getSimpleFunction("<get-$name>")
fun IrClassSymbol.getPropertySetter(name: String): IrSimpleFunctionSymbol? =
this.getPropertyDeclaration(name)?.setter?.symbol ?: this.getSimpleFunction("<set-$name>")
fun IrClassSymbol.getPropertyField(name: String): IrFieldSymbol? =
this.getPropertyDeclaration(name)?.backingField?.symbol
@@ -31,9 +31,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.impl.IrDynamicTypeImpl
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.getPropertyDeclaration
import org.jetbrains.kotlin.ir.util.kotlinPackageFqn
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
@@ -257,10 +255,14 @@ class JsIrBackendContext(
val throwNWBESymbol = ir.symbols.ThrowNoWhenBranchMatchedException
val throwUPAESymbol = ir.symbols.ThrowUninitializedPropertyAccessException
val coroutineImplLabelProperty by lazy { ir.symbols.coroutineImpl.getPropertyDeclaration("state")!! }
val coroutineImplResultSymbol by lazy { ir.symbols.coroutineImpl.getPropertyDeclaration("result")!! }
val coroutineImplExceptionProperty by lazy { ir.symbols.coroutineImpl.getPropertyDeclaration("exception")!! }
val coroutineImplExceptionStateProperty by lazy { ir.symbols.coroutineImpl.getPropertyDeclaration("exceptionState")!! }
val coroutineImplLabelPropertyGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("state")!!.owner }
val coroutineImplLabelPropertySetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("state")!!.owner }
val coroutineImplResultSymbolGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("result")!!.owner }
val coroutineImplResultSymbolSetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("result")!!.owner }
val coroutineImplExceptionPropertyGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("exception")!!.owner }
val coroutineImplExceptionPropertySetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("exception")!!.owner }
val coroutineImplExceptionStatePropertyGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("exceptionState")!!.owner }
val coroutineImplExceptionStatePropertySetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("exceptionState")!!.owner }
val primitiveClassProperties by lazy {
primitiveClassesObject.owner.declarations.filterIsInstance<IrProperty>()
@@ -81,18 +81,6 @@ private val expectDeclarationsRemovingPhase = makeJsModulePhase(
description = "Remove expect declaration from module fragment"
)
private val coroutineIntrinsicLoweringPhase = makeJsModulePhase(
::CoroutineIntrinsicLowering,
name = "CoroutineIntrinsicLowering",
description = "Replace common coroutine intrinsics with platform specific ones"
)
private val arrayInlineConstructorLoweringPhase = makeJsModulePhase(
::ArrayInlineConstructorLowering,
name = "ArrayInlineConstructorLowering",
description = "Replace array constructor with platform specific factory functions"
)
private val lateinitLoweringPhase = makeJsModulePhase(
::LateinitLowering,
name = "LateinitLowering",
@@ -107,7 +95,7 @@ private val functionInliningPhase = makeCustomJsModulePhase(
},
name = "FunctionInliningPhase",
description = "Perform function inlining",
prerequisite = setOf(lateinitLoweringPhase, arrayInlineConstructorLoweringPhase, coroutineIntrinsicLoweringPhase)
prerequisite = setOf(expectDeclarationsRemovingPhase)
)
private val removeInlineFunctionsWithReifiedTypeParametersLoweringPhase = makeJsModulePhase(
@@ -136,16 +124,24 @@ private val unitMaterializationLoweringPhase = makeJsModulePhase(
prerequisite = setOf(tailrecLoweringPhase)
)
private val enumClassConstructorLoweringPhase = makeJsModulePhase(
::EnumClassConstructorLowering,
name = "EnumClassConstructorLowering",
description = "Transform Enum Class into regular Class"
)
private val enumClassLoweringPhase = makeJsModulePhase(
::EnumClassLowering,
name = "EnumClassLowering",
description = "Transform Enum Class into regular Class"
description = "Transform Enum Class into regular Class",
prerequisite = setOf(enumClassConstructorLoweringPhase)
)
private val enumUsageLoweringPhase = makeJsModulePhase(
::EnumUsageLowering,
name = "EnumUsageLowering",
description = "Replace enum access with invocation of corresponding function"
description = "Replace enum access with invocation of corresponding function",
prerequisite = setOf(enumClassLoweringPhase)
)
private val sharedVariablesLoweringPhase = makeJsModulePhase(
@@ -171,7 +167,7 @@ private val localDeclarationsLoweringPhase = makeJsModulePhase(
::LocalDeclarationsLowering,
name = "LocalDeclarationsLowering",
description = "Move local declarations into nearest declaration container",
prerequisite = setOf(sharedVariablesLoweringPhase)
prerequisite = setOf(sharedVariablesLoweringPhase, localDelegatedPropertiesLoweringPhase)
)
private val innerClassesLoweringPhase = makeJsModulePhase(
@@ -190,7 +186,7 @@ private val suspendFunctionsLoweringPhase = makeJsModulePhase(
::SuspendFunctionsLowering,
name = "SuspendFunctionsLowering",
description = "Transform suspend functions into CoroutineImpl instance and build state machine",
prerequisite = setOf(unitMaterializationLoweringPhase, coroutineIntrinsicLoweringPhase)
prerequisite = setOf(unitMaterializationLoweringPhase)
)
private val privateMembersLoweringPhase = makeJsModulePhase(
@@ -253,7 +249,7 @@ private val initializersLoweringPhase = makeCustomJsModulePhase(
{ context, module -> InitializersLowering(context, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).lower(module) },
name = "InitializersLowering",
description = "Merge init block and field initializers into [primary] constructor",
prerequisite = setOf(enumClassLoweringPhase)
prerequisite = setOf(enumClassConstructorLoweringPhase)
)
private val multipleCatchesLoweringPhase = makeJsModulePhase(
@@ -344,24 +340,24 @@ private val callsLoweringPhase = makeJsModulePhase(
val jsPhases = namedIrModulePhase(
name = "IrModuleLowering",
description = "IR module lowering",
lower = moveBodilessDeclarationsToSeparatePlacePhase then
expectDeclarationsRemovingPhase then
coroutineIntrinsicLoweringPhase then
arrayInlineConstructorLoweringPhase then
lateinitLoweringPhase then
lower = expectDeclarationsRemovingPhase then
functionInliningPhase then
removeInlineFunctionsWithReifiedTypeParametersLoweringPhase then
throwableSuccessorsLoweringPhase then
lateinitLoweringPhase then
tailrecLoweringPhase then
unitMaterializationLoweringPhase then
enumClassLoweringPhase then
enumUsageLoweringPhase then
enumClassConstructorLoweringPhase then
sharedVariablesLoweringPhase then
returnableBlockLoweringPhase then
localDelegatedPropertiesLoweringPhase then
localDeclarationsLoweringPhase then
innerClassesLoweringPhase then
innerClassConstructorCallsLoweringPhase then
propertiesLoweringPhase then
initializersLoweringPhase then
// Common prefix ends
moveBodilessDeclarationsToSeparatePlacePhase then
enumClassLoweringPhase then
enumUsageLoweringPhase then
returnableBlockLoweringPhase then
unitMaterializationLoweringPhase then
suspendFunctionsLoweringPhase then
privateMembersLoweringPhase then
callableReferenceLoweringPhase then
@@ -369,9 +365,9 @@ val jsPhases = namedIrModulePhase(
defaultParameterInjectorPhase then
defaultParameterCleanerPhase then
jsDefaultCallbackGeneratorPhase then
removeInlineFunctionsWithReifiedTypeParametersLoweringPhase then
throwableSuccessorsLoweringPhase then
varargLoweringPhase then
propertiesLoweringPhase then
initializersLoweringPhase then
multipleCatchesLoweringPhase then
bridgesConstructionPhase then
typeOperatorLoweringPhase then
@@ -5,40 +5,25 @@
package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
// Replace array inline constructors with stdlib function invocations
// Should be performed before inliner
class ArrayInlineConstructorLowering(val context: JsIrBackendContext) : FileLoweringPass {
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(ArrayConstructorTransformer(context))
}
}
private class ArrayConstructorTransformer(
class ArrayConstructorTransformer(
val context: JsIrBackendContext
) : IrElementTransformerVoid() {
) {
// Inline constructor for CharArray is implemented in runtime
private val primitiveArrayInlineToSizeConstructorMap =
context.intrinsics.primitiveArrays.filter { it.value != PrimitiveType.CHAR }.keys.associate {
it.inlineConstructor to it.sizeConstructor
}
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
fun transformCall(expression: IrCall): IrCall {
if (expression.symbol == context.intrinsics.array.inlineConstructor) {
return irCall(expression, context.intrinsics.jsArray)
} else {
@@ -85,15 +85,11 @@ class EnumUsageLowering(val context: JsIrBackendContext) : FileLoweringPass {
class EnumClassLowering(val context: JsIrBackendContext) : DeclarationContainerLoweringPass {
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.transformDeclarationsFlat { declaration ->
if (declaration is IrClass && declaration.isEnumClass) {
if (declaration.descriptor.isExpect) {
emptyList()
} else {
EnumClassTransformer(context, declaration).transform()
}
} else {
listOf(declaration)
}
if (declaration is IrClass && declaration.isEnumClass &&
!declaration.descriptor.isExpect && !declaration.isEffectivelyExternal()
) {
EnumClassTransformer(context, declaration).transform()
} else null
}
}
}
@@ -104,12 +100,22 @@ private fun createEntryAccessorName(enumName: String, enumEntry: IrEnumEntry) =
private fun IrEnumEntry.getType(irClass: IrClass) = (correspondingClass ?: irClass).defaultType
class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: IrClass) {
class EnumClassConstructorLowering(val context: JsIrBackendContext) : DeclarationContainerLoweringPass {
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.transformDeclarationsFlat { declaration ->
if (declaration is IrClass && declaration.isEnumClass &&
!declaration.descriptor.isExpect && !declaration.isEffectivelyExternal()
) {
EnumClassConstructorTransformer(context, declaration).transform()
} else null
}
}
}
class EnumClassConstructorTransformer(val context: JsIrBackendContext, private val irClass: IrClass) {
private val builder = context.createIrBuilder(irClass.symbol)
private val enumEntries = irClass.declarations.filterIsInstance<IrEnumEntry>()
private val loweredEnumConstructors = HashMap<IrConstructorSymbol, IrConstructor>()
private val enumName = irClass.name.identifier
private val throwISESymbol = context.throwISEymbol
fun transform(): List<IrDeclaration> {
// Make sure InstanceInitializer exists
@@ -124,35 +130,16 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass:
// The first step creates a new `IrConstructor` with new `IrValueParameter`s so references to old `IrValueParameter`s must be replaced with new ones.
fixReferencesToConstructorParameters()
// Create instance variable for each enum entry initialized with `null`
val entryInstances = createEnumEntryInstanceVariables()
// Lower `IrEnumConstructorCall`s inside of enum entry class constructors to corresponding `IrDelegatingConstructorCall`s.
// Add `name` and `ordinal` parameters.
lowerEnumEntryClassConstructors(entryInstances)
lowerEnumEntryClassConstructors()
// Lower `IrEnumConstructorCall`s to corresponding `IrCall`s.
// Add `name` and `ordinal` constant parameters only for calls to the "enum class" constructors ("enum entry class" constructors
// already delegate these parameters)
lowerEnumEntryInitializerExpression()
// Create boolean flag that indicates if entry instances were initialized.
val entryInstancesInitializedVar = createEntryInstancesInitializedVar()
// Create function that initializes all enum entry instances using `IrEnumEntry.initializationExpression`.
// It should be called on the first `IrGetEnumValue`, consecutive calls to this function will do nothing.
val initEntryInstancesFun = createInitEntryInstancesFun(entryInstancesInitializedVar, entryInstances)
// Create entry instance getters. These are used to lower `IrGetEnumValue`.
val entryGetInstanceFuns = createGetEntryInstanceFuns(initEntryInstancesFun, entryInstances)
// Create body for `values` and `valueOf` functions
lowerSyntheticFunctions()
// Remove IrEnumEntry nodes from class declarations. Replace them with corresponding class declarations (if they have them).
replaceIrEntriesWithCorrespondingClasses()
return listOf(irClass) + entryInstances + listOf(entryInstancesInitializedVar, initEntryInstancesFun) + entryGetInstanceFuns
return listOf(irClass)
}
private fun insertInstanceInitializer() {
@@ -182,6 +169,82 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass:
})
}
private fun lowerEnumConstructorsSignature() {
irClass.declarations.transform { declaration ->
if (declaration is IrConstructor) {
transformEnumConstructor(declaration, irClass)
} else
declaration
}
}
private fun transformEnumConstructor(enumConstructor: IrConstructor, enumClass: IrClass): IrConstructor {
val loweredConstructorDescriptor = WrappedClassConstructorDescriptor()
val loweredConstructorSymbol = IrConstructorSymbolImpl(loweredConstructorDescriptor)
return IrConstructorImpl(
enumConstructor.startOffset,
enumConstructor.endOffset,
enumConstructor.origin,
loweredConstructorSymbol,
enumConstructor.name,
enumConstructor.visibility,
enumConstructor.returnType,
enumConstructor.isInline,
enumConstructor.isExternal,
enumConstructor.isPrimary
).apply {
loweredConstructorDescriptor.bind(this)
parent = enumClass
valueParameters += JsIrBuilder.buildValueParameter("name", 0, context.irBuiltIns.stringType).also { it.parent = this }
valueParameters += JsIrBuilder.buildValueParameter("ordinal", 1, context.irBuiltIns.intType).also { it.parent = this }
copyParameterDeclarationsFrom(enumConstructor)
body = enumConstructor.body
loweredEnumConstructors[enumConstructor.symbol] = this
this.acceptVoid(PatchDeclarationParentsVisitor(enumClass))
}
}
private fun lowerEnumConstructorsBody() {
irClass.declarations.filterIsInstance<IrConstructor>().forEach {
IrEnumClassConstructorTransformer(it).transformBody()
}
}
private inner class IrEnumClassConstructorTransformer(val constructor: IrConstructor) : IrElementTransformerVoid() {
val builder = context.createIrBuilder(constructor.symbol)
fun transformBody() {
constructor.body?.transformChildrenVoid(this)
}
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall) =
builder.irDelegatingConstructorCall(expression.symbol.owner).apply {
for (i in 0..1) {
putValueArgument(i, builder.irGet(constructor.valueParameters[i]))
}
}
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
var delegatingConstructor = expression.symbol.owner
val constructorWasTransformed = delegatingConstructor.symbol in loweredEnumConstructors
if (constructorWasTransformed)
delegatingConstructor = loweredEnumConstructors[delegatingConstructor.symbol]!!
return builder.irDelegatingConstructorCall(delegatingConstructor).apply {
var valueArgIdx = 0
for (i in 0..1) {
putValueArgument(valueArgIdx++, builder.irGet(constructor.valueParameters[i]))
}
for (i in 0 until expression.valueArgumentsCount) {
putValueArgument(valueArgIdx++, expression.getValueArgument(i))
}
}
}
}
private fun fixReferencesToConstructorParameters() {
val fromOldToNewParameter = mutableMapOf<IrValueParameterSymbol, IrValueParameter>()
@@ -205,6 +268,92 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass:
})
}
private fun lowerEnumEntryClassConstructors() {
for (entry in enumEntries) {
entry.correspondingClass?.constructors?.forEach {
it.transformChildrenVoid(IrEnumEntryClassConstructorTransformer(entry, true))
}
}
}
private inner class IrEnumEntryClassConstructorTransformer(val entry: IrEnumEntry, val isInsideConstructor: Boolean) :
IrElementTransformerVoid() {
private fun buildConstructorCall(constructor: IrConstructor) =
if (isInsideConstructor)
builder.irDelegatingConstructorCall(constructor)
else
builder.irCall(constructor)
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrExpression {
var constructor = expression.symbol.owner
val constructorWasTransformed = constructor.symbol in loweredEnumConstructors
// Enum entry class constructors are not transformed
if (constructorWasTransformed)
constructor = loweredEnumConstructors[constructor.symbol]!!
return buildConstructorCall(constructor).apply {
var valueArgIdx = 0
// Enum entry class constructors already delegate name and ordinal parameters in their body
if (constructorWasTransformed) {
putValueArgument(valueArgIdx++, entry.getNameExpression())
putValueArgument(valueArgIdx++, entry.getOrdinalExpression())
}
for (i in 0 until expression.valueArgumentsCount) {
putValueArgument(valueArgIdx++, expression.getValueArgument(i))
}
}
}
}
private fun lowerEnumEntryInitializerExpression() {
for (entry in enumEntries) {
entry.initializerExpression =
entry.initializerExpression?.transform(IrEnumEntryClassConstructorTransformer(entry, false), null)
}
}
private fun IrEnumEntry.getNameExpression() = builder.irString(this.name.identifier)
private fun IrEnumEntry.getOrdinalExpression() = builder.irInt(enumEntries.indexOf(this))
}
//-------------------------------------------------------
class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: IrClass) {
private val builder = context.createIrBuilder(irClass.symbol)
private val enumEntries = irClass.declarations.filterIsInstance<IrEnumEntry>()
private val enumName = irClass.name.identifier
private val throwISESymbol = context.throwISEymbol
fun transform(): List<IrDeclaration> {
// Create instance variable for each enum entry initialized with `null`
val entryInstances = createEnumEntryInstanceVariables()
// Create boolean flag that indicates if entry instances were initialized.
val entryInstancesInitializedVar = createEntryInstancesInitializedVar()
// Create function that initializes all enum entry instances using `IrEnumEntry.initializationExpression`.
// It should be called on the first `IrGetEnumValue`, consecutive calls to this function will do nothing.
val initEntryInstancesFun = createInitEntryInstancesFun(entryInstancesInitializedVar, entryInstances)
// Create entry instance getters. These are used to lower `IrGetEnumValue`.
val entryGetInstanceFuns = createGetEntryInstanceFuns(initEntryInstancesFun, entryInstances)
// Create body for `values` and `valueOf` functions
lowerSyntheticFunctions()
// Remove IrEnumEntry nodes from class declarations. Replace them with corresponding class declarations (if they have them).
replaceIrEntriesWithCorrespondingClasses()
return listOf(irClass) + entryInstances + listOf(entryInstancesInitializedVar, initEntryInstancesFun) + entryGetInstanceFuns
}
private fun createEnumValueOfBody(): IrBody {
val valueOfFun = findFunctionDescriptorForMemberWithSyntheticBodyKind(IrSyntheticBodyKind.ENUM_VALUEOF)
val nameParameter = valueOfFun.valueParameters[0]
@@ -249,25 +398,9 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass:
}
private fun lowerEnumConstructorsSignature() {
irClass.declarations.transform { declaration ->
if (declaration is IrConstructor) {
transformEnumConstructor(declaration, irClass)
} else
declaration
}
}
private fun lowerEnumConstructorsBody() {
irClass.declarations.filterIsInstance<IrConstructor>().forEach {
IrEnumClassConstructorTransformer(it).transformBody()
}
}
private fun lowerEnumEntryClassConstructors(entryInstances: List<IrVariable>) {
for ((entry, instance) in enumEntries.zip(entryInstances)) {
entry.correspondingClass?.constructors?.forEach {
it.transformChildrenVoid(IrEnumEntryClassConstructorTransformer(entry, true))
// Initialize entry instance at the beginning of constructor so it can be used inside constructor body
(it.body as? IrBlockBody)?.apply {
@@ -279,19 +412,23 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass:
}
}
private fun lowerEnumEntryInitializerExpression() {
for (entry in enumEntries) {
entry.initializerExpression =
entry.initializerExpression?.transform(IrEnumEntryClassConstructorTransformer(entry, false), null)
}
}
private fun createEnumEntryInstanceVariables() = enumEntries.map { enumEntry ->
val type = enumEntry.getType(irClass).makeNullable(false)
val name = "${enumName}_${enumEntry.name.identifier}_instance"
builder.run {
val result = builder.run {
scope.createTmpVariable(irImplicitCast(irNull(), type), name)
}
enumEntry.correspondingClass?.constructors?.forEach {
// Initialize entry instance at the beginning of constructor so it can be used inside constructor body
(it.body as? IrBlockBody)?.apply {
statements.add(0, context.createIrBuilder(it.symbol).run {
irSetVar(result.symbol, irGet(enumEntry.correspondingClass!!.thisReceiver!!))
})
}
}
result
}
private fun replaceIrEntriesWithCorrespondingClasses() {
@@ -346,98 +483,6 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass:
)
}
private inner class IrEnumClassConstructorTransformer(val constructor: IrConstructor) : IrElementTransformerVoid() {
val builder = context.createIrBuilder(constructor.symbol)
fun transformBody() {
constructor.body?.transformChildrenVoid(this)
}
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall) =
builder.irDelegatingConstructorCall(expression.symbol.owner).apply {
for (i in 0..1) {
putValueArgument(i, builder.irGet(constructor.valueParameters[i]))
}
}
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
var delegatingConstructor = expression.symbol.owner
val constructorWasTransformed = delegatingConstructor.symbol in loweredEnumConstructors
if (constructorWasTransformed)
delegatingConstructor = loweredEnumConstructors[delegatingConstructor.symbol]!!
return builder.irDelegatingConstructorCall(delegatingConstructor).apply {
var valueArgIdx = 0
for (i in 0..1) {
putValueArgument(valueArgIdx++, builder.irGet(constructor.valueParameters[i]))
}
for (i in 0 until expression.valueArgumentsCount) {
putValueArgument(valueArgIdx++, expression.getValueArgument(i))
}
}
}
}
private inner class IrEnumEntryClassConstructorTransformer(val entry: IrEnumEntry, val isInsideConstructor: Boolean) :
IrElementTransformerVoid() {
private fun buildConstructorCall(constructor: IrConstructor) =
if (isInsideConstructor)
builder.irDelegatingConstructorCall(constructor)
else
builder.irCall(constructor)
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrExpression {
var constructor = expression.symbol.owner
val constructorWasTransformed = constructor.symbol in loweredEnumConstructors
// Enum entry class constructors are not transformed
if (constructorWasTransformed)
constructor = loweredEnumConstructors[constructor.symbol]!!
return buildConstructorCall(constructor).apply {
var valueArgIdx = 0
// Enum entry class constructors already delegate name and ordinal parameters in their body
if (constructorWasTransformed) {
putValueArgument(valueArgIdx++, entry.getNameExpression())
putValueArgument(valueArgIdx++, entry.getOrdinalExpression())
}
for (i in 0 until expression.valueArgumentsCount) {
putValueArgument(valueArgIdx++, expression.getValueArgument(i))
}
}
}
}
private fun transformEnumConstructor(enumConstructor: IrConstructor, enumClass: IrClass): IrConstructor {
val loweredConstructorDescriptor = WrappedClassConstructorDescriptor()
val loweredConstructorSymbol = IrConstructorSymbolImpl(loweredConstructorDescriptor)
return IrConstructorImpl(
enumConstructor.startOffset,
enumConstructor.endOffset,
enumConstructor.origin,
loweredConstructorSymbol,
enumConstructor.name,
enumConstructor.visibility,
enumConstructor.returnType,
enumConstructor.isInline,
enumConstructor.isExternal,
enumConstructor.isPrimary
).apply {
loweredConstructorDescriptor.bind(this)
parent = enumClass
valueParameters += JsIrBuilder.buildValueParameter("name", 0, context.irBuiltIns.stringType).also { it.parent = this }
valueParameters += JsIrBuilder.buildValueParameter("ordinal", 1, context.irBuiltIns.intType).also { it.parent = this }
copyParameterDeclarationsFrom(enumConstructor)
body = enumConstructor.body
loweredEnumConstructors[enumConstructor.symbol] = this
this.acceptVoid(PatchDeclarationParentsVisitor(enumClass))
}
}
private fun findFunctionDescriptorForMemberWithSyntheticBodyKind(kind: IrSyntheticBodyKind): IrFunction =
irClass.declarations.asSequence().filterIsInstance<IrFunction>()
@@ -459,7 +504,4 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass:
) = JsIrBuilder.buildFunction(name, returnType, irClass).also {
it.body = context.createIrBuilder(it.symbol).irBlockBody(it, bodyBuilder)
}
private fun IrEnumEntry.getNameExpression() = builder.irString(this.name.identifier)
private fun IrEnumEntry.getOrdinalExpression() = builder.irInt(enumEntries.indexOf(this))
}
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.isThrowable
import org.jetbrains.kotlin.ir.util.isThrowableTypeOrSubtype
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.Name
@@ -147,12 +148,25 @@ class ThrowableSuccessorsLowering(val context: JsIrBackendContext) : FileLowerin
if (isDirectChildOfThrowable(declaration)) {
val messageField = createBackingField(declaration, messagePropertyName, stringType)
val causeField = createBackingField(declaration, causePropertyName, throwableType)
val existedMessageAccessor = ownPropertyAccessor(declaration, messageGetter)
if (existedMessageAccessor.origin == IrDeclarationOrigin.FAKE_OVERRIDE)
val newMessageAccessor = if (existedMessageAccessor.origin == IrDeclarationOrigin.FAKE_OVERRIDE) {
createPropertyAccessor(existedMessageAccessor, messageField)
} else existedMessageAccessor
val existedCauseAccessor = ownPropertyAccessor(declaration, causeGetter)
if (existedCauseAccessor.origin == IrDeclarationOrigin.FAKE_OVERRIDE)
val newCauseAccessor = if (existedCauseAccessor.origin == IrDeclarationOrigin.FAKE_OVERRIDE) {
createPropertyAccessor(existedCauseAccessor, causeField)
} else existedCauseAccessor
declaration.declarations.transformFlat {
when (it) {
existedMessageAccessor -> listOf(newMessageAccessor)
existedCauseAccessor -> listOf(newCauseAccessor)
else -> null
}
}
pendingSuperUsages += DirectThrowableSuccessors(declaration, messageField, causeField)
}
@@ -181,7 +195,7 @@ class ThrowableSuccessorsLowering(val context: JsIrBackendContext) : FileLowerin
return fieldDeclaration
}
private fun createPropertyAccessor(fakeAccessor: IrSimpleFunction, field: IrField) {
private fun createPropertyAccessor(fakeAccessor: IrSimpleFunction, field: IrField): IrSimpleFunction {
val name = fakeAccessor.name
val function = JsIrBuilder.buildFunction(name, fakeAccessor.returnType, fakeAccessor.parent).apply {
overriddenSymbols += fakeAccessor.overriddenSymbols
@@ -194,7 +208,7 @@ class ThrowableSuccessorsLowering(val context: JsIrBackendContext) : FileLowerin
val returnStatement = JsIrBuilder.buildReturn(function.symbol, returnValue, nothingType)
function.body = JsIrBuilder.buildBlockBody(listOf(returnStatement))
fakeAccessor.correspondingProperty?.getter = function
return function
}
}
@@ -315,7 +329,8 @@ class ThrowableSuccessorsLowering(val context: JsIrBackendContext) : FileLowerin
private fun isDirectChildOfThrowable(irClass: IrClass) = irClass.superTypes.any { it.isThrowable() }
private fun ownPropertyAccessor(irClass: IrClass, irBase: IrFunctionSymbol) =
irClass.declarations.filterIsInstance<IrProperty>().mapNotNull { it.getter }
.single { it.overriddenSymbols.any { s -> s == irBase } }
.singleOrNull { it.overriddenSymbols.any { s -> s == irBase } }
?: irClass.declarations.filterIsInstance<IrSimpleFunction>().single { it.overriddenSymbols.any { s -> s == irBase } }
inner class ThrowablePropertiesUsageTransformer : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression {
@@ -244,7 +244,8 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
}
val typeParameter = typeParameterSymbol.owner
assert(!typeParameter.isReified) { "reified parameters have to be lowered before" }
// TODO either remove functions with reified type parameters or support this case
// assert(!typeParameter.isReified) { "reified parameters have to be lowered before" }
return typeParameter.superTypes.fold(litTrue) { r, t ->
val check = generateTypeCheckNonNull(argument.copy(), t.makeNotNull(false))
calculator.and(r, check)
@@ -7,12 +7,12 @@ package org.jetbrains.kotlin.ir.backend.js.lower.calls
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.util.getSimpleFunction
import org.jetbrains.kotlin.ir.util.getPropertyGetter
class PrimitiveContainerMemberCallTransformer(private val context: JsIrBackendContext) : CallsTransformer {
private val intrinsics = context.intrinsics
@@ -65,22 +65,22 @@ class PrimitiveContainerMemberCallTransformer(private val context: JsIrBackendCo
}
private val IrClassSymbol.sizeProperty
get() = owner.declarations.filterIsInstance<IrProperty>().first { it.name.asString() == "size" }.getter!!.symbol
get() = getPropertyGetter("size")!!
private val IrClassSymbol.getFunction
get() = owner.declarations.filterIsInstance<IrFunction>().first { it.name.asString() == "get" }.symbol
get() = getSimpleFunction("get")!!
private val IrClassSymbol.setFunction
get() = owner.declarations.filterIsInstance<IrFunction>().first { it.name.asString() == "set" }.symbol
get() = getSimpleFunction("set")!!
private val IrClassSymbol.iterator
get() = owner.declarations.filterIsInstance<IrFunction>().first { it.name.asString() == "iterator" }.symbol
get() = getSimpleFunction("iterator")!!
private val IrClassSymbol.sizeConstructor
get() = owner.declarations.filterIsInstance<IrConstructor>().first { it.valueParameters.size == 1 }.symbol
private val IrClassSymbol.lengthProperty
get() = owner.declarations.filterIsInstance<IrProperty>().first { it.name.asString() == "length" }.getter!!.symbol
get() = getPropertyGetter("length")!!
private val IrClassSymbol.subSequence
get() = owner.declarations.filterIsInstance<IrFunction>().single { it.name.asString() == "subSequence" }.symbol
get() = getSimpleFunction("subSequence")!!
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
@@ -64,9 +65,11 @@ class StateMachineBuilder(
val context: JsIrBackendContext,
val function: IrFunctionSymbol,
private val rootLoop: IrLoop,
private val exceptionSymbol: IrProperty,
private val exStateSymbol: IrProperty,
private val stateSymbol: IrProperty,
private val exceptionSymbolGetter: IrSimpleFunction,
private val exceptionSymbolSetter: IrSimpleFunction,
private val exStateSymbolGetter: IrSimpleFunction,
private val exStateSymbolSetter: IrSimpleFunction,
private val stateSymbolSetter: IrSimpleFunction,
private val thisSymbol: IrValueParameterSymbol,
private val suspendResult: IrVariableSymbol
) : IrElementVisitorVoid {
@@ -84,7 +87,7 @@ class StateMachineBuilder(
val entryState = SuspendState(unit)
val rootExceptionTrap = buildExceptionTrapState()
private val globalExceptionVar = JsIrBuilder.buildVar(exceptionSymbol.getter!!.returnType, function.owner, "e")
private val globalExceptionVar = JsIrBuilder.buildVar(exceptionSymbolGetter.returnType, function.owner, "e")
lateinit var globalCatch: IrCatch
fun finalizeStateMachine() {
@@ -118,11 +121,11 @@ class StateMachineBuilder(
)
// TODO: exception table
elseBlock.statements += JsIrBuilder.buildCall(stateSymbol.setter!!.symbol, unit).apply {
elseBlock.statements += JsIrBuilder.buildCall(stateSymbolSetter.symbol, unit).apply {
dispatchReceiver = thisReceiver
putValueArgument(0, exceptionState())
}
elseBlock.statements += JsIrBuilder.buildCall(exceptionSymbol.setter!!.symbol, unit).apply {
elseBlock.statements += JsIrBuilder.buildCall(exceptionSymbolSetter.symbol, unit).apply {
dispatchReceiver = thisReceiver
putValueArgument(0, JsIrBuilder.buildGetValue(globalExceptionSymbol))
}
@@ -180,7 +183,7 @@ class StateMachineBuilder(
private fun doDispatchImpl(target: SuspendState, block: IrContainerExpression, andContinue: Boolean) {
val irDispatch = IrDispatchPoint(target)
currentState.successors.add(target)
block.addStatement(JsIrBuilder.buildCall(stateSymbol.setter!!.symbol, unit).apply {
block.addStatement(JsIrBuilder.buildCall(stateSymbolSetter.symbol, unit).apply {
dispatchReceiver = thisReceiver
putValueArgument(0, irDispatch)
})
@@ -297,7 +300,7 @@ class StateMachineBuilder(
currentState.successors += continueState
transformLastExpression {
JsIrBuilder.buildCall(stateSymbol.setter!!.symbol, unit).apply {
JsIrBuilder.buildCall(stateSymbolSetter.symbol, unit).apply {
dispatchReceiver = thisReceiver
putValueArgument(0, dispatch)
}
@@ -686,7 +689,7 @@ class StateMachineBuilder(
aTry.finallyExpression?.acceptVoid(this)
currentState.successors += listOf(throwExitState, exitState)
addStatement(
JsIrBuilder.buildCall(stateSymbol.setter!!.symbol, unit).also {
JsIrBuilder.buildCall(stateSymbolSetter.symbol, unit).also {
it.dispatchReceiver = thisReceiver
it.putValueArgument(0, JsIrBuilder.buildGetValue(finallyStateVar.symbol))
}
@@ -706,15 +709,15 @@ class StateMachineBuilder(
private fun setupExceptionState(target: SuspendState) {
addStatement(
JsIrBuilder.buildCall(exStateSymbol.setter!!.symbol, unit).apply {
JsIrBuilder.buildCall(exStateSymbolSetter.symbol, unit).apply {
dispatchReceiver = thisReceiver
putValueArgument(0, IrDispatchPoint(target))
}
)
}
private fun exceptionState() = JsIrBuilder.buildCall(exStateSymbol.getter!!.symbol).also { it.dispatchReceiver = thisReceiver }
private fun pendingException() = JsIrBuilder.buildCall(exceptionSymbol.getter!!.symbol).also { it.dispatchReceiver = thisReceiver }
private fun exceptionState() = JsIrBuilder.buildCall(exStateSymbolGetter.symbol).also { it.dispatchReceiver = thisReceiver }
private fun pendingException() = JsIrBuilder.buildCall(exceptionSymbolGetter.symbol).also { it.dispatchReceiver = thisReceiver }
private fun buildTryState(aTry: IrTry) =
TryState(
@@ -228,8 +228,8 @@ internal class SuspendFunctionsLowering(val context: JsIrBackendContext): FileLo
builtCoroutines[irFunction] = coroutine
if (functionReference == null) {
val resultSetter = context.coroutineImplResultSymbol.setter!!
val exceptionSetter = context.coroutineImplExceptionProperty.setter!!
val resultSetter = context.coroutineImplResultSymbolSetter
val exceptionSetter = context.coroutineImplExceptionPropertySetter
// It is not a lambda - replace original function with a call to constructor of the built coroutine.
val irBuilder = context.createIrBuilder(irFunction.symbol, irFunction.startOffset, irFunction.endOffset)
irFunction.body = irBuilder.irBlockBody(irFunction) {
@@ -290,10 +290,13 @@ internal class SuspendFunctionsLowering(val context: JsIrBackendContext): FileLo
private val create1CompletionParameter = create1Function.valueParameters[0]
private val coroutineImplLabelProperty = context.coroutineImplLabelProperty
private val coroutineImplResultSymbol = context.coroutineImplResultSymbol
private val coroutineImplExceptionProperty = context.coroutineImplExceptionProperty
private val coroutineImplExceptionStateProperty = context.coroutineImplExceptionStateProperty
private val coroutineImplLabelPropertyGetter = context.coroutineImplLabelPropertyGetter
private val coroutineImplLabelPropertySetter = context.coroutineImplLabelPropertySetter
private val coroutineImplResultSymbolGetter = context.coroutineImplResultSymbolGetter
private val coroutineImplExceptionPropertyGetter = context.coroutineImplExceptionPropertyGetter
private val coroutineImplExceptionPropertySetter = context.coroutineImplExceptionPropertySetter
private val coroutineImplExceptionStatePropertyGetter = context.coroutineImplExceptionStatePropertyGetter
private val coroutineImplExceptionStatePropertySetter = context.coroutineImplExceptionStatePropertySetter
private val coroutineConstructors = mutableListOf<IrConstructor>()
private var exceptionTrapId = -1
@@ -727,8 +730,8 @@ internal class SuspendFunctionsLowering(val context: JsIrBackendContext): FileLo
JsIrBuilder.buildValueParameter(p.name, p.index, p.type, p.origin).also { it.parent = declaration }
}
val resultSetter = context.coroutineImplResultSymbol.setter!!
val exceptionSetter = context.coroutineImplExceptionProperty.setter!!
val resultSetter = context.coroutineImplResultSymbolSetter
val exceptionSetter = context.coroutineImplExceptionPropertySetter
val thisReceiver = declaration.dispatchReceiverParameter!!
val irBuilder = context.createIrBuilder(symbol, irFunction.startOffset, irFunction.endOffset)
@@ -821,10 +824,10 @@ internal class SuspendFunctionsLowering(val context: JsIrBackendContext): FileLo
function,
"suspendResult",
true,
initializer = JsIrBuilder.buildCall(coroutineImplResultSymbol.getter!!.symbol).apply { dispatchReceiver = thisReceiver }
initializer = JsIrBuilder.buildCall(coroutineImplResultSymbolGetter.symbol).apply { dispatchReceiver = thisReceiver }
)
suspendState = JsIrBuilder.buildVar(coroutineImplLabelProperty.getter!!.returnType, function, "suspendState", true)
suspendState = JsIrBuilder.buildVar(coroutineImplLabelPropertyGetter.returnType, function, "suspendState", true)
val body =
(originalBody as IrBlockBody).run {
@@ -848,7 +851,7 @@ internal class SuspendFunctionsLowering(val context: JsIrBackendContext): FileLo
(it.body as? IrBlockBody)?.run {
val receiver = JsIrBuilder.buildGetValue(coroutineClassThis.symbol)
val id = JsIrBuilder.buildInt(context.irBuiltIns.intType, exceptionTrapId)
statements += JsIrBuilder.buildCall(coroutineImplExceptionStateProperty.setter!!.symbol).also { call ->
statements += JsIrBuilder.buildCall(coroutineImplExceptionStatePropertySetter.symbol).also { call ->
call.dispatchReceiver = receiver
call.putValueArgument(0, id)
}
@@ -880,9 +883,11 @@ internal class SuspendFunctionsLowering(val context: JsIrBackendContext): FileLo
context,
function.symbol,
rootLoop,
coroutineImplExceptionProperty,
coroutineImplExceptionStateProperty,
coroutineImplLabelProperty,
coroutineImplExceptionPropertyGetter,
coroutineImplExceptionPropertySetter,
coroutineImplExceptionStatePropertyGetter,
coroutineImplExceptionStatePropertySetter,
coroutineImplLabelPropertySetter,
thisReceiver,
suspendResult.symbol
)
@@ -907,7 +912,7 @@ internal class SuspendFunctionsLowering(val context: JsIrBackendContext): FileLo
for (state in sortedStates) {
val condition = JsIrBuilder.buildCall(eqeqeqInt).apply {
putValueArgument(0, JsIrBuilder.buildCall(coroutineImplLabelProperty.getter!!.symbol).also {
putValueArgument(0, JsIrBuilder.buildCall(coroutineImplLabelPropertyGetter.symbol).also {
it.dispatchReceiver = JsIrBuilder.buildGetValue(thisReceiver)
})
putValueArgument(1, JsIrBuilder.buildInt(context.irBuiltIns.intType, state.id))
@@ -7,8 +7,7 @@
package org.jetbrains.kotlin.ir.backend.js.lower.inline
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.ScopeWithIr
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.config.languageVersionSettings
@@ -19,6 +18,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.lower.ArrayConstructorTransformer
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irReturn
@@ -31,11 +31,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.types.irTypeKotlinBuiltIns
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.file
import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
@@ -53,11 +49,27 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
return irModule.accept(this, data = null)
}
private val arrayConstructorTransformer = ArrayConstructorTransformer(context)
override fun visitCall(expression: IrCall): IrExpression {
val callSite = super.visitCall(expression) as IrCall
val callSite = arrayConstructorTransformer.transformCall(super.visitCall(expression) as IrCall)
val functionDescriptor = callSite.descriptor
if (!functionDescriptor.needsInlining)
return callSite // This call does not need inlining.
if (!functionDescriptor.needsInlining) return callSite // This call does not need inlining.
val languageVersionSettings = context.configuration.languageVersionSettings
when {
callSite.symbol == context.ir.symbols.lateinitIsInitializedPropertyGetter ->
return callSite
// Handle coroutine intrinsics
// TODO These should actually be inlined.
callSite.descriptor.isBuiltInIntercepted(languageVersionSettings) ->
error("Continuation.intercepted is not available with release coroutines")
callSite.symbol.descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) ->
return irCall(callSite, context.coroutineSuspendOrReturn)
callSite.symbol == context.intrinsics.jsCoroutineContext ->
return irCall(callSite, context.coroutineGetContextJs)
}
val callee = getFunctionDeclaration(callSite.symbol) // Get declaration of the function to be inlined.
callee.transformChildrenVoid(this) // Process recursive inline.
@@ -21,7 +21,7 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
override fun visitFunction(declaration: IrFunction, data: JsGenerationContext) = JsEmpty.also {
assert(declaration.origin == JsIrBackendContext.callableClosureOrigin) {
"The only possible Function Declarartion is one composed in Callable Reference Lowering"
"The only possible Function Declaration is one composed in Callable Reference Lowering"
}
}