From ba69ba7b5b34eee79a2f3b8f9fddf00f6d6443e9 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Tue, 18 Oct 2016 13:13:08 +0300 Subject: [PATCH 1/9] common/hash: fix header compilation errors --- common/src/hash/headers/Sha1.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/src/hash/headers/Sha1.h b/common/src/hash/headers/Sha1.h index 65352e66fd9..34019dfe62f 100644 --- a/common/src/hash/headers/Sha1.h +++ b/common/src/hash/headers/Sha1.h @@ -1,5 +1,8 @@ #ifndef RUNTIME_SHA1_H #define RUNTIME_SHA1_H + +#include + /* SHA-1 in C By Steve Reid From 68686bd57741eba9cc4b39bd55316e0b777755f1 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Tue, 18 Oct 2016 13:49:29 +0300 Subject: [PATCH 2/9] runtime: move name hasing to common/hash --- {runtime/src/main => common/src/hash}/cpp/Names.cpp | 0 {runtime/src/main/cpp => common/src/hash/headers}/Names.h | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {runtime/src/main => common/src/hash}/cpp/Names.cpp (100%) rename {runtime/src/main/cpp => common/src/hash/headers}/Names.h (100%) diff --git a/runtime/src/main/cpp/Names.cpp b/common/src/hash/cpp/Names.cpp similarity index 100% rename from runtime/src/main/cpp/Names.cpp rename to common/src/hash/cpp/Names.cpp diff --git a/runtime/src/main/cpp/Names.h b/common/src/hash/headers/Names.h similarity index 100% rename from runtime/src/main/cpp/Names.h rename to common/src/hash/headers/Names.h From 7350b4da378fc3e0f92709527e354b36710c41bd Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Wed, 19 Oct 2016 11:03:29 +0300 Subject: [PATCH 3/9] backend-native: fix tests after reworking Gradle interop plugin --- backend.native/tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend.native/tests/Makefile b/backend.native/tests/Makefile index f23c927b4e7..f8cf91bfcdb 100644 --- a/backend.native/tests/Makefile +++ b/backend.native/tests/Makefile @@ -15,7 +15,7 @@ RUNTIME=${TOP}/runtime BACKEND=${TOP}/backend.native BACKEND_CLASSES=${TOP}/backend.native/build/classes KOTLIN_DIST=${BACKEND}/kotlin-ir/dist -KOTLIN_NATIVE_CLASSPATH=${BACKEND_CLASSES}/bc_frontend:${BACKEND_CLASSES}/cli_bc:${BACKEND_CLASSES}/compiler:${KOTLIN_DIST}/kotlinc/lib/kotlin-reflect.jar:${KOTLIN_DIST}kotlinc/lib/kotlin-stdlib.jar:${KOTLIN_DIST}/kotlinc/lib/kotlin-compiler.jar:${KOTLIN_DIST}/kotlinc/lib/kotlin-runtime.jar:${TOP}/Interop/Runtime/build/classes/main +KOTLIN_NATIVE_CLASSPATH=${BACKEND_CLASSES}/bc_frontend:${BACKEND_CLASSES}/cli_bc:${BACKEND_CLASSES}/compiler:${BACKEND_CLASSES}/llvmInteropStubs:${BACKEND_CLASSES}/hashInteropStubs:${KOTLIN_DIST}/kotlinc/lib/kotlin-reflect.jar:${KOTLIN_DIST}kotlinc/lib/kotlin-stdlib.jar:${KOTLIN_DIST}/kotlinc/lib/kotlin-compiler.jar:${KOTLIN_DIST}/kotlinc/lib/kotlin-runtime.jar:${TOP}/Interop/Runtime/build/classes/main define PROTO From 5bb5cb70ee1889dce044b1b7cee271333fcd9880 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Tue, 18 Oct 2016 14:49:40 +0300 Subject: [PATCH 4/9] build: trivially support runtime sources written in Kotlin --- backend.native/build.gradle | 4 ++++ backend.native/tests/Makefile | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/backend.native/build.gradle b/backend.native/build.gradle index aa1625fe52d..5faa5acc5ca 100644 --- a/backend.native/build.gradle +++ b/backend.native/build.gradle @@ -76,7 +76,11 @@ build.dependsOn 'compilerClasses','cli_bcClasses','bc_frontendClasses' task run(type: JavaExec) { main 'org.jetbrains.kotlin.cli.bc.K2NativeKt' classpath sourceSets.cli_bc.runtimeClasspath + args 'tests/codegen/function/sum.kt' + + args project(':runtime').file('src/main/kotlin') + args '-output', "$buildDir/out.bc" jvmArgs '-ea' diff --git a/backend.native/tests/Makefile b/backend.native/tests/Makefile index f8cf91bfcdb..556b47f474f 100644 --- a/backend.native/tests/Makefile +++ b/backend.native/tests/Makefile @@ -41,5 +41,5 @@ clean: %.BCkt:%.kt - ${JAVA} -cp ${KOTLIN_NATIVE_CLASSPATH} -Djava.library.path=${BACKEND}/build/nativelibs org.jetbrains.kotlin.cli.bc.K2NativeKt -output $@ -runtime ${RUNTIME}/build/runtime.bc $< + ${JAVA} -cp ${KOTLIN_NATIVE_CLASSPATH} -Djava.library.path=${BACKEND}/build/nativelibs org.jetbrains.kotlin.cli.bc.K2NativeKt -output $@ -runtime ${RUNTIME}/build/runtime.bc ${RUNTIME}/src/main/kotlin $< From d43b0f62bc2be9575b723d73bdbd1be3f4f42d3b Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Wed, 19 Oct 2016 11:02:14 +0300 Subject: [PATCH 5/9] Interop/Runtime: implement trivial lexical mem scopes --- .../kotlin/kotlin_native/interop/Utils.kt | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Utils.kt b/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Utils.kt index d1de51c09cf..db5fb71e7d7 100644 --- a/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Utils.kt +++ b/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Utils.kt @@ -48,4 +48,29 @@ fun CString.Companion.fromString(str: String?): CString? { fun NativeArray.asCString() = CString.fromArray(this) fun Int8Box.asCString() = CString.fromArray(NativeArray.byRefToFirstElem(this, Int8Box)) -fun String.toCString() = CString.fromString(this) \ No newline at end of file +fun String.toCString() = CString.fromString(this) + +class MemScope private constructor(private val arena: Arena) : Placement by arena { + val memScope: Placement + get() = this + + companion object { + internal inline fun use(block: MemScope.()->R): R { + val memScope = MemScope(Arena()) + try { + return memScope.block() + } finally { + memScope.arena.clear() + } + } + } +} + +/** + * Runs given [block] providing allocation of memory + * which will be automatically disposed at the end of this scope. + */ +inline fun memScoped(block: MemScope.()->R): R { + @Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") // TODO: it is a hack + return MemScope.use(block) +} \ No newline at end of file From 9f5f2eecfc94556392c11e4b8ed62b286a20de9f Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Wed, 19 Oct 2016 11:30:54 +0300 Subject: [PATCH 6/9] backend.native: add minor improvements to code for compile time values --- .../kotlin/backend/native/llvm/ContextUtils.kt | 4 +++- .../kotlin/backend/native/llvm/LlvmUtils.kt | 18 +++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/ContextUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/ContextUtils.kt index 7ca0df21e11..63d2df89378 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/ContextUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/ContextUtils.kt @@ -92,13 +92,15 @@ internal interface ContextUtils { /** * Returns pointer to first element of given array. * + * Note: this function doesn't depend on the context + * * @param arrayPtr pointer to array */ private fun getPtrToFirstElem(arrayPtr: CompileTimeValue): CompileTimeValue { val indices = longArrayOf(0, 0).map { LLVMConstInt(LLVMInt32Type(), it, 0) }.toTypedArray() val indicesNativeArrayPtr = mallocNativeArrayOf(LLVMOpaqueValue, *indices)[0] // TODO: dispose - return compileTimeValue(LLVMBuildGEP(context.llvmBuilder, arrayPtr.getLlvmValue(), indicesNativeArrayPtr, indices.size, "")) + return compileTimeValue(LLVMConstGEP(arrayPtr.getLlvmValue(), indicesNativeArrayPtr, indices.size)) } /** diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/LlvmUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/LlvmUtils.kt index 70338199966..bcc8a661229 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/LlvmUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/LlvmUtils.kt @@ -8,9 +8,9 @@ import org.jetbrains.kotlin.utils.singletonOrEmptyList /** * Represents the value which can be emitted as bitcode const value */ -internal abstract class CompileTimeValue { +internal interface CompileTimeValue { - abstract fun getLlvmValue(): LLVMOpaqueValue? + fun getLlvmValue(): LLVMOpaqueValue? fun getLlvmType(): LLVMOpaqueType? { return LLVMTypeOf(getLlvmValue()) @@ -18,7 +18,7 @@ internal abstract class CompileTimeValue { } -internal class ConstArray(val elemType: LLVMOpaqueType?, val elements: List) : CompileTimeValue() { +internal class ConstArray(val elemType: LLVMOpaqueType?, val elements: List) : CompileTimeValue { override fun getLlvmValue(): LLVMOpaqueValue? { val values = elements.map { it.getLlvmValue() }.toTypedArray() @@ -28,7 +28,7 @@ internal class ConstArray(val elemType: LLVMOpaqueType?, val elements: List) : CompileTimeValue() { +internal open class Struct(val type: LLVMOpaqueType?, val elements: List) : CompileTimeValue { constructor(type: LLVMOpaqueType?, vararg elements: CompileTimeValue) : this(type, elements.toList()) @@ -39,23 +39,23 @@ internal open class Struct(val type: LLVMOpaqueType?, val elements: List Date: Wed, 19 Oct 2016 11:31:42 +0300 Subject: [PATCH 7/9] backend.native: use common/hash to compute hashes for RTTI --- .../kotlin/kotlin_native/interop/Utils.kt | 17 +++--- .../backend/native/llvm/ContextUtils.kt | 52 ++++++++++++++++++- .../kotlin/backend/native/llvm/HashUtils.kt | 24 +++++++++ .../kotlin/backend/native/llvm/LlvmUtils.kt | 11 ++++ .../kotlin/backend/native/llvm/NameUtils.kt | 18 ------- .../backend/native/llvm/RTTIGenerator.kt | 26 ++++------ 6 files changed, 104 insertions(+), 44 deletions(-) create mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/HashUtils.kt diff --git a/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Utils.kt b/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Utils.kt index db5fb71e7d7..8027e9bc5e6 100644 --- a/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Utils.kt +++ b/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Utils.kt @@ -2,15 +2,6 @@ package kotlin_native.interop fun malloc(type: NativeRef.TypeWithSize) = type.byPtr(bridge.malloc(type.size)) -inline fun malloc(type: NativeRef.TypeWithSize, 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 Placement.allocNativeArrayOf(elemType: NativeRef.Type, va fun mallocNativeArrayOf(elemType: NativeRef.Type, vararg elements: T?) = heap.allocNativeArrayOf(elemType, *elements) +fun Placement.allocNativeArrayOf(elements: ByteArray): NativeArray { + 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 diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/ContextUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/ContextUtils.kt index 63d2df89378..97dc76328ac 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/ContextUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/ContextUtils.kt @@ -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 } \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/HashUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/HashUtils.kt new file mode 100644 index 00000000000..e5129d32972 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/HashUtils.kt @@ -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) \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/LlvmUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/LlvmUtils.kt index bcc8a661229..1f8e008b4a1 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/LlvmUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/LlvmUtils.kt @@ -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.asCompileTimeValue(size: Int): ConstArray { + return ConstArray(int8Type, (0 .. size-1).map { + Int8(this[it].value) + }) +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/NameUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/NameUtils.kt index 6f9f743cbac..754d64790df 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/NameUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/NameUtils.kt @@ -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 diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/RTTIGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/RTTIGenerator.kt index 18e08942248..c7226b5ef54 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/RTTIGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/RTTIGenerator.kt @@ -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) From a1593c86f149ee97ab090dd7cba9b2674b4e8bb7 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Wed, 19 Oct 2016 12:03:41 +0300 Subject: [PATCH 8/9] backend.native: support external functions also implement changing external function symbol name with the annotation --- .../kotlin/backend/native/llvm/CodeGenerator.kt | 4 ++++ .../kotlin/backend/native/llvm/IrToBitcode.kt | 15 +++++++++++++++ .../kotlin/backend/native/llvm/NameUtils.kt | 16 +++++++++++++++- .../src/main/kotlin/kotlin_native/annotations.kt | 11 +++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 runtime/src/main/kotlin/kotlin_native/annotations.kt diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/CodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/CodeGenerator.kt index 2f585dd0bb2..e4385de9246 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/CodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/CodeGenerator.kt @@ -11,6 +11,10 @@ internal class CodeGenerator(override val context:Context) : ContextUtils { var currentFunction:FunctionDescriptor? = null fun function(declaration: IrFunction) { + if (declaration.descriptor.isExternal) { + return + } + index = 0 currentFunction = declaration.descriptor val fn = LLVMAddFunction(context.llvmModule, declaration.descriptor.symbolName, getLlvmFunctionType(declaration.descriptor)) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/IrToBitcode.kt index ae0fa296d11..24d3331d231 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/IrToBitcode.kt @@ -34,6 +34,12 @@ internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid { override fun visitClass(declaration: IrClass) { super.visitClass(declaration) + + if (declaration.descriptor.kind == ClassKind.ANNOTATION_CLASS) { + // do not generate any RTTI for annotation classes as a workaround for link errors + return + } + generator.generate(declaration.descriptor) } @@ -50,6 +56,15 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid element.acceptChildrenVoid(this) } + override fun visitClass(declaration: IrClass) { + if (declaration.descriptor.kind == ClassKind.ANNOTATION_CLASS) { + // do not generate any code for annotation classes as a workaround for NotImplementedError + return + } + + super.visitClass(declaration) + } + override fun visitSetVariable(expression: IrSetVariable) { val value = evaluateExpression(generator.tmpVariable(), expression.value) generator.store(value!!, generator.variable(expression.descriptor.name.asString())!!) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/NameUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/NameUtils.kt index 754d64790df..a5646d4dead 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/NameUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/NameUtils.kt @@ -2,10 +2,24 @@ 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.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +private val symbolNameAnnotation = FqName("kotlin_native.SymbolName") + internal val FunctionDescriptor.symbolName: String - get() = "kfun:" + this.fqNameSafe.toString() // FIXME: add signature + get() { + this.annotations.findAnnotation(symbolNameAnnotation)?.let { + if (this.isExternal) { + val nameValue = it.allValueArguments.values.single() as StringValue + return nameValue.value + } else { + // ignore; TODO: report compile error + } + } + return "kfun:" + this.fqNameSafe.toString() // FIXME: add signature + } internal val ClassDescriptor.typeInfoSymbolName: String get() = "ktype:" + this.fqNameSafe.toString() \ No newline at end of file diff --git a/runtime/src/main/kotlin/kotlin_native/annotations.kt b/runtime/src/main/kotlin/kotlin_native/annotations.kt new file mode 100644 index 00000000000..de835209772 --- /dev/null +++ b/runtime/src/main/kotlin/kotlin_native/annotations.kt @@ -0,0 +1,11 @@ +package kotlin_native + +/** + * Forces the compiler to use specified symbol name for the target `external` function. + * + * TODO: changing symbol name breaks the binary compatibility, + * so it should probably be allowed on `internal` and `private` functions only. + */ +@Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.BINARY) +annotation class SymbolName(val name: String) From 25403723be4e5a029603dd978a486c6e74905c5a Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Wed, 19 Oct 2016 13:31:00 +0300 Subject: [PATCH 9/9] backend.native: improve memory management using mem scopes --- .../backend/native/llvm/CodeGenerator.kt | 8 ++++--- .../backend/native/llvm/ContextUtils.kt | 7 ++++-- .../kotlin/backend/native/llvm/LlvmUtils.kt | 24 ++++++++++++------- .../backend/native/llvm/RTTIGenerator.kt | 18 ++++++++------ 4 files changed, 36 insertions(+), 21 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/CodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/CodeGenerator.kt index e4385de9246..aec90c0eccc 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/CodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/CodeGenerator.kt @@ -66,9 +66,11 @@ internal class CodeGenerator(override val context:Context) : ContextUtils { fun load(value:LLVMOpaqueValue, varName: String):LLVMOpaqueValue = LLVMBuildLoad(context.llvmBuilder, value, varName)!! fun store(value:LLVMOpaqueValue, ptr:LLVMOpaqueValue):LLVMOpaqueValue = LLVMBuildStore(context.llvmBuilder, value, ptr)!! fun call(descriptor: FunctionDescriptor, args: MutableList, result: String): LLVMOpaqueValue? { - val rargs = malloc(array[args.size](Ref to LLVMOpaqueValue)) - args.forEachIndexed { i, llvmOpaqueValue -> rargs[i].value = args[i]} - return LLVMBuildCall(context.llvmBuilder, descriptor.llvmFunction.getLlvmValue(), rargs[0], args.size, result) + memScoped { + val rargs = alloc(array[args.size](Ref to LLVMOpaqueValue)) + args.forEachIndexed { i, llvmOpaqueValue -> rargs[i].value = args[i] } + return LLVMBuildCall(context.llvmBuilder, descriptor.llvmFunction.getLlvmValue(), rargs[0], args.size, result) + } } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/ContextUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/ContextUtils.kt index 97dc76328ac..4ab4ca692b8 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/ContextUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/ContextUtils.kt @@ -107,9 +107,12 @@ internal interface ContextUtils { */ private fun getPtrToFirstElem(arrayPtr: CompileTimeValue): CompileTimeValue { val indices = longArrayOf(0, 0).map { LLVMConstInt(LLVMInt32Type(), it, 0) }.toTypedArray() - val indicesNativeArrayPtr = mallocNativeArrayOf(LLVMOpaqueValue, *indices)[0] // TODO: dispose - return compileTimeValue(LLVMConstGEP(arrayPtr.getLlvmValue(), indicesNativeArrayPtr, indices.size)) + memScoped { + val indicesNativeArrayPtr = allocNativeArrayOf(LLVMOpaqueValue, *indices)[0] + + return compileTimeValue(LLVMConstGEP(arrayPtr.getLlvmValue(), indicesNativeArrayPtr, indices.size)) + } } /** diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/LlvmUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/LlvmUtils.kt index 1f8e008b4a1..8fca993ec9f 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/LlvmUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/LlvmUtils.kt @@ -1,8 +1,6 @@ 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.* import llvm.* import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.utils.singletonOrEmptyList @@ -24,9 +22,12 @@ internal class ConstArray(val elemType: LLVMOpaqueType?, val elements: List): LLVMOpaqueType? { val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), "kclass:" + className) val fieldTypes = fields.map { getLLVMType(it.returnType!!) }.toTypedArray() - val fieldTypesNativeArrayPtr = if (fieldTypes.size > 0) { - mallocNativeArrayOf(LLVMOpaqueType, *fieldTypes)[0] // TODO: dispose - } else { - null - } - LLVMStructSetBody(classType, fieldTypesNativeArrayPtr, fieldTypes.size, 0) + memScoped { + val fieldTypesNativeArrayPtr = if (fieldTypes.size > 0) { + allocNativeArrayOf(LLVMOpaqueType, *fieldTypes)[0] + } else { + null + } + + LLVMStructSetBody(classType, fieldTypesNativeArrayPtr, fieldTypes.size, 0) + } return classType }