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))
|
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?) {
|
fun free(ptr: NativePtr?) {
|
||||||
if (ptr != null) {
|
if (ptr != null) {
|
||||||
bridge.free(ptr)
|
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 <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? {
|
fun CString.Companion.fromString(str: String?): CString? {
|
||||||
if (str == null) {
|
if (str == null) {
|
||||||
return null
|
return null
|
||||||
|
|||||||
+50
-2
@@ -1,11 +1,14 @@
|
|||||||
package org.jetbrains.kotlin.backend.native.llvm
|
package org.jetbrains.kotlin.backend.native.llvm
|
||||||
|
|
||||||
import kotlin_native.interop.mallocNativeArrayOf
|
import kotlin_native.interop.*
|
||||||
import llvm.*
|
import llvm.*
|
||||||
|
import org.jetbrains.kotlin.backend.native.hash.GlobalHash
|
||||||
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
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
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.classId
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||||
@@ -16,6 +19,12 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
|||||||
internal interface ContextUtils {
|
internal interface ContextUtils {
|
||||||
val context: Context
|
val context: Context
|
||||||
|
|
||||||
|
val runtime: Runtime
|
||||||
|
get() = context.runtime
|
||||||
|
|
||||||
|
val llvmTargetData: LLVMOpaqueTargetData?
|
||||||
|
get() = runtime.targetData
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All fields of the class instance.
|
* All fields of the class instance.
|
||||||
* The order respects the class hierarchy, i.e. a class [fields] contains superclass [fields] as a prefix.
|
* 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 module = context.llvmModule
|
||||||
val globalName = this.typeInfoSymbolName
|
val globalName = this.typeInfoSymbolName
|
||||||
val globalPtr = LLVMGetNamedGlobal(module, globalName) ?:
|
val globalPtr = LLVMGetNamedGlobal(module, globalName) ?:
|
||||||
LLVMAddGlobal(module, context.runtime.typeInfoType, globalName)
|
LLVMAddGlobal(module, runtime.typeInfoType, globalName)
|
||||||
|
|
||||||
return compileTimeValue(globalPtr)
|
return compileTimeValue(globalPtr)
|
||||||
}
|
}
|
||||||
@@ -114,4 +123,43 @@ internal interface ContextUtils {
|
|||||||
Zero(pointerType(elemType))
|
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
|
package org.jetbrains.kotlin.backend.native.llvm
|
||||||
|
|
||||||
|
import kotlin_native.interop.Int8Box
|
||||||
|
import kotlin_native.interop.NativeArray
|
||||||
import kotlin_native.interop.mallocNativeArrayOf
|
import kotlin_native.interop.mallocNativeArrayOf
|
||||||
import llvm.*
|
import llvm.*
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
@@ -75,3 +77,12 @@ internal fun getLlvmFunctionType(function: FunctionDescriptor): LLVMOpaqueType?
|
|||||||
val paramTypesPtr = mallocNativeArrayOf(LLVMOpaqueType, *paramTypes)[0] // TODO: dispose
|
val paramTypesPtr = mallocNativeArrayOf(LLVMOpaqueType, *paramTypes)[0] // TODO: dispose
|
||||||
return LLVMFunctionType(returnType, paramTypesPtr, paramTypes.size, 0)
|
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.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
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 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
|
internal val FunctionDescriptor.symbolName: String
|
||||||
get() = "kfun:" + this.fqNameSafe.toString() // FIXME: add signature
|
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 {
|
internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||||
|
|
||||||
val runtime: Runtime
|
private inner class FieldTableRecord(val nameSignature: LocalHash, val fieldOffset: Int) :
|
||||||
get() = context.runtime
|
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) :
|
private inner class TypeInfo(val name: CompileTimeValue, val size: 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,
|
|
||||||
val superType: CompileTimeValue,
|
val superType: CompileTimeValue,
|
||||||
val objOffsets: CompileTimeValue,
|
val objOffsets: CompileTimeValue,
|
||||||
val objOffsetsCount: Int,
|
val objOffsetsCount: Int,
|
||||||
@@ -39,7 +35,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
Struct(
|
Struct(
|
||||||
runtime.typeInfoType,
|
runtime.typeInfoType,
|
||||||
|
|
||||||
Struct(runtime.globalhHashType, ConstArray(LLVMInt8Type(), Array(20, {i -> Int8(1)}).toList())),
|
name,
|
||||||
Int32(size),
|
Int32(size),
|
||||||
|
|
||||||
superType,
|
superType,
|
||||||
@@ -122,7 +118,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
|
|
||||||
val classType = createStructFor(className, classDesc.fields)
|
val classType = createStructFor(className, classDesc.fields)
|
||||||
|
|
||||||
val name = className.nameHash
|
val name = className.globalHash
|
||||||
|
|
||||||
val size = LLVMStoreSizeOfType(runtime.targetData, classType).toInt()
|
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 ->
|
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
|
// 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)
|
val fieldOffset = LLVMOffsetOfElement(runtime.targetData, classType, index)
|
||||||
FieldTableRecord(nameSignature, fieldOffset.toInt())
|
FieldTableRecord(nameSignature, fieldOffset.toInt())
|
||||||
}.sortedBy { it.nameSignature }
|
}.sortedBy { it.nameSignature.value }
|
||||||
|
|
||||||
val fieldsPtr = addGlobalConstArray("kfields:$className", runtime.fieldTableRecordType, fields)
|
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 vtablePtr = addGlobalConstArray("kvtable:$className", pointerType(int8Type), vtable)
|
||||||
|
|
||||||
val methods = getMethodTableEntries(classDesc).map {
|
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
|
// TODO: compile-time resolution limits binary compatibility
|
||||||
val methodEntryPoint = it.implementation.entryPointAddress
|
val methodEntryPoint = it.implementation.entryPointAddress
|
||||||
MethodTableRecord(nameSignature, methodEntryPoint)
|
MethodTableRecord(nameSignature, methodEntryPoint)
|
||||||
}.sortedBy { it.nameSignature }
|
}.sortedBy { it.nameSignature.value }
|
||||||
|
|
||||||
val methodsPtr = addGlobalConstArray("kmethods:$className", runtime.methodTableRecordType, methods)
|
val methodsPtr = addGlobalConstArray("kmethods:$className", runtime.methodTableRecordType, methods)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user