backend, runtime: place vtable at the end of TypeInfo
This commit is contained in:
committed by
Konstantin Anisimov
parent
24219c86b3
commit
c3e1dc37f2
+6
-1
@@ -170,6 +170,8 @@ internal val ClassDescriptor.сontributedMethods: List<FunctionDescriptor>
|
|||||||
return allMethods
|
return allMethods
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ClassDescriptor.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT
|
||||||
|
|
||||||
// TODO: optimize
|
// TODO: optimize
|
||||||
val ClassDescriptor.vtableEntries: List<FunctionDescriptor>
|
val ClassDescriptor.vtableEntries: List<FunctionDescriptor>
|
||||||
get() {
|
get() {
|
||||||
@@ -190,6 +192,9 @@ val ClassDescriptor.vtableEntries: List<FunctionDescriptor>
|
|||||||
return inheritedVtableSlots + (methods - inheritedVtableSlots).filter { it.isOverridable }
|
return inheritedVtableSlots + (methods - inheritedVtableSlots).filter { it.isOverridable }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val ClassDescriptor.vtableSize: Int
|
||||||
|
get() = if (this.isAbstract()) 0 else this.vtableEntries.size
|
||||||
|
|
||||||
fun ClassDescriptor.vtableIndex(function: FunctionDescriptor): Int {
|
fun ClassDescriptor.vtableIndex(function: FunctionDescriptor): Int {
|
||||||
this.vtableEntries.forEachIndexed { index, functionDescriptor ->
|
this.vtableEntries.forEachIndexed { index, functionDescriptor ->
|
||||||
if (functionDescriptor == function.original) return index
|
if (functionDescriptor == function.original) return index
|
||||||
@@ -199,7 +204,7 @@ fun ClassDescriptor.vtableIndex(function: FunctionDescriptor): Int {
|
|||||||
|
|
||||||
val ClassDescriptor.methodTableEntries: List<FunctionDescriptor>
|
val ClassDescriptor.methodTableEntries: List<FunctionDescriptor>
|
||||||
get() {
|
get() {
|
||||||
assert (this.modality != Modality.ABSTRACT)
|
assert (!this.isAbstract())
|
||||||
|
|
||||||
return this.сontributedMethods.filter { it.isOverridableOrOverrides }
|
return this.сontributedMethods.filter { it.isOverridableOrOverrides }
|
||||||
// TODO: probably method table should contain all accessible methods to improve binary compatibility
|
// TODO: probably method table should contain all accessible methods to improve binary compatibility
|
||||||
|
|||||||
+14
-11
@@ -7,6 +7,7 @@ import org.jetbrains.kotlin.backend.konan.Distribution
|
|||||||
import org.jetbrains.kotlin.backend.konan.hash.GlobalHash
|
import org.jetbrains.kotlin.backend.konan.hash.GlobalHash
|
||||||
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.backingField
|
import org.jetbrains.kotlin.backend.konan.descriptors.backingField
|
||||||
|
import org.jetbrains.kotlin.backend.konan.descriptors.vtableSize
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
@@ -114,22 +115,24 @@ internal interface ContextUtils {
|
|||||||
return constValue(result)
|
return constValue(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer to struct { TypeInfo, vtable }.
|
||||||
|
*/
|
||||||
|
val ClassDescriptor.typeInfoWithVtable: ConstPointer
|
||||||
|
get() {
|
||||||
|
val type = structType(runtime.typeInfoType, LLVMArrayType(int8TypePtr, this.vtableSize)!!)
|
||||||
|
return constPointer(externalGlobal(this.typeInfoSymbolName, type))
|
||||||
|
}
|
||||||
|
|
||||||
|
val ClassDescriptor.typeInfoPtr: ConstPointer
|
||||||
|
get() = typeInfoWithVtable.getElementPtr(0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pointer to type info for given class.
|
* Pointer to type info for given class.
|
||||||
* It may be declared as pointer to external variable.
|
* It may be declared as pointer to external variable.
|
||||||
*/
|
*/
|
||||||
val ClassDescriptor.llvmTypeInfoPtr: LLVMValueRef
|
val ClassDescriptor.llvmTypeInfoPtr: LLVMValueRef
|
||||||
get() {
|
get() = typeInfoPtr.llvm
|
||||||
val module = context.llvmModule
|
|
||||||
val globalName = this.typeInfoSymbolName
|
|
||||||
val globalPtr = LLVMGetNamedGlobal(module, globalName) ?:
|
|
||||||
LLVMAddGlobal(module, runtime.typeInfoType, globalName)!!
|
|
||||||
|
|
||||||
return globalPtr
|
|
||||||
}
|
|
||||||
|
|
||||||
val ClassDescriptor.typeInfoPtr: ConstPointer
|
|
||||||
get() = constPointer(this.llvmTypeInfoPtr)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pointer to type info for this type, or `null` if the type doesn't have corresponding type info.
|
* Pointer to type info for this type, or `null` if the type doesn't have corresponding type info.
|
||||||
|
|||||||
+5
-4
@@ -1846,15 +1846,16 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
fun callVirtual(descriptor: FunctionDescriptor, args: List<LLVMValueRef>): LLVMValueRef {
|
fun callVirtual(descriptor: FunctionDescriptor, args: List<LLVMValueRef>): LLVMValueRef {
|
||||||
val typeInfoPtrPtr = LLVMBuildStructGEP(codegen.builder, args[0], 0 /* type_info */, "")!!
|
val typeInfoPtrPtr = LLVMBuildStructGEP(codegen.builder, args[0], 0 /* type_info */, "")!!
|
||||||
val typeInfoPtr = codegen.load(typeInfoPtrPtr)
|
val typeInfoPtr = codegen.load(typeInfoPtrPtr)
|
||||||
|
assert (typeInfoPtr.type == codegen.kTypeInfoPtr)
|
||||||
|
|
||||||
val owner = descriptor.containingDeclaration as ClassDescriptor
|
val owner = descriptor.containingDeclaration as ClassDescriptor
|
||||||
val llvmMethod = if (!owner.isInterface) {
|
val llvmMethod = if (!owner.isInterface) {
|
||||||
// If this is a virtual method of the class - we can call via vtable.
|
// If this is a virtual method of the class - we can call via vtable.
|
||||||
val index = owner.vtableIndex(descriptor)
|
val index = owner.vtableIndex(descriptor)
|
||||||
val vtablePtr = LLVMBuildStructGEP(codegen.builder, typeInfoPtr, 7 /* vtable */, "")!!
|
|
||||||
val vtable = codegen.load(vtablePtr)
|
val vtablePlace = codegen.gep(typeInfoPtr, Int32(1).llvm) // typeInfoPtr + 1
|
||||||
// TODO: those two loads are bad, we shall rework vtable to follow TypeInfo in memory, so
|
val vtable = codegen.bitcast(kInt8PtrPtr, vtablePlace)
|
||||||
// this code shall just take end address of TypeInfo and use numbered slot from there.
|
|
||||||
val slot = codegen.gep(vtable, Int32(index).llvm)
|
val slot = codegen.gep(vtable, Int32(index).llvm)
|
||||||
codegen.load(slot)
|
codegen.load(slot)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+10
-17
@@ -4,11 +4,7 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
|||||||
import kotlinx.cinterop.*
|
import kotlinx.cinterop.*
|
||||||
import llvm.*
|
import llvm.*
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.methodTableEntries
|
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.vtableEntries
|
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.implementation
|
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.implementedInterfaces
|
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
@@ -31,7 +27,6 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
val objOffsetsCount: Int,
|
val objOffsetsCount: Int,
|
||||||
val interfaces: ConstValue,
|
val interfaces: ConstValue,
|
||||||
val interfacesCount: Int,
|
val interfacesCount: Int,
|
||||||
val vtable: ConstValue,
|
|
||||||
val methods: ConstValue,
|
val methods: ConstValue,
|
||||||
val methodsCount: Int,
|
val methodsCount: Int,
|
||||||
val fields: ConstValue,
|
val fields: ConstValue,
|
||||||
@@ -50,8 +45,6 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
interfaces,
|
interfaces,
|
||||||
Int32(interfacesCount),
|
Int32(interfacesCount),
|
||||||
|
|
||||||
vtable,
|
|
||||||
|
|
||||||
methods,
|
methods,
|
||||||
Int32(methodsCount),
|
Int32(methodsCount),
|
||||||
|
|
||||||
@@ -141,12 +134,12 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
val fieldsPtr = staticData.placeGlobalConstArray("kfields:$className",
|
val fieldsPtr = staticData.placeGlobalConstArray("kfields:$className",
|
||||||
runtime.fieldTableRecordType, fields)
|
runtime.fieldTableRecordType, fields)
|
||||||
|
|
||||||
val vtable: List<ConstValue>
|
val vtableEntries: List<ConstValue>
|
||||||
val methods: List<ConstValue>
|
val methods: List<ConstValue>
|
||||||
|
|
||||||
if (classDesc.modality != Modality.ABSTRACT) {
|
if (!classDesc.isAbstract()) {
|
||||||
// TODO: compile-time resolution limits binary compatibility
|
// TODO: compile-time resolution limits binary compatibility
|
||||||
vtable = classDesc.vtableEntries.map { it.implementation.entryPointAddress }
|
vtableEntries = classDesc.vtableEntries.map { it.implementation.entryPointAddress }
|
||||||
|
|
||||||
methods = classDesc.methodTableEntries.map {
|
methods = classDesc.methodTableEntries.map {
|
||||||
val nameSignature = it.functionName.localHash
|
val nameSignature = it.functionName.localHash
|
||||||
@@ -155,12 +148,13 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
MethodTableRecord(nameSignature, methodEntryPoint)
|
MethodTableRecord(nameSignature, methodEntryPoint)
|
||||||
}.sortedBy { it.nameSignature.value }
|
}.sortedBy { it.nameSignature.value }
|
||||||
} else {
|
} else {
|
||||||
vtable = emptyList()
|
vtableEntries = emptyList()
|
||||||
methods = emptyList()
|
methods = emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert (vtableEntries.size == classDesc.vtableSize)
|
||||||
|
|
||||||
val vtablePtr = staticData.placeGlobalConstArray("kvtable:$className", pointerType(int8Type), vtable)
|
val vtable = ConstArray(int8TypePtr, vtableEntries)
|
||||||
|
|
||||||
val methodsPtr = staticData.placeGlobalConstArray("kmethods:$className",
|
val methodsPtr = staticData.placeGlobalConstArray("kmethods:$className",
|
||||||
runtime.methodTableRecordType, methods)
|
runtime.methodTableRecordType, methods)
|
||||||
@@ -169,15 +163,14 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
superType,
|
superType,
|
||||||
objOffsetsPtr, objOffsets.size,
|
objOffsetsPtr, objOffsets.size,
|
||||||
interfacesPtr, interfaces.size,
|
interfacesPtr, interfaces.size,
|
||||||
vtablePtr,
|
|
||||||
methodsPtr, methods.size,
|
methodsPtr, methods.size,
|
||||||
fieldsPtr, if (classDesc.isInterface) -1 else fields.size)
|
fieldsPtr, if (classDesc.isInterface) -1 else fields.size)
|
||||||
|
|
||||||
val typeInfoGlobal = classDesc.llvmTypeInfoPtr // TODO: it is a hack
|
val typeInfoGlobal = classDesc.typeInfoWithVtable.llvm // TODO: it is a hack
|
||||||
LLVMSetInitializer(typeInfoGlobal, typeInfo.llvm)
|
LLVMSetInitializer(typeInfoGlobal, Struct(typeInfo, vtable).llvm)
|
||||||
LLVMSetGlobalConstant(typeInfoGlobal, 1)
|
LLVMSetGlobalConstant(typeInfoGlobal, 1)
|
||||||
|
|
||||||
exportTypeInfoIfRequired(classDesc, typeInfoGlobal)
|
exportTypeInfoIfRequired(classDesc, classDesc.llvmTypeInfoPtr)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,14 +34,14 @@ struct TypeInfo {
|
|||||||
const TypeInfo* const* implementedInterfaces_;
|
const TypeInfo* const* implementedInterfaces_;
|
||||||
int32_t implementedInterfacesCount_;
|
int32_t implementedInterfacesCount_;
|
||||||
// Null for abstract classes and interfaces.
|
// Null for abstract classes and interfaces.
|
||||||
// TODO: place vtable at the end of TypeInfo to eliminate the indirection.
|
|
||||||
void* const* vtable_;
|
|
||||||
// Null for abstract classes and interfaces.
|
|
||||||
const MethodTableRecord* openMethods_;
|
const MethodTableRecord* openMethods_;
|
||||||
uint32_t openMethodsCount_;
|
uint32_t openMethodsCount_;
|
||||||
const FieldTableRecord* fields_;
|
const FieldTableRecord* fields_;
|
||||||
// Is negative to mark an interface.
|
// Is negative to mark an interface.
|
||||||
int32_t fieldsCount_;
|
int32_t fieldsCount_;
|
||||||
|
|
||||||
|
// vtable starts just after declared contents of the TypeInfo:
|
||||||
|
// void* const vtable_[];
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
Reference in New Issue
Block a user