From 62e444c571c22d1b8eaca4af6c04c0c92ec11574 Mon Sep 17 00:00:00 2001 From: Alexey Stepanov Date: Tue, 19 Jul 2016 14:21:56 +0300 Subject: [PATCH] translator: add object declarations --- .../kotlinnative/translator/ClassCodegen.kt | 141 ++--------------- .../kotlinnative/translator/FileTranslator.kt | 15 +- .../translator/FunctionCodegen.kt | 4 +- .../kotlinnative/translator/ObjectCodegen.kt | 28 ++++ .../kotlinnative/translator/StructCodegen.kt | 147 ++++++++++++++++++ .../translator/TranslationState.kt | 1 + .../translator/llvm/LLVMBuilder.kt | 5 + .../src/test/kotlin/tests/input/object_1.txt | 1 + .../src/test/kotlin/tests/kotlin/object_1.kt | 6 + 9 files changed, 213 insertions(+), 135 deletions(-) create mode 100644 translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt create mode 100644 translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt create mode 100644 translator/src/test/kotlin/tests/input/object_1.txt create mode 100644 translator/src/test/kotlin/tests/kotlin/object_1.kt diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt index 20a22481620..9f8b8f6ade4 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt @@ -3,24 +3,27 @@ package org.kotlinnative.translator import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.psi.KtClass -import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.resolve.BindingContext import org.kotlinnative.translator.exceptions.TranslationException -import org.kotlinnative.translator.llvm.* -import org.kotlinnative.translator.llvm.types.* -import java.util.* +import org.kotlinnative.translator.llvm.LLVMBuilder +import org.kotlinnative.translator.llvm.LLVMClassVariable +import org.kotlinnative.translator.llvm.types.LLVMEnumItemType +import org.kotlinnative.translator.llvm.types.LLVMReferenceType +import org.kotlinnative.translator.llvm.types.LLVMType -class ClassCodegen(val state: TranslationState, val variableManager: VariableManager, val clazz: KtClass, val codeBuilder: LLVMBuilder) { +class ClassCodegen(override val state: TranslationState, override val variableManager: VariableManager, val clazz: KtClass, override val codeBuilder: LLVMBuilder) : + StructCodegen(state, variableManager, state.bindingContext.get(BindingContext.CLASS, clazz) ?: throw TranslationException(), codeBuilder) { val annotation: Boolean - val fields = ArrayList() - val fieldsIndex = HashMap() - val type: LLVMType = LLVMReferenceType(clazz.name.toString(), "class", byRef = true) - val size: Int - var methods = HashMap() + + override val size: Int + override val structName: String + override val type: LLVMType = LLVMReferenceType(clazz.name.toString(), "class", byRef = true) + init { + structName = clazz.name.toString() val descriptor = state.bindingContext.get(BindingContext.CLASS, clazz) ?: throw TranslationException() val parameterList = clazz.getPrimaryConstructorParameterList()?.parameters ?: listOf() @@ -66,22 +69,7 @@ class ClassCodegen(val state: TranslationState, val variableManager: VariableMan return } - generateStruct() - generatePrimaryConstructor() - - for (declaration in clazz.declarations) { - when (declaration) { - is KtNamedFunction -> { - val function = FunctionCodegen(state, variableManager, declaration, codeBuilder) - methods.put(function.name, function) - } - } - } - val classVal = LLVMVariable("classvariable.this", type, pointer = 1) - variableManager.addVariable("this", classVal, 0) - for (function in methods.values) { - function.generate(classVal) - } + generate(clazz.declarations) } private fun generateStruct() { @@ -89,105 +77,4 @@ class ClassCodegen(val state: TranslationState, val variableManager: VariableMan codeBuilder.createClass(name, fields) } - - private fun generatePrimaryConstructor() { - val classData = state.bindingContext.get(BindingContext.CLASS, clazz) - val classKind = classData?.kind - //if (classKind == ClassKind.ENUM_CLASS) - val argFields = ArrayList() - val refType = type.makeClone() as LLVMReferenceType - refType.addParam("sret") - refType.byRef = true - - val classVal = LLVMVariable("classvariable.this", type, pointer = 1) - variableManager.addVariable("this", classVal, 0) - - argFields.add(classVal) - argFields.addAll(fields) - - codeBuilder.addLLVMCode(LLVMFunctionDescriptor(clazz.name!!, argFields, LLVMVoidType(), arm = state.arm)) - - codeBuilder.addStartExpression() - generateLoadArguments(classVal) - generateAssignments() - generateReturn() - codeBuilder.addAnyReturn(LLVMVoidType()) - codeBuilder.addEndExpression() - } - - private fun generateLoadArguments(thisField: LLVMVariable) { - - val thisVariable = LLVMVariable(thisField.label, thisField.type, thisField.label, LLVMRegisterScope(), pointer = 0) - codeBuilder.loadArgument(thisVariable, false) - - fields.forEach { - if (it.type !is LLVMReferenceType) { - val loadVariable = LLVMVariable(it.label, it.type, it.label, LLVMRegisterScope()) - codeBuilder.loadArgument(loadVariable) - } - } - } - - private fun generateAssignments() { - fields.forEach { - when (it.type) { - is LLVMReferenceType -> { - val classField = codeBuilder.getNewVariable(it.type, pointer = it.pointer + 1) - codeBuilder.loadClassField(classField, LLVMVariable("classvariable.this.addr", type, scope = LLVMRegisterScope(), pointer = 1), (it as LLVMClassVariable).offset) - codeBuilder.storeVariable(classField, it) - } - else -> { - val argument = codeBuilder.getNewVariable(it.type, it.pointer) - codeBuilder.loadVariable(argument, LLVMVariable("${it.label}.addr", it.type, scope = LLVMRegisterScope(), pointer = it.pointer + 1)) - val classField = codeBuilder.getNewVariable(it.type, pointer = 1) - codeBuilder.loadClassField(classField, LLVMVariable("classvariable.this.addr", type, scope = LLVMRegisterScope(), pointer = 1), (it as LLVMClassVariable).offset) - codeBuilder.storeVariable(classField, argument) - } - } - - } - } - - private fun generateReturn() { - val dst = LLVMVariable("classvariable.this", type, scope = LLVMRegisterScope(), pointer = 1) - val src = LLVMVariable("classvariable.this.addr", type, scope = LLVMRegisterScope(), pointer = 1) - - val castedDst = codeBuilder.bitcast(dst, LLVMVariable("", LLVMCharType(), pointer = 1)) - val castedSrc = codeBuilder.bitcast(src, LLVMVariable("", LLVMCharType(), pointer = 1)) - - codeBuilder.memcpy(castedDst, castedSrc, size) - } - - private fun resolveType(field: KtParameter): 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) { - val type = result.type as LLVMReferenceType - type.prefix = "class" - type.byRef = true - } - - if (annotations.contains("Plain")) { - result.pointer = 0 - } - - return LLVMClassVariable(result.label, result.type, result.pointer) - } - - private fun parseFieldAnnotations(field: KtParameter): Set { - val result = HashSet() - - for (annotation in field.annotationEntries) { - val annotationDescriptor = state.bindingContext.get(BindingContext.ANNOTATION, annotation) - val type = annotationDescriptor?.type.toString() - - result.add(type) - } - - return result - } - } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/FileTranslator.kt b/translator/src/main/kotlin/org/kotlinnative/translator/FileTranslator.kt index 6a39fd060fb..7a158a8069e 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/FileTranslator.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/FileTranslator.kt @@ -1,9 +1,6 @@ package org.kotlinnative.translator -import org.jetbrains.kotlin.psi.KtClass -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtNamedFunction -import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.psi.* import org.kotlinnative.translator.llvm.LLVMBuilder class FileTranslator(val state: TranslationState, val file: KtFile) { @@ -31,6 +28,10 @@ class FileTranslator(val state: TranslationState, val file: KtFile) { val property = PropertyCodegen(state, VariableManager(state.globalVariableCollection), declaration, codeBuilder) state.properties.put(declaration.name!!, property) } + is KtObjectDeclaration -> { + val property = ObjectCodegen(state, VariableManager(state.globalVariableCollection), declaration, codeBuilder) + state.objects.put(declaration.name!!, property) + } } } @@ -38,6 +39,10 @@ class FileTranslator(val state: TranslationState, val file: KtFile) { property.generate() } + for (objectDeclaration in state.objects.values) { + objectDeclaration.generate() + } + for (clazz in state.classes.values) { clazz.generate() } @@ -45,8 +50,6 @@ class FileTranslator(val state: TranslationState, val file: KtFile) { for (function in state.functions.values) { function.generate() } - } - } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt index ffe23f884c4..93f53b57009 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt @@ -184,14 +184,14 @@ class FunctionCodegen(val state: TranslationState, val variableManager: Variable val receiver = variableManager.getLLVMvalue(receiverName)!! - val clazz = state.classes[(receiver.type as LLVMReferenceType).type]!! + val clazz = state.classes[(receiver.type as LLVMReferenceType).type] ?: state.objects[(receiver.type as LLVMReferenceType).type]!! val field = clazz.fieldsIndex[selectorName] if (field != null) { val result = codeBuilder.getNewVariable(field.type, pointer = 1) codeBuilder.loadClassField(result, receiver, field.offset) return result } else { - val methodName = clazz.clazz.name.toString() + '.' + selectorName.substringBefore('(') + val methodName = clazz.structName + '.' + selectorName.substringBefore('(') val method = clazz.methods[methodName]!! val returnType = clazz.methods[methodName]!!.returnType.type val methodArgs = mutableListOf(receiver) diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt new file mode 100644 index 00000000000..d34292d6097 --- /dev/null +++ b/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt @@ -0,0 +1,28 @@ +package org.kotlinnative.translator + +import org.jetbrains.kotlin.psi.KtObjectDeclaration +import org.jetbrains.kotlin.resolve.BindingContext +import org.kotlinnative.translator.exceptions.TranslationException +import org.kotlinnative.translator.llvm.LLVMBuilder +import org.kotlinnative.translator.llvm.LLVMVariable +import org.kotlinnative.translator.llvm.LLVMVariableScope +import org.kotlinnative.translator.llvm.types.LLVMReferenceType +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, state.bindingContext.get(BindingContext.CLASS, objectDeclaration) ?: throw TranslationException(), codeBuilder) { + override val size: Int = 0 + override val structName: String + override val type: LLVMType = LLVMReferenceType(objectDeclaration.name.toString(), "class", byRef = true) + + init { + structName = objectDeclaration.name!! + } + + fun generate() { + generate(objectDeclaration.declarations) + val classInstance = LLVMVariable("object.instance.${structName}", type, objectDeclaration.name, LLVMVariableScope()) + codeBuilder.addGlobalIntialize(classInstance, type); + variableManager.addGlobalVariable(structName, classInstance) + } +} diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt new file mode 100644 index 00000000000..847acfb94ed --- /dev/null +++ b/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt @@ -0,0 +1,147 @@ +package org.kotlinnative.translator + +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtNamedFunction +import org.jetbrains.kotlin.psi.KtParameter +import org.jetbrains.kotlin.resolve.BindingContext +import org.kotlinnative.translator.llvm.* +import org.kotlinnative.translator.llvm.types.LLVMCharType +import org.kotlinnative.translator.llvm.types.LLVMReferenceType +import org.kotlinnative.translator.llvm.types.LLVMType +import org.kotlinnative.translator.llvm.types.LLVMVoidType +import java.util.* + +abstract class StructCodegen(open val state: TranslationState, open val variableManager: VariableManager, open val classDescriptor: ClassDescriptor, open val codeBuilder: LLVMBuilder) { + + val plain: Boolean = false // TODO + val fields = ArrayList() + val fieldsIndex = HashMap() + abstract val type: LLVMType + abstract val size: Int + var methods = HashMap() + abstract val structName: String + + + fun generate(declarationList: List) { + generateStruct() + generatePrimaryConstructor() + + for (declaration in declarationList) { + when (declaration) { + is KtNamedFunction -> { + val function = FunctionCodegen(state, variableManager, declaration, codeBuilder) + methods.put(function.name, function) + } + } + } + val classVal = LLVMVariable("classvariable.this", type, pointer = 1) + variableManager.addVariable("this", classVal, 0) + for (function in methods.values) { + function.generate(classVal) + } + } + + private fun generateStruct() { + val name = classDescriptor.name.identifier + + codeBuilder.createClass(name, fields) + } + + private fun generatePrimaryConstructor() { + val argFields = ArrayList() + val refType = type.makeClone() as LLVMReferenceType + refType.addParam("sret") + refType.byRef = true + + val classVal = LLVMVariable("classvariable.this", type, pointer = 1) + variableManager.addVariable("this", classVal, 0) + + argFields.add(classVal) + argFields.addAll(fields) + + codeBuilder.addLLVMCode(LLVMFunctionDescriptor(classDescriptor.name.identifier, argFields, LLVMVoidType(), arm = state.arm)) + + codeBuilder.addStartExpression() + generateLoadArguments(classVal) + generateAssignments() + generateReturn() + codeBuilder.addAnyReturn(LLVMVoidType()) + codeBuilder.addEndExpression() + } + + private fun generateLoadArguments(thisField: LLVMVariable) { + + val thisVariable = LLVMVariable(thisField.label, thisField.type, thisField.label, LLVMRegisterScope(), pointer = 0) + codeBuilder.loadArgument(thisVariable, false) + + fields.forEach { + if (it.type !is LLVMReferenceType) { + val loadVariable = LLVMVariable(it.label, it.type, it.label, LLVMRegisterScope()) + codeBuilder.loadArgument(loadVariable) + } + } + } + + private fun generateAssignments() { + fields.forEach { + when (it.type) { + is LLVMReferenceType -> { + val classField = codeBuilder.getNewVariable(it.type, pointer = it.pointer + 1) + codeBuilder.loadClassField(classField, LLVMVariable("classvariable.this.addr", type, scope = LLVMRegisterScope(), pointer = 1), (it as LLVMClassVariable).offset) + codeBuilder.storeVariable(classField, it) + } + else -> { + val argument = codeBuilder.getNewVariable(it.type, it.pointer) + codeBuilder.loadVariable(argument, LLVMVariable("${it.label}.addr", it.type, scope = LLVMRegisterScope(), pointer = it.pointer + 1)) + val classField = codeBuilder.getNewVariable(it.type, pointer = 1) + codeBuilder.loadClassField(classField, LLVMVariable("classvariable.this.addr", type, scope = LLVMRegisterScope(), pointer = 1), (it as LLVMClassVariable).offset) + codeBuilder.storeVariable(classField, argument) + } + } + + } + } + + private fun generateReturn() { + val dst = LLVMVariable("classvariable.this", type, scope = LLVMRegisterScope(), pointer = 1) + val src = LLVMVariable("classvariable.this.addr", type, scope = LLVMRegisterScope(), pointer = 1) + + val castedDst = codeBuilder.bitcast(dst, LLVMVariable("", LLVMCharType(), pointer = 1)) + val castedSrc = codeBuilder.bitcast(src, LLVMVariable("", LLVMCharType(), pointer = 1)) + + codeBuilder.memcpy(castedDst, castedSrc, size) + } + + protected fun resolveType(field: KtParameter): 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) { + val type = result.type as LLVMReferenceType + type.prefix = "class" + type.byRef = true + } + + if (annotations.contains("Plain")) { + result.pointer = 0 + } + + return LLVMClassVariable(result.label, result.type, result.pointer) + } + + private fun parseFieldAnnotations(field: KtParameter): Set { + val result = HashSet() + + for (annotation in field.annotationEntries) { + val annotationDescriptor = state.bindingContext.get(BindingContext.ANNOTATION, annotation) + val type = annotationDescriptor?.type.toString() + + result.add(type) + } + + return result + } +} diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/TranslationState.kt b/translator/src/main/kotlin/org/kotlinnative/translator/TranslationState.kt index ea687fdf771..8ba47443cb8 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/TranslationState.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/TranslationState.kt @@ -26,6 +26,7 @@ class TranslationState(val environment: KotlinCoreEnvironment, val bindingContex var functions = HashMap() val globalVariableCollection = HashMap() var classes = HashMap() + var objects = HashMap() var properties = HashMap() } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt index 17ec8db3d23..593dabf8fe5 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt @@ -122,6 +122,11 @@ class LLVMBuilder(val arm: Boolean) { globalCode.appendln("$variable = private unnamed_addr constant ${type.fullType()} c\"$value\\00\", align 1") } + fun addGlobalIntialize(target: LLVMVariable, classType: LLVMType) { + val code = "$target = internal global $classType zeroinitializer, align ${classType.align}" + globalCode.appendln(code) + } + fun storeString(target: LLVMVariable, source: LLVMVariable, offset: Int) { val stringType = source.type as LLVMStringType val code = "store ${target.type} getelementptr inbounds (${stringType.fullType()}, " + diff --git a/translator/src/test/kotlin/tests/input/object_1.txt b/translator/src/test/kotlin/tests/input/object_1.txt new file mode 100644 index 00000000000..fdc224811d9 --- /dev/null +++ b/translator/src/test/kotlin/tests/input/object_1.txt @@ -0,0 +1 @@ +Singleton.create(5) == 40 \ No newline at end of file diff --git a/translator/src/test/kotlin/tests/kotlin/object_1.kt b/translator/src/test/kotlin/tests/kotlin/object_1.kt new file mode 100644 index 00000000000..4825ae45a68 --- /dev/null +++ b/translator/src/test/kotlin/tests/kotlin/object_1.kt @@ -0,0 +1,6 @@ +object Singleton { + fun create(x : Int): Int { + return x * 8 + } +} +