backend.native: use common/hash to compute hashes for RTTI
This commit is contained in:
@@ -2,15 +2,6 @@ package kotlin_native.interop
|
||||
|
||||
fun <T : NativeRef> malloc(type: NativeRef.TypeWithSize<T>) = type.byPtr(bridge.malloc(type.size))
|
||||
|
||||
inline fun <T : NativeRef, R> malloc(type: NativeRef.TypeWithSize<T>, action: (T) -> R): R {
|
||||
val ref = malloc(type)
|
||||
try {
|
||||
return action(ref)
|
||||
} finally {
|
||||
free(ref)
|
||||
}
|
||||
}
|
||||
|
||||
fun free(ptr: NativePtr?) {
|
||||
if (ptr != null) {
|
||||
bridge.free(ptr)
|
||||
@@ -29,6 +20,14 @@ fun <T : NativeRef> Placement.allocNativeArrayOf(elemType: NativeRef.Type<T>, va
|
||||
|
||||
fun <T : NativeRef> mallocNativeArrayOf(elemType: NativeRef.Type<T>, vararg elements: T?) = heap.allocNativeArrayOf(elemType, *elements)
|
||||
|
||||
fun Placement.allocNativeArrayOf(elements: ByteArray): NativeArray<Int8Box> {
|
||||
val res = this.alloc(array[elements.size](Int8Box))
|
||||
elements.forEachIndexed { i, element ->
|
||||
res[i].value = element
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
fun CString.Companion.fromString(str: String?): CString? {
|
||||
if (str == null) {
|
||||
return null
|
||||
|
||||
+50
-2
@@ -1,11 +1,14 @@
|
||||
package org.jetbrains.kotlin.backend.native.llvm
|
||||
|
||||
import kotlin_native.interop.mallocNativeArrayOf
|
||||
import kotlin_native.interop.*
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.native.hash.GlobalHash
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
@@ -16,6 +19,12 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
internal interface ContextUtils {
|
||||
val context: Context
|
||||
|
||||
val runtime: Runtime
|
||||
get() = context.runtime
|
||||
|
||||
val llvmTargetData: LLVMOpaqueTargetData?
|
||||
get() = runtime.targetData
|
||||
|
||||
/**
|
||||
* All fields of the class instance.
|
||||
* The order respects the class hierarchy, i.e. a class [fields] contains superclass [fields] as a prefix.
|
||||
@@ -73,7 +82,7 @@ internal interface ContextUtils {
|
||||
val module = context.llvmModule
|
||||
val globalName = this.typeInfoSymbolName
|
||||
val globalPtr = LLVMGetNamedGlobal(module, globalName) ?:
|
||||
LLVMAddGlobal(module, context.runtime.typeInfoType, globalName)
|
||||
LLVMAddGlobal(module, runtime.typeInfoType, globalName)
|
||||
|
||||
return compileTimeValue(globalPtr)
|
||||
}
|
||||
@@ -114,4 +123,43 @@ internal interface ContextUtils {
|
||||
Zero(pointerType(elemType))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this [GlobalHash] to compile-time value of [runtime]-defined `GlobalHash` type.
|
||||
*
|
||||
* These types must be defined identically.
|
||||
*/
|
||||
private fun GlobalHash.asCompileTimeValue(): Struct {
|
||||
val size = GlobalHash.size
|
||||
assert(size.toLong() == LLVMStoreSizeOfType(llvmTargetData, runtime.globalhHashType))
|
||||
|
||||
return Struct(runtime.globalhHashType, bits.asCompileTimeValue(size))
|
||||
// TODO: implement such transformation more generally using LLVM bitcast
|
||||
// (seems to require some investigation)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this string to the sequence of bytes to be used for hashing/storing to binary/etc.
|
||||
*
|
||||
* TODO: share this implementation
|
||||
*/
|
||||
private fun stringAsBytes(str: String) = str.toByteArray(Charsets.UTF_8)
|
||||
|
||||
val String.localHash: LocalHash
|
||||
get() = LocalHash(localHash(stringAsBytes(this)))
|
||||
|
||||
val String.globalHash: CompileTimeValue
|
||||
get() = memScoped {
|
||||
val hash = globalHash(stringAsBytes(this@globalHash), memScope)
|
||||
hash.asCompileTimeValue()
|
||||
}
|
||||
|
||||
val FqName.globalHash: CompileTimeValue
|
||||
get() = this.toString().globalHash
|
||||
|
||||
val Name.localHash: LocalHash
|
||||
get() = this.toString().localHash
|
||||
|
||||
val FqName.localHash: LocalHash
|
||||
get() = this.toString().localHash
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package org.jetbrains.kotlin.backend.native.llvm
|
||||
|
||||
import kotlin_native.interop.*
|
||||
import org.jetbrains.kotlin.backend.native.hash.*
|
||||
|
||||
internal fun localHash(data: ByteArray): Long {
|
||||
memScoped {
|
||||
val hashBox = alloc(Int64Box)
|
||||
val bytes = allocNativeArrayOf(data)
|
||||
MakeLocalHash(bytes.ptr, data.size, hashBox)
|
||||
return hashBox.value
|
||||
}
|
||||
}
|
||||
|
||||
internal fun globalHash(data: ByteArray, retValPlacement: Placement): GlobalHash {
|
||||
val res = retValPlacement.alloc(GlobalHash)
|
||||
memScoped {
|
||||
val bytes = allocNativeArrayOf(data)
|
||||
MakeGlobalHash(bytes.ptr, data.size, res)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
internal class LocalHash(val value: Long) : CompileTimeValue by Int64(value)
|
||||
+11
@@ -1,5 +1,7 @@
|
||||
package org.jetbrains.kotlin.backend.native.llvm
|
||||
|
||||
import kotlin_native.interop.Int8Box
|
||||
import kotlin_native.interop.NativeArray
|
||||
import kotlin_native.interop.mallocNativeArrayOf
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
@@ -75,3 +77,12 @@ internal fun getLlvmFunctionType(function: FunctionDescriptor): LLVMOpaqueType?
|
||||
val paramTypesPtr = mallocNativeArrayOf(LLVMOpaqueType, *paramTypes)[0] // TODO: dispose
|
||||
return LLVMFunctionType(returnType, paramTypesPtr, paramTypes.size, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents [size] bytes contained in this array as [ConstArray].
|
||||
*/
|
||||
internal fun NativeArray<Int8Box>.asCompileTimeValue(size: Int): ConstArray {
|
||||
return ConstArray(int8Type, (0 .. size-1).map {
|
||||
Int8(this[it].value)
|
||||
})
|
||||
}
|
||||
-18
@@ -2,25 +2,7 @@ package org.jetbrains.kotlin.backend.native.llvm
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import java.util.zip.CRC32
|
||||
|
||||
private fun crc32(str: String): Long {
|
||||
val c = CRC32()
|
||||
c.update(str.toByteArray())
|
||||
return c.value
|
||||
}
|
||||
|
||||
internal val String.nameHash: Long
|
||||
get() = crc32(this)
|
||||
|
||||
internal val Name.nameHash: Long
|
||||
get() = this.toString().nameHash
|
||||
|
||||
internal val FqName.nameHash: Long
|
||||
get() = this.toString().nameHash
|
||||
|
||||
internal val FunctionDescriptor.symbolName: String
|
||||
get() = "kfun:" + this.fqNameSafe.toString() // FIXME: add signature
|
||||
|
||||
+11
-15
@@ -15,17 +15,13 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
|
||||
internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
val runtime: Runtime
|
||||
get() = context.runtime
|
||||
private inner class FieldTableRecord(val nameSignature: LocalHash, val fieldOffset: Int) :
|
||||
Struct(runtime.fieldTableRecordType, nameSignature, Int32(fieldOffset))
|
||||
|
||||
private inner class MethodTableRecord(val nameSignature: LocalHash, val methodEntryPoint: CompileTimeValue) :
|
||||
Struct(runtime.methodTableRecordType, nameSignature, methodEntryPoint)
|
||||
|
||||
private inner class FieldTableRecord(val nameSignature: Long, val fieldOffset: Int) :
|
||||
Struct(runtime.fieldTableRecordType, Int64(nameSignature), Int32(fieldOffset))
|
||||
|
||||
private inner class MethodTableRecord(val nameSignature: Long, val methodEntryPoint: CompileTimeValue) :
|
||||
Struct(runtime.methodTableRecordType, Int64(nameSignature), methodEntryPoint)
|
||||
|
||||
private inner class TypeInfo(val name: Long, val size: Int,
|
||||
private inner class TypeInfo(val name: CompileTimeValue, val size: Int,
|
||||
val superType: CompileTimeValue,
|
||||
val objOffsets: CompileTimeValue,
|
||||
val objOffsetsCount: Int,
|
||||
@@ -39,7 +35,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
Struct(
|
||||
runtime.typeInfoType,
|
||||
|
||||
Struct(runtime.globalhHashType, ConstArray(LLVMInt8Type(), Array(20, {i -> Int8(1)}).toList())),
|
||||
name,
|
||||
Int32(size),
|
||||
|
||||
superType,
|
||||
@@ -122,7 +118,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
val classType = createStructFor(className, classDesc.fields)
|
||||
|
||||
val name = className.nameHash
|
||||
val name = className.globalHash
|
||||
|
||||
val size = LLVMStoreSizeOfType(runtime.targetData, classType).toInt()
|
||||
|
||||
@@ -145,10 +141,10 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
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 nameSignature = field.fqNameSafe.localHash // FIXME: add signature
|
||||
val fieldOffset = LLVMOffsetOfElement(runtime.targetData, classType, index)
|
||||
FieldTableRecord(nameSignature, fieldOffset.toInt())
|
||||
}.sortedBy { it.nameSignature }
|
||||
}.sortedBy { it.nameSignature.value }
|
||||
|
||||
val fieldsPtr = addGlobalConstArray("kfields:$className", runtime.fieldTableRecordType, fields)
|
||||
|
||||
@@ -157,11 +153,11 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
val vtablePtr = addGlobalConstArray("kvtable:$className", pointerType(int8Type), vtable)
|
||||
|
||||
val methods = getMethodTableEntries(classDesc).map {
|
||||
val nameSignature = it.name.nameHash // FIXME: add signature
|
||||
val nameSignature = it.name.localHash // FIXME: add signature
|
||||
// TODO: compile-time resolution limits binary compatibility
|
||||
val methodEntryPoint = it.implementation.entryPointAddress
|
||||
MethodTableRecord(nameSignature, methodEntryPoint)
|
||||
}.sortedBy { it.nameSignature }
|
||||
}.sortedBy { it.nameSignature.value }
|
||||
|
||||
val methodsPtr = addGlobalConstArray("kmethods:$className", runtime.methodTableRecordType, methods)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user