diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt index 5f880b2400e..9d5e1cab998 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt @@ -57,6 +57,10 @@ internal class KonanLower(val context: Context) { FunctionInlining(context).inline(irModule) } + phaser.phase(KonanPhase.LOWER_AFTER_INLINE) { + irModule.files.forEach(PostInlineLowering(context)::lower) + } + phaser.phase(KonanPhase.LOWER_INTEROP_PART1) { irModule.files.forEach(InteropLoweringPart1(context)::lower) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt index 1ad9e7d71bc..c1545df6ed0 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt @@ -32,6 +32,7 @@ enum class KonanPhase(val description: String, /* ... ... */ LOWER_BEFORE_INLINE("Special operations processing before inlining"), /* ... ... */ LOWER_INLINE_CONSTRUCTORS("Inline constructors transformation", LOWER_BEFORE_INLINE), /* ... ... */ LOWER_INLINE("Functions inlining", LOWER_INLINE_CONSTRUCTORS, LOWER_BEFORE_INLINE), + /* ... ... */ LOWER_AFTER_INLINE("Special operations processing after inlining"), /* ... ... ... */ DESERIALIZER("Deserialize inline bodies"), /* ... ... */ LOWER_INTEROP_PART1("Interop lowering, part 1", LOWER_INLINE), /* ... ... */ LOWER_FOR_LOOPS("For loops lowering"), diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt new file mode 100644 index 00000000000..fe13a8c81e2 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt @@ -0,0 +1,653 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.backend.konan.lower + +import org.jetbrains.kotlin.backend.common.CommonBackendContext +import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.* +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl +import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl +import org.jetbrains.kotlin.ir.util.DeepCopyIrTree +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.types.TypeUtils +import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.types.typeUtil.makeNullable + +class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor, + context: CommonBackendContext) { + + private val descriptorSubstituteMap: MutableMap = mutableMapOf() + private var typeSubstitutor: TypeSubstitutor? = null + private var nameIndex = 0 + + //-------------------------------------------------------------------------// + + fun copy(irElement: IrElement, typeSubstitutor: TypeSubstitutor?): IrElement { + this.typeSubstitutor = typeSubstitutor + irElement.acceptChildrenVoid(DescriptorCollector()) + return irElement.accept(InlineCopyIr(), null) + } + + //-------------------------------------------------------------------------// + + inner class DescriptorCollector: IrElementVisitorVoid { + + override fun visitElement(element: IrElement) { + element.acceptChildren(this, null) + } + + //---------------------------------------------------------------------// + + override fun visitClass(declaration: IrClass) { + + val oldDescriptor = declaration.descriptor + val newDescriptor = copyClassDescriptor(oldDescriptor) + descriptorSubstituteMap[oldDescriptor] = newDescriptor + descriptorSubstituteMap[oldDescriptor.thisAsReceiverParameter] = newDescriptor.thisAsReceiverParameter + + super.visitClass(declaration) + + val constructors = oldDescriptor.constructors.map { oldConstructorDescriptor -> + descriptorSubstituteMap[oldConstructorDescriptor] as ClassConstructorDescriptor + }.toSet() + + val oldPrimaryConstructor = oldDescriptor.unsubstitutedPrimaryConstructor + val primaryConstructor = oldPrimaryConstructor?.let { descriptorSubstituteMap[it] as ClassConstructorDescriptor } + + val contributedDescriptors = oldDescriptor.unsubstitutedMemberScope + .getContributedDescriptors() + .map { + descriptorSubstituteMap[it]!! + } + newDescriptor.initialize( + SimpleMemberScope(contributedDescriptors), + constructors, + primaryConstructor + ) + } + + //---------------------------------------------------------------------// + + override fun visitProperty(declaration: IrProperty) { + + copyPropertyOrField(declaration.descriptor) + super.visitProperty(declaration) + } + + //---------------------------------------------------------------------// + + override fun visitField(declaration: IrField) { + + val oldDescriptor = declaration.descriptor + if (descriptorSubstituteMap[oldDescriptor] == null) { + copyPropertyOrField(oldDescriptor) // A field without a property or a field of a delegated property. + } + super.visitField(declaration) + } + + //---------------------------------------------------------------------// + + override fun visitFunction(declaration: IrFunction) { + + val oldDescriptor = declaration.descriptor + if (oldDescriptor !is PropertyAccessorDescriptor) { // Property accessors are copied along with their property. + val newDescriptor = copyFunctionDescriptor(oldDescriptor) + descriptorSubstituteMap[oldDescriptor] = newDescriptor + oldDescriptor.extensionReceiverParameter?.let{ + descriptorSubstituteMap[it] = newDescriptor.extensionReceiverParameter!! + } + } + super.visitFunction(declaration) + } + + //---------------------------------------------------------------------// + + override fun visitVariable(declaration: IrVariable) { + + val oldDescriptor = declaration.descriptor + val oldContainingDeclaration = oldDescriptor.containingDeclaration + val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) + val newDescriptor = IrTemporaryVariableDescriptorImpl( + containingDeclaration = newContainingDeclaration, + name = generateCopyName(oldDescriptor.name), + outType = substituteType(oldDescriptor.type)!!, + isMutable = oldDescriptor.isVar) + descriptorSubstituteMap[oldDescriptor] = newDescriptor + + super.visitVariable(declaration) + } + + //---------------------------------------------------------------------// + + override fun visitCatch(aCatch: IrCatch) { + val oldDescriptor = aCatch.parameter + val oldContainingDeclaration = oldDescriptor.containingDeclaration + val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) + val newDescriptor = IrTemporaryVariableDescriptorImpl( + containingDeclaration = newContainingDeclaration, + name = generateCopyName(oldDescriptor.name), + outType = substituteType(oldDescriptor.type)!!, + isMutable = oldDescriptor.isVar) + descriptorSubstituteMap[oldDescriptor] = newDescriptor + + super.visitCatch(aCatch) + } + + //--- Copy descriptors ------------------------------------------------// + + private fun generateCopyName(name: Name): Name { + + val declarationName = name.toString() // Name of declaration + val indexStr = (nameIndex++).toString() // Unique for inline target index + return Name.identifier(declarationName + "_" + indexStr) + } + + //---------------------------------------------------------------------// + + private fun copyFunctionDescriptor(oldDescriptor: CallableDescriptor): CallableDescriptor { + + return when (oldDescriptor) { + is ConstructorDescriptor -> copyConstructorDescriptor(oldDescriptor) + is SimpleFunctionDescriptor -> copySimpleFunctionDescriptor(oldDescriptor) + else -> TODO("Unsupported FunctionDescriptor subtype: $oldDescriptor") + } + } + + //---------------------------------------------------------------------// + + private fun copySimpleFunctionDescriptor(oldDescriptor: SimpleFunctionDescriptor) : FunctionDescriptor { + + val oldContainingDeclaration = oldDescriptor.containingDeclaration + val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) + return SimpleFunctionDescriptorImpl.create( + /* containingDeclaration = */ newContainingDeclaration, + /* annotations = */ oldDescriptor.annotations, + /* name = */ generateCopyName(oldDescriptor.name), + /* kind = */ oldDescriptor.kind, + /* source = */ oldDescriptor.source + ).apply { + + val oldDispatchReceiverParameter = oldDescriptor.dispatchReceiverParameter + val newDispatchReceiverParameter = oldDispatchReceiverParameter?.let { descriptorSubstituteMap.getOrDefault(it, it) as ReceiverParameterDescriptor } + val newTypeParameters = oldDescriptor.typeParameters // TODO substitute types + val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this) + val newReceiverParameterType = substituteType(oldDescriptor.extensionReceiverParameter?.type) + val newReturnType = substituteType(oldDescriptor.returnType) + + initialize( + /* receiverParameterType = */ newReceiverParameterType, + /* dispatchReceiverParameter = */ newDispatchReceiverParameter, + /* typeParameters = */ newTypeParameters, + /* unsubstitutedValueParameters = */ newValueParameters, + /* unsubstitutedReturnType = */ newReturnType, + /* modality = */ oldDescriptor.modality, + /* visibility = */ oldDescriptor.visibility + ) + isTailrec = oldDescriptor.isTailrec + isSuspend = oldDescriptor.isSuspend + overriddenDescriptors += oldDescriptor.overriddenDescriptors + } + } + + //---------------------------------------------------------------------// + + private fun copyConstructorDescriptor(oldDescriptor: ConstructorDescriptor) : FunctionDescriptor { + + val oldContainingDeclaration = oldDescriptor.containingDeclaration + val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) + return ClassConstructorDescriptorImpl.create( + /* containingDeclaration = */ newContainingDeclaration as ClassDescriptor, + /* annotations = */ oldDescriptor.annotations, + /* isPrimary = */ oldDescriptor.isPrimary, + /* source = */ oldDescriptor.source + ).apply { + + val newTypeParameters = oldDescriptor.typeParameters + val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this) + val receiverParameterType = substituteType(oldDescriptor.dispatchReceiverParameter?.type) + val returnType = substituteType(oldDescriptor.returnType) + + initialize( + /* receiverParameterType = */ receiverParameterType, + /* dispatchReceiverParameter = */ null, // For constructor there is no explicit dispatch receiver. + /* typeParameters = */ newTypeParameters, + /* unsubstitutedValueParameters = */ newValueParameters, + /* unsubstitutedReturnType = */ returnType, + /* modality = */ oldDescriptor.modality, + /* visibility = */ oldDescriptor.visibility + ) + } + } + + //---------------------------------------------------------------------// + + private fun copyPropertyOrField(oldDescriptor: PropertyDescriptor) { + + val newDescriptor = copyPropertyDescriptor(oldDescriptor) + descriptorSubstituteMap[oldDescriptor] = newDescriptor + oldDescriptor.getter?.let { + descriptorSubstituteMap[it] = newDescriptor.getter!! + } + oldDescriptor.setter?.let { + descriptorSubstituteMap[it] = newDescriptor.setter!! + } + oldDescriptor.extensionReceiverParameter?.let{ + descriptorSubstituteMap[it] = newDescriptor.extensionReceiverParameter!! + } + + } + + //---------------------------------------------------------------------// + + private fun copyPropertyDescriptor(oldDescriptor: PropertyDescriptor): PropertyDescriptor { + + val oldContainingDeclaration = oldDescriptor.containingDeclaration + val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) as ClassDescriptor + return PropertyDescriptorImpl.create( + /* containingDeclaration = */ newContainingDeclaration, + /* annotations = */ oldDescriptor.annotations, + /* modality = */ oldDescriptor.modality, + /* visibility = */ oldDescriptor.visibility, + /* isVar = */ oldDescriptor.isVar, + /* name = */ oldDescriptor.name, + /* kind = */ oldDescriptor.kind, + /* source = */ oldDescriptor.source, + /* lateInit = */ oldDescriptor.isLateInit, + /* isConst = */ oldDescriptor.isConst, + /* isExpect = */ oldDescriptor.isExpect, + /* isActual = */ oldDescriptor.isActual, + /* isExternal = */ oldDescriptor.isExternal, + /* isDelegated = */ oldDescriptor.isDelegated + ).apply { + + setType( + /* outType = */ oldDescriptor.type, + /* typeParameters = */ oldDescriptor.typeParameters, + /* dispatchReceiverParameter = */ newContainingDeclaration.thisAsReceiverParameter, + /* receiverType = */ oldDescriptor.extensionReceiverParameter?.type) + + initialize( + /* getter = */ oldDescriptor.getter?.let { copyPropertyGetterDescriptor(it, this) }, + /* setter = */ oldDescriptor.setter?.let { copyPropertySetterDescriptor(it, this) }) + + overriddenDescriptors += oldDescriptor.overriddenDescriptors + } + } + + //---------------------------------------------------------------------// + + private fun copyPropertyGetterDescriptor(oldDescriptor: PropertyGetterDescriptor, newPropertyDescriptor: PropertyDescriptor) + : PropertyGetterDescriptorImpl { + + return PropertyGetterDescriptorImpl( + /* correspondingProperty = */ newPropertyDescriptor, + /* annotations = */ oldDescriptor.annotations, + /* modality = */ oldDescriptor.modality, + /* visibility = */ oldDescriptor.visibility, + /* isDefault = */ oldDescriptor.isDefault, + /* isExternal = */ oldDescriptor.isExternal, + /* isInline = */ oldDescriptor.isInline, + /* kind = */ oldDescriptor.kind, + /* original = */ null, + /* source = */ oldDescriptor.source).apply { + initialize(oldDescriptor.returnType) + } + } + + //---------------------------------------------------------------------// + + private fun copyPropertySetterDescriptor(oldDescriptor: PropertySetterDescriptor, newPropertyDescriptor: PropertyDescriptor) + : PropertySetterDescriptorImpl { + + return PropertySetterDescriptorImpl( + /* correspondingProperty = */ newPropertyDescriptor, + /* annotations = */ oldDescriptor.annotations, + /* modality = */ oldDescriptor.modality, + /* visibility = */ oldDescriptor.visibility, + /* isDefault = */ oldDescriptor.isDefault, + /* isExternal = */ oldDescriptor.isExternal, + /* isInline = */ oldDescriptor.isInline, + /* kind = */ oldDescriptor.kind, + /* original = */ null, + /* source = */ oldDescriptor.source).apply { + initialize(copyValueParameters(oldDescriptor.valueParameters, this).single()) + } + } + + //---------------------------------------------------------------------// + + private fun copyClassDescriptor(oldDescriptor: ClassDescriptor): ClassDescriptorImpl { + + val oldSuperClass = oldDescriptor.getSuperClassOrAny() + val newSuperClass = descriptorSubstituteMap.getOrDefault(oldSuperClass, oldSuperClass) as ClassDescriptor + val oldContainingDeclaration = oldDescriptor.containingDeclaration + val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) + val newName = if (DescriptorUtils.isAnonymousObject(oldDescriptor)) // Anonymous objects are identified by their name. + oldDescriptor.name // We need to preserve it for LocalDeclarationsLowering. + else + generateCopyName(oldDescriptor.name) + return ClassDescriptorImpl( + /* containingDeclaration = */ newContainingDeclaration, + /* name = */ newName, + /* modality = */ oldDescriptor.modality, + /* kind = */ oldDescriptor.kind, + /* supertypes = */ listOf(newSuperClass.defaultType), + /* source = */ oldDescriptor.source, + /* isExternal = */ oldDescriptor.isExternal + ) + } + } + +//-----------------------------------------------------------------------------// + + inner class InlineCopyIr : DeepCopyIrTree() { + + override fun mapClassDeclaration (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor + override fun mapTypeAliasDeclaration (descriptor: TypeAliasDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as TypeAliasDescriptor + override fun mapFunctionDeclaration (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor + override fun mapConstructorDeclaration (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor + override fun mapPropertyDeclaration (descriptor: PropertyDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as PropertyDescriptor + override fun mapLocalPropertyDeclaration (descriptor: VariableDescriptorWithAccessors) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptorWithAccessors + override fun mapEnumEntryDeclaration (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor + override fun mapVariableDeclaration (descriptor: VariableDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptor + override fun mapErrorDeclaration (descriptor: DeclarationDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) + + override fun mapClassReference (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor + override fun mapValueReference (descriptor: ValueDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ValueDescriptor + override fun mapVariableReference (descriptor: VariableDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptor + override fun mapPropertyReference (descriptor: PropertyDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as PropertyDescriptor + override fun mapCallee (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor + override fun mapDelegatedConstructorCallee (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor + override fun mapEnumConstructorCallee (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor + override fun mapLocalPropertyReference (descriptor: VariableDescriptorWithAccessors) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptorWithAccessors + override fun mapClassifierReference (descriptor: ClassifierDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassifierDescriptor + override fun mapReturnTarget (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor + + //---------------------------------------------------------------------// + + override fun mapSuperQualifier(qualifier: ClassDescriptor?): ClassDescriptor? { + if (qualifier == null) return null + return descriptorSubstituteMap.getOrDefault(qualifier, qualifier) as ClassDescriptor + } + + //--- Visits ----------------------------------------------------------// + + override fun visitCall(expression: IrCall): IrCall { + if (expression !is IrCallImpl) return super.visitCall(expression) + val newDescriptor = mapCallee(expression.descriptor) + return IrCallImpl( + startOffset = expression.startOffset, + endOffset = expression.endOffset, + type = newDescriptor.returnType!!, + calleeDescriptor = newDescriptor, + typeArguments = substituteTypeArguments(expression.transformTypeArguments(newDescriptor)), + origin = expression.origin, + superQualifierDescriptor = mapSuperQualifier(expression.superQualifier) + ).transformValueArguments(expression) + } + + //---------------------------------------------------------------------// + + override fun visitFunction(declaration: IrFunction): IrFunction = + IrFunctionImpl( + startOffset = declaration.startOffset, + endOffset = declaration.endOffset, + origin = mapDeclarationOrigin(declaration.origin), + descriptor = mapFunctionDeclaration(declaration.descriptor), + body = declaration.body?.transform(this, null) + ).transformParameters(declaration) + + //---------------------------------------------------------------------// + + private fun T.transformDefaults(original: T): T { + for (originalValueParameter in original.descriptor.valueParameters) { + val valueParameter = descriptor.valueParameters[originalValueParameter.index] + original.getDefault(originalValueParameter)?.let { irDefaultParameterValue -> + putDefault(valueParameter, irDefaultParameterValue.transform(this@InlineCopyIr, null)) + } + } + return this + } + + //---------------------------------------------------------------------// + + fun getTypeOperatorReturnType(operator: IrTypeOperator, type: KotlinType) : KotlinType { + return when (operator) { + IrTypeOperator.CAST, + IrTypeOperator.IMPLICIT_CAST, + IrTypeOperator.IMPLICIT_NOTNULL, + IrTypeOperator.IMPLICIT_COERCION_TO_UNIT, + IrTypeOperator.IMPLICIT_INTEGER_COERCION -> type + IrTypeOperator.SAFE_CAST -> type.makeNullable() + IrTypeOperator.INSTANCEOF, + IrTypeOperator.NOT_INSTANCEOF -> context.builtIns.booleanType + } + } + + //---------------------------------------------------------------------// + + override fun visitTypeOperator(expression: IrTypeOperatorCall): IrTypeOperatorCall { + val typeOperand = substituteType(expression.typeOperand)!! + val returnType = getTypeOperatorReturnType(expression.operator, typeOperand) + return IrTypeOperatorCallImpl( + startOffset = expression.startOffset, + endOffset = expression.endOffset, + type = returnType, + operator = expression.operator, + typeOperand = typeOperand, + argument = expression.argument.transform(this, null) + ) + } + + //---------------------------------------------------------------------// + + override fun visitReturn(expression: IrReturn): IrReturn = + IrReturnImpl( + startOffset = expression.startOffset, + endOffset = expression.endOffset, + type = substituteType(expression.type)!!, + returnTargetDescriptor = mapReturnTarget(expression.returnTarget), + value = expression.value.transform(this, null) + ) + + //---------------------------------------------------------------------// + + override fun visitBlock(expression: IrBlock): IrBlock { + return if (expression is IrReturnableBlock) { + IrReturnableBlockImpl( + startOffset = expression.startOffset, + endOffset = expression.endOffset, + type = expression.type, + descriptor = expression.descriptor, + origin = mapStatementOrigin(expression.origin), + statements = expression.statements.map { it.transform(this, null) }, + sourceFileName = expression.sourceFileName + ) + } else { + super.visitBlock(expression) + } + } + + //-------------------------------------------------------------------------// + + override fun visitClassReference(expression: IrClassReference): IrClassReference { + val newExpressionType = substituteType(expression.type)!! // Substituted expression type. + val newDescriptorType = substituteType(expression.descriptor.defaultType)!! // Substituted type of referenced class. + val classDescriptor = newDescriptorType.constructor.declarationDescriptor!! // Get ClassifierDescriptor of the referenced class. + return IrClassReferenceImpl( + startOffset = expression.startOffset, + endOffset = expression.endOffset, + type = newExpressionType, + descriptor = classDescriptor + ) + } + + //-------------------------------------------------------------------------// + + override fun visitGetClass(expression: IrGetClass): IrGetClass { + val type = substituteType(expression.type)!! + if (type == expression.type) return expression + return IrGetClassImpl( + startOffset = expression.startOffset, + endOffset = expression.endOffset, + type = type, + argument = expression.argument.transform(this, null) + ) + } + + //-------------------------------------------------------------------------// + + override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop { + return irLoop + } + } + + //-------------------------------------------------------------------------// + + private fun copyValueParameters(oldValueParameters: List , containingDeclaration: CallableDescriptor): List { + + return oldValueParameters.map { oldDescriptor -> + val newDescriptor = ValueParameterDescriptorImpl( + containingDeclaration = containingDeclaration, + original = oldDescriptor.original, + index = oldDescriptor.index, + annotations = oldDescriptor.annotations, + name = oldDescriptor.name, + outType = substituteType(oldDescriptor.type)!!, + declaresDefaultValue = oldDescriptor.declaresDefaultValue(), + isCrossinline = oldDescriptor.isCrossinline, + isNoinline = oldDescriptor.isNoinline, + varargElementType = substituteType(oldDescriptor.varargElementType), + source = oldDescriptor.source + ) + descriptorSubstituteMap[oldDescriptor] = newDescriptor + newDescriptor + } + } + + //-------------------------------------------------------------------------// + + private fun substituteType(oldType: KotlinType?): KotlinType? { + if (typeSubstitutor == null) return oldType + if (oldType == null) return oldType + return typeSubstitutor!!.substitute(oldType, Variance.INVARIANT) ?: oldType + } + + //-------------------------------------------------------------------------// + + private fun substituteTypeArguments(oldTypeArguments: Map ?): Map ? { + + if (oldTypeArguments == null) return null + if (typeSubstitutor == null) return oldTypeArguments + + val newTypeArguments = oldTypeArguments.entries.associate { + val typeParameterDescriptor = it.key + val oldTypeArgument = it.value + val newTypeArgument = substituteType(oldTypeArgument)!! + typeParameterDescriptor to newTypeArgument + } + return newTypeArguments + } + + //-------------------------------------------------------------------------// + + fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap) { + descriptorSubstituteMap.forEach { t, u -> + globalSubstituteMap.put(t, SubstitutedDescriptor(targetDescriptor, u)) + } + } + + val context = context + +} + +class SubstitutedDescriptor(val inlinedFunction: FunctionDescriptor, val descriptor: DeclarationDescriptor) + +class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap) + : IrElementTransformerVoidWithContext() { + + override fun visitCall(expression: IrCall): IrExpression { + val oldExpression = super.visitCall(expression) as IrCall + + val substitutedDescriptor = globalSubstituteMap[expression.descriptor.original] + ?: return oldExpression + if (allScopes.any { it.scope.scopeOwner == substitutedDescriptor.inlinedFunction }) + return oldExpression + return when (oldExpression) { + is IrCallImpl -> copyIrCallImpl(oldExpression, substitutedDescriptor) + is IrCallWithShallowCopy -> copyIrCallWithShallowCopy(oldExpression, substitutedDescriptor) + else -> oldExpression + } + } + + //-------------------------------------------------------------------------// + + private fun copyIrCallImpl(oldExpression: IrCallImpl, substitutedDescriptor: SubstitutedDescriptor): IrCallImpl { + + val oldDescriptor = oldExpression.descriptor + val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor + + if (newDescriptor == oldDescriptor) + return oldExpression + + val newExpression = IrCallImpl( + startOffset = oldExpression.startOffset, + endOffset = oldExpression.endOffset, + type = oldExpression.type, + calleeDescriptor = newDescriptor, + typeArguments = oldExpression.typeArguments, + origin = oldExpression.origin, + superQualifierDescriptor = oldExpression.superQualifier + ).apply { + oldExpression.descriptor.valueParameters.forEach { + val valueArgument = oldExpression.getValueArgument(it) + putValueArgument(it.index, valueArgument) + } + extensionReceiver = oldExpression.extensionReceiver + dispatchReceiver = oldExpression.dispatchReceiver + } + + return newExpression + } + + //-------------------------------------------------------------------------// + + private fun copyIrCallWithShallowCopy(oldExpression: IrCallWithShallowCopy, substitutedDescriptor: SubstitutedDescriptor): IrCall { + + val oldDescriptor = oldExpression.descriptor + val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor + + if (newDescriptor == oldDescriptor) + return oldExpression + + return oldExpression.shallowCopy(oldExpression.origin, newDescriptor, oldExpression.superQualifier) + } +} + diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt index 1d2eb0870c7..9a9ab2e9048 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt @@ -18,7 +18,9 @@ package org.jetbrains.kotlin.backend.konan.lower -import org.jetbrains.kotlin.backend.common.* +import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.ScopeWithIr +import org.jetbrains.kotlin.backend.common.reportWarning import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke import org.jetbrains.kotlin.backend.konan.descriptors.needsInlining diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/PostInlineLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/PostInlineLowering.kt new file mode 100644 index 00000000000..065eebf687a --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/PostInlineLowering.kt @@ -0,0 +1,106 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.backend.konan.lower + +import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.lower.IrBuildingTransformer +import org.jetbrains.kotlin.backend.common.lower.at +import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.backend.konan.reportCompilationError +import org.jetbrains.kotlin.ir.builders.irCall +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid + +/** + * This pass runs after inlining and performs the following additional transformations over some operations: + * - Convert immutableBinaryBlobOf() arguments to special IrConst. + * - Convert `obj::class` and `Class::class` to calls. + */ +internal class PostInlineLowering(val context: Context) : FileLoweringPass { + + private val symbols get() = context.ir.symbols + + override fun lower(irFile: IrFile) { + irFile.transformChildrenVoid(object : IrBuildingTransformer(context) { + + override fun visitClassReference(expression: IrClassReference): IrExpression { + expression.transformChildrenVoid() + builder.at(expression) + + val typeArgument = expression.descriptor.defaultType + + return builder.irCall(symbols.kClassImplConstructor, listOf(typeArgument)).apply { + putValueArgument(0, builder.irCall(symbols.getClassTypeInfo, listOf(typeArgument))) + } + } + + override fun visitGetClass(expression: IrGetClass): IrExpression { + expression.transformChildrenVoid() + builder.at(expression) + + val typeArgument = expression.type.arguments.single().type + return builder.irCall(symbols.kClassImplConstructor, listOf(typeArgument)).apply { + val typeInfo = builder.irCall(symbols.getObjectTypeInfo).apply { + putValueArgument(0, expression.argument) + } + + putValueArgument(0, typeInfo) + } + } + + override fun visitCall(expression: IrCall): IrExpression { + expression.transformChildrenVoid(this) + + if (expression.symbol == context.ir.symbols.immutableBinaryBlobOf) { + // Convert arguments of the binary blob to special IrConst structure, so that + // vararg lowering will not affect it. + val args = expression.getValueArgument(0) as? IrVararg + if (args == null) throw Error("varargs shall not be lowered yet") + if (args.elements.any { it is IrSpreadElement }) { + context.reportCompilationError("no spread elements allowed here", irFile, args) + } + val builder = StringBuilder() + args.elements.forEach { + if (it !is IrConst<*>) { + context.reportCompilationError( + "all elements of binary blob must be constants", irFile, it) + } + val value = when (it.kind) { + IrConstKind.Short -> (it.value as Short).toInt() + else -> + context.reportCompilationError("incorrect value for binary data: $it.value", irFile, it) + } + if (value < 0 || value > 0xff) + context.reportCompilationError("incorrect value for binary data: $value", irFile, it) + // Luckily, all values in range 0x00 .. 0xff represent valid UTF-16 symbols, + // block 0 (Basic Latin) and block 1 (Latin-1 Supplement) in + // Basic Multilingual Plane, so we could just append data "as is". + builder.append(value.toChar()) + } + expression.putValueArgument(0, IrConstImpl( + expression.startOffset, expression.endOffset, + context.ir.symbols.immutableBinaryBlob.descriptor.defaultType, + IrConstKind.String, builder.toString())) + } + + return expression + } + }) + } +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/PreInlineLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/PreInlineLowering.kt index 815b08875bd..fc1f3789be5 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/PreInlineLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/PreInlineLowering.kt @@ -18,22 +18,18 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.lower.IrBuildingTransformer -import org.jetbrains.kotlin.backend.common.lower.at -import org.jetbrains.kotlin.backend.konan.* +import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.KonanConfigKeys -import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.declarations.IrFile -import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.types.typeUtil.isUnit /** * This pass runs before inlining and performs the following additional transformations over some operations: * - Assertion call removal. - * - Convert immutableBinaryBlobOf() arguments to special IrConst. - * - Convert `obj::class` and `Class::class` to calls. */ internal class PreInlineLowering(val context: Context) : FileLoweringPass { @@ -45,31 +41,6 @@ internal class PreInlineLowering(val context: Context) : FileLoweringPass { override fun lower(irFile: IrFile) { irFile.transformChildrenVoid(object : IrBuildingTransformer(context) { - override fun visitClassReference(expression: IrClassReference): IrExpression { - expression.transformChildrenVoid() - builder.at(expression) - - val typeArgument = expression.descriptor.defaultType - - return builder.irCall(symbols.kClassImplConstructor, listOf(typeArgument)).apply { - putValueArgument(0, builder.irCall(symbols.getClassTypeInfo, listOf(typeArgument))) - } - } - - override fun visitGetClass(expression: IrGetClass): IrExpression { - expression.transformChildrenVoid() - builder.at(expression) - - val typeArgument = expression.type.arguments.single().type - return builder.irCall(symbols.kClassImplConstructor, listOf(typeArgument)).apply { - val typeInfo = builder.irCall(symbols.getObjectTypeInfo).apply { - putValueArgument(0, expression.argument) - } - - putValueArgument(0, typeInfo) - } - } - override fun visitCall(expression: IrCall): IrExpression { expression.transformChildrenVoid(this) @@ -79,38 +50,6 @@ internal class PreInlineLowering(val context: Context) : FileLoweringPass { return IrCompositeImpl(expression.startOffset, expression.endOffset, expression.type) } - if (expression.symbol == context.ir.symbols.immutableBinaryBlobOf) { - // Convert arguments of the binary blob to special IrConst structure, so that - // vararg lowering will not affect it. - val args = expression.getValueArgument(0) as? IrVararg - if (args == null) throw Error("varargs shall not be lowered yet") - if (args.elements.any { it is IrSpreadElement }) { - context.reportCompilationError("no spread elements allowed here", irFile, args) - } - val builder = StringBuilder() - args.elements.forEach { - if (it !is IrConst<*>) { - context.reportCompilationError( - "all elements of binary blob must be constants", irFile, it) - } - val value = when (it.kind) { - IrConstKind.Short -> (it.value as Short).toInt() - else -> - context.reportCompilationError("incorrect value for binary data: $it.value", irFile, it) - } - if (value < 0 || value > 0xff) - context.reportCompilationError("incorrect value for binary data: $value", irFile, it) - // Luckily, all values in range 0x00 .. 0xff represent valid UTF-16 symbols, - // block 0 (Basic Latin) and block 1 (Latin-1 Supplement) in - // Basic Multilingual Plane, so we could just append data "as is". - builder.append(value.toChar()) - } - expression.putValueArgument(0, IrConstImpl( - expression.startOffset, expression.endOffset, - context.ir.symbols.immutableBinaryBlob.descriptor.defaultType, - IrConstKind.String, builder.toString())) - } - return expression } }) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIr.proto b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIr.proto index c8fd37dc5d8..95fd95982f7 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIr.proto +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIr.proto @@ -251,7 +251,7 @@ message IrOperation { IrBreak break = 2; IrCall call = 3; IrCallableReference callable_reference = 4; - IrClassReference class_reference = 25; + IrClassReference class_reference = 27; IrConst const = 5; IrComposite composite = 26; IrContinue continue = 6;