From 0d4e3dc8a8305d13e2ae82fccdbe889f02742c6d Mon Sep 17 00:00:00 2001 From: Alexey Stepanov Date: Mon, 15 Aug 2016 15:31:55 +0300 Subject: [PATCH] translator: fix class class arguments, fix computing class size --- .../kotlinnative/translator/BlockCodegen.kt | 14 +++++------ .../kotlinnative/translator/ClassCodegen.kt | 18 +++---------- .../translator/FunctionCodegen.kt | 8 +++--- .../kotlinnative/translator/ObjectCodegen.kt | 8 ++++-- .../translator/PropertyCodegen.kt | 2 +- .../kotlinnative/translator/StructCodegen.kt | 25 +++++++++++++++++-- .../translator/TranslationState.kt | 2 ++ .../translator/llvm/generators.kt | 11 ++++---- .../translator/llvm/types/LLVMFunctionType.kt | 5 ++-- .../llvm/types/LLVMReferenceType.kt | 3 +-- .../tests/input/class_class_argument_1.txt | 1 + .../tests/kotlin/class_class_argument_1.kt | 12 +++++++++ 12 files changed, 69 insertions(+), 40 deletions(-) create mode 100644 translator/src/test/kotlin/tests/input/class_class_argument_1.txt create mode 100644 translator/src/test/kotlin/tests/kotlin/class_class_argument_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 6d09a966bf5..ebcca30e06f 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt @@ -121,7 +121,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va private fun evaluateCallableReferenceExpression(expr: KtCallableReferenceExpression): LLVMSingleValue? { val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, expr)!!.type!! - val result = LLVMInstanceOfStandardType(expr.text.substring(2), kotlinType, LLVMVariableScope()) + val result = LLVMInstanceOfStandardType(expr.text.substring(2), kotlinType, LLVMVariableScope(), state) return LLVMVariable("${result.label}${(result.type as LLVMFunctionType).mangleArgs()}", result.type, result.kotlinName, result.scope, result.pointer) } @@ -131,7 +131,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va val left = evaluateExpression(receiver, scopeDepth)!! val loadedLeft = codeBuilder.receiveNativeValue(left) - val expectedType = LLVMMapStandardType(state.bindingContext.get(BindingContext.EXPECTED_EXPRESSION_TYPE, expr)!!) as LLVMReferenceType + val expectedType = LLVMMapStandardType(state.bindingContext.get(BindingContext.EXPECTED_EXPRESSION_TYPE, expr)!!, state) as LLVMReferenceType if (state.classes.containsKey(expectedType.type)) { expectedType.prefix = "class" @@ -223,7 +223,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va private fun evaluateExtensionExpression(receiver: KtExpression, selector: KtCallExpression, scopeDepth: Int): LLVMSingleValue? { val receiverType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, receiver) - val standardType = LLVMMapStandardType(receiverType!!.type!!) + val standardType = LLVMMapStandardType(receiverType!!.type!!, state) val function = selector.firstChild.firstChild.text val names = parseArgList(selector, scopeDepth) @@ -809,7 +809,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va private fun evaluateConstantExpression(expr: KtConstantExpression): LLVMConstant { val expressionKotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, expr)!!.type!! val expressionValue = state.bindingContext.get(BindingContext.COMPILE_TIME_VALUE, expr)?.getValue(expressionKotlinType) - val type = LLVMMapStandardType(expressionKotlinType) + val type = LLVMMapStandardType(expressionKotlinType, state) return LLVMConstant(expressionValue?.toString() ?: "", type, pointer = 0) } @@ -866,7 +866,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va codeBuilder.addComment("start when expression") val whenExpression = expr.subjectExpression val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, expr)!!.type!! - val expressionType = LLVMMapStandardType(kotlinType) + val expressionType = LLVMMapStandardType(kotlinType, state) val targetExpression = evaluateExpression(whenExpression, scopeDepth + 1)!! val resultVariable = codeBuilder.getNewVariable(expressionType, pointer = 1) @@ -925,7 +925,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va private fun executeIfExpression(conditionResult: LLVMSingleValue, thenExpression: KtExpression, elseExpression: PsiElement?, ifExpression: KtIfExpression, scopeDepth: Int): LLVMVariable? { val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, ifExpression)!!.type!! - val expressionType = LLVMInstanceOfStandardType("type", kotlinType, LLVMVariableScope()).type + val expressionType = LLVMInstanceOfStandardType("type", kotlinType, LLVMVariableScope(), state).type val resultVariable = codeBuilder.getNewVariable(expressionType, pointer = 1) codeBuilder.allocStackPointedVarAsValue(resultVariable) val thenLabel = codeBuilder.getNewLabel(prefix = "if") @@ -988,7 +988,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va } is LLVMConstant -> { if (assignExpression.type is LLVMNullType) { - val reference = LLVMInstanceOfStandardType(identifier, variable.type) + val reference = LLVMInstanceOfStandardType(identifier, variable.type, state = state) if (state.classes.containsKey(variable.type.toString().dropLast(1))) { (reference.type as LLVMReferenceType).prefix = "class" } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt index 44774ac1a36..2c9e6f76a01 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt @@ -26,7 +26,7 @@ class ClassCodegen(state: TranslationState, override val type: LLVMReferenceType init { - type = LLVMReferenceType(structName, "class", byRef = true) + type = LLVMReferenceType(structName, "class", align = state.pointerAllign, size = state.pointerSize, byRef = true) if (parentCodegen != null) { type.location.addAll(parentCodegen.type.location) type.location.add(parentCodegen.structName) @@ -41,7 +41,9 @@ class ClassCodegen(state: TranslationState, indexFields(parameterList) generateInnerFields(clazz.declarations) + calculateTypeSize() type.size = size + type.align = state.pointerAllign } private fun indexFields(parameters: MutableList) { @@ -49,8 +51,6 @@ class ClassCodegen(state: TranslationState, return } - - for (field in parameters) { val item = resolveType(field, state.bindingContext.get(BindingContext.TYPE, field.typeReference)!!) item.offset = fields.size @@ -59,18 +59,6 @@ class ClassCodegen(state: TranslationState, fields.add(item) fieldsIndex[item.label] = item } - val classAlignment = fields.map { it.type.size }.max()?.toInt() ?: 0 - var alignmentRemainder = 0 - - for (item in fields) { - alignmentRemainder = alignmentRemainder - (alignmentRemainder % item.type.size) - if (alignmentRemainder < item.type.size) { - size += classAlignment - alignmentRemainder = classAlignment - item.type.size - } else { - alignmentRemainder -= item.type.size - } - } } override fun prepareForGenerate() { diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt index a251ee2db34..df379511f11 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt @@ -30,10 +30,10 @@ class FunctionCodegen(state: TranslationState, init { val descriptor = state.bindingContext.get(BindingContext.FUNCTION, function)!! args.addAll(descriptor.valueParameters.map { - LLVMInstanceOfStandardType(it.name.toString(), it.type) + LLVMInstanceOfStandardType(it.name.toString(), it.type, state = state) }) - returnType = LLVMInstanceOfStandardType("instance", descriptor.returnType!!) + returnType = LLVMInstanceOfStandardType("instance", descriptor.returnType!!, state = state) if (returnType!!.type is LLVMReferenceType) { returnType!!.pointer = 2 } @@ -42,7 +42,7 @@ class FunctionCodegen(state: TranslationState, if (isExtensionDeclaration) { val receiverType = descriptor.extensionReceiverParameter!!.type - val translatorType = LLVMMapStandardType(receiverType) + val translatorType = LLVMMapStandardType(receiverType, state) functionNamePrefix += translatorType.typename + "." val extensionFunctionsOfThisType = state.extensionFunctions.getOrDefault(translatorType.toString(), HashMap()) @@ -95,7 +95,7 @@ class FunctionCodegen(state: TranslationState, if (isExtensionDeclaration) { val receiverParameter = state.bindingContext.get(BindingContext.FUNCTION, function)!!.extensionReceiverParameter!! val receiverType = receiverParameter.type - val translatorType = LLVMMapStandardType(receiverType) + val translatorType = LLVMMapStandardType(receiverType, state) val classVal = when (translatorType) { is LLVMReferenceType -> LLVMVariable("classvariable.this", translatorType, pointer = 1) diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt index f489e692dd0..391a0b8630c 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt @@ -20,12 +20,16 @@ class ObjectCodegen(state: TranslationState, override val type: LLVMReferenceType init { - type = LLVMReferenceType(structName, "class", byRef = true) + type = LLVMReferenceType(structName, "class", align = state.pointerAllign, size = state.pointerSize, byRef = true) if (parentCodegen != null) { type.location.addAll(parentCodegen.type.location) type.location.add(parentCodegen.structName) } generateInnerFields(objectDeclaration.declarations) + + calculateTypeSize() + type.size = size + type.align = state.pointerAllign } override fun prepareForGenerate() { @@ -35,7 +39,7 @@ class ObjectCodegen(state: TranslationState, codeBuilder.addGlobalInitialize(classInstance, fields, initializedFields.map { val type = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, it.value)!!.type!! Pair(it.key, state.bindingContext.get(BindingContext.COMPILE_TIME_VALUE, it.value)!!.getValue(type).toString()) - }.toMap() , type) + }.toMap(), type) variableManager.addGlobalVariable(fullName, classInstance) } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/PropertyCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/PropertyCodegen.kt index 29fa64f1580..dd1638aa480 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/PropertyCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/PropertyCodegen.kt @@ -17,7 +17,7 @@ class PropertyCodegen(val state: TranslationState, val variableManager: Variable val kotlinType = varInfo.type val value = varInfo.value if (kotlinType.nameIfStandardType != null) { - val variableType = LLVMInstanceOfStandardType(property.name ?: return, kotlinType).type + val variableType = LLVMInstanceOfStandardType(property.name ?: return, kotlinType, state = state).type val variable = LLVMVariable(property.name.toString(), variableType, property.name.toString(), LLVMVariableScope()) variableManager.addGlobalVariable(property.name.toString(), variable) codeBuilder.defineGlobalVariable(variable, variableType.parseArg(value.toString())) diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt index 8d46c40331f..ec4cddd7f69 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt @@ -47,6 +47,23 @@ abstract class StructCodegen(val state: TranslationState, } } + fun calculateTypeSize() { + val classAlignment = fields.map { it.type.align }.max()?.toInt() ?: 0 + var alignmentRemainder = 0 + size = 0 + + for (item in fields) { + val currentFieldType = if (item.pointer > 0) state.pointerSize else item.type.size + alignmentRemainder -= (alignmentRemainder % currentFieldType) + if (alignmentRemainder < currentFieldType) { + size += classAlignment + alignmentRemainder = classAlignment - currentFieldType + } else { + alignmentRemainder -= currentFieldType + } + } + } + open fun generate() { generateEnumFields() generatePrimaryConstructor() @@ -76,7 +93,6 @@ abstract class StructCodegen(val state: TranslationState, } fields.add(field) fieldsIndex[field.label] = field - size += field.type.size } is KtEnumEntry -> { val name = declaration.name!! @@ -192,7 +208,7 @@ abstract class StructCodegen(val state: TranslationState, protected fun resolveType(field: KtNamedDeclaration, ktType: KotlinType): LLVMClassVariable { val annotations = parseFieldAnnotations(field) - val result = LLVMInstanceOfStandardType(field.name!!, ktType, LLVMRegisterScope()) + val result = LLVMInstanceOfStandardType(field.name!!, ktType, LLVMRegisterScope(), state = state) if (result.type is LLVMReferenceType) { val type = result.type as LLVMReferenceType @@ -200,6 +216,11 @@ abstract class StructCodegen(val state: TranslationState, type.byRef = true } + if (state.classes.containsKey(field.name!!)) { + return LLVMClassVariable(result.label, state.classes[field.name!!]!!.type, result.pointer) + } + + if (annotations.contains("Plain")) { result.pointer = 0 } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/TranslationState.kt b/translator/src/main/kotlin/org/kotlinnative/translator/TranslationState.kt index 53f378c0534..36afd0da840 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/TranslationState.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/TranslationState.kt @@ -34,6 +34,8 @@ class TranslationState(val environment: KotlinCoreEnvironment, val bindingContex var objects = HashMap() var properties = HashMap() val codeBuilder = LLVMBuilder(arm) + val pointerAllign = if (arm) 4 else 8 + val pointerSize = if (arm) 4 else 8 val extensionFunctions = HashMap>() } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/generators.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/generators.kt index 2b7cd2be78e..1f28d8146a9 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/generators.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/generators.kt @@ -5,6 +5,7 @@ import org.jetbrains.kotlin.cfg.pseudocode.getSubtypesPredicate import org.jetbrains.kotlin.js.descriptorUtils.nameIfStandardType import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.isUnit +import org.kotlinnative.translator.TranslationState import org.kotlinnative.translator.llvm.types.* @@ -14,8 +15,8 @@ fun LLVMFunctionDescriptor(name: String, argTypes: List?, returnTy "${s.getType()} ${if (s.type is LLVMReferenceType && !(s.type as LLVMReferenceType).byRef) "byval" else ""} %${s.label}" }?.joinToString()}) #0" -fun LLVMInstanceOfStandardType(name: String, type: KotlinType, scope: LLVMScope = LLVMRegisterScope()): LLVMVariable = when { - type.isFunctionTypeOrSubtype -> LLVMVariable(name, LLVMFunctionType(type), name, scope, pointer = 1) +fun LLVMInstanceOfStandardType(name: String, type: KotlinType, scope: LLVMScope = LLVMRegisterScope(), state: TranslationState): LLVMVariable = when { + type.isFunctionTypeOrSubtype -> LLVMVariable(name, LLVMFunctionType(type, state), name, scope, pointer = 1) type.toString() == "Boolean" -> LLVMVariable(name, LLVMBooleanType(), name, scope) type.toString() == "Byte" -> LLVMVariable(name, LLVMByteType(), name, scope) type.toString() == "Char" -> LLVMVariable(name, LLVMCharType(), name, scope) @@ -29,12 +30,12 @@ fun LLVMInstanceOfStandardType(name: String, type: KotlinType, scope: LLVMScope type.isUnit() -> LLVMVariable("", LLVMVoidType(), name, scope) type.isMarkedNullable -> LLVMVariable(name, LLVMReferenceType(type.toString().dropLast(1), prefix = "class"), name, scope, pointer = 1) else -> { - val refType = LLVMReferenceType(type.toString(), prefix = "class") + val refType = state.classes[type.toString()]!!.type val result = LLVMVariable(name, refType, name, scope, pointer = 1) refType.location.addAll(type.getSubtypesPredicate().toString().split(".").dropLast(1)) result } } -fun LLVMMapStandardType(type: KotlinType): LLVMType = - LLVMInstanceOfStandardType("type", type, LLVMRegisterScope()).type +fun LLVMMapStandardType(type: KotlinType, state: TranslationState): LLVMType = + LLVMInstanceOfStandardType("type", type, LLVMRegisterScope(), state).type diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMFunctionType.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMFunctionType.kt index a6b8d672dbf..276e4772e33 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMFunctionType.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMFunctionType.kt @@ -1,10 +1,11 @@ package org.kotlinnative.translator.llvm.types import org.jetbrains.kotlin.types.KotlinType +import org.kotlinnative.translator.TranslationState import org.kotlinnative.translator.llvm.LLVMInstanceOfStandardType import org.kotlinnative.translator.llvm.LLVMVariable -class LLVMFunctionType(type: KotlinType) : LLVMType() { +class LLVMFunctionType(type: KotlinType, state: TranslationState) : LLVMType() { override val defaultValue = "" override val align: Int = 4 @@ -14,7 +15,7 @@ class LLVMFunctionType(type: KotlinType) : LLVMType() { val returnType: LLVMVariable init { - val types = type.arguments.map { LLVMInstanceOfStandardType("", it.type) }.toList() + val types = type.arguments.map { LLVMInstanceOfStandardType("", it.type, state = state) }.toList() returnType = types.last() arguments = types.dropLast(1) } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMReferenceType.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMReferenceType.kt index 0c4958a199a..138fd691ad1 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMReferenceType.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMReferenceType.kt @@ -4,11 +4,10 @@ import org.kotlinnative.translator.llvm.LLVMExpression import org.kotlinnative.translator.llvm.LLVMSingleValue import java.util.* -class LLVMReferenceType(val type: String, var prefix: String = "", override val align: Int = 4, var byRef: Boolean = true) : LLVMType() { +class LLVMReferenceType(val type: String, var prefix: String = "", override var align: Int = 4, override var size: Int = 4, var byRef: Boolean = true) : LLVMType() { override val defaultValue: String = "" - override var size: Int = 4 override val typename: String get() = "$prefix${if (prefix.length > 0) "." else ""}${ if (location.size > 0) "${location.joinToString(".")}." else "" diff --git a/translator/src/test/kotlin/tests/input/class_class_argument_1.txt b/translator/src/test/kotlin/tests/input/class_class_argument_1.txt new file mode 100644 index 00000000000..ce212b26272 --- /dev/null +++ b/translator/src/test/kotlin/tests/input/class_class_argument_1.txt @@ -0,0 +1 @@ +class_class_argument_1() == 99999 diff --git a/translator/src/test/kotlin/tests/kotlin/class_class_argument_1.kt b/translator/src/test/kotlin/tests/kotlin/class_class_argument_1.kt new file mode 100644 index 00000000000..053600335da --- /dev/null +++ b/translator/src/test/kotlin/tests/kotlin/class_class_argument_1.kt @@ -0,0 +1,12 @@ +class class_class_argument_1_slave + +class class_class_argument_1_master(val buffer: class_class_argument_1_slave) { + var pos = 99999 +} + + +fun class_class_argument_1(): Int { + val buffer = class_class_argument_1_slave() + val output = class_class_argument_1_master(buffer) + return output.pos +} \ No newline at end of file