backend.native: add remaining info to RTTI
inheritance is not supported yet
This commit is contained in:
+113
-27
@@ -5,12 +5,18 @@ import kotlin_native.interop.*
|
|||||||
import llvm.*
|
import llvm.*
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
|
||||||
import java.util.zip.CRC32
|
import java.util.zip.CRC32
|
||||||
|
|
||||||
private fun crc32(str: String): Long {
|
private fun crc32(str: String): Long {
|
||||||
@@ -19,13 +25,18 @@ private fun crc32(str: String): Long {
|
|||||||
return c.value
|
return c.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun crc32(name: Name) = crc32(name.toString())
|
||||||
|
|
||||||
|
private fun getKotlinType(field: IrField) = field.descriptor.returnType!!
|
||||||
|
|
||||||
private fun getLLVMType(field: IrField): LLVMOpaqueType {
|
private fun getLLVMType(field: IrField): LLVMOpaqueType {
|
||||||
val type = field.descriptor.returnType!!
|
val type = getKotlinType(field)
|
||||||
return when {
|
return when {
|
||||||
KotlinBuiltIns.isBoolean(type) || KotlinBuiltIns.isByte(type) -> LLVMInt8Type()
|
KotlinBuiltIns.isBoolean(type) || KotlinBuiltIns.isByte(type) -> LLVMInt8Type()
|
||||||
KotlinBuiltIns.isShort(type) || KotlinBuiltIns.isChar(type) -> LLVMInt16Type()
|
KotlinBuiltIns.isShort(type) || KotlinBuiltIns.isChar(type) -> LLVMInt16Type()
|
||||||
KotlinBuiltIns.isInt(type) -> LLVMInt32Type()
|
KotlinBuiltIns.isInt(type) -> LLVMInt32Type()
|
||||||
KotlinBuiltIns.isLong(type) -> LLVMInt64Type()
|
KotlinBuiltIns.isLong(type) -> LLVMInt64Type()
|
||||||
|
!KotlinBuiltIns.isPrimitiveType(type) -> LLVMPointerType(LLVMInt8Type(), 0)
|
||||||
else -> throw NotImplementedError()
|
else -> throw NotImplementedError()
|
||||||
}!!
|
}!!
|
||||||
}
|
}
|
||||||
@@ -47,8 +58,6 @@ class RTTIGenerator(val module: LLVMOpaqueModule, val runtime: Runtime): IrEleme
|
|||||||
|
|
||||||
private inner class ConstArray(val elemType: LLVMOpaqueType?, val elements: List<CompileTimeValue>) : CompileTimeValue() {
|
private inner class ConstArray(val elemType: LLVMOpaqueType?, val elements: List<CompileTimeValue>) : CompileTimeValue() {
|
||||||
|
|
||||||
constructor(type: LLVMOpaqueType?, vararg elements: CompileTimeValue) : this(type, elements.toList())
|
|
||||||
|
|
||||||
override fun getLlvmValue(): LLVMOpaqueValue? {
|
override fun getLlvmValue(): LLVMOpaqueValue? {
|
||||||
val values = elements.map { it.getLlvmValue() }.toTypedArray()
|
val values = elements.map { it.getLlvmValue() }.toTypedArray()
|
||||||
val valuesNativeArrayPtr = arena.allocNativeArrayOf(LLVMOpaqueValue, *values)[0]
|
val valuesNativeArrayPtr = arena.allocNativeArrayOf(LLVMOpaqueValue, *values)[0]
|
||||||
@@ -92,23 +101,35 @@ class RTTIGenerator(val module: LLVMOpaqueModule, val runtime: Runtime): IrEleme
|
|||||||
private inner class FieldTableRecord(val nameSignature: Long, val fieldOffset: Int) :
|
private inner class FieldTableRecord(val nameSignature: Long, val fieldOffset: Int) :
|
||||||
Struct(runtime.fieldTableRecordType, Int64(nameSignature), Int32(fieldOffset))
|
Struct(runtime.fieldTableRecordType, Int64(nameSignature), Int32(fieldOffset))
|
||||||
|
|
||||||
private inner class TypeInfo(val name: Long, val size: Int, val superType: CompileTimeValue, val fields: CompileTimeValue,
|
private inner class MethodTableRecord(val nameSignature: Long, val methodEntryPoint: CompileTimeValue) :
|
||||||
val fieldsCount: Int) :
|
Struct(runtime.methodTableRecordType, Int64(nameSignature), methodEntryPoint)
|
||||||
|
|
||||||
|
private inner class TypeInfo(val name: Long, val size: Int,
|
||||||
|
val superType: CompileTimeValue,
|
||||||
|
val objOffsets: CompileTimeValue,
|
||||||
|
val objOffsetsCount: Int,
|
||||||
|
val interfaces: CompileTimeValue,
|
||||||
|
val interfacesCount: Int,
|
||||||
|
val methods: CompileTimeValue,
|
||||||
|
val methodsCount: Int,
|
||||||
|
val fields: CompileTimeValue,
|
||||||
|
val fieldsCount: Int) :
|
||||||
Struct(
|
Struct(
|
||||||
runtime.typeInfoType,
|
runtime.typeInfoType,
|
||||||
|
|
||||||
Int64(name),
|
Int64(name),
|
||||||
Int32(size),
|
Int32(size),
|
||||||
|
|
||||||
superType,
|
superType,
|
||||||
|
|
||||||
Zero(pointer(int32Type)),
|
objOffsets,
|
||||||
Int32(0),
|
Int32(objOffsetsCount),
|
||||||
|
|
||||||
Zero(pointer(pointer(runtime.typeInfoType))),
|
interfaces,
|
||||||
Int32(0),
|
Int32(interfacesCount),
|
||||||
|
|
||||||
Zero(pointer(runtime.methodTableRecordType)),
|
methods,
|
||||||
Int32(0),
|
Int32(methodsCount),
|
||||||
|
|
||||||
fields,
|
fields,
|
||||||
Int32(fieldsCount)
|
Int32(fieldsCount)
|
||||||
@@ -117,50 +138,115 @@ class RTTIGenerator(val module: LLVMOpaqueModule, val runtime: Runtime): IrEleme
|
|||||||
private val builder = LLVMCreateBuilder() // TODO: dispose
|
private val builder = LLVMCreateBuilder() // TODO: dispose
|
||||||
private val arena = Arena() // TODO: dispose
|
private val arena = Arena() // TODO: dispose
|
||||||
|
|
||||||
private fun addGlobalConst(name: String, value: CompileTimeValue): LLVMOpaqueValue? {
|
private fun addGlobalConst(name: String, value: CompileTimeValue): CompileTimeValue {
|
||||||
val global = LLVMAddGlobal(module, value.getLlvmType(), name)
|
val global = LLVMAddGlobal(module, value.getLlvmType(), name)
|
||||||
LLVMSetInitializer(global, value.getLlvmValue())
|
LLVMSetInitializer(global, value.getLlvmValue())
|
||||||
return global
|
return compileTimeValue(global)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getGlobalArrayPtr(array: LLVMOpaqueValue?): LLVMOpaqueValue? {
|
private fun getPtrToFirstElem(arrayPtr: CompileTimeValue): CompileTimeValue {
|
||||||
val indices = longArrayOf(0, 0).map { LLVMConstInt(LLVMInt32Type(), it, 0) }.toTypedArray()
|
val indices = longArrayOf(0, 0).map { LLVMConstInt(LLVMInt32Type(), it, 0) }.toTypedArray()
|
||||||
val indicesNativeArrayPtr = arena.allocNativeArrayOf(LLVMOpaqueValue, *indices)[0]
|
val indicesNativeArrayPtr = arena.allocNativeArrayOf(LLVMOpaqueValue, *indices)[0]
|
||||||
|
|
||||||
return LLVMBuildGEP(builder, array, indicesNativeArrayPtr, indices.size, "")
|
return compileTimeValue(LLVMBuildGEP(builder, arrayPtr.getLlvmValue(), indicesNativeArrayPtr, indices.size, ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addGlobalArray(name: String, elemType: LLVMOpaqueType?, elements: List<CompileTimeValue>): CompileTimeValue {
|
||||||
|
return if (elements.size > 0) {
|
||||||
|
getPtrToFirstElem(addGlobalConst(name, ConstArray(elemType, elements)))
|
||||||
|
} else {
|
||||||
|
Zero(pointer(elemType))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun typeInfoFor(classDesc: ClassDescriptor): LLVMOpaqueValue? {
|
private fun typeInfoFor(classDesc: ClassDescriptor): LLVMOpaqueValue? {
|
||||||
val globalName = classDesc.name.toString() + "_type" // FIXME: FQDN
|
val globalName = "ktype:" + classDesc.fqNameSafe.toString()
|
||||||
return LLVMGetNamedGlobal(module, globalName) ?: LLVMAddGlobal(module, runtime.typeInfoType, globalName)
|
return LLVMGetNamedGlobal(module, globalName) ?: LLVMAddGlobal(module, runtime.typeInfoType, globalName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createStructFor(className: FqName, declaredFields: List<IrField>): LLVMOpaqueType? {
|
||||||
|
val fieldTypes = declaredFields.map { getLLVMType(it) }.toTypedArray()
|
||||||
|
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(module), "kclass:" + className)
|
||||||
|
val fieldTypesNativeArray = mallocNativeArrayOf(LLVMOpaqueType, *fieldTypes)
|
||||||
|
LLVMStructSetBody(classType, fieldTypesNativeArray[0], fieldTypes.size, 0)
|
||||||
|
return classType
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun methodEntryPoint(function: FunctionDescriptor): CompileTimeValue {
|
||||||
|
val globalName = "kfun:" + function.fqNameSafe.toString() // FIXME: add signature
|
||||||
|
val functionType = LLVMFunctionType(LLVMVoidType(), null, 0, 0) // FIXME: use correct types
|
||||||
|
val function = LLVMGetNamedFunction(module, globalName) ?: LLVMAddFunction(module, globalName, functionType)
|
||||||
|
val result = compileTimeValue(LLVMConstBitCast(function, pointer(LLVMInt8Type())))
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDeclaredFields(irClass: IrClass) = irClass.declarations.mapNotNull { (it as? IrProperty)?.backingField }
|
||||||
|
|
||||||
|
private fun getDeclaredMethods(irClass: IrClass): List<IrFunction> {
|
||||||
|
val functions = irClass.declarations.filterIsInstance<IrFunction>()
|
||||||
|
val properties = irClass.declarations.filterIsInstance<IrProperty>()
|
||||||
|
return functions + properties.mapNotNull { it.getter } + properties.mapNotNull { it.setter }
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitElement(element: IrElement) {
|
override fun visitElement(element: IrElement) {
|
||||||
element.acceptChildren(this, null)
|
element.acceptChildren(this, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitClass(declaration: IrClass) {
|
override fun visitClass(declaration: IrClass) {
|
||||||
val className = declaration.descriptor.name // FIXME: FQDN
|
visitElement(declaration)
|
||||||
val fields = declaration.declarations.filterIsInstance<IrProperty>().mapNotNull { it.backingField }
|
|
||||||
val fieldTypes = fields.map { getLLVMType(it) }.toTypedArray()
|
val className = declaration.descriptor.fqNameSafe
|
||||||
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(module), "class." + className)
|
|
||||||
LLVMStructSetBody(classType, mallocNativeArrayOf(LLVMOpaqueType, *fieldTypes)[0], fieldTypes.size, 0)
|
val declaredFields = getDeclaredFields(declaration)
|
||||||
|
|
||||||
|
val classType = createStructFor(className, declaredFields)
|
||||||
|
|
||||||
val name = crc32(className.toString())
|
val name = crc32(className.toString())
|
||||||
|
|
||||||
val size = LLVMStoreSizeOfType(runtime.targetData, classType).toInt()
|
val size = LLVMStoreSizeOfType(runtime.targetData, classType).toInt()
|
||||||
|
|
||||||
val superType = compileTimeValue(typeInfoFor(declaration.descriptor.getSuperClassOrAny()))
|
val superType = compileTimeValue(typeInfoFor(declaration.descriptor.getSuperClassOrAny()))
|
||||||
|
|
||||||
val fieldTableRecords = fields.mapIndexed { index, field ->
|
val interfaces = declaration.descriptor.getSuperInterfaces().map { compileTimeValue(typeInfoFor(it)) }
|
||||||
val nameSignature = crc32(field.descriptor.name.toString()) // FIXME: add signature
|
val interfacesPtr = addGlobalArray("kintf:$className", pointer(runtime.typeInfoType), interfaces)
|
||||||
|
|
||||||
|
val refFieldIndices = declaredFields.mapIndexedNotNull { index, field ->
|
||||||
|
val type = getKotlinType(field)
|
||||||
|
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 = addGlobalArray("krefs:$className", int32Type, objOffsets.map { Int32(it.toInt()) })
|
||||||
|
|
||||||
|
// TODO: add fields from supers
|
||||||
|
val fields = declaredFields.mapIndexed { index, field ->
|
||||||
|
val nameSignature = crc32(field.descriptor.name) // FIXME: add signature
|
||||||
val fieldOffset = LLVMOffsetOfElement(runtime.targetData, classType, index)
|
val fieldOffset = LLVMOffsetOfElement(runtime.targetData, classType, index)
|
||||||
FieldTableRecord(nameSignature, fieldOffset.toInt())
|
FieldTableRecord(nameSignature, fieldOffset.toInt())
|
||||||
}.sortedBy { it.nameSignature }
|
}.sortedBy { it.nameSignature }
|
||||||
|
|
||||||
val fieldsArray = ConstArray(runtime.fieldTableRecordType, fieldTableRecords)
|
val fieldsPtr = addGlobalArray("kfields:$className", runtime.fieldTableRecordType, fields)
|
||||||
val fieldsGlobal = addGlobalConst("${className}_fields", fieldsArray)
|
|
||||||
val fieldsPtr = compileTimeValue(getGlobalArrayPtr(fieldsGlobal))
|
// TODO: add methods from supers
|
||||||
|
val methods = getDeclaredMethods(declaration).map {
|
||||||
|
val nameSignature = crc32(it.descriptor.name) // FIXME: add signature
|
||||||
|
val methodEntryPoint = methodEntryPoint(it.descriptor)
|
||||||
|
MethodTableRecord(nameSignature, methodEntryPoint)
|
||||||
|
}.sortedBy { it.nameSignature }
|
||||||
|
|
||||||
|
val methodsPtr = addGlobalArray("kmethods:$className", runtime.methodTableRecordType, methods)
|
||||||
|
|
||||||
|
val typeInfo = TypeInfo(name, size,
|
||||||
|
superType,
|
||||||
|
objOffsetsPtr, objOffsets.size,
|
||||||
|
interfacesPtr, interfaces.size,
|
||||||
|
methodsPtr, methods.size,
|
||||||
|
fieldsPtr, fields.size)
|
||||||
|
|
||||||
val typeInfo = TypeInfo(name, size, superType, fieldsPtr, fieldTableRecords.size)
|
|
||||||
val typeInfoGlobal = typeInfoFor(declaration.descriptor)
|
val typeInfoGlobal = typeInfoFor(declaration.descriptor)
|
||||||
LLVMSetInitializer(typeInfoGlobal, typeInfo.getLlvmValue())
|
LLVMSetInitializer(typeInfoGlobal, typeInfo.getLlvmValue())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user