translator: add object declarations

This commit is contained in:
Alexey Stepanov
2016-07-19 14:21:56 +03:00
parent 73d93c34ae
commit 62e444c571
9 changed files with 213 additions and 135 deletions
@@ -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<LLVMVariable>()
val fieldsIndex = HashMap<String, LLVMClassVariable>()
val type: LLVMType = LLVMReferenceType(clazz.name.toString(), "class", byRef = true)
val size: Int
var methods = HashMap<String, FunctionCodegen>()
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<LLVMVariable>()
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<String> {
val result = HashSet<String>()
for (annotation in field.annotationEntries) {
val annotationDescriptor = state.bindingContext.get(BindingContext.ANNOTATION, annotation)
val type = annotationDescriptor?.type.toString()
result.add(type)
}
return result
}
}
@@ -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()
}
}
}
@@ -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<LLVMSingleValue>(receiver)
@@ -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)
}
}
@@ -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<LLVMVariable>()
val fieldsIndex = HashMap<String, LLVMClassVariable>()
abstract val type: LLVMType
abstract val size: Int
var methods = HashMap<String, FunctionCodegen>()
abstract val structName: String
fun generate(declarationList: List<KtDeclaration>) {
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<LLVMVariable>()
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<String> {
val result = HashSet<String>()
for (annotation in field.annotationEntries) {
val annotationDescriptor = state.bindingContext.get(BindingContext.ANNOTATION, annotation)
val type = annotationDescriptor?.type.toString()
result.add(type)
}
return result
}
}
@@ -26,6 +26,7 @@ class TranslationState(val environment: KotlinCoreEnvironment, val bindingContex
var functions = HashMap<String, FunctionCodegen>()
val globalVariableCollection = HashMap<String, LLVMVariable>()
var classes = HashMap<String, ClassCodegen>()
var objects = HashMap<String, ObjectCodegen>()
var properties = HashMap<String, PropertyCodegen>()
}
@@ -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()}, " +
@@ -0,0 +1 @@
Singleton.create(5) == 40
@@ -0,0 +1,6 @@
object Singleton {
fun create(x : Int): Int {
return x * 8
}
}