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.*
|
||||||
import org.jetbrains.kotlin.descriptors.impl.LazyClassReceiverParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.LazyClassReceiverParameterDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
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.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
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.ir.visitors.acceptVoid
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
@@ -149,26 +151,11 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
override fun visitConstructor(declaration: IrConstructor) {
|
override fun visitConstructor(constructorDeclaration: IrConstructor) {
|
||||||
codegen.function(declaration)
|
codegen.function(constructorDeclaration)
|
||||||
val classDescriptor = DescriptorUtils.getContainingClass(declaration.descriptor)
|
val classDescriptor = DescriptorUtils.getContainingClass(constructorDeclaration.descriptor)
|
||||||
val thisPtr = codegen.load(codegen.thisVariable(), codegen.newVar())
|
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:
|
* IR for kotlin.Any is:
|
||||||
* BLOCK_BODY
|
* BLOCK_BODY
|
||||||
@@ -178,11 +165,35 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
* to avoid possible recursion we manually reject body generation for Any.
|
* to avoid possible recursion we manually reject body generation for Any.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!skipConstructorBodyGeneration(declaration))
|
if (!skipConstructorBodyGeneration(constructorDeclaration))
|
||||||
declaration.acceptChildrenVoid(this)
|
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)
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
super.visitField(expression)
|
//super.visitField(expression)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,8 +408,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
logger.log("evaluateGetValue : $tmpVariableName = ${ir2string(value)}")
|
logger.log("evaluateGetValue : $tmpVariableName = ${ir2string(value)}")
|
||||||
when (value.descriptor) {
|
when (value.descriptor) {
|
||||||
is LocalVariableDescriptor,
|
is LocalVariableDescriptor,
|
||||||
is ValueParameterDescriptor,
|
is IrTemporaryVariableDescriptor,
|
||||||
is IrTemporaryVariableDescriptor -> {
|
is ValueParameterDescriptor -> {
|
||||||
val variable = codegen.variable(value.descriptor.name.asString())
|
val variable = codegen.variable(value.descriptor.name.asString())
|
||||||
return codegen.load(variable!!, tmpVariableName)
|
return codegen.load(variable!!, tmpVariableName)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user