Constructor (w/o body) (#74)

This commit is contained in:
vvlevchenko
2016-11-19 19:45:21 +03:00
committed by Nikolay Igotti
parent 0e1ac89dbf
commit 5161155934
5 changed files with 85 additions and 49 deletions
@@ -43,31 +43,7 @@ internal class CodeGenerator(override val context:Context) : ContextUtils {
}
}
/* HACK: */
var currentClass:ClassDescriptor? = null
/* constructor */
fun initFunction(declaration: IrConstructor) {
function(declaration)
val thisPtr = bitcast(pointerType(classType(declaration.descriptor.containingDeclaration)), load(thisVariable(), newVar()), newVar())
/**
* TODO: check shadowing.
*/
declaration.descriptor.containingDeclaration.fields.forEachIndexed { i, descriptor ->
val name = descriptor.name.asString()
if (!declaration.descriptor.valueParameters.any { it -> it.name.asString() == name })
return@forEachIndexed
val ptr = LLVMBuildStructGEP(context.llvmBuilder, thisPtr, i, newVar())
val value = load(variable(name)!!, newVar())
val typePtr = bitcast(pointerType(LLVMTypeOf(value)), ptr!!, newVar())
store(value, typePtr!!)
}
currentClass = declaration.descriptor.constructedClass
}
fun fields(descriptor: ClassDescriptor):List<PropertyDescriptor> = descriptor.fields
private fun prolog(declaration: IrFunction): LLVMOpaqueValue? {
variableIndex = 0
@@ -171,7 +147,7 @@ internal class CodeGenerator(override val context:Context) : ContextUtils {
fun thisVariable() = variable("this")!!
fun param(fn: FunctionDescriptor?, i: Int): LLVMOpaqueValue? = LLVMGetParam(fn!!.llvmFunction.getLlvmValue(), i)
fun indexInClass(p:PropertyDescriptor):Int = currentClass!!.fields.indexOf(p)
fun indexInClass(p:PropertyDescriptor):Int = (p.containingDeclaration as ClassDescriptor).fields.indexOf(p)
fun basicBlock(): LLVMOpaqueBasicBlock? = LLVMAppendBasicBlock(currentFunction!!.llvmFunction.getLlvmValue(), currentFunction!!.bbLabel())
@@ -148,17 +148,28 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
override fun visitConstructor(declaration: IrConstructor) {
codegen.initFunction(declaration)
val thisValue = codegen.variable("this")
//super.visitConstructor(declaration)
/**
* %this = alloca i8*
* store i8* %0, i8** %this <- prolog
*
* %tmp0 = load i8*, i8** %this <- epilog
* ret i8* %tmp0
*/
codegen.ret(codegen.load(thisValue!!, codegen.newVar()))
codegen.function(declaration)
val classDescriptor = DescriptorUtils.getContainingClass(declaration.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!!)
}
/* TODO: body */
codegen.ret(thisPtr)
logger.log("visitConstructor : ${ir2string(declaration)}")
}
@@ -450,7 +461,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
logger.log("evaluateGetField : ${ir2string(value)}")
if (value.descriptor.dispatchReceiverParameter != null) {
val thisPtr = codegen.load(codegen.thisVariable(), codegen.newVar())
return codegen.load(fieldPtrOfClass(thisPtr, value)!!, codegen.newVar())
return codegen.load(fieldPtrOfClass(thisPtr, value.descriptor)!!, codegen.newVar())
}
else {
val ptr = LLVMGetNamedGlobal(context.llvmModule, value.descriptor.symbolName)!!
@@ -465,7 +476,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val valueToAssign = evaluateExpression(codegen.newVar(), value.value)!!
if (value.descriptor.dispatchReceiverParameter != null) {
val thisPtr = codegen.load(codegen.thisVariable(), codegen.newVar())
return codegen.store(valueToAssign, fieldPtrOfClass(thisPtr, value)!!)
return codegen.store(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor)!!)
}
else {
val globalValue = LLVMGetNamedGlobal(context.llvmModule, value.descriptor.symbolName)
@@ -507,14 +518,14 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
}
*/
private fun fieldPtrOfClass(thisPtr: LLVMOpaqueValue, value: IrFieldAccessExpression): LLVMOpaqueValue? {
private fun fieldPtrOfClass(thisPtr: LLVMOpaqueValue, value: PropertyDescriptor): LLVMOpaqueValue? {
val objHeaderPtr = codegen.bitcast(kObjHeaderPtr, thisPtr, codegen.newVar())
val typePtr = pointerType(codegen.classType(codegen.currentClass!!))
val typePtr = pointerType(codegen.classType(value.containingDeclaration as ClassDescriptor))
memScoped {
val args = allocNativeArrayOf(LLVMOpaqueValue, Int32(1).getLlvmValue())
val args = allocNativeArrayOf(LLVMOpaqueValue, kImmOne)
val objectPtr = LLVMBuildGEP(codegen.context.llvmBuilder, objHeaderPtr, args[0], 1, codegen.newVar())
val typedObjPtr = codegen.bitcast(typePtr, objectPtr!!, codegen.newVar())
val fieldPtr = LLVMBuildStructGEP(codegen.context.llvmBuilder, typedObjPtr, codegen.indexInClass(value.descriptor), codegen.newVar())
val fieldPtr = LLVMBuildStructGEP(codegen.context.llvmBuilder, typedObjPtr, codegen.indexInClass(value), codegen.newVar())
return fieldPtr
}
}
@@ -643,6 +654,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
private val kLteq0 = Name.identifier("LTEQ0")
private val kNot = Name.identifier("NOT")
private val kImmZero = LLVMConstInt(LLVMInt32Type(), 0, 1)!!
private val kImmOne = LLVMConstInt(LLVMInt32Type(), 1, 1)!!
private val kTrue = LLVMConstInt(LLVMInt1Type(), 1, 1)!!
private val kFalse = LLVMConstInt(LLVMInt1Type(), 0, 1)!!
+11 -6
View File
@@ -209,18 +209,23 @@ task run() {
task sum (type:UnitKonanTest) {
source = "codegen/function/sum.kt"
}
// FIXME (https://github.com/JetBrains/kotlin-native/pull/74)
//task method_call(type: UnitKonanTest) {
// source = "codegen/object/method_call.kt"
//}
task method_call(type: UnitKonanTest) {
source = "codegen/object/method_call.kt"
}
task fields(type: UnitKonanTest) {
source = "codegen/object/fields.kt"
}
/*task objectInitialization(type: UnitKonanTest) {
task constructor(type: UnitKonanTest) {
source = "codegen/object/constructor.kt"
}
task objectInitialization(type: UnitKonanTest) {
source = "codegen/object/initialization.kt"
}*/
}
/* task objectBasic(type: KonanTest) {
source = "$codegen/klass/basic.kt"
@@ -0,0 +1,38 @@
#include <stdint.h>
extern void *resolve_symbol(const char*);
extern void *AllocInstance(void *, int32_t);
#define CHECK_OBJ(obj, info) if ((uintptr_t)*(obj) != (uintptr_t)(info)) return 1;
#define MAGIC0 0xdeadbeef
#define MAGIC1 0xcafebabe
#define MAGIC2 0xabadbabe
int
run_test() {
void *a_type_info = resolve_symbol("ktype:A");
void *(*a_init)(void *) = resolve_symbol("kfun:A.<init>()");
void *b_type_info = resolve_symbol("ktype:B");
void *(*b_init)(void *, int) = resolve_symbol("kfun:B.<init>(Int)");
int (*b_get_a)(void *) = resolve_symbol("kfun:B.<get-a>()");
void *c_type_info = resolve_symbol("ktype:C");
void *(*c_init)(void *, int, int) = resolve_symbol("kfun:C.<init>(Int;Int)");
int (*c_get_a)(void *) = resolve_symbol("kfun:C.<get-a>()");
void **a = (void **)AllocInstance(a_type_info, 1);
CHECK_OBJ(a, a_type_info)
void **b = (void **)AllocInstance(b_type_info, 1);
CHECK_OBJ(b, b_type_info)
void *b_obj = b_init((void *)b, MAGIC0);
CHECK_OBJ(b, b_type_info)
if (b_get_a(b_obj) != MAGIC0) return 1;
void **c = (void **)AllocInstance(c_type_info, 1);
CHECK_OBJ(c, c_type_info)
void *c_obj = c_init((void *)c, 0xcafebabe, 0xabadbabe);
CHECK_OBJ(c, c_type_info)
if (c_get_a(c_obj) != MAGIC1) return 1;
return 0;
}
@@ -0,0 +1,5 @@
class A()
class B(val a:Int)
class C(val a:Int, b:Int)