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.<init>(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.<init>()"(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.<init>(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.<init>(Int;Int)"(i8* %tmp_4, i32 1, i32 %tmp_3) ; call primary constructor
  ret i8* %tmp_0
}

--------8<--------
This commit is contained in:
Vasily Levchenko
2016-11-24 10:03:06 +03:00
committed by vvlevchenko
parent 48ee81548e
commit 2a0d01191a
@@ -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)
}