From a1ee214c904f08a91d593ba59539afedd9a836a5 Mon Sep 17 00:00:00 2001 From: e5l Date: Tue, 19 Jul 2016 18:07:16 +0300 Subject: [PATCH] translator: object and class fields --- .../kotlinnative/translator/BlockCodegen.kt | 2 +- .../kotlinnative/translator/ClassCodegen.kt | 34 +++++--------- .../kotlinnative/translator/ObjectCodegen.kt | 3 +- .../kotlinnative/translator/StructCodegen.kt | 47 +++++++++++++------ .../test/kotlin/tests/input/classfields_1.txt | 2 + .../test/kotlin/tests/kotlin/classfields_1.kt | 21 +++++++++ 6 files changed, 70 insertions(+), 39 deletions(-) create mode 100644 translator/src/test/kotlin/tests/input/classfields_1.txt create mode 100644 translator/src/test/kotlin/tests/kotlin/classfields_1.kt diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt index 9b462bc73e8..e04b03a9f2e 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt @@ -138,7 +138,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM if (state.classes.containsKey(function)) { val descriptor = state.classes[function] ?: return null - val args = loadArgsIfRequired(names, descriptor.fields) + val args = loadArgsIfRequired(names, descriptor.constructorFields) return evaluateConstructorCallExpression(LLVMVariable(function, descriptor.type, scope = LLVMVariableScope()), args) } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt index 62f83ed5a01..aaeb81a5721 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt @@ -17,7 +17,7 @@ class ClassCodegen(override val state: TranslationState, override val variableMa val annotation: Boolean - override val size: Int + override var size: Int = 0 override val structName: String override val type: LLVMType = LLVMReferenceType(clazz.name.toString(), "class", byRef = true) @@ -27,52 +27,42 @@ class ClassCodegen(override val state: TranslationState, override val variableMa val parameterList = clazz.getPrimaryConstructorParameterList()?.parameters ?: listOf() annotation = descriptor.kind == ClassKind.ANNOTATION_CLASS - size = indexFields(descriptor, parameterList) + indexFields(descriptor, parameterList) + generateInnerFields(clazz.declarations) } - private fun indexFields(descriptor: ClassDescriptor, parameters: MutableList): Int { + private fun indexFields(descriptor: ClassDescriptor, parameters: MutableList) { if (annotation) { - return 0 + return } - var offset = 0 - var currentSize = 0 - for (field in parameters) { - val item = resolveType(field) - item.offset = offset + val item = resolveType(field, state.bindingContext.get(BindingContext.TYPE, field.typeReference)!!) + item.offset = fields.size + constructorFields.add(item) fields.add(item) fieldsIndex[item.label] = item - - currentSize += type.size - offset++ + size += type.size } when (descriptor.kind) { ClassKind.ENUM_CLASS -> { val item = LLVMClassVariable("enum_item", LLVMEnumItemType()) - item.offset = offset + item.offset = fields.size fields.add(item) fieldsIndex["enum_item"] = item - currentSize += type.size - offset++ + size += type.size } } - - return currentSize } fun generate() { if (annotation) { return } + generate(clazz.declarations) } - private fun generateStruct() { - val name = clazz.name!! - - codeBuilder.createClass(name, fields) - } } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt index 8cb84cd8c96..2c220c47ad0 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt @@ -12,12 +12,13 @@ import org.kotlinnative.translator.llvm.types.LLVMType class ObjectCodegen(override val state: TranslationState, override val variableManager: VariableManager, val objectDeclaration: KtObjectDeclaration, override val codeBuilder: LLVMBuilder) : StructCodegen(state, variableManager, objectDeclaration, state.bindingContext.get(BindingContext.CLASS, objectDeclaration) ?: throw TranslationException(), codeBuilder) { - override val size: Int = 0 + override var size: Int = 0 override val structName: String override val type: LLVMType = LLVMReferenceType(objectDeclaration.name.toString(), "class", byRef = true) init { structName = objectDeclaration.name!! + generateInnerFields(objectDeclaration.declarations) } fun generate() { diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt index 58a5c13a278..d565defc696 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt @@ -2,11 +2,9 @@ package org.kotlinnative.translator import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.psi.KtClassOrObject -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtNamedFunction -import org.jetbrains.kotlin.psi.KtParameter +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.types.KotlinType import org.kotlinnative.translator.llvm.* import org.kotlinnative.translator.llvm.types.LLVMCharType import org.kotlinnative.translator.llvm.types.LLVMReferenceType @@ -18,20 +16,21 @@ abstract class StructCodegen(open val state: TranslationState, open val variable val classDescriptor: ClassDescriptor, open val codeBuilder: LLVMBuilder) { - val plain: Boolean = false // TODO val fields = ArrayList() val fieldsIndex = HashMap() + + val constructorFields = ArrayList() + abstract val type: LLVMType - abstract val size: Int + abstract var size: Int var methods = HashMap() abstract val structName: String - fun generate(declarationList: List) { - + fun generate(declarations: List) { generateStruct() generatePrimaryConstructor() - for (declaration in declarationList) { + for (declaration in declarations) { when (declaration) { is KtNamedFunction -> { val function = FunctionCodegen(state, variableManager, declaration, codeBuilder) @@ -46,6 +45,25 @@ abstract class StructCodegen(open val state: TranslationState, open val variable } } + fun generateInnerFields(declarations: List) { + var offset = fields.size + + for (declaration in declarations) { + when (declaration) { + is KtProperty -> { + val ktType = state.bindingContext.get(BindingContext.TYPE, declaration.typeReference)!! + val field = resolveType(declaration, ktType) + field.offset = offset + offset++ + + fields.add(field) + fieldsIndex[field.label] = field + size += field.type.size + } + } + } + } + private fun generateStruct() { val name = classDescriptor.name.identifier @@ -62,7 +80,7 @@ abstract class StructCodegen(open val state: TranslationState, open val variable variableManager.addVariable("this", classVal, 0) argFields.add(classVal) - argFields.addAll(fields) + argFields.addAll(constructorFields) codeBuilder.addLLVMCode(LLVMFunctionDescriptor(classDescriptor.name.identifier, argFields, LLVMVoidType(), arm = state.arm)) @@ -80,7 +98,7 @@ abstract class StructCodegen(open val state: TranslationState, open val variable val thisVariable = LLVMVariable(thisField.label, thisField.type, thisField.label, LLVMRegisterScope(), pointer = 0) codeBuilder.loadArgument(thisVariable, false) - fields.forEach { + constructorFields.forEach { if (it.type !is LLVMReferenceType) { val loadVariable = LLVMVariable(it.label, it.type, it.label, LLVMRegisterScope()) codeBuilder.loadArgument(loadVariable) @@ -89,7 +107,7 @@ abstract class StructCodegen(open val state: TranslationState, open val variable } private fun generateAssignments() { - fields.forEach { + constructorFields.forEach { when (it.type) { is LLVMReferenceType -> { val classField = codeBuilder.getNewVariable(it.type, pointer = it.pointer + 1) @@ -118,10 +136,9 @@ abstract class StructCodegen(open val state: TranslationState, open val variable codeBuilder.memcpy(castedDst, castedSrc, size) } - protected fun resolveType(field: KtParameter): LLVMClassVariable { + protected fun resolveType(field: KtNamedDeclaration, ktType: KotlinType): LLVMClassVariable { val annotations = parseFieldAnnotations(field) - val ktType = state.bindingContext.get(BindingContext.TYPE, field.typeReference)!! val result = LLVMMapStandardType(field.name!!, ktType, LLVMRegisterScope()) if (result.type is LLVMReferenceType) { @@ -137,7 +154,7 @@ abstract class StructCodegen(open val state: TranslationState, open val variable return LLVMClassVariable(result.label, result.type, result.pointer) } - private fun parseFieldAnnotations(field: KtParameter): Set { + private fun parseFieldAnnotations(field: KtNamedDeclaration): Set { val result = HashSet() for (annotation in field.annotationEntries) { diff --git a/translator/src/test/kotlin/tests/input/classfields_1.txt b/translator/src/test/kotlin/tests/input/classfields_1.txt new file mode 100644 index 00000000000..20c7946e99b --- /dev/null +++ b/translator/src/test/kotlin/tests/input/classfields_1.txt @@ -0,0 +1,2 @@ +test_simple_field() == 0 +test_field_assignment(10) == 10 diff --git a/translator/src/test/kotlin/tests/kotlin/classfields_1.kt b/translator/src/test/kotlin/tests/kotlin/classfields_1.kt new file mode 100644 index 00000000000..f4b839a7dfd --- /dev/null +++ b/translator/src/test/kotlin/tests/kotlin/classfields_1.kt @@ -0,0 +1,21 @@ + +class WithFields(var i: Int) { + + var j: Int + + init { + this.j = 0 + } +} + +fun test_simple_field(): Int { + val i = WithFields(1) + return i.j +} + +fun test_field_assignment(i: Int): Int { + val k = WithFields(1) + k.j = i + + return k.j +}