backend.native: use common/hash to compute hashes for RTTI

This commit is contained in:
Svyatoslav Scherbina
2016-10-19 11:31:42 +03:00
parent 9f5f2eecfc
commit 61e1d91c03
6 changed files with 104 additions and 44 deletions
@@ -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
@@ -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
}
@@ -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)
@@ -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)
})
}
@@ -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
@@ -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)