backend: rework descriptor usage
* handle differently internal and exported declarations * bind LLVM declarations to descriptor instances used as keys * fix some related issues
This commit is contained in:
committed by
SvyatoslavScherbina
parent
cf946a7676
commit
a97b3935e2
+2
-5
@@ -3,10 +3,6 @@ package org.jetbrains.kotlin.backend.konan
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.ir.Ir
|
||||
import org.jetbrains.kotlin.backend.konan.ir.ModuleIndex
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.Runtime
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.getFunctionType
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.StaticData
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.Llvm
|
||||
import org.jetbrains.kotlin.backend.konan.KonanBackendContext
|
||||
import org.jetbrains.kotlin.backend.konan.KonanPhase
|
||||
import org.jetbrains.kotlin.backend.konan.KonanConfig
|
||||
@@ -15,7 +11,7 @@ import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.deepPrint
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.verifyModule
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||
import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
|
||||
import java.lang.System.out
|
||||
|
||||
@@ -50,6 +46,7 @@ internal final class Context(val config: KonanConfig) : KonanBackendContext() {
|
||||
}
|
||||
|
||||
lateinit var llvm: Llvm
|
||||
lateinit var llvmDeclarations: LlvmDeclarations
|
||||
|
||||
var phase: KonanPhase? = null
|
||||
var depth: Int = 0
|
||||
|
||||
+9
-12
@@ -35,16 +35,16 @@ internal val ClassDescriptor.implementedInterfaces: List<ClassDescriptor>
|
||||
*
|
||||
* TODO: this method is actually a part of resolve and probably duplicates another one
|
||||
*/
|
||||
internal val FunctionDescriptor.implementation: FunctionDescriptor
|
||||
get() {
|
||||
if (this.kind.isReal) {
|
||||
return this
|
||||
} else {
|
||||
val overridden = OverridingUtil.getOverriddenDeclarations(this)
|
||||
val filtered = OverridingUtil.filterOutOverridden(overridden)
|
||||
return filtered.first { it.modality != Modality.ABSTRACT } as FunctionDescriptor
|
||||
}
|
||||
internal fun FunctionDescriptor.resolveFakeOverride(): FunctionDescriptor {
|
||||
if (this.kind.isReal) {
|
||||
return this
|
||||
} else {
|
||||
val overridden = OverridingUtil.getOverriddenDeclarations(this)
|
||||
val filtered = OverridingUtil.filterOutOverridden(overridden)
|
||||
// TODO: is it correct to take first?
|
||||
return filtered.first { it.modality != Modality.ABSTRACT } as FunctionDescriptor
|
||||
}
|
||||
}
|
||||
|
||||
private val intrinsicAnnotation = FqName("konan.internal.Intrinsic")
|
||||
|
||||
@@ -193,9 +193,6 @@ val ClassDescriptor.vtableEntries: List<FunctionDescriptor>
|
||||
return inheritedVtableSlots + (methods - inheritedVtableSlots).filter { it.isOverridable }
|
||||
}
|
||||
|
||||
val ClassDescriptor.vtableSize: Int
|
||||
get() = if (this.isAbstract()) 0 else this.vtableEntries.size
|
||||
|
||||
fun ClassDescriptor.vtableIndex(function: FunctionDescriptor): Int {
|
||||
this.vtableEntries.forEachIndexed { index, functionDescriptor ->
|
||||
if (functionDescriptor == function.original) return index
|
||||
|
||||
+4
-8
@@ -1,5 +1,6 @@
|
||||
package org.jetbrains.kotlin.backend.konan.ir
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
@@ -8,15 +9,13 @@ import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
|
||||
class ModuleIndex(val module: IrModuleFragment) {
|
||||
|
||||
/**
|
||||
* Contains all classes declared in [module]
|
||||
*/
|
||||
val classes: Map<ClassId, IrClass>
|
||||
val classes: Map<ClassDescriptor, IrClass>
|
||||
|
||||
/**
|
||||
* Contains all functions declared in [module]
|
||||
@@ -24,7 +23,7 @@ class ModuleIndex(val module: IrModuleFragment) {
|
||||
val functions = mutableMapOf<FunctionDescriptor, IrFunction>()
|
||||
|
||||
init {
|
||||
val map = mutableMapOf<ClassId, IrClass>()
|
||||
val map = mutableMapOf<ClassDescriptor, IrClass>()
|
||||
|
||||
module.acceptVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
@@ -34,10 +33,7 @@ class ModuleIndex(val module: IrModuleFragment) {
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
super.visitClass(declaration)
|
||||
|
||||
val classId = declaration.descriptor.classId
|
||||
if (classId != null) {
|
||||
map[classId] = declaration
|
||||
}
|
||||
map[declaration.descriptor] = declaration
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
import llvm.LLVMTypeRef
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.allValueParameters
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isUnit
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.findOriginalTopMostOverriddenDescriptors
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||
|
||||
// This file describes the ABI for Kotlin descriptors of exported declarations.
|
||||
// TODO: revise the naming scheme to ensure it produces unique names.
|
||||
// TODO: do not serialize descriptors of non-exported declarations.
|
||||
|
||||
/**
|
||||
* Defines whether the declaration is exported, i.e. visible from other modules.
|
||||
*
|
||||
* Exported declarations must have predictable and stable ABI
|
||||
* that doesn't depend on any internal transformations (e.g. IR lowering),
|
||||
* and so should be computable from the descriptor itself without checking a backend state.
|
||||
*/
|
||||
internal tailrec fun DeclarationDescriptor.isExported(): Boolean {
|
||||
if (this.annotations.findAnnotation(symbolNameAnnotation) != null) {
|
||||
// Treat any `@SymbolName` declaration as exported.
|
||||
return true
|
||||
}
|
||||
if (this.annotations.findAnnotation(exportForCppRuntimeAnnotation) != null) {
|
||||
// Treat any `@ExportForCppRuntime` declaration as exported.
|
||||
return true
|
||||
}
|
||||
|
||||
if (this is ConstructorDescriptor && constructedClass.kind.isSingleton) {
|
||||
// Currently code generator can access the constructor of the singleton,
|
||||
// so ignore visibility of the constructor itself.
|
||||
return constructedClass.isExported()
|
||||
}
|
||||
|
||||
if (this is DeclarationDescriptorWithVisibility && !this.visibility.isPublicAPI) {
|
||||
// If the declaration is explicitly marked as non-public,
|
||||
// then it must not be accessible from other modules.
|
||||
return false
|
||||
}
|
||||
|
||||
if (this is DeclarationDescriptorNonRoot) {
|
||||
// If the declaration is not root, then check its container too.
|
||||
return containingDeclaration.isExported()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private val symbolNameAnnotation = FqName("konan.SymbolName")
|
||||
|
||||
private val exportForCppRuntimeAnnotation = FqName("konan.internal.ExportForCppRuntime")
|
||||
|
||||
private fun typeToHashString(type: KotlinType): String {
|
||||
if (TypeUtils.isTypeParameter(type)) return "GENERIC"
|
||||
|
||||
var hashString = TypeUtils.getClassDescriptor(type)!!.fqNameSafe.asString()
|
||||
if (!type.arguments.isEmpty()) {
|
||||
hashString += "<${type.arguments.map {
|
||||
typeToHashString(it.type)
|
||||
}.joinToString(",")}>"
|
||||
}
|
||||
|
||||
if (type.isMarkedNullable) hashString += "?"
|
||||
return hashString
|
||||
}
|
||||
|
||||
private val FunctionDescriptor.signature: String
|
||||
get() {
|
||||
val extensionReceiverPart = this.extensionReceiverParameter?.let { "${it.type}." } ?: ""
|
||||
val actualDescriptor = this.findOriginalTopMostOverriddenDescriptors().firstOrNull() ?: this
|
||||
|
||||
val argsPart = actualDescriptor.valueParameters.map {
|
||||
typeToHashString(it.type)
|
||||
}.joinToString(";")
|
||||
|
||||
// TODO: add return type
|
||||
// (it is not simple because return type can be changed when overriding)
|
||||
return "$extensionReceiverPart($argsPart)"
|
||||
}
|
||||
|
||||
// TODO: rename to indicate that it has signature included
|
||||
internal val FunctionDescriptor.functionName: String
|
||||
get() = with(this.original) { // basic support for generics
|
||||
"$name$signature"
|
||||
}
|
||||
|
||||
internal val FunctionDescriptor.symbolName: String
|
||||
get() {
|
||||
if (!this.isExported()) {
|
||||
throw AssertionError(this.toString())
|
||||
}
|
||||
|
||||
this.annotations.findAnnotation(symbolNameAnnotation)?.let {
|
||||
if (this.isExternal) {
|
||||
return getStringValue(it)!!
|
||||
} else {
|
||||
// ignore; TODO: report compile error
|
||||
}
|
||||
}
|
||||
|
||||
this.annotations.findAnnotation(exportForCppRuntimeAnnotation)?.let {
|
||||
val name = getStringValue(it) ?: this.name.asString()
|
||||
return name // no wrapping currently required
|
||||
}
|
||||
|
||||
val containingDeclarationPart = containingDeclaration.fqNameSafe.let {
|
||||
if (it.isRoot) "" else "$it."
|
||||
}
|
||||
return "kfun:$containingDeclarationPart$functionName"
|
||||
}
|
||||
|
||||
private fun getStringValue(annotation: AnnotationDescriptor): String? {
|
||||
annotation.allValueArguments.values.ifNotEmpty {
|
||||
val stringValue = this.single() as StringValue
|
||||
return stringValue.value
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
// TODO: bring here dependencies of this method?
|
||||
internal fun RuntimeAware.getLlvmFunctionType(function: FunctionDescriptor): LLVMTypeRef {
|
||||
val original = function.original
|
||||
val returnType = if (original is ConstructorDescriptor) voidType else getLLVMReturnType(original.returnType!!)
|
||||
val paramTypes = ArrayList(original.allValueParameters.map { getLLVMType(it.type) })
|
||||
if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr)
|
||||
|
||||
return functionType(returnType, isVarArg = false, paramTypes = *paramTypes.toTypedArray())
|
||||
}
|
||||
|
||||
internal val ClassDescriptor.typeInfoSymbolName: String
|
||||
get() {
|
||||
assert (this.isExported())
|
||||
return "ktype:" + this.fqNameSafe.toString()
|
||||
}
|
||||
|
||||
internal val theUnitInstanceName = "kobj:kotlin.Unit"
|
||||
|
||||
internal val ClassDescriptor.objectInstanceFieldSymbolName: String
|
||||
get() {
|
||||
assert (this.isExported())
|
||||
assert (this.kind.isSingleton)
|
||||
assert (!this.isUnit())
|
||||
|
||||
return "kobjref:$fqNameSafe"
|
||||
}
|
||||
+9
-8
@@ -23,8 +23,16 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
var localAllocs = 0
|
||||
|
||||
fun prologue(descriptor: FunctionDescriptor) {
|
||||
prologue(llvmFunction(descriptor),
|
||||
val llvmFunction = llvmFunction(descriptor)
|
||||
|
||||
prologue(llvmFunction,
|
||||
LLVMGetReturnType(getLlvmFunctionType(descriptor))!!)
|
||||
|
||||
if (!descriptor.isExported()) {
|
||||
LLVMSetLinkage(llvmFunction, LLVMLinkage.LLVMPrivateLinkage)
|
||||
// (Cannot do this before the function body is created).
|
||||
}
|
||||
|
||||
if (descriptor is ConstructorDescriptor) {
|
||||
constructedClass = descriptor.constructedClass
|
||||
}
|
||||
@@ -300,7 +308,6 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
/* to class descriptor */
|
||||
fun classType(descriptor: ClassDescriptor): LLVMTypeRef = LLVMGetTypeByName(context.llvmModule, descriptor.symbolName)!!
|
||||
fun typeInfoValue(descriptor: ClassDescriptor): LLVMValueRef = descriptor.llvmTypeInfoPtr
|
||||
|
||||
/**
|
||||
@@ -314,12 +321,6 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
}
|
||||
fun countParams(fn: FunctionDescriptor) = LLVMCountParams(fn.llvmFunction)
|
||||
|
||||
fun indexInClass(p:PropertyDescriptor):Int {
|
||||
val index = (p.containingDeclaration as ClassDescriptor).fields.indexOf(p)
|
||||
assert(index >= 0) { "Unable to find property $p" }
|
||||
return index
|
||||
}
|
||||
|
||||
fun basicBlock(name: String = "label_"): LLVMBasicBlockRef {
|
||||
val currentBlock = this.currentBlock
|
||||
val result = LLVMInsertBasicBlock(currentBlock, name)!!
|
||||
|
||||
+21
-83
@@ -3,24 +3,15 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
||||
import kotlinx.cinterop.*
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.Distribution
|
||||
import org.jetbrains.kotlin.backend.konan.hash.GlobalHash
|
||||
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.backingField
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.vtableSize
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
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
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
|
||||
@@ -33,10 +24,10 @@ const val SCOPE_PERMANENT = 3
|
||||
/**
|
||||
* Provides utility methods to the implementer.
|
||||
*/
|
||||
internal interface ContextUtils {
|
||||
internal interface ContextUtils : RuntimeAware {
|
||||
val context: Context
|
||||
|
||||
val runtime: Runtime
|
||||
override val runtime: Runtime
|
||||
get() = context.llvm.runtime
|
||||
|
||||
/**
|
||||
@@ -50,57 +41,7 @@ internal interface ContextUtils {
|
||||
val staticData: StaticData
|
||||
get() = context.llvm.staticData
|
||||
|
||||
/**
|
||||
* All fields of the class instance.
|
||||
* The order respects the class hierarchy, i.e. a class [fields] contains superclass [fields] as a prefix.
|
||||
*/
|
||||
val ClassDescriptor.fields: List<PropertyDescriptor>
|
||||
get() {
|
||||
val superClass = this.getSuperClassNotAny() // TODO: what if Any has fields?
|
||||
val superFields = if (superClass != null) superClass.fields else emptyList()
|
||||
|
||||
return superFields + this.declaredFields
|
||||
}
|
||||
|
||||
/**
|
||||
* Fields declared in the class.
|
||||
*/
|
||||
val ClassDescriptor.declaredFields: List<PropertyDescriptor>
|
||||
get() {
|
||||
// TODO: Here's what is going on here:
|
||||
// The existence of a backing field for a property is only described in the IR,
|
||||
// but not in the property descriptor.
|
||||
// That works, while we process the IR, but not for deserialized descriptors.
|
||||
//
|
||||
// So to have something in deserialized descriptors,
|
||||
// while we still see the IR, we mark the property with an annotation.
|
||||
//
|
||||
// We could apply the annotation during IR rewite, but we still are not
|
||||
// that far in the rewriting infrastructure. So we postpone
|
||||
// the annotation until the serializer.
|
||||
//
|
||||
// In this function we check the presence of the backing filed
|
||||
// two ways: first we check IR, then we check the annotation.
|
||||
|
||||
val irClass = context.ir.moduleIndexForCodegen.classes[this.classId]
|
||||
if (irClass != null) {
|
||||
val declarations = irClass.declarations
|
||||
|
||||
return declarations.mapNotNull {
|
||||
when (it) {
|
||||
is IrProperty -> it.backingField?.descriptor
|
||||
is IrField -> it.descriptor
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val properties = this.unsubstitutedMemberScope.
|
||||
getContributedDescriptors().
|
||||
filterIsInstance<PropertyDescriptor>()
|
||||
|
||||
return properties.mapNotNull{ it.backingField }
|
||||
}
|
||||
}
|
||||
fun isExternal(descriptor: DeclarationDescriptor) = descriptor.module != context.ir.irModule.descriptor
|
||||
|
||||
/**
|
||||
* LLVM function generated from the Kotlin function.
|
||||
@@ -112,13 +53,12 @@ internal interface ContextUtils {
|
||||
if (this is TypeAliasConstructorDescriptor) {
|
||||
return this.underlyingConstructorDescriptor.llvmFunction
|
||||
}
|
||||
val globalName = this.symbolName
|
||||
val module = context.llvmModule
|
||||
|
||||
val functionType = getLlvmFunctionType(this)
|
||||
|
||||
return LLVMGetNamedFunction(module, globalName) ?:
|
||||
LLVMAddFunction(module, globalName, functionType)!!
|
||||
return if (isExternal(this)) {
|
||||
context.llvm.externalFunction(this.symbolName, getLlvmFunctionType(this))
|
||||
} else {
|
||||
context.llvmDeclarations.forFunction(this).llvmFunction
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,17 +70,14 @@ internal interface ContextUtils {
|
||||
return constValue(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Pointer to struct { TypeInfo, vtable }.
|
||||
*/
|
||||
val ClassDescriptor.typeInfoWithVtable: ConstPointer
|
||||
get() {
|
||||
val type = structType(runtime.typeInfoType, LLVMArrayType(int8TypePtr, this.vtableSize)!!)
|
||||
return constPointer(externalGlobal(this.typeInfoSymbolName, type))
|
||||
}
|
||||
|
||||
val ClassDescriptor.typeInfoPtr: ConstPointer
|
||||
get() = typeInfoWithVtable.getElementPtr(0)
|
||||
get() {
|
||||
return if (isExternal(this)) {
|
||||
constPointer(externalGlobal(this.typeInfoSymbolName, runtime.typeInfoType))
|
||||
} else {
|
||||
context.llvmDeclarations.forClass(this).typeInfo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pointer to type info for given class.
|
||||
@@ -238,13 +175,14 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun externalFunction(name: String, type: LLVMTypeRef): LLVMValueRef {
|
||||
val found = LLVMGetNamedFunction(context.llvmModule, name)
|
||||
internal fun externalFunction(name: String, type: LLVMTypeRef): LLVMValueRef {
|
||||
val found = LLVMGetNamedFunction(llvmModule, name)
|
||||
if (found != null) {
|
||||
assert (getFunctionType(found) == type)
|
||||
assert (LLVMGetLinkage(found) == LLVMLinkage.LLVMExternalLinkage)
|
||||
return found
|
||||
} else {
|
||||
return LLVMAddFunction(context.llvmModule, name, type)!!
|
||||
return LLVMAddFunction(llvmModule, name, type)!!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
|
||||
internal fun ContextUtils.getLLVMType(type: KotlinType): LLVMTypeRef {
|
||||
internal fun RuntimeAware.getLLVMType(type: KotlinType): LLVMTypeRef {
|
||||
return when {
|
||||
// Nullable types must be represented as objects for boxing.
|
||||
type.isMarkedNullable -> this.kObjHeaderPtr
|
||||
@@ -23,7 +23,7 @@ internal fun ContextUtils.getLLVMType(type: KotlinType): LLVMTypeRef {
|
||||
}!!
|
||||
}
|
||||
|
||||
internal fun ContextUtils.getLLVMReturnType(type: KotlinType): LLVMTypeRef {
|
||||
internal fun RuntimeAware.getLLVMReturnType(type: KotlinType): LLVMTypeRef {
|
||||
return when {
|
||||
type.isUnit() -> LLVMVoidType()!!
|
||||
// TODO: stdlib have methods taking Nothing, such as kotlin.collections.EmptySet.contains().
|
||||
|
||||
+32
-33
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -41,6 +40,8 @@ internal fun emitLLVM(context: Context) {
|
||||
val llvmModule = LLVMModuleCreateWithName("out")!! // TODO: dispose
|
||||
context.llvmModule = llvmModule
|
||||
|
||||
context.llvmDeclarations = createLlvmDeclarations(context)
|
||||
|
||||
val phaser = PhaseManager(context)
|
||||
|
||||
phaser.phase(KonanPhase.RTTI) {
|
||||
@@ -83,11 +84,6 @@ 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
|
||||
}
|
||||
|
||||
if (declaration.descriptor.isIntrinsic) {
|
||||
// do not generate any code for intrinsic classes as they require special handling
|
||||
return
|
||||
@@ -254,7 +250,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val kNodeInitType = LLVMGetTypeByName(context.llvmModule, "struct.InitNode")!!
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun createInitBody(initName: String) {
|
||||
fun createInitBody(initName: String): LLVMValueRef {
|
||||
val initFunction = LLVMAddFunction(context.llvmModule, initName, kVoidFuncType)!! // create LLVM function
|
||||
codegen.prologue(initFunction, voidType)
|
||||
using(FunctionScope(initFunction)) {
|
||||
@@ -262,33 +258,33 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val irField = it as IrField
|
||||
val descriptor = irField.descriptor
|
||||
val initialization = evaluateExpression(irField.initializer!!.expression)
|
||||
val globalPtr = LLVMGetNamedGlobal(context.llvmModule, descriptor.symbolName)
|
||||
codegen.storeAnyGlobal(initialization, globalPtr!!)
|
||||
val globalPtr = context.llvmDeclarations.forStaticField(descriptor).storage
|
||||
codegen.storeAnyGlobal(initialization, globalPtr)
|
||||
}
|
||||
codegen.ret(null)
|
||||
}
|
||||
codegen.epilogue()
|
||||
|
||||
return initFunction
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
// Creates static struct InitNode $nodeName = {$initName, NULL};
|
||||
|
||||
fun createInitNode(initName: String, nodeName: String) {
|
||||
fun createInitNode(initFunction: LLVMValueRef, nodeName: String): LLVMValueRef {
|
||||
memScoped {
|
||||
val initFunction = LLVMGetNamedFunction(context.llvmModule, initName)!! // Get initialization function.
|
||||
val nextInitNode = LLVMConstNull(pointerType(kNodeInitType)) // Set InitNode.next = NULL.
|
||||
val argList = allocArrayOf(initFunction, nextInitNode)[0].ptr // Allocate array of args.
|
||||
val initNode = LLVMConstNamedStruct(kNodeInitType, argList, 2)!! // Create static object of class InitNode.
|
||||
context.llvm.staticData.placeGlobal(nodeName, constPointer(initNode)).llvmGlobal // Put the object in global var with name "nodeName".
|
||||
return context.llvm.staticData.placeGlobal(nodeName, constPointer(initNode)).llvmGlobal // Put the object in global var with name "nodeName".
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun createInitCtor(ctorName: String, nodeName: String) {
|
||||
fun createInitCtor(ctorName: String, initNodePtr: LLVMValueRef) {
|
||||
val ctorFunction = LLVMAddFunction(context.llvmModule, ctorName, kVoidFuncType)!! // Create constructor function.
|
||||
codegen.prologue(ctorFunction, voidType)
|
||||
val initNodePtr = LLVMGetNamedGlobal(context.llvmModule, nodeName)!! // Get LLVM function initializing globals of current file.
|
||||
codegen.call(context.llvm.appendToInitalizersTail, initNodePtr.singletonList()) // Add node to the tail of initializers list.
|
||||
codegen.ret(null)
|
||||
codegen.epilogue()
|
||||
@@ -313,9 +309,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val nodeName = "${fileName}_node_${context.llvm.globalInitIndex}"
|
||||
val ctorName = "${fileName}_ctor_${context.llvm.globalInitIndex++}"
|
||||
|
||||
createInitBody(initName)
|
||||
createInitNode(initName, nodeName)
|
||||
createInitCtor(ctorName, nodeName)
|
||||
val initFunction = createInitBody(initName)
|
||||
val initNode = createInitNode(initFunction, nodeName)
|
||||
createInitCtor(ctorName, initNode)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -388,15 +384,13 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
if (constructorDescriptor.isPrimary) {
|
||||
if (DescriptorUtils.isObject(classDescriptor)) {
|
||||
if (classDescriptor.isUnit()) {
|
||||
context.llvm.staticData.createUnitInstance(classDescriptor)
|
||||
} else {
|
||||
if (!classDescriptor.isUnit()) {
|
||||
val objectPtr = objectPtrByName(classDescriptor)
|
||||
|
||||
LLVMSetInitializer(objectPtr, codegen.kNullObjHeaderPtr)
|
||||
}
|
||||
}
|
||||
val irOfCurrentClass = context.ir.moduleIndexForCodegen.classes[classDescriptor.classId]
|
||||
val irOfCurrentClass = context.ir.moduleIndexForCodegen.classes[classDescriptor]
|
||||
irOfCurrentClass!!.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
@@ -612,13 +606,17 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val descriptor = expression.descriptor
|
||||
if (descriptor.containingDeclaration is PackageFragmentDescriptor) {
|
||||
val type = codegen.getLLVMType(descriptor.type)
|
||||
val globalProperty = LLVMAddGlobal(context.llvmModule, type, descriptor.symbolName)
|
||||
val globalProperty = context.llvmDeclarations.forStaticField(descriptor).storage
|
||||
if (expression.initializer!!.expression is IrConst<*>) {
|
||||
LLVMSetInitializer(globalProperty, evaluateExpression(expression.initializer!!.expression))
|
||||
} else {
|
||||
LLVMSetInitializer(globalProperty, LLVMConstNull(type))
|
||||
context.llvm.fileInitializers.add(expression)
|
||||
}
|
||||
|
||||
LLVMSetLinkage(globalProperty, LLVMLinkage.LLVMPrivateLinkage)
|
||||
// (Cannot do this before the global is initialized).
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1363,7 +1361,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
else {
|
||||
assert (value.receiver == null)
|
||||
val ptr = LLVMGetNamedGlobal(context.llvmModule, value.descriptor.symbolName)!!
|
||||
val ptr = context.llvmDeclarations.forStaticField(value.descriptor).storage
|
||||
return codegen.loadSlot(ptr, value.descriptor.isVar())
|
||||
}
|
||||
}
|
||||
@@ -1372,13 +1370,12 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
private fun objectPtrByName(descriptor: ClassDescriptor): LLVMValueRef {
|
||||
assert (!descriptor.isUnit())
|
||||
val objName = descriptor.fqNameSafe.asString()
|
||||
var objectPtr = LLVMGetNamedGlobal(context.llvmModule, objName)
|
||||
if (objectPtr == null) {
|
||||
return if (codegen.isExternal(descriptor)) {
|
||||
val llvmType = codegen.getLLVMType(descriptor.defaultType)
|
||||
objectPtr = LLVMAddGlobal(context.llvmModule, llvmType, objName)
|
||||
codegen.externalGlobal(descriptor.objectInstanceFieldSymbolName, llvmType)
|
||||
} else {
|
||||
context.llvmDeclarations.forSingleton(descriptor).instanceFieldRef
|
||||
}
|
||||
return objectPtr!!
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -1392,8 +1389,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
else {
|
||||
assert (value.receiver == null)
|
||||
val globalValue = LLVMGetNamedGlobal(context.llvmModule, value.descriptor.symbolName)
|
||||
codegen.storeAnyGlobal(valueToAssign, globalValue!!)
|
||||
val globalValue = context.llvmDeclarations.forStaticField(value.descriptor).storage
|
||||
codegen.storeAnyGlobal(valueToAssign, globalValue)
|
||||
}
|
||||
|
||||
assert (value.type.isUnit())
|
||||
@@ -1435,12 +1432,14 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
*/
|
||||
private fun fieldPtrOfClass(thisPtr: LLVMValueRef, value: PropertyDescriptor): LLVMValueRef {
|
||||
val typePtr = pointerType(codegen.classType(value.containingDeclaration as ClassDescriptor))
|
||||
val fieldInfo = context.llvmDeclarations.forField(value)
|
||||
|
||||
val typePtr = pointerType(fieldInfo.classBodyType)
|
||||
memScoped {
|
||||
val args = allocArrayOf(kImmOne)
|
||||
val objectPtr = LLVMBuildGEP(codegen.builder, thisPtr, args[0].ptr, 1, "")
|
||||
val typedObjPtr = codegen.bitcast(typePtr, objectPtr!!)
|
||||
val fieldPtr = LLVMBuildStructGEP(codegen.builder, typedObjPtr, codegen.indexInClass(value), "")
|
||||
val fieldPtr = LLVMBuildStructGEP(codegen.builder, typedObjPtr, fieldInfo.index, "")
|
||||
return fieldPtr!!
|
||||
}
|
||||
}
|
||||
@@ -1853,7 +1852,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun callDirect(descriptor: FunctionDescriptor, args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val realDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor)
|
||||
val realDescriptor = descriptor.resolveFakeOverride().original
|
||||
val llvmFunction = codegen.functionLlvmValue(realDescriptor)
|
||||
return call(descriptor, llvmFunction, args)
|
||||
}
|
||||
|
||||
+335
@@ -0,0 +1,335 @@
|
||||
package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
|
||||
internal fun createLlvmDeclarations(context: Context): LlvmDeclarations {
|
||||
val generator = DeclarationsGeneratorVisitor(context)
|
||||
context.ir.irModule.acceptChildrenVoid(generator)
|
||||
return with(generator) {
|
||||
LlvmDeclarations(
|
||||
functions, classes, fields, staticFields, theUnitInstanceRef
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class LlvmDeclarations(
|
||||
private val functions: Map<FunctionDescriptor, FunctionLlvmDeclarations>,
|
||||
private val classes: Map<ClassDescriptor, ClassLlvmDeclarations>,
|
||||
private val fields: Map<PropertyDescriptor, FieldLlvmDeclarations>,
|
||||
private val staticFields: Map<PropertyDescriptor, StaticFieldLlvmDeclarations>,
|
||||
private val theUnitInstanceRef: ConstPointer?
|
||||
) {
|
||||
fun forFunction(descriptor: FunctionDescriptor) = functions[descriptor] ?:
|
||||
error(descriptor.toString())
|
||||
|
||||
fun forClass(descriptor: ClassDescriptor) = classes[descriptor] ?:
|
||||
error(descriptor.toString())
|
||||
|
||||
fun forField(descriptor: PropertyDescriptor) = fields[descriptor] ?:
|
||||
error(descriptor.toString())
|
||||
|
||||
fun forStaticField(descriptor: PropertyDescriptor) = staticFields[descriptor] ?:
|
||||
error(descriptor.toString())
|
||||
|
||||
fun forSingleton(descriptor: ClassDescriptor) = forClass(descriptor).singletonDeclarations ?:
|
||||
error(descriptor.toString())
|
||||
|
||||
fun getUnitInstanceRef() = theUnitInstanceRef ?: error("")
|
||||
|
||||
}
|
||||
|
||||
internal class ClassLlvmDeclarations(
|
||||
val bodyType: LLVMTypeRef,
|
||||
val fields: List<PropertyDescriptor>, // TODO: it is not an LLVM declaration.
|
||||
val typeInfoGlobal: StaticData.Global,
|
||||
val typeInfo: ConstPointer,
|
||||
val singletonDeclarations: SingletonLlvmDeclarations?)
|
||||
|
||||
internal class SingletonLlvmDeclarations(val instanceFieldRef: LLVMValueRef)
|
||||
|
||||
internal class FunctionLlvmDeclarations(val llvmFunction: LLVMValueRef)
|
||||
|
||||
internal class FieldLlvmDeclarations(val index: Int, val classBodyType: LLVMTypeRef)
|
||||
|
||||
internal class StaticFieldLlvmDeclarations(val storage: LLVMValueRef)
|
||||
|
||||
// TODO: rework getFields and getDeclaredFields.
|
||||
|
||||
/**
|
||||
* All fields of the class instance.
|
||||
* The order respects the class hierarchy, i.e. a class [fields] contains superclass [fields] as a prefix.
|
||||
*/
|
||||
private fun getFields(context: Context, classDescriptor: ClassDescriptor): List<PropertyDescriptor> {
|
||||
val superClass = classDescriptor.getSuperClassNotAny() // TODO: what if Any has fields?
|
||||
val superFields = if (superClass != null) getFields(context, superClass) else emptyList()
|
||||
|
||||
return superFields + getDeclaredFields(context, classDescriptor)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fields declared in the class.
|
||||
*/
|
||||
private fun getDeclaredFields(context: Context, classDescriptor: ClassDescriptor): List<PropertyDescriptor> {
|
||||
// TODO: Here's what is going on here:
|
||||
// The existence of a backing field for a property is only described in the IR,
|
||||
// but not in the property descriptor.
|
||||
// That works, while we process the IR, but not for deserialized descriptors.
|
||||
//
|
||||
// So to have something in deserialized descriptors,
|
||||
// while we still see the IR, we mark the property with an annotation.
|
||||
//
|
||||
// We could apply the annotation during IR rewite, but we still are not
|
||||
// that far in the rewriting infrastructure. So we postpone
|
||||
// the annotation until the serializer.
|
||||
//
|
||||
// In this function we check the presence of the backing filed
|
||||
// two ways: first we check IR, then we check the annotation.
|
||||
|
||||
val irClass = context.ir.moduleIndexForCodegen.classes[classDescriptor]
|
||||
if (irClass != null) {
|
||||
val declarations = irClass.declarations
|
||||
|
||||
return declarations.mapNotNull {
|
||||
when (it) {
|
||||
is IrProperty -> it.backingField?.descriptor
|
||||
is IrField -> it.descriptor
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val properties = classDescriptor.unsubstitutedMemberScope.
|
||||
getContributedDescriptors().
|
||||
filterIsInstance<PropertyDescriptor>()
|
||||
|
||||
return properties.mapNotNull { it.backingField }
|
||||
}
|
||||
}
|
||||
|
||||
private fun ContextUtils.createClassBodyType(name: String, fields: List<PropertyDescriptor>): LLVMTypeRef {
|
||||
val fieldTypes = fields.map { getLLVMType(it.type) }.toTypedArray()
|
||||
|
||||
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!!
|
||||
|
||||
memScoped {
|
||||
val fieldTypesNativeArrayPtr = allocArrayOf(*fieldTypes)[0].ptr
|
||||
LLVMStructSetBody(classType, fieldTypesNativeArrayPtr, fieldTypes.size, 0)
|
||||
}
|
||||
return classType
|
||||
}
|
||||
|
||||
private class DeclarationsGeneratorVisitor(override val context: Context) :
|
||||
IrElementVisitorVoid, ContextUtils {
|
||||
|
||||
val functions = mutableMapOf<FunctionDescriptor, FunctionLlvmDeclarations>()
|
||||
val classes = mutableMapOf<ClassDescriptor, ClassLlvmDeclarations>()
|
||||
val fields = mutableMapOf<PropertyDescriptor, FieldLlvmDeclarations>()
|
||||
val staticFields = mutableMapOf<PropertyDescriptor, StaticFieldLlvmDeclarations>()
|
||||
var theUnitInstanceRef: ConstPointer? = null
|
||||
|
||||
private class Namer(val prefix: String) {
|
||||
private val names = mutableMapOf<DeclarationDescriptor, Name>()
|
||||
private val counts = mutableMapOf<FqName, Int>()
|
||||
|
||||
fun getName(parent: FqName, descriptor: DeclarationDescriptor): Name {
|
||||
return names.getOrPut(descriptor) {
|
||||
val count = counts.getOrDefault(parent, 0) + 1
|
||||
counts[parent] = count
|
||||
Name.identifier(prefix + count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val objectNamer = Namer("object-")
|
||||
|
||||
private fun getLocalName(parent: FqName, descriptor: DeclarationDescriptor): Name {
|
||||
if (DescriptorUtils.isAnonymousObject(descriptor)) {
|
||||
return objectNamer.getName(parent, descriptor)
|
||||
}
|
||||
|
||||
return descriptor.name
|
||||
}
|
||||
|
||||
private fun getFqName(descriptor: DeclarationDescriptor): FqName {
|
||||
if (descriptor is PackageFragmentDescriptor) {
|
||||
return descriptor.fqName
|
||||
}
|
||||
|
||||
|
||||
val containingDeclaration = descriptor.containingDeclaration
|
||||
val parent = if (containingDeclaration != null) {
|
||||
getFqName(containingDeclaration)
|
||||
} else {
|
||||
FqName.ROOT
|
||||
}
|
||||
|
||||
val localName = getLocalName(parent, descriptor)
|
||||
return parent.child(localName)
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces the name to be used for non-exported LLVM declarations corresponding to [descriptor].
|
||||
*
|
||||
* Note: since these declarations are going to be private, the name is only required not to clash with any
|
||||
* exported declarations.
|
||||
*/
|
||||
private fun qualifyInternalName(descriptor: DeclarationDescriptor): String {
|
||||
return getFqName(descriptor).asString() + "#internal"
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
|
||||
if (declaration.descriptor.isIntrinsic) {
|
||||
// do not generate any declarations for intrinsic classes as they require special handling
|
||||
} else {
|
||||
this.classes[declaration.descriptor] = createClassDeclarations(declaration)
|
||||
}
|
||||
|
||||
super.visitClass(declaration)
|
||||
}
|
||||
|
||||
private fun createClassDeclarations(declaration: IrClass): ClassLlvmDeclarations {
|
||||
val descriptor = declaration.descriptor
|
||||
|
||||
val internalName = qualifyInternalName(descriptor)
|
||||
|
||||
val fields = getFields(context, descriptor)
|
||||
val bodyType = createClassBodyType("kclassbody:$internalName", fields)
|
||||
|
||||
val typeInfoPtr: ConstPointer
|
||||
val typeInfoGlobal: StaticData.Global
|
||||
|
||||
val typeInfoSymbolName = if (descriptor.isExported()) {
|
||||
descriptor.typeInfoSymbolName
|
||||
} else {
|
||||
"ktype:$internalName"
|
||||
}
|
||||
|
||||
if (!descriptor.isAbstract()) {
|
||||
// Create the special global consisting of TypeInfo and vtable.
|
||||
|
||||
val typeInfoGlobalName = "ktypeglobal:$internalName"
|
||||
|
||||
val typeInfoWithVtableType = structType(
|
||||
runtime.typeInfoType,
|
||||
LLVMArrayType(int8TypePtr, descriptor.vtableEntries.size)!!
|
||||
)
|
||||
|
||||
typeInfoGlobal = staticData.createGlobal(typeInfoWithVtableType, typeInfoGlobalName, isExported = false)
|
||||
|
||||
val llvmTypeInfoPtr = LLVMAddAlias(context.llvmModule,
|
||||
kTypeInfoPtr,
|
||||
typeInfoGlobal.pointer.getElementPtr(0).llvm,
|
||||
typeInfoSymbolName)!!
|
||||
|
||||
if (!descriptor.isExported()) {
|
||||
LLVMSetLinkage(llvmTypeInfoPtr, LLVMLinkage.LLVMPrivateLinkage)
|
||||
}
|
||||
|
||||
typeInfoPtr = constPointer(llvmTypeInfoPtr)
|
||||
|
||||
} else {
|
||||
typeInfoGlobal = staticData.createGlobal(runtime.typeInfoType,
|
||||
typeInfoSymbolName,
|
||||
isExported = descriptor.isExported())
|
||||
|
||||
typeInfoPtr = typeInfoGlobal.pointer
|
||||
}
|
||||
|
||||
val singletonDeclarations = if (descriptor.kind.isSingleton) {
|
||||
createSingletonDeclarations(descriptor, typeInfoPtr, bodyType)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
return ClassLlvmDeclarations(bodyType, fields, typeInfoGlobal, typeInfoPtr, singletonDeclarations)
|
||||
}
|
||||
|
||||
private fun createSingletonDeclarations(
|
||||
descriptor: ClassDescriptor,
|
||||
typeInfoPtr: ConstPointer,
|
||||
bodyType: LLVMTypeRef
|
||||
): SingletonLlvmDeclarations? {
|
||||
|
||||
if (descriptor.isUnit()) {
|
||||
this.theUnitInstanceRef = staticData.createUnitInstance(descriptor, bodyType, typeInfoPtr)
|
||||
return null
|
||||
}
|
||||
|
||||
val symbolName = if (descriptor.isExported()) {
|
||||
descriptor.objectInstanceFieldSymbolName
|
||||
} else {
|
||||
"kobjref:" + qualifyInternalName(descriptor)
|
||||
}
|
||||
val instanceFieldRef = LLVMAddGlobal(
|
||||
context.llvmModule,
|
||||
getLLVMType(descriptor.defaultType),
|
||||
symbolName
|
||||
)!!
|
||||
|
||||
return SingletonLlvmDeclarations(instanceFieldRef)
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField) {
|
||||
super.visitField(declaration)
|
||||
|
||||
val descriptor = declaration.descriptor
|
||||
|
||||
val dispatchReceiverParameter = descriptor.dispatchReceiverParameter
|
||||
if (dispatchReceiverParameter != null) {
|
||||
val containingClass = dispatchReceiverParameter.containingDeclaration
|
||||
val classDeclarations = this.classes[containingClass] ?: error(containingClass.toString())
|
||||
|
||||
val allFields = classDeclarations.fields
|
||||
|
||||
this.fields[descriptor] = FieldLlvmDeclarations(
|
||||
allFields.indexOf(descriptor),
|
||||
classDeclarations.bodyType
|
||||
)
|
||||
} else {
|
||||
|
||||
// Fields are module-private, so we use internal name:
|
||||
val name = "kvar:" + qualifyInternalName(descriptor)
|
||||
|
||||
val storage = LLVMAddGlobal(context.llvmModule, getLLVMType(descriptor.type), name)!!
|
||||
|
||||
this.staticFields[descriptor] = StaticFieldLlvmDeclarations(storage)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
super.visitFunction(declaration)
|
||||
|
||||
val descriptor = declaration.descriptor
|
||||
val llvmFunctionType = getLlvmFunctionType(descriptor)
|
||||
|
||||
val llvmFunction = if (descriptor.isExternal) {
|
||||
context.llvm.externalFunction(descriptor.symbolName, llvmFunctionType)
|
||||
} else {
|
||||
val symbolName = if (descriptor.isExported()) {
|
||||
descriptor.symbolName
|
||||
} else {
|
||||
"kfun:" + qualifyInternalName(descriptor)
|
||||
}
|
||||
LLVMAddFunction(context.llvmModule, symbolName, llvmFunctionType)!!
|
||||
}
|
||||
|
||||
this.functions[descriptor] = FunctionLlvmDeclarations(llvmFunction)
|
||||
}
|
||||
}
|
||||
+20
-25
@@ -111,21 +111,21 @@ internal val ContextUtils.kTheAnyTypeInfo: LLVMValueRef
|
||||
get() = KonanPlatform.builtIns.any.llvmTypeInfoPtr
|
||||
internal val ContextUtils.kTheArrayTypeInfo: LLVMValueRef
|
||||
get() = KonanPlatform.builtIns.array.llvmTypeInfoPtr
|
||||
internal val ContextUtils.kTypeInfo: LLVMTypeRef
|
||||
get() = LLVMGetTypeByName(context.llvmModule, "struct.TypeInfo")!!
|
||||
internal val ContextUtils.kObjHeader: LLVMTypeRef
|
||||
get() = LLVMGetTypeByName(context.llvmModule, "struct.ObjHeader")!!
|
||||
internal val ContextUtils.kContainerHeader: LLVMTypeRef
|
||||
get() = LLVMGetTypeByName(context.llvmModule, "struct.ContainerHeader")!!
|
||||
internal val ContextUtils.kObjHeaderPtr: LLVMTypeRef
|
||||
internal val RuntimeAware.kTypeInfo: LLVMTypeRef
|
||||
get() = runtime.typeInfoType
|
||||
internal val RuntimeAware.kObjHeader: LLVMTypeRef
|
||||
get() = runtime.objHeaderType
|
||||
internal val RuntimeAware.kContainerHeader: LLVMTypeRef
|
||||
get() = runtime.containerHeaderType
|
||||
internal val RuntimeAware.kObjHeaderPtr: LLVMTypeRef
|
||||
get() = pointerType(kObjHeader)
|
||||
internal val ContextUtils.kObjHeaderPtrPtr: LLVMTypeRef
|
||||
internal val RuntimeAware.kObjHeaderPtrPtr: LLVMTypeRef
|
||||
get() = pointerType(kObjHeaderPtr)
|
||||
internal val ContextUtils.kArrayHeader: LLVMTypeRef
|
||||
get() = LLVMGetTypeByName(context.llvmModule, "struct.ArrayHeader")!!
|
||||
internal val ContextUtils.kArrayHeaderPtr: LLVMTypeRef
|
||||
internal val RuntimeAware.kArrayHeader: LLVMTypeRef
|
||||
get() = runtime.arrayHeaderType
|
||||
internal val RuntimeAware.kArrayHeaderPtr: LLVMTypeRef
|
||||
get() = pointerType(kArrayHeader)
|
||||
internal val ContextUtils.kTypeInfoPtr: LLVMTypeRef
|
||||
internal val RuntimeAware.kTypeInfoPtr: LLVMTypeRef
|
||||
get() = pointerType(kTypeInfo)
|
||||
internal val kInt1 = LLVMInt1Type()!!
|
||||
internal val kBoolean = kInt1
|
||||
@@ -151,18 +151,6 @@ internal fun structType(types: List<LLVMTypeRef>): LLVMTypeRef = memScoped {
|
||||
LLVMStructType(allocArrayOf(types)[0].ptr, types.size, 0)!!
|
||||
}
|
||||
|
||||
internal fun ContextUtils.getLlvmFunctionType(function: FunctionDescriptor): LLVMTypeRef {
|
||||
val original = function.original
|
||||
val returnType = if (original is ConstructorDescriptor) voidType else getLLVMReturnType(original.returnType!!)
|
||||
val paramTypes = ArrayList(original.allValueParameters.map { getLLVMType(it.type) })
|
||||
if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr)
|
||||
|
||||
memScoped {
|
||||
val paramTypesPtr = allocArrayOf(paramTypes)[0].ptr
|
||||
return LLVMFunctionType(returnType, paramTypesPtr, paramTypes.size, 0)!!
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ContextUtils.numParameters(functionType: LLVMTypeRef) : Int {
|
||||
// Note that type is usually function pointer, so we have to dereference it.
|
||||
return LLVMCountParamTypes(LLVMGetElementType(functionType))!!
|
||||
@@ -178,7 +166,7 @@ internal fun ContextUtils.isObjectRef(value: LLVMValueRef): Boolean {
|
||||
return isObjectType(value.type)
|
||||
}
|
||||
|
||||
internal fun ContextUtils.isObjectType(type: LLVMTypeRef): Boolean {
|
||||
internal fun RuntimeAware.isObjectType(type: LLVMTypeRef): Boolean {
|
||||
return type == kObjHeaderPtr || type == kArrayHeaderPtr
|
||||
}
|
||||
|
||||
@@ -200,6 +188,7 @@ internal fun ContextUtils.externalGlobal(name: String, type: LLVMTypeRef): LLVMV
|
||||
val found = LLVMGetNamedGlobal(context.llvmModule, name)
|
||||
if (found != null) {
|
||||
assert (getGlobalType(found) == type)
|
||||
assert (LLVMGetInitializer(found) == null)
|
||||
return found
|
||||
} else {
|
||||
return LLVMAddGlobal(context.llvmModule, type, name)!!
|
||||
@@ -227,3 +216,9 @@ internal operator fun LLVMAttributeSet.contains(attribute: LLVMAttribute): Boole
|
||||
return (this and attribute.value) != 0
|
||||
}
|
||||
|
||||
fun getStructElements(type: LLVMTypeRef): List<LLVMTypeRef> {
|
||||
val count = LLVMCountStructElementTypes(type)
|
||||
return (0 until count).map {
|
||||
LLVMStructGetTypeAtIndex(type, it)!!
|
||||
}
|
||||
}
|
||||
-101
@@ -1,101 +0,0 @@
|
||||
package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.resolve.findOriginalTopMostOverriddenDescriptors
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||
|
||||
|
||||
private val symbolNameAnnotation = FqName("konan.SymbolName")
|
||||
|
||||
private val exportForCppRuntimeAnnotation = FqName("konan.internal.ExportForCppRuntime")
|
||||
|
||||
fun typeToHashString(type: KotlinType): String {
|
||||
if (TypeUtils.isTypeParameter(type)) return "GENERIC"
|
||||
|
||||
var hashString = TypeUtils.getClassDescriptor(type)!!.fqNameSafe.asString()
|
||||
if (!type.arguments.isEmpty()) {
|
||||
hashString += "<${type.arguments.map {
|
||||
typeToHashString(it.type)
|
||||
}.joinToString(",")}>"
|
||||
}
|
||||
|
||||
if (type.isMarkedNullable) hashString += "?"
|
||||
return hashString
|
||||
}
|
||||
|
||||
private val FunctionDescriptor.signature: String
|
||||
get() {
|
||||
val extensionReceiverPart = this.extensionReceiverParameter?.let { "${it.type}." } ?: ""
|
||||
val actualDescriptor = this.findOriginalTopMostOverriddenDescriptors().firstOrNull() ?: this
|
||||
|
||||
val argsPart = actualDescriptor.valueParameters.map {
|
||||
typeToHashString(it.type)
|
||||
}.joinToString(";")
|
||||
|
||||
// TODO: add return type
|
||||
// (it is not simple because return type can be changed when overriding)
|
||||
return "$extensionReceiverPart($argsPart)"
|
||||
}
|
||||
|
||||
// TODO: rename to indicate that it has signature included
|
||||
internal val FunctionDescriptor.functionName: String
|
||||
get() = with(this.original) { // basic support for generics
|
||||
"$name$signature"
|
||||
}
|
||||
|
||||
internal val FunctionDescriptor.symbolName: String
|
||||
get() {
|
||||
this.annotations.findAnnotation(symbolNameAnnotation)?.let {
|
||||
if (this.isExternal) {
|
||||
return getStringValue(it)!!
|
||||
} else {
|
||||
// ignore; TODO: report compile error
|
||||
}
|
||||
}
|
||||
|
||||
this.annotations.findAnnotation(exportForCppRuntimeAnnotation)?.let {
|
||||
val name = getStringValue(it) ?: this.name.asString()
|
||||
return name // no wrapping currently required
|
||||
}
|
||||
|
||||
val containingDeclarationPart = containingDeclaration.fqNameSafe.let {
|
||||
if (it.isRoot) "" else "$it."
|
||||
}
|
||||
return "kfun:$containingDeclarationPart$functionName"
|
||||
}
|
||||
|
||||
private fun getStringValue(annotation: AnnotationDescriptor): String? {
|
||||
annotation.allValueArguments.values.ifNotEmpty {
|
||||
val stringValue = this.single() as StringValue
|
||||
return stringValue.value
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
internal val ClassDescriptor.symbolName: String
|
||||
get() = when (this.kind) {
|
||||
CLASS -> "kclass:"
|
||||
INTERFACE -> "kinf:"
|
||||
OBJECT -> "kclass:"
|
||||
ENUM_CLASS -> "kclass:"
|
||||
ENUM_ENTRY -> "kclass:"
|
||||
else -> TODO("fixme: " + this.kind)
|
||||
} + fqNameSafe
|
||||
|
||||
internal val ClassDescriptor.typeInfoSymbolName: String
|
||||
get() = "ktype:" + this.fqNameSafe.toString()
|
||||
|
||||
internal val PropertyDescriptor.symbolName:String
|
||||
get() = "kvar:${this.containingDeclaration.name.asString()}.${this.name.asString()}"
|
||||
+28
-42
@@ -1,7 +1,5 @@
|
||||
package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
@@ -52,18 +50,6 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
Int32(fieldsCount)
|
||||
)
|
||||
|
||||
// TODO: probably it should be moved out of this class and shared.
|
||||
private fun createStructFor(className: FqName, fields: List<PropertyDescriptor>): LLVMTypeRef? {
|
||||
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), "kclass:" + className)
|
||||
val fieldTypes = fields.map { getLLVMType(it.returnType!!) }.toTypedArray()
|
||||
|
||||
memScoped {
|
||||
val fieldTypesNativeArrayPtr = allocArrayOf(*fieldTypes)[0].ptr
|
||||
LLVMStructSetBody(classType, fieldTypesNativeArrayPtr, fieldTypes.size, 0)
|
||||
}
|
||||
return classType
|
||||
}
|
||||
|
||||
private fun exportTypeInfoIfRequired(classDesc: ClassDescriptor, typeInfoGlobal: LLVMValueRef?) {
|
||||
val annot = classDesc.annotations.findAnnotation(FqName("konan.ExportTypeInfo"))
|
||||
if (annot != null) {
|
||||
@@ -97,11 +83,13 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
val className = classDesc.fqNameSafe
|
||||
|
||||
val classType = createStructFor(className, classDesc.fields)
|
||||
val llvmDeclarations = context.llvmDeclarations.forClass(classDesc)
|
||||
|
||||
val bodyType = llvmDeclarations.bodyType
|
||||
|
||||
val name = className.globalHash
|
||||
|
||||
val size = getInstanceSize(classType, className)
|
||||
val size = getInstanceSize(bodyType, className)
|
||||
|
||||
val superTypeOrAny = classDesc.getSuperClassOrAny()
|
||||
val superType = if (KotlinBuiltIns.isAny(classDesc)) NullPointer(runtime.typeInfoType)
|
||||
@@ -111,51 +99,39 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
val interfacesPtr = staticData.placeGlobalConstArray("kintf:$className",
|
||||
pointerType(runtime.typeInfoType), interfaces)
|
||||
|
||||
val refFieldIndices = classDesc.fields.mapIndexedNotNull { index, field ->
|
||||
val type = field.returnType!!
|
||||
if (isObjectType(getLLVMType(type))) {
|
||||
index
|
||||
// TODO: reuse offsets obtained for 'fields' below
|
||||
val objOffsets = getStructElements(bodyType).mapIndexedNotNull { index, type ->
|
||||
if (isObjectType(type)) {
|
||||
LLVMOffsetOfElement(llvmTargetData, bodyType, index)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
// TODO: reuse offsets obtained for 'fields' below
|
||||
val objOffsets = refFieldIndices.map { LLVMOffsetOfElement(llvmTargetData, classType, it) }
|
||||
|
||||
val objOffsetsPtr = staticData.placeGlobalConstArray("krefs:$className", int32Type,
|
||||
objOffsets.map { Int32(it.toInt()) })
|
||||
|
||||
val fields = classDesc.fields.mapIndexed { index, field ->
|
||||
val fields = llvmDeclarations.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.localHash // FIXME: add signature
|
||||
val fieldOffset = LLVMOffsetOfElement(llvmTargetData, classType, index)
|
||||
val fieldOffset = LLVMOffsetOfElement(llvmTargetData, bodyType, index)
|
||||
FieldTableRecord(nameSignature, fieldOffset.toInt())
|
||||
}.sortedBy { it.nameSignature.value }
|
||||
|
||||
val fieldsPtr = staticData.placeGlobalConstArray("kfields:$className",
|
||||
runtime.fieldTableRecordType, fields)
|
||||
|
||||
val vtableEntries: List<ConstValue>
|
||||
val methods: List<ConstValue>
|
||||
|
||||
if (!classDesc.isAbstract()) {
|
||||
// TODO: compile-time resolution limits binary compatibility
|
||||
vtableEntries = classDesc.vtableEntries.map { it.implementation.entryPointAddress }
|
||||
|
||||
methods = classDesc.methodTableEntries.map {
|
||||
val methods = if (!classDesc.isAbstract()) {
|
||||
classDesc.methodTableEntries.map {
|
||||
val nameSignature = it.functionName.localHash
|
||||
// TODO: compile-time resolution limits binary compatibility
|
||||
val methodEntryPoint = it.implementation.entryPointAddress
|
||||
val methodEntryPoint = it.resolveFakeOverride().original.entryPointAddress
|
||||
MethodTableRecord(nameSignature, methodEntryPoint)
|
||||
}.sortedBy { it.nameSignature.value }
|
||||
} else {
|
||||
vtableEntries = emptyList()
|
||||
methods = emptyList()
|
||||
emptyList()
|
||||
}
|
||||
|
||||
assert (vtableEntries.size == classDesc.vtableSize)
|
||||
|
||||
val vtable = ConstArray(int8TypePtr, vtableEntries)
|
||||
|
||||
val methodsPtr = staticData.placeGlobalConstArray("kmethods:$className",
|
||||
runtime.methodTableRecordType, methods)
|
||||
|
||||
@@ -166,9 +142,19 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
methodsPtr, methods.size,
|
||||
fieldsPtr, if (classDesc.isInterface) -1 else fields.size)
|
||||
|
||||
val typeInfoGlobal = classDesc.typeInfoWithVtable.llvm // TODO: it is a hack
|
||||
LLVMSetInitializer(typeInfoGlobal, Struct(typeInfo, vtable).llvm)
|
||||
LLVMSetGlobalConstant(typeInfoGlobal, 1)
|
||||
val typeInfoGlobal = llvmDeclarations.typeInfoGlobal
|
||||
|
||||
val typeInfoGlobalValue = if (classDesc.isAbstract()) {
|
||||
typeInfo
|
||||
} else {
|
||||
// TODO: compile-time resolution limits binary compatibility
|
||||
val vtableEntries = classDesc.vtableEntries.map { it.resolveFakeOverride().original.entryPointAddress }
|
||||
val vtable = ConstArray(int8TypePtr, vtableEntries)
|
||||
Struct(typeInfo, vtable)
|
||||
}
|
||||
|
||||
typeInfoGlobal.setInitializer(typeInfoGlobalValue)
|
||||
typeInfoGlobal.setConstant(true)
|
||||
|
||||
exportTypeInfoIfRequired(classDesc, classDesc.llvmTypeInfoPtr)
|
||||
}
|
||||
|
||||
+4
@@ -3,6 +3,10 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
||||
import kotlinx.cinterop.*
|
||||
import llvm.*
|
||||
|
||||
interface RuntimeAware {
|
||||
val runtime: Runtime
|
||||
}
|
||||
|
||||
class Runtime(private val bitcodeFile: String) {
|
||||
val llvmModule: LLVMModuleRef
|
||||
|
||||
|
||||
+19
-19
@@ -15,34 +15,34 @@ internal class StaticData(override val context: Context): ContextUtils {
|
||||
class Global private constructor(val staticData: StaticData, val llvmGlobal: LLVMValueRef) {
|
||||
companion object {
|
||||
|
||||
private fun createLlvmGlobal(module: LLVMModuleRef, type: LLVMTypeRef, name: String): LLVMValueRef {
|
||||
val isUnnamed = (name == "") // LLVM will select the unique index and represent the global as `@idx`.
|
||||
private fun createLlvmGlobal(module: LLVMModuleRef,
|
||||
type: LLVMTypeRef,
|
||||
name: String,
|
||||
isExported: Boolean
|
||||
): LLVMValueRef {
|
||||
|
||||
if (!isUnnamed) {
|
||||
LLVMGetNamedGlobal(module, name)?.let { existingGlobal ->
|
||||
if (getGlobalType(existingGlobal) != type || LLVMGetInitializer(existingGlobal) != null) {
|
||||
throw IllegalArgumentException("Global '$name' already exists")
|
||||
} else {
|
||||
return existingGlobal
|
||||
}
|
||||
}
|
||||
if (isExported && LLVMGetNamedGlobal(module, name) != null) {
|
||||
throw IllegalArgumentException("Global '$name' already exists")
|
||||
}
|
||||
|
||||
val llvmGlobal = LLVMAddGlobal(module, type, name)!!
|
||||
|
||||
if (isUnnamed) {
|
||||
// Currently using unnamed globals may result in link errors due to symbol redefinition;
|
||||
// apply the workaround:
|
||||
if (!isExported) {
|
||||
LLVMSetLinkage(llvmGlobal, LLVMLinkage.LLVMPrivateLinkage)
|
||||
}
|
||||
|
||||
return llvmGlobal
|
||||
}
|
||||
|
||||
fun create(staticData: StaticData, type: LLVMTypeRef, name: String): Global {
|
||||
fun create(staticData: StaticData, type: LLVMTypeRef, name: String, isExported: Boolean): Global {
|
||||
val module = staticData.context.llvmModule
|
||||
|
||||
val llvmGlobal = createLlvmGlobal(module!!, type, name)
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -110,15 +110,15 @@ internal class StaticData(override val context: Context): ContextUtils {
|
||||
*
|
||||
* It is external until explicitly initialized with [Global.setInitializer].
|
||||
*/
|
||||
fun createGlobal(type: LLVMTypeRef, name: String): Global {
|
||||
return Global.create(this, type, name)
|
||||
fun createGlobal(type: LLVMTypeRef, name: String, isExported: Boolean = false): Global {
|
||||
return Global.create(this, type, name, isExported)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates [Global] with given name and value.
|
||||
*/
|
||||
fun placeGlobal(name: String, initializer: ConstValue): Global {
|
||||
val global = createGlobal(initializer.llvmType, name)
|
||||
fun placeGlobal(name: String, initializer: ConstValue, isExported: Boolean = false): Global {
|
||||
val global = createGlobal(initializer.llvmType, name, isExported)
|
||||
global.setInitializer(initializer)
|
||||
return global
|
||||
}
|
||||
|
||||
+14
-7
@@ -117,16 +117,23 @@ internal fun StaticData.createArrayList(elementType: TypeProjection, array: Cons
|
||||
return createKotlinObject(type, body)
|
||||
}
|
||||
|
||||
private val theUnitInstanceName = "kobj:kotlin.Unit"
|
||||
|
||||
internal fun StaticData.createUnitInstance(descriptor: ClassDescriptor): ConstPointer {
|
||||
internal fun StaticData.createUnitInstance(descriptor: ClassDescriptor,
|
||||
bodyType: LLVMTypeRef,
|
||||
typeInfo: ConstPointer
|
||||
): ConstPointer {
|
||||
assert (descriptor.isUnit())
|
||||
assert (descriptor.fields.isEmpty())
|
||||
val typeInfo = descriptor.defaultType.typeInfoPtr!!
|
||||
assert (getStructElements(bodyType).isEmpty())
|
||||
val objHeader = objHeader(typeInfo)
|
||||
val global = this.placeGlobal(theUnitInstanceName, objHeader)
|
||||
val global = this.placeGlobal(theUnitInstanceName, objHeader, isExported = true)
|
||||
return global.pointer
|
||||
}
|
||||
|
||||
internal val ContextUtils.theUnitInstanceRef: ConstPointer
|
||||
get() = constPointer(externalGlobal(theUnitInstanceName, context.llvm.runtime.objHeaderType))
|
||||
get() {
|
||||
val unitDescriptor = context.builtIns.unit
|
||||
return if (isExternal(unitDescriptor)) {
|
||||
constPointer(externalGlobal(theUnitInstanceName, context.llvm.runtime.objHeaderType))
|
||||
} else {
|
||||
context.llvmDeclarations.getUnitInstanceRef()
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package konan.internal
|
||||
|
||||
@ExportForCppRuntime
|
||||
internal fun ThrowNullPointerException(): Nothing {
|
||||
fun ThrowNullPointerException(): Nothing {
|
||||
throw NullPointerException()
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ internal fun ThrowArrayIndexOutOfBoundsException(): Nothing {
|
||||
}
|
||||
|
||||
@ExportForCppRuntime
|
||||
internal fun ThrowClassCastException(): Nothing {
|
||||
fun ThrowClassCastException(): Nothing {
|
||||
throw ClassCastException()
|
||||
}
|
||||
|
||||
@@ -20,14 +20,14 @@ internal fun ThrowArithmeticException() : Nothing {
|
||||
throw ArithmeticException()
|
||||
}
|
||||
|
||||
internal fun ThrowNoWhenBranchMatchedException(): Nothing {
|
||||
fun ThrowNoWhenBranchMatchedException(): Nothing {
|
||||
throw NoWhenBranchMatchedException()
|
||||
}
|
||||
|
||||
@ExportForCppRuntime
|
||||
internal fun TheEmptyString() = ""
|
||||
|
||||
internal fun <T: Enum<T>> valueOfForEnum(name: String, arr: Array<T>) : T
|
||||
fun <T: Enum<T>> valueOfForEnum(name: String, arr: Array<T>) : T
|
||||
{
|
||||
for (x in arr)
|
||||
if (x.name == name)
|
||||
@@ -35,7 +35,7 @@ internal fun <T: Enum<T>> valueOfForEnum(name: String, arr: Array<T>) : T
|
||||
throw Exception("Invalid enum name: $name")
|
||||
}
|
||||
|
||||
internal fun <T: Enum<T>> valuesForEnum(values: Array<T>): Array<T>
|
||||
fun <T: Enum<T>> valuesForEnum(values: Array<T>): Array<T>
|
||||
{
|
||||
return values.clone() as Array<T>
|
||||
}
|
||||
Reference in New Issue
Block a user