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 8ecf67293a6..125c4ba8b48 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 @@ -49,6 +49,9 @@ internal class KonanLower(val context: Context) { phaser.phase(KonanPhase.LOWER_INNER_CLASSES) { InnerClassLowering(context).runOnFilePostfix(irFile) } + phaser.phase(KonanPhase.LOWER_INITIALIZERS) { + InitializersLowering(context).runOnFilePostfix(irFile) + } phaser.phase(KonanPhase.LOWER_CALLABLES) { CallableReferenceLowering(context).runOnFilePostfix(irFile) } 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 116afa093c1..45d700dd42b 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 @@ -23,6 +23,7 @@ enum class KonanPhase(val description: String, /* ... ... */ LOWER_ENUMS("Enum classes lowering"), /* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering"), /* ... ... */ LOWER_STRING_CONCAT("String concatenation lowering"), + /* ... ... */ LOWER_INITIALIZERS("Initializers lowering"), /* ... */ BITCODE("LLVM BitCode Generation"), /* ... ... */ RTTI("RTTI Generation"), /* ... ... */ CODEGEN("Code Generation"), diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt index 916b7184969..0e7a0261d1d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt @@ -5,6 +5,8 @@ import org.jetbrains.kotlin.backend.konan.ValueType import org.jetbrains.kotlin.backend.konan.isRepresentedAs import org.jetbrains.kotlin.backend.konan.llvm.functionName import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor +import org.jetbrains.kotlin.builtins.getFunctionalClassKind import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations @@ -140,9 +142,22 @@ internal val CallableDescriptor.allValueParameters: List return receivers + this.valueParameters } +internal val KotlinType.isFunctionOrKFunctionType: Boolean + get() { + val kind = constructor.declarationDescriptor?.getFunctionalClassKind() + return kind == FunctionClassDescriptor.Kind.Function || kind == FunctionClassDescriptor.Kind.KFunction + } + +internal val KotlinType.isKFunctionType: Boolean + get() { + val kind = constructor.declarationDescriptor?.getFunctionalClassKind() + return kind == FunctionClassDescriptor.Kind.KFunction + } + internal val FunctionDescriptor.isFunctionInvoke: Boolean get() { val dispatchReceiver = dispatchReceiverParameter ?: return false + assert (!dispatchReceiver.type.isKFunctionType) return dispatchReceiver.type.isFunctionType && this.isOperator && this.name == OperatorNameConventions.INVOKE diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 9589474cdae..c688f81ed6a 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -352,78 +352,25 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// override fun visitConstructor(constructorDeclaration: IrConstructor) { + context.log("visitConstructor : ${ir2string(constructorDeclaration)}") if (constructorDeclaration.descriptor.containingDeclaration.isIntrinsic) { // Do not generate any ctors for intrinsic classes. return } - - codegen.prologue(constructorDeclaration.descriptor) - val constructorDescriptor = constructorDeclaration.descriptor val classDescriptor = constructorDescriptor.constructedClass + if (constructorDescriptor.isPrimary) { + if (DescriptorUtils.isObject(classDescriptor)) { + if (!classDescriptor.isUnit()) { + val objectPtr = objectPtrByName(classDescriptor) - using(FunctionScope(constructorDeclaration)) { - - val thisPtr = currentCodeContext.genGetValue(classDescriptor.thisAsReceiverParameter) - - /** - * IR for kotlin.Any is: - * BLOCK_BODY - * DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' - * INSTANCE_INITIALIZER_CALL classDescriptor='Any' - * - * to avoid possible recursion we manually reject body generation for Any. - */ - - if (!skipConstructorBodyGeneration(constructorDeclaration)) { - constructorDeclaration.body?.let { - generateBody(it) + LLVMSetInitializer(objectPtr, codegen.kNullObjHeaderPtr) } } - - if (constructorDescriptor.isPrimary) { - if (DescriptorUtils.isObject(classDescriptor)) { - if (!classDescriptor.isUnit()) { - val objectPtr = objectPtrByName(classDescriptor) - - LLVMSetInitializer(objectPtr, codegen.kNullObjHeaderPtr) - } - } - val irOfCurrentClass = context.ir.moduleIndexForCodegen.classes[classDescriptor] - irOfCurrentClass!!.acceptChildrenVoid(object : IrElementVisitorVoid { - override fun visitElement(element: IrElement) { - element.acceptChildrenVoid(this) - } - - override fun visitField(fieldDeclaration: IrField) { - - val fieldDescriptor = fieldDeclaration.descriptor - fieldDeclaration.initializer?.let { - val value = evaluateExpression(it.expression) - val fieldPtr = fieldPtrOfClass(thisPtr, fieldDescriptor) - codegen.storeAnyGlobal(value, fieldPtr) - } - } - - override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer) { - generateBlockBody(declaration.body) - } - - override fun visitClass(declaration: IrClass) { - return - } - - override fun visitConstructor(declaration: IrConstructor) { - return - } - }) - } } - codegen.ret(null) - codegen.epilogue() - context.log("visitConstructor : ${ir2string(constructorDeclaration)}") + visitFunction(constructorDeclaration) } //-------------------------------------------------------------------------// @@ -434,25 +381,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// - private fun generateBlockBody(body: IrBlockBody) { - using(VariableScope()) { - body.statements.forEach { - generateStatement(it) - } - // TODO: write it properly! - if (codegen.constructedClass == null && !codegen.isAfterTerminator()) { - if (codegen.returnType == voidType) { - codegen.ret(null) - } else { - codegen.unreachable() - } - } - } - context.log("generateBlockBody : ${ir2string(body)}") - } - - //-------------------------------------------------------------------------// - /** * The scope of variable visibility. */ @@ -559,14 +487,29 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid override fun visitFunction(declaration: IrFunction) { context.log("visitFunction : ${ir2string(declaration)}") val body = declaration.body - if (declaration.descriptor.modality == Modality.ABSTRACT || body == null) - return + if (declaration.descriptor.modality == Modality.ABSTRACT || declaration.descriptor.isExternal || body == null) + return codegen.prologue(declaration.descriptor) using(FunctionScope(declaration)) { - generateBody(body) + using(VariableScope()) { + context.log("generateBlockBody : ${ir2string(body)}") + when (body) { + is IrBlockBody -> body.statements.forEach { generateStatement(it) } + is IrExpressionBody -> generateStatement(body.expression) + is IrSyntheticBody -> throw AssertionError("Synthetic body ${body.kind} has not been lowered") + else -> TODO(ir2string(body)) + } + } + } + + if (!codegen.isAfterTerminator()) { + if (codegen.returnType == voidType) + codegen.ret(null) + else + codegen.unreachable() } codegen.epilogue() @@ -665,13 +608,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private fun IrStatement.generate() = generateStatement(this) - private fun generateBody(body: IrBody) { - when (body) { - is IrBlockBody -> generateBlockBody(body) - else -> TODO(ir2string(body)) - } - } - //-------------------------------------------------------------------------// private fun evaluateGetObjectValue(value: IrGetObjectValue): LLVMValueRef { @@ -1895,22 +1831,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// - private fun skipConstructorBodyGeneration(declaration: IrConstructor): Boolean { - var skipBody = false - declaration.acceptChildrenVoid(object : IrElementVisitorVoid { - override fun visitElement(element: IrElement) { - element.acceptChildrenVoid(this) - } - - override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) { - skipBody = expression.descriptor == declaration.descriptor - } - }) - return skipBody - } - - //-------------------------------------------------------------------------// - fun appendLlvmUsed(args: List) { if (args.isEmpty()) return diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt index d847e633147..07763b0b071 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt @@ -5,6 +5,7 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.ir.* +import org.jetbrains.kotlin.builtins.getFunctionalClassKind import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations @@ -86,7 +87,7 @@ private class CallableReferencesUnbinder(val lower: CallableReferenceLowering, } override fun visitCallableReference(expression: IrCallableReference): IrExpression { - assert (expression.type.isFunctionType) + assert (expression.type.isFunctionOrKFunctionType) val descriptor = expression.descriptor val boundArgs = expression.getArguments() diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InitializersLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InitializersLowering.kt new file mode 100644 index 00000000000..9abe0566dbc --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InitializersLowering.kt @@ -0,0 +1,100 @@ +package org.jetbrains.kotlin.backend.konan.lower + +import org.jetbrains.kotlin.backend.common.ClassLoweringPass +import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl +import org.jetbrains.kotlin.ir.expressions.IrBlockBody +import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall +import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall +import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl +import org.jetbrains.kotlin.ir.util.transformFlat +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid + +internal class InitializersLowering(val context: Context) : ClassLoweringPass { + override fun lower(irClass: IrClass) { + InitializersTransformer(irClass).lowerInitializers() + } + + private inner class InitializersTransformer(val irClass: IrClass) { + val fieldInitializers = mutableListOf() + val initializers = mutableListOf() + + fun lowerInitializers() { + collectAndRemoveInitializers() + lowerConstructors() + } + + object STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER : + IrStatementOriginImpl("ANONYMOUS_INITIALIZER") + + private fun collectAndRemoveInitializers() { + irClass.transformChildrenVoid(object : IrElementTransformerVoid() { + override fun visitClass(declaration: IrClass): IrStatement { + // Skip nested. + return declaration + } + + override fun visitField(declaration: IrField): IrStatement { + val initializer = declaration.initializer ?: return declaration + val propertyDescriptor = declaration.descriptor + val startOffset = initializer.startOffset + val endOffset = initializer.endOffset + fieldInitializers.add(IrBlockImpl(startOffset, endOffset, context.builtIns.unitType, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER, + listOf( + IrSetFieldImpl(startOffset, endOffset, propertyDescriptor, + IrGetValueImpl(startOffset, endOffset, irClass.descriptor.thisAsReceiverParameter), + initializer.expression, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER)))) + return IrFieldImpl(declaration.startOffset, declaration.endOffset, declaration.origin, propertyDescriptor) + } + }) + + irClass.declarations.transformFlat { + if (it !is IrAnonymousInitializer) + null + else { + initializers.add(IrBlockImpl(it.startOffset, it.endOffset, + context.builtIns.unitType, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER, it.body.statements)) + listOf() + } + } + } + + private fun lowerConstructors() { + irClass.transformChildrenVoid(object : IrElementTransformerVoid() { + override fun visitClass(declaration: IrClass): IrStatement { + // Skip nested. + return declaration + } + + override fun visitConstructor(declaration: IrConstructor): IrStatement { + val blockBody = declaration.body as? IrBlockBody ?: throw AssertionError("Unexpected constructor body: ${declaration.body}") + + blockBody.statements.transformFlat { + when { + it is IrInstanceInitializerCall -> fieldInitializers + initializers + /** + * IR for kotlin.Any is: + * BLOCK_BODY + * DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + * INSTANCE_INITIALIZER_CALL classDescriptor='Any' + * + * to avoid possible recursion we manually reject body generation for Any. + */ + it is IrDelegatingConstructorCall && irClass.descriptor == context.builtIns.any + && it.descriptor == declaration.descriptor -> listOf() + else -> null + } + } + + return declaration + } + }) + } + } +} \ No newline at end of file