[K/N] Refactor staticData to support several llvm modules
This commit is contained in:
+2
-2
@@ -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<String>()
|
||||
|
||||
val staticData = StaticData(context)
|
||||
val staticData = KotlinStaticData(context)
|
||||
|
||||
private val target = context.config.target
|
||||
|
||||
|
||||
+126
@@ -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<String, ConstPointer>()
|
||||
|
||||
// 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<LLVMValueRef>) =
|
||||
createConstKotlinArray(arrayClass, elements.map { constValue(it) }).llvm
|
||||
|
||||
fun createConstKotlinArray(arrayClass: IrClass, elements: List<ConstValue>): 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<String>): 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)
|
||||
+26
-72
@@ -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<String, ConstPointer>()
|
||||
private val cStringLiterals = mutableMapOf<String, ConstPointer>()
|
||||
|
||||
fun cStringLiteral(value: String) =
|
||||
cStringLiterals.getOrPut(value) { placeCStringLiteral(value) }
|
||||
internal fun placeGlobalConstArray(name: String,
|
||||
elemType: LLVMTypeRef,
|
||||
elements: List<ConstValue>,
|
||||
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<String>): LLVMValueRef {
|
||||
val args = value.value.map { Int8(it.code.toByte()).llvm }
|
||||
return createConstKotlinArray(context.ir.symbols.immutableBlob.owner, args)
|
||||
}
|
||||
-38
@@ -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<ConstValue>,
|
||||
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)
|
||||
}
|
||||
-107
@@ -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<LLVMValueRef>) =
|
||||
createConstKotlinArray(arrayClass, elements.map { constValue(it) }).llvm
|
||||
|
||||
internal fun StaticData.createConstKotlinArray(arrayClass: IrClass, elements: List<ConstValue>): 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)
|
||||
Reference in New Issue
Block a user