diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index 0540073a07a..88b36871e8c 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -157,7 +157,7 @@ internal interface ContextUtils : RuntimeAware { val llvmTargetData: LLVMTargetDataRef get() = runtime.targetData - val staticData: StaticData + val staticData: KotlinStaticData get() = context.llvm.staticData /** @@ -427,7 +427,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti val additionalProducedBitcodeFiles = mutableListOf() - val staticData = StaticData(context) + val staticData = KotlinStaticData(context) private val target = context.config.target diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinStaticData.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinStaticData.kt new file mode 100644 index 00000000000..ee1014b3149 --- /dev/null +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinStaticData.kt @@ -0,0 +1,126 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the LICENSE file. + */ + +package org.jetbrains.kotlin.backend.konan.llvm + +import kotlinx.cinterop.cValuesOf +import llvm.* +import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.expressions.IrConst + +private fun ConstPointer.add(index: Int): ConstPointer { + return constPointer(LLVMConstGEP(llvm, cValuesOf(Int32(index).llvm), 1)!!) +} + +internal class KotlinStaticData(override val context: Context) : ContextUtils, StaticData(context.llvmModule!!) { + private val stringLiterals = mutableMapOf() + + // Must match OBJECT_TAG_PERMANENT_CONTAINER in C++. + private fun permanentTag(typeInfo: ConstPointer): ConstPointer { + // Only pointer arithmetic via GEP works on constant pointers in LLVM. + return typeInfo.bitcast(int8TypePtr).add(1).bitcast(kTypeInfoPtr) + } + + + private fun objHeader(typeInfo: ConstPointer): Struct { + return Struct(runtime.objHeaderType, permanentTag(typeInfo)) + } + + private fun arrayHeader(typeInfo: ConstPointer, length: Int): Struct { + assert(length >= 0) + return Struct(runtime.arrayHeaderType, permanentTag(typeInfo), Int32(length)) + } + + private fun createRef(objHeaderPtr: ConstPointer) = objHeaderPtr.bitcast(kObjHeaderPtr) + + private fun createKotlinStringLiteral(value: String): ConstPointer { + val elements = value.toCharArray().map(::Char16) + val objRef = createConstKotlinArray(context.ir.symbols.string.owner, elements) + return objRef + } + + fun kotlinStringLiteral(value: String) = stringLiterals.getOrPut(value) { createKotlinStringLiteral(value) } + + fun createConstKotlinArray(arrayClass: IrClass, elements: List) = + createConstKotlinArray(arrayClass, elements.map { constValue(it) }).llvm + + fun createConstKotlinArray(arrayClass: IrClass, elements: List): ConstPointer { + val typeInfo = arrayClass.typeInfoPtr + + val bodyElementType: LLVMTypeRef = elements.firstOrNull()?.llvmType ?: int8Type + // (use [0 x i8] as body if there are no elements) + val arrayBody = ConstArray(bodyElementType, elements) + + val compositeType = structType(runtime.arrayHeaderType, arrayBody.llvmType) + + val global = this.createGlobal(compositeType, "") + + val objHeaderPtr = global.pointer.getElementPtr(0) + val arrayHeader = arrayHeader(typeInfo, elements.size) + + global.setInitializer(Struct(compositeType, arrayHeader, arrayBody)) + global.setConstant(true) + global.setUnnamedAddr(true) + + return createRef(objHeaderPtr) + } + + fun createConstKotlinObject(type: IrClass, vararg fields: ConstValue): ConstPointer { + val typeInfo = type.typeInfoPtr + val objHeader = objHeader(typeInfo) + + val global = this.placeGlobal("", Struct(objHeader, *fields)) + global.setUnnamedAddr(true) + global.setConstant(true) + + val objHeaderPtr = global.pointer.getElementPtr(0) + + return createRef(objHeaderPtr) + } + + fun createInitializer(type: IrClass, vararg fields: ConstValue): ConstValue = + Struct(objHeader(type.typeInfoPtr), *fields) + + fun createUniqueInstance( + kind: UniqueKind, bodyType: LLVMTypeRef, typeInfo: ConstPointer): ConstPointer { + assert(getStructElements(bodyType).size == 1) // ObjHeader only. + val objHeader = when (kind) { + UniqueKind.UNIT -> objHeader(typeInfo) + UniqueKind.EMPTY_ARRAY -> arrayHeader(typeInfo, 0) + } + val global = this.placeGlobal(kind.llvmName, objHeader, isExported = true) + global.setConstant(true) + return global.pointer + } + + fun unique(kind: UniqueKind): ConstPointer { + val descriptor = when (kind) { + UniqueKind.UNIT -> context.ir.symbols.unit.owner + UniqueKind.EMPTY_ARRAY -> context.ir.symbols.array.owner + } + return if (isExternal(descriptor)) { + constPointer(importGlobal( + kind.llvmName, context.llvm.runtime.objHeaderType, origin = descriptor.llvmSymbolOrigin + )) + } else { + context.llvmDeclarations.forUnique(kind).pointer + } + } + + /** + * Creates static instance of `konan.ImmutableByteArray` with given values of elements. + * + * @param args data for constant creation. + */ + fun createImmutableBlob(value: IrConst): LLVMValueRef { + val args = value.value.map { Int8(it.code.toByte()).llvm } + return createConstKotlinArray(context.ir.symbols.immutableBlob.owner, args) + } +} + +internal val ContextUtils.theUnitInstanceRef: ConstPointer + get() = staticData.unique(UniqueKind.UNIT) \ No newline at end of file diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticData.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticData.kt index 4333633292d..27695625678 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticData.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticData.kt @@ -7,17 +7,16 @@ package org.jetbrains.kotlin.backend.konan.llvm import llvm.* import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.ir.expressions.IrConst /** * Provides utilities to create static data. */ -internal class StaticData(override val context: Context): ContextUtils { +internal open class StaticData(val module: LLVMModuleRef) { /** * Represents the LLVM global variable. */ - class Global private constructor(val staticData: StaticData, val llvmGlobal: LLVMValueRef) { + class Global private constructor(val llvmGlobal: LLVMValueRef) { companion object { private fun createLlvmGlobal(module: LLVMModuleRef, @@ -41,20 +40,18 @@ internal class StaticData(override val context: Context): ContextUtils { } fun create(staticData: StaticData, type: LLVMTypeRef, name: String, isExported: Boolean): Global { - val module = staticData.context.llvmModule - val isUnnamed = (name == "") // LLVM will select the unique index and represent the global as `@idx`. if (isUnnamed && isExported) { throw IllegalArgumentException("unnamed global can't be exported") } - val llvmGlobal = createLlvmGlobal(module!!, type, name, isExported) - return Global(staticData, llvmGlobal) + val llvmGlobal = createLlvmGlobal(staticData.module, type, name, isExported) + return Global(llvmGlobal) } fun get(staticData: StaticData, name: String): Global? { - val llvmGlobal = LLVMGetNamedGlobal(staticData.context.llvmModule, name) ?: return null - return Global(staticData, llvmGlobal) + val llvmGlobal = LLVMGetNamedGlobal(staticData.module, name) ?: return null + return Global(llvmGlobal) } } @@ -97,54 +94,7 @@ internal class StaticData(override val context: Context): ContextUtils { LLVMSetExternallyInitialized(llvmGlobal, if (value) 1 else 0) } - val pointer = Pointer.to(this) - } - - /** - * Represents the pointer to static data. - * It can be a pointer to either a global or any its element. - * - * TODO: this class is probably should be implemented more optimally - */ - class Pointer private constructor(val global: Global, - private val delegate: ConstPointer, - val offsetInGlobal: Long) : ConstPointer by delegate { - - companion object { - fun to(global: Global) = Pointer(global, constPointer(global.llvmGlobal), 0L) - } - - private fun getElementOffset(index: Int): Long { - val llvmTargetData = global.staticData.llvmTargetData - val type = LLVMGetElementType(delegate.llvmType) - return when (LLVMGetTypeKind(type)) { - LLVMTypeKind.LLVMStructTypeKind -> LLVMOffsetOfElement(llvmTargetData, type, index) - LLVMTypeKind.LLVMArrayTypeKind -> LLVMABISizeOfType(llvmTargetData, LLVMGetElementType(type)) * index - else -> TODO() - } - } - - override fun getElementPtr(index: Int): Pointer { - return Pointer(global, delegate.getElementPtr(index), offsetInGlobal + this.getElementOffset(index)) - } - - /** - * @return the distance from other pointer to this. - * - * @throws UnsupportedOperationException if it is not possible to represent the distance as [Int] value - */ - fun sub(other: Pointer): Int { - if (this.global != other.global) { - throw UnsupportedOperationException("pointers must belong to the same global") - } - - val res = this.offsetInGlobal - other.offsetInGlobal - if (res.toInt().toLong() != res) { - throw UnsupportedOperationException("result doesn't fit into Int") - } - - return res.toInt() - } + val pointer : ConstPointer = constPointer(this.llvmGlobal) } /** @@ -179,22 +129,26 @@ internal class StaticData(override val context: Context): ContextUtils { return global } - private val stringLiterals = mutableMapOf() private val cStringLiterals = mutableMapOf() - fun cStringLiteral(value: String) = - cStringLiterals.getOrPut(value) { placeCStringLiteral(value) } + internal fun placeGlobalConstArray(name: String, + elemType: LLVMTypeRef, + elements: List, + isExported: Boolean = false): ConstPointer { + if (elements.isNotEmpty() || isExported) { + val global = placeGlobalArray(name, elemType, elements, isExported) + global.setConstant(true) + return global.pointer.getElementPtr(0) + } else { + return NullPointer(elemType) + } + } - fun kotlinStringLiteral(value: String) = - stringLiterals.getOrPut(value) { createKotlinStringLiteral(value) } + internal fun placeCStringLiteral(value: String) : ConstPointer { + val chars = value.toByteArray(Charsets.UTF_8).map { Int8(it) } + Int8(0) + + return placeGlobalConstArray("", int8Type, chars) + } + + internal fun cStringLiteral(value: String) = cStringLiterals.getOrPut(value) { placeCStringLiteral(value) } } - -/** - * Creates static instance of `konan.ImmutableByteArray` with given values of elements. - * - * @param args data for constant creation. - */ -internal fun StaticData.createImmutableBlob(value: IrConst): LLVMValueRef { - val args = value.value.map { Int8(it.code.toByte()).llvm } - return createConstKotlinArray(context.ir.symbols.immutableBlob.owner, args) -} \ No newline at end of file diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticDataUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticDataUtils.kt deleted file mode 100644 index 978dda08df6..00000000000 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticDataUtils.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package org.jetbrains.kotlin.backend.konan.llvm - -import llvm.* - -/** - * Creates const array-typed global with given name and value. - * Returns pointer to the first element of the array. - * - * If [elements] is empty, then null pointer is returned. - */ -internal fun StaticData.placeGlobalConstArray(name: String, - elemType: LLVMTypeRef, - elements: List, - isExported: Boolean = false): ConstPointer { - if (elements.isNotEmpty() || isExported) { - val global = this.placeGlobalArray(name, elemType, elements, isExported) - global.setConstant(true) - return global.pointer.getElementPtr(0) - } else { - return NullPointer(elemType) - } -} - -internal fun StaticData.createAlias(name: String, aliasee: ConstPointer): ConstPointer { - val alias = LLVMAddAlias(context.llvmModule, aliasee.llvmType, aliasee.llvm, name)!! - return constPointer(alias) -} - -internal fun StaticData.placeCStringLiteral(value: String): ConstPointer { - val chars = value.toByteArray(Charsets.UTF_8).map { Int8(it) } + Int8(0) - - return placeGlobalConstArray("", int8Type, chars) -} \ No newline at end of file diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticObjects.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticObjects.kt deleted file mode 100644 index af367293204..00000000000 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticObjects.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package org.jetbrains.kotlin.backend.konan.llvm - -import kotlinx.cinterop.cValuesOf -import llvm.* -import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin -import org.jetbrains.kotlin.ir.declarations.IrClass - -private fun ConstPointer.add(index: Int): ConstPointer { - return constPointer(LLVMConstGEP(llvm, cValuesOf(Int32(index).llvm), 1)!!) -} - -// Must match OBJECT_TAG_PERMANENT_CONTAINER in C++. -private fun StaticData.permanentTag(typeInfo: ConstPointer): ConstPointer { - // Only pointer arithmetic via GEP works on constant pointers in LLVM. - return typeInfo.bitcast(int8TypePtr).add(1).bitcast(kTypeInfoPtr) -} - -private fun StaticData.objHeader(typeInfo: ConstPointer): Struct { - return Struct(runtime.objHeaderType, permanentTag(typeInfo)) -} - -private fun StaticData.arrayHeader(typeInfo: ConstPointer, length: Int): Struct { - assert (length >= 0) - return Struct(runtime.arrayHeaderType, permanentTag(typeInfo), Int32(length)) -} - -internal fun StaticData.createKotlinStringLiteral(value: String): ConstPointer { - val elements = value.toCharArray().map(::Char16) - val objRef = createConstKotlinArray(context.ir.symbols.string.owner, elements) - return objRef -} - -private fun StaticData.createRef(objHeaderPtr: ConstPointer) = objHeaderPtr.bitcast(kObjHeaderPtr) - -internal fun StaticData.createConstKotlinArray(arrayClass: IrClass, elements: List) = - createConstKotlinArray(arrayClass, elements.map { constValue(it) }).llvm - -internal fun StaticData.createConstKotlinArray(arrayClass: IrClass, elements: List): ConstPointer { - val typeInfo = arrayClass.typeInfoPtr - - val bodyElementType: LLVMTypeRef = elements.firstOrNull()?.llvmType ?: int8Type - // (use [0 x i8] as body if there are no elements) - val arrayBody = ConstArray(bodyElementType, elements) - - val compositeType = structType(runtime.arrayHeaderType, arrayBody.llvmType) - - val global = this.createGlobal(compositeType, "") - - val objHeaderPtr = global.pointer.getElementPtr(0) - val arrayHeader = arrayHeader(typeInfo, elements.size) - - global.setInitializer(Struct(compositeType, arrayHeader, arrayBody)) - global.setConstant(true) - global.setUnnamedAddr(true) - - return createRef(objHeaderPtr) -} - -internal fun StaticData.createConstKotlinObject(type: IrClass, vararg fields: ConstValue): ConstPointer { - val typeInfo = type.typeInfoPtr - val objHeader = objHeader(typeInfo) - - val global = this.placeGlobal("", Struct(objHeader, *fields)) - global.setUnnamedAddr(true) - global.setConstant(true) - - val objHeaderPtr = global.pointer.getElementPtr(0) - - return createRef(objHeaderPtr) -} - -internal fun StaticData.createInitializer(type: IrClass, vararg fields: ConstValue): ConstValue = - Struct(objHeader(type.typeInfoPtr), *fields) - -internal fun StaticData.createUniqueInstance( - kind: UniqueKind, bodyType: LLVMTypeRef, typeInfo: ConstPointer): ConstPointer { - assert (getStructElements(bodyType).size == 1) // ObjHeader only. - val objHeader = when (kind) { - UniqueKind.UNIT -> objHeader(typeInfo) - UniqueKind.EMPTY_ARRAY -> arrayHeader(typeInfo, 0) - } - val global = this.placeGlobal(kind.llvmName, objHeader, isExported = true) - global.setConstant(true) - return global.pointer -} - -internal fun ContextUtils.unique(kind: UniqueKind): ConstPointer { - val descriptor = when (kind) { - UniqueKind.UNIT -> context.ir.symbols.unit.owner - UniqueKind.EMPTY_ARRAY -> context.ir.symbols.array.owner - } - return if (isExternal(descriptor)) { - constPointer(importGlobal( - kind.llvmName, context.llvm.runtime.objHeaderType, origin = descriptor.llvmSymbolOrigin - )) - } else { - context.llvmDeclarations.forUnique(kind).pointer - } -} - -internal val ContextUtils.theUnitInstanceRef: ConstPointer - get() = this.unique(UniqueKind.UNIT) \ No newline at end of file