From 2a0d01191a2afdacb45562ef46766f4276e3ec5d Mon Sep 17 00:00:00 2001 From: Vasily Levchenko Date: Thu, 24 Nov 2016 10:03:06 +0300 Subject: [PATCH] CODEGEN: primary/secondary constructor fields initialization for code: --------8<-------- >cat ../backend.native/tests/codegen/object/fields1.kt class B(val a:Int, b:Int) { constructor(pos:Int):this(1, pos) {} val pos = b + 1 } fun primaryConstructorCall(a:Int, b:Int) = B(a, b).pos fun secondaryConstructorCall(a:Int) = B(a).pos --------8<-------- translator generates: --------8<-------- ; ModuleID = '../backend.native/tests/codegen/object/fields1.kt.bc' target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.12.0" ... define i8* @"kfun:B.(Int;Int)"(i8*, i32, i32) { ;primary constructor entry: %this = alloca i8* store i8* %0, i8** %this %a = alloca i32 store i32 %1, i32* %a %b = alloca i32 store i32 %2, i32* %b %tmp_0 = load i8*, i8** %this %tmp_2 = load i8*, i8** %this %tmp_1 = call i8* @"kfun:kotlin.Any.()"(i8* %tmp_2) %tmp_3 = bitcast i8* %tmp_0 to %struct.ObjHeader* %tmp_4 = getelementptr %struct.ObjHeader, %struct.ObjHeader* %tmp_3, i32 1 %tmp_5 = bitcast %struct.ObjHeader* %tmp_4 to %"kclass:B"* %tmp_6 = getelementptr inbounds %"kclass:B", %"kclass:B"* %tmp_5, i32 0, i32 0 %tmp_7 = load i32, i32* %a store i32 %tmp_7, i32* %tmp_6 %tmp_8 = bitcast i8* %tmp_0 to %struct.ObjHeader* %tmp_9 = getelementptr %struct.ObjHeader, %struct.ObjHeader* %tmp_8, i32 1 %tmp_10 = bitcast %struct.ObjHeader* %tmp_9 to %"kclass:B"* %tmp_11 = getelementptr inbounds %"kclass:B", %"kclass:B"* %tmp_10, i32 0, i32 1 %tmp_13 = load i32, i32* %b %tmp_12 = call i32 @Kotlin_Int_plus_Int(i32 %tmp_13, i32 1) store i32 %tmp_12, i32* %tmp_11 ; <-- store b + 1 value to pos field ret i8* %tmp_0 } ... define i8* @"kfun:B.(Int)"(i8*, i32) { ;secondary constructor entry: %this = alloca i8* store i8* %0, i8** %this %pos = alloca i32 store i32 %1, i32* %pos %tmp_0 = load i8*, i8** %this %tmp_3 = load i32, i32* %pos %tmp_4 = load i8*, i8** %this %tmp_1 = call i8* @"kfun:B.(Int;Int)"(i8* %tmp_4, i32 1, i32 %tmp_3) ; call primary constructor ret i8* %tmp_0 } --------8<-------- --- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 61 +++++++++++-------- 1 file changed, 36 insertions(+), 25 deletions(-) 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 d10243c5fd3..323e85c068f 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 @@ -7,6 +7,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.LazyClassReceiverParameterDescriptor import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor +import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* @@ -20,6 +21,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils @@ -149,26 +151,11 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// - override fun visitConstructor(declaration: IrConstructor) { - codegen.function(declaration) - val classDescriptor = DescriptorUtils.getContainingClass(declaration.descriptor) + override fun visitConstructor(constructorDeclaration: IrConstructor) { + codegen.function(constructorDeclaration) + val classDescriptor = DescriptorUtils.getContainingClass(constructorDeclaration.descriptor) val thisPtr = codegen.load(codegen.thisVariable(), codegen.newVar()) - val typeOfClass = classDescriptor!!.defaultType - val names = typeOfClass.memberScope.getVariableNames() - val fields = codegen.fields(classDescriptor).toSet() - declaration.descriptor.valueParameters - .filter { names.contains(it.name) } // selects only parameters that match with declared class variables - .map { // maps parameter to list descriptors - val variables = typeOfClass.memberScope.getContributedVariables(it.name, NoLookupLocation.FROM_BACKEND) - assert(variables.size == 1) - variables.first() } - .filter {fields.contains(it)} // filter only fields that contains backing store - .forEach { // store parameters to backing storage - val fieldPtr = fieldPtrOfClass(thisPtr, it) - val variable = codegen.variable(it.name.asString()) - val value = codegen.load(variable!!, codegen.newVar()) - codegen.store(value, fieldPtr!!) - } + /** * IR for kotlin.Any is: * BLOCK_BODY @@ -178,11 +165,35 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid * to avoid possible recursion we manually reject body generation for Any. */ - if (!skipConstructorBodyGeneration(declaration)) - declaration.acceptChildrenVoid(this) + if (!skipConstructorBodyGeneration(constructorDeclaration)) + constructorDeclaration.acceptChildrenVoid(this) + + if (constructorDeclaration.descriptor.isPrimary) { + val irOfCurrentClass = context.moduleIndex.classes[classDescriptor!!.classId] + irOfCurrentClass!!.acceptChildrenVoid(object : IrElementVisitorVoid { + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitField(fieldDeclaration: IrField) { + + val fieldDescriptor = fieldDeclaration.descriptor + val fieldPtr = fieldPtrOfClass(thisPtr, fieldDescriptor) + var value:LLVMValueRef? = null + if (constructorDeclaration.descriptor.valueParameters.any{ it.name == fieldDescriptor.name }) { + val variable = codegen.variable(fieldDescriptor.name.asString()) + value = codegen.load(variable!!, codegen.newVar()) + } + else { + value = evaluateExpression(codegen.newVar(), fieldDeclaration.initializer) + } + codegen.store(value!!, fieldPtr!!) + } + }) + } codegen.ret(thisPtr) - logger.log("visitConstructor : ${ir2string(declaration)}") + logger.log("visitConstructor : ${ir2string(constructorDeclaration)}") } @@ -328,7 +339,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid return } - super.visitField(expression) + //super.visitField(expression) } @@ -397,8 +408,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid logger.log("evaluateGetValue : $tmpVariableName = ${ir2string(value)}") when (value.descriptor) { is LocalVariableDescriptor, - is ValueParameterDescriptor, - is IrTemporaryVariableDescriptor -> { + is IrTemporaryVariableDescriptor, + is ValueParameterDescriptor -> { val variable = codegen.variable(value.descriptor.name.asString()) return codegen.load(variable!!, tmpVariableName) }