Renamed “descriptor” identifiers

This commit is contained in:
Igor Chevdar
2019-01-29 20:36:45 +03:00
committed by alexander-gorshenev
parent 9565420c7a
commit 27a31167e6
16 changed files with 469 additions and 511 deletions
@@ -123,12 +123,12 @@ internal class SpecialDeclarationsFactory(val context: Context) {
return ordinals.getOrPut(enumClassDescriptor) { assignOrdinalsToEnumEntries(enumClassDescriptor) }[entryDescriptor]!! return ordinals.getOrPut(enumClassDescriptor) { assignOrdinalsToEnumEntries(enumClassDescriptor) }[entryDescriptor]!!
} }
fun getBridge(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): IrSimpleFunction { fun getBridge(overriddenFunction: OverriddenFunctionInfo): IrSimpleFunction {
val irFunction = overriddenFunctionDescriptor.descriptor val irFunction = overriddenFunction.function
assert(overriddenFunctionDescriptor.needBridge) { assert(overriddenFunction.needBridge) {
"Function ${irFunction.descriptor} is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor.descriptor}" "Function ${irFunction.descriptor} is not needed in a bridge to call overridden function ${overriddenFunction.overriddenFunction.descriptor}"
} }
val bridgeDirections = overriddenFunctionDescriptor.bridgeDirections val bridgeDirections = overriddenFunction.bridgeDirections
return bridgesDescriptors.getOrPut(irFunction to bridgeDirections) { return bridgesDescriptors.getOrPut(irFunction to bridgeDirections) {
createBridge(irFunction, bridgeDirections) createBridge(irFunction, bridgeDirections)
} }
@@ -16,98 +16,96 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.simpleFunctions import org.jetbrains.kotlin.ir.util.simpleFunctions
internal class OverriddenFunctionDescriptor( internal class OverriddenFunctionInfo(
val descriptor: IrSimpleFunction, val function: IrSimpleFunction,
overriddenDescriptor: IrSimpleFunction val overriddenFunction: IrSimpleFunction
) { ) {
val overriddenDescriptor = overriddenDescriptor.original
val needBridge: Boolean val needBridge: Boolean
get() = descriptor.target.needBridgeTo(overriddenDescriptor) get() = function.target.needBridgeTo(overriddenFunction)
val bridgeDirections: BridgeDirections val bridgeDirections: BridgeDirections
get() = descriptor.target.bridgeDirectionsTo(overriddenDescriptor) get() = function.target.bridgeDirectionsTo(overriddenFunction)
val canBeCalledVirtually: Boolean val canBeCalledVirtually: Boolean
get() { get() {
if (overriddenDescriptor.isObjCClassMethod()) { if (overriddenFunction.isObjCClassMethod()) {
return descriptor.canObjCClassMethodBeCalledVirtually(this.overriddenDescriptor) return function.canObjCClassMethodBeCalledVirtually(overriddenFunction)
} }
return overriddenDescriptor.isOverridable return overriddenFunction.isOverridable
} }
val inheritsBridge: Boolean val inheritsBridge: Boolean
get() = !descriptor.isReal get() = !function.isReal
&& descriptor.target.overrides(overriddenDescriptor) && function.target.overrides(overriddenFunction)
&& descriptor.bridgeDirectionsTo(overriddenDescriptor).allNotNeeded() && function.bridgeDirectionsTo(overriddenFunction).allNotNeeded()
fun getImplementation(context: Context): IrSimpleFunction? { fun getImplementation(context: Context): IrSimpleFunction? {
val target = descriptor.target val target = function.target
val implementation = if (!needBridge) val implementation = if (!needBridge)
target target
else { else {
val bridgeOwner = if (inheritsBridge) { val bridgeOwner = if (inheritsBridge) {
target // Bridge is inherited from superclass. target // Bridge is inherited from superclass.
} else { } else {
descriptor function
} }
context.specialDeclarationsFactory.getBridge(OverriddenFunctionDescriptor(bridgeOwner, overriddenDescriptor)) context.specialDeclarationsFactory.getBridge(OverriddenFunctionInfo(bridgeOwner, overriddenFunction))
} }
return if (implementation.modality == Modality.ABSTRACT) null else implementation return if (implementation.modality == Modality.ABSTRACT) null else implementation
} }
override fun toString(): String { override fun toString(): String {
return "(descriptor=$descriptor, overriddenDescriptor=$overriddenDescriptor)" return "(descriptor=$function, overriddenDescriptor=$overriddenFunction)"
} }
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other !is OverriddenFunctionDescriptor) return false if (other !is OverriddenFunctionInfo) return false
if (descriptor != other.descriptor) return false if (function != other.function) return false
if (overriddenDescriptor != other.overriddenDescriptor) return false if (overriddenFunction != other.overriddenFunction) return false
return true return true
} }
override fun hashCode(): Int { override fun hashCode(): Int {
var result = descriptor.hashCode() var result = function.hashCode()
result = 31 * result + overriddenDescriptor.hashCode() result = 31 * result + overriddenFunction.hashCode()
return result return result
} }
} }
internal class ClassVtablesBuilder(val classDescriptor: IrClass, val context: Context) { internal class ClassVtablesBuilder(val irClass: IrClass, val context: Context) {
private val DEBUG = 0 private val DEBUG = 0
private inline fun DEBUG_OUTPUT(severity: Int, block: () -> Unit) { private inline fun DEBUG_OUTPUT(severity: Int, block: () -> Unit) {
if (DEBUG > severity) block() if (DEBUG > severity) block()
} }
val vtableEntries: List<OverriddenFunctionDescriptor> by lazy { val vtableEntries: List<OverriddenFunctionInfo> by lazy {
assert(!classDescriptor.isInterface) assert(!irClass.isInterface)
DEBUG_OUTPUT(0) { DEBUG_OUTPUT(0) {
println() println()
println("BUILDING vTable for ${classDescriptor.descriptor}") println("BUILDING vTable for ${irClass.descriptor}")
} }
val superVtableEntries = if (classDescriptor.isSpecialClassWithNoSupertypes()) { val superVtableEntries = if (irClass.isSpecialClassWithNoSupertypes()) {
emptyList() emptyList()
} else { } else {
val superClass = classDescriptor.getSuperClassNotAny() ?: context.ir.symbols.any.owner val superClass = irClass.getSuperClassNotAny() ?: context.ir.symbols.any.owner
context.getVtableBuilder(superClass).vtableEntries context.getVtableBuilder(superClass).vtableEntries
} }
val methods = classDescriptor.sortedOverridableOrOverridingMethods val methods = irClass.sortedOverridableOrOverridingMethods
val newVtableSlots = mutableListOf<OverriddenFunctionDescriptor>() val newVtableSlots = mutableListOf<OverriddenFunctionInfo>()
DEBUG_OUTPUT(0) { DEBUG_OUTPUT(0) {
println() println()
println("SUPER vTable:") println("SUPER vTable:")
superVtableEntries.forEach { println(" ${it.overriddenDescriptor.descriptor} -> ${it.descriptor.descriptor}") } superVtableEntries.forEach { println(" ${it.overriddenFunction.descriptor} -> ${it.function.descriptor}") }
println() println()
println("METHODS:") println("METHODS:")
@@ -118,57 +116,57 @@ internal class ClassVtablesBuilder(val classDescriptor: IrClass, val context: Co
} }
val inheritedVtableSlots = superVtableEntries.map { superMethod -> val inheritedVtableSlots = superVtableEntries.map { superMethod ->
val overridingMethod = methods.singleOrNull { it.overrides(superMethod.descriptor) } val overridingMethod = methods.singleOrNull { it.overrides(superMethod.function) }
if (overridingMethod == null) { if (overridingMethod == null) {
DEBUG_OUTPUT(0) { println("Taking super ${superMethod.overriddenDescriptor.descriptor} -> ${superMethod.descriptor.descriptor}") } DEBUG_OUTPUT(0) { println("Taking super ${superMethod.overriddenFunction.descriptor} -> ${superMethod.function.descriptor}") }
superMethod superMethod
} else { } else {
newVtableSlots.add(OverriddenFunctionDescriptor(overridingMethod, superMethod.descriptor)) newVtableSlots.add(OverriddenFunctionInfo(overridingMethod, superMethod.function))
DEBUG_OUTPUT(0) { println("Taking overridden ${superMethod.overriddenDescriptor.descriptor} -> ${overridingMethod.descriptor}") } DEBUG_OUTPUT(0) { println("Taking overridden ${superMethod.overriddenFunction.descriptor} -> ${overridingMethod.descriptor}") }
OverriddenFunctionDescriptor(overridingMethod, superMethod.overriddenDescriptor) OverriddenFunctionInfo(overridingMethod, superMethod.overriddenFunction)
} }
} }
// Add all possible (descriptor, overriddenDescriptor) edges for now, redundant will be removed later. // Add all possible (descriptor, overriddenDescriptor) edges for now, redundant will be removed later.
methods.mapTo(newVtableSlots) { OverriddenFunctionDescriptor(it, it) } methods.mapTo(newVtableSlots) { OverriddenFunctionInfo(it, it) }
val inheritedVtableSlotsSet = inheritedVtableSlots.map { it.descriptor to it.bridgeDirections }.toSet() val inheritedVtableSlotsSet = inheritedVtableSlots.map { it.function to it.bridgeDirections }.toSet()
val filteredNewVtableSlots = newVtableSlots val filteredNewVtableSlots = newVtableSlots
.filterNot { inheritedVtableSlotsSet.contains(it.descriptor to it.bridgeDirections) } .filterNot { inheritedVtableSlotsSet.contains(it.function to it.bridgeDirections) }
.distinctBy { it.descriptor to it.bridgeDirections } .distinctBy { it.function to it.bridgeDirections }
.filter { it.descriptor.isOverridable } .filter { it.function.isOverridable }
DEBUG_OUTPUT(0) { DEBUG_OUTPUT(0) {
println() println()
println("INHERITED vTable slots:") println("INHERITED vTable slots:")
inheritedVtableSlots.forEach { println(" ${it.overriddenDescriptor.descriptor} -> ${it.descriptor.descriptor}") } inheritedVtableSlots.forEach { println(" ${it.overriddenFunction.descriptor} -> ${it.function.descriptor}") }
println() println()
println("MY OWN vTable slots:") println("MY OWN vTable slots:")
filteredNewVtableSlots.forEach { println(" ${it.overriddenDescriptor.descriptor} -> ${it.descriptor.descriptor}") } filteredNewVtableSlots.forEach { println(" ${it.overriddenFunction.descriptor} -> ${it.function.descriptor}") }
} }
inheritedVtableSlots + filteredNewVtableSlots.sortedBy { it.overriddenDescriptor.uniqueId } inheritedVtableSlots + filteredNewVtableSlots.sortedBy { it.overriddenFunction.uniqueId }
} }
fun vtableIndex(function: IrSimpleFunction): Int { fun vtableIndex(function: IrSimpleFunction): Int {
val bridgeDirections = function.target.bridgeDirectionsTo(function.original) val bridgeDirections = function.target.bridgeDirectionsTo(function)
val index = vtableEntries.indexOfFirst { it.descriptor == function.original && it.bridgeDirections == bridgeDirections } val index = vtableEntries.indexOfFirst { it.function == function && it.bridgeDirections == bridgeDirections }
if (index < 0) throw Error(function.toString() + " not in vtable of " + classDescriptor.toString()) if (index < 0) throw Error(function.toString() + " not in vtable of " + irClass.toString())
return index return index
} }
val methodTableEntries: List<OverriddenFunctionDescriptor> by lazy { val methodTableEntries: List<OverriddenFunctionInfo> by lazy {
classDescriptor.sortedOverridableOrOverridingMethods irClass.sortedOverridableOrOverridingMethods
.flatMap { method -> method.allOverriddenDescriptors.map { OverriddenFunctionDescriptor(method, it) } } .flatMap { method -> method.allOverriddenFunctions.map { OverriddenFunctionInfo(method, it) } }
.filter { it.canBeCalledVirtually } .filter { it.canBeCalledVirtually }
.distinctBy { it.overriddenDescriptor.uniqueId } .distinctBy { it.overriddenFunction.uniqueId }
.sortedBy { it.overriddenDescriptor.uniqueId } .sortedBy { it.overriddenFunction.uniqueId }
// TODO: probably method table should contain all accessible methods to improve binary compatibility // TODO: probably method table should contain all accessible methods to improve binary compatibility
} }
@@ -127,7 +127,7 @@ internal fun IrFunction.needBridgeTo(target: IrFunction)
= (0..this.valueParameters.size + 2).any { needBridgeToAt(target, it) } = (0..this.valueParameters.size + 2).any { needBridgeToAt(target, it) }
internal val IrSimpleFunction.target: IrSimpleFunction internal val IrSimpleFunction.target: IrSimpleFunction
get() = (if (modality == Modality.ABSTRACT) this else resolveFakeOverride()).original get() = (if (modality == Modality.ABSTRACT) this else resolveFakeOverride())
internal val IrFunction.target: IrFunction internal val IrFunction.target: IrFunction
get() = when (this) { get() = when (this) {
@@ -181,7 +181,7 @@ internal class BridgeDirections(val array: Array<BridgeDirection>) {
} }
} }
val IrSimpleFunction.allOverriddenDescriptors: Set<IrSimpleFunction> val IrSimpleFunction.allOverriddenFunctions: Set<IrSimpleFunction>
get() { get() {
val result = mutableSetOf<IrSimpleFunction>() val result = mutableSetOf<IrSimpleFunction>()
@@ -214,13 +214,13 @@ internal fun IrSimpleFunction.bridgeDirectionsTo(
return ourDirections return ourDirections
} }
tailrec internal fun IrDeclaration.findPackage(): IrPackageFragment { internal tailrec fun IrDeclaration.findPackage(): IrPackageFragment {
val parent = this.parent val parent = this.parent
return parent as? IrPackageFragment return parent as? IrPackageFragment
?: (parent as IrDeclaration).findPackage() ?: (parent as IrDeclaration).findPackage()
} }
fun IrFunction.isComparisonDescriptor(map: Map<SimpleType, IrSimpleFunction>): Boolean = fun IrFunction.isComparisonFunction(map: Map<SimpleType, IrSimpleFunction>): Boolean =
this in map.values this in map.values
val IrDeclaration.isPropertyAccessor get() = val IrDeclaration.isPropertyAccessor get() =
@@ -28,9 +28,6 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
val IrConstructor.constructedClass get() = this.parent as IrClass val IrConstructor.constructedClass get() = this.parent as IrClass
val <T : IrDeclaration> T.original get() = this
val IrDeclaration.containingDeclaration get() = this.parent
val IrDeclarationParent.fqNameSafe: FqName get() = when (this) { val IrDeclarationParent.fqNameSafe: FqName get() = when (this) {
is IrPackageFragment -> this.fqName is IrPackageFragment -> this.fqName
is IrDeclaration -> this.parent.fqNameSafe.child(this.name) is IrDeclaration -> this.parent.fqNameSafe.child(this.name)
@@ -116,8 +113,6 @@ val IrProperty.konanBackingField: IrField?
return null return null
} }
val IrField.containingClass get() = this.parent as? IrClass
val IrFunction.isReal get() = this.origin != IrDeclarationOrigin.FAKE_OVERRIDE val IrFunction.isReal get() = this.origin != IrDeclarationOrigin.FAKE_OVERRIDE
// Note: psi2ir doesn't set `origin = FAKE_OVERRIDE` for fields and properties yet. // Note: psi2ir doesn't set `origin = FAKE_OVERRIDE` for fields and properties yet.
@@ -151,8 +146,6 @@ fun IrSimpleFunction.overrides(other: IrSimpleFunction): Boolean {
fun IrClass.isSpecialClassWithNoSupertypes() = this.isAny() || this.isNothing() fun IrClass.isSpecialClassWithNoSupertypes() = this.isAny() || this.isNothing()
internal val IrValueParameter.isValueParameter get() = this.index >= 0
private val IrCall.annotationClass private val IrCall.annotationClass
get() = (this.symbol.owner as IrConstructor).constructedClass get() = (this.symbol.owner as IrConstructor).constructedClass
@@ -17,7 +17,6 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
@@ -181,37 +180,35 @@ private val IrFunction.signature: String
// TODO: rename to indicate that it has signature included // TODO: rename to indicate that it has signature included
internal val IrFunction.functionName: String internal val IrFunction.functionName: String
get() { get() {
with(this.original) { // basic support for generics (if (this is IrConstructor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo()?.let {
(if (this is IrConstructor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo()?.let { return buildString {
return buildString { if (extensionReceiverParameter != null) {
if (extensionReceiverParameter != null) { append(extensionReceiverParameter!!.type.getClass()!!.name)
append(extensionReceiverParameter!!.type.getClass()!!.name) append(".")
append(".") }
}
append("objc:") append("objc:")
append(it.selector) append(it.selector)
if (this@with is IrConstructor && this@with.isObjCConstructor) append("#Constructor") if (this@functionName is IrConstructor && this@functionName.isObjCConstructor) append("#Constructor")
// We happen to have the clashing combinations such as // We happen to have the clashing combinations such as
//@ObjCMethod("issueChallengeToPlayers:message:", "objcKniBridge1165") //@ObjCMethod("issueChallengeToPlayers:message:", "objcKniBridge1165")
//external fun GKScore.issueChallengeToPlayers(playerIDs: List<*>?, message: String?): Unit //external fun GKScore.issueChallengeToPlayers(playerIDs: List<*>?, message: String?): Unit
//@ObjCMethod("issueChallengeToPlayers:message:", "objcKniBridge1172") //@ObjCMethod("issueChallengeToPlayers:message:", "objcKniBridge1172")
//external fun GKScore.issueChallengeToPlayers(playerIDs: List<*>?, message: String?): Unit //external fun GKScore.issueChallengeToPlayers(playerIDs: List<*>?, message: String?): Unit
// So disambiguate by the name of the bridge for now. // So disambiguate by the name of the bridge for now.
// TODO: idealy we'd never generate such identical declarations. // TODO: idealy we'd never generate such identical declarations.
if (this@with is IrSimpleFunction && this@with.hasObjCMethodAnnotation()) { if (this@functionName is IrSimpleFunction && this@functionName.hasObjCMethodAnnotation()) {
this@with.objCMethodArgValue("selector") ?.let { append("#$it") } this@functionName.objCMethodArgValue("selector") ?.let { append("#$it") }
this@with.objCMethodArgValue("bridge") ?.let { append("#$it") } this@functionName.objCMethodArgValue("bridge") ?.let { append("#$it") }
}
} }
} }
val name = this.name.mangleIfInternal(this.module, this.visibility)
return "$name$signature"
} }
val name = this.name.mangleIfInternal(this.module, this.visibility)
return "$name$signature"
} }
private fun Name.mangleIfInternal(moduleDescriptor: ModuleDescriptor, visibility: Visibility): String = private fun Name.mangleIfInternal(moduleDescriptor: ModuleDescriptor, visibility: Visibility): String =
@@ -260,14 +257,13 @@ internal val IrField.symbolName: String
// TODO: bring here dependencies of this method? // TODO: bring here dependencies of this method?
internal fun RuntimeAware.getLlvmFunctionType(function: IrFunction): LLVMTypeRef { internal fun RuntimeAware.getLlvmFunctionType(function: IrFunction): LLVMTypeRef {
val original = function.original
val returnType = when { val returnType = when {
original is IrConstructor -> voidType function is IrConstructor -> voidType
original.isSuspend -> kObjHeaderPtr // Suspend functions return Any?. function.isSuspend -> kObjHeaderPtr // Suspend functions return Any?.
else -> getLLVMReturnType(original.returnType) else -> getLLVMReturnType(function.returnType)
} }
val paramTypes = ArrayList(original.allParameters.map { getLLVMType(it.type) }) val paramTypes = ArrayList(function.allParameters.map { getLLVMType(it.type) })
if (original.isSuspend) if (function.isSuspend)
paramTypes.add(kObjHeaderPtr) // Suspend functions have implicit parameter of type Continuation<>. paramTypes.add(kObjHeaderPtr) // Suspend functions have implicit parameter of type Continuation<>.
if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr) if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr)
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.* import kotlinx.cinterop.*
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.irasdescriptors.* import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
@@ -29,8 +28,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
/* to class descriptor */ fun typeInfoValue(irClass: IrClass): LLVMValueRef = irClass.llvmTypeInfoPtr
fun typeInfoValue(descriptor: IrClass): LLVMValueRef = descriptor.llvmTypeInfoPtr
fun param(fn: IrFunction, i: Int): LLVMValueRef { fun param(fn: IrFunction, i: Int): LLVMValueRef {
assert(i >= 0 && i < countParams(fn)) assert(i >= 0 && i < countParams(fn))
@@ -39,19 +37,19 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
private fun countParams(fn: IrFunction) = LLVMCountParams(fn.llvmFunction) private fun countParams(fn: IrFunction) = LLVMCountParams(fn.llvmFunction)
fun functionEntryPointAddress(descriptor: IrFunction) = descriptor.entryPointAddress.llvm fun functionEntryPointAddress(function: IrFunction) = function.entryPointAddress.llvm
fun functionHash(descriptor: IrFunction): LLVMValueRef = descriptor.functionName.localHash.llvm fun functionHash(function: IrFunction): LLVMValueRef = function.functionName.localHash.llvm
fun getObjectInstanceStorage(descriptor: IrClass, shared: Boolean): LLVMValueRef { fun getObjectInstanceStorage(irClass: IrClass, shared: Boolean): LLVMValueRef {
assert (!descriptor.isUnit()) assert (!irClass.isUnit())
val llvmGlobal = if (!isExternal(descriptor)) { val llvmGlobal = if (!isExternal(irClass)) {
context.llvmDeclarations.forSingleton(descriptor).instanceFieldRef context.llvmDeclarations.forSingleton(irClass).instanceFieldRef
} else { } else {
val llvmType = getLLVMType(descriptor.defaultType) val llvmType = getLLVMType(irClass.defaultType)
importGlobal( importGlobal(
descriptor.objectInstanceFieldSymbolName, irClass.objectInstanceFieldSymbolName,
llvmType, llvmType,
origin = descriptor.llvmSymbolOrigin, origin = irClass.llvmSymbolOrigin,
threadLocal = !shared threadLocal = !shared
) )
} }
@@ -62,17 +60,17 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
return llvmGlobal return llvmGlobal
} }
fun getObjectInstanceShadowStorage(descriptor: IrClass): LLVMValueRef { fun getObjectInstanceShadowStorage(irClass: IrClass): LLVMValueRef {
assert (!descriptor.isUnit()) assert (!irClass.isUnit())
assert (descriptor.objectIsShared) assert (irClass.objectIsShared)
val llvmGlobal = if (!isExternal(descriptor)) { val llvmGlobal = if (!isExternal(irClass)) {
context.llvmDeclarations.forSingleton(descriptor).instanceShadowFieldRef!! context.llvmDeclarations.forSingleton(irClass).instanceShadowFieldRef!!
} else { } else {
val llvmType = getLLVMType(descriptor.defaultType) val llvmType = getLLVMType(irClass.defaultType)
importGlobal( importGlobal(
descriptor.objectInstanceShadowFieldSymbolName, irClass.objectInstanceShadowFieldSymbolName,
llvmType, llvmType,
origin = descriptor.llvmSymbolOrigin, origin = irClass.llvmSymbolOrigin,
threadLocal = true threadLocal = true
) )
} }
@@ -112,18 +110,18 @@ val LLVMValueRef.isConst:Boolean
internal inline fun<R> generateFunction(codegen: CodeGenerator, internal inline fun<R> generateFunction(codegen: CodeGenerator,
descriptor: IrFunction, function: IrFunction,
startLocation: LocationInfo? = null, startLocation: LocationInfo? = null,
endLocation: LocationInfo? = null, endLocation: LocationInfo? = null,
code:FunctionGenerationContext.(FunctionGenerationContext) -> R) { code:FunctionGenerationContext.(FunctionGenerationContext) -> R) {
val llvmFunction = codegen.llvmFunction(descriptor) val llvmFunction = codegen.llvmFunction(function)
generateFunctionBody(FunctionGenerationContext( generateFunctionBody(FunctionGenerationContext(
llvmFunction, llvmFunction,
codegen, codegen,
startLocation, startLocation,
endLocation, endLocation,
descriptor), code) function), code)
} }
@@ -143,7 +141,7 @@ internal inline fun generateFunction(
return function return function
} }
inline private fun <R> generateFunctionBody( private inline fun <R> generateFunctionBody(
functionGenerationContext: FunctionGenerationContext, functionGenerationContext: FunctionGenerationContext,
code: FunctionGenerationContext.(FunctionGenerationContext) -> R) { code: FunctionGenerationContext.(FunctionGenerationContext) -> R) {
functionGenerationContext.prologue() functionGenerationContext.prologue()
@@ -158,7 +156,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
val codegen: CodeGenerator, val codegen: CodeGenerator,
startLocation: LocationInfo?, startLocation: LocationInfo?,
endLocation: LocationInfo?, endLocation: LocationInfo?,
internal val functionDescriptor: IrFunction? = null): ContextUtils { internal val irFunction: IrFunction? = null): ContextUtils {
override val context = codegen.context override val context = codegen.context
val vars = VariableManager(this) val vars = VariableManager(this)
@@ -171,9 +169,8 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
var returnType: LLVMTypeRef? = LLVMGetReturnType(getFunctionType(function)) var returnType: LLVMTypeRef? = LLVMGetReturnType(getFunctionType(function))
private val returns: MutableMap<LLVMBasicBlockRef, LLVMValueRef> = mutableMapOf() private val returns: MutableMap<LLVMBasicBlockRef, LLVMValueRef> = mutableMapOf()
// TODO: remove, to make CodeGenerator descriptor-agnostic.
val constructedClass: IrClass? val constructedClass: IrClass?
get() = (functionDescriptor as? IrConstructor)?.constructedClass get() = (irFunction as? IrConstructor)?.constructedClass
private var returnSlot: LLVMValueRef? = null private var returnSlot: LLVMValueRef? = null
private var slotsPhi: LLVMValueRef? = null private var slotsPhi: LLVMValueRef? = null
private val frameOverlaySlotCount = private val frameOverlaySlotCount =
@@ -195,8 +192,8 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
var forwardingForeignExceptionsTerminatedWith: LLVMValueRef? = null var forwardingForeignExceptionsTerminatedWith: LLVMValueRef? = null
init { init {
functionDescriptor?.let { irFunction?.let {
if (!functionDescriptor.isExported()) { if (!irFunction.isExported()) {
LLVMSetLinkage(function, LLVMLinkage.LLVMInternalLinkage) LLVMSetLinkage(function, LLVMLinkage.LLVMInternalLinkage)
// (Cannot do this before the function body is created). // (Cannot do this before the function body is created).
} }
@@ -409,8 +406,8 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
return call(context.llvm.allocInstanceFunction, listOf(typeInfo), lifetime) return call(context.llvm.allocInstanceFunction, listOf(typeInfo), lifetime)
} }
fun allocInstance(descriptor: IrClass, lifetime: Lifetime): LLVMValueRef = fun allocInstance(irClass: IrClass, lifetime: Lifetime): LLVMValueRef =
allocInstance(codegen.typeInfoForAllocation(descriptor), lifetime) allocInstance(codegen.typeInfoForAllocation(irClass), lifetime)
fun allocArray( fun allocArray(
typeInfo: LLVMValueRef, count: LLVMValueRef, lifetime: Lifetime): LLVMValueRef { typeInfo: LLVMValueRef, count: LLVMValueRef, lifetime: Lifetime): LLVMValueRef {
@@ -628,10 +625,10 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
return switch return switch
} }
fun lookupVirtualImpl(receiver: LLVMValueRef, descriptor: IrFunction): LLVMValueRef { fun lookupVirtualImpl(receiver: LLVMValueRef, irFunction: IrFunction): LLVMValueRef {
assert(LLVMTypeOf(receiver) == codegen.kObjHeaderPtr) assert(LLVMTypeOf(receiver) == codegen.kObjHeaderPtr)
val typeInfoPtr: LLVMValueRef = if (descriptor.getObjCMethodInfo() != null) { val typeInfoPtr: LLVMValueRef = if (irFunction.getObjCMethodInfo() != null) {
call(context.llvm.getObjCKotlinTypeInfo, listOf(receiver)) call(context.llvm.getObjCKotlinTypeInfo, listOf(receiver))
} else { } else {
val typeInfoOrMetaPtr = structGep(receiver, 0 /* typeInfoOrMeta_ */) val typeInfoOrMetaPtr = structGep(receiver, 0 /* typeInfoOrMeta_ */)
@@ -651,12 +648,12 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
* if toString/eq/hc is invoked on an interface instance, we resolve * if toString/eq/hc is invoked on an interface instance, we resolve
* owner as Any and dispatch it via vtable. * owner as Any and dispatch it via vtable.
*/ */
val anyMethod = (descriptor as IrSimpleFunction).findOverriddenMethodOfAny() val anyMethod = (irFunction as IrSimpleFunction).findOverriddenMethodOfAny()
val owner = (anyMethod ?: descriptor).containingDeclaration as IrClass val owner = (anyMethod ?: irFunction).parentAsClass
val llvmMethod = if (!owner.isInterface) { val llvmMethod = if (!owner.isInterface) {
// If this is a virtual method of the class - we can call via vtable. // If this is a virtual method of the class - we can call via vtable.
val index = context.getVtableBuilder(owner).vtableIndex(anyMethod ?: descriptor) val index = context.getVtableBuilder(owner).vtableIndex(anyMethod ?: irFunction)
val vtablePlace = gep(typeInfoPtr, Int32(1).llvm) // typeInfoPtr + 1 val vtablePlace = gep(typeInfoPtr, Int32(1).llvm) // typeInfoPtr + 1
val vtable = bitcast(kInt8PtrPtr, vtablePlace) val vtable = bitcast(kInt8PtrPtr, vtablePlace)
val slot = gep(vtable, Int32(index).llvm) val slot = gep(vtable, Int32(index).llvm)
@@ -666,11 +663,11 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
// TODO: optimize by storing interface number in lower bits of 'this' pointer // TODO: optimize by storing interface number in lower bits of 'this' pointer
// when passing object as an interface. This way we can use those bits as index // when passing object as an interface. This way we can use those bits as index
// for an additional per-interface vtable. // for an additional per-interface vtable.
val methodHash = codegen.functionHash(descriptor) // Calculate hash of the method to be invoked val methodHash = codegen.functionHash(irFunction) // Calculate hash of the method to be invoked
val lookupArgs = listOf(typeInfoPtr, methodHash) // Prepare args for lookup val lookupArgs = listOf(typeInfoPtr, methodHash) // Prepare args for lookup
call(context.llvm.lookupOpenMethodFunction, lookupArgs) call(context.llvm.lookupOpenMethodFunction, lookupArgs)
} }
val functionPtrType = pointerType(codegen.getLlvmFunctionType(descriptor)) // Construct type of the method to be invoked val functionPtrType = pointerType(codegen.getLlvmFunctionType(irFunction)) // Construct type of the method to be invoked
return bitcast(functionPtrType, llvmMethod) // Cast method address to the type return bitcast(functionPtrType, llvmMethod) // Cast method address to the type
} }
@@ -685,16 +682,16 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
} }
fun getObjectValue( fun getObjectValue(
descriptor: IrClass, irClass: IrClass,
exceptionHandler: ExceptionHandler, exceptionHandler: ExceptionHandler,
locationInfo: LocationInfo? locationInfo: LocationInfo?
): LLVMValueRef { ): LLVMValueRef {
if (descriptor.isUnit()) { if (irClass.isUnit()) {
return codegen.theUnitInstanceRef.llvm return codegen.theUnitInstanceRef.llvm
} }
if (descriptor.isCompanion) { if (irClass.isCompanion) {
val parent = descriptor.parent as IrClass val parent = irClass.parent as IrClass
if (parent.isObjCClass()) { if (parent.isObjCClass()) {
// TODO: cache it too. // TODO: cache it too.
@@ -707,8 +704,8 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
} }
} }
val shared = descriptor.objectIsShared && context.config.threadsAreAllowed val shared = irClass.objectIsShared && context.config.threadsAreAllowed
val objectPtr = codegen.getObjectInstanceStorage(descriptor, shared) val objectPtr = codegen.getObjectInstanceStorage(irClass, shared)
val bbInit = basicBlock("label_init", locationInfo) val bbInit = basicBlock("label_init", locationInfo)
val bbExit = basicBlock("label_continue", locationInfo) val bbExit = basicBlock("label_continue", locationInfo)
val objectVal = loadSlot(objectPtr, false) val objectVal = loadSlot(objectPtr, false)
@@ -717,12 +714,12 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
condBr(objectInitialized, bbExit, bbInit) condBr(objectInitialized, bbExit, bbInit)
positionAtEnd(bbInit) positionAtEnd(bbInit)
val typeInfo = codegen.typeInfoForAllocation(descriptor) val typeInfo = codegen.typeInfoForAllocation(irClass)
val defaultConstructor = descriptor.constructors.single { it.valueParameters.size == 0 } val defaultConstructor = irClass.constructors.single { it.valueParameters.size == 0 }
val ctor = codegen.llvmFunction(defaultConstructor) val ctor = codegen.llvmFunction(defaultConstructor)
val (initFunction, args) = val (initFunction, args) =
if (shared) { if (shared) {
val shadowObjectPtr = codegen.getObjectInstanceShadowStorage(descriptor) val shadowObjectPtr = codegen.getObjectInstanceShadowStorage(irClass)
context.llvm.initSharedInstanceFunction to listOf(objectPtr, shadowObjectPtr, typeInfo, ctor) context.llvm.initSharedInstanceFunction to listOf(objectPtr, shadowObjectPtr, typeInfo, ctor)
} else { } else {
context.llvm.initInstanceFunction to listOf(objectPtr, typeInfo, ctor) context.llvm.initInstanceFunction to listOf(objectPtr, typeInfo, ctor)
@@ -732,7 +729,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
br(bbExit) br(bbExit)
positionAtEnd(bbExit) positionAtEnd(bbExit)
val valuePhi = phi(codegen.getLLVMType(descriptor.defaultType)) val valuePhi = phi(codegen.getLLVMType(irClass.defaultType))
addPhiIncoming(valuePhi, bbCurrent to objectVal, bbInitResult to newValue) addPhiIncoming(valuePhi, bbCurrent to objectVal, bbInitResult to newValue)
return valuePhi return valuePhi
@@ -741,11 +738,11 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
/** /**
* Note: the same code is generated as IR in [org.jetbrains.kotlin.backend.konan.lower.EnumUsageLowering]. * Note: the same code is generated as IR in [org.jetbrains.kotlin.backend.konan.lower.EnumUsageLowering].
*/ */
fun getEnumEntry(descriptor: IrEnumEntry, exceptionHandler: ExceptionHandler): LLVMValueRef { fun getEnumEntry(enumEntry: IrEnumEntry, exceptionHandler: ExceptionHandler): LLVMValueRef {
val enumClassDescriptor = descriptor.containingDeclaration as IrClass val enumClass = enumEntry.parentAsClass
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClassDescriptor) val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClass)
val ordinal = loweredEnum.entriesMap[descriptor.name]!! val ordinal = loweredEnum.entriesMap[enumEntry.name]!!
val values = call( val values = call(
loweredEnum.valuesGetter.llvmFunction, loweredEnum.valuesGetter.llvmFunction,
emptyList(), emptyList(),
@@ -141,8 +141,8 @@ internal interface ContextUtils : RuntimeAware {
val staticData: StaticData val staticData: StaticData
get() = context.llvm.staticData get() = context.llvm.staticData
fun isExternal(descriptor: IrDeclaration): Boolean { fun isExternal(declaration: IrDeclaration): Boolean {
val pkg = descriptor.findPackage() val pkg = declaration.findPackage()
return when (pkg) { return when (pkg) {
is IrFile -> pkg.packageFragmentDescriptor.containingDeclaration != context.moduleDescriptor is IrFile -> pkg.packageFragmentDescriptor.containingDeclaration != context.moduleDescriptor
is IrExternalPackageFragment -> true is IrExternalPackageFragment -> true
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.SourceFile
import org.jetbrains.kotlin.descriptors.konan.CurrentKonanModuleOrigin import org.jetbrains.kotlin.descriptors.konan.CurrentKonanModuleOrigin
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
@@ -33,7 +32,7 @@ import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.getContainingFile import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
@@ -194,11 +193,9 @@ internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid {
override fun visitClass(declaration: IrClass) { override fun visitClass(declaration: IrClass) {
super.visitClass(declaration) super.visitClass(declaration)
val descriptor = declaration generator.generate(declaration)
generator.generate(descriptor) if (declaration.isKotlinObjCClass()) {
if (descriptor.isKotlinObjCClass()) {
kotlinObjCClassInfoGenerator.generate(declaration) kotlinObjCClassInfoGenerator.generate(declaration)
} }
} }
@@ -232,19 +229,19 @@ internal interface CodeContext {
* Declares the variable. * Declares the variable.
* @return index of declared variable. * @return index of declared variable.
*/ */
fun genDeclareVariable(descriptor: IrVariable, value: LLVMValueRef?, variableLocation: VariableDebugLocation?): Int fun genDeclareVariable(variable: IrVariable, value: LLVMValueRef?, variableLocation: VariableDebugLocation?): Int
/** /**
* @return index of variable declared before, or -1 if no such variable has been declared yet. * @return index of variable declared before, or -1 if no such variable has been declared yet.
*/ */
fun getDeclaredVariable(descriptor: IrVariable): Int fun getDeclaredVariable(variable: IrVariable): Int
/** /**
* Generates the code to obtain a value available in this context. * Generates the code to obtain a value available in this context.
* *
* @return the requested value * @return the requested value
*/ */
fun genGetValue(descriptor: IrValueDeclaration): LLVMValueRef fun genGetValue(value: IrValueDeclaration): LLVMValueRef
/** /**
* Returns owning function scope. * Returns owning function scope.
@@ -342,11 +339,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override fun genThrow(exception: LLVMValueRef) = unsupported() override fun genThrow(exception: LLVMValueRef) = unsupported()
override fun genDeclareVariable(descriptor: IrVariable, value: LLVMValueRef?, variableLocation: VariableDebugLocation?) = unsupported(descriptor) override fun genDeclareVariable(variable: IrVariable, value: LLVMValueRef?, variableLocation: VariableDebugLocation?) = unsupported(variable)
override fun getDeclaredVariable(descriptor: IrVariable) = -1 override fun getDeclaredVariable(variable: IrVariable) = -1
override fun genGetValue(descriptor: IrValueDeclaration) = unsupported(descriptor) override fun genGetValue(value: IrValueDeclaration) = unsupported(value)
override fun functionScope(): CodeContext? = null override fun functionScope(): CodeContext? = null
@@ -622,19 +619,19 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
*/ */
private inner class VariableScope : InnerScopeImpl() { private inner class VariableScope : InnerScopeImpl() {
override fun genDeclareVariable(descriptor: IrVariable, value: LLVMValueRef?, variableLocation: VariableDebugLocation?): Int { override fun genDeclareVariable(variable: IrVariable, value: LLVMValueRef?, variableLocation: VariableDebugLocation?): Int {
return functionGenerationContext.vars.createVariable(descriptor, value, variableLocation) return functionGenerationContext.vars.createVariable(variable, value, variableLocation)
} }
override fun getDeclaredVariable(descriptor: IrVariable): Int { override fun getDeclaredVariable(variable: IrVariable): Int {
val index = functionGenerationContext.vars.indexOf(descriptor) val index = functionGenerationContext.vars.indexOf(variable)
return if (index < 0) super.getDeclaredVariable(descriptor) else return index return if (index < 0) super.getDeclaredVariable(variable) else return index
} }
override fun genGetValue(descriptor: IrValueDeclaration): LLVMValueRef { override fun genGetValue(value: IrValueDeclaration): LLVMValueRef {
val index = functionGenerationContext.vars.indexOf(descriptor) val index = functionGenerationContext.vars.indexOf(value)
if (index < 0) { if (index < 0) {
return super.genGetValue(descriptor) return super.genGetValue(value)
} else { } else {
return functionGenerationContext.vars.load(index) return functionGenerationContext.vars.load(index)
} }
@@ -653,21 +650,20 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
init { init {
if (function != null) { if (function != null) {
parameters.forEach{ parameters.forEach{
val descriptor = it.key val parameter = it.key
val ir = descriptor
val local = functionGenerationContext.vars.createParameter(descriptor, val local = functionGenerationContext.vars.createParameter(parameter,
debugInfoIfNeeded(function, ir)) debugInfoIfNeeded(function, parameter))
functionGenerationContext.mapParameterForDebug(local, it.value) functionGenerationContext.mapParameterForDebug(local, it.value)
} }
} }
} }
override fun genGetValue(descriptor: IrValueDeclaration): LLVMValueRef { override fun genGetValue(value: IrValueDeclaration): LLVMValueRef {
val index = functionGenerationContext.vars.indexOf(descriptor) val index = functionGenerationContext.vars.indexOf(value)
if (index < 0) { if (index < 0) {
return super.genGetValue(descriptor) return super.genGetValue(value)
} else { } else {
return functionGenerationContext.vars.load(index) return functionGenerationContext.vars.load(index)
} }
@@ -690,7 +686,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
codegen.llvmFunction(it) codegen.llvmFunction(it)
} }
private var name:String? = declaration?.descriptor?.name?.asString() private var name:String? = declaration?.name?.asString()
override fun genReturn(target: IrSymbolOwner, value: LLVMValueRef?) { override fun genReturn(target: IrSymbolOwner, value: LLVMValueRef?) {
if (declaration == null || target == declaration) { if (declaration == null || target == declaration) {
@@ -735,13 +731,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
/** /**
* Binds LLVM function parameters to IR parameter descriptors. * Binds LLVM function parameters to IR parameter descriptors.
*/ */
private fun bindParameters(descriptor: IrFunction?): Map<IrValueParameter, LLVMValueRef> { private fun bindParameters(function: IrFunction?): Map<IrValueParameter, LLVMValueRef> {
if (descriptor == null) return emptyMap() if (function == null) return emptyMap()
val parameterDescriptors = descriptor.allParameters return function.allParameters.mapIndexed { i, irParameter ->
return parameterDescriptors.mapIndexed { i, parameterDescriptor -> val parameter = codegen.param(function, i)
val parameter = codegen.param(descriptor, i) assert(codegen.getLLVMType(irParameter.type) == parameter.type)
assert(codegen.getLLVMType(parameterDescriptor.type) == parameter.type) irParameter to parameter
parameterDescriptor to parameter
}.toMap() }.toMap()
} }
@@ -750,9 +745,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val body = declaration.body val body = declaration.body
if (declaration.descriptor.modality == Modality.ABSTRACT) return if ((declaration as? IrSimpleFunction)?.modality == Modality.ABSTRACT
if (declaration.descriptor.isExternal) return || declaration.isExternal
if (body == null) return || body == null)
return
generateFunction(codegen, declaration, generateFunction(codegen, declaration,
declaration.location(start = true), declaration.location(start = true),
@@ -826,10 +822,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override fun visitField(declaration: IrField) { override fun visitField(declaration: IrField) {
context.log{"visitField : ${ir2string(declaration)}"} context.log{"visitField : ${ir2string(declaration)}"}
debugFieldDeclaration(declaration) debugFieldDeclaration(declaration)
val descriptor = declaration
if (context.needGlobalInit(declaration)) { if (context.needGlobalInit(declaration)) {
val type = codegen.getLLVMType(descriptor.type) val type = codegen.getLLVMType(declaration.type)
val globalProperty = context.llvmDeclarations.forStaticField(descriptor).storage val globalProperty = context.llvmDeclarations.forStaticField(declaration).storage
val initializer = declaration.initializer?.expression as? IrConst<*> val initializer = declaration.initializer?.expression as? IrConst<*>
if (initializer != null) if (initializer != null)
LLVMSetInitializer(globalProperty, evaluateExpression(initializer)) LLVMSetInitializer(globalProperty, evaluateExpression(initializer))
@@ -1378,14 +1373,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateCast(value: IrTypeOperatorCall): LLVMValueRef { private fun evaluateCast(value: IrTypeOperatorCall): LLVMValueRef {
context.log{"evaluateCast : ${ir2string(value)}"} context.log{"evaluateCast : ${ir2string(value)}"}
val dstDescriptor = value.typeOperand.getClass()!! val dstClass = value.typeOperand.getClass()!!
val srcArg = evaluateExpression(value.argument) // Evaluate src expression. val srcArg = evaluateExpression(value.argument) // Evaluate src expression.
assert(srcArg.type == codegen.kObjHeaderPtr) assert(srcArg.type == codegen.kObjHeaderPtr)
if (dstDescriptor.defaultType.isObjCObjectType()) { if (dstClass.defaultType.isObjCObjectType()) {
with(functionGenerationContext) { with(functionGenerationContext) {
ifThen(not(genInstanceOf(srcArg, dstDescriptor))) { ifThen(not(genInstanceOf(srcArg, dstClass))) {
callDirect( callDirect(
context.ir.symbols.ThrowTypeCastException.owner, context.ir.symbols.ThrowTypeCastException.owner,
emptyList(), emptyList(),
@@ -1398,7 +1393,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
// Note: the code above would actually work for any classes. // Note: the code above would actually work for any classes.
// However, the code generated below is shorter. Consider it to be a specialization. // However, the code generated below is shorter. Consider it to be a specialization.
val dstTypeInfo = codegen.typeInfoValue(dstDescriptor) // Get TypeInfo for dst type. val dstTypeInfo = codegen.typeInfoValue(dstClass) // Get TypeInfo for dst type.
val srcObjInfoPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, srcArg) // Cast src to ObjInfoPtr. val srcObjInfoPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, srcArg) // Cast src to ObjInfoPtr.
val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list. val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list.
call(context.llvm.checkInstanceFunction, args) // Check if dst is subclass of src. call(context.llvm.checkInstanceFunction, args) // Check if dst is subclass of src.
@@ -1600,24 +1595,23 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun fieldPtrOfClass(thisPtr: LLVMValueRef, value: IrField): LLVMValueRef { private fun fieldPtrOfClass(thisPtr: LLVMValueRef, value: IrField): LLVMValueRef {
val fieldInfo = context.llvmDeclarations.forField(value) val fieldInfo = context.llvmDeclarations.forField(value)
val classDescriptor = value.containingDeclaration as IrClass
val typePtr = pointerType(fieldInfo.classBodyType) val typePtr = pointerType(fieldInfo.classBodyType)
val bodyPtr = getObjectBodyPtr(classDescriptor, thisPtr) val bodyPtr = getObjectBodyPtr(value.parentAsClass, thisPtr)
val typedBodyPtr = functionGenerationContext.bitcast(typePtr, bodyPtr) val typedBodyPtr = functionGenerationContext.bitcast(typePtr, bodyPtr)
val fieldPtr = LLVMBuildStructGEP(functionGenerationContext.builder, typedBodyPtr, fieldInfo.index, "") val fieldPtr = LLVMBuildStructGEP(functionGenerationContext.builder, typedBodyPtr, fieldInfo.index, "")
return fieldPtr!! return fieldPtr!!
} }
private fun getObjectBodyPtr(classDescriptor: IrClass, objectPtr: LLVMValueRef): LLVMValueRef { private fun getObjectBodyPtr(irClass: IrClass, objectPtr: LLVMValueRef): LLVMValueRef {
return if (classDescriptor.isObjCClass()) { return if (irClass.isObjCClass()) {
assert(classDescriptor.isKotlinObjCClass()) assert(irClass.isKotlinObjCClass())
val objCPtr = callDirect(context.ir.symbols.interopObjCObjectRawValueGetter.owner, val objCPtr = callDirect(context.ir.symbols.interopObjCObjectRawValueGetter.owner,
listOf(objectPtr), Lifetime.IRRELEVANT) listOf(objectPtr), Lifetime.IRRELEVANT)
val objCDeclarations = context.llvmDeclarations.forClass(classDescriptor).objCDeclarations!! val objCDeclarations = context.llvmDeclarations.forClass(irClass).objCDeclarations!!
val bodyOffset = functionGenerationContext.load(objCDeclarations.bodyOffsetGlobal.llvmGlobal) val bodyOffset = functionGenerationContext.load(objCDeclarations.bodyOffsetGlobal.llvmGlobal)
functionGenerationContext.gep(objCPtr, bodyOffset) functionGenerationContext.gep(objCPtr, bodyOffset)
@@ -1962,7 +1956,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
.filterIsInstance<IrSimpleFunction>().single { it.name.asString() == "invokeSuspend" } .filterIsInstance<IrSimpleFunction>().single { it.name.asString() == "invokeSuspend" }
private fun getContinuation(): LLVMValueRef { private fun getContinuation(): LLVMValueRef {
val caller = functionGenerationContext.functionDescriptor!! val caller = functionGenerationContext.irFunction!!
return if (caller.isSuspend) return if (caller.isSuspend)
codegen.param(caller, caller.allParameters.size) // The last argument. codegen.param(caller, caller.allParameters.size) // The last argument.
else { else {
@@ -2002,11 +1996,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
assert (expression.getArguments().isEmpty()) assert (expression.getArguments().isEmpty())
val descriptor = expression.symbol.owner val function = expression.symbol.owner
assert (descriptor.dispatchReceiverParameter == null) assert (function.dispatchReceiverParameter == null)
val entry = codegen.functionEntryPointAddress(descriptor) return codegen.functionEntryPointAddress(function)
return entry
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
@@ -2050,14 +2043,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private inner class SuspensionPointScope(val suspensionPointId: IrVariable, private inner class SuspensionPointScope(val suspensionPointId: IrVariable,
val bbResume: LLVMBasicBlockRef, val bbResume: LLVMBasicBlockRef,
val bbResumeId: Int): InnerScopeImpl() { val bbResumeId: Int): InnerScopeImpl() {
override fun genGetValue(descriptor: IrValueDeclaration): LLVMValueRef { override fun genGetValue(value: IrValueDeclaration): LLVMValueRef {
if (descriptor == suspensionPointId) { if (value == suspensionPointId) {
return if (context.config.indirectBranchesAreAllowed) return if (context.config.indirectBranchesAreAllowed)
functionGenerationContext.blockAddress(bbResume) functionGenerationContext.blockAddress(bbResume)
else else
functionGenerationContext.intToPtr(Int32(bbResumeId + 1).llvm, int8TypePtr) functionGenerationContext.intToPtr(Int32(bbResumeId + 1).llvm, int8TypePtr)
} }
return super.genGetValue(descriptor) return super.genGetValue(value)
} }
} }
@@ -2141,13 +2134,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun evaluateSimpleFunctionCall( private fun evaluateSimpleFunctionCall(
descriptor: IrFunction, args: List<LLVMValueRef>, function: IrFunction, args: List<LLVMValueRef>,
resultLifetime: Lifetime, superClass: IrClass? = null): LLVMValueRef { resultLifetime: Lifetime, superClass: IrClass? = null): LLVMValueRef {
//context.log{"evaluateSimpleFunctionCall : $tmpVariableName = ${ir2string(value)}"} //context.log{"evaluateSimpleFunctionCall : $tmpVariableName = ${ir2string(value)}"}
if (superClass == null && descriptor is IrSimpleFunction && descriptor.isOverridable) if (superClass == null && function is IrSimpleFunction && function.isOverridable)
return callVirtual(descriptor, args, resultLifetime) return callVirtual(function, args, resultLifetime)
else else
return callDirect(descriptor, args, resultLifetime) return callDirect(function, args, resultLifetime)
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
@@ -2190,8 +2183,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
} }
private fun genGetObjCClass(classDescriptor: IrClass): LLVMValueRef { private fun genGetObjCClass(irClass: IrClass): LLVMValueRef {
return functionGenerationContext.getObjCClass(classDescriptor, currentCodeContext.exceptionHandler) return functionGenerationContext.getObjCClass(irClass, currentCodeContext.exceptionHandler)
} }
private fun genGetObjCProtocol(irClass: IrClass): LLVMValueRef { private fun genGetObjCProtocol(irClass: IrClass): LLVMValueRef {
@@ -2220,68 +2213,63 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
// TODO: Intrinsify? // TODO: Intrinsify?
private fun evaluateOperatorCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef { private fun evaluateOperatorCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
context.log{"evaluateOperatorCall : origin:${ir2string(callee)}"} context.log{"evaluateOperatorCall : origin:${ir2string(callee)}"}
val descriptor = callee.symbol.owner val function = callee.symbol.owner
val ib = context.irModule!!.irBuiltins val ib = context.irModule!!.irBuiltins
with(functionGenerationContext) { with(functionGenerationContext) {
return when { return when {
descriptor == ib.eqeqeqFun -> icmpEq(args[0], args[1]) function == ib.eqeqeqFun -> icmpEq(args[0], args[1])
descriptor == ib.booleanNotFun -> icmpNe(args[0], kTrue) function == ib.booleanNotFun -> icmpNe(args[0], kTrue)
descriptor.isComparisonDescriptor(ib.greaterFunByOperandType) -> { function.isComparisonFunction(ib.greaterFunByOperandType) -> {
if (args[0].type.isFloatingPoint()) fcmpGt(args[0], args[1]) if (args[0].type.isFloatingPoint()) fcmpGt(args[0], args[1])
else icmpGt(args[0], args[1]) else icmpGt(args[0], args[1])
} }
descriptor.isComparisonDescriptor(ib.greaterOrEqualFunByOperandType) -> { function.isComparisonFunction(ib.greaterOrEqualFunByOperandType) -> {
if (args[0].type.isFloatingPoint()) fcmpGe(args[0], args[1]) if (args[0].type.isFloatingPoint()) fcmpGe(args[0], args[1])
else icmpGe(args[0], args[1]) else icmpGe(args[0], args[1])
} }
descriptor.isComparisonDescriptor(ib.lessFunByOperandType) -> { function.isComparisonFunction(ib.lessFunByOperandType) -> {
if (args[0].type.isFloatingPoint()) fcmpLt(args[0], args[1]) if (args[0].type.isFloatingPoint()) fcmpLt(args[0], args[1])
else icmpLt(args[0], args[1]) else icmpLt(args[0], args[1])
} }
descriptor.isComparisonDescriptor(ib.lessOrEqualFunByOperandType) -> { function.isComparisonFunction(ib.lessOrEqualFunByOperandType) -> {
if (args[0].type.isFloatingPoint()) fcmpLe(args[0], args[1]) if (args[0].type.isFloatingPoint()) fcmpLe(args[0], args[1])
else icmpLe(args[0], args[1]) else icmpLe(args[0], args[1])
} }
else -> TODO(descriptor.name.toString()) else -> TODO(function.name.toString())
} }
} }
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun callDirect(descriptor: IrFunction, args: List<LLVMValueRef>, fun callDirect(function: IrFunction, args: List<LLVMValueRef>,
resultLifetime: Lifetime): LLVMValueRef { resultLifetime: Lifetime): LLVMValueRef {
val realDescriptor = descriptor.target val llvmFunction = codegen.llvmFunction(function.target)
val llvmFunction = codegen.llvmFunction(realDescriptor) return call(function, llvmFunction, args, resultLifetime)
return call(descriptor, llvmFunction, args, resultLifetime)
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun callVirtual(descriptor: IrFunction, args: List<LLVMValueRef>, fun callVirtual(function: IrFunction, args: List<LLVMValueRef>,
resultLifetime: Lifetime): LLVMValueRef { resultLifetime: Lifetime): LLVMValueRef {
val function = functionGenerationContext.lookupVirtualImpl(args.first(), descriptor) val llvmFunction = functionGenerationContext.lookupVirtualImpl(args.first(), function)
return call(descriptor, function, args, resultLifetime) // Invoke the method return call(function, llvmFunction, args, resultLifetime) // Invoke the method
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
// TODO: it seems to be much more reliable to get args as a mapping from parameter descriptor to LLVM value, private fun call(function: IrFunction, llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
// instead of a plain list.
// In such case it would be possible to check that all args are available and in the correct order.
// However, it currently requires some refactoring to be performed.
private fun call(descriptor: IrFunction, function: LLVMValueRef, args: List<LLVMValueRef>,
resultLifetime: Lifetime): LLVMValueRef { resultLifetime: Lifetime): LLVMValueRef {
val result = call(function, args, resultLifetime) val result = call(llvmFunction, args, resultLifetime)
if (descriptor.returnType.isNothing()) { if (function.returnType.isNothing()) {
functionGenerationContext.unreachable() functionGenerationContext.unreachable()
} }
if (LLVMGetReturnType(getFunctionType(function)) == voidType) { if (LLVMGetReturnType(getFunctionType(llvmFunction)) == voidType) {
return codegen.theUnitInstanceRef.llvm return codegen.theUnitInstanceRef.llvm
} }
@@ -2289,10 +2277,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
// TODO: it seems to be much more reliable to get args as a mapping from parameter descriptor to LLVM value,
// instead of a plain list.
// In such case it would be possible to check that all args are available and in the correct order.
// However, it currently requires some refactoring to be performed.
private fun call(symbol: DataFlowIR.FunctionSymbol, function: LLVMValueRef, args: List<LLVMValueRef>, private fun call(symbol: DataFlowIR.FunctionSymbol, function: LLVMValueRef, args: List<LLVMValueRef>,
resultLifetime: Lifetime): LLVMValueRef { resultLifetime: Lifetime): LLVMValueRef {
val result = call(function, args, resultLifetime) val result = call(function, args, resultLifetime)
@@ -2315,17 +2299,17 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun delegatingConstructorCall( private fun delegatingConstructorCall(
descriptor: IrConstructor, args: List<LLVMValueRef>): LLVMValueRef { constructor: IrConstructor, args: List<LLVMValueRef>): LLVMValueRef {
val constructedClass = functionGenerationContext.constructedClass!! val constructedClass = functionGenerationContext.constructedClass!!
val thisPtr = currentCodeContext.genGetValue(constructedClass.thisReceiver!!) val thisPtr = currentCodeContext.genGetValue(constructedClass.thisReceiver!!)
if (descriptor.constructedClass.isExternalObjCClass()) { if (constructor.constructedClass.isExternalObjCClass()) {
assert(args.isEmpty()) assert(args.isEmpty())
return codegen.theUnitInstanceRef.llvm return codegen.theUnitInstanceRef.llvm
} }
val thisPtrArgType = codegen.getLLVMType(descriptor.allParameters[0].type) val thisPtrArgType = codegen.getLLVMType(constructor.allParameters[0].type)
val thisPtrArg = if (thisPtr.type == thisPtrArgType) { val thisPtrArg = if (thisPtr.type == thisPtrArgType) {
thisPtr thisPtr
} else { } else {
@@ -2333,7 +2317,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionGenerationContext.bitcast(thisPtrArgType, thisPtr) functionGenerationContext.bitcast(thisPtrArgType, thisPtr)
} }
return callDirect(descriptor, listOf(thisPtrArg) + args, return callDirect(constructor, listOf(thisPtrArg) + args,
Lifetime.IRRELEVANT /* no value returned */) Lifetime.IRRELEVANT /* no value returned */)
} }
@@ -2385,13 +2369,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun appendEntryPointSelector(descriptor: IrFunction?) { private fun appendEntryPointSelector(function: IrFunction?) {
if (descriptor == null) return if (function == null) return
val entryPoint = codegen.llvmFunction(descriptor) val entryPoint = codegen.llvmFunction(function)
val selectorName = "EntryPointSelector" val selectorName = "EntryPointSelector"
val entryPointType = getFunctionType(entryPoint) val entryPointType = getFunctionType(entryPoint)
val argCount = descriptor.valueParameters.size val argCount = function.valueParameters.size
assert(argCount <= 1) assert(argCount <= 1)
val selector = entryPointSelector(entryPoint, entryPointType, selectorName, argCount) val selector = entryPointSelector(entryPoint, entryPointType, selectorName, argCount)
@@ -41,20 +41,20 @@ internal class LlvmDeclarations(
private val fields: Map<IrField, FieldLlvmDeclarations>, private val fields: Map<IrField, FieldLlvmDeclarations>,
private val staticFields: Map<IrField, StaticFieldLlvmDeclarations>, private val staticFields: Map<IrField, StaticFieldLlvmDeclarations>,
private val unique: Map<UniqueKind, UniqueLlvmDeclarations>) { private val unique: Map<UniqueKind, UniqueLlvmDeclarations>) {
fun forFunction(descriptor: IrFunction) = functions[descriptor] ?: fun forFunction(function: IrFunction) = functions[function] ?:
error("${descriptor.toString()} ${descriptor.name} in ${(descriptor.parent as IrDeclaration).name}") error("${function.descriptor} in ${(function.parent as IrDeclaration).name}")
fun forClass(descriptor: IrClass) = classes[descriptor] ?: fun forClass(irClass: IrClass) = classes[irClass] ?:
error("$descriptor ${descriptor.name}") error(irClass.descriptor.toString())
fun forField(descriptor: IrField) = fields[descriptor] ?: fun forField(field: IrField) = fields[field] ?:
error(descriptor.toString()) error(field.descriptor.toString())
fun forStaticField(descriptor: IrField) = staticFields[descriptor] ?: fun forStaticField(field: IrField) = staticFields[field] ?:
error(descriptor.toString()) error(field.descriptor.toString())
fun forSingleton(descriptor: IrClass) = forClass(descriptor).singletonDeclarations ?: fun forSingleton(irClass: IrClass) = forClass(irClass).singletonDeclarations ?:
error(descriptor.toString()) error(irClass.descriptor.toString())
fun forUnique(kind: UniqueKind) = unique[kind] ?: error("No unique $kind") fun forUnique(kind: UniqueKind) = unique[kind] ?: error("No unique $kind")
@@ -91,19 +91,19 @@ internal class UniqueLlvmDeclarations(val pointer: ConstPointer)
* All fields of the class instance. * All fields of the class instance.
* The order respects the class hierarchy, i.e. a class [fields] contains superclass [fields] as a prefix. * The order respects the class hierarchy, i.e. a class [fields] contains superclass [fields] as a prefix.
*/ */
internal fun ContextUtils.getFields(classDescriptor: IrClass) = context.getFields(classDescriptor) internal fun ContextUtils.getFields(irClass: IrClass) = context.getFields(irClass)
internal fun Context.getFields(classDescriptor: IrClass): List<IrField> { internal fun Context.getFields(irClass: IrClass): List<IrField> {
val superClass = classDescriptor.getSuperClassNotAny() // TODO: what if Any has fields? val superClass = irClass.getSuperClassNotAny() // TODO: what if Any has fields?
val superFields = if (superClass != null) getFields(superClass) else emptyList() val superFields = if (superClass != null) getFields(superClass) else emptyList()
return superFields + getDeclaredFields(classDescriptor) return superFields + getDeclaredFields(irClass)
} }
/** /**
* Fields declared in the class. * Fields declared in the class.
*/ */
private fun Context.getDeclaredFields(classDescriptor: IrClass): List<IrField> { private fun Context.getDeclaredFields(irClass: IrClass): List<IrField> {
// TODO: Here's what is going on here: // TODO: Here's what is going on here:
// The existence of a backing field for a property is only described in the IR, // The existence of a backing field for a property is only described in the IR,
// but not in the PropertyDescriptor. // but not in the PropertyDescriptor.
@@ -114,7 +114,6 @@ private fun Context.getDeclaredFields(classDescriptor: IrClass): List<IrField> {
// In this function we check the presence of the backing field // In this function we check the presence of the backing field
// two ways: first we check IR, then we check the protobuf extension. // two ways: first we check IR, then we check the protobuf extension.
val irClass = classDescriptor
val fields = irClass.declarations.mapNotNull { val fields = irClass.declarations.mapNotNull {
when (it) { when (it) {
is IrField -> it.takeIf { it.isReal } is IrField -> it.takeIf { it.isReal }
@@ -125,7 +124,7 @@ private fun Context.getDeclaredFields(classDescriptor: IrClass): List<IrField> {
// TODO: hack over missed parents in deserialized fields/property declarations. // TODO: hack over missed parents in deserialized fields/property declarations.
fields.forEach{it.parent = irClass} fields.forEach{it.parent = irClass}
if (classDescriptor.hasAnnotation(FqName.fromSegments(listOf("kotlin", "native", "internal", "NoReorderFields")))) if (irClass.hasAnnotation(FqName.fromSegments(listOf("kotlin", "native", "internal", "NoReorderFields"))))
return fields return fields
return fields.sortedBy { return fields.sortedBy {
@@ -157,8 +156,8 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
private val names = mutableMapOf<IrDeclaration, Name>() private val names = mutableMapOf<IrDeclaration, Name>()
private val counts = mutableMapOf<FqName, Int>() private val counts = mutableMapOf<FqName, Int>()
fun getName(parent: FqName, descriptor: IrDeclaration): Name { fun getName(parent: FqName, declaration: IrDeclaration): Name {
return names.getOrPut(descriptor) { return names.getOrPut(declaration) {
val count = counts.getOrDefault(parent, 0) + 1 val count = counts.getOrDefault(parent, 0) + 1
counts[parent] = count counts[parent] = count
Name.identifier(prefix + count) Name.identifier(prefix + count)
@@ -168,34 +167,34 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val objectNamer = Namer("object-") val objectNamer = Namer("object-")
private fun getLocalName(parent: FqName, descriptor: IrDeclaration): Name { private fun getLocalName(parent: FqName, declaration: IrDeclaration): Name {
if (descriptor.isAnonymousObject) { if (declaration.isAnonymousObject) {
return objectNamer.getName(parent, descriptor) return objectNamer.getName(parent, declaration)
} }
return descriptor.name return declaration.name
} }
private fun getFqName(descriptor: IrDeclaration): FqName { private fun getFqName(declaration: IrDeclaration): FqName {
val parent = descriptor.parent val parent = declaration.parent
val parentFqName = when (parent) { val parentFqName = when (parent) {
is IrPackageFragment -> parent.fqName is IrPackageFragment -> parent.fqName
is IrDeclaration -> getFqName(parent) is IrDeclaration -> getFqName(parent)
else -> error(parent) else -> error(parent)
} }
val localName = getLocalName(parentFqName, descriptor) val localName = getLocalName(parentFqName, declaration)
return parentFqName.child(localName) return parentFqName.child(localName)
} }
/** /**
* Produces the name to be used for non-exported LLVM declarations corresponding to [descriptor]. * Produces the name to be used for non-exported LLVM declarations corresponding to [declaration].
* *
* Note: since these declarations are going to be private, the name is only required not to clash with any * Note: since these declarations are going to be private, the name is only required not to clash with any
* exported declarations. * exported declarations.
*/ */
private fun qualifyInternalName(descriptor: IrDeclaration): String { private fun qualifyInternalName(declaration: IrDeclaration): String {
return getFqName(descriptor).asString() + "#internal" return getFqName(declaration).asString() + "#internal"
} }
override fun visitElement(element: IrElement) { override fun visitElement(element: IrElement) {
@@ -209,30 +208,28 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
} }
private fun createClassDeclarations(declaration: IrClass): ClassLlvmDeclarations { private fun createClassDeclarations(declaration: IrClass): ClassLlvmDeclarations {
val descriptor = declaration val internalName = qualifyInternalName(declaration)
val internalName = qualifyInternalName(descriptor) val fields = getFields(declaration)
val fields = getFields(descriptor)
val bodyType = createClassBodyType("kclassbody:$internalName", fields) val bodyType = createClassBodyType("kclassbody:$internalName", fields)
val typeInfoPtr: ConstPointer val typeInfoPtr: ConstPointer
val typeInfoGlobal: StaticData.Global val typeInfoGlobal: StaticData.Global
val typeInfoSymbolName = if (descriptor.isExported()) { val typeInfoSymbolName = if (declaration.isExported()) {
descriptor.typeInfoSymbolName declaration.typeInfoSymbolName
} else { } else {
"ktype:$internalName" "ktype:$internalName"
} }
if (descriptor.typeInfoHasVtableAttached) { if (declaration.typeInfoHasVtableAttached) {
// Create the special global consisting of TypeInfo and vtable. // Create the special global consisting of TypeInfo and vtable.
val typeInfoGlobalName = "ktypeglobal:$internalName" val typeInfoGlobalName = "ktypeglobal:$internalName"
val typeInfoWithVtableType = structType( val typeInfoWithVtableType = structType(
runtime.typeInfoType, runtime.typeInfoType,
LLVMArrayType(int8TypePtr, context.getVtableBuilder(descriptor).vtableEntries.size)!! LLVMArrayType(int8TypePtr, context.getVtableBuilder(declaration).vtableEntries.size)!!
) )
typeInfoGlobal = staticData.createGlobal(typeInfoWithVtableType, typeInfoGlobalName, isExported = false) typeInfoGlobal = staticData.createGlobal(typeInfoWithVtableType, typeInfoGlobalName, isExported = false)
@@ -242,7 +239,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
typeInfoGlobal.pointer.getElementPtr(0).llvm, typeInfoGlobal.pointer.getElementPtr(0).llvm,
typeInfoSymbolName)!! typeInfoSymbolName)!!
if (descriptor.isExported()) { if (declaration.isExported()) {
if (llvmTypeInfoPtr.name != typeInfoSymbolName) { if (llvmTypeInfoPtr.name != typeInfoSymbolName) {
// So alias name has been mangled by LLVM to avoid name clash. // So alias name has been mangled by LLVM to avoid name clash.
throw IllegalArgumentException("Global '$typeInfoSymbolName' already exists") throw IllegalArgumentException("Global '$typeInfoSymbolName' already exists")
@@ -256,22 +253,22 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
} else { } else {
typeInfoGlobal = staticData.createGlobal(runtime.typeInfoType, typeInfoGlobal = staticData.createGlobal(runtime.typeInfoType,
typeInfoSymbolName, typeInfoSymbolName,
isExported = descriptor.isExported()) isExported = declaration.isExported())
typeInfoPtr = typeInfoGlobal.pointer typeInfoPtr = typeInfoGlobal.pointer
} }
if (descriptor.isUnit() || descriptor.isKotlinArray()) if (declaration.isUnit() || declaration.isKotlinArray())
createUniqueDeclarations(descriptor, typeInfoPtr, bodyType) createUniqueDeclarations(declaration, typeInfoPtr, bodyType)
val singletonDeclarations = if (descriptor.kind.isSingleton) { val singletonDeclarations = if (declaration.kind.isSingleton) {
createSingletonDeclarations(descriptor) createSingletonDeclarations(declaration)
} else { } else {
null null
} }
val objCDeclarations = if (descriptor.isKotlinObjCClass()) { val objCDeclarations = if (declaration.isKotlinObjCClass()) {
createKotlinObjCClassDeclarations(descriptor) createKotlinObjCClassDeclarations(declaration)
} else { } else {
null null
} }
@@ -279,8 +276,8 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val writableTypeInfoType = runtime.writableTypeInfoType val writableTypeInfoType = runtime.writableTypeInfoType
val writableTypeInfoGlobal = if (writableTypeInfoType == null) { val writableTypeInfoGlobal = if (writableTypeInfoType == null) {
null null
} else if (descriptor.isExported()) { } else if (declaration.isExported()) {
val name = descriptor.writableTypeInfoSymbolName val name = declaration.writableTypeInfoSymbolName
staticData.createGlobal(writableTypeInfoType, name, isExported = true).also { staticData.createGlobal(writableTypeInfoType, name, isExported = true).also {
it.setLinkage(LLVMLinkage.LLVMCommonLinkage) // Allows to be replaced by other bitcode module. it.setLinkage(LLVMLinkage.LLVMCommonLinkage) // Allows to be replaced by other bitcode module.
} }
@@ -295,35 +292,35 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
} }
private fun createUniqueDeclarations( private fun createUniqueDeclarations(
descriptor: IrClass, typeInfoPtr: ConstPointer, bodyType: LLVMTypeRef) { irClass: IrClass, typeInfoPtr: ConstPointer, bodyType: LLVMTypeRef) {
when { when {
descriptor.isUnit() -> { irClass.isUnit() -> {
uniques[UniqueKind.UNIT] = uniques[UniqueKind.UNIT] =
UniqueLlvmDeclarations(staticData.createUniqueInstance(UniqueKind.UNIT, bodyType, typeInfoPtr)) UniqueLlvmDeclarations(staticData.createUniqueInstance(UniqueKind.UNIT, bodyType, typeInfoPtr))
} }
descriptor.isKotlinArray() -> { irClass.isKotlinArray() -> {
uniques[UniqueKind.EMPTY_ARRAY] = uniques[UniqueKind.EMPTY_ARRAY] =
UniqueLlvmDeclarations(staticData.createUniqueInstance(UniqueKind.EMPTY_ARRAY, bodyType, typeInfoPtr)) UniqueLlvmDeclarations(staticData.createUniqueInstance(UniqueKind.EMPTY_ARRAY, bodyType, typeInfoPtr))
} }
else -> TODO("Unsupported unique $descriptor") else -> TODO("Unsupported unique $irClass")
} }
} }
private fun createSingletonDeclarations(descriptor: IrClass): SingletonLlvmDeclarations? { private fun createSingletonDeclarations(irClass: IrClass): SingletonLlvmDeclarations? {
if (descriptor.isUnit()) { if (irClass.isUnit()) {
return null return null
} }
val isExported = descriptor.isExported() val isExported = irClass.isExported()
val symbolName = if (isExported) { val symbolName = if (isExported) {
descriptor.objectInstanceFieldSymbolName irClass.objectInstanceFieldSymbolName
} else { } else {
"kobjref:" + qualifyInternalName(descriptor) "kobjref:" + qualifyInternalName(irClass)
} }
val threadLocal = !(descriptor.objectIsShared && context.config.threadsAreAllowed) val threadLocal = !(irClass.objectIsShared && context.config.threadsAreAllowed)
val instanceFieldRef = addGlobal( val instanceFieldRef = addGlobal(
symbolName, getLLVMType(descriptor.defaultType), isExported = isExported, threadLocal = threadLocal) symbolName, getLLVMType(irClass.defaultType), isExported = isExported, threadLocal = threadLocal)
LLVMSetInitializer(instanceFieldRef, kNullObjHeaderPtr) LLVMSetInitializer(instanceFieldRef, kNullObjHeaderPtr)
@@ -331,11 +328,11 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
if (threadLocal) null if (threadLocal) null
else { else {
val shadowSymbolName = if (isExported) { val shadowSymbolName = if (isExported) {
descriptor.objectInstanceShadowFieldSymbolName irClass.objectInstanceShadowFieldSymbolName
} else { } else {
"kshadowobjref:" + qualifyInternalName(descriptor) "kshadowobjref:" + qualifyInternalName(irClass)
} }
addGlobal(shadowSymbolName, getLLVMType(descriptor.defaultType), isExported = isExported, threadLocal = true) addGlobal(shadowSymbolName, getLLVMType(irClass.defaultType), isExported = isExported, threadLocal = true)
} }
instanceShadowFieldRef?.let { LLVMSetInitializer(it, kNullObjHeaderPtr) } instanceShadowFieldRef?.let { LLVMSetInitializer(it, kNullObjHeaderPtr) }
@@ -343,8 +340,8 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
return SingletonLlvmDeclarations(instanceFieldRef, instanceShadowFieldRef) return SingletonLlvmDeclarations(instanceFieldRef, instanceShadowFieldRef)
} }
private fun createKotlinObjCClassDeclarations(descriptor: IrClass): KotlinObjCClassLlvmDeclarations { private fun createKotlinObjCClassDeclarations(irClass: IrClass): KotlinObjCClassLlvmDeclarations {
val internalName = qualifyInternalName(descriptor) val internalName = qualifyInternalName(irClass)
val classPointerGlobal = staticData.createGlobal(int8TypePtr, "kobjcclassptr:$internalName") val classPointerGlobal = staticData.createGlobal(int8TypePtr, "kobjcclassptr:$internalName")
@@ -363,25 +360,23 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
override fun visitField(declaration: IrField) { override fun visitField(declaration: IrField) {
super.visitField(declaration) super.visitField(declaration)
val descriptor = declaration val containingClass = declaration.parent as? IrClass
val containingClass = descriptor.containingClass
if (containingClass != null) { if (containingClass != null) {
val classDeclarations = this.classes[containingClass] ?: val classDeclarations = this.classes[containingClass] ?:
error(containingClass.descriptor.toString()) error(containingClass.descriptor.toString())
val allFields = classDeclarations.fields val allFields = classDeclarations.fields
this.fields[descriptor] = FieldLlvmDeclarations( this.fields[declaration] = FieldLlvmDeclarations(
allFields.indexOf(descriptor) + 1, // First field is ObjHeader. allFields.indexOf(declaration) + 1, // First field is ObjHeader.
classDeclarations.bodyType classDeclarations.bodyType
) )
} else { } else {
// Fields are module-private, so we use internal name: // Fields are module-private, so we use internal name:
val name = "kvar:" + qualifyInternalName(descriptor) val name = "kvar:" + qualifyInternalName(declaration)
val storage = addGlobal( val storage = addGlobal(
name, getLLVMType(descriptor.type), isExported = false, name, getLLVMType(declaration.type), isExported = false,
threadLocal = declaration.storageClass == FieldStorage.THREAD_LOCAL) threadLocal = declaration.storageClass == FieldStorage.THREAD_LOCAL)
this.staticFields[descriptor] = StaticFieldLlvmDeclarations(storage) this.staticFields[declaration] = StaticFieldLlvmDeclarations(storage)
} }
} }
@@ -390,25 +385,24 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
if (!declaration.isReal) return if (!declaration.isReal) return
val descriptor = declaration val llvmFunctionType = getLlvmFunctionType(declaration)
val llvmFunctionType = getLlvmFunctionType(descriptor)
if ((descriptor is IrConstructor && descriptor.isObjCConstructor)) { if ((declaration is IrConstructor && declaration.isObjCConstructor)) {
return return
} }
val llvmFunction = if (descriptor.isExternal) { val llvmFunction = if (declaration.isExternal) {
if (descriptor.isTypedIntrinsic || descriptor.isObjCBridgeBased() if (declaration.isTypedIntrinsic || declaration.isObjCBridgeBased()
|| descriptor.annotations.hasAnnotation(RuntimeNames.cCall)) return || declaration.annotations.hasAnnotation(RuntimeNames.cCall)) return
context.llvm.externalFunction(descriptor.symbolName, llvmFunctionType, context.llvm.externalFunction(declaration.symbolName, llvmFunctionType,
// Assume that `external fun` is defined in native libs attached to this module: // Assume that `external fun` is defined in native libs attached to this module:
origin = descriptor.llvmSymbolOrigin origin = declaration.llvmSymbolOrigin
) )
} else { } else {
val symbolName = if (descriptor.isExported()) { val symbolName = if (declaration.isExported()) {
descriptor.symbolName.also { declaration.symbolName.also {
if (descriptor.name.asString() != "main") { if (declaration.name.asString() != "main") {
assert(LLVMGetNamedFunction(context.llvm.llvmModule, it) == null) { it } assert(LLVMGetNamedFunction(context.llvm.llvmModule, it) == null) { it }
} else { } else {
// As a workaround, allow `main` functions to clash because frontend accepts this. // As a workaround, allow `main` functions to clash because frontend accepts this.
@@ -416,10 +410,10 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
} }
} }
} else { } else {
"kfun:" + qualifyInternalName(descriptor) "kfun:" + qualifyInternalName(declaration)
} }
val function = LLVMAddFunction(context.llvmModule, symbolName, llvmFunctionType)!! val function = LLVMAddFunction(context.llvmModule, symbolName, llvmFunctionType)!!
if (descriptor.returnType.isNothing()) if (declaration.returnType.isNothing())
setFunctionNoReturn(function) setFunctionNoReturn(function)
function function
} }
@@ -429,6 +423,6 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
LLVMAddTargetDependentFunctionAttr(llvmFunction, "no-frame-pointer-elim", "true") LLVMAddTargetDependentFunctionAttr(llvmFunction, "no-frame-pointer-elim", "true")
} }
this.functions[descriptor] = FunctionLlvmDeclarations(llvmFunction) this.functions[declaration] = FunctionLlvmDeclarations(llvmFunction)
} }
} }
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.backend.konan.llvm package org.jetbrains.kotlin.backend.konan.llvm
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.computePrimitiveBinaryTypeOrNull import org.jetbrains.kotlin.backend.konan.computePrimitiveBinaryTypeOrNull
import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.descriptors.*
@@ -46,24 +45,24 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
} }
} }
private fun checkAcyclicClass(classDescriptor: IrClass): Boolean = when { private fun checkAcyclicClass(irClass: IrClass): Boolean = when {
classDescriptor.symbol == context.ir.symbols.array -> false irClass.symbol == context.ir.symbols.array -> false
classDescriptor.isArray -> true irClass.isArray -> true
context.llvmDeclarations.forClass(classDescriptor).fields.all { checkAcyclicFieldType(it.type) } -> true context.llvmDeclarations.forClass(irClass).fields.all { checkAcyclicFieldType(it.type) } -> true
else -> false else -> false
} }
private fun flagsFromClass(classDescriptor: IrClass): Int { private fun flagsFromClass(irClass: IrClass): Int {
var result = 0 var result = 0
if (classDescriptor.isFrozen) if (irClass.isFrozen)
result = result or TF_IMMUTABLE result = result or TF_IMMUTABLE
// TODO: maybe perform deeper analysis to find surely acyclic types. // TODO: maybe perform deeper analysis to find surely acyclic types.
if (!classDescriptor.isInterface && !classDescriptor.isAbstract() && !classDescriptor.isAnnotationClass) { if (!irClass.isInterface && !irClass.isAbstract() && !irClass.isAnnotationClass) {
if (checkAcyclicClass(classDescriptor)) { if (checkAcyclicClass(irClass)) {
result = result or TF_ACYCLIC result = result or TF_ACYCLIC
} }
} }
if (classDescriptor.isInterface) if (irClass.isInterface)
result = result or TF_INTERFACE result = result or TF_INTERFACE
return result return result
} }
@@ -125,10 +124,10 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
private val EXPORT_TYPE_INFO_FQ_NAME = FqName.fromSegments(listOf("kotlin", "native", "internal", "ExportTypeInfo")) private val EXPORT_TYPE_INFO_FQ_NAME = FqName.fromSegments(listOf("kotlin", "native", "internal", "ExportTypeInfo"))
private fun exportTypeInfoIfRequired(classDesc: IrClass, typeInfoGlobal: LLVMValueRef?) { private fun exportTypeInfoIfRequired(irClass: IrClass, typeInfoGlobal: LLVMValueRef?) {
val annot = classDesc.descriptor.annotations.findAnnotation(EXPORT_TYPE_INFO_FQ_NAME) val annotation = irClass.descriptor.annotations.findAnnotation(EXPORT_TYPE_INFO_FQ_NAME)
if (annot != null) { if (annotation != null) {
val name = getAnnotationValue(annot)!! val name = getAnnotationValue(annotation)!!
// TODO: use LLVMAddAlias. // TODO: use LLVMAddAlias.
val global = addGlobal(name, pointerType(runtime.typeInfoType), isExported = true) val global = addGlobal(name, pointerType(runtime.typeInfoType), isExported = true)
LLVMSetInitializer(global, typeInfoGlobal) LLVMSetInitializer(global, typeInfoGlobal)
@@ -170,21 +169,21 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
return LLVMStoreSizeOfType(llvmTargetData, classType).toInt() return LLVMStoreSizeOfType(llvmTargetData, classType).toInt()
} }
fun generate(classDesc: IrClass) { fun generate(irClass: IrClass) {
val className = classDesc.fqNameSafe val className = irClass.fqNameSafe
val llvmDeclarations = context.llvmDeclarations.forClass(classDesc) val llvmDeclarations = context.llvmDeclarations.forClass(irClass)
val bodyType = llvmDeclarations.bodyType val bodyType = llvmDeclarations.bodyType
val size = getInstanceSize(bodyType, className) val size = getInstanceSize(bodyType, className)
val superTypeOrAny = classDesc.getSuperClassNotAny() ?: context.ir.symbols.any.owner val superTypeOrAny = irClass.getSuperClassNotAny() ?: context.ir.symbols.any.owner
val superType = if (classDesc.isAny()) NullPointer(runtime.typeInfoType) val superType = if (irClass.isAny()) NullPointer(runtime.typeInfoType)
else superTypeOrAny.typeInfoPtr else superTypeOrAny.typeInfoPtr
val interfaces = classDesc.implementedInterfaces.map { it.typeInfoPtr } val interfaces = irClass.implementedInterfaces.map { it.typeInfoPtr }
val interfacesPtr = staticData.placeGlobalConstArray("kintf:$className", val interfacesPtr = staticData.placeGlobalConstArray("kintf:$className",
pointerType(runtime.typeInfoType), interfaces) pointerType(runtime.typeInfoType), interfaces)
@@ -199,26 +198,26 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
val objOffsetsPtr = staticData.placeGlobalConstArray("krefs:$className", int32Type, val objOffsetsPtr = staticData.placeGlobalConstArray("krefs:$className", int32Type,
objOffsets.map { Int32(it.toInt()) }) objOffsets.map { Int32(it.toInt()) })
val objOffsetsCount = if (classDesc.descriptor == context.builtIns.array) { val objOffsetsCount = if (irClass.descriptor == context.builtIns.array) {
1 // To mark it as non-leaf. 1 // To mark it as non-leaf.
} else { } else {
objOffsets.size objOffsets.size
} }
val methods = if (classDesc.isAbstract()) { val methods = if (irClass.isAbstract()) {
emptyList() emptyList()
} else { } else {
methodTableRecords(classDesc) methodTableRecords(irClass)
} }
val methodsPtr = staticData.placeGlobalConstArray("kmethods:$className", val methodsPtr = staticData.placeGlobalConstArray("kmethods:$className",
runtime.methodTableRecordType, methods) runtime.methodTableRecordType, methods)
val reflectionInfo = getReflectionInfo(classDesc) val reflectionInfo = getReflectionInfo(irClass)
val typeInfoGlobal = llvmDeclarations.typeInfoGlobal val typeInfoGlobal = llvmDeclarations.typeInfoGlobal
val typeInfo = TypeInfo( val typeInfo = TypeInfo(
classDesc.typeInfoPtr, irClass.typeInfoPtr,
makeExtendedInfo(classDesc), makeExtendedInfo(irClass),
size, size,
superType, superType,
objOffsetsPtr, objOffsetsCount, objOffsetsPtr, objOffsetsCount,
@@ -226,26 +225,26 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
methodsPtr, methods.size, methodsPtr, methods.size,
reflectionInfo.packageName, reflectionInfo.packageName,
reflectionInfo.relativeName, reflectionInfo.relativeName,
flagsFromClass(classDesc), flagsFromClass(irClass),
llvmDeclarations.writableTypeInfoGlobal?.pointer llvmDeclarations.writableTypeInfoGlobal?.pointer
) )
val typeInfoGlobalValue = if (!classDesc.typeInfoHasVtableAttached) { val typeInfoGlobalValue = if (!irClass.typeInfoHasVtableAttached) {
typeInfo typeInfo
} else { } else {
val vtable = vtable(classDesc) val vtable = vtable(irClass)
Struct(typeInfo, vtable) Struct(typeInfo, vtable)
} }
typeInfoGlobal.setInitializer(typeInfoGlobalValue) typeInfoGlobal.setInitializer(typeInfoGlobalValue)
typeInfoGlobal.setConstant(true) typeInfoGlobal.setConstant(true)
exportTypeInfoIfRequired(classDesc, classDesc.llvmTypeInfoPtr) exportTypeInfoIfRequired(irClass, irClass.llvmTypeInfoPtr)
} }
fun vtable(classDesc: IrClass): ConstArray { fun vtable(irClass: IrClass): ConstArray {
// TODO: compile-time resolution limits binary compatibility // TODO: compile-time resolution limits binary compatibility
val vtableEntries = context.getVtableBuilder(classDesc).vtableEntries.map { val vtableEntries = context.getVtableBuilder(irClass).vtableEntries.map {
val implementation = it.implementation val implementation = it.implementation
if (implementation == null || implementation.isExternalObjCClassMethod()) { if (implementation == null || implementation.isExternalObjCClassMethod()) {
NullPointer(int8Type) NullPointer(int8Type)
@@ -256,10 +255,10 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
return ConstArray(int8TypePtr, vtableEntries) return ConstArray(int8TypePtr, vtableEntries)
} }
fun methodTableRecords(classDesc: IrClass): List<MethodTableRecord> { fun methodTableRecords(irClass: IrClass): List<MethodTableRecord> {
val functionNames = mutableMapOf<Long, OverriddenFunctionDescriptor>() val functionNames = mutableMapOf<Long, OverriddenFunctionInfo>()
return context.getVtableBuilder(classDesc).methodTableEntries.map { return context.getVtableBuilder(irClass).methodTableEntries.map {
val functionName = it.overriddenDescriptor.functionName val functionName = it.overriddenFunction.functionName
val nameSignature = functionName.localHash val nameSignature = functionName.localHash
val previous = functionNames.putIfAbsent(nameSignature.value, it) val previous = functionNames.putIfAbsent(nameSignature.value, it)
if (previous != null) if (previous != null)
@@ -275,13 +274,13 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
private fun mapRuntimeType(type: LLVMTypeRef): Int = private fun mapRuntimeType(type: LLVMTypeRef): Int =
runtimeTypeMap[type] ?: throw Error("Unmapped type: ${llvmtype2string(type)}") runtimeTypeMap[type] ?: throw Error("Unmapped type: ${llvmtype2string(type)}")
private fun makeExtendedInfo(descriptor: IrClass): ConstPointer { private fun makeExtendedInfo(irClass: IrClass): ConstPointer {
// TODO: shall we actually do that? // TODO: shall we actually do that?
if (context.shouldOptimize()) if (context.shouldOptimize())
return NullPointer(runtime.extendedTypeInfoType) return NullPointer(runtime.extendedTypeInfoType)
val className = descriptor.fqNameSafe.toString() val className = irClass.fqNameSafe.toString()
val llvmDeclarations = context.llvmDeclarations.forClass(descriptor) val llvmDeclarations = context.llvmDeclarations.forClass(irClass)
val bodyType = llvmDeclarations.bodyType val bodyType = llvmDeclarations.bodyType
val elementType = arrayClasses[className] val elementType = arrayClasses[className]
val value = if (elementType != null) { val value = if (elementType != null) {
@@ -313,18 +312,18 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
// TODO: extract more code common with generate(). // TODO: extract more code common with generate().
fun generateSyntheticInterfaceImpl( fun generateSyntheticInterfaceImpl(
descriptor: IrClass, irClass: IrClass,
methodImpls: Map<IrFunction, ConstPointer>, methodImpls: Map<IrFunction, ConstPointer>,
immutable: Boolean = false immutable: Boolean = false
): ConstPointer { ): ConstPointer {
assert(descriptor.isInterface) assert(irClass.isInterface)
val size = LLVMStoreSizeOfType(llvmTargetData, kObjHeader).toInt() val size = LLVMStoreSizeOfType(llvmTargetData, kObjHeader).toInt()
val superClass = context.ir.symbols.any.owner val superClass = context.ir.symbols.any.owner
assert(superClass.implementedInterfaces.isEmpty()) assert(superClass.implementedInterfaces.isEmpty())
val interfaces = listOf(descriptor.typeInfoPtr) val interfaces = listOf(irClass.typeInfoPtr)
val interfacesPtr = staticData.placeGlobalConstArray("", val interfacesPtr = staticData.placeGlobalConstArray("",
pointerType(runtime.typeInfoType), interfaces) pointerType(runtime.typeInfoType), interfaces)
@@ -333,7 +332,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
val objOffsetsCount = 0 val objOffsetsCount = 0
val methods = (methodTableRecords(superClass) + methodImpls.map { (method, impl) -> val methods = (methodTableRecords(superClass) + methodImpls.map { (method, impl) ->
assert(method.containingDeclaration == descriptor) assert(method.parent == irClass)
MethodTableRecord(method.functionName.localHash, impl.bitcast(int8TypePtr)) MethodTableRecord(method.functionName.localHash, impl.bitcast(int8TypePtr))
}).sortedBy { it.nameSignature.value }.also { }).sortedBy { it.nameSignature.value }.also {
assert(it.distinctBy { it.nameSignature.value } == it) assert(it.distinctBy { it.nameSignature.value } == it)
@@ -365,7 +364,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
methods = methodsPtr, methodsCount = methods.size, methods = methodsPtr, methodsCount = methods.size,
packageName = reflectionInfo.packageName, packageName = reflectionInfo.packageName,
relativeName = reflectionInfo.relativeName, relativeName = reflectionInfo.relativeName,
flags = flagsFromClass(descriptor) or (if (immutable) TF_IMMUTABLE else 0), flags = flagsFromClass(irClass) or (if (immutable) TF_IMMUTABLE else 0),
writableTypeInfo = writableTypeInfo writableTypeInfo = writableTypeInfo
), vtable) ), vtable)
@@ -375,23 +374,21 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
return result return result
} }
private val OverriddenFunctionDescriptor.implementation get() = getImplementation(context) private val OverriddenFunctionInfo.implementation get() = getImplementation(context)
data class ReflectionInfo(val packageName: String?, val relativeName: String?) data class ReflectionInfo(val packageName: String?, val relativeName: String?)
private fun getReflectionInfo(descriptor: IrClass): ReflectionInfo { private fun getReflectionInfo(irClass: IrClass): ReflectionInfo = when {
return if (descriptor.isAnonymousObject) { irClass.isAnonymousObject -> ReflectionInfo(packageName = null, relativeName = null)
ReflectionInfo(packageName = null, relativeName = null)
} else if (descriptor.isLocal) { irClass.isLocal -> ReflectionInfo(packageName = null, relativeName = irClass.name.asString())
ReflectionInfo(packageName = null, relativeName = descriptor.name.asString())
} else { else -> ReflectionInfo(
ReflectionInfo( packageName = irClass.findPackage().fqName.asString(),
packageName = descriptor.findPackage().fqName.asString(), relativeName = generateSequence(irClass) { it.parent as? IrClass }
relativeName = generateSequence(descriptor, { it.parent as? IrClass }) .toList().reversed()
.toList().reversed() .joinToString(".") { it.name.asString() }
.joinToString(".") { it.name.asString() } )
)
}
} }
} }
@@ -8,14 +8,12 @@ package org.jetbrains.kotlin.backend.konan.llvm
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.common.ir.ir2string import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrValueDeclaration import org.jetbrains.kotlin.ir.declarations.IrValueDeclaration
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
internal fun IrElement.needDebugInfo(context: Context) = context.shouldContainDebugInfo() || (this is IrVariable && this.descriptor.isVar) internal fun IrElement.needDebugInfo(context: Context) = context.shouldContainDebugInfo() || (this is IrVariable && this.isVar)
internal class VariableManager(val functionGenerationContext: FunctionGenerationContext) { internal class VariableManager(val functionGenerationContext: FunctionGenerationContext) {
internal interface Record { internal interface Record {
@@ -54,41 +52,41 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
contextVariablesToIndex.clear() contextVariablesToIndex.clear()
} }
fun createVariable(descriptor: IrValueDeclaration, value: LLVMValueRef? = null, variableLocation: VariableDebugLocation?) : Int { fun createVariable(valueDeclaration: IrValueDeclaration, value: LLVMValueRef? = null, variableLocation: VariableDebugLocation?) : Int {
val isVar = descriptor is IrVariable && descriptor.isVar val isVar = valueDeclaration is IrVariable && valueDeclaration.isVar
// Note that we always create slot for object references for memory management. // Note that we always create slot for object references for memory management.
if (!functionGenerationContext.context.shouldContainDebugInfo() && !isVar && value != null) if (!functionGenerationContext.context.shouldContainDebugInfo() && !isVar && value != null)
return createImmutable(descriptor, value) return createImmutable(valueDeclaration, value)
else else
// Unfortunately, we have to create mutable slots here, // Unfortunately, we have to create mutable slots here,
// as even vals can be assigned on multiple paths. However, we use varness // as even vals can be assigned on multiple paths. However, we use varness
// knowledge, as anonymous slots are created only for true vars (for vals // knowledge, as anonymous slots are created only for true vars (for vals
// their single assigner already have slot). // their single assigner already have slot).
return createMutable(descriptor, isVar, value, variableLocation) return createMutable(valueDeclaration, isVar, value, variableLocation)
} }
internal fun createMutable(descriptor: IrValueDeclaration, internal fun createMutable(valueDeclaration: IrValueDeclaration,
isVar: Boolean, value: LLVMValueRef? = null, variableLocation: VariableDebugLocation?) : Int { isVar: Boolean, value: LLVMValueRef? = null, variableLocation: VariableDebugLocation?) : Int {
assert(!contextVariablesToIndex.contains(descriptor)) assert(!contextVariablesToIndex.contains(valueDeclaration))
val index = variables.size val index = variables.size
val type = functionGenerationContext.getLLVMType(descriptor.type) val type = functionGenerationContext.getLLVMType(valueDeclaration.type)
val slot = functionGenerationContext.alloca(type, descriptor.name.asString(), variableLocation) val slot = functionGenerationContext.alloca(type, valueDeclaration.name.asString(), variableLocation)
if (value != null) if (value != null)
functionGenerationContext.storeAny(value, slot) functionGenerationContext.storeAny(value, slot)
variables.add(SlotRecord(slot, functionGenerationContext.isObjectType(type), isVar)) variables.add(SlotRecord(slot, functionGenerationContext.isObjectType(type), isVar))
contextVariablesToIndex[descriptor] = index contextVariablesToIndex[valueDeclaration] = index
return index return index
} }
internal var skip = 0 internal var skip = 0
internal fun createParameter(descriptor: IrValueDeclaration, variableLocation: VariableDebugLocation?) : Int { internal fun createParameter(valueDeclaration: IrValueDeclaration, variableLocation: VariableDebugLocation?) : Int {
assert(!contextVariablesToIndex.contains(descriptor)) assert(!contextVariablesToIndex.contains(valueDeclaration))
val index = variables.size val index = variables.size
val type = functionGenerationContext.getLLVMType(descriptor.type) val type = functionGenerationContext.getLLVMType(valueDeclaration.type)
val slot = functionGenerationContext.alloca(type, "p-${descriptor.name.asString()}", variableLocation) val slot = functionGenerationContext.alloca(type, "p-${valueDeclaration.name.asString()}", variableLocation)
val isObject = functionGenerationContext.isObjectType(type) val isObject = functionGenerationContext.isObjectType(type)
variables.add(ParameterRecord(slot, isObject)) variables.add(ParameterRecord(slot, isObject))
contextVariablesToIndex[descriptor] = index contextVariablesToIndex[valueDeclaration] = index
if (isObject) if (isObject)
skip++ skip++
return index return index
@@ -110,17 +108,17 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
return index return index
} }
internal fun createImmutable(descriptor: IrValueDeclaration, value: LLVMValueRef) : Int { internal fun createImmutable(valueDeclaration: IrValueDeclaration, value: LLVMValueRef) : Int {
if (contextVariablesToIndex.containsKey(descriptor)) if (contextVariablesToIndex.containsKey(valueDeclaration))
throw Error("${ir2string(descriptor)} is already defined") throw Error("${ir2string(valueDeclaration)} is already defined")
val index = variables.size val index = variables.size
variables.add(ValueRecord(value, descriptor.name)) variables.add(ValueRecord(value, valueDeclaration.name))
contextVariablesToIndex[descriptor] = index contextVariablesToIndex[valueDeclaration] = index
return index return index
} }
fun indexOf(descriptor: IrValueDeclaration) : Int { fun indexOf(valueDeclaration: IrValueDeclaration) : Int {
return contextVariablesToIndex.getOrElse(descriptor) { -1 } return contextVariablesToIndex.getOrElse(valueDeclaration) { -1 }
} }
fun addressOf(index: Int): LLVMValueRef { fun addressOf(index: Int): LLVMValueRef {
@@ -1010,7 +1010,7 @@ private fun ObjCExportCodeGenerator.createDirectAdapters(
val implementation = if (this.modality == Modality.ABSTRACT) { val implementation = if (this.modality == Modality.ABSTRACT) {
null null
} else { } else {
OverriddenFunctionDescriptor( OverriddenFunctionInfo(
context.ir.get(this) as IrSimpleFunction, context.ir.get(this) as IrSimpleFunction,
context.ir.get(base) as IrSimpleFunction context.ir.get(base) as IrSimpleFunction
).getImplementation(context) ).getImplementation(context)
@@ -102,13 +102,13 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
).apply { it.bind(this) } ).apply { it.bind(this) }
} }
} }
val overriddenJobDescriptor = OverriddenFunctionDescriptor(jobFunction, runtimeJobFunction) val overriddenJobDescriptor = OverriddenFunctionInfo(jobFunction, runtimeJobFunction)
if (!overriddenJobDescriptor.needBridge) return expression if (!overriddenJobDescriptor.needBridge) return expression
val bridge = context.buildBridge( val bridge = context.buildBridge(
startOffset = job.startOffset, startOffset = job.startOffset,
endOffset = job.endOffset, endOffset = job.endOffset,
descriptor = overriddenJobDescriptor, overriddenFunction = overriddenJobDescriptor,
targetSymbol = job.symbol) targetSymbol = job.symbol)
bridges += bridge bridges += bridge
expression.putValueArgument(3, IrFunctionReferenceImpl( expression.putValueArgument(3, IrFunctionReferenceImpl(
@@ -133,15 +133,15 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
irClass.simpleFunctions() irClass.simpleFunctions()
.forEach { function -> .forEach { function ->
function.allOverriddenDescriptors function.allOverriddenFunctions
.map { OverriddenFunctionDescriptor(function, it) } .map { OverriddenFunctionInfo(function, it) }
.filter { !it.bridgeDirections.allNotNeeded() } .filter { !it.bridgeDirections.allNotNeeded() }
.filter { it.canBeCalledVirtually } .filter { it.canBeCalledVirtually }
.filter { !it.inheritsBridge } .filter { !it.inheritsBridge }
.distinctBy { it.bridgeDirections } .distinctBy { it.bridgeDirections }
.forEach { .forEach {
buildBridge(it, irClass) buildBridge(it, irClass)
builtBridges += it.descriptor builtBridges += it.function
} }
} }
irClass.transformChildrenVoid(object: IrElementTransformerVoid() { irClass.transformChildrenVoid(object: IrElementTransformerVoid() {
@@ -165,12 +165,12 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
}) })
} }
private fun buildBridge(descriptor: OverriddenFunctionDescriptor, irClass: IrClass) { private fun buildBridge(overriddenFunction: OverriddenFunctionInfo, irClass: IrClass) {
irClass.declarations.add(context.buildBridge( irClass.declarations.add(context.buildBridge(
startOffset = irClass.startOffset, startOffset = irClass.startOffset,
endOffset = irClass.endOffset, endOffset = irClass.endOffset,
descriptor = descriptor, overriddenFunction = overriddenFunction,
targetSymbol = descriptor.descriptor.symbol, targetSymbol = overriddenFunction.function.symbol,
superQualifierSymbol = irClass.symbol) superQualifierSymbol = irClass.symbol)
) )
} }
@@ -217,10 +217,10 @@ private fun IrBlockBodyBuilder.buildTypeSafeBarrier(function: IrFunction,
} }
private fun Context.buildBridge(startOffset: Int, endOffset: Int, private fun Context.buildBridge(startOffset: Int, endOffset: Int,
descriptor: OverriddenFunctionDescriptor, targetSymbol: IrFunctionSymbol, overriddenFunction: OverriddenFunctionInfo, targetSymbol: IrFunctionSymbol,
superQualifierSymbol: IrClassSymbol? = null): IrFunction { superQualifierSymbol: IrClassSymbol? = null): IrFunction {
val bridge = specialDeclarationsFactory.getBridge(descriptor) val bridge = specialDeclarationsFactory.getBridge(overriddenFunction)
if (bridge.modality == Modality.ABSTRACT) { if (bridge.modality == Modality.ABSTRACT) {
return bridge return bridge
@@ -228,8 +228,8 @@ private fun Context.buildBridge(startOffset: Int, endOffset: Int,
val irBuilder = createIrBuilder(bridge.symbol, startOffset, endOffset) val irBuilder = createIrBuilder(bridge.symbol, startOffset, endOffset)
bridge.body = irBuilder.irBlockBody(bridge) { bridge.body = irBuilder.irBlockBody(bridge) {
val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor.overriddenDescriptor.descriptor) val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(overriddenFunction.overriddenFunction.descriptor)
typeSafeBarrierDescription?.let { buildTypeSafeBarrier(bridge, descriptor.descriptor, it) } typeSafeBarrierDescription?.let { buildTypeSafeBarrier(bridge, overriddenFunction.function, it) }
val delegatingCall = IrCallImpl( val delegatingCall = IrCallImpl(
startOffset, startOffset,
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.backend.konan.cgen.KotlinStubs
import org.jetbrains.kotlin.backend.konan.cgen.generateCCall import org.jetbrains.kotlin.backend.konan.cgen.generateCCall
import org.jetbrains.kotlin.backend.konan.cgen.generateCFunctionPointer import org.jetbrains.kotlin.backend.konan.cgen.generateCFunctionPointer
import org.jetbrains.kotlin.backend.konan.getInlinedClass import org.jetbrains.kotlin.backend.konan.getInlinedClass
import org.jetbrains.kotlin.backend.konan.descriptors.allOverriddenDescriptors import org.jetbrains.kotlin.backend.konan.descriptors.allOverriddenFunctions
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.irasdescriptors.* import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
@@ -478,7 +478,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
context.ir.symbols.any.owner.declarations.filterIsInstance<IrSimpleFunction>().toSet() context.ir.symbols.any.owner.declarations.filterIsInstance<IrSimpleFunction>().toSet()
irClass.declarations.filterIsInstance<IrSimpleFunction>().filter { it.isReal }.forEach { method -> irClass.declarations.filterIsInstance<IrSimpleFunction>().filter { it.isReal }.forEach { method ->
val overriddenMethodOfAny = method.allOverriddenDescriptors.firstOrNull { val overriddenMethodOfAny = method.allOverriddenFunctions.firstOrNull {
it in methodsOfAny it in methodsOfAny
} }
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.backend.common.peek
import org.jetbrains.kotlin.backend.common.pop import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.allOverriddenDescriptors import org.jetbrains.kotlin.backend.konan.descriptors.allOverriddenFunctions
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.descriptors.target import org.jetbrains.kotlin.backend.konan.descriptors.target
import org.jetbrains.kotlin.backend.konan.irasdescriptors.* import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.simpleFunctions import org.jetbrains.kotlin.ir.util.simpleFunctions
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -34,7 +35,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
private fun IrClass.getOverridingOf(function: IrFunction) = (function as? IrSimpleFunction)?.let { private fun IrClass.getOverridingOf(function: IrFunction) = (function as? IrSimpleFunction)?.let {
it.allOverriddenDescriptors.atMostOne { it.parent == this } it.allOverriddenFunctions.atMostOne { it.parent == this }
} }
private fun IrTypeOperator.isCast() = private fun IrTypeOperator.isCast() =
@@ -78,9 +79,9 @@ private class VariableValues {
if (element !is IrGetValue) if (element !is IrGetValue)
result += element result += element
else { else {
val descriptor = element.symbol.owner val declaration = element.symbol.owner
if (descriptor is IrVariable && !seen.contains(descriptor)) if (declaration is IrVariable && !seen.contains(declaration))
dfs(descriptor, seen, result) dfs(declaration, seen, result)
} }
} }
} }
@@ -230,7 +231,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
} }
} }
private fun analyze(descriptor: IrDeclaration, body: IrElement?) { private fun analyze(declaration: IrDeclaration, body: IrElement?) {
// Find all interesting expressions, variables and functions. // Find all interesting expressions, variables and functions.
val visitor = ElementFinderVisitor() val visitor = ElementFinderVisitor()
body?.acceptVoid(visitor) body?.acceptVoid(visitor)
@@ -262,7 +263,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
} }
val function = FunctionDFGBuilder(expressionValuesExtractor, visitor.variableValues, val function = FunctionDFGBuilder(expressionValuesExtractor, visitor.variableValues,
descriptor, visitor.expressions, visitor.returnValues, visitor.thrownValues, visitor.catchParameters).build() declaration, visitor.expressions, visitor.returnValues, visitor.thrownValues, visitor.catchParameters).build()
DEBUG_OUTPUT(0) { DEBUG_OUTPUT(0) {
function.debugOutput() function.debugOutput()
@@ -274,8 +275,8 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
DEBUG_OUTPUT(1) { DEBUG_OUTPUT(1) {
println("SYMBOL TABLE:") println("SYMBOL TABLE:")
symbolTable.classMap.forEach { descriptor, type -> symbolTable.classMap.forEach { irClass, type ->
println(" DESCRIPTOR: $descriptor") println(" DESCRIPTOR: ${irClass.descriptor}")
println(" TYPE: $type") println(" TYPE: $type")
if (type !is DataFlowIR.Type.Declared) if (type !is DataFlowIR.Type.Declared)
return@forEach return@forEach
@@ -326,13 +327,13 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
// Producer and job of executeImpl are called externally, we need to reflect this somehow. // Producer and job of executeImpl are called externally, we need to reflect this somehow.
val producerInvocation = IrCallImpl(expression.startOffset, expression.endOffset, val producerInvocation = IrCallImpl(expression.startOffset, expression.endOffset,
executeImplProducerInvoke.returnType, executeImplProducerInvoke.returnType,
executeImplProducerInvoke.symbol, executeImplProducerInvoke.descriptor) executeImplProducerInvoke.symbol)
producerInvocation.dispatchReceiver = expression.getValueArgument(2) producerInvocation.dispatchReceiver = expression.getValueArgument(2)
val jobFunctionReference = expression.getValueArgument(3) as? IrFunctionReference val jobFunctionReference = expression.getValueArgument(3) as? IrFunctionReference
?: error("A function reference expected") ?: error("A function reference expected")
val jobInvocation = IrCallImpl(expression.startOffset, expression.endOffset, val jobInvocation = IrCallImpl(expression.startOffset, expression.endOffset,
jobFunctionReference.symbol.owner.returnType, jobFunctionReference.symbol.owner.returnType,
jobFunctionReference.symbol, jobFunctionReference.descriptor) jobFunctionReference.symbol)
jobInvocation.putValueArgument(0, producerInvocation) jobInvocation.putValueArgument(0, producerInvocation)
expressions += jobInvocation expressions += jobInvocation
@@ -410,27 +411,27 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
private inner class FunctionDFGBuilder(val expressionValuesExtractor: ExpressionValuesExtractor, private inner class FunctionDFGBuilder(val expressionValuesExtractor: ExpressionValuesExtractor,
val variableValues: VariableValues, val variableValues: VariableValues,
val descriptor: IrDeclaration, val declaration: IrDeclaration,
val expressions: List<IrExpression>, val expressions: List<IrExpression>,
val returnValues: List<IrExpression>, val returnValues: List<IrExpression>,
val thrownValues: List<IrExpression>, val thrownValues: List<IrExpression>,
val catchParameters: Set<IrVariable>) { val catchParameters: Set<IrVariable>) {
private val allParameters = (descriptor as? IrFunction)?.allParameters ?: emptyList() private val allParameters = (declaration as? IrFunction)?.allParameters ?: emptyList()
private val templateParameters = allParameters.withIndex().associateBy({ it.value }, { DataFlowIR.Node.Parameter(it.index) }) private val templateParameters = allParameters.withIndex().associateBy({ it.value }, { DataFlowIR.Node.Parameter(it.index) })
private val continuationParameter = when { private val continuationParameter = when {
descriptor !is IrSimpleFunction -> null declaration !is IrSimpleFunction -> null
descriptor.isSuspend -> DataFlowIR.Node.Parameter(allParameters.size) declaration.isSuspend -> DataFlowIR.Node.Parameter(allParameters.size)
descriptor.overrides(invokeSuspendFunctionSymbol.owner) -> // <this> is a ContinuationImpl inheritor. declaration.overrides(invokeSuspendFunctionSymbol.owner) -> // <this> is a ContinuationImpl inheritor.
templateParameters[descriptor.dispatchReceiverParameter!!] // It is its own continuation. templateParameters[declaration.dispatchReceiverParameter!!] // It is its own continuation.
else -> null else -> null
} }
private fun getContinuation() = continuationParameter ?: error("Function $descriptor has no continuation parameter") private fun getContinuation() = continuationParameter ?: error("Function ${declaration.descriptor} has no continuation parameter")
private val nodes = mutableMapOf<IrExpression, DataFlowIR.Node>() private val nodes = mutableMapOf<IrExpression, DataFlowIR.Node>()
private val variables = variableValues.elementData.keys.associate { private val variables = variableValues.elementData.keys.associate {
@@ -444,14 +445,14 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
} }
fun build(): DataFlowIR.Function { fun build(): DataFlowIR.Function {
val isSuspend = descriptor is IrSimpleFunction && descriptor.isSuspend val isSuspend = declaration is IrSimpleFunction && declaration.isSuspend
expressions.forEach { getNode(it) } expressions.forEach { getNode(it) }
val returnNodeType = when (descriptor) { val returnNodeType = when (declaration) {
is IrField -> descriptor.type is IrField -> declaration.type
is IrFunction -> descriptor.returnType is IrFunction -> declaration.returnType
else -> error(descriptor) else -> error(declaration)
} }
val returnsNode = DataFlowIR.Node.Variable( val returnsNode = DataFlowIR.Node.Variable(
@@ -464,8 +465,8 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
type = symbolTable.mapClassReferenceType(symbols.throwable.owner), type = symbolTable.mapClassReferenceType(symbols.throwable.owner),
kind = DataFlowIR.VariableKind.Temporary kind = DataFlowIR.VariableKind.Temporary
) )
variables.forEach { descriptor, node -> variables.forEach { variable, node ->
variableValues.elementData[descriptor]!!.forEach { variableValues.elementData[variable]!!.forEach {
node.values += expressionToEdge(it) node.values += expressionToEdge(it)
} }
} }
@@ -473,7 +474,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
(if (isSuspend) listOf(continuationParameter!!) else emptyList()) (if (isSuspend) listOf(continuationParameter!!) else emptyList())
return DataFlowIR.Function( return DataFlowIR.Function(
symbol = symbolTable.mapFunction(descriptor), symbol = symbolTable.mapFunction(declaration),
body = DataFlowIR.FunctionBody(allNodes.distinct().toList(), returnsNode, throwsNode) body = DataFlowIR.FunctionBody(allNodes.distinct().toList(), returnsNode, throwsNode)
) )
} }
@@ -488,10 +489,10 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
private fun getNode(expression: IrExpression): DataFlowIR.Node { private fun getNode(expression: IrExpression): DataFlowIR.Node {
if (expression is IrGetValue) { if (expression is IrGetValue) {
val descriptor = expression.symbol.owner val valueDeclaration = expression.symbol.owner
if (descriptor is IrValueParameter) if (valueDeclaration is IrValueParameter)
return templateParameters[descriptor]!! return templateParameters[valueDeclaration]!!
return variables[descriptor]!! return variables[valueDeclaration]!!
} }
return nodes.getOrPut(expression) { return nodes.getOrPut(expression) {
DEBUG_OUTPUT(0) { DEBUG_OUTPUT(0) {
@@ -580,7 +581,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
} else { } else {
callee as IrSimpleFunction callee as IrSimpleFunction
if (callee.isOverridable && value.superQualifier == null) { if (callee.isOverridable && value.superQualifier == null) {
val owner = callee.containingDeclaration as IrClass val owner = callee.parentAsClass
val actualReceiverType = value.dispatchReceiver!!.type val actualReceiverType = value.dispatchReceiver!!.type
val actualReceiverClassifier = actualReceiverType.classifierOrFail val actualReceiverClassifier = actualReceiverType.classifierOrFail
@@ -634,7 +635,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
} }
is IrDelegatingConstructorCall -> { is IrDelegatingConstructorCall -> {
val thisReceiver = (descriptor as IrConstructor).constructedClass.thisReceiver!! val thisReceiver = (declaration as IrConstructor).constructedClass.thisReceiver!!
val thiz = IrGetValueImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, thisReceiver.type, val thiz = IrGetValueImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, thisReceiver.type,
thisReceiver.symbol) thisReceiver.symbol)
val arguments = listOf(thiz) + value.getArguments().map { it.second } val arguments = listOf(thiz) + value.getArguments().map { it.second }
@@ -649,7 +650,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
is IrGetField -> { is IrGetField -> {
val receiver = value.receiver?.let { expressionToEdge(it) } val receiver = value.receiver?.let { expressionToEdge(it) }
val receiverType = value.receiver?.let { symbolTable.mapType(it.type) } val receiverType = value.receiver?.let { symbolTable.mapType(it.type) }
val name = value.descriptor.name.asString() val name = value.symbol.owner.name.asString()
DataFlowIR.Node.FieldRead( DataFlowIR.Node.FieldRead(
receiver, receiver,
DataFlowIR.Field( DataFlowIR.Field(
@@ -665,7 +666,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
is IrSetField -> { is IrSetField -> {
val receiver = value.receiver?.let { expressionToEdge(it) } val receiver = value.receiver?.let { expressionToEdge(it) }
val receiverType = value.receiver?.let { symbolTable.mapType(it.type) } val receiverType = value.receiver?.let { symbolTable.mapType(it.type) }
val name = value.descriptor.name.asString() val name = value.symbol.owner.name.asString()
DataFlowIR.Node.FieldWrite( DataFlowIR.Node.FieldWrite(
receiver, receiver,
DataFlowIR.Field( DataFlowIR.Field(
@@ -679,7 +680,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
} }
is IrTypeOperatorCall -> { is IrTypeOperatorCall -> {
assert(!value.operator.isCast(), { "Casts should've been handled earlier" }) assert(!value.operator.isCast()) { "Casts should've been handled earlier" }
expressionToEdge(value.argument) // Put argument as a separate vertex. expressionToEdge(value.argument) // Put argument as a separate vertex.
DataFlowIR.Node.Const(symbolTable.mapType(value.type)) // All operators except casts are basically constants. DataFlowIR.Node.Const(symbolTable.mapType(value.type)) // All operators except casts are basically constants.
} }
@@ -490,41 +490,41 @@ internal object DataFlowIR {
private fun IrClass.isFinal() = modality == Modality.FINAL && kind != ClassKind.ENUM_CLASS private fun IrClass.isFinal() = modality == Modality.FINAL && kind != ClassKind.ENUM_CLASS
fun mapClassReferenceType(descriptor: IrClass, eraseLocalObjects: Boolean = true): Type { fun mapClassReferenceType(irClass: IrClass, eraseLocalObjects: Boolean = true): Type {
// Do not try to devirtualize ObjC classes. // Do not try to devirtualize ObjC classes.
if (descriptor.module.name == Name.special("<forward declarations>") || descriptor.isObjCClass()) if (irClass.module.name == Name.special("<forward declarations>") || irClass.isObjCClass())
return Type.Virtual return Type.Virtual
if (eraseLocalObjects && descriptor.isAnonymousObject && descriptor.isLocal) if (eraseLocalObjects && irClass.isAnonymousObject && irClass.isLocal)
return mapClassReferenceType(descriptor.getSuperClassNotAny() ?: context.irBuiltIns.anyClass.owner) return mapClassReferenceType(irClass.getSuperClassNotAny() ?: context.irBuiltIns.anyClass.owner)
val isFinal = descriptor.isFinal() val isFinal = irClass.isFinal()
val isAbstract = descriptor.isAbstract() val isAbstract = irClass.isAbstract()
val name = descriptor.fqNameSafe.asString() val name = irClass.fqNameSafe.asString()
if (descriptor.module != irModule.descriptor) if (irClass.module != irModule.descriptor)
return classMap.getOrPut(descriptor) { return classMap.getOrPut(irClass) {
Type.External(name.localHash.value, isFinal, isAbstract, null, takeName { name }) Type.External(name.localHash.value, isFinal, isAbstract, null, takeName { name })
} }
classMap[descriptor]?.let { return it } classMap[irClass]?.let { return it }
val placeToClassTable = true val placeToClassTable = true
val symbolTableIndex = if (placeToClassTable) module.numberOfClasses++ else -1 val symbolTableIndex = if (placeToClassTable) module.numberOfClasses++ else -1
val type = if (descriptor.isExported()) val type = if (irClass.isExported())
Type.Public(name.localHash.value, isFinal, isAbstract, null, Type.Public(name.localHash.value, isFinal, isAbstract, null,
module, symbolTableIndex, takeName { name }) module, symbolTableIndex, takeName { name })
else else
Type.Private(privateTypeIndex++, isFinal, isAbstract, null, Type.Private(privateTypeIndex++, isFinal, isAbstract, null,
module, symbolTableIndex, takeName { name }) module, symbolTableIndex, takeName { name })
classMap[descriptor] = type classMap[irClass] = type
type.superTypes += descriptor.superTypes.map { mapClassReferenceType(it.getClass()!!) } type.superTypes += irClass.superTypes.map { mapClassReferenceType(it.getClass()!!) }
if (!isAbstract) { if (!isAbstract) {
val vtableBuilder = context.getVtableBuilder(descriptor) val vtableBuilder = context.getVtableBuilder(irClass)
type.vtable += vtableBuilder.vtableEntries.map { mapFunction(it.getImplementation(context)!!) } type.vtable += vtableBuilder.vtableEntries.map { mapFunction(it.getImplementation(context)!!) }
vtableBuilder.methodTableEntries.forEach { vtableBuilder.methodTableEntries.forEach {
type.itable[it.overriddenDescriptor.functionName.localHash.value] = mapFunction(it.getImplementation(context)!!) type.itable[it.overriddenFunction.functionName.localHash.value] = mapFunction(it.getImplementation(context)!!)
} }
} }
return type return type
@@ -564,18 +564,18 @@ internal object DataFlowIR {
} }
// TODO: use from LlvmDeclarations. // TODO: use from LlvmDeclarations.
private fun getFqName(descriptor: IrDeclaration): FqName = private fun getFqName(declaration: IrDeclaration): FqName =
descriptor.parent.fqNameSafe.child(descriptor.name) declaration.parent.fqNameSafe.child(declaration.name)
private val IrFunction.internalName get() = getFqName(this).asString() + "#internal" private val IrFunction.internalName get() = getFqName(this).asString() + "#internal"
fun mapFunction(descriptor: IrDeclaration): FunctionSymbol = when (descriptor) { fun mapFunction(declaration: IrDeclaration): FunctionSymbol = when (declaration) {
is IrFunction -> mapFunction(descriptor) is IrFunction -> mapFunction(declaration)
is IrField -> mapPropertyInitializer(descriptor) is IrField -> mapPropertyInitializer(declaration)
else -> error("Unknown descriptor: $descriptor") else -> error("Unknown declaration: $declaration")
} }
private fun mapFunction(descriptor: IrFunction): FunctionSymbol = descriptor.target.let { private fun mapFunction(function: IrFunction): FunctionSymbol = function.target.let {
functionMap[it]?.let { return it } functionMap[it]?.let { return it }
val name = if (it.isExported()) it.symbolName else it.internalName val name = if (it.isExported()) it.symbolName else it.internalName
@@ -602,15 +602,15 @@ internal object DataFlowIR {
else -> { else -> {
val isAbstract = it is IrSimpleFunction && it.modality == Modality.ABSTRACT val isAbstract = it is IrSimpleFunction && it.modality == Modality.ABSTRACT
val classDescriptor = it.containingDeclaration as? IrClass val irClass = it.parent as? IrClass
val bridgeTarget = it.bridgeTarget val bridgeTarget = it.bridgeTarget
val isSpecialBridge = bridgeTarget.let { val isSpecialBridge = bridgeTarget.let {
it != null && BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(it.descriptor) != null it != null && BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(it.descriptor) != null
} }
val bridgeTargetSymbol = if (isSpecialBridge || bridgeTarget == null) null else mapFunction(bridgeTarget) val bridgeTargetSymbol = if (isSpecialBridge || bridgeTarget == null) null else mapFunction(bridgeTarget)
val placeToFunctionsTable = !isAbstract && it !is IrConstructor && classDescriptor != null val placeToFunctionsTable = !isAbstract && it !is IrConstructor && irClass != null
&& !classDescriptor.isNonGeneratedAnnotation() && !irClass.isNonGeneratedAnnotation()
&& (it.isOverridableOrOverrides || bridgeTarget != null || descriptor.isSpecial || !classDescriptor.isFinal()) && (it.isOverridableOrOverrides || bridgeTarget != null || function.isSpecial || !irClass.isFinal())
val symbolTableIndex = if (placeToFunctionsTable) module.numberOfFunctions++ else -1 val symbolTableIndex = if (placeToFunctionsTable) module.numberOfFunctions++ else -1
if (it.isExported()) if (it.isExported())
FunctionSymbol.Public(name.localHash.value, module, symbolTableIndex, attributes, bridgeTargetSymbol, takeName { name }) FunctionSymbol.Public(name.localHash.value, module, symbolTableIndex, attributes, bridgeTargetSymbol, takeName { name })
@@ -621,13 +621,13 @@ internal object DataFlowIR {
functionMap[it] = symbol functionMap[it] = symbol
symbol.parameters = symbol.parameters =
(descriptor.allParameters.map { it.type } + (if (descriptor.isSuspend) listOf(continuationType) else emptyList())) (function.allParameters.map { it.type } + (if (function.isSuspend) listOf(continuationType) else emptyList()))
.map { mapTypeToFunctionParameter(it) } .map { mapTypeToFunctionParameter(it) }
.toTypedArray() .toTypedArray()
symbol.returnParameter = mapTypeToFunctionParameter(if (descriptor.isSuspend) symbol.returnParameter = mapTypeToFunctionParameter(if (function.isSuspend)
context.irBuiltIns.anyType context.irBuiltIns.anyType
else else
descriptor.returnType) function.returnType)
return symbol return symbol
} }
@@ -635,14 +635,14 @@ internal object DataFlowIR {
private val IrFunction.isSpecial get() = private val IrFunction.isSpecial get() =
name.asString().let { it.startsWith("<bridge-") || it == "<box>" || it == "<unbox>" } name.asString().let { it.startsWith("<bridge-") || it == "<box>" || it == "<unbox>" }
private fun mapPropertyInitializer(descriptor: IrField): FunctionSymbol = descriptor.original.let { private fun mapPropertyInitializer(irField: IrField): FunctionSymbol {
functionMap[it]?.let { return it } functionMap[irField]?.let { return it }
assert(it.parent !is IrClass) { "All local properties initializers should've been lowered" } assert(irField.parent !is IrClass) { "All local properties initializers should've been lowered" }
val attributes = FunctionAttributes.IS_GLOBAL_INITIALIZER or FunctionAttributes.RETURNS_UNIT val attributes = FunctionAttributes.IS_GLOBAL_INITIALIZER or FunctionAttributes.RETURNS_UNIT
val symbol = FunctionSymbol.Private(privateFunIndex++, module, -1, attributes, null, takeName { "${it.symbolName}_init" }) val symbol = FunctionSymbol.Private(privateFunIndex++, module, -1, attributes, null, takeName { "${irField.symbolName}_init" })
functionMap[it] = symbol functionMap[irField] = symbol
symbol.parameters = emptyArray() symbol.parameters = emptyArray()
symbol.returnParameter = mapTypeToFunctionParameter(context.irBuiltIns.unitType) symbol.returnParameter = mapTypeToFunctionParameter(context.irBuiltIns.unitType)