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]!!
}
fun getBridge(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): IrSimpleFunction {
val irFunction = overriddenFunctionDescriptor.descriptor
assert(overriddenFunctionDescriptor.needBridge) {
"Function ${irFunction.descriptor} is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor.descriptor}"
fun getBridge(overriddenFunction: OverriddenFunctionInfo): IrSimpleFunction {
val irFunction = overriddenFunction.function
assert(overriddenFunction.needBridge) {
"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) {
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.util.simpleFunctions
internal class OverriddenFunctionDescriptor(
val descriptor: IrSimpleFunction,
overriddenDescriptor: IrSimpleFunction
internal class OverriddenFunctionInfo(
val function: IrSimpleFunction,
val overriddenFunction: IrSimpleFunction
) {
val overriddenDescriptor = overriddenDescriptor.original
val needBridge: Boolean
get() = descriptor.target.needBridgeTo(overriddenDescriptor)
get() = function.target.needBridgeTo(overriddenFunction)
val bridgeDirections: BridgeDirections
get() = descriptor.target.bridgeDirectionsTo(overriddenDescriptor)
get() = function.target.bridgeDirectionsTo(overriddenFunction)
val canBeCalledVirtually: Boolean
get() {
if (overriddenDescriptor.isObjCClassMethod()) {
return descriptor.canObjCClassMethodBeCalledVirtually(this.overriddenDescriptor)
if (overriddenFunction.isObjCClassMethod()) {
return function.canObjCClassMethodBeCalledVirtually(overriddenFunction)
}
return overriddenDescriptor.isOverridable
return overriddenFunction.isOverridable
}
val inheritsBridge: Boolean
get() = !descriptor.isReal
&& descriptor.target.overrides(overriddenDescriptor)
&& descriptor.bridgeDirectionsTo(overriddenDescriptor).allNotNeeded()
get() = !function.isReal
&& function.target.overrides(overriddenFunction)
&& function.bridgeDirectionsTo(overriddenFunction).allNotNeeded()
fun getImplementation(context: Context): IrSimpleFunction? {
val target = descriptor.target
val target = function.target
val implementation = if (!needBridge)
target
else {
val bridgeOwner = if (inheritsBridge) {
target // Bridge is inherited from superclass.
} else {
descriptor
function
}
context.specialDeclarationsFactory.getBridge(OverriddenFunctionDescriptor(bridgeOwner, overriddenDescriptor))
context.specialDeclarationsFactory.getBridge(OverriddenFunctionInfo(bridgeOwner, overriddenFunction))
}
return if (implementation.modality == Modality.ABSTRACT) null else implementation
}
override fun toString(): String {
return "(descriptor=$descriptor, overriddenDescriptor=$overriddenDescriptor)"
return "(descriptor=$function, overriddenDescriptor=$overriddenFunction)"
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is OverriddenFunctionDescriptor) return false
if (other !is OverriddenFunctionInfo) return false
if (descriptor != other.descriptor) return false
if (overriddenDescriptor != other.overriddenDescriptor) return false
if (function != other.function) return false
if (overriddenFunction != other.overriddenFunction) return false
return true
}
override fun hashCode(): Int {
var result = descriptor.hashCode()
result = 31 * result + overriddenDescriptor.hashCode()
var result = function.hashCode()
result = 31 * result + overriddenFunction.hashCode()
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 inline fun DEBUG_OUTPUT(severity: Int, block: () -> Unit) {
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) {
println()
println("BUILDING vTable for ${classDescriptor.descriptor}")
println("BUILDING vTable for ${irClass.descriptor}")
}
val superVtableEntries = if (classDescriptor.isSpecialClassWithNoSupertypes()) {
val superVtableEntries = if (irClass.isSpecialClassWithNoSupertypes()) {
emptyList()
} else {
val superClass = classDescriptor.getSuperClassNotAny() ?: context.ir.symbols.any.owner
val superClass = irClass.getSuperClassNotAny() ?: context.ir.symbols.any.owner
context.getVtableBuilder(superClass).vtableEntries
}
val methods = classDescriptor.sortedOverridableOrOverridingMethods
val newVtableSlots = mutableListOf<OverriddenFunctionDescriptor>()
val methods = irClass.sortedOverridableOrOverridingMethods
val newVtableSlots = mutableListOf<OverriddenFunctionInfo>()
DEBUG_OUTPUT(0) {
println()
println("SUPER vTable:")
superVtableEntries.forEach { println(" ${it.overriddenDescriptor.descriptor} -> ${it.descriptor.descriptor}") }
superVtableEntries.forEach { println(" ${it.overriddenFunction.descriptor} -> ${it.function.descriptor}") }
println()
println("METHODS:")
@@ -118,57 +116,57 @@ internal class ClassVtablesBuilder(val classDescriptor: IrClass, val context: Co
}
val inheritedVtableSlots = superVtableEntries.map { superMethod ->
val overridingMethod = methods.singleOrNull { it.overrides(superMethod.descriptor) }
val overridingMethod = methods.singleOrNull { it.overrides(superMethod.function) }
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
} 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.
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
.filterNot { inheritedVtableSlotsSet.contains(it.descriptor to it.bridgeDirections) }
.distinctBy { it.descriptor to it.bridgeDirections }
.filter { it.descriptor.isOverridable }
.filterNot { inheritedVtableSlotsSet.contains(it.function to it.bridgeDirections) }
.distinctBy { it.function to it.bridgeDirections }
.filter { it.function.isOverridable }
DEBUG_OUTPUT(0) {
println()
println("INHERITED vTable slots:")
inheritedVtableSlots.forEach { println(" ${it.overriddenDescriptor.descriptor} -> ${it.descriptor.descriptor}") }
inheritedVtableSlots.forEach { println(" ${it.overriddenFunction.descriptor} -> ${it.function.descriptor}") }
println()
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 {
val bridgeDirections = function.target.bridgeDirectionsTo(function.original)
val index = vtableEntries.indexOfFirst { it.descriptor == function.original && it.bridgeDirections == bridgeDirections }
if (index < 0) throw Error(function.toString() + " not in vtable of " + classDescriptor.toString())
val bridgeDirections = function.target.bridgeDirectionsTo(function)
val index = vtableEntries.indexOfFirst { it.function == function && it.bridgeDirections == bridgeDirections }
if (index < 0) throw Error(function.toString() + " not in vtable of " + irClass.toString())
return index
}
val methodTableEntries: List<OverriddenFunctionDescriptor> by lazy {
classDescriptor.sortedOverridableOrOverridingMethods
.flatMap { method -> method.allOverriddenDescriptors.map { OverriddenFunctionDescriptor(method, it) } }
val methodTableEntries: List<OverriddenFunctionInfo> by lazy {
irClass.sortedOverridableOrOverridingMethods
.flatMap { method -> method.allOverriddenFunctions.map { OverriddenFunctionInfo(method, it) } }
.filter { it.canBeCalledVirtually }
.distinctBy { it.overriddenDescriptor.uniqueId }
.sortedBy { it.overriddenDescriptor.uniqueId }
.distinctBy { it.overriddenFunction.uniqueId }
.sortedBy { it.overriddenFunction.uniqueId }
// 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) }
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
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() {
val result = mutableSetOf<IrSimpleFunction>()
@@ -214,13 +214,13 @@ internal fun IrSimpleFunction.bridgeDirectionsTo(
return ourDirections
}
tailrec internal fun IrDeclaration.findPackage(): IrPackageFragment {
internal tailrec fun IrDeclaration.findPackage(): IrPackageFragment {
val parent = this.parent
return parent as? IrPackageFragment
?: (parent as IrDeclaration).findPackage()
}
fun IrFunction.isComparisonDescriptor(map: Map<SimpleType, IrSimpleFunction>): Boolean =
fun IrFunction.isComparisonFunction(map: Map<SimpleType, IrSimpleFunction>): Boolean =
this in map.values
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 <T : IrDeclaration> T.original get() = this
val IrDeclaration.containingDeclaration get() = this.parent
val IrDeclarationParent.fqNameSafe: FqName get() = when (this) {
is IrPackageFragment -> this.fqName
is IrDeclaration -> this.parent.fqNameSafe.child(this.name)
@@ -116,8 +113,6 @@ val IrProperty.konanBackingField: IrField?
return null
}
val IrField.containingClass get() = this.parent as? IrClass
val IrFunction.isReal get() = this.origin != IrDeclarationOrigin.FAKE_OVERRIDE
// 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()
internal val IrValueParameter.isValueParameter get() = this.index >= 0
private val IrCall.annotationClass
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.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
@@ -181,37 +180,35 @@ private val IrFunction.signature: String
// TODO: rename to indicate that it has signature included
internal val IrFunction.functionName: String
get() {
with(this.original) { // basic support for generics
(if (this is IrConstructor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo()?.let {
return buildString {
if (extensionReceiverParameter != null) {
append(extensionReceiverParameter!!.type.getClass()!!.name)
append(".")
}
(if (this is IrConstructor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo()?.let {
return buildString {
if (extensionReceiverParameter != null) {
append(extensionReceiverParameter!!.type.getClass()!!.name)
append(".")
}
append("objc:")
append(it.selector)
if (this@with is IrConstructor && this@with.isObjCConstructor) append("#Constructor")
append("objc:")
append(it.selector)
if (this@functionName is IrConstructor && this@functionName.isObjCConstructor) append("#Constructor")
// We happen to have the clashing combinations such as
//@ObjCMethod("issueChallengeToPlayers:message:", "objcKniBridge1165")
//external fun GKScore.issueChallengeToPlayers(playerIDs: List<*>?, message: String?): Unit
//@ObjCMethod("issueChallengeToPlayers:message:", "objcKniBridge1172")
//external fun GKScore.issueChallengeToPlayers(playerIDs: List<*>?, message: String?): Unit
// So disambiguate by the name of the bridge for now.
// TODO: idealy we'd never generate such identical declarations.
// We happen to have the clashing combinations such as
//@ObjCMethod("issueChallengeToPlayers:message:", "objcKniBridge1165")
//external fun GKScore.issueChallengeToPlayers(playerIDs: List<*>?, message: String?): Unit
//@ObjCMethod("issueChallengeToPlayers:message:", "objcKniBridge1172")
//external fun GKScore.issueChallengeToPlayers(playerIDs: List<*>?, message: String?): Unit
// So disambiguate by the name of the bridge for now.
// TODO: idealy we'd never generate such identical declarations.
if (this@with is IrSimpleFunction && this@with.hasObjCMethodAnnotation()) {
this@with.objCMethodArgValue("selector") ?.let { append("#$it") }
this@with.objCMethodArgValue("bridge") ?.let { append("#$it") }
}
if (this@functionName is IrSimpleFunction && this@functionName.hasObjCMethodAnnotation()) {
this@functionName.objCMethodArgValue("selector") ?.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 =
@@ -260,14 +257,13 @@ internal val IrField.symbolName: String
// TODO: bring here dependencies of this method?
internal fun RuntimeAware.getLlvmFunctionType(function: IrFunction): LLVMTypeRef {
val original = function.original
val returnType = when {
original is IrConstructor -> voidType
original.isSuspend -> kObjHeaderPtr // Suspend functions return Any?.
else -> getLLVMReturnType(original.returnType)
function is IrConstructor -> voidType
function.isSuspend -> kObjHeaderPtr // Suspend functions return Any?.
else -> getLLVMReturnType(function.returnType)
}
val paramTypes = ArrayList(original.allParameters.map { getLLVMType(it.type) })
if (original.isSuspend)
val paramTypes = ArrayList(function.allParameters.map { getLLVMType(it.type) })
if (function.isSuspend)
paramTypes.add(kObjHeaderPtr) // Suspend functions have implicit parameter of type Continuation<>.
if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr)
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.*
import llvm.*
import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
@@ -29,8 +28,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
//-------------------------------------------------------------------------//
/* to class descriptor */
fun typeInfoValue(descriptor: IrClass): LLVMValueRef = descriptor.llvmTypeInfoPtr
fun typeInfoValue(irClass: IrClass): LLVMValueRef = irClass.llvmTypeInfoPtr
fun param(fn: IrFunction, i: Int): LLVMValueRef {
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)
fun functionEntryPointAddress(descriptor: IrFunction) = descriptor.entryPointAddress.llvm
fun functionHash(descriptor: IrFunction): LLVMValueRef = descriptor.functionName.localHash.llvm
fun functionEntryPointAddress(function: IrFunction) = function.entryPointAddress.llvm
fun functionHash(function: IrFunction): LLVMValueRef = function.functionName.localHash.llvm
fun getObjectInstanceStorage(descriptor: IrClass, shared: Boolean): LLVMValueRef {
assert (!descriptor.isUnit())
val llvmGlobal = if (!isExternal(descriptor)) {
context.llvmDeclarations.forSingleton(descriptor).instanceFieldRef
fun getObjectInstanceStorage(irClass: IrClass, shared: Boolean): LLVMValueRef {
assert (!irClass.isUnit())
val llvmGlobal = if (!isExternal(irClass)) {
context.llvmDeclarations.forSingleton(irClass).instanceFieldRef
} else {
val llvmType = getLLVMType(descriptor.defaultType)
val llvmType = getLLVMType(irClass.defaultType)
importGlobal(
descriptor.objectInstanceFieldSymbolName,
irClass.objectInstanceFieldSymbolName,
llvmType,
origin = descriptor.llvmSymbolOrigin,
origin = irClass.llvmSymbolOrigin,
threadLocal = !shared
)
}
@@ -62,17 +60,17 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
return llvmGlobal
}
fun getObjectInstanceShadowStorage(descriptor: IrClass): LLVMValueRef {
assert (!descriptor.isUnit())
assert (descriptor.objectIsShared)
val llvmGlobal = if (!isExternal(descriptor)) {
context.llvmDeclarations.forSingleton(descriptor).instanceShadowFieldRef!!
fun getObjectInstanceShadowStorage(irClass: IrClass): LLVMValueRef {
assert (!irClass.isUnit())
assert (irClass.objectIsShared)
val llvmGlobal = if (!isExternal(irClass)) {
context.llvmDeclarations.forSingleton(irClass).instanceShadowFieldRef!!
} else {
val llvmType = getLLVMType(descriptor.defaultType)
val llvmType = getLLVMType(irClass.defaultType)
importGlobal(
descriptor.objectInstanceShadowFieldSymbolName,
irClass.objectInstanceShadowFieldSymbolName,
llvmType,
origin = descriptor.llvmSymbolOrigin,
origin = irClass.llvmSymbolOrigin,
threadLocal = true
)
}
@@ -112,18 +110,18 @@ val LLVMValueRef.isConst:Boolean
internal inline fun<R> generateFunction(codegen: CodeGenerator,
descriptor: IrFunction,
function: IrFunction,
startLocation: LocationInfo? = null,
endLocation: LocationInfo? = null,
code:FunctionGenerationContext.(FunctionGenerationContext) -> R) {
val llvmFunction = codegen.llvmFunction(descriptor)
val llvmFunction = codegen.llvmFunction(function)
generateFunctionBody(FunctionGenerationContext(
llvmFunction,
codegen,
startLocation,
endLocation,
descriptor), code)
function), code)
}
@@ -143,7 +141,7 @@ internal inline fun generateFunction(
return function
}
inline private fun <R> generateFunctionBody(
private inline fun <R> generateFunctionBody(
functionGenerationContext: FunctionGenerationContext,
code: FunctionGenerationContext.(FunctionGenerationContext) -> R) {
functionGenerationContext.prologue()
@@ -158,7 +156,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
val codegen: CodeGenerator,
startLocation: LocationInfo?,
endLocation: LocationInfo?,
internal val functionDescriptor: IrFunction? = null): ContextUtils {
internal val irFunction: IrFunction? = null): ContextUtils {
override val context = codegen.context
val vars = VariableManager(this)
@@ -171,9 +169,8 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
var returnType: LLVMTypeRef? = LLVMGetReturnType(getFunctionType(function))
private val returns: MutableMap<LLVMBasicBlockRef, LLVMValueRef> = mutableMapOf()
// TODO: remove, to make CodeGenerator descriptor-agnostic.
val constructedClass: IrClass?
get() = (functionDescriptor as? IrConstructor)?.constructedClass
get() = (irFunction as? IrConstructor)?.constructedClass
private var returnSlot: LLVMValueRef? = null
private var slotsPhi: LLVMValueRef? = null
private val frameOverlaySlotCount =
@@ -195,8 +192,8 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
var forwardingForeignExceptionsTerminatedWith: LLVMValueRef? = null
init {
functionDescriptor?.let {
if (!functionDescriptor.isExported()) {
irFunction?.let {
if (!irFunction.isExported()) {
LLVMSetLinkage(function, LLVMLinkage.LLVMInternalLinkage)
// (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)
}
fun allocInstance(descriptor: IrClass, lifetime: Lifetime): LLVMValueRef =
allocInstance(codegen.typeInfoForAllocation(descriptor), lifetime)
fun allocInstance(irClass: IrClass, lifetime: Lifetime): LLVMValueRef =
allocInstance(codegen.typeInfoForAllocation(irClass), lifetime)
fun allocArray(
typeInfo: LLVMValueRef, count: LLVMValueRef, lifetime: Lifetime): LLVMValueRef {
@@ -628,10 +625,10 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
return switch
}
fun lookupVirtualImpl(receiver: LLVMValueRef, descriptor: IrFunction): LLVMValueRef {
fun lookupVirtualImpl(receiver: LLVMValueRef, irFunction: IrFunction): LLVMValueRef {
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))
} else {
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
* owner as Any and dispatch it via vtable.
*/
val anyMethod = (descriptor as IrSimpleFunction).findOverriddenMethodOfAny()
val owner = (anyMethod ?: descriptor).containingDeclaration as IrClass
val anyMethod = (irFunction as IrSimpleFunction).findOverriddenMethodOfAny()
val owner = (anyMethod ?: irFunction).parentAsClass
val llvmMethod = if (!owner.isInterface) {
// 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 vtable = bitcast(kInt8PtrPtr, vtablePlace)
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
// when passing object as an interface. This way we can use those bits as index
// 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
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
}
@@ -685,16 +682,16 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
}
fun getObjectValue(
descriptor: IrClass,
exceptionHandler: ExceptionHandler,
locationInfo: LocationInfo?
irClass: IrClass,
exceptionHandler: ExceptionHandler,
locationInfo: LocationInfo?
): LLVMValueRef {
if (descriptor.isUnit()) {
if (irClass.isUnit()) {
return codegen.theUnitInstanceRef.llvm
}
if (descriptor.isCompanion) {
val parent = descriptor.parent as IrClass
if (irClass.isCompanion) {
val parent = irClass.parent as IrClass
if (parent.isObjCClass()) {
// TODO: cache it too.
@@ -707,8 +704,8 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
}
}
val shared = descriptor.objectIsShared && context.config.threadsAreAllowed
val objectPtr = codegen.getObjectInstanceStorage(descriptor, shared)
val shared = irClass.objectIsShared && context.config.threadsAreAllowed
val objectPtr = codegen.getObjectInstanceStorage(irClass, shared)
val bbInit = basicBlock("label_init", locationInfo)
val bbExit = basicBlock("label_continue", locationInfo)
val objectVal = loadSlot(objectPtr, false)
@@ -717,12 +714,12 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
condBr(objectInitialized, bbExit, bbInit)
positionAtEnd(bbInit)
val typeInfo = codegen.typeInfoForAllocation(descriptor)
val defaultConstructor = descriptor.constructors.single { it.valueParameters.size == 0 }
val typeInfo = codegen.typeInfoForAllocation(irClass)
val defaultConstructor = irClass.constructors.single { it.valueParameters.size == 0 }
val ctor = codegen.llvmFunction(defaultConstructor)
val (initFunction, args) =
if (shared) {
val shadowObjectPtr = codegen.getObjectInstanceShadowStorage(descriptor)
val shadowObjectPtr = codegen.getObjectInstanceShadowStorage(irClass)
context.llvm.initSharedInstanceFunction to listOf(objectPtr, shadowObjectPtr, typeInfo, ctor)
} else {
context.llvm.initInstanceFunction to listOf(objectPtr, typeInfo, ctor)
@@ -732,7 +729,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
br(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)
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].
*/
fun getEnumEntry(descriptor: IrEnumEntry, exceptionHandler: ExceptionHandler): LLVMValueRef {
val enumClassDescriptor = descriptor.containingDeclaration as IrClass
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClassDescriptor)
fun getEnumEntry(enumEntry: IrEnumEntry, exceptionHandler: ExceptionHandler): LLVMValueRef {
val enumClass = enumEntry.parentAsClass
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClass)
val ordinal = loweredEnum.entriesMap[descriptor.name]!!
val ordinal = loweredEnum.entriesMap[enumEntry.name]!!
val values = call(
loweredEnum.valuesGetter.llvmFunction,
emptyList(),
@@ -141,8 +141,8 @@ internal interface ContextUtils : RuntimeAware {
val staticData: StaticData
get() = context.llvm.staticData
fun isExternal(descriptor: IrDeclaration): Boolean {
val pkg = descriptor.findPackage()
fun isExternal(declaration: IrDeclaration): Boolean {
val pkg = declaration.findPackage()
return when (pkg) {
is IrFile -> pkg.packageFragmentDescriptor.containingDeclaration != context.moduleDescriptor
is IrExternalPackageFragment -> true
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.SourceFile
import org.jetbrains.kotlin.descriptors.konan.CurrentKonanModuleOrigin
import org.jetbrains.kotlin.ir.IrElement
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.util.defaultType
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.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
@@ -194,11 +193,9 @@ internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid {
override fun visitClass(declaration: IrClass) {
super.visitClass(declaration)
val descriptor = declaration
generator.generate(declaration)
generator.generate(descriptor)
if (descriptor.isKotlinObjCClass()) {
if (declaration.isKotlinObjCClass()) {
kotlinObjCClassInfoGenerator.generate(declaration)
}
}
@@ -232,19 +229,19 @@ internal interface CodeContext {
* Declares the 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.
*/
fun getDeclaredVariable(descriptor: IrVariable): Int
fun getDeclaredVariable(variable: IrVariable): Int
/**
* Generates the code to obtain a value available in this context.
*
* @return the requested value
*/
fun genGetValue(descriptor: IrValueDeclaration): LLVMValueRef
fun genGetValue(value: IrValueDeclaration): LLVMValueRef
/**
* 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 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
@@ -622,19 +619,19 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
*/
private inner class VariableScope : InnerScopeImpl() {
override fun genDeclareVariable(descriptor: IrVariable, value: LLVMValueRef?, variableLocation: VariableDebugLocation?): Int {
return functionGenerationContext.vars.createVariable(descriptor, value, variableLocation)
override fun genDeclareVariable(variable: IrVariable, value: LLVMValueRef?, variableLocation: VariableDebugLocation?): Int {
return functionGenerationContext.vars.createVariable(variable, value, variableLocation)
}
override fun getDeclaredVariable(descriptor: IrVariable): Int {
val index = functionGenerationContext.vars.indexOf(descriptor)
return if (index < 0) super.getDeclaredVariable(descriptor) else return index
override fun getDeclaredVariable(variable: IrVariable): Int {
val index = functionGenerationContext.vars.indexOf(variable)
return if (index < 0) super.getDeclaredVariable(variable) else return index
}
override fun genGetValue(descriptor: IrValueDeclaration): LLVMValueRef {
val index = functionGenerationContext.vars.indexOf(descriptor)
override fun genGetValue(value: IrValueDeclaration): LLVMValueRef {
val index = functionGenerationContext.vars.indexOf(value)
if (index < 0) {
return super.genGetValue(descriptor)
return super.genGetValue(value)
} else {
return functionGenerationContext.vars.load(index)
}
@@ -653,21 +650,20 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
init {
if (function != null) {
parameters.forEach{
val descriptor = it.key
val ir = descriptor
val parameter = it.key
val local = functionGenerationContext.vars.createParameter(descriptor,
debugInfoIfNeeded(function, ir))
val local = functionGenerationContext.vars.createParameter(parameter,
debugInfoIfNeeded(function, parameter))
functionGenerationContext.mapParameterForDebug(local, it.value)
}
}
}
override fun genGetValue(descriptor: IrValueDeclaration): LLVMValueRef {
val index = functionGenerationContext.vars.indexOf(descriptor)
override fun genGetValue(value: IrValueDeclaration): LLVMValueRef {
val index = functionGenerationContext.vars.indexOf(value)
if (index < 0) {
return super.genGetValue(descriptor)
return super.genGetValue(value)
} else {
return functionGenerationContext.vars.load(index)
}
@@ -690,7 +686,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
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?) {
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.
*/
private fun bindParameters(descriptor: IrFunction?): Map<IrValueParameter, LLVMValueRef> {
if (descriptor == null) return emptyMap()
val parameterDescriptors = descriptor.allParameters
return parameterDescriptors.mapIndexed { i, parameterDescriptor ->
val parameter = codegen.param(descriptor, i)
assert(codegen.getLLVMType(parameterDescriptor.type) == parameter.type)
parameterDescriptor to parameter
private fun bindParameters(function: IrFunction?): Map<IrValueParameter, LLVMValueRef> {
if (function == null) return emptyMap()
return function.allParameters.mapIndexed { i, irParameter ->
val parameter = codegen.param(function, i)
assert(codegen.getLLVMType(irParameter.type) == parameter.type)
irParameter to parameter
}.toMap()
}
@@ -750,9 +745,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val body = declaration.body
if (declaration.descriptor.modality == Modality.ABSTRACT) return
if (declaration.descriptor.isExternal) return
if (body == null) return
if ((declaration as? IrSimpleFunction)?.modality == Modality.ABSTRACT
|| declaration.isExternal
|| body == null)
return
generateFunction(codegen, declaration,
declaration.location(start = true),
@@ -826,10 +822,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override fun visitField(declaration: IrField) {
context.log{"visitField : ${ir2string(declaration)}"}
debugFieldDeclaration(declaration)
val descriptor = declaration
if (context.needGlobalInit(declaration)) {
val type = codegen.getLLVMType(descriptor.type)
val globalProperty = context.llvmDeclarations.forStaticField(descriptor).storage
val type = codegen.getLLVMType(declaration.type)
val globalProperty = context.llvmDeclarations.forStaticField(declaration).storage
val initializer = declaration.initializer?.expression as? IrConst<*>
if (initializer != null)
LLVMSetInitializer(globalProperty, evaluateExpression(initializer))
@@ -1378,14 +1373,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateCast(value: IrTypeOperatorCall): LLVMValueRef {
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)
if (dstDescriptor.defaultType.isObjCObjectType()) {
if (dstClass.defaultType.isObjCObjectType()) {
with(functionGenerationContext) {
ifThen(not(genInstanceOf(srcArg, dstDescriptor))) {
ifThen(not(genInstanceOf(srcArg, dstClass))) {
callDirect(
context.ir.symbols.ThrowTypeCastException.owner,
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.
// 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 args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list.
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 {
val fieldInfo = context.llvmDeclarations.forField(value)
val classDescriptor = value.containingDeclaration as IrClass
val typePtr = pointerType(fieldInfo.classBodyType)
val bodyPtr = getObjectBodyPtr(classDescriptor, thisPtr)
val bodyPtr = getObjectBodyPtr(value.parentAsClass, thisPtr)
val typedBodyPtr = functionGenerationContext.bitcast(typePtr, bodyPtr)
val fieldPtr = LLVMBuildStructGEP(functionGenerationContext.builder, typedBodyPtr, fieldInfo.index, "")
return fieldPtr!!
}
private fun getObjectBodyPtr(classDescriptor: IrClass, objectPtr: LLVMValueRef): LLVMValueRef {
return if (classDescriptor.isObjCClass()) {
assert(classDescriptor.isKotlinObjCClass())
private fun getObjectBodyPtr(irClass: IrClass, objectPtr: LLVMValueRef): LLVMValueRef {
return if (irClass.isObjCClass()) {
assert(irClass.isKotlinObjCClass())
val objCPtr = callDirect(context.ir.symbols.interopObjCObjectRawValueGetter.owner,
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)
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" }
private fun getContinuation(): LLVMValueRef {
val caller = functionGenerationContext.functionDescriptor!!
val caller = functionGenerationContext.irFunction!!
return if (caller.isSuspend)
codegen.param(caller, caller.allParameters.size) // The last argument.
else {
@@ -2002,11 +1996,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
assert (expression.getArguments().isEmpty())
val descriptor = expression.symbol.owner
assert (descriptor.dispatchReceiverParameter == null)
val function = expression.symbol.owner
assert (function.dispatchReceiverParameter == null)
val entry = codegen.functionEntryPointAddress(descriptor)
return entry
return codegen.functionEntryPointAddress(function)
}
//-------------------------------------------------------------------------//
@@ -2050,14 +2043,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private inner class SuspensionPointScope(val suspensionPointId: IrVariable,
val bbResume: LLVMBasicBlockRef,
val bbResumeId: Int): InnerScopeImpl() {
override fun genGetValue(descriptor: IrValueDeclaration): LLVMValueRef {
if (descriptor == suspensionPointId) {
override fun genGetValue(value: IrValueDeclaration): LLVMValueRef {
if (value == suspensionPointId) {
return if (context.config.indirectBranchesAreAllowed)
functionGenerationContext.blockAddress(bbResume)
else
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(
descriptor: IrFunction, args: List<LLVMValueRef>,
resultLifetime: Lifetime, superClass: IrClass? = null): LLVMValueRef {
function: IrFunction, args: List<LLVMValueRef>,
resultLifetime: Lifetime, superClass: IrClass? = null): LLVMValueRef {
//context.log{"evaluateSimpleFunctionCall : $tmpVariableName = ${ir2string(value)}"}
if (superClass == null && descriptor is IrSimpleFunction && descriptor.isOverridable)
return callVirtual(descriptor, args, resultLifetime)
if (superClass == null && function is IrSimpleFunction && function.isOverridable)
return callVirtual(function, args, resultLifetime)
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 {
return functionGenerationContext.getObjCClass(classDescriptor, currentCodeContext.exceptionHandler)
private fun genGetObjCClass(irClass: IrClass): LLVMValueRef {
return functionGenerationContext.getObjCClass(irClass, currentCodeContext.exceptionHandler)
}
private fun genGetObjCProtocol(irClass: IrClass): LLVMValueRef {
@@ -2220,68 +2213,63 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
// TODO: Intrinsify?
private fun evaluateOperatorCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
context.log{"evaluateOperatorCall : origin:${ir2string(callee)}"}
val descriptor = callee.symbol.owner
val function = callee.symbol.owner
val ib = context.irModule!!.irBuiltins
with(functionGenerationContext) {
return when {
descriptor == ib.eqeqeqFun -> icmpEq(args[0], args[1])
descriptor == ib.booleanNotFun -> icmpNe(args[0], kTrue)
function == ib.eqeqeqFun -> icmpEq(args[0], args[1])
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])
else icmpGt(args[0], args[1])
}
descriptor.isComparisonDescriptor(ib.greaterOrEqualFunByOperandType) -> {
function.isComparisonFunction(ib.greaterOrEqualFunByOperandType) -> {
if (args[0].type.isFloatingPoint()) fcmpGe(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])
else icmpLt(args[0], args[1])
}
descriptor.isComparisonDescriptor(ib.lessOrEqualFunByOperandType) -> {
function.isComparisonFunction(ib.lessOrEqualFunByOperandType) -> {
if (args[0].type.isFloatingPoint()) fcmpLe(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 {
val realDescriptor = descriptor.target
val llvmFunction = codegen.llvmFunction(realDescriptor)
return call(descriptor, llvmFunction, args, resultLifetime)
val llvmFunction = codegen.llvmFunction(function.target)
return call(function, llvmFunction, args, resultLifetime)
}
//-------------------------------------------------------------------------//
fun callVirtual(descriptor: IrFunction, args: List<LLVMValueRef>,
fun callVirtual(function: IrFunction, args: List<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,
// 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>,
private fun call(function: IrFunction, llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
resultLifetime: Lifetime): LLVMValueRef {
val result = call(function, args, resultLifetime)
if (descriptor.returnType.isNothing()) {
val result = call(llvmFunction, args, resultLifetime)
if (function.returnType.isNothing()) {
functionGenerationContext.unreachable()
}
if (LLVMGetReturnType(getFunctionType(function)) == voidType) {
if (LLVMGetReturnType(getFunctionType(llvmFunction)) == voidType) {
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>,
resultLifetime: Lifetime): LLVMValueRef {
val result = call(function, args, resultLifetime)
@@ -2315,17 +2299,17 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun delegatingConstructorCall(
descriptor: IrConstructor, args: List<LLVMValueRef>): LLVMValueRef {
constructor: IrConstructor, args: List<LLVMValueRef>): LLVMValueRef {
val constructedClass = functionGenerationContext.constructedClass!!
val thisPtr = currentCodeContext.genGetValue(constructedClass.thisReceiver!!)
if (descriptor.constructedClass.isExternalObjCClass()) {
if (constructor.constructedClass.isExternalObjCClass()) {
assert(args.isEmpty())
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) {
thisPtr
} else {
@@ -2333,7 +2317,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionGenerationContext.bitcast(thisPtrArgType, thisPtr)
}
return callDirect(descriptor, listOf(thisPtrArg) + args,
return callDirect(constructor, listOf(thisPtrArg) + args,
Lifetime.IRRELEVANT /* no value returned */)
}
@@ -2385,13 +2369,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun appendEntryPointSelector(descriptor: IrFunction?) {
if (descriptor == null) return
private fun appendEntryPointSelector(function: IrFunction?) {
if (function == null) return
val entryPoint = codegen.llvmFunction(descriptor)
val entryPoint = codegen.llvmFunction(function)
val selectorName = "EntryPointSelector"
val entryPointType = getFunctionType(entryPoint)
val argCount = descriptor.valueParameters.size
val argCount = function.valueParameters.size
assert(argCount <= 1)
val selector = entryPointSelector(entryPoint, entryPointType, selectorName, argCount)
@@ -41,20 +41,20 @@ internal class LlvmDeclarations(
private val fields: Map<IrField, FieldLlvmDeclarations>,
private val staticFields: Map<IrField, StaticFieldLlvmDeclarations>,
private val unique: Map<UniqueKind, UniqueLlvmDeclarations>) {
fun forFunction(descriptor: IrFunction) = functions[descriptor] ?:
error("${descriptor.toString()} ${descriptor.name} in ${(descriptor.parent as IrDeclaration).name}")
fun forFunction(function: IrFunction) = functions[function] ?:
error("${function.descriptor} in ${(function.parent as IrDeclaration).name}")
fun forClass(descriptor: IrClass) = classes[descriptor] ?:
error("$descriptor ${descriptor.name}")
fun forClass(irClass: IrClass) = classes[irClass] ?:
error(irClass.descriptor.toString())
fun forField(descriptor: IrField) = fields[descriptor] ?:
error(descriptor.toString())
fun forField(field: IrField) = fields[field] ?:
error(field.descriptor.toString())
fun forStaticField(descriptor: IrField) = staticFields[descriptor] ?:
error(descriptor.toString())
fun forStaticField(field: IrField) = staticFields[field] ?:
error(field.descriptor.toString())
fun forSingleton(descriptor: IrClass) = forClass(descriptor).singletonDeclarations ?:
error(descriptor.toString())
fun forSingleton(irClass: IrClass) = forClass(irClass).singletonDeclarations ?:
error(irClass.descriptor.toString())
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.
* 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> {
val superClass = classDescriptor.getSuperClassNotAny() // TODO: what if Any has fields?
internal fun Context.getFields(irClass: IrClass): List<IrField> {
val superClass = irClass.getSuperClassNotAny() // TODO: what if Any has fields?
val superFields = if (superClass != null) getFields(superClass) else emptyList()
return superFields + getDeclaredFields(classDescriptor)
return superFields + getDeclaredFields(irClass)
}
/**
* 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:
// The existence of a backing field for a property is only described in the IR,
// 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
// two ways: first we check IR, then we check the protobuf extension.
val irClass = classDescriptor
val fields = irClass.declarations.mapNotNull {
when (it) {
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.
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.sortedBy {
@@ -157,8 +156,8 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
private val names = mutableMapOf<IrDeclaration, Name>()
private val counts = mutableMapOf<FqName, Int>()
fun getName(parent: FqName, descriptor: IrDeclaration): Name {
return names.getOrPut(descriptor) {
fun getName(parent: FqName, declaration: IrDeclaration): Name {
return names.getOrPut(declaration) {
val count = counts.getOrDefault(parent, 0) + 1
counts[parent] = count
Name.identifier(prefix + count)
@@ -168,34 +167,34 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val objectNamer = Namer("object-")
private fun getLocalName(parent: FqName, descriptor: IrDeclaration): Name {
if (descriptor.isAnonymousObject) {
return objectNamer.getName(parent, descriptor)
private fun getLocalName(parent: FqName, declaration: IrDeclaration): Name {
if (declaration.isAnonymousObject) {
return objectNamer.getName(parent, declaration)
}
return descriptor.name
return declaration.name
}
private fun getFqName(descriptor: IrDeclaration): FqName {
val parent = descriptor.parent
private fun getFqName(declaration: IrDeclaration): FqName {
val parent = declaration.parent
val parentFqName = when (parent) {
is IrPackageFragment -> parent.fqName
is IrDeclaration -> getFqName(parent)
else -> error(parent)
}
val localName = getLocalName(parentFqName, descriptor)
val localName = getLocalName(parentFqName, declaration)
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
* exported declarations.
*/
private fun qualifyInternalName(descriptor: IrDeclaration): String {
return getFqName(descriptor).asString() + "#internal"
private fun qualifyInternalName(declaration: IrDeclaration): String {
return getFqName(declaration).asString() + "#internal"
}
override fun visitElement(element: IrElement) {
@@ -209,30 +208,28 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
}
private fun createClassDeclarations(declaration: IrClass): ClassLlvmDeclarations {
val descriptor = declaration
val internalName = qualifyInternalName(declaration)
val internalName = qualifyInternalName(descriptor)
val fields = getFields(descriptor)
val fields = getFields(declaration)
val bodyType = createClassBodyType("kclassbody:$internalName", fields)
val typeInfoPtr: ConstPointer
val typeInfoGlobal: StaticData.Global
val typeInfoSymbolName = if (descriptor.isExported()) {
descriptor.typeInfoSymbolName
val typeInfoSymbolName = if (declaration.isExported()) {
declaration.typeInfoSymbolName
} else {
"ktype:$internalName"
}
if (descriptor.typeInfoHasVtableAttached) {
if (declaration.typeInfoHasVtableAttached) {
// Create the special global consisting of TypeInfo and vtable.
val typeInfoGlobalName = "ktypeglobal:$internalName"
val typeInfoWithVtableType = structType(
runtime.typeInfoType,
LLVMArrayType(int8TypePtr, context.getVtableBuilder(descriptor).vtableEntries.size)!!
LLVMArrayType(int8TypePtr, context.getVtableBuilder(declaration).vtableEntries.size)!!
)
typeInfoGlobal = staticData.createGlobal(typeInfoWithVtableType, typeInfoGlobalName, isExported = false)
@@ -242,7 +239,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
typeInfoGlobal.pointer.getElementPtr(0).llvm,
typeInfoSymbolName)!!
if (descriptor.isExported()) {
if (declaration.isExported()) {
if (llvmTypeInfoPtr.name != typeInfoSymbolName) {
// So alias name has been mangled by LLVM to avoid name clash.
throw IllegalArgumentException("Global '$typeInfoSymbolName' already exists")
@@ -256,22 +253,22 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
} else {
typeInfoGlobal = staticData.createGlobal(runtime.typeInfoType,
typeInfoSymbolName,
isExported = descriptor.isExported())
isExported = declaration.isExported())
typeInfoPtr = typeInfoGlobal.pointer
}
if (descriptor.isUnit() || descriptor.isKotlinArray())
createUniqueDeclarations(descriptor, typeInfoPtr, bodyType)
if (declaration.isUnit() || declaration.isKotlinArray())
createUniqueDeclarations(declaration, typeInfoPtr, bodyType)
val singletonDeclarations = if (descriptor.kind.isSingleton) {
createSingletonDeclarations(descriptor)
val singletonDeclarations = if (declaration.kind.isSingleton) {
createSingletonDeclarations(declaration)
} else {
null
}
val objCDeclarations = if (descriptor.isKotlinObjCClass()) {
createKotlinObjCClassDeclarations(descriptor)
val objCDeclarations = if (declaration.isKotlinObjCClass()) {
createKotlinObjCClassDeclarations(declaration)
} else {
null
}
@@ -279,8 +276,8 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val writableTypeInfoType = runtime.writableTypeInfoType
val writableTypeInfoGlobal = if (writableTypeInfoType == null) {
null
} else if (descriptor.isExported()) {
val name = descriptor.writableTypeInfoSymbolName
} else if (declaration.isExported()) {
val name = declaration.writableTypeInfoSymbolName
staticData.createGlobal(writableTypeInfoType, name, isExported = true).also {
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(
descriptor: IrClass, typeInfoPtr: ConstPointer, bodyType: LLVMTypeRef) {
irClass: IrClass, typeInfoPtr: ConstPointer, bodyType: LLVMTypeRef) {
when {
descriptor.isUnit() -> {
irClass.isUnit() -> {
uniques[UniqueKind.UNIT] =
UniqueLlvmDeclarations(staticData.createUniqueInstance(UniqueKind.UNIT, bodyType, typeInfoPtr))
}
descriptor.isKotlinArray() -> {
irClass.isKotlinArray() -> {
uniques[UniqueKind.EMPTY_ARRAY] =
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
}
val isExported = descriptor.isExported()
val isExported = irClass.isExported()
val symbolName = if (isExported) {
descriptor.objectInstanceFieldSymbolName
irClass.objectInstanceFieldSymbolName
} else {
"kobjref:" + qualifyInternalName(descriptor)
"kobjref:" + qualifyInternalName(irClass)
}
val threadLocal = !(descriptor.objectIsShared && context.config.threadsAreAllowed)
val threadLocal = !(irClass.objectIsShared && context.config.threadsAreAllowed)
val instanceFieldRef = addGlobal(
symbolName, getLLVMType(descriptor.defaultType), isExported = isExported, threadLocal = threadLocal)
symbolName, getLLVMType(irClass.defaultType), isExported = isExported, threadLocal = threadLocal)
LLVMSetInitializer(instanceFieldRef, kNullObjHeaderPtr)
@@ -331,11 +328,11 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
if (threadLocal) null
else {
val shadowSymbolName = if (isExported) {
descriptor.objectInstanceShadowFieldSymbolName
irClass.objectInstanceShadowFieldSymbolName
} 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) }
@@ -343,8 +340,8 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
return SingletonLlvmDeclarations(instanceFieldRef, instanceShadowFieldRef)
}
private fun createKotlinObjCClassDeclarations(descriptor: IrClass): KotlinObjCClassLlvmDeclarations {
val internalName = qualifyInternalName(descriptor)
private fun createKotlinObjCClassDeclarations(irClass: IrClass): KotlinObjCClassLlvmDeclarations {
val internalName = qualifyInternalName(irClass)
val classPointerGlobal = staticData.createGlobal(int8TypePtr, "kobjcclassptr:$internalName")
@@ -363,25 +360,23 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
override fun visitField(declaration: IrField) {
super.visitField(declaration)
val descriptor = declaration
val containingClass = descriptor.containingClass
val containingClass = declaration.parent as? IrClass
if (containingClass != null) {
val classDeclarations = this.classes[containingClass] ?:
error(containingClass.descriptor.toString())
val allFields = classDeclarations.fields
this.fields[descriptor] = FieldLlvmDeclarations(
allFields.indexOf(descriptor) + 1, // First field is ObjHeader.
this.fields[declaration] = FieldLlvmDeclarations(
allFields.indexOf(declaration) + 1, // First field is ObjHeader.
classDeclarations.bodyType
)
} else {
// Fields are module-private, so we use internal name:
val name = "kvar:" + qualifyInternalName(descriptor)
val name = "kvar:" + qualifyInternalName(declaration)
val storage = addGlobal(
name, getLLVMType(descriptor.type), isExported = false,
name, getLLVMType(declaration.type), isExported = false,
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
val descriptor = declaration
val llvmFunctionType = getLlvmFunctionType(descriptor)
val llvmFunctionType = getLlvmFunctionType(declaration)
if ((descriptor is IrConstructor && descriptor.isObjCConstructor)) {
if ((declaration is IrConstructor && declaration.isObjCConstructor)) {
return
}
val llvmFunction = if (descriptor.isExternal) {
if (descriptor.isTypedIntrinsic || descriptor.isObjCBridgeBased()
|| descriptor.annotations.hasAnnotation(RuntimeNames.cCall)) return
val llvmFunction = if (declaration.isExternal) {
if (declaration.isTypedIntrinsic || declaration.isObjCBridgeBased()
|| 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:
origin = descriptor.llvmSymbolOrigin
origin = declaration.llvmSymbolOrigin
)
} else {
val symbolName = if (descriptor.isExported()) {
descriptor.symbolName.also {
if (descriptor.name.asString() != "main") {
val symbolName = if (declaration.isExported()) {
declaration.symbolName.also {
if (declaration.name.asString() != "main") {
assert(LLVMGetNamedFunction(context.llvm.llvmModule, it) == null) { it }
} else {
// As a workaround, allow `main` functions to clash because frontend accepts this.
@@ -416,10 +410,10 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
}
}
} else {
"kfun:" + qualifyInternalName(descriptor)
"kfun:" + qualifyInternalName(declaration)
}
val function = LLVMAddFunction(context.llvmModule, symbolName, llvmFunctionType)!!
if (descriptor.returnType.isNothing())
if (declaration.returnType.isNothing())
setFunctionNoReturn(function)
function
}
@@ -429,6 +423,6 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
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
import llvm.*
import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.computePrimitiveBinaryTypeOrNull
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 {
classDescriptor.symbol == context.ir.symbols.array -> false
classDescriptor.isArray -> true
context.llvmDeclarations.forClass(classDescriptor).fields.all { checkAcyclicFieldType(it.type) } -> true
private fun checkAcyclicClass(irClass: IrClass): Boolean = when {
irClass.symbol == context.ir.symbols.array -> false
irClass.isArray -> true
context.llvmDeclarations.forClass(irClass).fields.all { checkAcyclicFieldType(it.type) } -> true
else -> false
}
private fun flagsFromClass(classDescriptor: IrClass): Int {
private fun flagsFromClass(irClass: IrClass): Int {
var result = 0
if (classDescriptor.isFrozen)
if (irClass.isFrozen)
result = result or TF_IMMUTABLE
// TODO: maybe perform deeper analysis to find surely acyclic types.
if (!classDescriptor.isInterface && !classDescriptor.isAbstract() && !classDescriptor.isAnnotationClass) {
if (checkAcyclicClass(classDescriptor)) {
if (!irClass.isInterface && !irClass.isAbstract() && !irClass.isAnnotationClass) {
if (checkAcyclicClass(irClass)) {
result = result or TF_ACYCLIC
}
}
if (classDescriptor.isInterface)
if (irClass.isInterface)
result = result or TF_INTERFACE
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 fun exportTypeInfoIfRequired(classDesc: IrClass, typeInfoGlobal: LLVMValueRef?) {
val annot = classDesc.descriptor.annotations.findAnnotation(EXPORT_TYPE_INFO_FQ_NAME)
if (annot != null) {
val name = getAnnotationValue(annot)!!
private fun exportTypeInfoIfRequired(irClass: IrClass, typeInfoGlobal: LLVMValueRef?) {
val annotation = irClass.descriptor.annotations.findAnnotation(EXPORT_TYPE_INFO_FQ_NAME)
if (annotation != null) {
val name = getAnnotationValue(annotation)!!
// TODO: use LLVMAddAlias.
val global = addGlobal(name, pointerType(runtime.typeInfoType), isExported = true)
LLVMSetInitializer(global, typeInfoGlobal)
@@ -170,21 +169,21 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
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 size = getInstanceSize(bodyType, className)
val superTypeOrAny = classDesc.getSuperClassNotAny() ?: context.ir.symbols.any.owner
val superType = if (classDesc.isAny()) NullPointer(runtime.typeInfoType)
val superTypeOrAny = irClass.getSuperClassNotAny() ?: context.ir.symbols.any.owner
val superType = if (irClass.isAny()) NullPointer(runtime.typeInfoType)
else superTypeOrAny.typeInfoPtr
val interfaces = classDesc.implementedInterfaces.map { it.typeInfoPtr }
val interfaces = irClass.implementedInterfaces.map { it.typeInfoPtr }
val interfacesPtr = staticData.placeGlobalConstArray("kintf:$className",
pointerType(runtime.typeInfoType), interfaces)
@@ -199,26 +198,26 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
val objOffsetsPtr = staticData.placeGlobalConstArray("krefs:$className", int32Type,
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.
} else {
objOffsets.size
}
val methods = if (classDesc.isAbstract()) {
val methods = if (irClass.isAbstract()) {
emptyList()
} else {
methodTableRecords(classDesc)
methodTableRecords(irClass)
}
val methodsPtr = staticData.placeGlobalConstArray("kmethods:$className",
runtime.methodTableRecordType, methods)
val reflectionInfo = getReflectionInfo(classDesc)
val reflectionInfo = getReflectionInfo(irClass)
val typeInfoGlobal = llvmDeclarations.typeInfoGlobal
val typeInfo = TypeInfo(
classDesc.typeInfoPtr,
makeExtendedInfo(classDesc),
irClass.typeInfoPtr,
makeExtendedInfo(irClass),
size,
superType,
objOffsetsPtr, objOffsetsCount,
@@ -226,26 +225,26 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
methodsPtr, methods.size,
reflectionInfo.packageName,
reflectionInfo.relativeName,
flagsFromClass(classDesc),
flagsFromClass(irClass),
llvmDeclarations.writableTypeInfoGlobal?.pointer
)
val typeInfoGlobalValue = if (!classDesc.typeInfoHasVtableAttached) {
val typeInfoGlobalValue = if (!irClass.typeInfoHasVtableAttached) {
typeInfo
} else {
val vtable = vtable(classDesc)
val vtable = vtable(irClass)
Struct(typeInfo, vtable)
}
typeInfoGlobal.setInitializer(typeInfoGlobalValue)
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
val vtableEntries = context.getVtableBuilder(classDesc).vtableEntries.map {
val vtableEntries = context.getVtableBuilder(irClass).vtableEntries.map {
val implementation = it.implementation
if (implementation == null || implementation.isExternalObjCClassMethod()) {
NullPointer(int8Type)
@@ -256,10 +255,10 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
return ConstArray(int8TypePtr, vtableEntries)
}
fun methodTableRecords(classDesc: IrClass): List<MethodTableRecord> {
val functionNames = mutableMapOf<Long, OverriddenFunctionDescriptor>()
return context.getVtableBuilder(classDesc).methodTableEntries.map {
val functionName = it.overriddenDescriptor.functionName
fun methodTableRecords(irClass: IrClass): List<MethodTableRecord> {
val functionNames = mutableMapOf<Long, OverriddenFunctionInfo>()
return context.getVtableBuilder(irClass).methodTableEntries.map {
val functionName = it.overriddenFunction.functionName
val nameSignature = functionName.localHash
val previous = functionNames.putIfAbsent(nameSignature.value, it)
if (previous != null)
@@ -275,13 +274,13 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
private fun mapRuntimeType(type: LLVMTypeRef): Int =
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?
if (context.shouldOptimize())
return NullPointer(runtime.extendedTypeInfoType)
val className = descriptor.fqNameSafe.toString()
val llvmDeclarations = context.llvmDeclarations.forClass(descriptor)
val className = irClass.fqNameSafe.toString()
val llvmDeclarations = context.llvmDeclarations.forClass(irClass)
val bodyType = llvmDeclarations.bodyType
val elementType = arrayClasses[className]
val value = if (elementType != null) {
@@ -313,18 +312,18 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
// TODO: extract more code common with generate().
fun generateSyntheticInterfaceImpl(
descriptor: IrClass,
methodImpls: Map<IrFunction, ConstPointer>,
immutable: Boolean = false
irClass: IrClass,
methodImpls: Map<IrFunction, ConstPointer>,
immutable: Boolean = false
): ConstPointer {
assert(descriptor.isInterface)
assert(irClass.isInterface)
val size = LLVMStoreSizeOfType(llvmTargetData, kObjHeader).toInt()
val superClass = context.ir.symbols.any.owner
assert(superClass.implementedInterfaces.isEmpty())
val interfaces = listOf(descriptor.typeInfoPtr)
val interfaces = listOf(irClass.typeInfoPtr)
val interfacesPtr = staticData.placeGlobalConstArray("",
pointerType(runtime.typeInfoType), interfaces)
@@ -333,7 +332,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
val objOffsetsCount = 0
val methods = (methodTableRecords(superClass) + methodImpls.map { (method, impl) ->
assert(method.containingDeclaration == descriptor)
assert(method.parent == irClass)
MethodTableRecord(method.functionName.localHash, impl.bitcast(int8TypePtr))
}).sortedBy { it.nameSignature.value }.also {
assert(it.distinctBy { it.nameSignature.value } == it)
@@ -365,7 +364,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
methods = methodsPtr, methodsCount = methods.size,
packageName = reflectionInfo.packageName,
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
), vtable)
@@ -375,23 +374,21 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
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?)
private fun getReflectionInfo(descriptor: IrClass): ReflectionInfo {
return if (descriptor.isAnonymousObject) {
ReflectionInfo(packageName = null, relativeName = null)
} else if (descriptor.isLocal) {
ReflectionInfo(packageName = null, relativeName = descriptor.name.asString())
} else {
ReflectionInfo(
packageName = descriptor.findPackage().fqName.asString(),
relativeName = generateSequence(descriptor, { it.parent as? IrClass })
.toList().reversed()
.joinToString(".") { it.name.asString() }
)
}
private fun getReflectionInfo(irClass: IrClass): ReflectionInfo = when {
irClass.isAnonymousObject -> ReflectionInfo(packageName = null, relativeName = null)
irClass.isLocal -> ReflectionInfo(packageName = null, relativeName = irClass.name.asString())
else -> ReflectionInfo(
packageName = irClass.findPackage().fqName.asString(),
relativeName = generateSequence(irClass) { it.parent as? IrClass }
.toList().reversed()
.joinToString(".") { it.name.asString() }
)
}
}
@@ -8,14 +8,12 @@ package org.jetbrains.kotlin.backend.konan.llvm
import llvm.*
import org.jetbrains.kotlin.backend.common.ir.ir2string
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.declarations.IrValueDeclaration
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.declarations.IrVariable
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 interface Record {
@@ -54,41 +52,41 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
contextVariablesToIndex.clear()
}
fun createVariable(descriptor: IrValueDeclaration, value: LLVMValueRef? = null, variableLocation: VariableDebugLocation?) : Int {
val isVar = descriptor is IrVariable && descriptor.isVar
fun createVariable(valueDeclaration: IrValueDeclaration, value: LLVMValueRef? = null, variableLocation: VariableDebugLocation?) : Int {
val isVar = valueDeclaration is IrVariable && valueDeclaration.isVar
// Note that we always create slot for object references for memory management.
if (!functionGenerationContext.context.shouldContainDebugInfo() && !isVar && value != null)
return createImmutable(descriptor, value)
return createImmutable(valueDeclaration, value)
else
// Unfortunately, we have to create mutable slots here,
// 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
// 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 {
assert(!contextVariablesToIndex.contains(descriptor))
assert(!contextVariablesToIndex.contains(valueDeclaration))
val index = variables.size
val type = functionGenerationContext.getLLVMType(descriptor.type)
val slot = functionGenerationContext.alloca(type, descriptor.name.asString(), variableLocation)
val type = functionGenerationContext.getLLVMType(valueDeclaration.type)
val slot = functionGenerationContext.alloca(type, valueDeclaration.name.asString(), variableLocation)
if (value != null)
functionGenerationContext.storeAny(value, slot)
variables.add(SlotRecord(slot, functionGenerationContext.isObjectType(type), isVar))
contextVariablesToIndex[descriptor] = index
contextVariablesToIndex[valueDeclaration] = index
return index
}
internal var skip = 0
internal fun createParameter(descriptor: IrValueDeclaration, variableLocation: VariableDebugLocation?) : Int {
assert(!contextVariablesToIndex.contains(descriptor))
internal fun createParameter(valueDeclaration: IrValueDeclaration, variableLocation: VariableDebugLocation?) : Int {
assert(!contextVariablesToIndex.contains(valueDeclaration))
val index = variables.size
val type = functionGenerationContext.getLLVMType(descriptor.type)
val slot = functionGenerationContext.alloca(type, "p-${descriptor.name.asString()}", variableLocation)
val type = functionGenerationContext.getLLVMType(valueDeclaration.type)
val slot = functionGenerationContext.alloca(type, "p-${valueDeclaration.name.asString()}", variableLocation)
val isObject = functionGenerationContext.isObjectType(type)
variables.add(ParameterRecord(slot, isObject))
contextVariablesToIndex[descriptor] = index
contextVariablesToIndex[valueDeclaration] = index
if (isObject)
skip++
return index
@@ -110,17 +108,17 @@ internal class VariableManager(val functionGenerationContext: FunctionGeneration
return index
}
internal fun createImmutable(descriptor: IrValueDeclaration, value: LLVMValueRef) : Int {
if (contextVariablesToIndex.containsKey(descriptor))
throw Error("${ir2string(descriptor)} is already defined")
internal fun createImmutable(valueDeclaration: IrValueDeclaration, value: LLVMValueRef) : Int {
if (contextVariablesToIndex.containsKey(valueDeclaration))
throw Error("${ir2string(valueDeclaration)} is already defined")
val index = variables.size
variables.add(ValueRecord(value, descriptor.name))
contextVariablesToIndex[descriptor] = index
variables.add(ValueRecord(value, valueDeclaration.name))
contextVariablesToIndex[valueDeclaration] = index
return index
}
fun indexOf(descriptor: IrValueDeclaration) : Int {
return contextVariablesToIndex.getOrElse(descriptor) { -1 }
fun indexOf(valueDeclaration: IrValueDeclaration) : Int {
return contextVariablesToIndex.getOrElse(valueDeclaration) { -1 }
}
fun addressOf(index: Int): LLVMValueRef {
@@ -1010,7 +1010,7 @@ private fun ObjCExportCodeGenerator.createDirectAdapters(
val implementation = if (this.modality == Modality.ABSTRACT) {
null
} else {
OverriddenFunctionDescriptor(
OverriddenFunctionInfo(
context.ir.get(this) as IrSimpleFunction,
context.ir.get(base) as IrSimpleFunction
).getImplementation(context)
@@ -102,13 +102,13 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
).apply { it.bind(this) }
}
}
val overriddenJobDescriptor = OverriddenFunctionDescriptor(jobFunction, runtimeJobFunction)
val overriddenJobDescriptor = OverriddenFunctionInfo(jobFunction, runtimeJobFunction)
if (!overriddenJobDescriptor.needBridge) return expression
val bridge = context.buildBridge(
startOffset = job.startOffset,
endOffset = job.endOffset,
descriptor = overriddenJobDescriptor,
overriddenFunction = overriddenJobDescriptor,
targetSymbol = job.symbol)
bridges += bridge
expression.putValueArgument(3, IrFunctionReferenceImpl(
@@ -133,15 +133,15 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
irClass.simpleFunctions()
.forEach { function ->
function.allOverriddenDescriptors
.map { OverriddenFunctionDescriptor(function, it) }
function.allOverriddenFunctions
.map { OverriddenFunctionInfo(function, it) }
.filter { !it.bridgeDirections.allNotNeeded() }
.filter { it.canBeCalledVirtually }
.filter { !it.inheritsBridge }
.distinctBy { it.bridgeDirections }
.forEach {
buildBridge(it, irClass)
builtBridges += it.descriptor
builtBridges += it.function
}
}
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(
startOffset = irClass.startOffset,
endOffset = irClass.endOffset,
descriptor = descriptor,
targetSymbol = descriptor.descriptor.symbol,
overriddenFunction = overriddenFunction,
targetSymbol = overriddenFunction.function.symbol,
superQualifierSymbol = irClass.symbol)
)
}
@@ -217,10 +217,10 @@ private fun IrBlockBodyBuilder.buildTypeSafeBarrier(function: IrFunction,
}
private fun Context.buildBridge(startOffset: Int, endOffset: Int,
descriptor: OverriddenFunctionDescriptor, targetSymbol: IrFunctionSymbol,
overriddenFunction: OverriddenFunctionInfo, targetSymbol: IrFunctionSymbol,
superQualifierSymbol: IrClassSymbol? = null): IrFunction {
val bridge = specialDeclarationsFactory.getBridge(descriptor)
val bridge = specialDeclarationsFactory.getBridge(overriddenFunction)
if (bridge.modality == Modality.ABSTRACT) {
return bridge
@@ -228,8 +228,8 @@ private fun Context.buildBridge(startOffset: Int, endOffset: Int,
val irBuilder = createIrBuilder(bridge.symbol, startOffset, endOffset)
bridge.body = irBuilder.irBlockBody(bridge) {
val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor.overriddenDescriptor.descriptor)
typeSafeBarrierDescription?.let { buildTypeSafeBarrier(bridge, descriptor.descriptor, it) }
val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(overriddenFunction.overriddenFunction.descriptor)
typeSafeBarrierDescription?.let { buildTypeSafeBarrier(bridge, overriddenFunction.function, it) }
val delegatingCall = IrCallImpl(
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.generateCFunctionPointer
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.synthesizedName
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()
irClass.declarations.filterIsInstance<IrSimpleFunction>().filter { it.isReal }.forEach { method ->
val overriddenMethodOfAny = method.allOverriddenDescriptors.firstOrNull {
val overriddenMethodOfAny = method.allOverriddenFunctions.firstOrNull {
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.push
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.target
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.util.constructors
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.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -34,7 +35,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.util.OperatorNameConventions
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() =
@@ -78,9 +79,9 @@ private class VariableValues {
if (element !is IrGetValue)
result += element
else {
val descriptor = element.symbol.owner
if (descriptor is IrVariable && !seen.contains(descriptor))
dfs(descriptor, seen, result)
val declaration = element.symbol.owner
if (declaration is IrVariable && !seen.contains(declaration))
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.
val visitor = ElementFinderVisitor()
body?.acceptVoid(visitor)
@@ -262,7 +263,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
}
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) {
function.debugOutput()
@@ -274,8 +275,8 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
DEBUG_OUTPUT(1) {
println("SYMBOL TABLE:")
symbolTable.classMap.forEach { descriptor, type ->
println(" DESCRIPTOR: $descriptor")
symbolTable.classMap.forEach { irClass, type ->
println(" DESCRIPTOR: ${irClass.descriptor}")
println(" TYPE: $type")
if (type !is DataFlowIR.Type.Declared)
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.
val producerInvocation = IrCallImpl(expression.startOffset, expression.endOffset,
executeImplProducerInvoke.returnType,
executeImplProducerInvoke.symbol, executeImplProducerInvoke.descriptor)
executeImplProducerInvoke.symbol)
producerInvocation.dispatchReceiver = expression.getValueArgument(2)
val jobFunctionReference = expression.getValueArgument(3) as? IrFunctionReference
?: error("A function reference expected")
val jobInvocation = IrCallImpl(expression.startOffset, expression.endOffset,
jobFunctionReference.symbol.owner.returnType,
jobFunctionReference.symbol, jobFunctionReference.descriptor)
jobFunctionReference.symbol)
jobInvocation.putValueArgument(0, producerInvocation)
expressions += jobInvocation
@@ -410,27 +411,27 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
private inner class FunctionDFGBuilder(val expressionValuesExtractor: ExpressionValuesExtractor,
val variableValues: VariableValues,
val descriptor: IrDeclaration,
val declaration: IrDeclaration,
val expressions: List<IrExpression>,
val returnValues: List<IrExpression>,
val thrownValues: List<IrExpression>,
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 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.
templateParameters[descriptor.dispatchReceiverParameter!!] // It is its own continuation.
declaration.overrides(invokeSuspendFunctionSymbol.owner) -> // <this> is a ContinuationImpl inheritor.
templateParameters[declaration.dispatchReceiverParameter!!] // It is its own continuation.
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 variables = variableValues.elementData.keys.associate {
@@ -444,14 +445,14 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
}
fun build(): DataFlowIR.Function {
val isSuspend = descriptor is IrSimpleFunction && descriptor.isSuspend
val isSuspend = declaration is IrSimpleFunction && declaration.isSuspend
expressions.forEach { getNode(it) }
val returnNodeType = when (descriptor) {
is IrField -> descriptor.type
is IrFunction -> descriptor.returnType
else -> error(descriptor)
val returnNodeType = when (declaration) {
is IrField -> declaration.type
is IrFunction -> declaration.returnType
else -> error(declaration)
}
val returnsNode = DataFlowIR.Node.Variable(
@@ -464,8 +465,8 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
type = symbolTable.mapClassReferenceType(symbols.throwable.owner),
kind = DataFlowIR.VariableKind.Temporary
)
variables.forEach { descriptor, node ->
variableValues.elementData[descriptor]!!.forEach {
variables.forEach { variable, node ->
variableValues.elementData[variable]!!.forEach {
node.values += expressionToEdge(it)
}
}
@@ -473,7 +474,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
(if (isSuspend) listOf(continuationParameter!!) else emptyList())
return DataFlowIR.Function(
symbol = symbolTable.mapFunction(descriptor),
symbol = symbolTable.mapFunction(declaration),
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 {
if (expression is IrGetValue) {
val descriptor = expression.symbol.owner
if (descriptor is IrValueParameter)
return templateParameters[descriptor]!!
return variables[descriptor]!!
val valueDeclaration = expression.symbol.owner
if (valueDeclaration is IrValueParameter)
return templateParameters[valueDeclaration]!!
return variables[valueDeclaration]!!
}
return nodes.getOrPut(expression) {
DEBUG_OUTPUT(0) {
@@ -580,7 +581,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
} else {
callee as IrSimpleFunction
if (callee.isOverridable && value.superQualifier == null) {
val owner = callee.containingDeclaration as IrClass
val owner = callee.parentAsClass
val actualReceiverType = value.dispatchReceiver!!.type
val actualReceiverClassifier = actualReceiverType.classifierOrFail
@@ -634,7 +635,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
}
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,
thisReceiver.symbol)
val arguments = listOf(thiz) + value.getArguments().map { it.second }
@@ -649,7 +650,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
is IrGetField -> {
val receiver = value.receiver?.let { expressionToEdge(it) }
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(
receiver,
DataFlowIR.Field(
@@ -665,7 +666,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
is IrSetField -> {
val receiver = value.receiver?.let { expressionToEdge(it) }
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(
receiver,
DataFlowIR.Field(
@@ -679,7 +680,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
}
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.
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
fun mapClassReferenceType(descriptor: IrClass, eraseLocalObjects: Boolean = true): Type {
fun mapClassReferenceType(irClass: IrClass, eraseLocalObjects: Boolean = true): Type {
// 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
if (eraseLocalObjects && descriptor.isAnonymousObject && descriptor.isLocal)
return mapClassReferenceType(descriptor.getSuperClassNotAny() ?: context.irBuiltIns.anyClass.owner)
if (eraseLocalObjects && irClass.isAnonymousObject && irClass.isLocal)
return mapClassReferenceType(irClass.getSuperClassNotAny() ?: context.irBuiltIns.anyClass.owner)
val isFinal = descriptor.isFinal()
val isAbstract = descriptor.isAbstract()
val name = descriptor.fqNameSafe.asString()
if (descriptor.module != irModule.descriptor)
return classMap.getOrPut(descriptor) {
val isFinal = irClass.isFinal()
val isAbstract = irClass.isAbstract()
val name = irClass.fqNameSafe.asString()
if (irClass.module != irModule.descriptor)
return classMap.getOrPut(irClass) {
Type.External(name.localHash.value, isFinal, isAbstract, null, takeName { name })
}
classMap[descriptor]?.let { return it }
classMap[irClass]?.let { return it }
val placeToClassTable = true
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,
module, symbolTableIndex, takeName { name })
else
Type.Private(privateTypeIndex++, isFinal, isAbstract, null,
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) {
val vtableBuilder = context.getVtableBuilder(descriptor)
val vtableBuilder = context.getVtableBuilder(irClass)
type.vtable += vtableBuilder.vtableEntries.map { mapFunction(it.getImplementation(context)!!) }
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
@@ -564,18 +564,18 @@ internal object DataFlowIR {
}
// TODO: use from LlvmDeclarations.
private fun getFqName(descriptor: IrDeclaration): FqName =
descriptor.parent.fqNameSafe.child(descriptor.name)
private fun getFqName(declaration: IrDeclaration): FqName =
declaration.parent.fqNameSafe.child(declaration.name)
private val IrFunction.internalName get() = getFqName(this).asString() + "#internal"
fun mapFunction(descriptor: IrDeclaration): FunctionSymbol = when (descriptor) {
is IrFunction -> mapFunction(descriptor)
is IrField -> mapPropertyInitializer(descriptor)
else -> error("Unknown descriptor: $descriptor")
fun mapFunction(declaration: IrDeclaration): FunctionSymbol = when (declaration) {
is IrFunction -> mapFunction(declaration)
is IrField -> mapPropertyInitializer(declaration)
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 }
val name = if (it.isExported()) it.symbolName else it.internalName
@@ -602,15 +602,15 @@ internal object DataFlowIR {
else -> {
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 isSpecialBridge = bridgeTarget.let {
it != null && BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(it.descriptor) != null
}
val bridgeTargetSymbol = if (isSpecialBridge || bridgeTarget == null) null else mapFunction(bridgeTarget)
val placeToFunctionsTable = !isAbstract && it !is IrConstructor && classDescriptor != null
&& !classDescriptor.isNonGeneratedAnnotation()
&& (it.isOverridableOrOverrides || bridgeTarget != null || descriptor.isSpecial || !classDescriptor.isFinal())
val placeToFunctionsTable = !isAbstract && it !is IrConstructor && irClass != null
&& !irClass.isNonGeneratedAnnotation()
&& (it.isOverridableOrOverrides || bridgeTarget != null || function.isSpecial || !irClass.isFinal())
val symbolTableIndex = if (placeToFunctionsTable) module.numberOfFunctions++ else -1
if (it.isExported())
FunctionSymbol.Public(name.localHash.value, module, symbolTableIndex, attributes, bridgeTargetSymbol, takeName { name })
@@ -621,13 +621,13 @@ internal object DataFlowIR {
functionMap[it] = symbol
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) }
.toTypedArray()
symbol.returnParameter = mapTypeToFunctionParameter(if (descriptor.isSuspend)
symbol.returnParameter = mapTypeToFunctionParameter(if (function.isSuspend)
context.irBuiltIns.anyType
else
descriptor.returnType)
function.returnType)
return symbol
}
@@ -635,14 +635,14 @@ internal object DataFlowIR {
private val IrFunction.isSpecial get() =
name.asString().let { it.startsWith("<bridge-") || it == "<box>" || it == "<unbox>" }
private fun mapPropertyInitializer(descriptor: IrField): FunctionSymbol = descriptor.original.let {
functionMap[it]?.let { return it }
private fun mapPropertyInitializer(irField: IrField): FunctionSymbol {
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 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.returnParameter = mapTypeToFunctionParameter(context.irBuiltIns.unitType)