[JS IR BE] Reorder phases in order to extract a common prefix
This commit is contained in:
+15
-13
@@ -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
|
||||
|
||||
+3
-18
@@ -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 {
|
||||
|
||||
+194
-152
@@ -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))
|
||||
}
|
||||
|
||||
+20
-5
@@ -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 {
|
||||
|
||||
+2
-1
@@ -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)
|
||||
|
||||
+8
-8
@@ -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")!!
|
||||
|
||||
+15
-12
@@ -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(
|
||||
|
||||
+20
-15
@@ -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))
|
||||
|
||||
+22
-10
@@ -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.
|
||||
|
||||
+1
-1
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user