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:
committed by
vvlevchenko
parent
48ee81548e
commit
2a0d01191a
+36
-25
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user