translator: add secondary constructors

This commit is contained in:
Alexey Stepanov
2016-08-19 16:36:07 +03:00
parent d98df3c748
commit 4535c94c28
9 changed files with 119 additions and 58 deletions
@@ -31,7 +31,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
var returnType: LLVMVariable? = null
var wasReturnOnTopLevel = false
protected fun evaluateCodeBlock(expr: PsiElement?, startLabel: LLVMLabel? = null, nextIterationLabel: LLVMLabel? = null, breakLabel: LLVMLabel? = null, scopeDepth: Int = 0, isBlock: Boolean = true) {
fun evaluateCodeBlock(expr: PsiElement?, startLabel: LLVMLabel? = null, nextIterationLabel: LLVMLabel? = null, breakLabel: LLVMLabel? = null, scopeDepth: Int = 0, isBlock: Boolean = true) {
codeBuilder.markWithLabel(startLabel)
if (isBlock) {
expressionWalker(expr, breakLabel, scopeDepth)
@@ -116,6 +116,14 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
}
}
fun evaluateConstructorDelegationReferenceExpression(expr: KtConstructorDelegationReferenceExpression, structCodegen: StructCodegen, constructorArguments: List<LLVMVariable>, scopeDepth: Int): LLVMSingleValue? {
val targetCall = state.bindingContext.get(BindingContext.CALL, expr)
val names = parseValueArguments(targetCall!!.valueArguments, scopeDepth)
val args = loadArgsIfRequired(names, constructorArguments)
return evaluateConstructorCallExpression(LLVMVariable(structCodegen.fullName + structCodegen.primaryConstructorIndex, structCodegen.type, scope = LLVMVariableScope()), args)
}
private fun evaluateThisExpression(): LLVMSingleValue? {
return variableManager["this"]
}
@@ -247,7 +255,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
else -> LLVMVariable("type", standardType, pointer = 0)
}
val args = mutableListOf(loadArgumentIfRequired(receiverExpression, typeThisArgument))
val args = mutableListOf(codeBuilder.loadArgumentIfRequired(receiverExpression, typeThisArgument))
args.addAll(loadArgsIfRequired(names, extensionCodegen.args))
return evaluateFunctionCallExpression(LLVMVariable(extensionCodegen.fullName, extensionCodegen.returnType!!.type, scope = LLVMVariableScope()), args)
}
@@ -315,7 +323,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
val arrayActionType = if (callMaker.callType == Call.CallType.ARRAY_SET_METHOD) "set" else "get"
val explicitReceiver = callMaker.explicitReceiver as ExpressionReceiver
val receiver = evaluateExpression(explicitReceiver.expression, scope)!! as LLVMVariable
val pureReceiver = downLoadArgument(receiver, 1)
val pureReceiver = codeBuilder.downLoadArgument(receiver, 1)
val targetClassName = (receiver.type as LLVMReferenceType).type
@@ -397,7 +405,6 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
val names = parseArgList(expr, scopeDepth)
var name = expr.firstChild.firstChild.text
val external = state.externalFunctions.containsKey(name)
val function = "$name${if (names.size > 0 && !external) "_${names.joinToString(separator = "_", transform = { it.type!!.mangle() })}" else ""}"
if (state.functions.containsKey(function) || state.externalFunctions.containsKey(function)) {
@@ -408,8 +415,9 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
if (state.classes.containsKey(name) || classScope?.structName == name) {
val descriptor = state.classes[name] ?: classScope ?: return null
val args = loadArgsIfRequired(names, descriptor.constructorFields)
return evaluateConstructorCallExpression(LLVMVariable(descriptor.fullName, descriptor.type, scope = LLVMVariableScope()), args)
val detectedConstructor = LLVMType.mangleFunctionArguments(names)
val args = loadArgsIfRequired(names, descriptor.constructorFields[detectedConstructor]!!)
return evaluateConstructorCallExpression(LLVMVariable(descriptor.fullName + detectedConstructor, descriptor.type, scope = LLVMVariableScope()), args)
}
val localFunction = variableManager[name]
@@ -437,7 +445,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
val nestedConstructor = classScope?.nestedClasses?.get(expr.calleeExpression!!.text)
if (nestedConstructor != null) {
val args = loadArgsIfRequired(names, nestedConstructor.constructorFields)
val args = loadArgsIfRequired(names, nestedConstructor.constructorFields[nestedConstructor.primaryConstructorIndex]!!)
return evaluateConstructorCallExpression(LLVMVariable(nestedConstructor.fullName, nestedConstructor.type, scope = LLVMVariableScope()), args)
}
@@ -445,7 +453,6 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
name = "${containingClass.fullName}.$function"
val method = containingClass.methods[name]!!
val args = mutableListOf<LLVMSingleValue>()
val leftName = (expr.context as? KtDotQualifiedExpression)?.receiverExpression?.text
if (caller != null) {
args.add(caller)
@@ -467,7 +474,6 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
if (location.size > 0) {
val type = LLVMReferenceType(name, prefix = "class")
type.location.addAll(location)
return resolveClassOrObjectLocation(type)
}
@@ -510,34 +516,9 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
return null
}
private fun loadArgumentIfRequired(value: LLVMSingleValue, argument: LLVMVariable): LLVMSingleValue {
var result = value
while (argument.pointer < result.pointer) {
result = codeBuilder.getNewVariable(argument.type, pointer = result.pointer - 1)
codeBuilder.loadVariable(result, value as LLVMVariable)
}
when (value.type) {
is LLVMStringType -> if (!(value.type as LLVMStringType).isLoaded) {
val newVariable = codeBuilder.getNewVariable(value.type!!, pointer = result.pointer + 1)
codeBuilder.allocStackVar(newVariable, asValue = true)
codeBuilder.copyVariable(result as LLVMVariable, newVariable)
result = codeBuilder.getNewVariable(argument.type, pointer = newVariable.pointer - 1)
codeBuilder.loadVariable(result, newVariable)
}
}
return result
}
private fun downLoadArgument(value: LLVMSingleValue, pointer: Int): LLVMSingleValue =
loadArgumentIfRequired(value, LLVMVariable("", value.type!!, pointer = pointer))
private fun loadArgsIfRequired(names: List<LLVMSingleValue>, args: List<LLVMVariable>) =
names.mapIndexed(fun(i: Int, value: LLVMSingleValue): LLVMSingleValue {
return loadArgumentIfRequired(value, args[i])
return codeBuilder.loadArgumentIfRequired(value, args[i])
}).toList()
private fun evaluateConstructorCallExpression(function: LLVMVariable, names: List<LLVMSingleValue>): LLVMSingleValue? {
@@ -968,7 +949,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
private fun evaluateIfOperator(element: KtIfExpression, scopeDepth: Int, isExpression: Boolean = true): LLVMVariable? {
val conditionResult = evaluateExpression(element.condition, scopeDepth)!!
val conditionNativeResult = downLoadArgument(conditionResult, 0)
val conditionNativeResult = codeBuilder.downLoadArgument(conditionResult, 0)
return if (isExpression)
executeIfExpression(conditionNativeResult, element.then!!, element.`else`, element, scopeDepth + 1)
@@ -6,7 +6,10 @@ import org.jetbrains.kotlin.psi.KtParameter
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.types.LLVMReferenceType
import org.kotlinnative.translator.llvm.types.LLVMType
import java.util.*
class ClassCodegen(state: TranslationState,
variableManager: VariableManager,
@@ -49,15 +52,17 @@ class ClassCodegen(state: TranslationState,
if (annotation) {
return
}
val currentConstructorFields = ArrayList<LLVMVariable>()
for (field in parameters) {
val item = resolveType(field, state.bindingContext.get(BindingContext.TYPE, field.typeReference)!!)
item.offset = fields.size
constructorFields.add(item)
currentConstructorFields.add(item)
fields.add(item)
fieldsIndex[item.label] = item
}
primaryConstructorIndex = LLVMType.mangleFunctionArguments(currentConstructorFields)
constructorFields.put(primaryConstructorIndex!!, currentConstructorFields)
}
override fun prepareForGenerate() {
@@ -7,6 +7,7 @@ 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(state: TranslationState,
variableManager: VariableManager,
@@ -25,6 +26,9 @@ class ObjectCodegen(state: TranslationState,
type.location.addAll(parentCodegen.type.location)
type.location.add(parentCodegen.structName)
}
primaryConstructorIndex = LLVMType.mangleFunctionArguments(emptyList())
constructorFields.put(primaryConstructorIndex!!, arrayListOf())
generateInnerFields(objectDeclaration.declarations)
calculateTypeSize()
@@ -9,6 +9,7 @@ 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
import org.kotlinnative.translator.llvm.types.LLVMType
import org.kotlinnative.translator.llvm.types.LLVMVoidType
import java.util.*
@@ -24,7 +25,8 @@ abstract class StructCodegen(val state: TranslationState,
val nestedClasses = HashMap<String, ClassCodegen>()
val enumFields = HashMap<String, LLVMVariable>()
val constructorFields = ArrayList<LLVMVariable>()
val constructorFields = HashMap<String, ArrayList<LLVMVariable>>()
var primaryConstructorIndex: String? = null
val initializedFields = HashMap<LLVMVariable, KtExpression>()
abstract val type: LLVMReferenceType
@@ -67,6 +69,9 @@ abstract class StructCodegen(val state: TranslationState,
open fun generate() {
generateEnumFields()
generatePrimaryConstructor()
for (secondaryConstructor in classOrObject.getSecondaryConstructors()) {
generateSecondaryConstructor(secondaryConstructor)
}
val classVal = LLVMVariable("classvariable.this", type, pointer = if (type.isPrimitive()) 0 else 1)
variableManager.addVariable("this", classVal, 0)
@@ -110,6 +115,7 @@ abstract class StructCodegen(val state: TranslationState,
}
}
private fun generateEnumFields() {
val enumEntries = classOrObject.declarations.filter { it is KtEnumEntry }
@@ -121,7 +127,7 @@ abstract class StructCodegen(val state: TranslationState,
val field = codeBuilder.getNewVariable(type, scope = LLVMVariableScope())
val enumField = enumFields[name]!!
codeBuilder.defineGlobalVariable(field, codeBuilder.makeStructInitializer(constructorFields, arguments))
codeBuilder.defineGlobalVariable(field, codeBuilder.makeStructInitializer(constructorFields[primaryConstructorIndex]!!, arguments))
codeBuilder.defineGlobalVariable(LLVMVariable(enumField.label, enumField.type, enumField.kotlinName, enumField.scope, enumField.pointer - 1), "$field")
}
}
@@ -130,24 +136,56 @@ abstract class StructCodegen(val state: TranslationState,
codeBuilder.createClass(fullName, fields)
}
private fun generateSecondaryConstructor(secondaryConstructor: KtSecondaryConstructor) {
val thisCall = secondaryConstructor.getDelegationCall().calleeExpression
val descriptor = state.bindingContext.get(BindingContext.CONSTRUCTOR, secondaryConstructor)
val argFields = ArrayList<LLVMVariable>()
val classVal = LLVMVariable("classvariable.this", type, pointer = 1)
variableManager.addVariable("this", classVal, 0)
val secondaryConstructorArguments = descriptor!!.valueParameters.map {
LLVMInstanceOfStandardType(it.name.toString(), it.type, state = state)
}
argFields.add(classVal)
argFields.addAll(secondaryConstructorArguments)
val currentConstructorIndex = LLVMType.mangleFunctionArguments(secondaryConstructorArguments)
constructorFields.put(currentConstructorIndex, argFields)
codeBuilder.addLLVMCode(LLVMFunctionDescriptor(fullName + currentConstructorIndex, argFields, LLVMVoidType(), arm = state.arm))
codeBuilder.addStartExpression()
for (variable in secondaryConstructorArguments) {
variableManager.addVariable(variable.label, variable, 2)
}
val blockCodegen = object : BlockCodegen(state, variableManager, codeBuilder) {}
val mainConstructorThis = blockCodegen.evaluateConstructorDelegationReferenceExpression(thisCall!!, this, secondaryConstructorArguments, 1) as LLVMVariable
variableManager.addVariable("this", mainConstructorThis, 0)
blockCodegen.evaluateCodeBlock(secondaryConstructor.bodyExpression, scopeDepth = 1)
generateReturn(codeBuilder.downLoadArgument(variableManager.get("this")!!, 1) as LLVMVariable)
codeBuilder.addAnyReturn(LLVMVoidType())
codeBuilder.addEndExpression()
}
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(constructorFields)
argFields.addAll(constructorFields[primaryConstructorIndex]!!)
codeBuilder.addLLVMCode(LLVMFunctionDescriptor(fullName, argFields, LLVMVoidType(), arm = state.arm))
codeBuilder.addLLVMCode(LLVMFunctionDescriptor(fullName + primaryConstructorIndex, argFields, LLVMVoidType(), arm = state.arm))
codeBuilder.addStartExpression()
generateLoadArguments(classVal)
generateAssignments()
generateReturn()
generateReturn(LLVMVariable("classvariable.this.addr", type, scope = LLVMRegisterScope(), pointer = 1))
genClassInitializers()
codeBuilder.addAnyReturn(LLVMVoidType())
codeBuilder.addEndExpression()
@@ -157,7 +195,7 @@ abstract class StructCodegen(val state: TranslationState,
val thisVariable = LLVMVariable(thisField.label, thisField.type, thisField.label, LLVMRegisterScope(), pointer = 0)
codeBuilder.loadArgument(thisVariable, false)
constructorFields.forEach {
constructorFields[primaryConstructorIndex]!!.forEach {
if (it.type !is LLVMReferenceType) {
val loadVariable = LLVMVariable(it.label, it.type, it.label, LLVMRegisterScope())
codeBuilder.loadArgument(loadVariable)
@@ -166,7 +204,7 @@ abstract class StructCodegen(val state: TranslationState,
}
private fun generateAssignments() {
constructorFields.forEach {
constructorFields[primaryConstructorIndex]!!.forEach {
when (it.type) {
is LLVMReferenceType -> {
val classField = codeBuilder.getNewVariable(it.type, pointer = it.pointer + 1)
@@ -200,9 +238,8 @@ abstract class StructCodegen(val state: TranslationState,
codeBuilder.addComment("field initilizers ends")
}
private fun generateReturn() {
private fun generateReturn(src: LLVMVariable) {
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))
@@ -72,6 +72,31 @@ class LLVMBuilder(val arm: Boolean = false) {
else -> throw UnsupportedOperationException()
}
fun loadArgumentIfRequired(value: LLVMSingleValue, argument: LLVMVariable): LLVMSingleValue {
var result = value
while (argument.pointer < result.pointer) {
result = getNewVariable(argument.type, pointer = result.pointer - 1)
loadVariable(result, value as LLVMVariable)
}
when (value.type) {
is LLVMStringType -> if (!(value.type as LLVMStringType).isLoaded) {
val newVariable = getNewVariable(value.type!!, pointer = result.pointer + 1)
allocStackVar(newVariable, asValue = true)
copyVariable(result as LLVMVariable, newVariable)
result = getNewVariable(argument.type, pointer = newVariable.pointer - 1)
loadVariable(result, newVariable)
}
}
return result
}
fun downLoadArgument(value: LLVMSingleValue, pointer: Int): LLVMSingleValue =
loadArgumentIfRequired(value, LLVMVariable("", value.type!!, pointer = pointer))
fun clean() {
localCode = StringBuilder()
globalCode = StringBuilder()
@@ -15,16 +15,10 @@ class LLVMReferenceType(val type: String, var prefix: String = "", override var
override fun toString() = "%$typename"
private val params = ArrayList<String>()
val location = ArrayList<String>()
override fun mangle() = "Ref_$type"
fun addParam(param: String) {
params.add(param)
}
override fun operatorEq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression =
LLVMExpression(LLVMBooleanType(), "icmp eq ${firstOp.getType()} $firstOp, ${if (secondOp.type is LLVMNullType) "null" else "$secondOp"}")
@@ -26,8 +26,6 @@ abstract class LLVMType() : Cloneable {
open fun operatorDec(firstOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun parseArg(inputArg: String) = inputArg
fun makeClone() = clone()
open fun convertFrom(source: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
abstract fun mangle(): String
@@ -38,6 +36,12 @@ abstract class LLVMType() : Cloneable {
abstract var size: Int
abstract val defaultValue: String
open fun isPrimitive(): Boolean = false
companion object {
fun mangleFunctionArguments(names: List<LLVMSingleValue>) =
"_${names.joinToString(separator = "_", transform = { it.type!!.mangle() })}"
}
}
fun parseLLVMType(type: String): LLVMType = when (type) {
@@ -0,0 +1 @@
secondary_constructor_1_Int(1389) == 1401
@@ -0,0 +1,10 @@
class secondary_constructor_1_class(var field1: Int) {
constructor(field1: Int, field2: Int) : this(field1) {
this.field1 = field1 + field2
}
}
fun secondary_constructor_1(x: Int): Int {
val cls = secondary_constructor_1_class(12, x)
return cls.field1
}