From 83fbb3342fc50c8187911dcb93ecc9fde44fa541 Mon Sep 17 00:00:00 2001 From: Nikolay Igotti Date: Tue, 11 Oct 2016 18:44:27 +0300 Subject: [PATCH] Restore codegen. --- .../kotlin/backend/native/llvm/IrToBitcode.kt | 84 +++--- .../kotlin/backend/native/llvm/LlvmUtils.kt | 18 +- .../backend/native/llvm/RTTIGenerator.kt | 258 +++++++++--------- .../kotlin/backend/native/llvm/Runtime.kt | 52 ++-- 4 files changed, 206 insertions(+), 206 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/IrToBitcode.kt index dc95eb2c3d3..7fc5e0448d1 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/IrToBitcode.kt @@ -27,12 +27,12 @@ internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid { val generator = RTTIGenerator(context) override fun visitElement(element: IrElement) { - element.acceptChildrenVoid(this) + element.acceptChildrenVoid(this) } override fun visitClass(declaration: IrClass) { - super.visitClass(declaration) - generator.generate(declaration.descriptor) + super.visitClass(declaration) + generator.generate(declaration.descriptor) } } @@ -43,63 +43,63 @@ internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid { internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid { val generator = CodeGenerator(context) override fun visitFunction(declaration: IrFunction) { - generator.function(declaration) - declaration.acceptChildrenVoid(this) + generator.function(declaration) + declaration.acceptChildrenVoid(this) } override fun visitElement(element: IrElement) { - element.acceptChildrenVoid(this) + element.acceptChildrenVoid(this) } override fun visitSetVariable(expression: IrSetVariable) { - val value = evaluateExpression(generator.tmpVariable(), expression.value) - generator.store(value!!, generator.variable(expression.descriptor.name.asString())!!) + val value = evaluateExpression(generator.tmpVariable(), expression.value) + generator.store(value!!, generator.variable(expression.descriptor.name.asString())!!) } private fun evaluateExpression(tmpVariableName: String, value: IrExpression?): LLVMOpaqueValue? { - when (value) { - is IrCall -> return evaluateCall(tmpVariableName, value) - is IrGetValue -> return generator.load(generator.variable(value.descriptor.name.asString())!!, tmpVariableName) - null -> return null - else -> { - TODO() - } - } + when (value) { + is IrCall -> return evaluateCall(tmpVariableName, value) + is IrGetValue -> return generator.load(generator.variable(value.descriptor.name.asString())!!, tmpVariableName) + null -> return null + else -> { + TODO() + } + } } private fun evaluateCall(tmpVariableName: String, value: IrCall?): LLVMOpaqueValue? { - /* TODO: should we count on receiver? - * val tmp = tmpVar() - * val lhs = evaluateExpression(tmp, value.dispatchReceiver!!) - */ - val args = mutableListOf() - value!!.acceptChildrenVoid(object:IrElementVisitorVoid{ - override fun visitElement(element: IrElement) { - val tmp = generator.tmpVariable() - args.add(evaluateExpression(tmp, element as IrExpression)) - } - }) - when (value!!.origin) { - IrStatementOrigin.PLUS -> return generator.plus(args[0]!!, args[1]!!, tmpVariableName) - else -> { - TODO() - } - } - TODO() + /* TODO: should we count on receiver? + * val tmp = tmpVar() + * val lhs = evaluateExpression(tmp, value.dispatchReceiver!!) + */ + val args = mutableListOf() + value!!.acceptChildrenVoid(object:IrElementVisitorVoid{ + override fun visitElement(element: IrElement) { + val tmp = generator.tmpVariable() + args.add(evaluateExpression(tmp, element as IrExpression)) + } + }) + when (value!!.origin) { + IrStatementOrigin.PLUS -> return generator.plus(args[0]!!, args[1]!!, tmpVariableName) + else -> { + TODO() + } + } + TODO() } override fun visitVariable(declaration: IrVariable) { - val variableName = declaration.descriptor.name.asString() - val variableType = declaration.descriptor.type - generator.registerVariable(variableName, generator.alloca(variableType, variableName)) + val variableName = declaration.descriptor.name.asString() + val variableType = declaration.descriptor.type + generator.registerVariable(variableName, generator.alloca(variableType, variableName)) - evaluateExpression(variableName, declaration.initializer) + evaluateExpression(variableName, declaration.initializer) } override fun visitReturn(expression: IrReturn) { - val tmpVarName = generator.tmpVariable() - val value:LLVMOpaqueValue? - value = evaluateExpression(tmpVarName, expression.value) - LLVMBuildRet(context.llvmBuilder, value) + val tmpVarName = generator.tmpVariable() + val value:LLVMOpaqueValue? + value = evaluateExpression(tmpVarName, expression.value) + LLVMBuildRet(context.llvmBuilder, value) } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/LlvmUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/LlvmUtils.kt index 6af02d97179..642063e3fa5 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/LlvmUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/LlvmUtils.kt @@ -13,7 +13,7 @@ internal abstract class CompileTimeValue { abstract fun getLlvmValue(): LLVMOpaqueValue? fun getLlvmType(): LLVMOpaqueType? { - return LLVMTypeOf(getLlvmValue()) + return LLVMTypeOf(getLlvmValue()) } } @@ -21,10 +21,10 @@ internal abstract class CompileTimeValue { internal class ConstArray(val elemType: LLVMOpaqueType?, val elements: List) : CompileTimeValue() { override fun getLlvmValue(): LLVMOpaqueValue? { - val values = elements.map { it.getLlvmValue() }.toTypedArray() - val valuesNativeArrayPtr = mallocNativeArrayOf(LLVMOpaqueValue, *values)[0] // FIXME: dispose + val values = elements.map { it.getLlvmValue() }.toTypedArray() + val valuesNativeArrayPtr = mallocNativeArrayOf(LLVMOpaqueValue, *values)[0] // FIXME: dispose - return LLVMConstArray(elemType, valuesNativeArrayPtr, values.size) + return LLVMConstArray(elemType, valuesNativeArrayPtr, values.size) } } @@ -33,9 +33,9 @@ internal open class Struct(val type: LLVMOpaqueType?, val elements: List Int8(1)}).toList())), - Int32(size), + Struct(runtime.globalhHashType, ConstArray(LLVMInt8Type(), Array(20, {i -> Int8(1)}).toList())), + Int32(size), - superType, + superType, - objOffsets, - Int32(objOffsetsCount), + objOffsets, + Int32(objOffsetsCount), - interfaces, - Int32(interfacesCount), + interfaces, + Int32(interfacesCount), - vtable, + vtable, - methods, - Int32(methodsCount), + methods, + Int32(methodsCount), - fields, - Int32(fieldsCount) - ) + fields, + Int32(fieldsCount) + ) - // TODO: probably it should be moved out of this class and shared. - private fun createStructFor(className: FqName, fields: List): LLVMOpaqueType? { - val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), "kclass:" + className) - val fieldTypes = fields.map { getLLVMType(it.returnType!!) }.toTypedArray() - val fieldTypesNativeArrayPtr = if (fieldTypes.size > 0) { - mallocNativeArrayOf(LLVMOpaqueType, *fieldTypes)[0] // TODO: dispose - } else { - null - } - - LLVMStructSetBody(classType, fieldTypesNativeArrayPtr, fieldTypes.size, 0) - return classType - } - - // TODO: optimize - private fun getVtableEntries(classDesc: ClassDescriptor): List { - val superVtableEntries = if (KotlinBuiltIns.isAny(classDesc)) { - emptyList() - } else { - getVtableEntries(classDesc.getSuperClassOrAny()) - } - - val inheritedVtableSlots = Array(superVtableEntries.size, { null }) - val methods = getMethodTableEntries(classDesc) // TODO: ensure order is well-defined - val entriesForNewVtableSlots = methods.toMutableSet() - - methods.forEach { method -> - superVtableEntries.forEachIndexed { i, superMethod -> - if (OverridingUtil.overrides(method, superMethod)) { - assert (inheritedVtableSlots[i] == null) - inheritedVtableSlots[i] = method - - assert (method in entriesForNewVtableSlots) - entriesForNewVtableSlots.remove(method) + // TODO: probably it should be moved out of this class and shared. + private fun createStructFor(className: FqName, fields: List): LLVMOpaqueType? { + val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), "kclass:" + className) + val fieldTypes = fields.map { getLLVMType(it.returnType!!) }.toTypedArray() + val fieldTypesNativeArrayPtr = if (fieldTypes.size > 0) { + mallocNativeArrayOf(LLVMOpaqueType, *fieldTypes)[0] // TODO: dispose + } else { + null } - } + + LLVMStructSetBody(classType, fieldTypesNativeArrayPtr, fieldTypes.size, 0) + return classType } - return inheritedVtableSlots.map { it!! } + methods.filter { it in entriesForNewVtableSlots } - } + // TODO: optimize + private fun getVtableEntries(classDesc: ClassDescriptor): List { + val superVtableEntries = if (KotlinBuiltIns.isAny(classDesc)) { + emptyList() + } else { + getVtableEntries(classDesc.getSuperClassOrAny()) + } - private fun getMethodTableEntries(classDesc: ClassDescriptor): List { - val contributedDescriptors = classDesc.unsubstitutedMemberScope.getContributedDescriptors() - // (includes declarations from supers) + val inheritedVtableSlots = Array(superVtableEntries.size, { null }) + val methods = getMethodTableEntries(classDesc) // TODO: ensure order is well-defined + val entriesForNewVtableSlots = methods.toMutableSet() - val functions = contributedDescriptors.filterIsInstance() + methods.forEach { method -> + superVtableEntries.forEachIndexed { i, superMethod -> + if (OverridingUtil.overrides(method, superMethod)) { + assert (inheritedVtableSlots[i] == null) + inheritedVtableSlots[i] = method - val properties = contributedDescriptors.filterIsInstance() - val getters = properties.mapNotNull { it.getter } - val setters = properties.mapNotNull { it.setter } + assert (method in entriesForNewVtableSlots) + entriesForNewVtableSlots.remove(method) + } + } + } - val allMethods = functions + getters + setters - - // TODO: adding or removing 'open' modifier will break the binary compatibility - return allMethods.filter { it.modality != Modality.FINAL } - } - - fun generate(classDesc: ClassDescriptor) { - - val className = classDesc.fqNameSafe - - val classType = createStructFor(className, classDesc.fields) - - val name = className.nameHash - - val size = LLVMStoreSizeOfType(runtime.targetData, classType).toInt() - - val superType = classDesc.getSuperClassOrAny().llvmTypeInfoPtr - - val interfaces = classDesc.implementedInterfaces.map { it.llvmTypeInfoPtr } - val interfacesPtr = addGlobalConstArray("kintf:$className", pointerType(runtime.typeInfoType), interfaces) - - val refFieldIndices = classDesc.fields.mapIndexedNotNull { index, field -> - val type = field.returnType!! - if (!KotlinBuiltIns.isPrimitiveType(type)) { - index - } else { - null - } + return inheritedVtableSlots.map { it!! } + methods.filter { it in entriesForNewVtableSlots } } - // TODO: reuse offsets obtained for 'fields' below - val objOffsets = refFieldIndices.map { LLVMOffsetOfElement(runtime.targetData, classType, it) } - val objOffsetsPtr = addGlobalConstArray("krefs:$className", int32Type, objOffsets.map { Int32(it.toInt()) }) - val fields = classDesc.fields.mapIndexed { index, field -> - // Note: using FQ name because a class may have multiple fields with the same name due to property overriding - val nameSignature = field.fqNameSafe.nameHash // FIXME: add signature - val fieldOffset = LLVMOffsetOfElement(runtime.targetData, classType, index) - FieldTableRecord(nameSignature, fieldOffset.toInt()) - }.sortedBy { it.nameSignature } + private fun getMethodTableEntries(classDesc: ClassDescriptor): List { + val contributedDescriptors = classDesc.unsubstitutedMemberScope.getContributedDescriptors() + // (includes declarations from supers) - val fieldsPtr = addGlobalConstArray("kfields:$className", runtime.fieldTableRecordType, fields) + val functions = contributedDescriptors.filterIsInstance() - // TODO: compile-time resolution limits binary compatibility - val vtable = getVtableEntries(classDesc).map { it.implementation.entryPointAddress } - val vtablePtr = addGlobalConstArray("kvtable:$className", pointerType(int8Type), vtable) + val properties = contributedDescriptors.filterIsInstance() + val getters = properties.mapNotNull { it.getter } + val setters = properties.mapNotNull { it.setter } - val methods = getMethodTableEntries(classDesc).map { - val nameSignature = it.name.nameHash // FIXME: add signature - // TODO: compile-time resolution limits binary compatibility - val methodEntryPoint = it.implementation.entryPointAddress - MethodTableRecord(nameSignature, methodEntryPoint) - }.sortedBy { it.nameSignature } + val allMethods = functions + getters + setters - val methodsPtr = addGlobalConstArray("kmethods:$className", runtime.methodTableRecordType, methods) + // TODO: adding or removing 'open' modifier will break the binary compatibility + return allMethods.filter { it.modality != Modality.FINAL } + } - val typeInfo = TypeInfo(name, size, + fun generate(classDesc: ClassDescriptor) { + + val className = classDesc.fqNameSafe + + val classType = createStructFor(className, classDesc.fields) + + val name = className.nameHash + + val size = LLVMStoreSizeOfType(runtime.targetData, classType).toInt() + + val superType = classDesc.getSuperClassOrAny().llvmTypeInfoPtr + + val interfaces = classDesc.implementedInterfaces.map { it.llvmTypeInfoPtr } + val interfacesPtr = addGlobalConstArray("kintf:$className", pointerType(runtime.typeInfoType), interfaces) + + val refFieldIndices = classDesc.fields.mapIndexedNotNull { index, field -> + val type = field.returnType!! + if (!KotlinBuiltIns.isPrimitiveType(type)) { + index + } else { + null + } + } + // TODO: reuse offsets obtained for 'fields' below + val objOffsets = refFieldIndices.map { LLVMOffsetOfElement(runtime.targetData, classType, it) } + val objOffsetsPtr = addGlobalConstArray("krefs:$className", int32Type, objOffsets.map { Int32(it.toInt()) }) + + val fields = classDesc.fields.mapIndexed { index, field -> + // Note: using FQ name because a class may have multiple fields with the same name due to property overriding + val nameSignature = field.fqNameSafe.nameHash // FIXME: add signature + val fieldOffset = LLVMOffsetOfElement(runtime.targetData, classType, index) + FieldTableRecord(nameSignature, fieldOffset.toInt()) + }.sortedBy { it.nameSignature } + + val fieldsPtr = addGlobalConstArray("kfields:$className", runtime.fieldTableRecordType, fields) + + // TODO: compile-time resolution limits binary compatibility + val vtable = getVtableEntries(classDesc).map { it.implementation.entryPointAddress } + val vtablePtr = addGlobalConstArray("kvtable:$className", pointerType(int8Type), vtable) + + val methods = getMethodTableEntries(classDesc).map { + val nameSignature = it.name.nameHash // FIXME: add signature + // TODO: compile-time resolution limits binary compatibility + val methodEntryPoint = it.implementation.entryPointAddress + MethodTableRecord(nameSignature, methodEntryPoint) + }.sortedBy { it.nameSignature } + + val methodsPtr = addGlobalConstArray("kmethods:$className", runtime.methodTableRecordType, methods) + + val typeInfo = TypeInfo(name, size, superType, objOffsetsPtr, objOffsets.size, interfacesPtr, interfaces.size, @@ -173,9 +173,9 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { methodsPtr, methods.size, fieldsPtr, fields.size) - val typeInfoGlobal = classDesc.llvmTypeInfoPtr.getLlvmValue() // TODO: it is a hack - LLVMSetInitializer(typeInfoGlobal, typeInfo.getLlvmValue()) - LLVMSetGlobalConstant(typeInfoGlobal, 1) - } + val typeInfoGlobal = classDesc.llvmTypeInfoPtr.getLlvmValue() // TODO: it is a hack + LLVMSetInitializer(typeInfoGlobal, typeInfo.getLlvmValue()) + LLVMSetGlobalConstant(typeInfoGlobal, 1) + } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/Runtime.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/Runtime.kt index 942f22ad3ce..081c0714c09 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/Runtime.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/Runtime.kt @@ -4,41 +4,41 @@ import kotlin_native.interop.* import llvm.* class Runtime(private val bitcodeFile: String) { - val llvmModule: LLVMOpaqueModule + val llvmModule: LLVMOpaqueModule - init { - val arena = Arena() - try { + init { + val arena = Arena() + try { - val bufRef = arena.alloc(LLVMOpaqueMemoryBuffer.ref) - val errorRef = arena.alloc(Int8Box.ref) - val res = LLVMCreateMemoryBufferWithContentsOfFile(bitcodeFile, bufRef, errorRef) - if (res != 0) { - throw Error(errorRef.value?.asCString()?.toString()) - } + val bufRef = arena.alloc(LLVMOpaqueMemoryBuffer.ref) + val errorRef = arena.alloc(Int8Box.ref) + val res = LLVMCreateMemoryBufferWithContentsOfFile(bitcodeFile, bufRef, errorRef) + if (res != 0) { + throw Error(errorRef.value?.asCString()?.toString()) + } - val moduleRef = arena.alloc(LLVMOpaqueModule.ref) - val parseRes = LLVMParseBitcode2(bufRef.value, moduleRef) - if (parseRes != 0) { - throw Error(parseRes.toString()) - } + val moduleRef = arena.alloc(LLVMOpaqueModule.ref) + val parseRes = LLVMParseBitcode2(bufRef.value, moduleRef) + if (parseRes != 0) { + throw Error(parseRes.toString()) + } - llvmModule = moduleRef.value!! + llvmModule = moduleRef.value!! - } finally { - arena.clear() + } finally { + arena.clear() + } } - } - val typeInfoType = LLVMGetTypeByName(llvmModule, "struct.TypeInfo") - val fieldTableRecordType = LLVMGetTypeByName(llvmModule, "struct.FieldTableRecord") - val methodTableRecordType = LLVMGetTypeByName(llvmModule, "struct.MethodTableRecord") - val globalhHashType = LLVMGetTypeByName(llvmModule, "struct.GlobalHash") + val typeInfoType = LLVMGetTypeByName(llvmModule, "struct.TypeInfo") + val fieldTableRecordType = LLVMGetTypeByName(llvmModule, "struct.FieldTableRecord") + val methodTableRecordType = LLVMGetTypeByName(llvmModule, "struct.MethodTableRecord") + val globalhHashType = LLVMGetTypeByName(llvmModule, "struct.GlobalHash") - val target = LLVMGetTarget(llvmModule)!!.asCString().toString() + val target = LLVMGetTarget(llvmModule)!!.asCString().toString() - val dataLayout = LLVMGetDataLayout(llvmModule)!!.asCString().toString() + val dataLayout = LLVMGetDataLayout(llvmModule)!!.asCString().toString() - val targetData = LLVMCreateTargetData(dataLayout) + val targetData = LLVMCreateTargetData(dataLayout) }